Unstop_Retail / app.py
Dasdeman's picture
Upload 26 files
c4fab07 verified
import os
import re
import traceback
import gradio as gr
from fastapi import FastAPI, Request
from fastapi.responses import RedirectResponse, PlainTextResponse
from dotenv import load_dotenv
from slowapi import Limiter, _rate_limit_exceeded_handler
from slowapi.util import get_remote_address
from slowapi.errors import RateLimitExceeded
from showcase_ui import build_showcase_app
from admin_ui import build_admin_app
load_dotenv()
ADMIN_USER = os.getenv("ADMIN_USER", "admin")
ADMIN_PASSWORD = os.getenv("ADMIN_PASSWORD", "admin")
# Патч: відключаємо get_api_info щоб уникнути 500
try:
import gradio.blocks as _gb
_gb.Blocks.get_api_info = lambda self, *a, **kw: {"named_endpoints": {}, "unnamed_endpoints": {}}
print("[OK] get_api_info patched")
except Exception:
traceback.print_exc()
limiter = Limiter(key_func=get_remote_address, default_limits=["60/minute"])
print("[..] building showcase...")
app_showcase = build_showcase_app()
print("[OK] showcase built")
print("[..] building admin...")
app_admin = build_admin_app()
print("[OK] admin built")
app = FastAPI()
app.state.limiter = limiter
app.add_exception_handler(RateLimitExceeded, _rate_limit_exceeded_handler)
BLOCKED_PATHS = (
"/config.json", "/.env", "/utils.py", "/main.py",
"/admin_ui.py", "/showcase_ui.py", "/.git",
)
@app.middleware("http")
async def security_middleware(request: Request, call_next):
path = request.url.path
# Нормалізуємо подвійні слеші: //figvam/ -> /figvam/
clean_path = re.sub(r'/{2,}', '/', path)
if clean_path != path:
return RedirectResponse(url=clean_path, status_code=301)
path_lower = path.lower()
for blocked in BLOCKED_PATHS:
if path_lower.startswith(blocked):
return PlainTextResponse("404 Not Found", status_code=404)
if ".." in path or "%2e%2e" in path:
return PlainTextResponse("400 Bad Request", status_code=400)
try:
response = await call_next(request)
except Exception:
traceback.print_exc()
return PlainTextResponse("500 Internal Server Error", status_code=500)
response.headers["X-Content-Type-Options"] = "nosniff"
response.headers["X-Frame-Options"] = "SAMEORIGIN"
return response
@app.get("/figvam")
def redirect_admin():
return RedirectResponse(url="/figvam/")
app = gr.mount_gradio_app(app, app_admin, path="/figvam",
auth=(ADMIN_USER, ADMIN_PASSWORD),
auth_message="Unstop Admin")
app = gr.mount_gradio_app(app, app_showcase, path="/")