diff --git a/backend/api_server.py b/backend/api_server.py index 1e7b287..5850057 100755 --- a/backend/api_server.py +++ b/backend/api_server.py @@ -1247,6 +1247,66 @@ def generate_html_response(report_data, filename, save_to_file=False, session_id else: return Response(html_content, mimetype='text/html') +def _render_technical_section_html(report): + """Render the technical pre-flight report as an HTML block. Empty string if no report.""" + if not report or report.get('kind') in (None, 'unknown'): + return '' + kind = report['kind'] + rows = [] + size_mb = report.get('file_size_mb') + if size_mb is not None: + rows.append(f'
File size: {size_mb} MB
') + dims = report.get('dimensions') + if dims: + rows.append(f'
Dimensions: {dims["width"]} × {dims["height"]}
') + fmt = report.get('format') + if fmt: + rows.append(f'
Format: {fmt}
') + dpi = report.get('dpi') + if dpi: + rows.append(f'
DPI: {dpi[0]} × {dpi[1]}
') + mode = report.get('mode') + if mode: + rows.append(f'
Color mode: {mode}
') + pc = report.get('page_count') + if pc is not None: + rows.append(f'
Pages: {pc}
') + pdf_ver = report.get('pdf_version') + if pdf_ver: + rows.append(f'
PDF version: {pdf_ver}
') + duration = report.get('duration_seconds') + if duration is not None: + rows.append(f'
Duration: {duration}s
') + codec = report.get('video_codec') + if codec: + rows.append(f'
Video codec: {codec}
') + fps = report.get('fps') + if fps: + rows.append(f'
Frame rate: {fps} fps
') + fonts = report.get('embedded_fonts') + if fonts: + suffix = ' …' if len(fonts) > 8 else '' + rows.append(f'
Embedded fonts: {", ".join(fonts[:8])}{suffix}
') + fm = report.get('filename_match') + if fm: + if fm['match']: + badge = '✓ Matches filename' + else: + badge = '⚠ Filename mismatch' + rows.append(f'
{badge} {fm["detail"]}
') + errors = report.get('errors', []) + if errors: + rows.append(f'
Inspection notes: {"; ".join(errors)}
') + if not rows: + return '' + return f''' +
+

🔧 Technical Details (machine-inspected, no AI)

+
{''.join(rows)}
+
+ ''' + + def generate_comprehensive_html_report(analysis_result, filename, file_path=None): """Generate comprehensive HTML report similar to the web UI format""" summary = analysis_result.get('summary', {}) @@ -1308,7 +1368,9 @@ def generate_comprehensive_html_report(analysis_result, filename, file_path=None avg_individual_score = overall_score / 10 # Normalize to 1-10 scale grade_text = 'Pass' if avg_individual_score >= 6 else 'Fail' score_color = '#28a745' if avg_individual_score >= 6 else '#dc3545' - + + technical_html = _render_technical_section_html(analysis_result.get('technical_report', {})) + return f''' @@ -1332,6 +1394,9 @@ def generate_comprehensive_html_report(analysis_result, filename, file_path=None .summary {{ background: linear-gradient(135deg, #FFF9E6 0%, #FFFBF0 100%); padding: 25px; border-radius: 15px; margin: 30px 0; border-left: 5px solid #FFC407; }} .summary-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin-top: 15px; }} .summary-item {{ background: white; padding: 15px; border-radius: 10px; text-align: center; box-shadow: 0 2px 4px rgba(0,0,0,0.05); }} + .technical {{ background: linear-gradient(135deg, #e3f2fd 0%, #f0f7ff 100%); padding: 25px; border-radius: 15px; margin: 30px 0; border-left: 5px solid #1565c0; }} + .technical-grid {{ display: grid; grid-template-columns: repeat(auto-fit, minmax(280px, 1fr)); gap: 8px 24px; margin-top: 12px; }} + .tech-row {{ padding: 4px 0; color: #495057; font-size: 0.95em; word-break: break-word; }} .score-display {{ font-size: 2.5em; font-weight: bold; color: {score_color}; margin-bottom: 5px; }} .grade {{ font-size: 1.3em; font-weight: bold; color: #495057; }} .expandable-section {{ margin-bottom: 15px; border: 2px solid #e9ecef; border-radius: 12px; overflow: hidden; background: white; }} @@ -1392,7 +1457,9 @@ def generate_comprehensive_html_report(analysis_result, filename, file_path=None - + + {technical_html} +

🔍 Detailed Analysis Results

Click on any section below to expand and view detailed analysis