muhammadnoman76 commited on
Commit
1ef76e3
·
1 Parent(s): c5a8382
app/routers/chat.py CHANGED
@@ -11,7 +11,6 @@ from pydantic import BaseModel
11
 
12
  from app.database.database_query import DatabaseQuery
13
  from app.middleware.auth import get_current_user, get_optional_user
14
- from app.services import ChatProcessor
15
  from app.services.skincare_scheduler import SkinCareScheduler
16
  from app.services.wheel import EnvironmentalConditions
17
  from app.services.RAG_evaluation import RAGEvaluation
@@ -189,32 +188,6 @@ async def export_all_chats(username: str = Depends(get_current_user)):
189
  except Exception as e:
190
  raise HTTPException(status_code=500, detail=str(e))
191
 
192
- @router.post('/web-search')
193
- async def web_search(
194
- data: dict,
195
- authorization: str = Header(None),
196
- username: str = Depends(get_current_user)
197
- ):
198
- try:
199
- token = authorization.split(" ")[1]
200
- session_id = data.get("session_id")
201
- query = data.get("query")
202
- num_results = data.get("num_results", 3)
203
- num_images = data.get("num_images", 3)
204
-
205
- if not session_id or not query:
206
- return JSONResponse(
207
- status_code=400,
208
- content={"error": "session_id and query are required"}
209
- )
210
-
211
- chat_processor = ChatProcessor(token=token, session_id=session_id, num_results=num_results, num_images=num_images)
212
- response = chat_processor.web_search(query=query)
213
-
214
- return {"response": response}
215
- except Exception as e:
216
- raise HTTPException(status_code=500, detail=str(e))
217
-
218
  @router.post('/report-analysis')
219
  async def upload_report(
220
  file: UploadFile = File(...),
 
11
 
12
  from app.database.database_query import DatabaseQuery
13
  from app.middleware.auth import get_current_user, get_optional_user
 
14
  from app.services.skincare_scheduler import SkinCareScheduler
15
  from app.services.wheel import EnvironmentalConditions
16
  from app.services.RAG_evaluation import RAGEvaluation
 
188
  except Exception as e:
189
  raise HTTPException(status_code=500, detail=str(e))
190
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
191
  @router.post('/report-analysis')
192
  async def upload_report(
193
  file: UploadFile = File(...),
app/services/__init__.py CHANGED
@@ -1,7 +1,6 @@
1
  # app/services/__init__.py
2
  from app.services.image_classification_vit import SkinDiseaseClassifier
3
  from app.services.llm_model import Model
4
- from app.services.chat_processor import ChatProcessor
5
  from app.services.chathistory import ChatSession
6
  from app.services.environmental_condition import EnvironmentalData
7
  from app.services.prompts import *
@@ -15,7 +14,6 @@ __all__ = [
15
  "AISkinDetector",
16
  "SkinDiseaseClassifier",
17
  "Model",
18
- "ChatProcessor",
19
  "ChatSession",
20
  "EnvironmentalData",
21
  "RAGEvaluation",
 
1
  # app/services/__init__.py
2
  from app.services.image_classification_vit import SkinDiseaseClassifier
3
  from app.services.llm_model import Model
 
4
  from app.services.chathistory import ChatSession
5
  from app.services.environmental_condition import EnvironmentalData
6
  from app.services.prompts import *
 
14
  "AISkinDetector",
15
  "SkinDiseaseClassifier",
16
  "Model",
 
17
  "ChatSession",
18
  "EnvironmentalData",
19
  "RAGEvaluation",
app/services/agentic_prompt.py CHANGED
@@ -1,9 +1,6 @@
1
  from typing import Dict
2
 
3
 
4
-
5
-
6
-
7
  def _append_personalization(prompt: str, user_data: Dict) -> str:
8
  personalized_tool = user_data.get('personalized_tool_name')
9
  if user_data.get('has_personalized_data') and personalized_tool:
@@ -72,7 +69,8 @@ def _append_image_guidance(prompt: str, user_data: Dict) -> str:
72
 
73
  def _format_json_guidance(user_data: Dict) -> str:
74
  references_instruction = (
75
- "Populate the `references` array with source links mapped from your tool calls."
 
76
  if user_data.get('include_references', True)
77
  else "Set `references` to an empty array because the user disabled references."
78
  )
@@ -106,15 +104,13 @@ def _format_json_guidance(user_data: Dict) -> str:
106
  "If the skin-image analysis tool succeeds, integrate its findings into `## Response from References`, cite it explicitly (e.g., [image]) and describe clinical caution."
107
  " If it reports an error or low confidence, explain the limitation and advise on next best steps instead of guessing."
108
  )
109
- safety_instruction = (
110
- "If the question is outside dermatology/medical scope or evidence is insufficient, respond with a safe refusal inside the JSON instead of guessing."
111
- )
112
  return (
113
  "\nYour final response MUST be valid JSON with this shape:\n"
114
  "{\n"
115
  " \"response\": \"Always start with `## Response from References`. Add `## Personalization Recommendation` only after ingesting personalization tool data, and add `## Environmental Condition` only after ingesting environmental tool data. Under each heading, report only evidence-backed details with inline citations like [1], [2].\",\n"
116
  " \"keywords\": [\"keyword1\", \"keyword2\", ...],\n"
117
- " \"references\": [\"url_or_source_1\", ...],\n"
118
  " \"images\": [\"image_url_1\", ...]\n"
119
  "}\n"
120
  f"{references_instruction}\n"
@@ -123,55 +119,104 @@ def _format_json_guidance(user_data: Dict) -> str:
123
  f"{personalization_instruction}\n"
124
  f"{environmental_instruction}\n"
125
  f"{image_instruction}\n"
126
- f"{safety_instruction}\n"
127
- "Return only JSON (no prose outside the JSON object).\n"
 
 
 
 
128
  "Do NOT hallucinate or invent facts.\n"
129
  )
130
 
131
 
132
  def get_web_search_prompt(user_data: Dict) -> str:
133
  prompt_lines = [
134
- "You are Dr. DermAI, an evidence-based dermatology consultant.",
 
 
 
 
 
135
  "",
136
- "PRIMARY DIRECTIVES:",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137
  ]
138
 
139
  if user_data.get('image_info') and user_data.get('image_tool_name'):
140
  prompt_lines.append(
141
- "0. If an uploaded skin image is provided, call the `analyze_skin_image` tool BEFORE any other tool."
142
  )
143
  prompt_lines.append(
144
- " Summarize its findings (or explain any errors) in your final response, citing it as [image]."
145
- )
146
 
147
  prompt_lines.extend(
148
  [
149
- "1. ALWAYS call the `get_web_search` tool next to gather the latest medical knowledge.",
150
- "2. After reviewing text sources, call `get_image_search` if fresh comparison imagery would help.",
151
- "3. Base every statement on retrieved sources or tool outputs; do not rely solely on prior training.",
152
- "4. Cite the supporting evidence inline using [1], [2], etc.",
153
- "5. Answer ONLY dermatology or medically relevant queries. Politely refuse others inside the JSON response.",
154
- "6. If evidence is insufficient, state the limitation rather than speculating.",
 
 
 
 
 
 
155
  ]
156
  )
157
 
158
  prompt_lines.extend(
159
  [
160
  "",
161
- "TOOL CALL ORDER:",
 
 
 
 
 
 
 
 
 
 
 
 
 
162
  ]
163
  )
164
 
165
  if user_data.get('image_info') and user_data.get('image_tool_name'):
166
  prompt_lines.append(
167
- f"- Step 0: {user_data.get('image_tool_name')}(file_path=<uploaded image path>)"
168
  )
169
 
170
  prompt_lines.extend(
171
  [
172
- "- Step 1: get_web_search(query=<user question>)",
173
- "- Step 2: get_image_search(query=<key medical term>) when live imagery adds value",
174
- "- Step 3: Synthesize findings into the structured JSON response.",
 
 
 
 
 
175
  ]
176
  )
177
 
@@ -194,45 +239,84 @@ def get_vector_search_prompt(user_data: Dict) -> str:
194
  prompt_lines = [
195
  "You are Dr. DermAI, a dermatologist with access to a curated clinical knowledge base.",
196
  "",
197
- "PRIMARY DIRECTIVES:",
 
 
 
 
 
 
 
 
 
 
198
  ]
199
 
200
  if user_data.get('image_info') and user_data.get('image_tool_name'):
201
  prompt_lines.append(
202
- "0. If an uploaded skin image is provided, call the `analyze_skin_image` tool BEFORE any database queries."
203
  )
204
  prompt_lines.append(
205
- " Summarize its findings (or any failure) using [image] in the final JSON response."
206
  )
207
 
208
  prompt_lines.extend(
209
  [
210
- "1. ALWAYS call the `get_vector_search` tool next to retrieve authoritative dermatology passages.",
211
- "2. After reviewing text sources, call `get_image_search` if comparison imagery supports your reasoning.",
212
- "3. Ground every recommendation in tool-derived evidence and cite it inline using [1], [2], etc.",
213
- "4. If the knowledge base lacks coverage, state this explicitly and provide the safest guidance you can.",
214
- "5. Answer ONLY dermatology or medically relevant queries. Politely refuse others inside the JSON response.",
215
- "6. If evidence is insufficient, acknowledge the limitation instead of speculating.",
 
 
 
 
 
 
216
  ]
217
  )
218
 
219
  prompt_lines.extend(
220
  [
221
  "",
222
- "TOOL CALL ORDER:",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
223
  ]
224
  )
225
 
226
  if user_data.get('image_info') and user_data.get('image_tool_name'):
227
  prompt_lines.append(
228
- f"- Step 0: {user_data.get('image_tool_name')}(file_path=<uploaded image path>)"
229
  )
230
 
231
  prompt_lines.extend(
232
  [
233
- "- Step 1: get_vector_search(query=<user question>)",
234
- "- Step 2: get_image_search(query=<key medical term>) when imagery helps",
235
- "- Step 3: Synthesize findings into the structured JSON response.",
 
 
 
 
 
236
  ]
237
  )
238
 
 
1
  from typing import Dict
2
 
3
 
 
 
 
4
  def _append_personalization(prompt: str, user_data: Dict) -> str:
5
  personalized_tool = user_data.get('personalized_tool_name')
6
  if user_data.get('has_personalized_data') and personalized_tool:
 
69
 
70
  def _format_json_guidance(user_data: Dict) -> str:
71
  references_instruction = (
72
+ "Populate the `references` array with ALL unique source links/pages from your tool calls. "
73
+ "If the same source appears multiple times with different pages, include each as a separate reference (e.g., 'Source (page 1)', 'Source (page 2)', 'Source (page 3)', 'Source (page 4)')."
74
  if user_data.get('include_references', True)
75
  else "Set `references` to an empty array because the user disabled references."
76
  )
 
104
  "If the skin-image analysis tool succeeds, integrate its findings into `## Response from References`, cite it explicitly (e.g., [image]) and describe clinical caution."
105
  " If it reports an error or low confidence, explain the limitation and advise on next best steps instead of guessing."
106
  )
107
+
 
 
108
  return (
109
  "\nYour final response MUST be valid JSON with this shape:\n"
110
  "{\n"
111
  " \"response\": \"Always start with `## Response from References`. Add `## Personalization Recommendation` only after ingesting personalization tool data, and add `## Environmental Condition` only after ingesting environmental tool data. Under each heading, report only evidence-backed details with inline citations like [1], [2].\",\n"
112
  " \"keywords\": [\"keyword1\", \"keyword2\", ...],\n"
113
+ " \"references\": [\"url_or_source_1\", \"source_page_2\", ...],\n"
114
  " \"images\": [\"image_url_1\", ...]\n"
115
  "}\n"
116
  f"{references_instruction}\n"
 
119
  f"{personalization_instruction}\n"
120
  f"{environmental_instruction}\n"
121
  f"{image_instruction}\n"
122
+ "\n## CRITICAL CITATION RULES:\n"
123
+ "- Every citation [1], [2], etc. in your response text MUST have a corresponding entry in the references array\n"
124
+ "- If 4 results come from the same source but different pages, cite them as [1], [2], [3], [4] and include ALL 4 in references: ['Source (page 1)', 'Source (page 2)', 'Source (page 3)', 'Source (page 4)']\n"
125
+ "- The number of citations in your text should EXACTLY match the number of references in the array\n"
126
+ "- Never merge multiple citations into one reference\n"
127
+ "\nReturn only JSON (no prose outside the JSON object).\n"
128
  "Do NOT hallucinate or invent facts.\n"
129
  )
130
 
131
 
132
  def get_web_search_prompt(user_data: Dict) -> str:
133
  prompt_lines = [
134
+ "You are Dr. DermAI, an evidence-based dermatology consultant working like a real dermatologist.",
135
+ "",
136
+ "## CRITICAL PRE-FLIGHT CHECK (DO THIS BEFORE ANY TOOL CALLS):",
137
+ "Analyze the user's query to determine if it is:",
138
+ "1. Related to dermatology, skin conditions, or medical topics that could affect skin health",
139
+ "2. A legitimate medical question requiring evidence-based response",
140
  "",
141
+ "Examples of MEDICAL queries (proceed with tools):",
142
+ "- Acne, eczema, psoriasis, skin rashes, infections",
143
+ "- Medications affecting skin, allergies, autoimmune conditions",
144
+ "- Skin cancer, moles, lesions, cosmetic dermatology",
145
+ "- General health topics that impact skin (diabetes, nutrition, etc.)",
146
+ "",
147
+ "Examples of NON-MEDICAL queries (DO NOT use any tools):",
148
+ "- Weather forecasts, sports scores, programming questions",
149
+ "- Cooking recipes, travel advice, entertainment",
150
+ "- Math problems, history facts, non-medical science",
151
+ "",
152
+ "If query is NOT medical/dermatological:",
153
+ "- DO NOT call any search tools, image tools, or other tools",
154
+ "- Return immediately with JSON response containing a polite refusal",
155
+ "- Example response: \"I'm Dr. DermAI, a dermatology specialist. I can only answer questions about skin conditions, dermatological concerns, and related medical topics. For [topic mentioned], please consult an appropriate resource.\"",
156
+ "",
157
+ "## PRIMARY DIRECTIVES FOR MEDICAL QUERIES:",
158
  ]
159
 
160
  if user_data.get('image_info') and user_data.get('image_tool_name'):
161
  prompt_lines.append(
162
+ "0. If an uploaded skin image is provided, call the `analyze_skin_image` tool FIRST."
163
  )
164
  prompt_lines.append(
165
+ " Integrate its findings into your response, citing it as [image]."
166
+ )
167
 
168
  prompt_lines.extend(
169
  [
170
+ "1. Like a real dermatologist, make MULTIPLE targeted searches to gather comprehensive information:",
171
+ " - First search: General query about the condition",
172
+ " - Second search: Specific symptoms or differential diagnosis if needed",
173
+ " - Third search: Treatment options if discussing management",
174
+ " - Fourth search: Complications or prognosis if relevant",
175
+ "2. Each search should build upon previous findings to create a thorough assessment.",
176
+ "3. If initial searches return insufficient results:",
177
+ " - Try ONE reformulated query with medical synonyms",
178
+ " - If still no results, clearly state: \"I don't have sufficient information about [specific topic] in the current medical literature. Please consult a dermatologist for evaluation.\"",
179
+ "4. After text searches, call `get_image_search` ONLY if visual comparison would genuinely aid diagnosis.",
180
+ "5. Base EVERY statement on retrieved sources; cite using [1], [2], etc.",
181
+ "6. Never invent information - only report what sources confirm.",
182
  ]
183
  )
184
 
185
  prompt_lines.extend(
186
  [
187
  "",
188
+ "## SEARCH STRATEGY (Think like a dermatologist):",
189
+ "- Start broad, then narrow based on findings",
190
+ "- Maximum 4-5 web searches for thorough investigation",
191
+ "- Each search should have a clear diagnostic purpose",
192
+ "- Stop searching once you have sufficient evidence",
193
+ "- If searches yield nothing relevant, admit knowledge gap",
194
+ "",
195
+ "## HANDLING INSUFFICIENT INFORMATION:",
196
+ "When searches return no relevant results:",
197
+ "1. Do NOT keep searching endlessly",
198
+ "2. Do NOT make up information",
199
+ "3. State clearly: \"Based on my search, I don't have specific information about [topic]. This may be a rare condition or require specialized evaluation. Please consult a dermatologist for proper assessment.\"",
200
+ "",
201
+ "TOOL CALL ORDER FOR MEDICAL QUERIES:",
202
  ]
203
  )
204
 
205
  if user_data.get('image_info') and user_data.get('image_tool_name'):
206
  prompt_lines.append(
207
+ f"- Step 0: {user_data.get('image_tool_name')}(file_path=<uploaded image path>) - if image uploaded"
208
  )
209
 
210
  prompt_lines.extend(
211
  [
212
+ "- Step 1: Verify query is medical/dermatological (no tools if not)",
213
+ "- Step 2-5: Multiple get_web_search calls with different angles:",
214
+ " get_web_search(query=<main condition/symptoms>)",
215
+ " • get_web_search(query=<differential diagnosis or causes>)",
216
+ " • get_web_search(query=<treatment options>) if applicable",
217
+ " • get_web_search(query=<complications or when to see doctor>) if needed",
218
+ "- Step 6: get_image_search(query=<visual term>) if images would help",
219
+ "- Step 7: Synthesize all findings into structured JSON response",
220
  ]
221
  )
222
 
 
239
  prompt_lines = [
240
  "You are Dr. DermAI, a dermatologist with access to a curated clinical knowledge base.",
241
  "",
242
+ "## CRITICAL PRE-FLIGHT CHECK (DO THIS BEFORE ANY TOOL CALLS):",
243
+ "Analyze the user's query to determine if it is:",
244
+ "1. Related to dermatology, skin conditions, or medical topics",
245
+ "2. A legitimate medical question requiring clinical knowledge",
246
+ "",
247
+ "If query is NOT medical/dermatological:",
248
+ "- DO NOT call any search tools or other tools",
249
+ "- Return immediately with JSON response containing a polite refusal",
250
+ "- Example: \"I'm Dr. DermAI, specialized in dermatology. I can only answer questions about skin conditions and related medical topics. For [topic mentioned], please consult an appropriate resource.\"",
251
+ "",
252
+ "## PRIMARY DIRECTIVES FOR MEDICAL QUERIES:",
253
  ]
254
 
255
  if user_data.get('image_info') and user_data.get('image_tool_name'):
256
  prompt_lines.append(
257
+ "0. If an uploaded skin image is provided, call the `analyze_skin_image` tool FIRST."
258
  )
259
  prompt_lines.append(
260
+ " Include its findings in your response, citing as [image]."
261
  )
262
 
263
  prompt_lines.extend(
264
  [
265
+ "1. Like a thorough dermatologist, make MULTIPLE vector searches to gather comprehensive knowledge:",
266
+ " - First search: Main condition or symptom",
267
+ " - Second search: Related symptoms or differential diagnosis",
268
+ " - Third search: Treatment protocols if discussing management",
269
+ " - Fourth search: Patient counseling points if relevant",
270
+ "2. Each search should explore different aspects of the condition.",
271
+ "3. If vector searches return no relevant results:",
272
+ " - Try ONE reformulated query using medical terminology",
273
+ " - If still no results, state: \"This topic is not covered in my current knowledge base. For the most up-to-date information about [topic], please consult a dermatologist.\"",
274
+ "4. After text searches, call `get_image_search` if clinical images would enhance understanding.",
275
+ "5. Every claim must be grounded in retrieved sources with citations [1], [2], etc.",
276
+ "6. Never fabricate medical information.",
277
  ]
278
  )
279
 
280
  prompt_lines.extend(
281
  [
282
  "",
283
+ "## VECTOR SEARCH STRATEGY:",
284
+ "- Search different aspects: pathophysiology, diagnosis, treatment, prognosis",
285
+ "- Maximum 4-5 vector searches for complete coverage",
286
+ "- Each search should target specific clinical information",
287
+ "- Stop when you have sufficient evidence-based content",
288
+ "",
289
+ "## CITATION CONSISTENCY RULES:",
290
+ "- If 4 results come from the same source but different pages, cite as [1], [2], [3], [4]",
291
+ "- Include ALL 4 in references: ['Source (page 1)', 'Source (page 2)', 'Source (page 3)', 'Source (page 4)']",
292
+ "- NEVER merge multiple page citations into a single reference",
293
+ "- The number of citations MUST match the number of references",
294
+ "",
295
+ "## WHEN KNOWLEDGE IS ABSENT:",
296
+ "If the knowledge base lacks information:",
297
+ "1. Do NOT continue searching repeatedly",
298
+ "2. Do NOT hallucinate medical facts",
299
+ "3. Acknowledge clearly: \"I don't have information about [specific topic] in my knowledge base. This may require consultation with a specialist for proper evaluation.\"",
300
+ "",
301
+ "TOOL CALL ORDER FOR MEDICAL QUERIES:",
302
  ]
303
  )
304
 
305
  if user_data.get('image_info') and user_data.get('image_tool_name'):
306
  prompt_lines.append(
307
+ f"- Step 0: {user_data.get('image_tool_name')}(file_path=<uploaded image path>) - if image uploaded"
308
  )
309
 
310
  prompt_lines.extend(
311
  [
312
+ "- Step 1: Verify query is medical/dermatological (no tools if not)",
313
+ "- Step 2-5: Multiple get_vector_search calls exploring different angles:",
314
+ " get_vector_search(query=<primary condition/symptoms>)",
315
+ " • get_vector_search(query=<differential or related conditions>)",
316
+ " • get_vector_search(query=<treatment guidelines>) if applicable",
317
+ " • get_vector_search(query=<patient education points>) if relevant",
318
+ "- Step 6: get_image_search(query=<clinical term>) if visuals help",
319
+ "- Step 7: Synthesize findings into structured JSON response with proper citations",
320
  ]
321
  )
322
 
app/services/chat_processor.py DELETED
@@ -1,272 +0,0 @@
1
- from datetime import datetime, timezone
2
- from typing import Optional, Dict, Any
3
- from concurrent.futures import ThreadPoolExecutor
4
- from yake import KeywordExtractor
5
- from app.services.chathistory import ChatSession
6
- from app.services.websearch import WebSearch
7
- from app.services.llm_model import Model
8
- from app.services.environmental_condition import EnvironmentalData
9
- from app.services.prompts import *
10
- from app.services.vector_database_search import VectorDatabaseSearch
11
- import re
12
- import logging
13
-
14
- logger = logging.getLogger(__name__)
15
-
16
- # Initialize vector database with error handling
17
- try:
18
- vectordb = VectorDatabaseSearch()
19
- except Exception as e:
20
- logger.error(f"Failed to initialize vector database: {e}")
21
- vectordb = None
22
-
23
- class ChatProcessor:
24
- def __init__(self, token: str, session_id: Optional[str] = None, num_results: int = 3, num_images: int = 3):
25
- self.token = token
26
- self.session_id = session_id
27
- self.num_results = num_results
28
- self.num_images = num_images
29
- self.chat_session = ChatSession(token, session_id)
30
- self.user_city = self.chat_session.get_city()
31
- city = self.user_city if self.user_city else ''
32
- self.environment_data = EnvironmentalData(city)
33
- self.web_searcher = WebSearch(num_results=num_results, max_images=num_images)
34
- self.web_search_required = True
35
-
36
- def extract_keywords_yake(self, text: str, language: str, max_ngram_size: int = 2, num_keywords: int = 4) -> list:
37
- lang_code = "en"
38
- if language.lower() == "urdu":
39
- lang_code = "ur"
40
-
41
- kw_extractor = KeywordExtractor(
42
- lan=lang_code,
43
- n=max_ngram_size,
44
- top=num_keywords,
45
- features=None
46
- )
47
- keywords = kw_extractor.extract_keywords(text)
48
- return [kw[0] for kw in keywords]
49
-
50
- def ensure_valid_session(self, title: str = None) -> str:
51
- if not self.session_id or not self.session_id.strip():
52
- self.chat_session.create_new_session(title=title)
53
- self.session_id = self.chat_session.session_id
54
- else:
55
- try:
56
- if not self.chat_session.validate_session(self.session_id, title=title):
57
- self.chat_session.create_new_session(title=title)
58
- self.session_id = self.chat_session.session_id
59
- except ValueError:
60
- self.chat_session.create_new_session(title=title)
61
- self.session_id = self.chat_session.session_id
62
- return self.session_id
63
-
64
- def process_chat(self, query: str) -> Dict[str, Any]:
65
- try:
66
- profile = self.chat_session.get_name_and_age()
67
- name = profile['name']
68
- age = profile['age']
69
- self.chat_session.load_chat_history()
70
- self.chat_session.update_title(self.session_id, query)
71
- history = self.chat_session.format_history()
72
-
73
- # Enhanced query generation
74
- history_based_prompt = HISTORY_BASED_PROMPT.format(history=history, query=query)
75
- enhanced_query = Model().send_message_openrouter(history_based_prompt)
76
-
77
- self.session_id = self.ensure_valid_session(title=enhanced_query)
78
- permission = self.chat_session.get_user_preferences()
79
- websearch_enabled = permission.get('websearch', False)
80
- env_recommendations = permission.get('environmental_recommendations', False)
81
- personalized_recommendations = permission.get('personalized_recommendations', False)
82
- keywords_permission = permission.get('keywords', False)
83
- reference_permission = permission.get('references', False)
84
- language = self.chat_session.get_language().lower()
85
-
86
- language_prompt = LANGUAGE_RESPONSE_PROMPT.format(language=language)
87
-
88
- # Check if vector database is available when websearch is disabled
89
- vector_db_available = vectordb and vectordb.is_available() if not websearch_enabled else False
90
-
91
- # If websearch is disabled and vector DB is not available, enable websearch as fallback
92
- use_websearch = websearch_enabled or not vector_db_available
93
-
94
- if use_websearch:
95
- logger.info("Using web search for context")
96
- with ThreadPoolExecutor(max_workers=2) as executor:
97
- future_web = executor.submit(self.web_searcher.search, enhanced_query)
98
- future_images = executor.submit(self.web_searcher.search_images, enhanced_query)
99
- web_results = future_web.result()
100
- image_results = future_images.result()
101
-
102
- context_parts = []
103
- references = []
104
-
105
- for idx, result in enumerate(web_results, 1):
106
- if result['text']:
107
- context_parts.append(f"From Source {idx}: {result['text']}\n")
108
- references.append(result['link'])
109
-
110
- context = "\n".join(context_parts)
111
-
112
- # If web search returns no results, provide a helpful context
113
- if not context:
114
- context = "No specific information found. Please provide general dermatological advice based on your expertise."
115
-
116
- else:
117
- logger.info("Using vector database for context")
118
- attach_image = False
119
-
120
- with ThreadPoolExecutor(max_workers=1) as executor:
121
- future_images = executor.submit(self.web_searcher.search_images, enhanced_query)
122
- image_results = future_images.result()
123
-
124
- start_time = datetime.now(timezone.utc)
125
-
126
- # Search vector database
127
- if vectordb:
128
- results = vectordb.search(query=enhanced_query, top_k=5) # Increased top_k for better results
129
- else:
130
- results = []
131
-
132
- context_parts = []
133
- references = []
134
- seen_pages = set()
135
-
136
- for result in results:
137
- confidence = result.get('confidence', 0)
138
- # Lowered confidence threshold for better recall
139
- if confidence > 30:
140
- context_parts.append(f"Content: {result['content']}")
141
- source = result.get('source', 'Unknown')
142
- page = result.get('page', 0)
143
- page_key = f"{source}_{page}"
144
- if page_key not in seen_pages:
145
- references.append(f"Source: {source}, Page: {page}")
146
- seen_pages.add(page_key)
147
- attach_image = True
148
-
149
- context = "\n".join(context_parts)
150
-
151
- # Provide more helpful context when vector search returns nothing
152
- if not context or len(context) < 50:
153
- logger.warning("Vector database returned insufficient context")
154
- # Fall back to web search if available
155
- if self.web_searcher:
156
- logger.info("Falling back to web search due to insufficient vector results")
157
- web_results = self.web_searcher.search(enhanced_query)
158
- context_parts = []
159
- references = []
160
- for idx, result in enumerate(web_results[:3], 1):
161
- if result['text']:
162
- context_parts.append(f"From Source {idx}: {result['text']}\n")
163
- references.append(result['link'])
164
- context = "\n".join(context_parts)
165
-
166
- if not context:
167
- context = "Based on general dermatological knowledge and best practices."
168
- attach_image = False
169
-
170
- end_time = datetime.now(timezone.utc)
171
-
172
- # Generate appropriate prompt based on user preferences
173
- if env_recommendations and personalized_recommendations:
174
- prompt = ENVIRONMENTAL_PERSONALIZED_PROMPT.format(
175
- user_name=name,
176
- user_age=age,
177
- history=history,
178
- user_details=self.chat_session.get_personalized_recommendation(),
179
- environmental_condition=self.environment_data.get_environmental_data(),
180
- previous_history=history,
181
- context=context,
182
- current_query=enhanced_query
183
- )
184
- elif personalized_recommendations:
185
- prompt = PERSONALIZED_PROMPT.format(
186
- user_name=name,
187
- user_age=age,
188
- user_details=self.chat_session.get_personalized_recommendation(),
189
- previous_history=history,
190
- context=context,
191
- current_query=enhanced_query
192
- )
193
- elif env_recommendations:
194
- prompt = ENVIRONMENTAL_PROMPT.format(
195
- user_name=name,
196
- user_age=age,
197
- environmental_condition=self.environment_data.get_environmental_data(),
198
- previous_history=history,
199
- context=context,
200
- current_query=enhanced_query
201
- )
202
- else:
203
- prompt = DEFAULT_PROMPT.format(
204
- previous_history=history,
205
- context=context,
206
- current_query=enhanced_query
207
- )
208
-
209
- prompt = prompt + "\n" + language_prompt
210
-
211
- # Generate response
212
- response = Model().llm(prompt, enhanced_query)
213
-
214
- # Extract keywords if enabled
215
- keywords = ""
216
- if keywords_permission:
217
- keywords = self.extract_keywords_yake(response, language=language)
218
-
219
- if not reference_permission:
220
- references = ""
221
-
222
- # Prepare images
223
- if not use_websearch and not attach_image:
224
- image_results = ""
225
- keywords = ""
226
-
227
- # Prepare chat data
228
- chat_data = {
229
- "query": enhanced_query,
230
- "response": response,
231
- "references": references,
232
- "page_no": "",
233
- "keywords": keywords,
234
- "images": image_results if 'image_results' in locals() else "",
235
- "context": context,
236
- "timestamp": datetime.now(timezone.utc).isoformat(),
237
- "session_id": self.chat_session.session_id
238
- }
239
-
240
- # Save RAG details if using vector database
241
- if not use_websearch and 'start_time' in locals() and 'end_time' in locals():
242
- match = re.search(r'(## Personal Recommendations|## Environmental Considerations)', response)
243
- truncated_response = response[:match.start()].strip() if match else response
244
-
245
- if not self.chat_session.save_details(
246
- session_id=self.session_id,
247
- context=context,
248
- query=enhanced_query,
249
- response=truncated_response,
250
- rag_start_time=start_time,
251
- rag_end_time=end_time
252
- ):
253
- logger.warning("Failed to save RAG details")
254
-
255
- # Save chat
256
- if not self.chat_session.save_chat(chat_data):
257
- raise ValueError("Failed to save chat message")
258
-
259
- return chat_data
260
-
261
- except Exception as e:
262
- logger.error(f"Error in process_chat: {str(e)}")
263
- return {
264
- "error": str(e),
265
- "query": query,
266
- "response": "I apologize, but I'm experiencing technical difficulties. Please try again or enable web search in your preferences for better results.",
267
- "timestamp": datetime.now(timezone.utc).isoformat()
268
- }
269
-
270
- def web_search(self, query: str) -> Dict[str, Any]:
271
- """Public method for web search endpoint"""
272
- return self.process_chat(query=query)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/services/prompts.py CHANGED
@@ -1,230 +1,3 @@
1
- HISTORY_BASED_PROMPT = """
2
- You are an expert in formulating queries based on history. You have no concern with the answer to the user's question; your focus is solely on the question asked by the user.
3
-
4
- History: {history}
5
-
6
- new_question_by_human: {query}
7
-
8
- Given the conversation history and the new question, return only the concise question that should be understood by a web search engine. Ensure that the final question correctly reflects the context of the conversation, especially when a specific term (like things "disease", "person", "anything") is implied. Do not include any explanation or additional text, just return the final question and remember if the question is not related to history then just write the same question without changing anything even a single word.
9
-
10
- Weather what language give you, you should strictly just response english
11
- """
12
-
13
- DEFAULT_PROMPT = """
14
- Previous Conversation Context:
15
- {previous_history}
16
-
17
- You are a professional dermatologist with years of clinical experience. Your name is Dr. Derma, and you're here to provide medically accurate skin care advice.
18
-
19
- Respond to the user's question based STRICTLY on the following context information. If the context doesn't contain sufficient information, clearly state: "As a dermatologist, I don't have enough specific information about this in my reference materials."
20
-
21
- Context:
22
- {context}
23
- User Question: {current_query}
24
-
25
- Important guidelines:
26
- 1. Only answer medical/dermatological questions or engage in casual conversation. For any other topics, politely redirect the conversation to skin health.
27
- 2. Always maintain a professional, caring tone typical of an experienced dermatologist.
28
- 3. Never mention that you're using "context" or following instructions - speak naturally as a real doctor would.
29
- 4. For non-medical casual questions, provide brief, friendly responses while subtly steering back to dermatology topics.
30
- 5. Never make up medical information - if the context doesn't provide sufficient information, acknowledge the limitations.
31
-
32
- Response format:
33
- - For dermatological questions: Provide clear, concise medical information using your expertise.
34
- - For greetings/casual conversation: Respond warmly but concisely as a friendly dermatologist would.
35
- - For non-dermatological questions: Politely note that as a dermatologist, you focus on skin health topics, and offer to help with any skin-related concerns.
36
-
37
- End your response with: "*For proper medical advice, an in-person consultation is always recommended.*"
38
- """
39
-
40
- PERSONALIZED_PROMPT = """
41
- I am speaking with {user_name}, age {user_age}.
42
-
43
- Patient Information:
44
- <user_details>
45
- {user_details}
46
- </user_details>
47
-
48
- Previous Conversation:
49
- {previous_history}
50
-
51
- I am Dr. Derma, a board-certified dermatologist with 15+ years of experience. I will provide personalized dermatological advice based exclusively on the following clinical reference materials:
52
-
53
- Reference Materials:
54
- {context}
55
-
56
- Patient Question: {current_query}
57
-
58
- As a dermatologist, I will:
59
- 1. Answer ONLY with information supported by my reference materials
60
- 2. Speak naturally as I would in my clinic, without referencing "context" or "instructions"
61
- 3. Maintain a professional yet warm tone appropriate for a doctor-patient relationship
62
- 4. Only discuss dermatological topics and casual conversation - for unrelated topics, I'll gently redirect to skin health
63
- 5. ALWAYS include a "Personal Recommendations" section when answering medical questions
64
-
65
- For dermatological questions:
66
- ## [Relevant Medical Topic]
67
- [Main clinical answer based strictly on reference materials]
68
-
69
- ## Personal Recommendations
70
- [Specific recommendations considering the patient's age, skin type, medical history, and other relevant factors from their profile]
71
-
72
- *These recommendations are based on limited information. For proper diagnosis and treatment, an in-person consultation is always recommended.*
73
- """
74
-
75
- ENVIRONMENTAL_PROMPT = """
76
- I am speaking with {user_name}, age {user_age}.
77
-
78
- Environmental Factors:
79
- <environmental_info>
80
- {environmental_condition}
81
- </environmental_info>
82
-
83
- Previous Conversation:
84
- {previous_history}
85
-
86
- I am Dr. Derma, a board-certified dermatologist with 15+ years of experience. I will provide environmentally-conscious dermatological advice based exclusively on the following clinical reference materials:
87
-
88
- Reference Materials:
89
- {context}
90
-
91
- Patient Question: {current_query}
92
-
93
- As a dermatologist, I will:
94
- 1. Answer ONLY with information supported by my reference materials
95
- 2. Speak naturally as I would in my clinic, without referencing "context" or "instructions"
96
- 3. Maintain a professional yet warm tone appropriate for a doctor-patient relationship
97
- 4. Only discuss dermatological topics and casual conversation - for unrelated topics, I'll gently redirect to skin health
98
- 5. ALWAYS include an "Environmental Considerations" section when answering medical questions
99
-
100
- For dermatological questions:
101
- ## [Relevant Medical Topic]
102
- [Main clinical answer based strictly on reference materials]
103
-
104
- ## Environmental Considerations
105
- [Specific recommendations considering local climate, pollution levels, UV index, and other environmental factors]
106
-
107
- *These recommendations are based on limited information. For proper diagnosis and treatment, an in-person consultation is always recommended.*
108
- """
109
-
110
-
111
- ENVIRONMENTAL_PERSONALIZED_PROMPT = """
112
- I am speaking with {user_name}, age {user_age}.
113
-
114
- Patient Information:
115
- <user_details>
116
- {user_details}
117
- </user_details>
118
-
119
- Environmental Factors:
120
- <environmental_info>
121
- {environmental_condition}
122
- </environmental_info>
123
-
124
- Previous Conversation:
125
- {previous_history}
126
-
127
- I am Dr. Derma, a board-certified dermatologist with 15+ years of experience. I will provide comprehensive dermatological advice based exclusively on the following clinical reference materials:
128
-
129
- Reference Materials:
130
- {context}
131
-
132
- Patient Question: {current_query}
133
-
134
- As a dermatologist, I will:
135
- 1. Answer ONLY with information supported by my reference materials
136
- 2. Speak naturally as I would in my clinic, without referencing "context" or "instructions"
137
- 3. Maintain a professional yet warm tone appropriate for a doctor-patient relationship
138
- 4. Only discuss dermatological topics and casual conversation - for unrelated topics, I'll gently redirect to skin health
139
- 5. ALWAYS include BOTH "Personal Recommendations" AND "Environmental Considerations" sections when answering medical questions
140
-
141
- For dermatological questions:
142
- ## [Relevant Medical Topic]
143
- [Main clinical answer based strictly on reference materials]
144
-
145
- ## Personal Recommendations
146
- [Specific recommendations considering the patient's age, skin type, medical history, and other relevant factors from their profile]
147
-
148
- ## Environmental Considerations
149
- [Specific recommendations considering local climate, pollution levels, UV index, and other environmental factors]
150
-
151
- *These recommendations are based on limited information. For proper diagnosis and treatment, an in-person consultation is always recommended.*
152
- """
153
-
154
- MEDICAL_REPORT_ANALYSIS_PROMPT = """
155
- You are an advanced medical report analysis system specializing in dermatology. Your purpose is to analyze and interpret the medical report for patient with the highest level of accuracy and clinical relevance.
156
-
157
- CONTEXT AND CONSTRAINTS:
158
- - Base your analysis EXCLUSIVELY on the provided medical report content
159
- - Do not make assumptions or introduce external medical knowledge
160
- - Maintain strict medical privacy and confidentiality standards
161
-
162
- MEDICAL REPORT:
163
- {report}
164
-
165
- CURRENT QUERY:
166
- {current_query}
167
-
168
- ANALYSIS GUIDELINES:
169
- 1. Primary Findings
170
- - Identify and explain key clinical observations
171
- - Highlight any critical diagnostic information
172
- - Note any abnormal results or concerning findings
173
-
174
- 2. Clinical Interpretation
175
- - Analyze the findings in their clinical context
176
- - Connect related symptoms and observations
177
- - Identify any patterns or correlations in the data
178
-
179
- 3. Response Format:
180
- - Start with a clear, direct answer to the query
181
- - Support your response with specific evidence from the report
182
- - Use medical terminology appropriately with plain language explanations
183
- - Clearly separate facts from interpretations
184
- - Structure information in a logical, easy-to-follow manner
185
-
186
- 4. Information Gaps:
187
- - If any critical information is missing, clearly state: "The report does not contain sufficient information regarding [specific aspect]"
188
- - Specify what additional information would be needed for a complete assessment
189
-
190
- IMPORTANT NOTES:
191
- - If the report contains laboratory values or measurements, include the relevant numbers and reference ranges
192
- - For any medical terms used, provide brief explanations in parentheses
193
- - If multiple interpretations are possible, list them in order of likelihood based on the report data
194
- - Flag any urgent or critical findings that may require immediate attention
195
-
196
- Please analyze the provided report and respond to the query while adhering to these guidelines. Maintain professional medical communication standards while ensuring clarity for the reader.
197
-
198
- [At Last add this disclaimer]
199
- *We acknowledge the possibility of errors, so it is always recommended to consult with a doctor for a thorough check-up.*
200
-
201
- And If the report is not Related to Medical the just write
202
- `Sorry Please upload Medical related Report`
203
- """
204
-
205
-
206
-
207
- LANGUAGE_RESPONSE_PROMPT = """
208
- STRICT LANGUAGE REQUIREMENTS:
209
- 1. Response must be written EXCLUSIVELY in {language} using its official script/orthography
210
- 2. English terms ONLY permitted when:
211
- - There's no direct translation (technical terms/proper nouns)
212
- - Retention is crucial for meaning preservation
213
- 3. STRICTLY PROHIBITED:
214
- - Code-switching/mixing languages
215
- - Transliterations of {language} words using Latin script
216
- - Non-native punctuation/formatting
217
- 4. Ensure:
218
- - Correct grammatical structure for {language}
219
- - Proper script-specific punctuation
220
- - Native character set compliance
221
- 5. Formatting must follow {language}'s typographical conventions
222
- 6. If unsure about translations: Use native {language} equivalents first
223
-
224
- Respond ONLY in {language} script. Never include translations/explanations.
225
- """
226
-
227
-
228
  SKIN_CARE_SCHEDULER = """As a skincare expert, generate a daily schedule based on:
229
  - User's skin profile: {personalized_condition}
230
  - Current environmental conditions: {environmental_values}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
  SKIN_CARE_SCHEDULER = """As a skincare expert, generate a daily schedule based on:
2
  - User's skin profile: {personalized_condition}
3
  - Current environmental conditions: {environmental_values}