55from langchain_pinecone import PineconeVectorStore
66from langchain .prompts import PromptTemplate
77from langchain_openai import ChatOpenAI
8- from langchain_core .runnables import RunnablePassthrough
98from pinecone import Pinecone , ServerlessSpec
109
1110# Load environment variables
1211load_dotenv ()
1312pinecone_api_key = st .secrets ["PINECONE_API_KEY2" ]
1413openai_api_key = st .secrets ["OPENAI_API_KEY" ]
1514
16- # Session State Initialization (Moved to top)
15+ # Session State Initialization
1716if "history" not in st .session_state :
1817 st .session_state .history = []
1918if "last_chunks" not in st .session_state :
2019 st .session_state .last_chunks = []
2120
2221# Embeddings and LLM
23- embedding_model = HuggingFaceEmbeddings (
24- model_name = "sentence-transformers/all-MiniLM-L6-v2" , model_kwargs = {"device" : "cpu" }
25- )
22+ try :
23+ embedding_model = HuggingFaceEmbeddings (
24+ model_name = "sentence-transformers/all-MiniLM-L6-v2" ,
25+ model_kwargs = {"device" : "cpu" }, # Explicitly set device
26+ )
27+ except Exception as e :
28+ st .error (f"Error initializing embeddings: { e } . Please ensure 'sentence-transformers' is installed with `pip install sentence-transformers` and compatible PyTorch version." )
29+ embedding_model = None
30+
2631llm = ChatOpenAI (
2732 model = "gpt-4o-mini" ,
2833 temperature = 0.2 ,
3338# Pinecone Initialization
3439pc = Pinecone (api_key = pinecone_api_key )
3540index_name = "chat-models-v1-all-minilm-l6"
36- embedding_dim = len (embedding_model .embed_query ("test" ))
41+ embedding_dim = len (embedding_model .embed_query ("test" )) if embedding_model else 384 # Default dim if embedding fails
3742
3843if index_name not in pc .list_indexes ().names ():
3944 pc .create_index (
4550
4651vector_store = PineconeVectorStore (
4752 index_name = index_name , embedding = embedding_model , pinecone_api_key = pinecone_api_key
48- )
49- retriever = vector_store .as_retriever (search_type = "similarity" , search_kwargs = {"k" : 6 })
50-
51- # Medical Abbreviations
52- MEDICAL_ABBRS = {
53- "IUFD" : "Intrauterine fetal death" ,
54- "PROM" : "Prelabour Rupture of Membranes"
55- # Add more as needed
56- }
57-
58- # Intent Examples
59- INTENT_EXAMPLES = [
60- {"question" : "What are symptoms?" , "intent" : "new_question" },
61- {"question" : "Explain more" , "intent" : "follow_up" },
62- {"question" : "What about diabetes?" , "intent" : "follow_up" },
63- {"question" : "Thanks!" , "intent" : "gratitude" },
64- {"question" : "How are you?" , "intent" : "chitchat" }
65- ]
66-
67- intent_prompt = PromptTemplate .from_template (
68- """
69- You are an intent classifier for a medical chatbot. Classify the user's message into:
70- - new_question: A fresh medical query.
71- - follow_up: Seeks elaboration or new info based on prior context.
72- - gratitude: Thanks or positive feedback.
73- - chitchat: Casual talk.
74-
75- Output one label: new_question, follow_up, gratitude, or chitchat.
76-
77- Examples:
78- {% for ex in examples %}- {{ ex.question }} → {{ ex.intent }}
79- {% endfor %}
80-
81- User: {input}
82- Intent:
83- """
84- )
85-
86- def build_intent_prompt (user_input : str , examples : list [dict ]) -> str :
87- formatted_examples = "\n " .join ([f"- { ex ['question' ]} → { ex ['intent' ]} " for ex in examples ])
88- history = "\n " .join ([f"User: { q } | Bot: { a } " for q , a , _ in st .session_state .history [- 2 :]])
89- return f"""
90- You are an intent classifier. Classify based on recent history:
91- - new_question: Fresh query.
92- - follow_up: Elaboration or new info from prior context.
93- - gratitude: Thanks.
94- - chitchat: Casual talk.
95-
96- History:
97- { history }
98- Examples:
99- { formatted_examples }
100-
101- User: { user_input }
102- Intent:"""
53+ ) if embedding_model else None
54+ retriever = vector_store .as_retriever (search_type = "similarity" , search_kwargs = {"k" : 6 }) if vector_store else None
10355
104- def detect_intent (message : str ) -> str :
105- prompt = build_intent_prompt (message , INTENT_EXAMPLES )
106- return llm .invoke (prompt ).content .strip ().lower ()
10756
10857# Reformulation Prompt
10958reformulate_prompt = PromptTemplate .from_template (
11059 """
111- You are the main component of existence of a rag chat-bot you take in the last question and answer and a follow up question
112- Basis the context of conversation and the follow up question, rewrite the question in a way that is more suite for the retreiver
113- to search in documents
60+ You are a smart medical assistant for a RAG chatbot.
61+
62+ Tasks:
63+ 1. Correct spelling mistakes in the input prompt, assuming a medical context.
64+ 2. Rephrase any medical abbreviations to their full terms (e.g., IUFD to Intrauterine fetal death).
65+ 3. Categorize and act:
66+ - If only medical terminology, rephrase to "cure of [term]."
67+ - If a new medical question, return as is.
68+ - If a follow-up, rewrite based on last Q&A and context for document retrieval.
69+ - If chitchat, return "chitchat."
11470
11571Previous Q&A:
11672Q: {last_question}
@@ -136,9 +92,7 @@ def detect_intent(message: str) -> str:
13692- Use context to address unanswered aspects from the previous answer.
13793- Consider recent chat history for coherence.
13894- Word limit: 150 words.
139-
140- After you've answered the query assess the context retreived,recent_history and what you answered
141- and suggest relevant followup question like for eg would you like to know about...
95+ - Suggest a relevant follow-up question (e.g., "Would you like to know about...").
14296
14397Context:
14498{context}
@@ -153,65 +107,32 @@ def detect_intent(message: str) -> str:
153107)
154108
155109def route_intent (user_message : str ):
156- # Preprocess abbreviations
157- for abbr , full_term in MEDICAL_ABBRS .items ():
158- user_message = user_message .replace (abbr , full_term )
159-
160- intent = detect_intent (user_message )
110+ #print("here 1")
111+ if not llm or not retriever :
112+ return "Error: System not fully initialized. Check dependencies."
113+ #print("here 2")
161114 history = st .session_state .history
162115 last_turn = history [- 1 ] if history else None
163116 prev_question , prev_answer , _ = last_turn if last_turn else ("" , "" , "" )
164117 prev_chunks = st .session_state .last_chunks if st .session_state .last_chunks else []
165-
166- if intent == "new_question" :
167- docs = retriever .invoke (user_message )
118+
119+ reform = reformulate_prompt .format (last_question = prev_question , last_answer = prev_answer , question = user_message )
120+ rewritten = llm .invoke (reform ).content .strip ()
121+ #print(rewritten)
122+ if rewritten .lower () == "chitchat" :
123+
124+ answer = "I'm here for medical questions. Ask one!"
125+ else :
126+ docs = retriever .invoke (rewritten )
168127 chunks = [f"From [{ os .path .basename (d .metadata .get ('source' , '' ))} .pdf]: { d .page_content } " for d in docs ]
169128 context = "\n \n " .join (chunks [:3 ]) # Top 3 for brevity
170- prompt = answer_prompt_template .format (context = context , prev_answer = "" , prev_history = "" , question = user_message )
129+ prompt = answer_prompt_template .format (context = context , prev_answer = prev_answer , prev_history = f"User: { prev_question } | Bot: { prev_answer } " if last_turn else "" , question = rewritten )
171130 answer = llm .invoke (prompt ).content
172131 st .session_state .last_chunks = docs
173-
174- elif intent == "follow_up" :
175- if last_turn and prev_chunks :
176- # Reformulate with prior context
177- reform = reformulate_prompt .format (last_question = prev_question , last_answer = prev_answer , question = user_message )
178-
179- rewritten = llm .invoke (reform ).content
180- print (rewritten )
181- # Smart retrieval: Exclude prior chunk IDs, filter out None values
182- prev_ids = [doc .metadata .get ('id' ) for doc in prev_chunks if doc .metadata .get ('id' ) is not None ]
183- new_docs = vector_store .similarity_search (rewritten , k = 6 , filter = {"id" : {"$nin" : prev_ids }} if prev_ids else {})
184- new_chunks = [f"From [{ os .path .basename (d .metadata .get ('source' , '' ))} .pdf]: { d .page_content } " for d in new_docs ]
185-
186- # Combine context: 3 new + 1 past (if relevant)
187- combined_context = "\n \n " .join (new_chunks [:3 ] + [prev_chunks [0 ].page_content ] if prev_chunks else new_chunks [:3 ])
188-
189- # Prepare history
190- prev_history = f"User: { prev_question } | Bot: { prev_answer } "
191-
192- # Prompt with fused context
193- prompt = answer_prompt_template .format (
194- context = combined_context ,
195- prev_answer = prev_answer ,
196- prev_history = prev_history ,
197- question = rewritten
198- )
199- answer = llm .invoke (prompt ).content
200- st .session_state .last_chunks = new_docs
201- else :
202- answer = "Sorry, I need more context to answer."
203-
204- elif intent == "gratitude" :
205- answer = "You're welcome! Ask me anything else."
206-
207- elif intent == "chitchat" :
208- answer = "I'm here for medical questions. Ask one!"
209-
210- else :
211- answer = "Sorry, I didn't understand. Please rephrase."
212-
213- st .session_state .history .append ((user_message , answer , intent ))
132+ #st.session_state.history.append((user_message, answer, "follow_up" if last_turn else "new_question"))
133+ st .session_state .history .append ((user_message , answer , "dummy" ))
214134 return answer
135+
215136# Streamlit UI
216137st .set_page_config (page_title = "Medical Chatbot" , layout = "centered" )
217138st .title ("🩺 Smart Medical Chatbot" )
@@ -221,7 +142,7 @@ def route_intent(user_message: str):
221142if user_input :
222143 with st .spinner ("Thinking..." ):
223144 response = route_intent (user_input )
224-
145+ #print(response)
225146# Safely handle history display
226147if st .session_state .history :
227148 for i , (q , a , intent ) in enumerate (reversed (st .session_state .history )):
0 commit comments