o
    hhL;                     @   s6  d dl Z d dlZd dlZd dlZd dlmZ d dlmZ d dlZd dl	Z	d dl
Z
d dlmZ e  edZeddZedZed	d
ZeddZd dlmZ eeedZdZedadZeeZeZeZe	jedZe
je
jdd e
 e!Z"dd Z#dd Z$dd Z%dd Z&dd Z'dd  Z(d!d" Z)dS )#    N)bulk)Elasticsearch)load_dotenvANTHROPIC_API_KEYANTHROPIC_MODELzclaude-3-5-haiku-latestOPENAI_API_KEYOPENAI_MODELz Qwen/Qwen3-Next-80B-A3B-Instruct
OPENAI_URLz#https://api.deepinfra.com/v1/openai)OpenAI)api_keybase_urlopen_llmzhttp://localhost:9200(Az1yGMw8rORRk87fO38h9fpmwqJ6ZY9IRA1ZGjEo)r   z4%(asctime)s - %(name)s - %(levelname)s - %(message)s)levelformatc                 C   s:   d}t d| dt|   tj| |ddgd}|jjS )Nz
embed-v4.0z*Inside encode_cohere function with model: z and search_documentfloat)textsmodel
input_typeembedding_types)loggerinfolencoembed
embeddingsr   )chunksco_modelresponse r    8/var/www/html/minaions-tender/ai-engine/chat_with_rfp.pyencode_cohere5   s   r"   c                 C   s  t d|   |  }tjj|drdS t|}t|}t d|  tjj	||d |d d i }t
j|rdt|}t|}W d    n1 sPw   Y  g }	g }
t|dkrb|D ]d}i }t|d	 tr|d	 D ]}|r| r|	|  |d
 |d
< t|}|
| qqn#|d	 r|d	  r|	|d	   |d
 |d
< t|}|
| g ||d
 < ||d
  |d  qb|	r]t dt|	 d t|	}t|t|	krt dt| dt|	 d |S g }d}d}t|
D ]\}}zk|t|k r^|| d ur^|| }t|dkrLi |d|i}d
|v r>|d
 r>|d|t||d |d7 }n-t d| d |d7 }nt d| dt|  |d7 }nt d| d |d7 }W q ty } zt d| d|  |d7 }W Y d }~qd }~ww t d| d| d |rVzHtt||dd d!d"d#\}}t d$| d% |rt d&t| d% |d d' D ]}t d(|  qtjj|d t d)|  W |S  ty@ } zMt d*|  t d+ |jd d' D ]}t d,|  qztj|d}|d- }t d.| d/ W n	   t d0 Y tjj|d W Y d }~|S d }~w tyU } z	t d1|   d }~ww t d2 |S t d3 |S t d4|  |S )5Nz"Creating the Elasticsearch index: index
   zindex file for ES:
 settingsmappings)r$   r&   r'   r   questiontagNameanswerzProcessing z questions for embedding...zERROR: Vector count (z ) doesn't match question count ()i   title_vectorr$   )_op_type_index_id_source   zSkipping document z: missing tagNamez: invalid vector dimension z: missing or null vectorzError processing document z: z	Prepared z documents for indexing, z failed<         iX  )r$   request_timeoutmax_retriesinitial_backoffmax_backoffzSuccessfully indexed z
 documentszFailed to index    zFailed item: zDone indexing for zBulk indexing error: zError details:z  - countzDespite errors, z$ documents were successfully indexedz3Could not determine how many documents were indexedz'Unexpected error during bulk indexing: zNo valid documents to indexz#No valid questions found to processz$Data file doesn't exist. File name: )r   r   lower	es_clientindicesexistsopenjsonloadcreateospathisfiler   
isinstanceliststripappendcopydeepcopyr"   	enumeratestr	Exceptionr   refreshBulkIndexErrorerrorsr:   )bid_idindex_config_file	data_file	bid_indexfindex_configtag_responsesdata_json_filedocs	questionsnew_docsfaqnew_faqqdtitle_vectorsrequestssuccessful_docsfailed_docsidocvectorrequestesuccess_countfailed_itemsitemerrorcount_responseindexed_countr    r    r!   es_index_dataA   s   





 







rp   c                    s`   t |ddd}t|}W d    n1 sw   Y  dd |D   fdd| d d D S )	Nrzutf-8)encodingc                 S   s   i | ]	}|d  |d qS )r)   r*   r    ).0rl   r    r    r!   
<dictcomp>   s    z'get_matched_answers.<locals>.<dictcomp>c                    s,   g | ]}|d  d  v r |d  d  qS )r0   r)   r    )rs   hittag_answer_mapr    r!   
<listcomp>   s
    z'get_matched_answers.<locals>.<listcomp>hits)r?   r@   rA   )es_responsejson_filepathrV   	json_datar    rv   r!   get_matched_answers   s   

r}   c                 C   s*  t d|  tjj|drt d| d n	t d| d |d }dd	i id
d|iddi}tj|d|ddgidd}g }t d|  t|d d dkrt d t||}	tj	| |	ddd}
t d|	  t d|
  t
|
jD ]\}}||	|j  q~t d|  |S )NzEntered ES Query for client: r#   u   ✅ z index exists in ESu   ⚠️ z index does not exist in ESr   script_score	match_allz@cosineSimilarity(params.query_vector, doc['title_vector']) + 1.0query_vector)sourceparams)queryscript   includesr)   )sizer   r0   )r$   bodyzData File path is ry   u,   ✅ Positive responses returned in ES search   zrerank-v3.5)r   	documentstop_nr   zAnswer doc list shows zReranked response list shows zFinal FAQ list is: )r   r   r<   r=   r>   searchr   r}   r   rerankrL   resultsrI   r$   )r   query_embeddings	client_idrR   rT   r   script_queryrz   final_contextanswer_doc_listreranked_responseidxresr    r    r!   run_es_query   sH   
	

r   c                 C   sJ   t d| d|   g }tjj| dr#t| g}t| ||||}|S )z<
    Get context for a given query using Elasticsearch.
    z"Entered get_intent for client id: z, With user input: r#   )r   r   r<   r=   r>   r;   r"   r   )textrR   r   rT   context_listtext_embeddingsr    r    r!   get_context  s   
r   c                 C   s   t d|  |r|}nd|}d| d|  d}tdkr9tjjtddd	d
|dgd}t d |jd j	S tdkrZt
jjjtdd	dd
|dgd}t d |jd jjS dS )a_  
    Get response from Claude LLM using the context and user query.
    
    Args:
        query (str): The user's question
        context_list (list): List of context documents retrieved from Elasticsearch
        client_id (str): The client identifier
        
    Returns:
        str: Claude's response to the user query based on the context
    z&Getting Minaions response for client: z

zYYou are an AI assistant helping with RFP (Request for Proposal) questions.
    
CONTEXT:
z

USER QUERY:
a  

Provide a helpful, accurate, and concise response to the user query based only on the information provided in the context above. If the context doesn't contain relevant information to answer the query, say "I don't have enough information to answer that question." 
DO NOT make up information not present in the context.

Return ONLY the response to the USER QUERY with no additional commentary.
claudei  g?zYou are an AI assistant helping with RFP (Request for Proposal) questions. Respond only with information found in the provided context.user)rolecontent)r   
max_tokenstemperaturesystemmessagesz(Minaions response generated successfullyr   r   r   )r   r   N)r   r   join	llm_modelclaude_clientr   rB   claude_modelr   r   openaichatcompletionsr   choicesmessage)r   r   r   no_es_queryformatted_contextpromptr   r    r    r!   get_claude_response$  s<   

	
r   c                 C   s6   |rt | |||}|S t| |||}t | |||}|S )aN  
    Main function to handle the chat flow with RFP context retrieval and Claude response.
    
    Args:
        query (str): The user's question
        bid_id (str): The bid identifier for Elasticsearch index
        client_id (str): The client identifier
        
    Returns:
        str: Claude's response to the user query
    )r   r   )r   rR   r   rT   r   merged_txt_fileclaude_responser   r    r    r!   chat_with_rfp_  s   r   )*r@   rC   rJ   cohereelasticsearch.helpersr   elasticsearchr   redis	anthropicloggingdotenvr   getenvr   r   r   r   r	   r   r
   r   r<   
CO_API_KEYClientr   r   CLAUDE_API_KEY	Anthropicr   basicConfigINFO	getLogger__name__r   r"   rp   r}   r   r   r   r   r    r    r    r!   <module>   sL   



 5;