pk75 commited on
Commit
4fb2f1b
·
verified ·
1 Parent(s): 8f736d9

Update modules/report_generator.py

Browse files
Files changed (1) hide show
  1. modules/report_generator.py +56 -27
modules/report_generator.py CHANGED
@@ -3,7 +3,7 @@ import datetime
3
  import os
4
  import numpy as np
5
  import matplotlib.pyplot as plt
6
- from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Image
7
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
8
  from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER
9
  from reportlab.lib.units import inch
@@ -11,48 +11,73 @@ from reportlab.lib import colors
11
  from modules.llm_handler import generate_holistic_feedback, parse_scores_from_evaluation
12
  import config
13
 
14
- def define_skill_areas(interview_type):
15
- if interview_type == 'Technical':
16
- return ['Factual Accuracy', 'Structure & Clarity', 'Relevance & Directness']
17
- return ['Factual Accuracy', 'Relevance & Directness', 'Structure & Clarity']
 
18
 
 
 
 
 
 
 
 
 
 
19
  def create_radar_chart(labels, scores, file_path):
20
  num_vars = len(labels)
21
  angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
22
- scores += scores[:1]
23
- angles += angles[:1]
24
  fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
25
- ax.fill(angles, scores, color='#4A90E2', alpha=0.25)
26
- ax.plot(angles, scores, color='#4A90E2', linewidth=2)
27
- ax.set_yticklabels([])
28
- ax.set_xticks(angles[:-1])
29
- ax.set_xticklabels(labels)
30
- plt.savefig(file_path, transparent=True)
 
 
 
31
  plt.close(fig)
32
  print(f"📈 Radar chart saved to {file_path}")
33
 
34
  def generate_pdf_report(interview_data, file_path):
35
- doc = SimpleDocTemplate(file_path, pagesize=(8.5 * inch, 11 * inch))
 
 
 
36
  styles = getSampleStyleSheet()
37
  styles.add(ParagraphStyle(name='ReportTitle', parent=styles['h1'], fontSize=28, alignment=TA_CENTER, spaceAfter=24))
38
- styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY, spaceAfter=12))
39
- styles.add(ParagraphStyle(name='QuestionTitle', parent=styles['h2'], spaceBefore=20, spaceAfter=10))
40
- styles.add(ParagraphStyle(name='SectionTitle', parent=styles['h3'], spaceBefore=12, spaceAfter=6, textColor=colors.darkblue))
41
-
 
 
42
  story = []
 
 
 
43
  story.append(Paragraph("Interview Performance Report", styles['ReportTitle']))
 
 
 
 
 
 
44
  story.append(PageBreak())
45
 
46
- story.append(Paragraph("Overall Performance Analysis", styles['h1']))
 
47
  full_log_text = ""
48
  all_scores = []
49
- skill_labels = define_skill_areas(interview_data['type'])
50
-
51
  for i, qa in enumerate(interview_data['q_and_a']):
52
  full_log_text += f"Q{i+1}: {qa['question']}\nA: {qa['answer']}\n---\n"
53
  scores = parse_scores_from_evaluation(qa['evaluation'])
54
  all_scores.append([scores.get(label, 0) for label in skill_labels])
55
-
56
  holistic_feedback = generate_holistic_feedback(full_log_text).replace('\n', '<br/>')
57
  story.append(Paragraph(holistic_feedback, styles['Justify']))
58
  story.append(Spacer(1, 0.3 * inch))
@@ -62,16 +87,20 @@ def generate_pdf_report(interview_data, file_path):
62
  chart_path = os.path.join(config.REPORT_FOLDER, "skill_chart.png")
63
  if os.path.exists(chart_path): os.remove(chart_path)
64
  create_radar_chart(skill_labels, avg_scores, chart_path)
65
- story.append(Image(chart_path, width=4*inch, height=4*inch, hAlign='CENTER'))
66
  story.append(PageBreak())
67
 
68
- story.append(Paragraph("Detailed Question Analysis", styles['h1']))
 
69
  for i, qa in enumerate(interview_data['q_and_a']):
70
  story.append(Paragraph(f"Question {i+1}: {qa['question']}", styles['QuestionTitle']))
71
  story.append(Paragraph("Your Answer:", styles['SectionTitle']))
72
  story.append(Paragraph(qa.get('answer', 'N/A'), styles['Justify']))
73
  story.append(Paragraph("AI Evaluation:", styles['SectionTitle']))
74
  story.append(Paragraph(qa.get('evaluation', 'N/A').replace('\n', '<br/>'), styles['Justify']))
75
-
76
- doc.build(story)
77
- print(f"\n✅ Data-driven report generated successfully: {file_path}")
 
 
 
 
3
  import os
4
  import numpy as np
5
  import matplotlib.pyplot as plt
6
+ from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Image, Frame, PageTemplate
7
  from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
8
  from reportlab.lib.enums import TA_JUSTIFY, TA_CENTER
9
  from reportlab.lib.units import inch
 
11
  from modules.llm_handler import generate_holistic_feedback, parse_scores_from_evaluation
12
  import config
13
 
14
+ # This class is unchanged
15
+ class ReportPageTemplate(PageTemplate):
16
+ def __init__(self, id, pagesize):
17
+ frame = Frame(inch, inch, pagesize[0] - 2 * inch, pagesize[1] - 2 * inch, id='normal')
18
+ PageTemplate.__init__(self, id, [frame])
19
 
20
+ def beforeDrawPage(self, canvas, doc):
21
+ canvas.saveState()
22
+ canvas.setFont('Helvetica', 9)
23
+ canvas.setFillColor(colors.grey)
24
+ footer_text = f"Page {doc.page} | AI Interview Coach Report | Generated on {datetime.datetime.now().strftime('%Y-%m-%d')}"
25
+ canvas.drawCentredString(doc.width / 2 + inch, 0.75 * inch, footer_text)
26
+ canvas.restoreState()
27
+
28
+ # This function is unchanged
29
  def create_radar_chart(labels, scores, file_path):
30
  num_vars = len(labels)
31
  angles = np.linspace(0, 2 * np.pi, num_vars, endpoint=False).tolist()
32
+ scores += scores[:1]; angles += angles[:1]
 
33
  fig, ax = plt.subplots(figsize=(6, 6), subplot_kw=dict(polar=True))
34
+ ax.fill(angles, scores, color='#4A90E2', alpha=0.2)
35
+ ax.plot(angles, scores, color='#4A90E2', linewidth=2, linestyle='solid')
36
+ ax.set_yticklabels([]); ax.set_xticks(angles[:-1]); ax.set_xticklabels(labels, size=12, color='grey')
37
+ ax.set_ylim(0, 10)
38
+ for angle, score in zip(angles[:-1], scores[:-1]):
39
+ ax.text(angle, score + 1.5, str(score), ha='center', va='center', size=14, color="#000000", weight='bold')
40
+ plt.title('Performance Snapshot', size=20, color='#333333', y=1.1)
41
+ os.makedirs(os.path.dirname(file_path), exist_ok=True)
42
+ plt.savefig(file_path, transparent=True, dpi=150)
43
  plt.close(fig)
44
  print(f"📈 Radar chart saved to {file_path}")
45
 
46
  def generate_pdf_report(interview_data, file_path):
47
+ doc = SimpleDocTemplate(file_path, pagesize=(8.5 * inch, 11 * inch),
48
+ leftMargin=inch, rightMargin=inch, topMargin=inch, bottomMargin=inch)
49
+ doc.addPageTemplates([ReportPageTemplate('main_template', (8.5 * inch, 11 * inch))])
50
+
51
  styles = getSampleStyleSheet()
52
  styles.add(ParagraphStyle(name='ReportTitle', parent=styles['h1'], fontSize=28, alignment=TA_CENTER, spaceAfter=24))
53
+ styles.add(ParagraphStyle(name='ReportSubTitle', parent=styles['h2'], fontSize=16, alignment=TA_CENTER, spaceAfter=12, textColor=colors.HexColor('#555555')))
54
+ styles.add(ParagraphStyle(name='Justify', alignment=TA_JUSTIFY, spaceAfter=12, leading=14))
55
+ styles.add(ParagraphStyle(name='MainHeader', parent=styles['h1'], fontSize=22, spaceBefore=12, spaceAfter=20, alignment=TA_LEFT, textColor=colors.HexColor('#2c3e50')))
56
+ styles.add(ParagraphStyle(name='QuestionTitle', parent=styles['h2'], spaceBefore=20, spaceAfter=10, textColor=colors.HexColor('#2980b9')))
57
+ styles.add(ParagraphStyle(name='SectionTitle', parent=styles['h3'], spaceBefore=12, spaceAfter=6, textColor=colors.HexColor('#34495e')))
58
+
59
  story = []
60
+
61
+ # --- 1. The Title Page ---
62
+ # This section now safely gets the data it needs.
63
  story.append(Paragraph("Interview Performance Report", styles['ReportTitle']))
64
+ story.append(Spacer(1, 0.5 * inch))
65
+ story.append(Paragraph(f"Prepared for: <b>{interview_data.get('name', 'N/A')}</b>", styles['ReportSubTitle']))
66
+ story.append(Spacer(1, 0.2 * inch))
67
+ story.append(Paragraph(f"Interview Type: <b>{interview_data.get('type', 'N/A')}</b>", styles['ReportSubTitle']))
68
+ story.append(Spacer(1, 0.2 * inch))
69
+ story.append(Paragraph(f"Date of Report: <b>{datetime.datetime.now().strftime('%B %d, %Y')}</b>", styles['ReportSubTitle']))
70
  story.append(PageBreak())
71
 
72
+ # --- 2. Overall Performance & Graph Section ---
73
+ story.append(Paragraph("Overall Performance Analysis", styles['MainHeader']))
74
  full_log_text = ""
75
  all_scores = []
76
+ skill_labels = ['Factual Accuracy', 'Relevance & Directness', 'Structure & Clarity']
 
77
  for i, qa in enumerate(interview_data['q_and_a']):
78
  full_log_text += f"Q{i+1}: {qa['question']}\nA: {qa['answer']}\n---\n"
79
  scores = parse_scores_from_evaluation(qa['evaluation'])
80
  all_scores.append([scores.get(label, 0) for label in skill_labels])
 
81
  holistic_feedback = generate_holistic_feedback(full_log_text).replace('\n', '<br/>')
82
  story.append(Paragraph(holistic_feedback, styles['Justify']))
83
  story.append(Spacer(1, 0.3 * inch))
 
87
  chart_path = os.path.join(config.REPORT_FOLDER, "skill_chart.png")
88
  if os.path.exists(chart_path): os.remove(chart_path)
89
  create_radar_chart(skill_labels, avg_scores, chart_path)
90
+ story.append(Image(chart_path, width=4.5*inch, height=4.5*inch, hAlign='CENTER'))
91
  story.append(PageBreak())
92
 
93
+ # --- 3. Detailed Question-by-Question Analysis ---
94
+ story.append(Paragraph("Detailed Question Analysis", styles['MainHeader']))
95
  for i, qa in enumerate(interview_data['q_and_a']):
96
  story.append(Paragraph(f"Question {i+1}: {qa['question']}", styles['QuestionTitle']))
97
  story.append(Paragraph("Your Answer:", styles['SectionTitle']))
98
  story.append(Paragraph(qa.get('answer', 'N/A'), styles['Justify']))
99
  story.append(Paragraph("AI Evaluation:", styles['SectionTitle']))
100
  story.append(Paragraph(qa.get('evaluation', 'N/A').replace('\n', '<br/>'), styles['Justify']))
101
+
102
+ try:
103
+ doc.build(story)
104
+ print(f"\n✅ Professional report generated successfully: {file_path}")
105
+ except Exception as e:
106
+ print(f"💥 Error generating professional PDF report: {e}")