Spaces:
Running
Running
Commit
·
1ef76e3
1
Parent(s):
c5a8382
update
Browse files- app/routers/chat.py +0 -27
- app/services/__init__.py +0 -2
- app/services/agentic_prompt.py +124 -40
- app/services/chat_processor.py +0 -272
- app/services/prompts.py +0 -227
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
|
|
|
|
| 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 |
-
|
| 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 |
-
|
| 127 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 142 |
)
|
| 143 |
prompt_lines.append(
|
| 144 |
-
"
|
| 145 |
-
|
| 146 |
|
| 147 |
prompt_lines.extend(
|
| 148 |
[
|
| 149 |
-
"1.
|
| 150 |
-
"
|
| 151 |
-
"
|
| 152 |
-
"
|
| 153 |
-
"
|
| 154 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
]
|
| 156 |
)
|
| 157 |
|
| 158 |
prompt_lines.extend(
|
| 159 |
[
|
| 160 |
"",
|
| 161 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 173 |
-
"- Step 2:
|
| 174 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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
|
| 203 |
)
|
| 204 |
prompt_lines.append(
|
| 205 |
-
"
|
| 206 |
)
|
| 207 |
|
| 208 |
prompt_lines.extend(
|
| 209 |
[
|
| 210 |
-
"1.
|
| 211 |
-
"
|
| 212 |
-
"
|
| 213 |
-
"
|
| 214 |
-
"
|
| 215 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 216 |
]
|
| 217 |
)
|
| 218 |
|
| 219 |
prompt_lines.extend(
|
| 220 |
[
|
| 221 |
"",
|
| 222 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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:
|
| 234 |
-
"- Step 2:
|
| 235 |
-
"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 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}
|