scormon-predata-ai commited on
Commit
6b8739c
·
verified ·
1 Parent(s): 1e7473a

Update researchsimulation/InteractiveInterviewChatbot.py

Browse files
researchsimulation/InteractiveInterviewChatbot.py CHANGED
@@ -391,88 +391,47 @@ def tailor_answer_to_profile(agent_name, generic_answer, agent_question, user_pr
391
  return result
392
 
393
 
394
- def validate_tailored_answer(agent_name, agent_question, respondent_agent, tailored_answer_generator, user_profile, processor_llm, max_attempts=3):
395
- """
396
- Re-generates and validates the respondent's tailored answer with retry logic.
397
- Returns the validated answer, or a fallback string if validation fails after max_attempts.
398
- """
399
- logging.info("[validate_tailored_answer] Entry")
400
- logging.debug(f"[validate_tailored_answer] Parameters: agent_name={agent_name}, agent_question={agent_question}, max_attempts={max_attempts}")
401
-
402
- attempt = 0
403
- validated = False
404
- validated_answer = None
405
- overall_start = time.time()
406
-
407
- while attempt < max_attempts and not validated:
408
- logging.info(f"[validate_tailored_answer] Starting attempt {attempt+1} of {max_attempts}")
409
- attempt_start = time.time()
410
-
411
- try:
412
- logging.info(f"[validate_tailored_answer] Attempt {attempt+1}: Generating and validating answer for '{agent_name}'")
413
- gen_start = time.time()
414
- # Generate tailored answer from generic → styled
415
- tailored_answer = tailored_answer_generator()
416
- gen_duration = time.time() - gen_start
417
- logging.info(f"[validate_tailored_answer] Tailored answer generation completed in {gen_duration:.2f} seconds")
418
- logging.debug(f"[validate_tailored_answer] Tailored answer (attempt {attempt+1}): {tailored_answer}")
419
-
420
- # Validate response
421
- logging.info(f"[validate_tailored_answer] Validating answer (attempt {attempt+1})")
422
- val_start = time.time()
423
- is_valid = validate_response(
424
- question=agent_question,
425
- answer=tailored_answer,
426
- user_profile_str=str(user_profile),
427
- fast_facts_str="",
428
- interview_transcript_text="",
429
- respondent_type=agent_name,
430
- ai_evaluator_agent=None,
431
- processor_llm=processor_llm
432
- )
433
- val_duration = time.time() - val_start
434
- logging.info(f"[validate_tailored_answer] Validation completed in {val_duration:.2f} seconds")
435
- logging.info(f"[validate_tailored_answer] Validation result for attempt {attempt+1}: {is_valid}")
436
-
437
- if is_valid:
438
- if len(tailored_answer) > 2000:
439
- logging.warning(f"Tailored answer exceeds 2000 characters (length={len(tailored_answer)}); retrying...")
440
- attempt += 1
441
- else:
442
- validated = True
443
- validated_answer = tailored_answer
444
- logging.info(f"Answer validated successfully on attempt {attempt+1}")
445
- break
446
- else:
447
- logging.warning(f"Validation failed on attempt {attempt+1}")
448
- attempt += 1
449
-
450
- except Exception as e:
451
- logging.exception(f"[validate_tailored_answer] Exception on attempt {attempt+1}")
452
- attempt += 1
453
-
454
- attempt_duration = time.time() - attempt_start
455
- logging.info(f"[validate_tailored_answer] Attempt {attempt+1} duration: {attempt_duration:.2f} seconds")
456
-
457
- overall_duration = time.time() - overall_start
458
-
459
- if validated_answer:
460
- final_response = f"**{agent_name}**: {validated_answer}"
461
- logging.info(f"[validate_tailored_answer] Successfully returning validated answer after {overall_duration:.2f} seconds")
462
- else:
463
- final_response = f"**PreData Moderator**: Unable to pass validation after {max_attempts} attempts for {agent_name}."
464
- logging.warning(f"[validate_tailored_answer] Returning failure message after {overall_duration:.2f} seconds")
465
 
466
- logging.debug(f"[validate_tailored_answer] Final response: {final_response}")
467
- logging.info("[validate_tailored_answer] Exit")
468
- return final_response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
469
 
 
470
  def ask_interview_question(respondent_agents_dict, last_active_agent, question, processor_llm):
471
- """
472
- Handles both individual and group interview questions while tracking conversation flow.
473
- Uses OpenAI's LLM to extract the intended respondent(s) and their specific question(s).
474
- Generates generic answers, styles them, and validates the output.
475
- """
476
  logging.info("[ask_interview_question] Entry")
477
  logging.debug(f"[ask_interview_question] Parameters: question={question}, last_active_agent={last_active_agent}")
478
 
@@ -482,99 +441,70 @@ def ask_interview_question(respondent_agents_dict, last_active_agent, question,
482
  agent_names = list(respondent_agents_dict.keys())
483
  logging.info(f"[ask_interview_question] Available respondents: {agent_names}")
484
 
485
- # --- Step 1: Parse question ---
486
- logging.info("[ask_interview_question] Parsing question with LLM")
487
- parse_start = time.time()
488
  parsed_questions = parse_question_with_llm(question, str(agent_names), processor_llm)
489
- parse_duration = time.time() - parse_start
490
- logging.info(f"[ask_interview_question] Parsing completed in {parse_duration:.2f} seconds")
491
- logging.debug(f"[ask_interview_question] Parsed questions: {parsed_questions}")
492
-
493
  if not parsed_questions:
494
- logging.warning("[ask_interview_question] No questions were parsed from input.")
495
  return ["**PreData Moderator**: No valid respondents were detected for this question."]
496
 
497
- # --- Step 2: Validate topics and spelling ---
498
- logging.info("[ask_interview_question] Validating parsed questions")
499
- validation_start = time.time()
500
  validated_questions = validate_question_topics(parsed_questions, processor_llm)
501
- validation_duration = time.time() - validation_start
502
- logging.info(f"[ask_interview_question] Validation completed in {validation_duration:.2f} seconds")
503
- logging.debug(f"[ask_interview_question] Validated questions: {validated_questions}")
504
-
505
  for resp_name, extracted_question in validated_questions.items():
506
  if extracted_question == "INVALID":
507
- logging.warning(f"[ask_interview_question] Invalid question detected for {resp_name}: {extracted_question}")
508
  return ["**PreData Moderator**: The question is invalid. Please ask another question."]
509
 
510
- # --- Handle "General" or "All" ---
511
  if len(validated_questions) > 1:
512
- logging.warning("[ask_interview_question] Multiple respondents detected in single question")
513
  return ["**PreData Moderator**: Please ask each respondent one question at a time."]
514
 
515
  if "General" in validated_questions:
516
- logging.info("[ask_interview_question] Handling 'General' question")
517
  if isinstance(last_active_agent, list) and all(name in agent_names for name in last_active_agent):
518
  validated_questions = {name: validated_questions["General"] for name in last_active_agent}
519
  else:
520
  validated_questions = {name: validated_questions["General"] for name in agent_names}
521
- logging.debug(f"[ask_interview_question] Expanded to: {validated_questions}")
522
-
523
  elif "All" in validated_questions:
524
- logging.info("[ask_interview_question] Handling 'All' question")
525
  validated_questions = {name: validated_questions["All"] for name in agent_names}
526
- logging.debug(f"[ask_interview_question] Expanded to: {validated_questions}")
527
 
528
- # --- Update last_active_agent ---
529
  last_active_agent = list(validated_questions.keys())
530
- logging.info(f"[ask_interview_question] Updated last_active_agent: {last_active_agent}")
531
-
532
- # --- Step 3: Generate + Tailor answers ---
533
  responses = []
534
- for agent_name, agent_question in validated_questions.items():
535
- logging.info(f"[ask_interview_question] Processing respondent: {agent_name}")
536
- generation_start = time.time()
537
 
 
538
  if agent_name not in respondent_agents_dict:
539
- logging.warning(f"[ask_interview_question] Invalid respondent name detected: {agent_name}")
540
  responses.append(f"**PreData Moderator**: {agent_name} is not a valid respondent.")
541
  continue
542
 
543
  respondent_agent = respondent_agents_dict[agent_name].get_agent()
544
  user_profile = respondent_agents_dict[agent_name].get_user_profile()
545
 
546
- # --- Generate Generic Answer ---
547
- logging.info(f"[ask_interview_question] Generating generic answer for {agent_name}")
548
  generic_answer = generate_generic_answer(agent_name, agent_question, respondent_agent)
549
- logging.debug(f"[ask_interview_question] Generic answer: {generic_answer}")
550
 
551
- # --- Tailor + Validate with Retry ---
 
 
 
552
  def generator():
553
  return tailor_answer_to_profile(agent_name, generic_answer, agent_question, user_profile, respondent_agent)
554
 
555
- logging.info(f"[ask_interview_question] Tailoring and validating answer for {agent_name}")
556
- validated_response = validate_tailored_answer(
557
- agent_name=agent_name,
558
- agent_question=agent_question,
559
- respondent_agent=respondent_agent,
560
- tailored_answer_generator=generator,
561
- user_profile=user_profile,
562
- processor_llm=processor_llm
563
- )
564
- logging.debug(f"[ask_interview_question] Validated response: {validated_response}")
565
-
566
- responses.append(validated_response)
567
- generation_duration = time.time() - generation_start
568
- logging.info(f"[ask_interview_question] Completed generation + validation for {agent_name} in {generation_duration:.2f} seconds")
569
-
570
- # --- Format final return ---
571
- if len(set(validated_questions.values())) == 1:
572
- result = ["\n\n".join(responses)]
573
- else:
574
- result = responses
575
 
576
- logging.info("[ask_interview_question] Successfully generated all responses")
577
- logging.debug(f"[ask_interview_question] Final responses: {result}")
 
 
 
 
 
 
578
 
579
  except Exception as e:
580
  logging.exception("[ask_interview_question] Exception occurred during processing")
@@ -582,6 +512,4 @@ def ask_interview_question(respondent_agents_dict, last_active_agent, question,
582
 
583
  overall_duration = time.time() - overall_start
584
  logging.info(f"[ask_interview_question] Completed in {overall_duration:.2f} seconds")
585
- logging.info("[ask_interview_question] Exit")
586
-
587
  return result
 
391
  return result
392
 
393
 
394
+ # --- New Validation Functions ---
395
+ def validate_generic_answer(agent_name, agent_question, generic_answer, user_profile, processor_llm):
396
+ logging.info("[validate_generic_answer] Entry")
397
+ try:
398
+ is_valid = validate_response(
399
+ question=agent_question,
400
+ answer=generic_answer,
401
+ user_profile_str=str(user_profile),
402
+ fast_facts_str="",
403
+ interview_transcript_text="",
404
+ respondent_type=agent_name,
405
+ ai_evaluator_agent=None,
406
+ processor_llm=processor_llm
407
+ )
408
+ logging.info(f"[validate_generic_answer] Result: {is_valid}")
409
+ return is_valid
410
+ except Exception as e:
411
+ logging.exception("[validate_generic_answer] Exception during validation")
412
+ return False
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
413
 
414
+ def validate_styled_answer(agent_name, agent_question, styled_answer, user_profile, processor_llm):
415
+ logging.info("[validate_styled_answer] Entry")
416
+ try:
417
+ is_valid = validate_response(
418
+ question=agent_question,
419
+ answer=styled_answer,
420
+ user_profile_str=str(user_profile),
421
+ fast_facts_str="",
422
+ interview_transcript_text="",
423
+ respondent_type=agent_name,
424
+ ai_evaluator_agent=None,
425
+ processor_llm=processor_llm
426
+ )
427
+ logging.info(f"[validate_styled_answer] Result: {is_valid}")
428
+ return is_valid
429
+ except Exception as e:
430
+ logging.exception("[validate_styled_answer] Exception during style validation")
431
+ return False
432
 
433
+ # --- Updated ask_interview_question Function ---
434
  def ask_interview_question(respondent_agents_dict, last_active_agent, question, processor_llm):
 
 
 
 
 
435
  logging.info("[ask_interview_question] Entry")
436
  logging.debug(f"[ask_interview_question] Parameters: question={question}, last_active_agent={last_active_agent}")
437
 
 
441
  agent_names = list(respondent_agents_dict.keys())
442
  logging.info(f"[ask_interview_question] Available respondents: {agent_names}")
443
 
 
 
 
444
  parsed_questions = parse_question_with_llm(question, str(agent_names), processor_llm)
 
 
 
 
445
  if not parsed_questions:
 
446
  return ["**PreData Moderator**: No valid respondents were detected for this question."]
447
 
 
 
 
448
  validated_questions = validate_question_topics(parsed_questions, processor_llm)
 
 
 
 
449
  for resp_name, extracted_question in validated_questions.items():
450
  if extracted_question == "INVALID":
 
451
  return ["**PreData Moderator**: The question is invalid. Please ask another question."]
452
 
 
453
  if len(validated_questions) > 1:
 
454
  return ["**PreData Moderator**: Please ask each respondent one question at a time."]
455
 
456
  if "General" in validated_questions:
 
457
  if isinstance(last_active_agent, list) and all(name in agent_names for name in last_active_agent):
458
  validated_questions = {name: validated_questions["General"] for name in last_active_agent}
459
  else:
460
  validated_questions = {name: validated_questions["General"] for name in agent_names}
 
 
461
  elif "All" in validated_questions:
 
462
  validated_questions = {name: validated_questions["All"] for name in agent_names}
 
463
 
 
464
  last_active_agent = list(validated_questions.keys())
 
 
 
465
  responses = []
 
 
 
466
 
467
+ for agent_name, agent_question in validated_questions.items():
468
  if agent_name not in respondent_agents_dict:
 
469
  responses.append(f"**PreData Moderator**: {agent_name} is not a valid respondent.")
470
  continue
471
 
472
  respondent_agent = respondent_agents_dict[agent_name].get_agent()
473
  user_profile = respondent_agents_dict[agent_name].get_user_profile()
474
 
 
 
475
  generic_answer = generate_generic_answer(agent_name, agent_question, respondent_agent)
 
476
 
477
+ if not validate_generic_answer(agent_name, agent_question, generic_answer, user_profile, processor_llm):
478
+ responses.append(f"**PreData Moderator**: The generated answer for {agent_name} did not meet our content standards.")
479
+ continue
480
+
481
  def generator():
482
  return tailor_answer_to_profile(agent_name, generic_answer, agent_question, user_profile, respondent_agent)
483
 
484
+ tailored_attempts = 0
485
+ max_tailored_attempts = 3
486
+ tailored_answer = None
487
+
488
+ while tailored_attempts < max_tailored_attempts:
489
+ styled = generator()
490
+
491
+ if len(styled) > 2000:
492
+ logging.warning(f"[ask_interview_question] Styled answer too long (len={len(styled)}), retrying...")
493
+ tailored_attempts += 1
494
+ continue
495
+
496
+ if validate_styled_answer(agent_name, agent_question, styled, user_profile, processor_llm):
497
+ tailored_answer = styled
498
+ break
 
 
 
 
 
499
 
500
+ tailored_attempts += 1
501
+
502
+ if tailored_answer:
503
+ responses.append(f"**{agent_name}**: {tailored_answer}")
504
+ else:
505
+ responses.append(f"**PreData Moderator**: Failed to stylise the response for {agent_name} after multiple attempts.")
506
+
507
+ result = ["\n\n".join(responses)] if len(set(validated_questions.values())) == 1 else responses
508
 
509
  except Exception as e:
510
  logging.exception("[ask_interview_question] Exception occurred during processing")
 
512
 
513
  overall_duration = time.time() - overall_start
514
  logging.info(f"[ask_interview_question] Completed in {overall_duration:.2f} seconds")
 
 
515
  return result