YF-proxy / app.py
vakabunga
chore: adds logging secrets
67639c3
Raw
History Blame Contribute Delete
4.61 kB
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")
@fastapi_app.get("/")
async def root_redirect():
return RedirectResponse(url="/ui")
@fastapi_app.get("/health")
async def health_check():
# Не показываем детали, просто жив сервис или нет
return {"status": "ok" if client else "connecting"}
@fastapi_app.post(f"/{PUBLIC_ENDPOINT}")
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)