Spaces:
Running on Zero
Running on Zero
| """Haqeeqat Check — Gradio interface for Hugging Face Spaces. | |
| Run locally: python app.py | |
| """ | |
| import os | |
| import subprocess | |
| import sys | |
| from pathlib import Path | |
| # --------------------------------------------------------------------------- | |
| # Ensure GROQ_API_KEY is loaded from Space secrets before any module import | |
| # --------------------------------------------------------------------------- | |
| if not os.environ.get("GROQ_API_KEY"): | |
| pass # will be read at runtime by verification/config.py | |
| import gradio as gr | |
| try: | |
| import spaces | |
| _HAS_SPACES = True | |
| except ImportError: | |
| _HAS_SPACES = False | |
| # --------------------------------------------------------------------------- | |
| # Model bootstrap — runs once at import time | |
| # --------------------------------------------------------------------------- | |
| _MODEL_FILES = ["best_norm_ED.pth", "yolov8m_UrduDoc.pt"] | |
| def _ensure_models(): | |
| """Download OCR + Whisper models if not already present.""" | |
| root = Path(__file__).resolve().parent | |
| models_dir = root / "models" | |
| if os.environ.get("SPACE_ID"): | |
| models_dir = Path("/home/user/app/models") | |
| if all((models_dir / name).is_file() for name in _MODEL_FILES): | |
| return | |
| subprocess.run( | |
| [sys.executable, str(root / "download_models.py")], | |
| check=True, | |
| ) | |
| _ensure_models() | |
| # --------------------------------------------------------------------------- | |
| # Lazy singletons — heavy imports deferred until first request | |
| # --------------------------------------------------------------------------- | |
| _ingestor = None | |
| _agent = None | |
| def _get_ingestor(): | |
| global _ingestor | |
| if _ingestor is None: | |
| from ingestion.ingestor import HaqeeqatIngestor | |
| _ingestor = HaqeeqatIngestor() | |
| return _ingestor | |
| def _get_agent(): | |
| global _agent | |
| if _agent is None: | |
| from verification.verdict_agent import VerdictAgent | |
| _agent = VerdictAgent() | |
| return _agent | |
| # --------------------------------------------------------------------------- | |
| # Labels | |
| # --------------------------------------------------------------------------- | |
| URDU_LABELS = {"sacha": "سچا", "jhoota": "جھوٹا", "mashkook": "مشکوک"} | |
| ENGLISH_LABELS = {"sacha": "True", "jhoota": "False", "mashkook": "Unverified"} | |
| VERDICT_ICONS = {"sacha": "✔", "jhoota": "✗", "mashkook": "?"} | |
| # --------------------------------------------------------------------------- | |
| # Core processing | |
| # --------------------------------------------------------------------------- | |
| if _HAS_SPACES: | |
| def _gpu_startup(): | |
| """Dummy function so Gradio 6.x detects a GPU-capable handler at startup.""" | |
| pass | |
| def _resolve_path(file_data) -> str | None: | |
| """Extract a filesystem path from a Gradio FileData object or plain string.""" | |
| if isinstance(file_data, str): | |
| return file_data | |
| # Gradio 6.x FileData: object with .path or dict-like access | |
| if hasattr(file_data, "path"): | |
| return file_data.path | |
| if isinstance(file_data, dict): | |
| return file_data.get("path") | |
| return None | |
| def _process_media_inner(file_data) -> tuple[str, str]: | |
| """Ingest a media file, verify claims, return (verdict_box, reasoning_box).""" | |
| if file_data is None: | |
| return "کوئی فائل منتخب نہیں / No file selected.", "" | |
| # Gradio 6.x passes a FileData object; extract the path string | |
| file_path = _resolve_path(file_data) | |
| if not file_path: | |
| return "کوئی فائل منتخب نہیں / No file selected.", "" | |
| ingestor = _get_ingestor() | |
| agent = _get_agent() | |
| report = ingestor.ingest(file_path) | |
| text = report.get("combined_text", "") | |
| if not text or not text.strip(): | |
| return "کوئی متن نکالا نہیں جا سکا / No text was extracted from the file.", "" | |
| if report.get("metadata", {}).get("ocr_garbled"): | |
| return ( | |
| "تصحیح OCR ناکام رہی / OCR failed to read this image properly.\n" | |
| "براہ کرم واضح تصویر اپ لوڈ کریں / Please upload a clearer image." | |
| ), f"استخراج شدہ متن:\n{text[:300]}" | |
| result = agent.run(text) | |
| if not result.is_checkworthy: | |
| return "کوئی قابلِ تصدیق دعویٰ نہیں / No checkworthy claim found.", ( | |
| f"استخراج شدہ متن:\n{text[:500]}" | |
| ) | |
| verdict_box = _format_verdict(result) | |
| reasoning_box = _format_reasoning(result) | |
| return verdict_box, reasoning_box | |
| def _process_text(text: str) -> tuple[str, str]: | |
| """Verify a pasted text claim, return (verdict_box, reasoning_box).""" | |
| if not text or not text.strip(): | |
| return "براہ کرم متن لکھیں / Please enter some text.", "" | |
| agent = _get_agent() | |
| result = agent.run(text) | |
| if not result.is_checkworthy: | |
| return "کوئی قابلِ تصدیق دعویٰ نہیں / No checkworthy claim found.", "" | |
| verdict_box = _format_verdict(result) | |
| reasoning_box = _format_reasoning(result) | |
| return verdict_box, reasoning_box | |
| # Wrap _process_media_inner with @spaces.GPU on HF so UTRNet gets a GPU. | |
| if _HAS_SPACES: | |
| def _process_media(file_data) -> tuple[str, str]: | |
| return _process_media_inner(file_data) | |
| else: | |
| _process_media = _process_media_inner | |
| def _format_verdict(result) -> str: | |
| key = result.verdict.value | |
| icon = VERDICT_ICONS[key] | |
| urdu_label = URDU_LABELS[key] | |
| eng_label = ENGLISH_LABELS[key] | |
| lines = [ | |
| f"{icon} فیصلہ / Verdict: {urdu_label} ({eng_label})", | |
| f" Confidence: {result.confidence:.0%}", | |
| "", | |
| f"دعویٰ / Claim:", | |
| f" {result.claim_urdu}", | |
| f" {result.claim_english}", | |
| ] | |
| return "\n".join(lines) | |
| def _format_reasoning(result) -> str: | |
| parts = [ | |
| "وجوہات / Reasoning:", | |
| "", | |
| result.reasoning_urdu, | |
| "", | |
| result.reasoning_english, | |
| ] | |
| if result.evidence: | |
| parts.append("") | |
| parts.append("شواہد / Sources:") | |
| for item in result.evidence: | |
| parts.append(f" [{item.source_domain}] {item.title}") | |
| parts.append(f" {item.url}") | |
| if item.snippet: | |
| parts.append(f" {item.snippet[:200]}") | |
| parts.append("") | |
| return "\n".join(parts) | |
| # --------------------------------------------------------------------------- | |
| # Gradio UI | |
| # --------------------------------------------------------------------------- | |
| def build_ui() -> gr.Blocks: | |
| with gr.Blocks( | |
| title="Haqeeqat Check — Urdu Misinformation Detector", | |
| ) as demo: | |
| gr.Markdown( | |
| "# Uraan Techathon 2.0\n" | |
| "# Haqeeqat Check: Urdu Misinformation Detector\n" | |
| "### حقیقت چیک: اردو غلط معلومات کی جانچ پڑتال" | |
| ) | |
| with gr.Tabs(): | |
| with gr.Tab("Image"): | |
| img_input = gr.Image(label="تصویر اپ لوڈ کریں / Upload Image", type="filepath") | |
| img_btn = gr.Button("Check / چیک کریں", variant="primary") | |
| with gr.Tab("Audio"): | |
| aud_input = gr.Audio(label="آڈیو اپ لوڈ کریں / Upload Audio", type="filepath") | |
| aud_btn = gr.Button("Check / چیک کریں", variant="primary") | |
| with gr.Tab("Video"): | |
| vid_input = gr.Video(label="ویڈیو اپ لوڈ کریں / Upload Video") | |
| vid_btn = gr.Button("Check / چیک کریں", variant="primary") | |
| with gr.Tab("Paste Text"): | |
| txt_input = gr.Textbox( | |
| label="اردو متن لکھیں یا پیسٹ کریں / Enter or paste Urdu text", | |
| lines=5, | |
| ) | |
| txt_btn = gr.Button("Check / چیک کریں", variant="primary") | |
| gr.Markdown("---") | |
| verdict_output = gr.Textbox( | |
| label="فیصلہ / Verdict", | |
| lines=8, | |
| interactive=False, | |
| ) | |
| reasoning_output = gr.Textbox( | |
| label="وجوہات و شواہد / Reasoning & Sources", | |
| lines=14, | |
| interactive=False, | |
| ) | |
| img_btn.click(fn=_process_media, inputs=img_input, outputs=[verdict_output, reasoning_output]) | |
| aud_btn.click(fn=_process_media, inputs=aud_input, outputs=[verdict_output, reasoning_output]) | |
| vid_btn.click(fn=_process_media, inputs=vid_input, outputs=[verdict_output, reasoning_output]) | |
| txt_btn.click(fn=_process_text, inputs=txt_input, outputs=[verdict_output, reasoning_output]) | |
| return demo | |
| if __name__ == "__main__": | |
| demo = build_ui() | |
| demo.launch(theme=gr.themes.Soft()) | |