Files
gpu-services/hub-api/routers/embeddings.py
Hyungi Ahn 3794afff95 feat: AI Gateway Phase 1 - FastAPI 코어 구현
GPU 서버 중앙 AI 라우팅 서비스 초기 구현:
- OpenAI 호환 API (/v1/chat/completions, /v1/models, /v1/embeddings)
- 모델 레지스트리 + 백엔드 헬스체크 (30초 루프)
- Ollama SSE 프록시 (NDJSON → OpenAI SSE 변환)
- JWT 인증 이중 경로 (httpOnly 쿠키 + Bearer 토큰)
- owner/guest 역할 분리, 로그인 rate limiting
- 백엔드별 rate limiting (NanoClaude 대비)
- SQLite 스키마 사전 정의 (aiosqlite + WAL)
- Docker Compose + Caddy 리버스 프록시

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-03-31 13:41:46 +09:00

68 lines
1.9 KiB
Python

from typing import List, Union
from fastapi import APIRouter, HTTPException, Request
from pydantic import BaseModel
from services import proxy_ollama
from services.registry import registry
router = APIRouter(prefix="/v1", tags=["embeddings"])
class EmbeddingRequest(BaseModel):
model: str
input: Union[str, List[str]]
@router.post("/embeddings")
async def create_embedding(body: EmbeddingRequest, request: Request):
role = getattr(request.state, "role", "anonymous")
if role == "anonymous":
raise HTTPException(
status_code=401,
detail={"error": {"message": "Authentication required", "type": "auth_error", "code": "unauthorized"}},
)
result = registry.resolve_model(body.model, role)
if not result:
raise HTTPException(
status_code=404,
detail={
"error": {
"message": f"Model '{body.model}' not found or not available",
"type": "invalid_request_error",
"code": "model_not_found",
}
},
)
backend, model_info = result
if "embed" not in model_info.capabilities:
raise HTTPException(
status_code=400,
detail={
"error": {
"message": f"Model '{body.model}' does not support embeddings",
"type": "invalid_request_error",
"code": "capability_mismatch",
}
},
)
if backend.type == "ollama":
return await proxy_ollama.generate_embedding(
backend.url, body.model, body.input
)
raise HTTPException(
status_code=501,
detail={
"error": {
"message": f"Embedding not supported for backend type '{backend.type}'",
"type": "api_error",
"code": "not_implemented",
}
},
)