Update process_interview.py
Browse files- process_interview.py +32 -26
process_interview.py
CHANGED
|
@@ -387,23 +387,27 @@ def analyze_interviewee_voice(audio_path: str, utterances: List[Dict]) -> Dict:
|
|
| 387 |
return {'error': f'Voice analysis incomplete due to audio processing issues: {str(e)}'}
|
| 388 |
|
| 389 |
def generate_voice_interpretation(analysis: Dict) -> str:
|
| 390 |
-
|
| 391 |
-
|
| 392 |
-
|
| 393 |
-
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 407 |
|
| 408 |
def generate_anxiety_confidence_chart(composite_scores: Dict, chart_buffer):
|
| 409 |
try:
|
|
@@ -457,8 +461,9 @@ def generate_report(analysis_data: Dict) -> str:
|
|
| 457 |
interviewee_responses = [u['text'] for u in analysis_data['transcript'] if u['role'] == 'Interviewee']
|
| 458 |
if not interviewee_responses:
|
| 459 |
logger.warning("No interviewee responses found for report generation")
|
| 460 |
-
return """**1. Executive Summary**
|
| 461 |
- Insufficient interviewee content to generate a summary.
|
|
|
|
| 462 |
|
| 463 |
**2. Communication and Vocal Dynamics**
|
| 464 |
{voice_interpretation}
|
|
@@ -485,14 +490,15 @@ def generate_report(analysis_data: Dict) -> str:
|
|
| 485 |
acceptance_line += "HR Verdict: Limited fit, significant improvement required."
|
| 486 |
transcript_text = "\n".join([f"- {u['speaker']}: {u['text']}" for u in analysis_data['transcript']])
|
| 487 |
prompt = f"""
|
| 488 |
-
You are EvalBot, a senior HR consultant delivering a professional interview analysis report. Use clear headings with '**', bullet points ('-'), complete sentences, and formal language. Avoid redundancy, vague terms, and special characters that could break formatting (e.g., parentheses). Ensure each section is unique, actionable, and at least 2-3 bullet points
|
| 489 |
|
| 490 |
**Input Data**
|
| 491 |
- Suitability Score: {acceptance_prob:.2f}%
|
| 492 |
- Interview Duration: {analysis_data['text_analysis']['total_duration']:.2f} seconds
|
| 493 |
- Speaker Turns: {analysis_data['text_analysis']['speaker_turns']}
|
| 494 |
- Participants: {', '.join(sorted(set(u['speaker'] for u in analysis_data['transcript'])))}
|
| 495 |
-
- Voice Analysis:
|
|
|
|
| 496 |
- Transcript Sample:
|
| 497 |
{transcript_text[:1000]}...
|
| 498 |
|
|
@@ -523,7 +529,7 @@ You are EvalBot, a senior HR consultant delivering a professional interview anal
|
|
| 523 |
"""
|
| 524 |
response = gemini_model.generate_content(prompt)
|
| 525 |
report_text = re.sub(r'[^\x00-\x7F]+|[()]+', '', response.text)
|
| 526 |
-
logger.info(f"Generated Gemini report: {report_text[:500]}...") # Log
|
| 527 |
return report_text
|
| 528 |
except Exception as e:
|
| 529 |
logger.error(f"Report generation failed: {str(e)}", exc_info=True)
|
|
@@ -562,7 +568,7 @@ def create_pdf_report(analysis_data: Dict, output_path: str, gemini_report_text:
|
|
| 562 |
canvas.saveState()
|
| 563 |
canvas.setFont('Helvetica', 7)
|
| 564 |
canvas.setFillColor(colors.HexColor('#666666'))
|
| 565 |
-
canvas.drawString(doc.leftMargin, 0.5*inch, f"Page {doc.page} | EvalBot HR Interview Report | Confidential")
|
| 566 |
canvas.setStrokeColor(colors.HexColor('#0050BC'))
|
| 567 |
canvas.setLineWidth(0.5)
|
| 568 |
canvas.line(doc.leftMargin, doc.height + 0.9*inch, doc.width + doc.leftMargin, doc.height + 0.9*inch)
|
|
@@ -609,8 +615,8 @@ def create_pdf_report(analysis_data: Dict, output_path: str, gemini_report_text:
|
|
| 609 |
('TOPPADDING', (0,0), (-1,0), 6),
|
| 610 |
('BACKGROUND', (0,1), (-1,-1), colors.HexColor('#F5F6FA')),
|
| 611 |
('GRID', (0,0), (-1,-1), 0.4, colors.HexColor('#DDE4EB')),
|
| 612 |
-
('LEFTPADDING', (1,3), (1,3), 10),
|
| 613 |
-
('WORDWRAP', (1,3), (1,3), 'CJK'),
|
| 614 |
]))
|
| 615 |
story.append(table)
|
| 616 |
story.append(Spacer(1, 0.3*inch))
|
|
@@ -695,7 +701,7 @@ def create_pdf_report(analysis_data: Dict, output_path: str, gemini_report_text:
|
|
| 695 |
clean_line = line.lstrip('-').strip()
|
| 696 |
if not clean_line:
|
| 697 |
continue
|
| 698 |
-
clean_line = re.sub(r'[^\w\s.,;:-]', '', clean_line)
|
| 699 |
if current_section == 'Competency':
|
| 700 |
if any(k in clean_line.lower() for k in ['leader', 'problem', 'commun', 'adapt', 'achieve', 'skill', 'success']):
|
| 701 |
current_subsection = 'Strengths'
|
|
@@ -712,7 +718,7 @@ def create_pdf_report(analysis_data: Dict, output_path: str, gemini_report_text:
|
|
| 712 |
sections[current_section][current_subsection].append(clean_line)
|
| 713 |
else:
|
| 714 |
sections[current_section].append(clean_line)
|
| 715 |
-
elif current_section and line:
|
| 716 |
clean_line = re.sub(r'[^\w\s.,;:-]', '', line)
|
| 717 |
sections[current_section].append(clean_line)
|
| 718 |
|
|
|
|
| 387 |
return {'error': f'Voice analysis incomplete due to audio processing issues: {str(e)}'}
|
| 388 |
|
| 389 |
def generate_voice_interpretation(analysis: Dict) -> str:
|
| 390 |
+
try:
|
| 391 |
+
if 'error' in analysis:
|
| 392 |
+
return f"Voice analysis unavailable: {analysis['error']}"
|
| 393 |
+
interpretation_lines = [
|
| 394 |
+
f"- Speaking rate: {analysis.get('speaking_rate', 0):.2f} words/sec (Benchmark: 2.0-3.0; affects clarity)", # Fixed syntax error
|
| 395 |
+
f"- Filler words: {analysis.get('filler_ratio', 0) * 100:.1f}% (High usage reduces credibility)",
|
| 396 |
+
f"- Anxiety: {analysis.get('interpretation', {}).get('anxiety_level', 'N/A')} (Score: {analysis.get('composite_scores', {}).get('anxiety', 0):.3f}; stress response)",
|
| 397 |
+
f"- Confidence: {analysis.get('interpretation', {}).get('confidence_level', 'N/A')} (Score: {analysis.get('composite_scores', {}).get('confidence', 0):.3f}; vocal strength)",
|
| 398 |
+
f"- Fluency: {analysis.get('interpretation', {}).get('fluency_level', 'N/A')} (Drives engagement)",
|
| 399 |
+
"",
|
| 400 |
+
"HR Insights:",
|
| 401 |
+
"- Rapid speech (>3.0 wps) may reduce clarity; slower pacing enhances professionalism.",
|
| 402 |
+
"- High filler word usage undermines perceived credibility.",
|
| 403 |
+
"- Elevated anxiety suggests pressure; training can improve resilience.",
|
| 404 |
+
"- Strong confidence supports leadership presence.",
|
| 405 |
+
"- Fluent speech enhances engagement in team settings."
|
| 406 |
+
]
|
| 407 |
+
return "\n".join(interpretation_lines)
|
| 408 |
+
except Exception as e:
|
| 409 |
+
logger.error(f"Error generating voice interpretation: {str(e)}")
|
| 410 |
+
return f"Voice analysis unavailable: Error in interpretation formatting"
|
| 411 |
|
| 412 |
def generate_anxiety_confidence_chart(composite_scores: Dict, chart_buffer):
|
| 413 |
try:
|
|
|
|
| 461 |
interviewee_responses = [u['text'] for u in analysis_data['transcript'] if u['role'] == 'Interviewee']
|
| 462 |
if not interviewee_responses:
|
| 463 |
logger.warning("No interviewee responses found for report generation")
|
| 464 |
+
return f"""**1. Executive Summary**
|
| 465 |
- Insufficient interviewee content to generate a summary.
|
| 466 |
+
- Interview duration suggests limited engagement.
|
| 467 |
|
| 468 |
**2. Communication and Vocal Dynamics**
|
| 469 |
{voice_interpretation}
|
|
|
|
| 490 |
acceptance_line += "HR Verdict: Limited fit, significant improvement required."
|
| 491 |
transcript_text = "\n".join([f"- {u['speaker']}: {u['text']}" for u in analysis_data['transcript']])
|
| 492 |
prompt = f"""
|
| 493 |
+
You are EvalBot, a senior HR consultant delivering a professional interview analysis report. Use clear headings with '**', bullet points ('-'), complete sentences, and formal language. Avoid redundancy, vague terms, and special characters that could break formatting (e.g., parentheses). Ensure each section is unique, actionable, and contains at least 2-3 bullet points. If content is limited, provide reasonable inferences based on available data.
|
| 494 |
|
| 495 |
**Input Data**
|
| 496 |
- Suitability Score: {acceptance_prob:.2f}%
|
| 497 |
- Interview Duration: {analysis_data['text_analysis']['total_duration']:.2f} seconds
|
| 498 |
- Speaker Turns: {analysis_data['text_analysis']['speaker_turns']}
|
| 499 |
- Participants: {', '.join(sorted(set(u['speaker'] for u in analysis_data['transcript'])))}
|
| 500 |
+
- Voice Analysis:
|
| 501 |
+
{voice_interpretation}
|
| 502 |
- Transcript Sample:
|
| 503 |
{transcript_text[:1000]}...
|
| 504 |
|
|
|
|
| 529 |
"""
|
| 530 |
response = gemini_model.generate_content(prompt)
|
| 531 |
report_text = re.sub(r'[^\x00-\x7F]+|[()]+', '', response.text)
|
| 532 |
+
logger.info(f"Generated Gemini report: {report_text[:500]}...") # Log for debugging
|
| 533 |
return report_text
|
| 534 |
except Exception as e:
|
| 535 |
logger.error(f"Report generation failed: {str(e)}", exc_info=True)
|
|
|
|
| 568 |
canvas.saveState()
|
| 569 |
canvas.setFont('Helvetica', 7)
|
| 570 |
canvas.setFillColor(colors.HexColor('#666666'))
|
| 571 |
+
canvas.drawString(doc.leftMargin, 0.5*inch, f"Page {doc.page} | EvalBot HR Interview Report | Confidential") # Fixed typo
|
| 572 |
canvas.setStrokeColor(colors.HexColor('#0050BC'))
|
| 573 |
canvas.setLineWidth(0.5)
|
| 574 |
canvas.line(doc.leftMargin, doc.height + 0.9*inch, doc.width + doc.leftMargin, doc.height + 0.9*inch)
|
|
|
|
| 615 |
('TOPPADDING', (0,0), (-1,0), 6),
|
| 616 |
('BACKGROUND', (0,1), (-1,-1), colors.HexColor('#F5F6FA')),
|
| 617 |
('GRID', (0,0), (-1,-1), 0.4, colors.HexColor('#DDE4EB')),
|
| 618 |
+
('LEFTPADDING', (1,3), (1,3), 10),
|
| 619 |
+
('WORDWRAP', (1,3), (1,3), 'CJK'),
|
| 620 |
]))
|
| 621 |
story.append(table)
|
| 622 |
story.append(Spacer(1, 0.3*inch))
|
|
|
|
| 701 |
clean_line = line.lstrip('-').strip()
|
| 702 |
if not clean_line:
|
| 703 |
continue
|
| 704 |
+
clean_line = re.sub(r'[^\w\s.,;:-]', '', clean_line)
|
| 705 |
if current_section == 'Competency':
|
| 706 |
if any(k in clean_line.lower() for k in ['leader', 'problem', 'commun', 'adapt', 'achieve', 'skill', 'success']):
|
| 707 |
current_subsection = 'Strengths'
|
|
|
|
| 718 |
sections[current_section][current_subsection].append(clean_line)
|
| 719 |
else:
|
| 720 |
sections[current_section].append(clean_line)
|
| 721 |
+
elif current_section and line:
|
| 722 |
clean_line = re.sub(r'[^\w\s.,;:-]', '', line)
|
| 723 |
sections[current_section].append(clean_line)
|
| 724 |
|