Spaces:
Sleeping
Sleeping
import logging | |
import os | |
import time | |
import gradio as gr | |
import structlog | |
import uvicorn | |
from asgi_correlation_id import CorrelationIdMiddleware | |
from asgi_correlation_id.context import correlation_id | |
from fastapi import FastAPI, Request, Response, APIRouter | |
from uvicorn.protocols.utils import get_path_with_query_string | |
from helpers.structlog_setup import setup_logging | |
from helpers import formatters | |
from dotenv import load_dotenv | |
from routes import router | |
load_dotenv() | |
# LOG_JSON_FORMAT = parse_obj_as(bool, os.getenv("LOG_JSON_FORMAT", False)) | |
LOG_JSON_FORMAT = bool(os.getenv("LOG_JSON_FORMAT", False)) | |
LOG_LEVEL = os.getenv("LOG_LEVEL", "INFO") | |
setup_logging(json_logs=LOG_JSON_FORMAT, log_level=LOG_LEVEL) | |
access_logger = structlog.stdlib.get_logger(__name__) | |
app = FastAPI(title="Example API", version="1.0.0") | |
async def logging_middleware(request: Request, call_next) -> Response: | |
structlog.contextvars.clear_contextvars() | |
# These context vars will be added to all log entries emitted during the request | |
request_id = correlation_id.get() | |
# print(f"request_id:{request_id}.") | |
structlog.contextvars.bind_contextvars(request_id=request_id) | |
start_time = time.perf_counter_ns() | |
# If the call_next raises an error, we still want to return our own 500 response, | |
# so we can add headers to it (process time, request ID...) | |
response = Response(status_code=500) | |
try: | |
response = await call_next(request) | |
except Exception: | |
# TODO: Validate that we don't swallow exceptions (unit test?) | |
structlog.stdlib.get_logger("api.error").exception("Uncaught exception") | |
raise | |
finally: | |
process_time = time.perf_counter_ns() - start_time | |
status_code = response.status_code | |
url = get_path_with_query_string(request.scope) | |
client_host = request.client.host | |
client_port = request.client.port | |
http_method = request.method | |
http_version = request.scope["http_version"] | |
# Recreate the Uvicorn access log format, but add all parameters as structured information | |
access_logger.info( | |
f"""{client_host}:{client_port} - "{http_method} {url} HTTP/{http_version}" {status_code}""", | |
http={ | |
"url": str(request.url), | |
"status_code": status_code, | |
"method": http_method, | |
"request_id": request_id, | |
"version": http_version, | |
}, | |
network={"client": {"ip": client_host, "port": client_port}}, | |
duration=process_time, | |
) | |
response.headers["X-Process-Time"] = str(process_time / 10 ** 9) | |
return response | |
app.include_router(router) | |
logging.info("routes included, creating gradio app") | |
CUSTOM_GRADIO_PATH = "/" | |
def get_gradio_app(): | |
with gr.Blocks() as gradio_app: | |
access_logger.info("start gradio app building...") | |
gr.Markdown( | |
""" | |
# Hello World! | |
Start typing below to _see_ the *output*. | |
Here a [link](https://huggingface.co/spaces/aletrn/gradio_with_fastapi). | |
""" | |
) | |
btn = gr.Button(value="Divide et Impera") | |
text_input = gr.Textbox(lines=1, placeholder="10", | |
label="write an integer to divide 100; 0 will raise ZeroDivisionError") | |
text_output = gr.Textbox(lines=1, placeholder=None, label="Text Output") | |
gr.Examples( | |
examples=[19, 1, -7, 0], | |
inputs=[text_input], | |
) | |
btn.click( | |
formatters.request_formatter, | |
inputs=[text_input, ], | |
outputs=[text_output] | |
) | |
return gradio_app | |
logging.info("mounting gradio app within FastAPI...") | |
gradio_app_md = get_gradio_app() | |
app.add_middleware(CorrelationIdMiddleware) | |
app = gr.mount_gradio_app(app, gradio_app_md, path=CUSTOM_GRADIO_PATH) | |
logging.info("gradio app mounted") | |
if __name__ == "__main__": | |
try: | |
uvicorn.run("app:app", host="127.0.0.1", port=7860, log_config=None, reload=True) | |
except Exception as ex: | |
logging.error(f"ex:{ex}.") | |
raise ex | |