waliullah123 commited on
Commit
14b2035
Β·
verified Β·
1 Parent(s): e6414cc

fix: mount gradio on fastapi directly

Browse files
Files changed (1) hide show
  1. app.py +23 -70
app.py CHANGED
@@ -655,29 +655,16 @@ def verify_claim():
655
  init_db() # Ensure DB exists before accepting requests
656
  load_models()
657
 
658
- # ─── Gradio + Flask Integration via Thread Proxy ──────────────────────────────
659
- # Flask runs on internal port 7861. Gradio exposes it via a FastAPI proxy route
660
- # at /backend/{path}, which forwards to http://127.0.0.1:7861/{path}.
661
- # This avoids all WSGIMiddleware path-stripping conflicts with HF's Gradio proxy.
662
  try:
663
- import threading
664
- import httpx
665
  import gradio as gr
666
  import spaces
667
- from fastapi import Request as _FastAPIRequest
668
- from fastapi.responses import Response as _FastAPIResponse
669
 
670
- # ── 1. Start Flask on internal port 7861 ─────────────────────────────────
671
- _FLASK_PORT = 7861
672
-
673
- def _run_flask_internal():
674
- logger.info(f"Starting internal Flask server on port {_FLASK_PORT}...")
675
- app.run(host='127.0.0.1', port=_FLASK_PORT, debug=False, use_reloader=False)
676
-
677
- _flask_thread = threading.Thread(target=_run_flask_internal, daemon=True)
678
- _flask_thread.start()
679
-
680
- # ── 2. Gradio UI ─────────────────────────────────────────────────────────
681
  @spaces.GPU
682
  def predict_gradio(statement, model_type):
683
  if not statement or len(statement) < 5:
@@ -715,58 +702,22 @@ try:
715
  ],
716
  outputs="text",
717
  title="Truth Detector API & Interactive Demo",
718
- description="Backend API for Fake News Detection. REST API available at /backend/api/*"
719
  )
720
 
721
- # ── 3. FastAPI middleware proxy: /backend/{path} β†’ Flask on 127.0.0.1:7861/{path} ──
722
- _SKIP_HEADERS = {'host', 'content-length', 'transfer-encoding', 'content-encoding'}
723
-
724
- @demo.app.middleware("http")
725
- async def flask_proxy_middleware(request: _FastAPIRequest, call_next):
726
- if request.url.path.startswith("/backend/"):
727
- target_path = request.url.path[len("/backend"):]
728
- if not target_path.startswith("/"):
729
- target_path = "/" + target_path
730
-
731
- target_url = f"http://127.0.0.1:{_FLASK_PORT}{target_path}"
732
-
733
- # Read the request body
734
- body = await request.body()
735
-
736
- fwd_headers = {
737
- k: v for k, v in request.headers.items()
738
- if k.lower() not in _SKIP_HEADERS
739
- }
740
-
741
- try:
742
- async with httpx.AsyncClient(timeout=60) as client:
743
- resp = await client.request(
744
- method=request.method,
745
- url=target_url,
746
- headers=fwd_headers,
747
- content=body,
748
- params=dict(request.query_params),
749
- follow_redirects=True,
750
- )
751
- resp_headers = {
752
- k: v for k, v in resp.headers.items()
753
- if k.lower() not in _SKIP_HEADERS
754
- }
755
- return _FastAPIResponse(
756
- content=resp.content,
757
- status_code=resp.status_code,
758
- headers=resp_headers,
759
- )
760
- except Exception as proxy_err:
761
- logger.error(f"Proxy error for {request.url.path}: {proxy_err}")
762
- return _FastAPIResponse(
763
- content=b'{"error":"Backend proxy error","detail":"' + str(proxy_err).encode() + b'"}',
764
- status_code=502,
765
- headers={"Content-Type": "application/json"},
766
- )
767
-
768
- # If not /backend/*, let Gradio handle it normally
769
- return await call_next(request)
770
 
771
  _GRADIO_AVAILABLE = True
772
 
@@ -777,7 +728,9 @@ except ImportError as _ie:
777
  if __name__ == '__main__':
778
  port = int(os.environ.get('PORT', 7860))
779
  if _GRADIO_AVAILABLE:
780
- demo.launch(server_name="0.0.0.0", server_port=port)
 
 
781
  else:
782
  app.run(host='0.0.0.0', port=port, debug=False)
783
 
 
655
  init_db() # Ensure DB exists before accepting requests
656
  load_models()
657
 
658
+ # ─── Gradio + Flask Integration via FastAPI mount ──────────────────────────────
659
+ # The official way to combine Gradio and custom APIs in HF Spaces is to create
660
+ # a FastAPI app, mount the custom API, and then mount Gradio on top.
 
661
  try:
 
 
662
  import gradio as gr
663
  import spaces
664
+ from fastapi import FastAPI
665
+ from fastapi.middleware.wsgi import WSGIMiddleware
666
 
667
+ # ── 1. Gradio UI ─────────────────────────────────────────────────────────
 
 
 
 
 
 
 
 
 
 
668
  @spaces.GPU
669
  def predict_gradio(statement, model_type):
670
  if not statement or len(statement) < 5:
 
702
  ],
703
  outputs="text",
704
  title="Truth Detector API & Interactive Demo",
705
+ description="Backend API for Fake News Detection. REST API available at /api/*"
706
  )
707
 
708
+ # ── 2. Create master FastAPI app ─────────────────────────────────────────
709
+ # We rename the existing Flask app to flask_app, and create a new FastAPI app
710
+ # named `app` because Hugging Face will automatically run the variable named `app`.
711
+ flask_app = app
712
+ app = FastAPI()
713
+
714
+ # Mount Flask API routes at /api/ (This handles /api/predict, /api/auth/*, etc.)
715
+ # Flask routes internally start with /api (e.g. @app.route('/api/health')),
716
+ # so we mount it at root "/" so that /api/health goes straight to Flask's /api/health
717
+ app.mount("/flask", WSGIMiddleware(flask_app))
718
+
719
+ # Mount Gradio app at root
720
+ app = gr.mount_gradio_app(app, demo, path="/")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
721
 
722
  _GRADIO_AVAILABLE = True
723
 
 
728
  if __name__ == '__main__':
729
  port = int(os.environ.get('PORT', 7860))
730
  if _GRADIO_AVAILABLE:
731
+ # For local testing, run the master FastAPI app with Uvicorn
732
+ import uvicorn
733
+ uvicorn.run(app, host="0.0.0.0", port=port)
734
  else:
735
  app.run(host='0.0.0.0', port=port, debug=False)
736