Yaswanth123 commited on
Commit
e0d1ba6
·
verified ·
1 Parent(s): 9064aae

Update orchestrator.py

Browse files
Files changed (1) hide show
  1. orchestrator.py +70 -21
orchestrator.py CHANGED
@@ -40,24 +40,36 @@ It is provided for Your reference after the user has uploaded a resource.
40
  This information is primarily for understanding the context of the user's resource.
41
  For the syllabus, you should provide either the raw data or a dynamic summary.\n"""
42
 
43
- if dspy.settings.lm:
44
- CONVO_MANAGER = ConversationManager()
45
- SYLLABUS_ROUTER = SyllabusGeneratorRouter()
46
- INITIAL_RESOURCE_SUMMARIZER = InitialResourceSummarizer()
47
- DYNAMIC_SUMMARIZER_MODULE = DynamicResourceSummarizerModule()
48
- LEARNING_STYLE_QUESTIONER = LearningStyleQuestioner()
49
- PERSONA_PROMPT_GENERATOR = PersonaPromptGenerator()
50
- EXPLAINER_MODULE = ExplainerModule()
51
- SYLLABUS_FEEDBACK_REQUESTER = dspy.Predict(SyllabusFeedbackRequestSignature, temperature=0.7)
52
- SYLLABUS_XML_TO_MARKDOWN_FORMATTER = dspy.Predict(FormatSyllabusXMLToMarkdown, temperature=0.3)
53
- TITLE_GENERATOR_PREDICTOR = dspy.Predict(TitleGenerationSignature, temperature=0.4)
54
- logger.info("Orchestrator's DSPy modules initialized successfully.")
55
- else:
56
- logger.critical("Orchestrator loaded, but DSPy LM is NOT configured. This will cause errors when the orchestrator is called.")
57
- # Set all modules to None so we can check for their existence and fail gracefully.
58
- CONVO_MANAGER, SYLLABUS_ROUTER, INITIAL_RESOURCE_SUMMARIZER, DYNAMIC_SUMMARIZER_MODULE, \
59
- LEARNING_STYLE_QUESTIONER, PERSONA_PROMPT_GENERATOR, EXPLAINER_MODULE, TITLE_GENERATOR_PREDICTOR, \
60
- SYLLABUS_FEEDBACK_REQUESTER, SYLLABUS_XML_TO_MARKDOWN_FORMATTER = (None,) * 10
 
 
 
 
 
 
 
 
 
 
 
 
61
 
62
  # --- Helper functions and the main process_chat_message function follow below ---
63
  # (The rest of your file remains the same)
@@ -138,6 +150,11 @@ def process_chat_message(
138
  Processes user message using DSPy modules.
139
  Handles initial resource processing if `uploaded_resource_data` is provided.
140
  """
 
 
 
 
 
141
  if not CONVO_MANAGER:
142
  logger.error("Orchestrator's DSPy modules are not initialized. Cannot process message.")
143
  # Return an error state immediately
@@ -145,7 +162,8 @@ def process_chat_message(
145
  error_state[STATE_STAGE] = STAGE_ERROR
146
  error_state[STATE_HISTORY].append({'role': 'user', 'parts': [{'text': user_message_text}]})
147
  error_state[STATE_HISTORY].append({'role': 'model', 'parts': [{'text': "[FATAL ERROR: AI modules not initialized. Please contact support.]"}]})
148
- return "[FATAL ERROR: AI modules not initialized]", error_state
 
149
 
150
 
151
  new_state = current_session_state.copy()
@@ -169,7 +187,10 @@ def process_chat_message(
169
  # --- Initial Resource Processing (only if resources are provided AND it's the start of negotiation) ---
170
  #Resources can Be only Uploaded at the start.
171
  if stage == STAGE_START and uploaded_resource_data:
 
 
172
  logger.info("First turn with resources. Processing them now...")
 
173
 
174
  total_chars = sum(len(text) for text in uploaded_resource_data.values())
175
 
@@ -218,6 +239,7 @@ def process_chat_message(
218
  if stage == STAGE_START:
219
  new_state[STATE_STAGE] = STAGE_NEGOTIATING
220
  stage = STAGE_NEGOTIATING # Update local stage variable
 
221
 
222
  logger.info(f"Orchestrator (DSPy): Stage={stage}. Calling ConversationManager.")
223
 
@@ -228,6 +250,8 @@ def process_chat_message(
228
 
229
  # Get resource overview from state if set, otherwise "None"
230
  resource_overview_for_manager = new_state.get(STATE_RESOURCE_SUMMARY_OVERVIEW, "No resources were processed or provided by the user for this session.")
 
 
231
 
232
  action_code, display_text = CONVO_MANAGER.forward(
233
  conversation_history_str=history_str,
@@ -245,6 +269,9 @@ def process_chat_message(
245
 
246
  # --- Handle Actions from ConversationManager ---
247
  if action_code in ["GENERATE", "MODIFY"]:
 
 
 
248
  task_type_str = "generation" if action_code == "GENERATE" else "modification"
249
  logger.info(f"Syllabus {task_type_str} requested. Resource type: {new_state.get(STATE_RESOURCE_TYPE_FOR_SYLLABUS)}")
250
  retrieved_resource_type = new_state.get(STATE_RESOURCE_TYPE_FOR_SYLLABUS, "NONE")
@@ -257,6 +284,8 @@ def process_chat_message(
257
  logger.info(f"Syllabus {task_type_str} requested. Resource type from state: {retrieved_resource_type}")
258
  # If type is SUMMARIES, we need to generate them now using DynamicSummarizer
259
  if retrieved_resource_type == "SUMMARIES":
 
 
260
  raw_data_for_dynamic_summary = new_state.get('raw_resource_data_for_dynamic_summary')
261
  if raw_data_for_dynamic_summary and isinstance(raw_data_for_dynamic_summary, dict):
262
  logger.info("Generating dynamic summaries for syllabus router...")
@@ -296,7 +325,11 @@ def process_chat_message(
296
  # --- BLOCK 1: XML to Markdown Formatting (and set success flag) ---
297
  if generated_xml and not generated_xml.strip().upper().startswith(("<SYLLABUS>\n[ERROR", "<SYLLABUS>[ERROR")):
298
  syllabus_generation_was_successful = True # Mark initial generation as successful
 
 
299
  logger.info(f"Syllabus XML generated. Length: {len(generated_xml)}. Attempting Markdown formatting.")
 
 
300
 
301
  if SYLLABUS_XML_TO_MARKDOWN_FORMATTER:
302
  try:
@@ -370,6 +403,8 @@ def process_chat_message(
370
  logger.info("Finalization requested by manager.")
371
  last_syllabus_in_history = get_last_syllabus_content_from_history(history)
372
  if last_syllabus_in_history:
 
 
373
  new_state[STATE_FINAL_SYLLABUS] = f"<syllabus>\n{last_syllabus_in_history}\n</syllabus>" # Store it
374
 
375
  # Ask for learning style
@@ -384,9 +419,12 @@ def process_chat_message(
384
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
385
 
386
  elif action_code == "PERSONA":
 
387
  logger.info("Persona generation triggered by manager.")
388
  final_syllabus_xml_str = new_state.get(STATE_FINAL_SYLLABUS)
389
  if final_syllabus_xml_str:
 
 
390
  logger.info("Generating explainer prompt body...")
391
  explainer_prompt_body = PERSONA_PROMPT_GENERATOR.forward(
392
  conversation_history_str=format_history_for_dspy(history)
@@ -408,6 +446,8 @@ def process_chat_message(
408
  history_str="None", # No prior *explainer* history for this first turn
409
  user_query_str=explainer_intro_query
410
  )
 
 
411
  ai_reply_for_user = explainer_intro_response
412
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
413
  else:
@@ -434,7 +474,11 @@ def process_chat_message(
434
 
435
  # --- Explanation Phase (STAGE_EXPLAINING) ---
436
  elif stage == STAGE_EXPLAINING:
 
 
437
  logger.info(f"Orchestrator (DSPy): Stage={stage}. Calling ExplainerModule.")
 
 
438
  explainer_sys_prompt = modified_explainer_prompt or new_state.get(STATE_EXPLAINER_PROMPT)
439
  expl_start_idx = new_state.get(STATE_EXPLANATION_START_INDEX, 0)
440
 
@@ -498,10 +542,15 @@ def process_chat_message(
498
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
499
 
500
  # --- Final State Update & Return ---
501
- new_state[STATE_HISTORY] = history
502
  logger.debug(f"Orchestrator (DSPy) returning: Stage='{new_state.get(STATE_STAGE)}', History Len={len(history)}, AI Reply starts: '{ai_reply_for_user[:50]}...'")
503
  logger.debug(f"Flags: DisplaySyllabus='{new_state.get(STATE_DISPLAY_SYLLABUS_FLAG) is not None}', TransitionExplainer='{new_state.get(STATE_TRANSITION_EXPLAINER_FLAG)}'")
 
 
504
 
505
- return ai_reply_for_user, new_state
 
 
 
506
 
507
 
 
40
  This information is primarily for understanding the context of the user's resource.
41
  For the syllabus, you should provide either the raw data or a dynamic summary.\n"""
42
 
43
+ def initialize_orchestrator_modules():
44
+ """
45
+ Instantiates all DSPy modules AFTER the LM has been configured.
46
+ This function must be called from the main app script.
47
+ """
48
+ global CONVO_MANAGER, SYLLABUS_ROUTER, INITIAL_RESOURCE_SUMMARIZER, DYNAMIC_SUMMARIZER_MODULE, \
49
+ LEARNING_STYLE_QUESTIONER, PERSONA_PROMPT_GENERATOR, EXPLAINER_MODULE, SYLLABUS_FEEDBACK_REQUESTER, \
50
+ SYLLABUS_XML_TO_MARKDOWN_FORMATTER, TITLE_GENERATOR_PREDICTOR
51
+
52
+ if not dspy.settings.lm:
53
+ logger.error("Cannot initialize orchestrator modules: DSPy LM is not configured.")
54
+ return False
55
+
56
+ try:
57
+ CONVO_MANAGER = ConversationManager()
58
+ SYLLABUS_ROUTER = SyllabusGeneratorRouter()
59
+ INITIAL_RESOURCE_SUMMARIZER = InitialResourceSummarizer()
60
+ DYNAMIC_SUMMARIZER_MODULE = DynamicResourceSummarizerModule()
61
+ LEARNING_STYLE_QUESTIONER = LearningStyleQuestioner()
62
+ PERSONA_PROMPT_GENERATOR = PersonaPromptGenerator()
63
+ EXPLAINER_MODULE = ExplainerModule()
64
+ SYLLABUS_FEEDBACK_REQUESTER = dspy.Predict(SyllabusFeedbackRequestSignature, temperature=0.7)
65
+ SYLLABUS_XML_TO_MARKDOWN_FORMATTER = dspy.Predict(FormatSyllabusXMLToMarkdown, temperature=0.3)
66
+ TITLE_GENERATOR_PREDICTOR = dspy.Predict(TitleGenerationSignature, temperature=0.4)
67
+ logger.info("Orchestrator's DSPy modules initialized successfully.")
68
+ return True
69
+ except Exception as e:
70
+ logger.critical(f"A critical error occurred during orchestrator module initialization: {e}", exc_info=True)
71
+ return False
72
+
73
 
74
  # --- Helper functions and the main process_chat_message function follow below ---
75
  # (The rest of your file remains the same)
 
150
  Processes user message using DSPy modules.
151
  Handles initial resource processing if `uploaded_resource_data` is provided.
152
  """
153
+
154
+ # def yield_feedback(state_to_update: Dict, feedback_key: str):
155
+ # feedback_state = state_to_update.copy()
156
+ # feedback_state[STATE_UI_FEEDBACK_MESSAGE] = UI_FEEDBACK_MAP.get(feedback_key, "Processing...")
157
+ # return feedback_state
158
  if not CONVO_MANAGER:
159
  logger.error("Orchestrator's DSPy modules are not initialized. Cannot process message.")
160
  # Return an error state immediately
 
162
  error_state[STATE_STAGE] = STAGE_ERROR
163
  error_state[STATE_HISTORY].append({'role': 'user', 'parts': [{'text': user_message_text}]})
164
  error_state[STATE_HISTORY].append({'role': 'model', 'parts': [{'text': "[FATAL ERROR: AI modules not initialized. Please contact support.]"}]})
165
+ yield ("final_result", error_state)
166
+ return
167
 
168
 
169
  new_state = current_session_state.copy()
 
187
  # --- Initial Resource Processing (only if resources are provided AND it's the start of negotiation) ---
188
  #Resources can Be only Uploaded at the start.
189
  if stage == STAGE_START and uploaded_resource_data:
190
+ yield ("status", "ANALYZING_RESOURCES_INITIAL")
191
+
192
  logger.info("First turn with resources. Processing them now...")
193
+
194
 
195
  total_chars = sum(len(text) for text in uploaded_resource_data.values())
196
 
 
239
  if stage == STAGE_START:
240
  new_state[STATE_STAGE] = STAGE_NEGOTIATING
241
  stage = STAGE_NEGOTIATING # Update local stage variable
242
+
243
 
244
  logger.info(f"Orchestrator (DSPy): Stage={stage}. Calling ConversationManager.")
245
 
 
250
 
251
  # Get resource overview from state if set, otherwise "None"
252
  resource_overview_for_manager = new_state.get(STATE_RESOURCE_SUMMARY_OVERVIEW, "No resources were processed or provided by the user for this session.")
253
+ # yield yield_feedback(new_state, "PROCESSING_INPUT")
254
+ yield ("status", "PROCESSING_INPUT")
255
 
256
  action_code, display_text = CONVO_MANAGER.forward(
257
  conversation_history_str=history_str,
 
269
 
270
  # --- Handle Actions from ConversationManager ---
271
  if action_code in ["GENERATE", "MODIFY"]:
272
+ yield ("status", "GENERATING_SYLLABUS")
273
+
274
+
275
  task_type_str = "generation" if action_code == "GENERATE" else "modification"
276
  logger.info(f"Syllabus {task_type_str} requested. Resource type: {new_state.get(STATE_RESOURCE_TYPE_FOR_SYLLABUS)}")
277
  retrieved_resource_type = new_state.get(STATE_RESOURCE_TYPE_FOR_SYLLABUS, "NONE")
 
284
  logger.info(f"Syllabus {task_type_str} requested. Resource type from state: {retrieved_resource_type}")
285
  # If type is SUMMARIES, we need to generate them now using DynamicSummarizer
286
  if retrieved_resource_type == "SUMMARIES":
287
+ # yield yield_feedback(new_state, "GENERATING_DYNAMIC_SUMMARIES")
288
+
289
  raw_data_for_dynamic_summary = new_state.get('raw_resource_data_for_dynamic_summary')
290
  if raw_data_for_dynamic_summary and isinstance(raw_data_for_dynamic_summary, dict):
291
  logger.info("Generating dynamic summaries for syllabus router...")
 
325
  # --- BLOCK 1: XML to Markdown Formatting (and set success flag) ---
326
  if generated_xml and not generated_xml.strip().upper().startswith(("<SYLLABUS>\n[ERROR", "<SYLLABUS>[ERROR")):
327
  syllabus_generation_was_successful = True # Mark initial generation as successful
328
+ yield ("status", "FORMATTING_SYLLABUS")
329
+
330
  logger.info(f"Syllabus XML generated. Length: {len(generated_xml)}. Attempting Markdown formatting.")
331
+ # yield yield_feedback(new_state, "FORMATTING_SYLLABUS")
332
+
333
 
334
  if SYLLABUS_XML_TO_MARKDOWN_FORMATTER:
335
  try:
 
403
  logger.info("Finalization requested by manager.")
404
  last_syllabus_in_history = get_last_syllabus_content_from_history(history)
405
  if last_syllabus_in_history:
406
+ # yield yield_feedback(new_state, "FINALIZING_SYLLABUS")
407
+
408
  new_state[STATE_FINAL_SYLLABUS] = f"<syllabus>\n{last_syllabus_in_history}\n</syllabus>" # Store it
409
 
410
  # Ask for learning style
 
419
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
420
 
421
  elif action_code == "PERSONA":
422
+ yield ("status", "GENERATING_PERSONA")
423
  logger.info("Persona generation triggered by manager.")
424
  final_syllabus_xml_str = new_state.get(STATE_FINAL_SYLLABUS)
425
  if final_syllabus_xml_str:
426
+ # yield yield_feedback(new_state, "GENERATING_PERSONA")
427
+
428
  logger.info("Generating explainer prompt body...")
429
  explainer_prompt_body = PERSONA_PROMPT_GENERATOR.forward(
430
  conversation_history_str=format_history_for_dspy(history)
 
446
  history_str="None", # No prior *explainer* history for this first turn
447
  user_query_str=explainer_intro_query
448
  )
449
+ yield ("status", "TUTOR_INTRODUCTION")
450
+
451
  ai_reply_for_user = explainer_intro_response
452
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
453
  else:
 
474
 
475
  # --- Explanation Phase (STAGE_EXPLAINING) ---
476
  elif stage == STAGE_EXPLAINING:
477
+ yield ("status", "EXPLAINER_RESPONSE")
478
+
479
  logger.info(f"Orchestrator (DSPy): Stage={stage}. Calling ExplainerModule.")
480
+ # yield yield_feedback(new_state, "EXPLAINER_RESPONSE")
481
+
482
  explainer_sys_prompt = modified_explainer_prompt or new_state.get(STATE_EXPLAINER_PROMPT)
483
  expl_start_idx = new_state.get(STATE_EXPLANATION_START_INDEX, 0)
484
 
 
542
  history.append({'role': 'model', 'parts': [{'text': ai_reply_for_user}]})
543
 
544
  # --- Final State Update & Return ---
545
+ # new_state[STATE_HISTORY] = history
546
  logger.debug(f"Orchestrator (DSPy) returning: Stage='{new_state.get(STATE_STAGE)}', History Len={len(history)}, AI Reply starts: '{ai_reply_for_user[:50]}...'")
547
  logger.debug(f"Flags: DisplaySyllabus='{new_state.get(STATE_DISPLAY_SYLLABUS_FLAG) is not None}', TransitionExplainer='{new_state.get(STATE_TRANSITION_EXPLAINER_FLAG)}'")
548
+ new_state[STATE_HISTORY] = history
549
+ # new_state.pop(STATE_UI_FEEDBACK_MESSAGE, None) # Clear feedback message for the final state
550
 
551
+ new_state[STATE_HISTORY] = history
552
+ yield ("final_result", new_state)
553
+
554
+
555
 
556