# retoor import logging from fastapi import APIRouter, Request from fastapi.responses import HTMLResponse, JSONResponse from pydantic import ValidationError from devplacepy.seo import base_seo_context, site_url, website_schema from devplacepy.services.audit import record as audit from devplacepy.services.manager import service_manager from devplacepy.services.openai_gateway import routing from devplacepy.templating import templates from devplacepy.utils import require_admin logger = logging.getLogger(__name__) router = APIRouter() def _default_provider_summary() -> dict: svc = service_manager.get_service("openai") cfg = svc.get_config() if svc is not None else {} return { "base_url": cfg.get("gateway_upstream_url", ""), "model": cfg.get("gateway_model", ""), "embed_url": cfg.get("gateway_embed_url", ""), "embed_model": cfg.get("gateway_embed_model", ""), "image_url": cfg.get("gateway_image_url", ""), "image_model": cfg.get("gateway_image_model", ""), "vision_url": cfg.get("gateway_vision_url", ""), "vision_model": cfg.get("gateway_vision_model", ""), } def _validation_error(exc: ValidationError) -> JSONResponse: first = exc.errors()[0] message = first.get("msg", "Invalid input") return JSONResponse({"ok": False, "error": message}, status_code=400) async def _payload(request: Request) -> dict: content_type = request.headers.get("content-type", "") if "application/json" in content_type: try: data = await request.json() except Exception: return {} return data if isinstance(data, dict) else {} form = await request.form() return {key: value for key, value in form.items()} @router.get("/gateway", response_class=HTMLResponse) async def gateway_config_page(request: Request): admin = require_admin(request) base = site_url(request) seo_ctx = base_seo_context( request, title="Gateway routing - Admin", description="Manage OpenAI gateway providers and per-model routing.", robots="noindex,nofollow", breadcrumbs=[ {"name": "Home", "url": "/feed"}, {"name": "Admin", "url": "/admin"}, {"name": "Gateway", "url": "/admin/gateway"}, ], schemas=[website_schema(base)], ) return templates.TemplateResponse( request, "admin_gateway.html", { **seo_ctx, "request": request, "user": admin, "admin_section": "gateway", "default_provider": _default_provider_summary(), }, ) @router.get("/gateway/providers") async def list_providers(request: Request): require_admin(request) return JSONResponse( { "providers": routing.provider_store.list(), "default": _default_provider_summary(), "count": routing.provider_store.count(), } ) @router.post("/gateway/providers") async def save_provider(request: Request): admin = require_admin(request) body = await _payload(request) try: payload = routing.ProviderIn(**body) except ValidationError as exc: return _validation_error(exc) saved = routing.provider_store.set(payload) audit.record( request, "gateway.provider.update", user=admin, target_type="gateway_provider", target_uid=payload.name, target_label=payload.name, summary=f"admin {admin['username']} saved gateway provider {payload.name}", ) return JSONResponse({"ok": True, "provider": saved}) @router.delete("/gateway/providers/{name}") async def delete_provider(request: Request, name: str): admin = require_admin(request) existed = routing.provider_store.remove(name) if not existed: return JSONResponse({"ok": False, "error": "Provider not found"}, status_code=404) audit.record( request, "gateway.provider.delete", user=admin, target_type="gateway_provider", target_uid=name, target_label=name, summary=f"admin {admin['username']} deleted gateway provider {name}", ) return JSONResponse({"ok": True}) @router.get("/gateway/models") async def list_models(request: Request): require_admin(request) return JSONResponse( { "models": routing.model_store.list(), "providers": routing.provider_store.names(), "count": routing.model_store.count(), } ) @router.post("/gateway/models") async def save_model(request: Request): admin = require_admin(request) body = await _payload(request) try: payload = routing.ModelRouteIn(**body) except ValidationError as exc: return _validation_error(exc) saved = routing.model_store.set(payload) audit.record( request, "gateway.model.update", user=admin, target_type="gateway_model", target_uid=payload.source_model, target_label=f"{payload.source_model} -> {payload.target_model}", summary=( f"admin {admin['username']} saved gateway model route " f"{payload.source_model} -> {payload.target_model}" ), ) return JSONResponse({"ok": True, "model": saved}) @router.delete("/gateway/models/{source_model}") async def delete_model(request: Request, source_model: str): admin = require_admin(request) existed = routing.model_store.remove(source_model) if not existed: return JSONResponse({"ok": False, "error": "Model route not found"}, status_code=404) audit.record( request, "gateway.model.delete", user=admin, target_type="gateway_model", target_uid=source_model, target_label=source_model, summary=f"admin {admin['username']} deleted gateway model route {source_model}", ) return JSONResponse({"ok": True})