Spaces:
Sleeping
Sleeping
Update main.py
Browse files
main.py
CHANGED
|
@@ -313,174 +313,102 @@ Root Causes:\n{root_causes}""",
|
|
| 313 |
|
| 314 |
# ── PDF Generator ─────────────────────────────────────────────────────────────
|
| 315 |
|
| 316 |
-
def
|
| 317 |
-
"""Remove markdown bold/italic markers for plain PDF text."""
|
| 318 |
text = re.sub(r"\*\*(.*?)\*\*", r"\1", text)
|
| 319 |
text = re.sub(r"\*(.*?)\*", r"\1", text)
|
| 320 |
return text
|
| 321 |
|
| 322 |
|
| 323 |
def build_pdf(analysis: FullAnalysis, name: str, role: str) -> bytes:
|
| 324 |
-
"""
|
| 325 |
buf = io.BytesIO()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 326 |
|
| 327 |
-
# ── Page setup
|
| 328 |
doc = SimpleDocTemplate(
|
| 329 |
-
buf,
|
| 330 |
-
|
| 331 |
-
|
| 332 |
-
leftMargin=20 * mm,
|
| 333 |
-
topMargin=22 * mm,
|
| 334 |
-
bottomMargin=22 * mm,
|
| 335 |
)
|
| 336 |
-
|
| 337 |
styles = getSampleStyleSheet()
|
| 338 |
-
W = A4[0] - 40 * mm # usable width
|
| 339 |
-
|
| 340 |
-
# ── Custom styles
|
| 341 |
-
s_title = ParagraphStyle(
|
| 342 |
-
"title",
|
| 343 |
-
parent=styles["Normal"],
|
| 344 |
-
fontSize=22,
|
| 345 |
-
fontName="Helvetica-Bold",
|
| 346 |
-
textColor=colors.HexColor("#1a1a2e"),
|
| 347 |
-
spaceAfter=4,
|
| 348 |
-
)
|
| 349 |
-
s_sub = ParagraphStyle(
|
| 350 |
-
"sub",
|
| 351 |
-
parent=styles["Normal"],
|
| 352 |
-
fontSize=11,
|
| 353 |
-
fontName="Helvetica",
|
| 354 |
-
textColor=colors.HexColor("#6b7280"),
|
| 355 |
-
spaceAfter=12,
|
| 356 |
-
)
|
| 357 |
-
s_section = ParagraphStyle(
|
| 358 |
-
"section",
|
| 359 |
-
parent=styles["Normal"],
|
| 360 |
-
fontSize=13,
|
| 361 |
-
fontName="Helvetica-Bold",
|
| 362 |
-
textColor=colors.HexColor("#2563eb"),
|
| 363 |
-
spaceBefore=16,
|
| 364 |
-
spaceAfter=6,
|
| 365 |
-
)
|
| 366 |
-
s_h3 = ParagraphStyle(
|
| 367 |
-
"h3",
|
| 368 |
-
parent=styles["Normal"],
|
| 369 |
-
fontSize=11,
|
| 370 |
-
fontName="Helvetica-Bold",
|
| 371 |
-
textColor=colors.HexColor("#374151"),
|
| 372 |
-
spaceBefore=8,
|
| 373 |
-
spaceAfter=3,
|
| 374 |
-
)
|
| 375 |
-
s_body = ParagraphStyle(
|
| 376 |
-
"body",
|
| 377 |
-
parent=styles["Normal"],
|
| 378 |
-
fontSize=10,
|
| 379 |
-
fontName="Helvetica",
|
| 380 |
-
textColor=colors.HexColor("#374151"),
|
| 381 |
-
leading=15,
|
| 382 |
-
spaceAfter=4,
|
| 383 |
-
)
|
| 384 |
-
s_label = ParagraphStyle(
|
| 385 |
-
"label",
|
| 386 |
-
parent=styles["Normal"],
|
| 387 |
-
fontSize=8,
|
| 388 |
-
fontName="Helvetica-Bold",
|
| 389 |
-
textColor=colors.white,
|
| 390 |
-
)
|
| 391 |
|
| 392 |
-
|
| 393 |
-
""
|
| 394 |
-
|
| 395 |
-
|
| 396 |
-
|
| 397 |
-
|
| 398 |
-
|
| 399 |
-
|
| 400 |
-
|
| 401 |
-
|
| 402 |
-
|
| 403 |
-
|
| 404 |
-
|
| 405 |
-
|
| 406 |
-
)
|
| 407 |
-
|
| 408 |
-
|
| 409 |
-
|
| 410 |
-
|
| 411 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
for line in md_text.splitlines():
|
| 413 |
line = line.strip()
|
| 414 |
if not line:
|
| 415 |
-
|
| 416 |
-
|
| 417 |
-
|
| 418 |
-
flowables.append(Paragraph(line[3:], s_section))
|
| 419 |
elif line.startswith("### "):
|
| 420 |
-
|
| 421 |
elif line.startswith("- ") or line.startswith("* "):
|
| 422 |
-
|
| 423 |
-
flowables.append(Paragraph(f"• {clean}", s_body))
|
| 424 |
elif re.match(r"^\d+\.", line):
|
| 425 |
-
|
| 426 |
-
flowables.append(Paragraph(clean, s_body))
|
| 427 |
-
elif line.startswith("**") and line.endswith("**"):
|
| 428 |
-
flowables.append(Paragraph(line[2:-2], s_h3))
|
| 429 |
else:
|
| 430 |
-
|
| 431 |
-
|
| 432 |
-
return flowables
|
| 433 |
|
| 434 |
story = []
|
| 435 |
|
| 436 |
-
#
|
| 437 |
-
story.append(Paragraph("Problem Analysis
|
| 438 |
-
story.append(
|
| 439 |
-
|
| 440 |
-
|
| 441 |
-
|
| 442 |
-
|
| 443 |
-
|
| 444 |
-
|
| 445 |
-
|
| 446 |
-
|
| 447 |
-
|
| 448 |
-
|
| 449 |
-
|
| 450 |
-
|
| 451 |
-
#
|
| 452 |
-
story.append(Spacer(1,
|
| 453 |
-
story.append(
|
| 454 |
-
story.append(
|
| 455 |
-
|
| 456 |
-
|
| 457 |
-
|
| 458 |
-
story.append(Spacer(1, 8))
|
| 459 |
-
story.append(agent_badge("AGENT 3 — Solution Brainstorm", "#4a1942"))
|
| 460 |
-
story.append(Spacer(1, 6))
|
| 461 |
-
story += render_markdown_block(analysis.solutions)
|
| 462 |
-
|
| 463 |
-
# ── Section 4: Action Plan
|
| 464 |
-
story.append(Spacer(1, 8))
|
| 465 |
-
story.append(agent_badge("AGENT 4 — Action Planner", "#7c2d12"))
|
| 466 |
-
story.append(Spacer(1, 6))
|
| 467 |
-
story += render_markdown_block(analysis.action_plan)
|
| 468 |
-
|
| 469 |
-
# ── Section 5: Thinking Coach
|
| 470 |
-
story.append(Spacer(1, 8))
|
| 471 |
-
story.append(agent_badge("AGENT 5 — Thinking Coach", "#312e81"))
|
| 472 |
-
story.append(Spacer(1, 6))
|
| 473 |
-
story += render_markdown_block(analysis.thinking_feedback)
|
| 474 |
-
|
| 475 |
-
# ── Footer note
|
| 476 |
-
story.append(Spacer(1, 16))
|
| 477 |
-
story.append(HRFlowable(width=W, thickness=0.5, color=colors.HexColor("#e5e7eb"), spaceAfter=6))
|
| 478 |
-
story.append(
|
| 479 |
-
Paragraph(
|
| 480 |
-
"Generated by the AI Intern Problem-Solving System · Confidential",
|
| 481 |
-
ParagraphStyle("footer", parent=styles["Normal"], fontSize=8, textColor=colors.HexColor("#9ca3af"), alignment=1),
|
| 482 |
-
)
|
| 483 |
-
)
|
| 484 |
|
| 485 |
doc.build(story)
|
| 486 |
buf.seek(0)
|
|
|
|
| 313 |
|
| 314 |
# ── PDF Generator ─────────────────────────────────────────────────────────────
|
| 315 |
|
| 316 |
+
def strip_md(text: str) -> str:
|
|
|
|
| 317 |
text = re.sub(r"\*\*(.*?)\*\*", r"\1", text)
|
| 318 |
text = re.sub(r"\*(.*?)\*", r"\1", text)
|
| 319 |
return text
|
| 320 |
|
| 321 |
|
| 322 |
def build_pdf(analysis: FullAnalysis, name: str, role: str) -> bytes:
|
| 323 |
+
"""Clean black-and-white PDF report."""
|
| 324 |
buf = io.BytesIO()
|
| 325 |
+
INK = colors.HexColor("#111827")
|
| 326 |
+
INK2 = colors.HexColor("#374151")
|
| 327 |
+
GRAY = colors.HexColor("#6b7280")
|
| 328 |
+
LGRAY = colors.HexColor("#d1d5db")
|
| 329 |
+
W = A4[0] - 48 * mm
|
| 330 |
|
|
|
|
| 331 |
doc = SimpleDocTemplate(
|
| 332 |
+
buf, pagesize=A4,
|
| 333 |
+
rightMargin=24 * mm, leftMargin=24 * mm,
|
| 334 |
+
topMargin=24 * mm, bottomMargin=24 * mm,
|
|
|
|
|
|
|
|
|
|
| 335 |
)
|
|
|
|
| 336 |
styles = getSampleStyleSheet()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 337 |
|
| 338 |
+
s_title = ParagraphStyle("t", parent=styles["Normal"],
|
| 339 |
+
fontSize=20, fontName="Helvetica-Bold", textColor=INK, spaceAfter=3)
|
| 340 |
+
s_meta = ParagraphStyle("m", parent=styles["Normal"],
|
| 341 |
+
fontSize=10, fontName="Helvetica", textColor=GRAY, spaceAfter=14)
|
| 342 |
+
s_section_head = ParagraphStyle("sh", parent=styles["Normal"],
|
| 343 |
+
fontSize=11, fontName="Helvetica-Bold", textColor=INK,
|
| 344 |
+
spaceBefore=20, spaceAfter=2)
|
| 345 |
+
s_section_num = ParagraphStyle("sn", parent=styles["Normal"],
|
| 346 |
+
fontSize=10, fontName="Helvetica", textColor=GRAY, spaceAfter=8)
|
| 347 |
+
s_h2 = ParagraphStyle("h2", parent=styles["Normal"],
|
| 348 |
+
fontSize=10, fontName="Helvetica-Bold", textColor=INK,
|
| 349 |
+
spaceBefore=10, spaceAfter=3)
|
| 350 |
+
s_h3 = ParagraphStyle("h3", parent=styles["Normal"],
|
| 351 |
+
fontSize=10, fontName="Helvetica-Bold", textColor=INK2,
|
| 352 |
+
spaceBefore=7, spaceAfter=2)
|
| 353 |
+
s_body = ParagraphStyle("b", parent=styles["Normal"],
|
| 354 |
+
fontSize=10, fontName="Helvetica", textColor=INK2,
|
| 355 |
+
leading=15, spaceAfter=3)
|
| 356 |
+
s_bullet = ParagraphStyle("bl", parent=styles["Normal"],
|
| 357 |
+
fontSize=10, fontName="Helvetica", textColor=INK2,
|
| 358 |
+
leading=15, spaceAfter=2, leftIndent=12, firstLineIndent=-12)
|
| 359 |
+
s_footer = ParagraphStyle("f", parent=styles["Normal"],
|
| 360 |
+
fontSize=8, fontName="Helvetica", textColor=GRAY, alignment=1)
|
| 361 |
+
|
| 362 |
+
SECTIONS = [
|
| 363 |
+
("Problem Analyst", analysis.problem_statement),
|
| 364 |
+
("Root Cause Analyst", analysis.root_causes),
|
| 365 |
+
("Solutions", analysis.solutions),
|
| 366 |
+
("Action Plan", analysis.action_plan),
|
| 367 |
+
("Thinking Coach", analysis.thinking_feedback),
|
| 368 |
+
]
|
| 369 |
+
|
| 370 |
+
def render_block(md_text: str) -> list:
|
| 371 |
+
out = []
|
| 372 |
for line in md_text.splitlines():
|
| 373 |
line = line.strip()
|
| 374 |
if not line:
|
| 375 |
+
out.append(Spacer(1, 3))
|
| 376 |
+
elif line.startswith("## "):
|
| 377 |
+
out.append(Paragraph(strip_md(line[3:]), s_h2))
|
|
|
|
| 378 |
elif line.startswith("### "):
|
| 379 |
+
out.append(Paragraph(strip_md(line[4:]), s_h3))
|
| 380 |
elif line.startswith("- ") or line.startswith("* "):
|
| 381 |
+
out.append(Paragraph(f"– {strip_md(line[2:])}", s_bullet))
|
|
|
|
| 382 |
elif re.match(r"^\d+\.", line):
|
| 383 |
+
out.append(Paragraph(strip_md(line), s_body))
|
|
|
|
|
|
|
|
|
|
| 384 |
else:
|
| 385 |
+
out.append(Paragraph(strip_md(line), s_body))
|
| 386 |
+
return out
|
|
|
|
| 387 |
|
| 388 |
story = []
|
| 389 |
|
| 390 |
+
# Header
|
| 391 |
+
story.append(Paragraph("Problem Analysis", s_title))
|
| 392 |
+
story.append(Paragraph(
|
| 393 |
+
f"{name} · {datetime.now().strftime('%d %B %Y')}",
|
| 394 |
+
s_meta,
|
| 395 |
+
))
|
| 396 |
+
story.append(HRFlowable(width=W, thickness=0.5, color=LGRAY, spaceAfter=4))
|
| 397 |
+
|
| 398 |
+
# Sections
|
| 399 |
+
for i, (title, text) in enumerate(SECTIONS, 1):
|
| 400 |
+
story.append(Spacer(1, 4))
|
| 401 |
+
story.append(Paragraph(title, s_section_head))
|
| 402 |
+
story.append(HRFlowable(width=W, thickness=0.5, color=LGRAY, spaceAfter=6))
|
| 403 |
+
story += render_block(text)
|
| 404 |
+
|
| 405 |
+
# Footer
|
| 406 |
+
story.append(Spacer(1, 20))
|
| 407 |
+
story.append(HRFlowable(width=W, thickness=0.5, color=LGRAY, spaceAfter=6))
|
| 408 |
+
story.append(Paragraph(
|
| 409 |
+
f"Problem Solver · {datetime.now().strftime('%d %B %Y')}",
|
| 410 |
+
s_footer,
|
| 411 |
+
))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 412 |
|
| 413 |
doc.build(story)
|
| 414 |
buf.seek(0)
|