This commit is contained in:
2026-07-19 18:57:43 +02:00
parent 48bb6c2ec2
commit c53e2a3319
179 changed files with 9307 additions and 897 deletions
+46 -3
View File
@@ -3,18 +3,32 @@
import json
import logging
import os
import re
import time
from fastapi import HTTPException, Request
from fastapi.responses import JSONResponse
from devplacepy.database import get_int_setting
from devplacepy.services.base import BaseService, ConfigField
from devplacepy.services.openai_gateway import config
from devplacepy.services.openai_gateway.analytics import summary_metrics
from devplacepy.services.openai_gateway.gateway import GatewayRuntime
from devplacepy.services.openai_gateway.routing import model_store
from devplacepy.utils import get_current_user
logger = logging.getLogger(__name__)
APP_REFERENCE_PATTERN = re.compile(r"^[a-zA-Z0-9_.-]{1,30}$")
DEFAULT_APP_REFERENCE = "default"
def _validate_app_reference(value: str) -> str:
stripped = (value or "").strip()
if not stripped or not APP_REFERENCE_PATTERN.match(stripped):
return DEFAULT_APP_REFERENCE
return stripped
def _presented_key(request: Request) -> str:
key = request.headers.get("X-API-KEY")
@@ -449,6 +463,29 @@ class GatewayService(BaseService):
return (kind, user.get("uid") or "unknown")
return ("anonymous", "anonymous")
def _models_response(self) -> JSONResponse:
created = int(time.time())
seen: set = set()
data = []
for row in model_store.list():
if str(row.get("kind") or "chat") != "chat":
continue
if not row.get("is_active", True):
continue
source = str(row.get("source_model") or "").strip()
if not source or source in seen:
continue
seen.add(source)
data.append(
{
"id": source,
"object": "model",
"created": created,
"owned_by": "molodetz",
}
)
return JSONResponse({"object": "list", "data": data})
async def handle(self, request: Request, subpath: str):
if not self.is_enabled():
raise HTTPException(status_code=503, detail="Gateway is disabled")
@@ -459,6 +496,11 @@ class GatewayService(BaseService):
runtime = self.runtime()
owner = self.resolve_owner(request)
user_agent = request.headers.get("user-agent", "")
app_reference = _validate_app_reference(
request.headers.get("X-App-Reference", DEFAULT_APP_REFERENCE)
)
if subpath == "models" and request.method == "GET":
return self._models_response()
if subpath == "chat/completions" and request.method == "POST":
try:
body = await request.json()
@@ -468,7 +510,7 @@ class GatewayService(BaseService):
if not isinstance(body, dict):
self.log("Rejected chat request: JSON body was not an object")
raise HTTPException(status_code=400, detail="Invalid JSON body")
return await runtime.handle_chat(body, cfg, owner, user_agent, self.log)
return await runtime.handle_chat(body, cfg, owner, user_agent, app_reference, self.log)
if subpath == "embeddings" and request.method == "POST":
try:
body = await request.json()
@@ -479,7 +521,7 @@ class GatewayService(BaseService):
self.log("Rejected embeddings request: JSON body was not an object")
raise HTTPException(status_code=400, detail="Invalid JSON body")
return await runtime.handle_embeddings(
body, cfg, owner, user_agent, self.log
body, cfg, owner, user_agent, app_reference, self.log
)
if subpath == "images/generations" and request.method == "POST":
try:
@@ -491,7 +533,7 @@ class GatewayService(BaseService):
self.log("Rejected images request: JSON body was not an object")
raise HTTPException(status_code=400, detail="Invalid JSON body")
return await runtime.handle_images(
body, cfg, owner, user_agent, self.log
body, cfg, owner, user_agent, app_reference, self.log
)
body = await request.body()
content_type = request.headers.get("content-type", "")
@@ -503,6 +545,7 @@ class GatewayService(BaseService):
cfg,
owner,
user_agent,
app_reference,
self.log,
)