Spaces:
Sleeping
Sleeping
| import os | |
| import json | |
| import gradio as gr | |
| from fastapi import FastAPI, Request, HTTPException | |
| from fastapi.responses import JSONResponse, RedirectResponse | |
| from gradio_client import Client | |
| # ==================== Конфигурация ==================== | |
| PRIVATE_SPACE_URL = os.getenv("PRIVATE_SPACE_URL") | |
| PRIVATE_TOKEN = os.getenv("PRIVATE_TOKEN") | |
| PUBLIC_ENDPOINT = os.getenv("PUBLIC_ENDPOINT") | |
| PRIVATE_ENDPOINT = os.getenv("PRIVATE_ENDPOINT") | |
| # ==================== Инициализация Клиента ==================== | |
| client = None | |
| def init_client(): | |
| """Ленивая или повторная инициализация клиента""" | |
| global client | |
| if not PRIVATE_SPACE_URL or not PRIVATE_TOKEN: | |
| print("⚠️ Config missing: PRIVATE_SPACE_URL or TOKEN not set.") | |
| return None | |
| print("🔄 Initializing upstream connection...") | |
| try: | |
| # Клиент создается | |
| new_client = Client(PRIVATE_SPACE_URL, token=PRIVATE_TOKEN, verbose=False) | |
| print("✅ Upstream connection established.") | |
| return new_client | |
| except Exception as e: | |
| # Логируем только факт ошибки, не печатаем само исключение, так как оно может содержать URL | |
| print(PRIVATE_SPACE_URL) | |
| print("❌ Connection failed.") | |
| print(e) | |
| return None | |
| # Пробуем соединиться при старте | |
| client = init_client() | |
| # ==================== FastAPI (Прокси) ==================== | |
| fastapi_app = FastAPI(title="Secure Proxy") | |
| async def root_redirect(): | |
| return RedirectResponse(url="/ui") | |
| async def health_check(): | |
| # Не показываем детали, просто жив сервис или нет | |
| return {"status": "ok" if client else "connecting"} | |
| async def proxy_webhook(request: Request): | |
| global client | |
| # Если клиент отвалился или не был создан, пробуем пересоздать | |
| if not client: | |
| client = init_client() | |
| if not client: | |
| raise HTTPException(status_code=503, detail="Upstream unavailable") | |
| try: | |
| # 1. Получаем JSON (без логирования содержимого) | |
| payload = await request.json() | |
| # 2. Конвертируем в строку для Gradio | |
| payload_str = json.dumps(payload, ensure_ascii=False) | |
| # 3. Вызываем приватный API | |
| # Используем api_name, это безопаснее при изменениях кода. | |
| result = client.predict(payload_str, api_name=f"/{PRIVATE_ENDPOINT}") | |
| # 4. Возвращаем успех, не показывая ответ приватного сервера (если там есть данные) | |
| # Если нужно вернуть ID для отладки Яндекс.Форм, можно вернуть минимальный JSON | |
| return JSONResponse( | |
| content={ | |
| "status": "forwarded", | |
| "timestamp": os.urandom(4).hex(), # Просто уникальный маркер | |
| } | |
| ) | |
| except Exception: | |
| # В случае ошибки не возвращаем её текст клиенту, чтобы не светить внутренности | |
| print("❌ Error during forwarding.") | |
| raise HTTPException(status_code=500, detail="Internal forwarding error") | |
| # ==================== Безопасный Gradio UI ==================== | |
| def create_secure_ui(): | |
| with gr.Blocks(title="System Status") as demo: | |
| gr.Markdown("## 🛡️ Gateway Status") | |
| # Индикатор статуса без деталей | |
| status_indicator = gr.Textbox( | |
| label="Service State", value="Checking...", interactive=False | |
| ) | |
| btn = gr.Button("Refresh Status") | |
| def check_safe(): | |
| if client: | |
| return "✅ Online / Connected to Upstream" | |
| else: | |
| return "⚠️ Offline / Reconnecting..." | |
| # При загрузке и нажатии проверяем статус | |
| demo.load(check_safe, outputs=status_indicator) | |
| btn.click(check_safe, outputs=status_indicator) | |
| return demo | |
| app = gr.mount_gradio_app(fastapi_app, create_secure_ui(), path="/ui") | |
| if __name__ == "__main__": | |
| import uvicorn | |
| uvicorn.run(app, host="0.0.0.0", port=7860) | |