"""OpenAI native endpoint (passthrough).""" import time from typing import Optional, List from fastapi import APIRouter, Depends, HTTPException from fastapi.responses import StreamingResponse from pydantic import BaseModel from ..models import ClientKey from ..middleware.auth import get_current_client from ..services.router import ModelRouter from ..services.key_selector import key_selector from ..services.logger import async_logger, LogEntry from ..providers.litellm_wrapper import LiteLLMWrapper router = APIRouter(prefix="/v1/openai", tags=["openai"]) class ChatMessage(BaseModel): role: str content: str class ChatRequest(BaseModel): model: str messages: List[ChatMessage] stream: bool = False temperature: Optional[float] = None max_tokens: Optional[int] = None @router.post("/chat/completions") async def openai_chat( request: ChatRequest, client: ClientKey = Depends(get_current_client) ): """OpenAI native chat completions (passthrough).""" start_time = time.time() # Get OpenAI provider provider = await ModelRouter.get_provider("openai") if not provider: raise HTTPException(status_code=503, detail={"error": "OpenAI provider not configured"}) # Get next API key provider_key = await key_selector.get_next_key(provider.id) if not provider_key: raise HTTPException(status_code=503, detail={"error": "No available OpenAI API key"}) messages = [{"role": m.role, "content": m.content} for m in request.messages] kwargs = {} if request.temperature is not None: kwargs["temperature"] = request.temperature if request.max_tokens is not None: kwargs["max_tokens"] = request.max_tokens try: response, prompt_tokens, completion_tokens = await LiteLLMWrapper.chat_completion( provider=provider, api_key=provider_key.key, model=request.model, messages=messages, stream=request.stream, **kwargs ) if request.stream: return StreamingResponse( LiteLLMWrapper.stream_response( response, client.id, provider.id, request.model, start_time ), media_type="text/event-stream" ) else: latency_ms = int((time.time() - start_time) * 1000) await async_logger.log(LogEntry( client_key_id=client.id, provider_id=provider.id, model=request.model, prompt_tokens=prompt_tokens, completion_tokens=completion_tokens, latency_ms=latency_ms, success=True )) return response except Exception as e: latency_ms = int((time.time() - start_time) * 1000) await async_logger.log(LogEntry( client_key_id=client.id, provider_id=provider.id, model=request.model, latency_ms=latency_ms, success=False, error_message=str(e) )) raise HTTPException(status_code=500, detail={"error": str(e)}) @router.get("/models") async def openai_models(client: ClientKey = Depends(get_current_client)): """List OpenAI models.""" return { "object": "list", "data": [ {"id": "gpt-4o", "object": "model", "owned_by": "openai"}, {"id": "gpt-4o-mini", "object": "model", "owned_by": "openai"}, {"id": "o1", "object": "model", "owned_by": "openai"}, {"id": "o1-mini", "object": "model", "owned_by": "openai"}, ] }