api: Improve Gradio client stability.
Browse files
app.py
CHANGED
|
@@ -16,6 +16,7 @@ from fastapi.responses import StreamingResponse, JSONResponse
|
|
| 16 |
from pydantic import BaseModel, Field, ValidationError
|
| 17 |
from gradio_client import Client
|
| 18 |
from contextlib import asynccontextmanager
|
|
|
|
| 19 |
|
| 20 |
logging.basicConfig(
|
| 21 |
level=logging.INFO,
|
|
@@ -71,20 +72,31 @@ class SessionManager:
|
|
| 71 |
|
| 72 |
session_manager = SessionManager()
|
| 73 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
async def refresh_client(app: FastAPI):
|
| 75 |
while True:
|
| 76 |
await asyncio.sleep(15 * 60)
|
| 77 |
async with app.state.client_lock:
|
| 78 |
-
|
| 79 |
-
|
| 80 |
old_client = app.state.client
|
| 81 |
app.state.client = None
|
| 82 |
del old_client
|
| 83 |
-
|
| 84 |
-
|
| 85 |
-
|
| 86 |
-
|
| 87 |
-
|
| 88 |
|
| 89 |
async def clear_terminal_periodically():
|
| 90 |
while True:
|
|
@@ -99,6 +111,11 @@ async def lifespan(app: FastAPI):
|
|
| 99 |
app.state.session_manager = session_manager
|
| 100 |
app.state.client = None
|
| 101 |
app.state.client_lock = asyncio.Lock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 102 |
app.state.refresh_task = asyncio.create_task(refresh_client(app))
|
| 103 |
app.state.cleanup_task = asyncio.create_task(session_manager.cleanup())
|
| 104 |
app.state.clear_log_task = asyncio.create_task(clear_terminal_periodically())
|
|
@@ -208,7 +225,7 @@ async def get_client(app: FastAPI) -> Client:
|
|
| 208 |
async with app.state.client_lock:
|
| 209 |
if app.state.client is None:
|
| 210 |
try:
|
| 211 |
-
app.state.client =
|
| 212 |
logger.info("Created Gradio client connection on demand")
|
| 213 |
except Exception as e:
|
| 214 |
logger.error(f"Failed to create Gradio client: {e}", exc_info=True)
|
|
@@ -420,7 +437,10 @@ async def router(request: Request):
|
|
| 420 |
elif endpoint == "history":
|
| 421 |
return await get_history(body.user, body.session_id)
|
| 422 |
elif endpoint == "responses/cancel":
|
| 423 |
-
|
|
|
|
|
|
|
|
|
|
| 424 |
else:
|
| 425 |
raise HTTPException(status_code=404, detail="Endpoint not found")
|
| 426 |
else:
|
|
|
|
| 16 |
from pydantic import BaseModel, Field, ValidationError
|
| 17 |
from gradio_client import Client
|
| 18 |
from contextlib import asynccontextmanager
|
| 19 |
+
import httpx
|
| 20 |
|
| 21 |
logging.basicConfig(
|
| 22 |
level=logging.INFO,
|
|
|
|
| 72 |
|
| 73 |
session_manager = SessionManager()
|
| 74 |
|
| 75 |
+
async def create_gradio_client_with_retry(url: str, max_retries: int = 3, backoff_factor: float = 0.5) -> Client:
|
| 76 |
+
for attempt in range(max_retries):
|
| 77 |
+
try:
|
| 78 |
+
client = Client(url)
|
| 79 |
+
_ = client.config
|
| 80 |
+
return client
|
| 81 |
+
except (httpx.ReadTimeout, httpx.ConnectTimeout, httpx.HTTPError, Exception) as e:
|
| 82 |
+
logger.warning(f"Attempt {attempt+1}/{max_retries} failed to create Gradio client: {e}")
|
| 83 |
+
await asyncio.sleep(backoff_factor * (2 ** attempt))
|
| 84 |
+
raise RuntimeError("Failed to create Gradio client after retries")
|
| 85 |
+
|
| 86 |
async def refresh_client(app: FastAPI):
|
| 87 |
while True:
|
| 88 |
await asyncio.sleep(15 * 60)
|
| 89 |
async with app.state.client_lock:
|
| 90 |
+
try:
|
| 91 |
+
if app.state.client is not None:
|
| 92 |
old_client = app.state.client
|
| 93 |
app.state.client = None
|
| 94 |
del old_client
|
| 95 |
+
app.state.client = await create_gradio_client_with_retry("https://hadadrjt-ai.hf.space/")
|
| 96 |
+
logger.info("Refreshed Gradio client connection")
|
| 97 |
+
except Exception as e:
|
| 98 |
+
logger.error(f"Error refreshing Gradio client: {e}", exc_info=True)
|
| 99 |
+
app.state.client = None
|
| 100 |
|
| 101 |
async def clear_terminal_periodically():
|
| 102 |
while True:
|
|
|
|
| 111 |
app.state.session_manager = session_manager
|
| 112 |
app.state.client = None
|
| 113 |
app.state.client_lock = asyncio.Lock()
|
| 114 |
+
try:
|
| 115 |
+
app.state.client = await create_gradio_client_with_retry("https://hadadrjt-ai.hf.space/")
|
| 116 |
+
except Exception as e:
|
| 117 |
+
logger.error(f"Initial Gradio client creation failed: {e}", exc_info=True)
|
| 118 |
+
app.state.client = None
|
| 119 |
app.state.refresh_task = asyncio.create_task(refresh_client(app))
|
| 120 |
app.state.cleanup_task = asyncio.create_task(session_manager.cleanup())
|
| 121 |
app.state.clear_log_task = asyncio.create_task(clear_terminal_periodically())
|
|
|
|
| 225 |
async with app.state.client_lock:
|
| 226 |
if app.state.client is None:
|
| 227 |
try:
|
| 228 |
+
app.state.client = await create_gradio_client_with_retry("https://hadadrjt-ai.hf.space/")
|
| 229 |
logger.info("Created Gradio client connection on demand")
|
| 230 |
except Exception as e:
|
| 231 |
logger.error(f"Failed to create Gradio client: {e}", exc_info=True)
|
|
|
|
| 437 |
elif endpoint == "history":
|
| 438 |
return await get_history(body.user, body.session_id)
|
| 439 |
elif endpoint == "responses/cancel":
|
| 440 |
+
task_id = None
|
| 441 |
+
if isinstance(body.tool_choice, str):
|
| 442 |
+
task_id = body.tool_choice
|
| 443 |
+
return await cancel_response(body.user, body.session_id, task_id)
|
| 444 |
else:
|
| 445 |
raise HTTPException(status_code=404, detail="Endpoint not found")
|
| 446 |
else:
|