Amogh1221 commited on
Commit
63e75cd
·
verified ·
1 Parent(s): 73b3d4a

Update services/conversation_orchestrator.py

Browse files
Files changed (1) hide show
  1. services/conversation_orchestrator.py +70 -34
services/conversation_orchestrator.py CHANGED
@@ -54,9 +54,17 @@ class ConversationOrchestrator:
54
  self.session_store.append_message(session_id, "user", user_message)
55
 
56
  history = self.session_store.get_working_context(session_id, llm_engine=self.llm_provider)
57
-
 
 
 
 
 
 
58
  try:
59
- llm1_response = self.llm_provider.psychiatrist_response(history, patient_info)
 
 
60
  log.llm1_decision(llm1_response)
61
 
62
  base_risk = self.risk_service.assess(message, llm1_response, None)
@@ -76,7 +84,12 @@ class ConversationOrchestrator:
76
 
77
  # Synchronous execution of LLM2 pipeline
78
  if intent == "ANALYZE" and patient_id:
79
- llm2_message = self._run_sync_analysis(session_id, patient_id, llm1_response.clinical_summary, llm1_response.assistant_message)
 
 
 
 
 
80
  if llm2_message:
81
  final_message = llm2_message
82
 
@@ -106,9 +119,25 @@ class ConversationOrchestrator:
106
  clinical_summary=None
107
  )
108
 
109
- def _run_sync_analysis(self, session_id: str, patient_id: str, clinical_summary: Optional[str] = None, llm1_draft: Optional[str] = None) -> Optional[str]:
 
 
 
 
 
 
 
110
  """
111
- Executes the heavy LLM2 pattern analysis synchronously and returns the LLM2 generated response.
 
 
 
 
 
 
 
 
 
112
  """
113
  session_number = self.session_store.get_session_count(patient_id) if patient_id else 1
114
  log = get_logger(session_id, "Sync Analysis Task", session_number)
@@ -129,48 +158,55 @@ class ConversationOrchestrator:
129
  retrieved_context = self.vector_store.retrieve(retrieval_query)
130
  log.retrieved_context(retrieved_context)
131
 
132
- existing_profile_recap = self.profile_store.build_profile_recap(patient_id) or "No previous clinical profile exists for this patient."
133
-
134
  patient_info = self.profile_store.get_patient(patient_id) if patient_id else None
135
- demographics = ""
 
 
 
 
136
  if patient_info:
137
- demographics = (
138
  f"PATIENT DEMOGRAPHICS:\n"
139
  f"- Name: {patient_info.get('name', 'Unknown')}\n"
140
  f"- Age: {patient_info.get('age', 'Unknown')}\n"
141
  f"- Gender: {patient_info.get('gender', 'Unknown')}\n"
142
  f"- Nationality: {patient_info.get('nationality', 'Unknown')}\n"
143
- f"- Primary Concern: {patient_info.get('primary_concern', 'Unknown')}\n\n"
144
  )
145
-
146
- context_prompt = (
147
- f"{demographics}"
148
- f"Existing Clinical Profile:\n{existing_profile_recap}\n\n"
149
- )
 
 
 
 
 
 
 
150
  if clinical_summary and clinical_summary.strip():
151
- context_prompt += f"Current Session Clinical Summary:\n{clinical_summary}\n\n"
152
-
153
- context_prompt += (
154
- f"Retrieved Clinical Reference (Sims' Symptoms in the Mind):\n{retrieved_context}\n\n"
155
  )
156
-
157
  if llm1_draft:
158
- context_prompt += (
159
- f"Intern's Draft Response:\n{llm1_draft}\n\n"
160
- )
161
-
162
- context_prompt += (
163
- "Please perform pattern analysis across all eight domains. Evaluate how the user is behaving now (based on the current session messages and summary) compared to their existing profile, and output the updated patterns. "
164
- "You must also review the Intern's Draft Response, refine and amplify it using your deeper clinical insights, and provide the final polished conversational response."
165
  )
166
-
167
- llm2_input = history[-10:] + [{
168
- "role": "user",
169
- "content": context_prompt
170
- }]
171
- llm2_response = self.llm_provider.internal_reasoning(llm2_input)
172
  log.llm2_output(llm2_response)
173
-
174
  self.profile_store.update_long_term_memory(patient_id, llm2_response)
175
  serinity_logger.info(f"Synchronous analysis completed for patient {patient_id}.")
176
  return llm2_response.assistant_message
 
54
  self.session_store.append_message(session_id, "user", user_message)
55
 
56
  history = self.session_store.get_working_context(session_id, llm_engine=self.llm_provider)
57
+
58
+ # Build medium-term memory once — constant within a session, stable between LLM2 updates.
59
+ # Passed to LLM1 as a cached context block and reused in LLM2 via _run_sync_analysis.
60
+ medium_term_memory: Optional[str] = None
61
+ if patient_id:
62
+ medium_term_memory = self.profile_store.build_profile_recap(patient_id)
63
+
64
  try:
65
+ llm1_response = self.llm_provider.psychiatrist_response(
66
+ history, patient_info, medium_term_memory=medium_term_memory
67
+ )
68
  log.llm1_decision(llm1_response)
69
 
70
  base_risk = self.risk_service.assess(message, llm1_response, None)
 
84
 
85
  # Synchronous execution of LLM2 pipeline
86
  if intent == "ANALYZE" and patient_id:
87
+ llm2_message = self._run_sync_analysis(
88
+ session_id, patient_id,
89
+ llm1_response.clinical_summary,
90
+ llm1_response.assistant_message,
91
+ medium_term_memory=medium_term_memory,
92
+ )
93
  if llm2_message:
94
  final_message = llm2_message
95
 
 
119
  clinical_summary=None
120
  )
121
 
122
+ def _run_sync_analysis(
123
+ self,
124
+ session_id: str,
125
+ patient_id: str,
126
+ clinical_summary: Optional[str] = None,
127
+ llm1_draft: Optional[str] = None,
128
+ medium_term_memory: Optional[str] = None,
129
+ ) -> Optional[str]:
130
  """
131
+ Executes the heavy LLM2 pattern analysis synchronously.
132
+
133
+ Groq caching layers:
134
+ [1] system, cached LLM2_SYSTEM_PROMPT (constant — provider handles this)
135
+ [2] user, cached stable_prefix (demographics + medium-term memory;
136
+ constant between LLM2 calls)
137
+ [3] dynamic history[-6:] + context (RAG + session summary + draft)
138
+
139
+ `medium_term_memory` is passed in from handle_message (already fetched once)
140
+ to avoid a redundant DB round-trip.
141
  """
142
  session_number = self.session_store.get_session_count(patient_id) if patient_id else 1
143
  log = get_logger(session_id, "Sync Analysis Task", session_number)
 
158
  retrieved_context = self.vector_store.retrieve(retrieval_query)
159
  log.retrieved_context(retrieved_context)
160
 
 
 
161
  patient_info = self.profile_store.get_patient(patient_id) if patient_id else None
162
+
163
+ # --- Build stable_prefix (cached at the provider) ---
164
+ # Contains demographics + medium-term memory. These are constant between
165
+ # LLM2 calls, so Groq can serve them from cache after the first warm-up.
166
+ stable_parts = []
167
  if patient_info:
168
+ stable_parts.append(
169
  f"PATIENT DEMOGRAPHICS:\n"
170
  f"- Name: {patient_info.get('name', 'Unknown')}\n"
171
  f"- Age: {patient_info.get('age', 'Unknown')}\n"
172
  f"- Gender: {patient_info.get('gender', 'Unknown')}\n"
173
  f"- Nationality: {patient_info.get('nationality', 'Unknown')}\n"
174
+ f"- Primary Concern: {patient_info.get('primary_concern', 'Unknown')}"
175
  )
176
+ mtm = medium_term_memory or self.profile_store.build_profile_recap(patient_id)
177
+ if mtm:
178
+ stable_parts.append(
179
+ f"PATIENT MEDIUM-TERM MEMORY (prior sessions & profile — do not quote verbatim):\n"
180
+ f"{mtm}"
181
+ )
182
+ stable_prefix = "\n\n".join(stable_parts) if stable_parts else None
183
+
184
+ # --- Build dynamic context_prompt (only the changing parts) ---
185
+ # Demographics + MTM are now in stable_prefix (cached), so we only
186
+ # include the truly dynamic content here.
187
+ context_parts = []
188
  if clinical_summary and clinical_summary.strip():
189
+ context_parts.append(f"Current Session Clinical Summary:\n{clinical_summary}")
190
+ context_parts.append(
191
+ f"Retrieved Clinical Reference (Sims' Symptoms in the Mind):\n{retrieved_context}"
 
192
  )
 
193
  if llm1_draft:
194
+ context_parts.append(f"Intern's Draft Response:\n{llm1_draft}")
195
+ context_parts.append(
196
+ "Please perform pattern analysis across all eight domains. Evaluate how the user "
197
+ "is behaving now (based on the current session messages and summary) compared to "
198
+ "their existing profile, and output the updated patterns. You must also review the "
199
+ "Intern's Draft Response, refine and amplify it using your deeper clinical insights, "
200
+ "and provide the final polished conversational response."
201
  )
202
+ context_prompt = "\n\n".join(context_parts)
203
+
204
+ # history[-6:] reduces TPM by ~35% vs [-10:]; profile_recap + rolling
205
+ # summary already carry the earlier context, so quality loss is negligible.
206
+ llm2_input = history[-6:] + [{"role": "user", "content": context_prompt}]
207
+ llm2_response = self.llm_provider.internal_reasoning(llm2_input, stable_prefix=stable_prefix)
208
  log.llm2_output(llm2_response)
209
+
210
  self.profile_store.update_long_term_memory(patient_id, llm2_response)
211
  serinity_logger.info(f"Synchronous analysis completed for patient {patient_id}.")
212
  return llm2_response.assistant_message