CoolFace
Apppublic

build-small-hackathon/HF-Agentic-Search-Live

sourceHugging Faceapache-2.0updated 3mo agoView on Hugging Face
3likes
app.py121 linesDownload Raw Back to root
1"""HF Agentic Search - Gradio Space entrypoint."""2from __future__ import annotations3 4import json5import os6import sys7import threading8import uuid9 10os.environ.setdefault("GRADIO_ANALYTICS_ENABLED", "False")11 12_ROOT = os.path.dirname(os.path.abspath(__file__))13if _ROOT not in sys.path:14    sys.path.insert(0, _ROOT)15 16import gradio as gr17from fastapi import Request18from fastapi.responses import FileResponse, JSONResponse, StreamingResponse19from fastapi.staticfiles import StaticFiles20 21from backend.agent import MAX_TASK_LENGTH, weave, weave_events22 23app = gr.Server()24_DIST = os.path.join(_ROOT, "frontend", "dist")25_sessions: dict[str, dict] = {}26_lock = threading.Lock()27 28 29def _session_id(request: Request) -> str:30    supplied = (request.headers.get("X-Session-Id") or "").strip()31    return supplied[:80] if supplied else f"dw-{uuid.uuid4().hex[:16]}"32 33 34async def _task_from_request(request: Request) -> tuple[str | None, JSONResponse | None]:35    try:36        body = await request.json()37    except Exception:38        return None, JSONResponse({"error": "Body is not valid JSON."}, status_code=400)39    task = str(body.get("task") or "").strip()40    if not task:41        return None, JSONResponse({"error": "Task description is required."}, status_code=400)42    if len(task) > MAX_TASK_LENGTH:43        return None, JSONResponse(44            {"error": f"Task description must be {MAX_TASK_LENGTH} characters or fewer."},45            status_code=422,46        )47    return task, None48 49 50@app.post("/weave")51async def api_weave(request: Request):52    task, error = await _task_from_request(request)53    if error:54        return error55    sid = _session_id(request)56    try:57        result = weave(task or "")58    except Exception as exc:59        return JSONResponse({"error": str(exc)}, status_code=502)60    with _lock:61        _sessions[sid] = result62    return JSONResponse(result, headers={"X-Session-Id": sid})63 64 65@app.post("/weave/stream")66async def api_weave_stream(request: Request):67    task, error = await _task_from_request(request)68    if error:69        return error70    sid = _session_id(request)71 72    def stream():73        try:74            for event in weave_events(task or ""):75                if event["type"] == "complete":76                    with _lock:77                        _sessions[sid] = event["result"]78                yield json.dumps(event, ensure_ascii=True) + "\n"79        except Exception as exc:80            yield json.dumps({"type": "error", "message": str(exc)}) + "\n"81 82    return StreamingResponse(83        stream(),84        media_type="application/x-ndjson",85        headers={"X-Session-Id": sid, "Cache-Control": "no-store"},86    )87 88 89@app.get("/state")90async def get_state(request: Request):91    sid = _session_id(request)92    with _lock:93        result = _sessions.get(sid)94    if result is None:95        result = {96            "datasets": [], "nodes": [], "threads": [], "task": "",97            "top_pick": None, "fallback_used": False,98        }99    return JSONResponse(result, headers={"X-Session-Id": sid})100 101 102_DIST_ASSETS = os.path.join(_DIST, "assets")103if os.path.isdir(_DIST_ASSETS):104    app.mount("/assets", StaticFiles(directory=_DIST_ASSETS), name="assets")105 106 107@app.get("/")108def index():109    path = os.path.join(_DIST, "index.html")110    if os.path.isfile(path):111        return FileResponse(path)112    return JSONResponse({"error": "Frontend not built."}, status_code=503)113 114 115if __name__ == "__main__":116    app.launch(117        server_name="0.0.0.0",118        server_port=int(os.environ.get("PORT", os.environ.get("GRADIO_SERVER_PORT", "7860"))),119        show_error=True,120    )121