File size: 2,620 Bytes
75db650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
689163b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
75db650
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
"""
Hugging Face Spaces entry point (Gradio).

Run locally:
  python app.py --config config/default_config.yaml --host 0.0.0.0 --port 7860
"""

from __future__ import annotations

import argparse
import logging
import os
from pathlib import Path

from radiology_rag.gradio_compat import patch_gradio_predict_body_for_pydantic_v2
from radiology_rag.ui import RadiologyRAGApp


# NOTE: ZeroGPU compatibility
# If your Space hardware is set to "ZeroGPU", Hugging Face requires at least one
# function decorated with `@spaces.GPU`, otherwise the Space will fail at startup
# with: "No @spaces.GPU function detected during startup".
#
# This app is API-first and does not require a GPU, but we provide a tiny no-op
# GPU-decorated function so the Space can still boot on ZeroGPU.
try:
    import spaces  # type: ignore

    @spaces.GPU  # type: ignore[attr-defined]
    def _zerogpu_noop() -> None:
        return None

except Exception:
    # Fallback for local runs or non-ZeroGPU environments.
    def _zerogpu_noop() -> None:  # noqa: D401
        return None


def _configure_logging() -> None:
    level = os.getenv("LOG_LEVEL", "INFO").upper()
    logging.basicConfig(
        level=getattr(logging, level, logging.INFO),
        format="%(asctime)s - %(levelname)s - %(message)s",
    )


def _default_storage_dir() -> str:
    # Prefer /data on Spaces if persistent storage is enabled.
    if Path("/data").exists():
        return "/data/radiology_rag"
    return "./storage"


def main() -> int:
    _configure_logging()

    parser = argparse.ArgumentParser(description="Radiology RAG (Spaces-ready)")
    parser.add_argument("--config", type=str, default="config/default_config.yaml", help="Path to config YAML")
    parser.add_argument("--host", type=str, default="0.0.0.0", help="Server host")
    parser.add_argument("--port", type=int, default=int(os.getenv("PORT", "7860")), help="Server port")
    args = parser.parse_args()

    # Ensure storage dir env is set early so config interpolation uses it.
    if not os.getenv("RAG_STORAGE_DIR"):
        os.environ["RAG_STORAGE_DIR"] = _default_storage_dir()

    # Optional compatibility patch for Gradio 4.16 + Pydantic v2.
    if patch_gradio_predict_body_for_pydantic_v2():
        logging.getLogger(__name__).info("Applied Gradio/Pydantic v2 compatibility patch")

    app = RadiologyRAGApp(config_path=args.config)
    demo = app.create_interface()

    demo.launch(
        server_name=args.host,
        server_port=args.port,
        share=False,
        show_error=True,
    )
    return 0


if __name__ == "__main__":
    raise SystemExit(main())