Spaces:
Sleeping
Sleeping
Download src/core/report_generator.py from FajarHidaa/HumanPlusX: direct link, hf CLI and curl.
- Browser
- Download file 21 kB
-
https://huggingface.co/spaces/FajarHidaa/HumanPlusX/resolve/main/src/core/report_generator.py
- Command line
-
hf download hf://spaces/FajarHidaa/HumanPlusX/src/core/report_generator.py
-
curl -L -o report_generator.py https://huggingface.co/spaces/FajarHidaa/HumanPlusX/resolve/main/src/core/report_generator.py
21 kB
| """ | |
| Human+ Branded PDF Report Generator | |
| Creates a polished, branded PDF using reportlab. | |
| Returns PDF as bytes for Streamlit download_button. | |
| """ | |
| import io | |
| from datetime import datetime | |
| from typing import Optional | |
| from reportlab.lib.pagesizes import A4 | |
| from reportlab.lib.units import mm | |
| from reportlab.lib.colors import HexColor, white, black | |
| from reportlab.lib.enums import TA_CENTER, TA_LEFT, TA_RIGHT | |
| from reportlab.lib.styles import ParagraphStyle | |
| from reportlab.platypus import ( | |
| SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, | |
| HRFlowable, KeepTogether, | |
| ) | |
| from reportlab.platypus import PageBreak | |
| # ββ Brand colors βββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| C_BG = HexColor("#070710") | |
| C_SURFACE = HexColor("#0d0d1a") | |
| C_ELEVATED = HexColor("#131325") | |
| C_LINE = HexColor("#1f1f38") | |
| C_TEXT = HexColor("#f0f0fa") | |
| C_MUTED = HexColor("#8b8ba7") | |
| C_VIOLET = HexColor("#6d28d9") | |
| C_VIOLET_LT = HexColor("#8b5cf6") | |
| C_CYAN = HexColor("#22d3ee") | |
| C_OPTIMAL = HexColor("#10b981") | |
| C_WARNING = HexColor("#f59e0b") | |
| C_DANGER = HexColor("#ef4444") | |
| C_NEUTRAL = HexColor("#6b7280") | |
| STATUS_COLOR = { | |
| "optimal": C_OPTIMAL, | |
| "warning": C_WARNING, | |
| "danger": C_DANGER, | |
| "neutral": C_NEUTRAL, | |
| } | |
| # ββ Styles ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _make_styles(): | |
| return { | |
| "hero_title": ParagraphStyle( | |
| "hero_title", | |
| fontName="Helvetica-Bold", | |
| fontSize=28, | |
| textColor=white, | |
| alignment=TA_CENTER, | |
| spaceAfter=4, | |
| leading=32, | |
| ), | |
| "hero_sub": ParagraphStyle( | |
| "hero_sub", | |
| fontName="Helvetica", | |
| fontSize=10, | |
| textColor=C_MUTED, | |
| alignment=TA_CENTER, | |
| spaceAfter=2, | |
| leading=14, | |
| letterSpacing=2, | |
| ), | |
| "section_label": ParagraphStyle( | |
| "section_label", | |
| fontName="Helvetica-Bold", | |
| fontSize=7, | |
| textColor=C_MUTED, | |
| spaceBefore=20, | |
| spaceAfter=8, | |
| leading=10, | |
| letterSpacing=2, | |
| ), | |
| "section_title": ParagraphStyle( | |
| "section_title", | |
| fontName="Helvetica-Bold", | |
| fontSize=14, | |
| textColor=white, | |
| spaceBefore=4, | |
| spaceAfter=10, | |
| leading=18, | |
| ), | |
| "body": ParagraphStyle( | |
| "body", | |
| fontName="Helvetica", | |
| fontSize=9, | |
| textColor=C_MUTED, | |
| spaceAfter=4, | |
| leading=14, | |
| ), | |
| "body_white": ParagraphStyle( | |
| "body_white", | |
| fontName="Helvetica", | |
| fontSize=9, | |
| textColor=C_TEXT, | |
| spaceAfter=4, | |
| leading=14, | |
| ), | |
| "biomarker_name": ParagraphStyle( | |
| "biomarker_name", | |
| fontName="Helvetica-Bold", | |
| fontSize=9, | |
| textColor=white, | |
| leading=12, | |
| ), | |
| "biomarker_ref": ParagraphStyle( | |
| "biomarker_ref", | |
| fontName="Helvetica", | |
| fontSize=7, | |
| textColor=C_MUTED, | |
| leading=10, | |
| ), | |
| "biomarker_value": ParagraphStyle( | |
| "biomarker_value", | |
| fontName="Helvetica-Bold", | |
| fontSize=11, | |
| alignment=TA_RIGHT, | |
| leading=14, | |
| ), | |
| "caption": ParagraphStyle( | |
| "caption", | |
| fontName="Helvetica", | |
| fontSize=7, | |
| textColor=C_MUTED, | |
| alignment=TA_CENTER, | |
| leading=10, | |
| ), | |
| "quote": ParagraphStyle( | |
| "quote", | |
| fontName="Helvetica-Oblique", | |
| fontSize=10, | |
| textColor=C_TEXT, | |
| alignment=TA_CENTER, | |
| spaceBefore=8, | |
| spaceAfter=4, | |
| leading=15, | |
| ), | |
| "footer": ParagraphStyle( | |
| "footer", | |
| fontName="Helvetica", | |
| fontSize=7, | |
| textColor=C_MUTED, | |
| alignment=TA_CENTER, | |
| leading=10, | |
| ), | |
| } | |
| # ββ Page template with dark background βββββββββββββββββββββββββββββββ | |
| def _draw_background(canvas, doc): | |
| """Draw dark background on every page.""" | |
| canvas.saveState() | |
| canvas.setFillColor(C_BG) | |
| canvas.rect(0, 0, A4[0], A4[1], fill=1, stroke=0) | |
| # Subtle top gradient bar (violet β cyan) | |
| canvas.setFillColor(C_VIOLET) | |
| canvas.rect(0, A4[1] - 4*mm, A4[0] * 0.5, 4*mm, fill=1, stroke=0) | |
| canvas.setFillColor(C_CYAN) | |
| canvas.rect(A4[0] * 0.5, A4[1] - 4*mm, A4[0] * 0.5, 4*mm, fill=1, stroke=0) | |
| # Bottom bar | |
| canvas.setFillColor(C_LINE) | |
| canvas.rect(0, 0, A4[0], 1*mm, fill=1, stroke=0) | |
| canvas.restoreState() | |
| def _draw_footer(canvas, doc): | |
| """Draw page footer.""" | |
| canvas.saveState() | |
| canvas.setFont("Helvetica", 7) | |
| canvas.setFillColor(C_MUTED) | |
| canvas.drawCentredString( | |
| A4[0] / 2, | |
| 12*mm, | |
| f"Human+ Bali Β· From Injured β Optimized Β· @bennywhitethatsright Β· Halaman {doc.page}" | |
| ) | |
| canvas.restoreState() | |
| def _on_page(canvas, doc): | |
| _draw_background(canvas, doc) | |
| _draw_footer(canvas, doc) | |
| # ββ Main generator ββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def generate_pdf_report( | |
| biomarkers: list[dict], | |
| protocol: dict, | |
| patient_name: str = "", | |
| generated_at: Optional[str] = None, | |
| ) -> bytes: | |
| """ | |
| Generate branded PDF report. | |
| Args: | |
| biomarkers: list of enriched biomarker dicts | |
| protocol: dict with keys summary, iv_drip, supplements, lifestyle, retest | |
| patient_name: optional patient name for personalization | |
| generated_at: optional datetime string, defaults to now | |
| Returns: | |
| PDF as bytes β ready for st.download_button | |
| """ | |
| buf = io.BytesIO() | |
| doc = SimpleDocTemplate( | |
| buf, | |
| pagesize=A4, | |
| leftMargin=20*mm, | |
| rightMargin=20*mm, | |
| topMargin=18*mm, | |
| bottomMargin=22*mm, | |
| title="Human+ Lab-to-Protocol Report", | |
| author="Human+ Bali", | |
| subject="Personalized Longevity Protocol", | |
| ) | |
| styles = _make_styles() | |
| story = [] | |
| W = A4[0] - 40*mm # usable width | |
| if generated_at is None: | |
| generated_at = datetime.now().strftime("%d %B %Y, %H:%M") | |
| # ββ Cover block ββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| story += _build_cover(styles, W, patient_name, generated_at) | |
| # ββ Biomarker summary ββββββββββββββββββββββββββββββββββββββββββββ | |
| story += _build_biomarker_section(styles, W, biomarkers) | |
| # ββ Protocol sections ββββββββββββββββββββββββββββββββββββββββββββ | |
| story += _build_protocol_section( | |
| styles, W, | |
| icon="IV DRIP", | |
| title="Rekomendasi IV Drip", | |
| color=C_VIOLET_LT, | |
| content=protocol.get("iv_drip", ""), | |
| ) | |
| story += _build_protocol_section( | |
| styles, W, | |
| icon="SUPLEMEN", | |
| title="Suplemen Harian", | |
| color=C_CYAN, | |
| content=protocol.get("supplements", ""), | |
| ) | |
| story += _build_protocol_section( | |
| styles, W, | |
| icon="LIFESTYLE", | |
| title="Lifestyle & Recovery Protocol", | |
| color=C_OPTIMAL, | |
| content=protocol.get("lifestyle", ""), | |
| ) | |
| story += _build_protocol_section( | |
| styles, W, | |
| icon="RETEST", | |
| title="Jadwal Retest & Next Step", | |
| color=C_WARNING, | |
| content=protocol.get("retest", ""), | |
| ) | |
| # ββ Closing quote & disclaimer βββββββββββββββββββββββββββββββββββ | |
| story += _build_footer_block(styles, W) | |
| doc.build(story, onFirstPage=_on_page, onLaterPages=_on_page) | |
| return buf.getvalue() | |
| # ββ Section builders βββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _build_cover(styles, W, patient_name: str, generated_at: str) -> list: | |
| s = styles | |
| items = [] | |
| # Spacer for top bar | |
| items.append(Spacer(1, 8*mm)) | |
| # Logo / brand name | |
| items.append(Paragraph("Human+", s["hero_title"])) | |
| items.append(Paragraph("LAB-TO-PROTOCOL REPORT", s["hero_sub"])) | |
| items.append(Spacer(1, 2*mm)) | |
| # Divider | |
| items.append(HRFlowable( | |
| width=W, thickness=1, | |
| color=C_LINE, spaceAfter=6*mm, spaceBefore=4*mm, | |
| )) | |
| # Meta info row | |
| meta_rows = [] | |
| if patient_name: | |
| meta_rows.append(["Pasien", patient_name]) | |
| meta_rows.append(["Dibuat", generated_at]) | |
| meta_rows.append(["Klinik", "Human+ Bali"]) | |
| meta_rows.append(["Founder", "Benjamin White @bennywhitethatsright"]) | |
| meta_data = [[ | |
| Paragraph(k, ParagraphStyle("ml", fontName="Helvetica-Bold", fontSize=8, | |
| textColor=C_MUTED, leading=12)), | |
| Paragraph(v, ParagraphStyle("mv", fontName="Helvetica", fontSize=8, | |
| textColor=C_TEXT, leading=12)), | |
| ] for k, v in meta_rows] | |
| meta_table = Table(meta_data, colWidths=[35*mm, W - 35*mm]) | |
| meta_table.setStyle(TableStyle([ | |
| ("BACKGROUND", (0, 0), (-1, -1), C_SURFACE), | |
| ("ROWBACKGROUNDS", (0, 0), (-1, -1), [C_SURFACE, C_ELEVATED]), | |
| ("TOPPADDING", (0, 0), (-1, -1), 5), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 5), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 8), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 8), | |
| ("ROUNDEDCORNERS", [6]), | |
| ])) | |
| items.append(meta_table) | |
| items.append(Spacer(1, 6*mm)) | |
| # Protocol summary | |
| summary = styles # shorthand | |
| if True: # placeholder β summary handled in protocol section | |
| pass | |
| return items | |
| def _build_biomarker_section(styles, W, biomarkers: list[dict]) -> list: | |
| if not biomarkers: | |
| return [] | |
| items = [] | |
| # Section label | |
| items.append(Paragraph("HASIL BIOMARKER", styles["section_label"])) | |
| items.append(Spacer(1, 2*mm)) | |
| # Summary counts | |
| optimal = sum(1 for b in biomarkers if b["status"] == "optimal") | |
| warning = sum(1 for b in biomarkers if b["status"] == "warning") | |
| danger = sum(1 for b in biomarkers if b["status"] == "danger") | |
| total = len(biomarkers) | |
| summary_data = [[ | |
| _stat_cell(str(danger), "PERLU PERHATIAN", C_DANGER), | |
| _stat_cell(str(warning), "SUB-OPTIMAL", C_WARNING), | |
| _stat_cell(str(optimal), "OPTIMAL", C_OPTIMAL), | |
| _stat_cell(str(total), "TOTAL MARKER", C_MUTED), | |
| ]] | |
| summary_table = Table(summary_data, colWidths=[W/4]*4) | |
| summary_table.setStyle(TableStyle([ | |
| ("BACKGROUND", (0, 0), (-1, -1), C_SURFACE), | |
| ("TOPPADDING", (0, 0), (-1, -1), 8), | |
| ("BOTTOMPADDING",(0, 0), (-1, -1), 8), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 4), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 4), | |
| ("LINEAFTER", (0, 0), (2, 0), 0.5, C_LINE), | |
| ])) | |
| items.append(summary_table) | |
| items.append(Spacer(1, 4*mm)) | |
| # Biomarker rows β sorted danger β warning β optimal | |
| priority = {"danger": 0, "warning": 1, "optimal": 2, "neutral": 3} | |
| sorted_bm = sorted(biomarkers, key=lambda b: priority.get(b["status"], 3)) | |
| # Table header | |
| header = [ | |
| Paragraph("BIOMARKER", ParagraphStyle("th", fontName="Helvetica-Bold", fontSize=7, | |
| textColor=C_MUTED, leading=10)), | |
| Paragraph("NILAI", ParagraphStyle("th", fontName="Helvetica-Bold", fontSize=7, | |
| textColor=C_MUTED, alignment=TA_RIGHT, leading=10)), | |
| Paragraph("TARGET HUMAN+", ParagraphStyle("th", fontName="Helvetica-Bold", fontSize=7, | |
| textColor=C_MUTED, alignment=TA_RIGHT, leading=10)), | |
| Paragraph("STATUS", ParagraphStyle("th", fontName="Helvetica-Bold", fontSize=7, | |
| textColor=C_MUTED, alignment=TA_CENTER, leading=10)), | |
| ] | |
| bm_rows = [header] | |
| row_colors = [C_ELEVATED] | |
| for b in sorted_bm: | |
| sc = STATUS_COLOR.get(b["status"], C_NEUTRAL) | |
| status_label = { | |
| "optimal": "OPTIMAL", | |
| "warning": "SUB-OPTIMAL", | |
| "danger": "KRITIS", | |
| "neutral": "-", | |
| }.get(b["status"], "-") | |
| row = [ | |
| Paragraph(b["name"], styles["biomarker_name"]), | |
| Paragraph( | |
| f'<font color="#{sc.hexval()[1:]}">{b["value"]} {b.get("unit","")}</font>', | |
| ParagraphStyle("bv", fontName="Helvetica-Bold", fontSize=10, | |
| alignment=TA_RIGHT, textColor=sc, leading=13) | |
| ), | |
| Paragraph(b.get("reference", "β"), | |
| ParagraphStyle("br", fontName="Helvetica", fontSize=8, | |
| textColor=C_MUTED, alignment=TA_RIGHT, leading=11)), | |
| Paragraph( | |
| f'<font color="#{sc.hexval()[1:]}">{status_label}</font>', | |
| ParagraphStyle("bs", fontName="Helvetica-Bold", fontSize=7, | |
| alignment=TA_CENTER, textColor=sc, leading=10) | |
| ), | |
| ] | |
| bm_rows.append(row) | |
| row_colors.append(C_SURFACE) | |
| col_w = [W * 0.38, W * 0.22, W * 0.25, W * 0.15] | |
| bm_table = Table(bm_rows, colWidths=col_w, repeatRows=1) | |
| bm_style = [ | |
| ("BACKGROUND", (0, 0), (-1, 0), C_ELEVATED), | |
| ("TOPPADDING", (0, 0), (-1, -1), 7), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 7), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 6), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 6), | |
| ("LINEBELOW", (0, 0), (-1, -1), 0.4, C_LINE), | |
| ("ROWBACKGROUNDS", (0, 1), (-1, -1), [C_SURFACE, C_ELEVATED]), | |
| ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), | |
| ] | |
| # Color left border per status | |
| for i, b in enumerate(sorted_bm, 1): | |
| sc = STATUS_COLOR.get(b["status"], C_NEUTRAL) | |
| bm_style.append(("LINESBEFORE", (0, i), (0, i), 3, sc)) | |
| bm_table.setStyle(TableStyle(bm_style)) | |
| items.append(bm_table) | |
| items.append(Spacer(1, 6*mm)) | |
| return items | |
| def _build_protocol_section( | |
| styles, W, | |
| icon: str, | |
| title: str, | |
| color: HexColor, | |
| content: str, | |
| ) -> list: | |
| if not content or not content.strip(): | |
| return [] | |
| items = [] | |
| # Section header card | |
| header_data = [[ | |
| Paragraph(icon, ParagraphStyle( | |
| "icon", fontName="Helvetica-Bold", fontSize=7, | |
| textColor=color, leading=10, letterSpacing=1.5, | |
| )), | |
| Paragraph(title, ParagraphStyle( | |
| "st", fontName="Helvetica-Bold", fontSize=12, | |
| textColor=white, leading=15, | |
| )), | |
| ]] | |
| header_table = Table(header_data, colWidths=[25*mm, W - 25*mm]) | |
| header_table.setStyle(TableStyle([ | |
| ("BACKGROUND", (0, 0), (-1, -1), C_ELEVATED), | |
| ("TOPPADDING", (0, 0), (-1, -1), 9), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 9), | |
| ("LEFTPADDING", (0, 0), (-1, -1), 10), | |
| ("RIGHTPADDING", (0, 0), (-1, -1), 10), | |
| ("LINESBEFORE", (0, 0), (0, 0), 3, color), | |
| ("VALIGN", (0, 0), (-1, -1), "MIDDLE"), | |
| ])) | |
| items.append(KeepTogether([header_table])) | |
| # Content β strip markdown and render as styled paragraphs | |
| content_lines = _parse_markdown_to_paragraphs(content, styles, W) | |
| items += content_lines | |
| items.append(Spacer(1, 4*mm)) | |
| items.append(HRFlowable(width=W, thickness=0.5, color=C_LINE, spaceAfter=4*mm)) | |
| return items | |
| def _build_footer_block(styles, W) -> list: | |
| items = [] | |
| items.append(Spacer(1, 4*mm)) | |
| items.append(Paragraph( | |
| "Tubuh Anda bukan sekadar 'normal' β Anda layak mendapatkan yang optimal.", | |
| styles["quote"], | |
| )) | |
| items.append(Paragraph( | |
| "β Benjamin White, Founder Human+ Bali", | |
| ParagraphStyle("attr", fontName="Helvetica", fontSize=8, | |
| textColor=C_MUTED, alignment=TA_CENTER, leading=11), | |
| )) | |
| items.append(Spacer(1, 6*mm)) | |
| # Gradient-style divider (simulated with two colored cells) | |
| div_data = [[" ", " "]] | |
| div_table = Table(div_data, colWidths=[W/2, W/2]) | |
| div_table.setStyle(TableStyle([ | |
| ("BACKGROUND", (0, 0), (0, 0), C_VIOLET), | |
| ("BACKGROUND", (1, 0), (1, 0), C_CYAN), | |
| ("TOPPADDING", (0, 0), (-1, -1), 1.5), | |
| ("BOTTOMPADDING", (0, 0), (-1, -1), 1.5), | |
| ])) | |
| items.append(div_table) | |
| items.append(Spacer(1, 4*mm)) | |
| disclaimer = ( | |
| "Disclaimer: Laporan ini bukan pengganti konsultasi medis. " | |
| "Final protocol selalu direview oleh practitioner Human+ sebelum diberikan. " | |
| "Untuk konsultasi personal, hubungi @bennywhitethatsright di Instagram." | |
| ) | |
| items.append(Paragraph(disclaimer, styles["caption"])) | |
| return items | |
| # ββ Helpers βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ | |
| def _stat_cell(value: str, label: str, color: HexColor): | |
| """Build a stat count cell for the summary table.""" | |
| return [ | |
| Paragraph(value, ParagraphStyle( | |
| "sv", fontName="Helvetica-Bold", fontSize=20, | |
| textColor=color, alignment=TA_CENTER, leading=24, | |
| )), | |
| Paragraph(label, ParagraphStyle( | |
| "sl", fontName="Helvetica-Bold", fontSize=6, | |
| textColor=C_MUTED, alignment=TA_CENTER, leading=8, letterSpacing=1.2, | |
| )), | |
| ] | |
| def _parse_markdown_to_paragraphs(text: str, styles: dict, W: float) -> list: | |
| """ | |
| Simple markdown β ReportLab paragraph converter. | |
| Handles: **bold**, # headers, - bullets, tables (basic), plain text. | |
| """ | |
| import re | |
| items = [] | |
| lines = text.strip().split("\n") | |
| for line in lines: | |
| stripped = line.strip() | |
| if not stripped: | |
| items.append(Spacer(1, 2*mm)) | |
| continue | |
| # Header lines | |
| if stripped.startswith("### "): | |
| text_content = stripped[4:] | |
| items.append(Paragraph( | |
| _md_inline(text_content), | |
| ParagraphStyle("h3", fontName="Helvetica-Bold", fontSize=10, | |
| textColor=C_TEXT, spaceBefore=6, spaceAfter=3, leading=14), | |
| )) | |
| elif stripped.startswith("## "): | |
| text_content = stripped[3:] | |
| items.append(Paragraph( | |
| _md_inline(text_content), | |
| ParagraphStyle("h2", fontName="Helvetica-Bold", fontSize=11, | |
| textColor=white, spaceBefore=8, spaceAfter=4, leading=15), | |
| )) | |
| elif stripped.startswith("**") and stripped.endswith("**") and stripped.count("**") == 2: | |
| # Standalone bold line β treat as sub-header | |
| inner = stripped.strip("*") | |
| items.append(Paragraph( | |
| inner, | |
| ParagraphStyle("bold_line", fontName="Helvetica-Bold", fontSize=9, | |
| textColor=C_TEXT, spaceBefore=4, spaceAfter=2, leading=13), | |
| )) | |
| elif stripped.startswith("- ") or stripped.startswith("* "): | |
| # Bullet | |
| content = stripped[2:] | |
| items.append(Paragraph( | |
| f"β’ {_md_inline(content)}", | |
| ParagraphStyle("bullet", fontName="Helvetica", fontSize=9, | |
| textColor=C_MUTED, leftIndent=8, spaceAfter=2, | |
| leading=13), | |
| )) | |
| elif re.match(r"^\|.+\|$", stripped): | |
| # Skip markdown table rows β complex tables handled separately | |
| pass | |
| elif stripped.startswith("|---") or stripped == "": | |
| pass | |
| else: | |
| items.append(Paragraph( | |
| _md_inline(stripped), | |
| styles["body"], | |
| )) | |
| return items | |
| def _md_inline(text: str) -> str: | |
| """Convert inline markdown (**bold**, *italic*) to ReportLab XML.""" | |
| import re | |
| # Bold | |
| text = re.sub(r"\*\*(.+?)\*\*", r"<b>\1</b>", text) | |
| # Italic | |
| text = re.sub(r"\*(.+?)\*", r"<i>\1</i>", text) | |
| # Inline code | |
| text = re.sub(r"`(.+?)`", r"<font name='Courier'>\1</font>", text) | |
| return text | |