Spaces:
Runtime error
Runtime error
File size: 4,696 Bytes
4b8eb24 29857ea 40ec306 4b8eb24 12bad22 4b8eb24 12bad22 29857ea 12bad22 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 40ec306 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 29857ea 4b8eb24 40ec306 4b8eb24 40ec306 4b8eb24 212bd1b | 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 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 | """
DocuLens β Hugging Face Spaces entry point (Gradio SDK wrapper).
HF free-tier Spaces only support Gradio/Streamlit SDK, not Docker.
This file creates a minimal Gradio UI and mounts all FastAPI API routes
onto the same server, so the REST API works exactly as before.
How it works:
1. Build a FastAPI app with all DocuLens API routes.
2. Create a minimal Gradio Blocks UI.
3. Mount Gradio onto the FastAPI app via gr.mount_gradio_app().
4. Expose the combined ASGI app as `app` β HF Spaces detects and
serves it automatically. We do NOT call uvicorn.run() or
demo.launch() ourselves β HF handles that.
The `demo` variable is renamed to `_gradio_ui` so HF's runner doesn't
auto-launch it separately (which would cause a port conflict).
"""
import os
import logging
# ---------------------------------------------------------------------------
# Structured logging β configure once, before anything else logs
# ---------------------------------------------------------------------------
LOG_LEVEL = os.environ.get("LOG_LEVEL", "INFO").upper()
LOG_FORMAT = os.environ.get(
"LOG_FORMAT",
"%(asctime)s [%(levelname)s] %(name)s: %(message)s",
)
logging.basicConfig(
level=getattr(logging, LOG_LEVEL, logging.INFO),
format=LOG_FORMAT,
datefmt="%Y-%m-%d %H:%M:%S",
)
# Quieten noisy third-party loggers
for _noisy in ("httpx", "httpcore", "urllib3", "uvicorn.access"):
logging.getLogger(_noisy).setLevel(logging.WARNING)
logger = logging.getLogger(__name__)
# ---------------------------------------------------------------------------
# 1. Build the FastAPI app with all API routes (same as main.py)
# ---------------------------------------------------------------------------
from fastapi import FastAPI
from fastapi.responses import JSONResponse
fastapi_app = FastAPI(
title="DocuLens",
description="AI-Powered Invoice & Document Extraction API",
version="1.2.0",
)
# CORS
from api import add_cors_middleware
add_cors_middleware(fastapi_app)
# Mount all API routers
from api import api_router
from api_runs import runs_router
from api_prompts import prompts_router
from api_chat import chat_router
from api_webhooks import webhooks_router
from api_export import export_router
from api_batch import batch_router
from api_tiers import tiers_router
from api_golden import golden_router
fastapi_app.include_router(api_router)
fastapi_app.include_router(runs_router)
fastapi_app.include_router(prompts_router)
fastapi_app.include_router(chat_router)
fastapi_app.include_router(webhooks_router)
fastapi_app.include_router(export_router)
fastapi_app.include_router(batch_router)
fastapi_app.include_router(tiers_router)
fastapi_app.include_router(golden_router)
@fastapi_app.get("/health")
async def health():
return JSONResponse(
{
"service": "DocuLens",
"version": "1.2.0",
"status": "running",
"docs": "/docs",
}
)
# ---------------------------------------------------------------------------
# 2. Create a minimal Gradio UI (required by HF Spaces free-tier SDK)
# ---------------------------------------------------------------------------
import gradio as gr
# Use _gradio_ui (not `demo`) to prevent HF from auto-launching it
# separately β we mount it onto our FastAPI app below instead.
with gr.Blocks(title="DocuLens", theme=gr.themes.Soft()) as _gradio_ui:
gr.Markdown(
"""
# DocuLens API
AI-Powered Invoice & Document Extraction.
**API Documentation:** Navigate to [`/docs`](/docs) for the interactive
Swagger UI, or [`/redoc`](/redoc) for ReDoc.
**Health check:** [`/health`](/health)
"""
)
# ---------------------------------------------------------------------------
# 3. Mount Gradio onto the FastAPI app so both coexist on the same server.
# ---------------------------------------------------------------------------
app = gr.mount_gradio_app(fastapi_app, _gradio_ui, path="/")
# ---------------------------------------------------------------------------
# 4. Start the server β no __main__ guard.
#
# HF's `gradio` CLI may import rather than exec the file, so
# `if __name__ == "__main__"` can be skipped. We start uvicorn
# unconditionally on port 7860 (HF's health-check port).
# The Gradio Blocks is named `_gradio_ui` (not `demo`) to prevent
# HF from auto-launching a second server that would conflict.
# ---------------------------------------------------------------------------
import uvicorn
port = int(os.environ.get("PORT", "7860"))
logger.info("Starting DocuLens on port %d", port)
uvicorn.run(app, host="0.0.0.0", port=port)
|