Spaces:
Running on Zero
Running on Zero
feat: resolve nearby masjids 500 error, add popular sanctuaries, and optimize search architecture
ae9655d Download scripts/generate_architecture_pdf.py from sahihislam/superadmin: direct link, hf CLI and curl.
- Browser
- Download file 24 kB
-
https://huggingface.co/spaces/sahihislam/superadmin/resolve/main/scripts/generate_architecture_pdf.py
- Command line
-
hf download hf://spaces/sahihislam/superadmin/scripts/generate_architecture_pdf.py
-
curl -L -o generate_architecture_pdf.py https://huggingface.co/spaces/sahihislam/superadmin/resolve/main/scripts/generate_architecture_pdf.py
24 kB
| """ | |
| Generate an executive, publication-grade Architecture & Workflow Specification PDF for Sahih Islam. | |
| Uses WeasyPrint to render clean HTML5/CSS3 into a high-resolution PDF. | |
| """ | |
| import os | |
| import sys | |
| sys.stdout.reconfigure(encoding='utf-8') | |
| from pathlib import Path | |
| import weasyprint | |
| OUTPUT_PDF = Path("D:/Project-x/SahihIslam_Architecture_Workflow.pdf") | |
| HTML_CONTENT = """<!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <title>Sahih Islam — System Architecture & Workflow Specification</title> | |
| <style> | |
| @page { | |
| size: A4; | |
| margin: 20mm 15mm 20mm 15mm; | |
| @top-right { | |
| content: "Sahih Islam — Architecture Specification"; | |
| font-size: 8pt; | |
| color: #718096; | |
| font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
| } | |
| @bottom-center { | |
| content: "Page " counter(page) " of " counter(pages); | |
| font-size: 8pt; | |
| color: #718096; | |
| font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
| } | |
| } | |
| body { | |
| font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; | |
| color: #2D3748; | |
| line-height: 1.55; | |
| font-size: 10pt; | |
| } | |
| h1 { | |
| color: #1A365D; | |
| font-size: 24pt; | |
| margin-bottom: 4px; | |
| font-weight: 800; | |
| letter-spacing: -0.5px; | |
| } | |
| .subtitle { | |
| color: #4A5568; | |
| font-size: 11pt; | |
| margin-top: 0; | |
| margin-bottom: 24px; | |
| font-weight: 400; | |
| border-bottom: 2px solid #E2E8F0; | |
| padding-bottom: 12px; | |
| } | |
| h2 { | |
| color: #2B6CB0; | |
| font-size: 15pt; | |
| margin-top: 24px; | |
| margin-bottom: 10px; | |
| font-weight: 700; | |
| border-bottom: 1px solid #E2E8F0; | |
| padding-bottom: 4px; | |
| page-break-after: avoid; | |
| } | |
| h3 { | |
| color: #2D3748; | |
| font-size: 12pt; | |
| margin-top: 16px; | |
| margin-bottom: 6px; | |
| font-weight: 600; | |
| page-break-after: avoid; | |
| } | |
| p { | |
| margin-top: 0; | |
| margin-bottom: 10px; | |
| } | |
| .card { | |
| background-color: #F7FAFC; | |
| border-left: 4px solid #3182CE; | |
| padding: 12px 16px; | |
| margin-bottom: 16px; | |
| border-radius: 0 6px 6px 0; | |
| } | |
| .card-title { | |
| font-weight: 700; | |
| color: #2B6CB0; | |
| margin-bottom: 4px; | |
| font-size: 10.5pt; | |
| } | |
| .grid-2 { | |
| display: flex; | |
| flex-direction: row; | |
| gap: 15px; | |
| margin-bottom: 15px; | |
| } | |
| .grid-col { | |
| flex: 1; | |
| background: #FFFFFF; | |
| border: 1px solid #E2E8F0; | |
| border-radius: 6px; | |
| padding: 12px; | |
| box-shadow: 0 1px 3px rgba(0,0,0,0.05); | |
| } | |
| table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| margin-top: 10px; | |
| margin-bottom: 18px; | |
| font-size: 9pt; | |
| } | |
| th { | |
| background-color: #EDF2F7; | |
| color: #2D3748; | |
| text-align: left; | |
| padding: 8px 10px; | |
| font-weight: 700; | |
| border-top: 1px solid #CBD5E0; | |
| border-bottom: 2px solid #CBD5E0; | |
| } | |
| td { | |
| padding: 7px 10px; | |
| border-bottom: 1px solid #E2E8F0; | |
| vertical-align: top; | |
| } | |
| tr:nth-child(even) td { | |
| background-color: #F8FAFC; | |
| } | |
| .badge { | |
| display: inline-block; | |
| padding: 2px 7px; | |
| border-radius: 10px; | |
| font-size: 7.5pt; | |
| font-weight: 700; | |
| text-transform: uppercase; | |
| } | |
| .badge-primary { background: #EBF8FF; color: #2B6CB0; } | |
| .badge-success { background: #F0FFF4; color: #276749; } | |
| .badge-warning { background: #FFFAF0; color: #C05621; } | |
| .badge-danger { background: #FFF5F5; color: #9B2C2C; } | |
| .badge-purple { background: #FAF5FF; color: #6B46C1; } | |
| .workflow-step { | |
| display: flex; | |
| margin-bottom: 12px; | |
| page-break-inside: avoid; | |
| } | |
| .step-num { | |
| width: 28px; | |
| height: 28px; | |
| background: #3182CE; | |
| color: #FFFFFF; | |
| border-radius: 50%; | |
| text-align: center; | |
| line-height: 28px; | |
| font-weight: 700; | |
| font-size: 10pt; | |
| margin-right: 12px; | |
| flex-shrink: 0; | |
| } | |
| .step-content { | |
| flex: 1; | |
| background: #FFFFFF; | |
| border: 1px solid #E2E8F0; | |
| border-radius: 6px; | |
| padding: 10px 14px; | |
| } | |
| .step-header { | |
| font-weight: 700; | |
| color: #1A365D; | |
| margin-bottom: 4px; | |
| font-size: 10pt; | |
| } | |
| .code-block { | |
| background: #1A202C; | |
| color: #E2E8F0; | |
| padding: 10px; | |
| border-radius: 5px; | |
| font-family: 'Courier New', Courier, monospace; | |
| font-size: 8pt; | |
| margin-top: 6px; | |
| margin-bottom: 8px; | |
| white-space: pre-wrap; | |
| } | |
| .page-break { | |
| page-break-before: always; | |
| } | |
| .tagline { | |
| background: #2B6CB0; | |
| color: white; | |
| padding: 15px; | |
| border-radius: 6px; | |
| margin-bottom: 20px; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="tagline"> | |
| <h1 style="color: white; margin-top: 0;">Sahih Islam Enterprise Architecture</h1> | |
| <div style="font-size: 11pt; opacity: 0.95;"> | |
| Comprehensive System Workflow, Component Functionality & Data Flow Blueprint | |
| </div> | |
| </div> | |
| <p> | |
| <strong>Sahih Islam</strong> is engineered as a high-precision, low-latency, distributed Islamic intelligence ecosystem. | |
| It integrates an offline-capable cross-platform mobile client with an asynchronous backend, distributed object storage, | |
| in-memory caching, double-entry financial ledger accounting, and a pure cloud high-performance semantic search and RAG engine. | |
| </p> | |
| <h2>1. Executive Component Matrix: What Everything Actually Does</h2> | |
| <p>Every tier in the stack serves a strictly defined, non-overlapping architectural purpose:</p> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th style="width: 18%;">Technology</th> | |
| <th style="width: 22%;">Role in Stack</th> | |
| <th style="width: 60%;">Actual Real-World Function & Responsibilities</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td><strong>FastAPI</strong><br><span class="badge badge-primary">Backend Gateway</span></td> | |
| <td>Asynchronous Python REST & SSE Server</td> | |
| <td> | |
| • Routes all client requests (auth, hadith, quran, payments, ads, masjids).<br> | |
| • Serves non-blocking Server-Sent Events (SSE) and NDJSON for real-time AI token streaming.<br> | |
| • Orchestrates cloud neural inference bridges (BGE-M3 bi-encoder + cross-encoder reranker).<br> | |
| • Validates JWTs, processes Razorpay/Google Play webhooks, orchestrates background jobs. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>MongoDB Atlas</strong><br><span class="badge badge-success">Primary Database</span></td> | |
| <td>Multi-Collection Document & Vector Store</td> | |
| <td> | |
| • Stores structured relational-like data: 24,356 Hadiths, 114 Surahs, 6,236 Ayahs, Users.<br> | |
| • Runs <strong>Atlas Vector Search</strong> (<code>$vectorSearch</code>) using 1024-dim HNSW cosine index.<br> | |
| • Stores double-entry financial ledgers (Wallets, Transactions, Invoices).<br> | |
| • Geospatial queries for Masjids (2dsphere index for nearby prayer facilities). | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>Cloudflare R2</strong><br><span class="badge badge-warning">Object Storage</span></td> | |
| <td>S3-Compatible Zero-Egress Storage & Edge CDN</td> | |
| <td> | |
| • Stores large binary assets outside MongoDB to prevent database bloat.<br> | |
| • Houses complete 114 Surah recitations (Mishary Alafasy high-quality audio files).<br> | |
| • Hosts Urdu & English Tafseer audio libraries (Dr. Israr Ahmed, Maududi).<br> | |
| • Distributes 8 multi-language Quran translation bundles (EN, UR, HI, FR, ES, ID, TR, BN).<br> | |
| • Caches and streams 16-line Mushaf Hafizi PDFs and advertiser media creatives globally with <strong>zero egress bandwidth fees</strong>. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>Redis / Upstash</strong><br><span class="badge badge-danger">In-Memory Cache</span></td> | |
| <td>Sub-millisecond State & Distributed Cache</td> | |
| <td> | |
| • Caches repetitive, read-heavy data (Prayer calculation parameters, daily Hadith pool).<br> | |
| • Rate limiting & IP throttling to safeguard expensive AI vector inference endpoints.<br> | |
| • Distributed locks for atomic wallet debit operations (prevents race-condition double spends).<br> | |
| • Caches active user tokens and real-time ad impression frequency counters. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>Flutter Client</strong><br><span class="badge badge-purple">Frontend Application</span></td> | |
| <td>Multi-Platform UI (Android, iOS, Web)</td> | |
| <td> | |
| • Renders responsive interfaces for Quran, Hadith, Tasbeeh, Ads Marketplace, and Masjid Finder.<br> | |
| • Offline-first capabilities: Local SQLite/Hive caches recent Quran, Tasbeeh counts, and settings.<br> | |
| • Executes high-precision astronomical prayer calculation algorithms locally on device.<br> | |
| • Native audio player engine with background playback, seek bars, and auto-scrolling Ayah markers. | |
| </td> | |
| </tr> | |
| <tr> | |
| <td><strong>SuperAdmin</strong><br><span class="badge badge-primary">Control Plane</span></td> | |
| <td>Enterprise Operations & Moderation Portal</td> | |
| <td> | |
| • Real-time financial telemetry (Wallet flows, platform earnings, payment gateway health).<br> | |
| • Ad review pipeline (Approve, reject, or pause advertisers' commercial campaigns).<br> | |
| • Mufti verification, Masjid claim dispute resolution, and audit log inspection. | |
| </td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| <div class="page-break"></div> | |
| <h2>2. Deep-Dive Component Architecture</h2> | |
| <div class="card"> | |
| <div class="card-title">A. FastAPI — The High-Throughput Orchestrator</div> | |
| <p> | |
| Unlike traditional synchronous frameworks (e.g. Django, Flask), FastAPI runs on top of <strong>Starlette</strong> | |
| and <strong>Uvicorn</strong> utilizing Python's asynchronous event loop (<code>asyncio</code>). | |
| In Sahih Islam, every database call uses <code>Motor</code> (non-blocking async MongoDB driver) so a single server process can sustain thousands of concurrent connections without thread exhaustion. | |
| </p> | |
| <p><strong>Key Internal Engines inside FastAPI:</strong></p> | |
| <ul> | |
| <li><strong>High-Speed Cloud Neural Engine:</strong> Highly scalable 1024-dim BGE-M3 bi-encoder embeddings and cross-encoder neural reranking routed via dedicated cloud API providers (OpenRouter, Jina, Cohere) with zero container RAM/CPU overhead.</li> | |
| <li><strong>NDJSON / SSE Streaming Pipeline:</strong> For the search/ask endpoint (<code>/api/hadith/ask</code>), FastAPI streams AI responses word-by-word as NDJSON chunks. This eliminates user perceived latency.</li> | |
| <li><strong>Background Task Dispatcher:</strong> Post-query operations (such as saving conversation history, recording ad impressions, and vectorizing memory) are dispatched to <code>BackgroundTasks</code> so the HTTP response returns immediately.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <div class="card-title">B. MongoDB Atlas — The Ground Truth & Vector Knowledge Base</div> | |
| <p> | |
| MongoDB acts as the permanent system of record. It is structured into high-performance collections with targeted indexes: | |
| </p> | |
| <ul> | |
| <li><code>hadiths</code> (24,356 items): Contains the Arabic Matn, English translation, Urdu translation, Sanad (narrator chain), grade, and pre-computed 1024-dimensional <code>embedding_1024</code> vectors.</li> | |
| <li><code>quran</code> & <code>quran_verses</code> (114 Surahs / 6,236 Ayahs): Verse-level records indexed by Surah number and Ayah number with linguistic tafseer references.</li> | |
| <li><code>wallets</code> & <code>transactions</code>: Implements transactional double-entry accounting. Wallets store available balance, locked balance, and currency. Every credit or debit logs an immutable transaction record.</li> | |
| <li><code>ads</code> & <code>ad_analytics</code>: Stores advertiser campaigns, targeting parameters, daily budget, remaining wallet balance, and real-time impression counts.</li> | |
| <li><code>vector_memory</code>: Stores past user conversations embedded into vector space so the AI can recall previous discussions in follow-up queries.</li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <div class="card-title">C. Cloudflare R2 — Heavy Object & Audio CDN</div> | |
| <p> | |
| Storing gigabytes of audio and PDF files inside MongoDB would degrade database performance, bloat backups, and skyrocket RAM costs. | |
| Sahih Islam solves this by offloading all static media to <strong>Cloudflare R2</strong>: | |
| </p> | |
| <ul> | |
| <li><strong>Zero Egress Bandwidth Pricing:</strong> Traditional clouds (AWS S3, GCP) charge \$0.08–\$0.12 per GB downloaded. Streaming gigabytes of high-quality Quran recitation audio daily would cost hundreds of dollars. Cloudflare R2 charges <strong>\$0.00 for egress bandwidth</strong>.</li> | |
| <li><strong>Global Edge Caching:</strong> R2 connects directly to Cloudflare’s CDN across 300+ global cities. When a user in the UK, USA, or South Asia plays an audio file, it is delivered from the nearest local edge server with instant time-to-first-byte (TTFB).</li> | |
| <li><strong>Storage Breakdown:</strong> | |
| <br>• <code>/surah_audio/</code>: 114 recitations in 128kbps/64kbps MP3. | |
| <br>• <code>/tafseer_audio/</code>: Thousands of detailed Tafseer lectures. | |
| <br>• <code>/quran_translations/</code>: Clean JSON translation files across 8 major world languages. | |
| <br>• <code>/mushaf_pdfs/</code>: 16-line and 15-line high-resolution Mushaf pages. | |
| </li> | |
| </ul> | |
| </div> | |
| <div class="card"> | |
| <div class="card-title">D. Redis / Upstash — Sub-Millisecond Speed Layer</div> | |
| <p> | |
| Redis operates entirely in RAM. It handles functions where a disk-based database would be too slow: | |
| </p> | |
| <ul> | |
| <li><strong>Rate Limiting:</strong> Enforces user quotas (e.g., max 20 AI searches per minute for free users, 100 for Pro users) using Redis token buckets.</li> | |
| <li><strong>Hot Query Caching:</strong> Common queries (e.g. "Surah Al-Mulk translation", "Ayah of the day", "Fajr prayer calculation constants") are cached in Redis with a TTL. Requests return in < 2 milliseconds without hitting MongoDB.</li> | |
| <li><strong>Atomic Locks for Payments:</strong> When an ad is displayed and money is deducted from an advertiser's wallet, Redis handles atomic counter decrements (<code>DECRBY</code>) to prevent balance underflow or race conditions.</li> | |
| </ul> | |
| </div> | |
| <div class="page-break"></div> | |
| <h2>3. Complete End-to-End Workflows & Data Flows</h2> | |
| <h3>Workflow 1: The AI RAG Search Engine (User Ask Page)</h3> | |
| <p>How the system processes an Islamic question through neural retrieval, verification, and streaming:</p> | |
| <div class="workflow-step"> | |
| <div class="step-num">1</div> | |
| <div class="step-content"> | |
| <div class="step-header">User Prompt Input & Intent Routing (Flutter → FastAPI)</div> | |
| The user types a query (e.g. <em>"What does Quran say about patience in hardship?"</em>) or selects books (Quran, Sahih al-Bukhari, Muslim). | |
| Flutter sends an HTTP POST request to <code>/api/hadith/ask</code>. FastAPI analyzes the intent using a local Intent Classifier. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">2</div> | |
| <div class="step-content"> | |
| <div class="step-header">Bi-Encoder Query Vectorization (Cloud Neural BGE-M3)</div> | |
| FastAPI passes the query to the high-performance <strong>BGE-M3</strong> bi-encoder. | |
| It transforms the query text into a normalized <strong>1,024-dimensional dense vector</strong>. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">3</div> | |
| <div class="step-content"> | |
| <div class="step-header">Parallel MongoDB Atlas Vector Search ($vectorSearch)</div> | |
| FastAPI dispatches parallel queries into MongoDB Atlas: | |
| <div class="code-block">{"$vectorSearch": {"index": "vector_index", "path": "embedding_1024", "queryVector": [...], "numCandidates": 100, "limit": 20}}</div> | |
| Atlas retrieves the top 20 mathematically closest candidate Hadiths and Quran verses using HNSW Cosine Similarity. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">4</div> | |
| <div class="step-content"> | |
| <div class="step-header">Cross-Encoder Neural Reranking (Precision Gate)</div> | |
| Bi-encoder recall brings potential candidates, but some might be superficially related. | |
| FastAPI pairs the query with each candidate text and runs them through the <strong>Cloud Cross-Encoder Reranker</strong>. | |
| Pairs with low relevance logits (< 0.0) are discarded. Candidates are sorted in order of absolute factual relevance. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">5</div> | |
| <div class="step-content"> | |
| <div class="step-header">Dynamic Semantic Boundary Expansion (Cloudflare R2 Context Injection)</div> | |
| For Quranic verses, an Ayah often belongs to a passage. FastAPI fetches the full Surah JSON from Cloudflare R2 / MongoDB cache, | |
| detects the surrounding Ayahs with high semantic continuation, attaches Arabic text with verse badges (e.g. ﴿153﴾), and appends audio recitation links. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">6</div> | |
| <div class="step-content"> | |
| <div class="step-header">Zero-Hallucination Strict LLM Generation & NDJSON Streaming</div> | |
| The verified religious texts are injected into the LLM system prompt under strict zero-extrapolation guardrails. | |
| Tokens are streamed live back to Flutter via <code>StreamingResponse(media_type="application/x-ndjson")</code>. | |
| The Flutter UI paints the words in real time with clickable source badges, audio player controls, and transliterations. | |
| </div> | |
| </div> | |
| <div class="page-break"></div> | |
| <h3>Workflow 2: The AADS Marketplace & Wallet Deduction Lifecycle</h3> | |
| <p>How the system serves ads, protects advertiser budgets, and handles usage-based wallet deduction:</p> | |
| <div class="workflow-step"> | |
| <div class="step-num">1</div> | |
| <div class="step-content"> | |
| <div class="step-header">Campaign Creation & Wallet Balance Verification</div> | |
| An advertiser creates an ad campaign in Flutter. | |
| The Flutter app verifies that the user's wallet balance in <code>wallets</code> covers the campaign total. | |
| If balance is insufficient, creation is rejected with an instant top-up modal. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">2</div> | |
| <div class="step-content"> | |
| <div class="step-header">Non-Sequential Weighted Probability Selection (AADS Feed)</div> | |
| When standard users scroll through the feed, Flutter requests an ad. | |
| FastAPI fetches all active campaigns with remaining daily budget and balance > 0. | |
| Instead of boring sequential loops, it computes a <strong>weighted probability distribution</strong> (based on bid tier, relevance, and impression targets) to return a randomized, high-yield ad. | |
| </div> | |
| </div> | |
| <div class="workflow-step"> | |
| <div class="step-num">3</div> | |
| <div class="step-content"> | |
| <div class="step-header">Usage-Based Deductions (Post-Impression / Click)</div> | |
| The advertiser's money is <strong>not</strong> deducted all at once upon posting. | |
| Instead, when Flutter reports a verified impression (2+ seconds view) or click, FastAPI executes an atomic debit: | |
| <div class="code-block">wallets.update_one({"user_id": seller_id, "balance": {"$gte": cost_per_click}}, {"$inc": {"balance": -cost_per_click}})</div> | |
| This guarantees fair, usage-based pay-as-you-go billing. | |
| </div> | |
| </div> | |
| <h3>Workflow 3: Quran Audio & Multi-Language Translation Delivery</h3> | |
| <div class="grid-2"> | |
| <div class="grid-col"> | |
| <strong style="color: #2B6CB0;">1. Translation Delivery Pipeline</strong> | |
| <p style="font-size: 8.5pt; margin-top: 5px;"> | |
| Flutter requests translations for a Surah. | |
| Instead of burdening MongoDB with repetitive full-text pulls, requests are routed directly to | |
| <strong>Cloudflare R2</strong> (<code>/quran_translations/{lang}.json</code>). | |
| Cloudflare's CDN caches the response at the edge, serving 114 Surahs across 8 languages in < 30ms. | |
| </p> | |
| </div> | |
| <div class="grid-col"> | |
| <strong style="color: #2B6CB0;">2. Audio Recitation Streaming</strong> | |
| <p style="font-size: 8.5pt; margin-top: 5px;"> | |
| When a user taps play on Ayah recitation or Tafseer, Flutter connects to Cloudflare R2's streaming endpoints. | |
| The native <code>just_audio</code> plugin handles chunked buffering, background lock-screen notifications, | |
| and emits Ayah completion events to automatically highlight the current verse. | |
| </p> | |
| </div> | |
| </div> | |
| <h2>4. Architecture Summary & Design Principles</h2> | |
| <ul> | |
| <li><strong>Strict Separation of Concerns:</strong> Static heavy assets live in Cloudflare R2. High-speed caching and locks live in Redis. Rich relational and vector data live in MongoDB Atlas. Computational inference and business logic live in FastAPI. Rendering and offline state live in Flutter.</li> | |
| <li><strong>Zero Data Lock-in & Predictable Costs:</strong> Using Cloudflare R2 eliminates egress fees. Using managed neural cloud endpoints eliminates server RAM/GPU maintenance costs.</li> | |
| <li><strong>Absolute Factual Rigor:</strong> The RAG architecture utilizes a dual-gate (Bi-encoder recall + Cross-encoder precision) combined with dynamic semantic boundary detection, preventing generative hallucinations in Islamic knowledge retrieval.</li> | |
| </ul> | |
| </body> | |
| </html> | |
| """ | |
| def generate_pdf(): | |
| print(f"📄 Compiling HTML and generating PDF via WeasyPrint...") | |
| html = weasyprint.HTML(string=HTML_CONTENT) | |
| html.write_pdf(str(OUTPUT_PDF)) | |
| print(f"✅ PDF successfully generated at: {OUTPUT_PDF}") | |
| print(f" File size: {OUTPUT_PDF.stat().st_size / 1024:.1f} KB") | |
| if __name__ == "__main__": | |
| generate_pdf() | |