Spaces:
Sleeping
Sleeping
fix: use threading+httpx proxy instead of WSGIMiddleware mount
Browse files
app.py
CHANGED
|
@@ -655,14 +655,29 @@ def verify_claim():
|
|
| 655 |
init_db() # Ensure DB exists before accepting requests
|
| 656 |
load_models()
|
| 657 |
|
| 658 |
-
# βββ
|
| 659 |
-
#
|
| 660 |
-
#
|
|
|
|
| 661 |
try:
|
|
|
|
|
|
|
| 662 |
import gradio as gr
|
| 663 |
import spaces
|
| 664 |
-
from fastapi
|
|
|
|
| 665 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 666 |
@spaces.GPU
|
| 667 |
def predict_gradio(statement, model_type):
|
| 668 |
if not statement or len(statement) < 5:
|
|
@@ -700,13 +715,55 @@ try:
|
|
| 700 |
],
|
| 701 |
outputs="text",
|
| 702 |
title="Truth Detector API & Interactive Demo",
|
| 703 |
-
description="Backend API for Fake News Detection. REST API
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 704 |
)
|
| 705 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 706 |
_GRADIO_AVAILABLE = True
|
| 707 |
-
|
|
|
|
| 708 |
_GRADIO_AVAILABLE = False
|
| 709 |
-
logger.info("Gradio not available β running in Flask-only (Docker) mode.")
|
| 710 |
|
| 711 |
if __name__ == '__main__':
|
| 712 |
port = int(os.environ.get('PORT', 7860))
|
|
@@ -715,4 +772,3 @@ if __name__ == '__main__':
|
|
| 715 |
else:
|
| 716 |
app.run(host='0.0.0.0', port=port, debug=False)
|
| 717 |
|
| 718 |
-
|
|
|
|
| 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 |
],
|
| 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 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.api_route(
|
| 725 |
+
"/backend/{path:path}",
|
| 726 |
+
methods=["GET", "POST", "PUT", "DELETE", "OPTIONS", "HEAD", "PATCH"]
|
| 727 |
)
|
| 728 |
+
async def flask_proxy(request: _FastAPIRequest, path: str):
|
| 729 |
+
"""Transparent proxy forwarding /backend/* β internal Flask server."""
|
| 730 |
+
target_url = f"http://127.0.0.1:{_FLASK_PORT}/{path}"
|
| 731 |
+
fwd_headers = {
|
| 732 |
+
k: v for k, v in request.headers.items()
|
| 733 |
+
if k.lower() not in _SKIP_HEADERS
|
| 734 |
+
}
|
| 735 |
+
try:
|
| 736 |
+
async with httpx.AsyncClient(timeout=60) as client:
|
| 737 |
+
resp = await client.request(
|
| 738 |
+
method=request.method,
|
| 739 |
+
url=target_url,
|
| 740 |
+
headers=fwd_headers,
|
| 741 |
+
content=await request.body(),
|
| 742 |
+
params=dict(request.query_params),
|
| 743 |
+
follow_redirects=True,
|
| 744 |
+
)
|
| 745 |
+
resp_headers = {
|
| 746 |
+
k: v for k, v in resp.headers.items()
|
| 747 |
+
if k.lower() not in _SKIP_HEADERS
|
| 748 |
+
}
|
| 749 |
+
return _FastAPIResponse(
|
| 750 |
+
content=resp.content,
|
| 751 |
+
status_code=resp.status_code,
|
| 752 |
+
headers=resp_headers,
|
| 753 |
+
)
|
| 754 |
+
except Exception as proxy_err:
|
| 755 |
+
logger.error(f"Proxy error for /{path}: {proxy_err}")
|
| 756 |
+
return _FastAPIResponse(
|
| 757 |
+
content=b'{"error":"Backend proxy error","detail":"' + str(proxy_err).encode() + b'"}',
|
| 758 |
+
status_code=502,
|
| 759 |
+
headers={"Content-Type": "application/json"},
|
| 760 |
+
)
|
| 761 |
+
|
| 762 |
_GRADIO_AVAILABLE = True
|
| 763 |
+
|
| 764 |
+
except ImportError as _ie:
|
| 765 |
_GRADIO_AVAILABLE = False
|
| 766 |
+
logger.info(f"Gradio not available ({_ie}) β running in Flask-only (Docker) mode.")
|
| 767 |
|
| 768 |
if __name__ == '__main__':
|
| 769 |
port = int(os.environ.get('PORT', 7860))
|
|
|
|
| 772 |
else:
|
| 773 |
app.run(host='0.0.0.0', port=port, debug=False)
|
| 774 |
|
|
|