LovnishVerma commited on
Commit
be6e7ff
Β·
verified Β·
1 Parent(s): 4bad871

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +94 -26
app.py CHANGED
@@ -205,8 +205,8 @@ Click "Generate Report" to download your detailed results!""", True
205
  else:
206
  return "πŸ“š Needs Improvement"
207
 
208
- def generate_pdf_report(self, logo_path: Optional[str] = None) -> Optional[str]:
209
- """Generate PDF report"""
210
  if not self.user_answers:
211
  return None
212
 
@@ -220,7 +220,14 @@ Click "Generate Report" to download your detailed results!""", True
220
  temp_file.close()
221
 
222
  # Create PDF
223
- doc = SimpleDocTemplate(temp_file.name, pagesize=A4)
 
 
 
 
 
 
 
224
  styles = getSampleStyleSheet()
225
  story = []
226
 
@@ -243,10 +250,45 @@ Click "Generate Report" to download your detailed results!""", True
243
  spaceAfter=20
244
  )
245
 
246
- # Header
247
- story.append(Paragraph("CCC Plus - Computer Concepts Plus", title_style))
248
- story.append(Paragraph("Quiz Assessment Report", subtitle_style))
249
- story.append(Spacer(1, 12))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
250
 
251
  # Candidate info
252
  info_data = [
@@ -269,40 +311,60 @@ Click "Generate Report" to download your detailed results!""", True
269
  story.append(info_table)
270
  story.append(Spacer(1, 20))
271
 
272
- # Results table
273
  story.append(Paragraph("Detailed Results", styles['Heading2']))
274
  story.append(Spacer(1, 12))
275
 
276
  table_data = [['#', 'Question', 'Your Answer', 'Correct Answer', 'Result']]
277
 
 
 
 
 
 
 
 
 
 
 
 
278
  for i, answer in enumerate(self.user_answers, 1):
279
  result_icon = 'βœ“' if answer['is_correct'] else 'βœ—'
280
- question_text = answer['question'][:100] + ('...' if len(answer['question']) > 100 else '')
 
 
 
 
281
 
282
  table_data.append([
283
  str(i),
284
- question_text,
285
- answer['selected'],
286
- answer['correct_answer'],
287
  result_icon
288
  ])
289
 
290
- results_table = Table(table_data, colWidths=[20, 200, 80, 80, 30])
 
291
  results_table.setStyle(TableStyle([
292
  ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#003366')),
293
  ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
294
  ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
 
 
295
  ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
296
- ('FONTSIZE', (0, 0), (-1, -1), 8),
297
  ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#f8f9fa')]),
298
- ('GRID', (0, 0), (-1, -1), 1, colors.HexColor('#dee2e6')),
299
  ('VALIGN', (0, 0), (-1, -1), 'TOP'),
300
- ('BOTTOMPADDING', (0, 0), (-1, -1), 4),
301
- ('TOPPADDING', (0, 0), (-1, -1), 4),
 
 
302
  ]))
303
 
304
  story.append(results_table)
305
- story.append(Spacer(1, 20))
306
 
307
  # Footer
308
  footer_style = ParagraphStyle(
@@ -434,8 +496,8 @@ def handle_next_question(selected_answer: str) -> Tuple[str, Any, Any, str, Any]
434
  gr.update()
435
  )
436
 
437
- def handle_generate_report(logo_file) -> Tuple[str, Any]:
438
- """Handle report generation"""
439
  if not quiz_app.user_answers:
440
  return "❌ No quiz results available. Please complete a quiz first.", gr.update(visible=False)
441
 
@@ -469,8 +531,13 @@ def handle_generate_report(logo_file) -> Tuple[str, Any]:
469
 
470
  report_md = "\n".join(report_lines)
471
 
 
 
 
 
 
472
  # Generate PDF
473
- pdf_path = quiz_app.generate_pdf_report()
474
 
475
  if pdf_path:
476
  return report_md, gr.update(value=pdf_path, visible=True)
@@ -592,12 +659,13 @@ def create_app():
592
  report_btn = gr.Button("πŸ“‹ Generate Report", visible=False)
593
  reset_btn = gr.Button("πŸ”„ Reset All", variant="secondary")
594
 
595
- # Logo upload
596
  gr.Markdown("---")
597
- gr.Markdown("### 🎨 Branding (Optional)")
598
- logo_upload = gr.File(
599
- label="Upload Logo for PDF",
600
- file_types=[".png", ".jpg", ".jpeg"]
 
601
  )
602
 
603
  # Right Panel - Quiz Area
 
205
  else:
206
  return "πŸ“š Needs Improvement"
207
 
208
+ def generate_pdf_report(self, photo_path: Optional[str] = None) -> Optional[str]:
209
+ """Generate PDF report with candidate photo"""
210
  if not self.user_answers:
211
  return None
212
 
 
220
  temp_file.close()
221
 
222
  # Create PDF
223
+ doc = SimpleDocTemplate(
224
+ temp_file.name,
225
+ pagesize=A4,
226
+ leftMargin=25*mm,
227
+ rightMargin=25*mm,
228
+ topMargin=25*mm,
229
+ bottomMargin=25*mm
230
+ )
231
  styles = getSampleStyleSheet()
232
  story = []
233
 
 
250
  spaceAfter=20
251
  )
252
 
253
+ # Header with candidate photo
254
+ from reportlab.platypus import Image
255
+ header_data = []
256
+
257
+ if photo_path and os.path.exists(photo_path):
258
+ try:
259
+ # Create header table with photo
260
+ photo_img = Image(photo_path, width=60, height=60)
261
+ header_info = [
262
+ "CCC Plus - Computer Concepts Plus",
263
+ "Quiz Assessment Report",
264
+ f"Candidate: {self.user_name}",
265
+ datetime.now().strftime('%d %B %Y at %H:%M:%S')
266
+ ]
267
+
268
+ header_table = Table([
269
+ [photo_img, Paragraph("<br/>".join(header_info), styles['Normal'])]
270
+ ], colWidths=[80, 400])
271
+
272
+ header_table.setStyle(TableStyle([
273
+ ('ALIGN', (0, 0), (0, 0), 'CENTER'),
274
+ ('VALIGN', (0, 0), (-1, -1), 'TOP'),
275
+ ('FONTSIZE', (1, 0), (1, 0), 12),
276
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 12),
277
+ ]))
278
+
279
+ story.append(header_table)
280
+
281
+ except Exception as e:
282
+ logger.warning(f"Could not add photo to PDF: {e}")
283
+ # Fallback to text header
284
+ story.append(Paragraph("CCC Plus - Computer Concepts Plus", title_style))
285
+ story.append(Paragraph("Quiz Assessment Report", subtitle_style))
286
+ else:
287
+ # Text-only header
288
+ story.append(Paragraph("CCC Plus - Computer Concepts Plus", title_style))
289
+ story.append(Paragraph("Quiz Assessment Report", subtitle_style))
290
+
291
+ story.append(Spacer(1, 20))
292
 
293
  # Candidate info
294
  info_data = [
 
311
  story.append(info_table)
312
  story.append(Spacer(1, 20))
313
 
314
+ # Results table with proper text wrapping
315
  story.append(Paragraph("Detailed Results", styles['Heading2']))
316
  story.append(Spacer(1, 12))
317
 
318
  table_data = [['#', 'Question', 'Your Answer', 'Correct Answer', 'Result']]
319
 
320
+ # Custom paragraph style for table cells
321
+ cell_style = ParagraphStyle(
322
+ 'CellStyle',
323
+ parent=styles['Normal'],
324
+ fontSize=8,
325
+ leading=10,
326
+ wordWrap='LTR',
327
+ leftIndent=2,
328
+ rightIndent=2
329
+ )
330
+
331
  for i, answer in enumerate(self.user_answers, 1):
332
  result_icon = 'βœ“' if answer['is_correct'] else 'βœ—'
333
+
334
+ # Wrap text in Paragraph objects for proper text wrapping
335
+ question_para = Paragraph(answer['question'], cell_style)
336
+ selected_para = Paragraph(answer['selected'], cell_style)
337
+ correct_para = Paragraph(answer['correct_answer'], cell_style)
338
 
339
  table_data.append([
340
  str(i),
341
+ question_para,
342
+ selected_para,
343
+ correct_para,
344
  result_icon
345
  ])
346
 
347
+ # Adjust column widths for better fit
348
+ results_table = Table(table_data, colWidths=[15*mm, 90*mm, 35*mm, 35*mm, 15*mm])
349
  results_table.setStyle(TableStyle([
350
  ('BACKGROUND', (0, 0), (-1, 0), colors.HexColor('#003366')),
351
  ('TEXTCOLOR', (0, 0), (-1, 0), colors.whitesmoke),
352
  ('ALIGN', (0, 0), (-1, -1), 'LEFT'),
353
+ ('ALIGN', (0, 0), (0, -1), 'CENTER'), # Center align the # column
354
+ ('ALIGN', (-1, 0), (-1, -1), 'CENTER'), # Center align the Result column
355
  ('FONTNAME', (0, 0), (-1, 0), 'Helvetica-Bold'),
356
+ ('FONTSIZE', (0, 0), (-1, 0), 9),
357
  ('ROWBACKGROUNDS', (0, 1), (-1, -1), [colors.white, colors.HexColor('#f8f9fa')]),
358
+ ('GRID', (0, 0), (-1, -1), 0.5, colors.HexColor('#dee2e6')),
359
  ('VALIGN', (0, 0), (-1, -1), 'TOP'),
360
+ ('BOTTOMPADDING', (0, 0), (-1, -1), 6),
361
+ ('TOPPADDING', (0, 0), (-1, -1), 6),
362
+ ('LEFTPADDING', (0, 0), (-1, -1), 4),
363
+ ('RIGHTPADDING', (0, 0), (-1, -1), 4),
364
  ]))
365
 
366
  story.append(results_table)
367
+ story.append(Spacer(1, 30))
368
 
369
  # Footer
370
  footer_style = ParagraphStyle(
 
496
  gr.update()
497
  )
498
 
499
+ def handle_generate_report(photo_file) -> Tuple[str, Any]:
500
+ """Handle report generation with candidate photo"""
501
  if not quiz_app.user_answers:
502
  return "❌ No quiz results available. Please complete a quiz first.", gr.update(visible=False)
503
 
 
531
 
532
  report_md = "\n".join(report_lines)
533
 
534
+ # Extract photo path
535
+ photo_path = None
536
+ if photo_file is not None:
537
+ photo_path = photo_file.name if hasattr(photo_file, 'name') else str(photo_file)
538
+
539
  # Generate PDF
540
+ pdf_path = quiz_app.generate_pdf_report(photo_path)
541
 
542
  if pdf_path:
543
  return report_md, gr.update(value=pdf_path, visible=True)
 
659
  report_btn = gr.Button("πŸ“‹ Generate Report", visible=False)
660
  reset_btn = gr.Button("πŸ”„ Reset All", variant="secondary")
661
 
662
+ # Candidate photo upload
663
  gr.Markdown("---")
664
+ gr.Markdown("### πŸ“Έ Candidate Photo (Optional)")
665
+ photo_upload = gr.File(
666
+ label="Upload Candidate Photo",
667
+ file_types=[".png", ".jpg", ".jpeg"],
668
+ info="Photo will be included in the PDF report"
669
  )
670
 
671
  # Right Panel - Quiz Area