Files
loom/backend/app/api/v1/llm.py
T
2026-04-24 17:46:03 +08:00

154 lines
4.9 KiB
Python

from __future__ import annotations
from fastapi import APIRouter, Depends, Query
from app.core.deps import CurrentUser, DbDep, require_perm
from app.core.exceptions import ok
from app.schemas.llm import (
ChatRequest,
ModelCreate,
ModelUpdate,
ProviderCreate,
ProviderUpdate,
RuleCreate,
RuleUpdate,
UsageRead,
)
from app.services import llm_service
router = APIRouter(prefix="/llm", tags=["llm"])
# -------- Providers --------
@router.get("/providers", dependencies=[Depends(require_perm("system:executor:view"))])
async def list_providers(db: DbDep) -> dict:
return ok([p.model_dump() for p in await llm_service.list_providers(db)])
@router.post("/providers", dependencies=[Depends(require_perm("system:executor:update"))])
async def create_provider(data: ProviderCreate, db: DbDep) -> dict:
p = await llm_service.create_provider(db, data)
return ok(llm_service.provider_to_read(p).model_dump())
@router.patch(
"/providers/{pid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def update_provider(pid: int, data: ProviderUpdate, db: DbDep) -> dict:
p = await llm_service.update_provider(db, pid, data)
return ok(llm_service.provider_to_read(p).model_dump())
@router.delete(
"/providers/{pid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def delete_provider(pid: int, db: DbDep) -> dict:
await llm_service.delete_provider(db, pid)
return ok()
# -------- Models --------
@router.get("/models", dependencies=[Depends(require_perm("system:executor:view"))])
async def list_models(db: DbDep) -> dict:
return ok([m.model_dump() for m in await llm_service.list_models(db)])
@router.post("/models", dependencies=[Depends(require_perm("system:executor:update"))])
async def create_model(data: ModelCreate, db: DbDep) -> dict:
m = await llm_service.create_model(db, data)
return ok((await llm_service.model_to_read(db, m)).model_dump())
@router.patch(
"/models/{mid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def update_model(mid: int, data: ModelUpdate, db: DbDep) -> dict:
m = await llm_service.update_model(db, mid, data)
return ok((await llm_service.model_to_read(db, m)).model_dump())
@router.delete(
"/models/{mid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def delete_model(mid: int, db: DbDep) -> dict:
await llm_service.delete_model(db, mid)
return ok()
# -------- Routing --------
@router.get("/rules", dependencies=[Depends(require_perm("system:executor:view"))])
async def list_rules(db: DbDep) -> dict:
return ok([r.model_dump() for r in await llm_service.list_rules(db)])
@router.post("/rules", dependencies=[Depends(require_perm("system:executor:update"))])
async def create_rule(data: RuleCreate, db: DbDep) -> dict:
r = await llm_service.create_rule(db, data)
return ok({
"id": r.id, "name": r.name, "priority": r.priority,
"conditions": r.conditions, "model_id": r.model_id,
"enabled": r.enabled, "description": r.description,
})
@router.patch(
"/rules/{rid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def update_rule(rid: int, data: RuleUpdate, db: DbDep) -> dict:
r = await llm_service.update_rule(db, rid, data)
return ok({
"id": r.id, "name": r.name, "priority": r.priority,
"conditions": r.conditions, "model_id": r.model_id,
"enabled": r.enabled, "description": r.description,
})
@router.delete(
"/rules/{rid}", dependencies=[Depends(require_perm("system:executor:update"))]
)
async def delete_rule(rid: int, db: DbDep) -> dict:
await llm_service.delete_rule(db, rid)
return ok()
# -------- Chat / Usage --------
@router.post("/chat", dependencies=[Depends(require_perm("system:executor:view"))])
async def chat(body: ChatRequest, db: DbDep, user: CurrentUser) -> dict:
resp = await llm_service.call_chat(
db,
operator=user,
messages=body.messages,
model_label=body.model,
conditions=body.conditions,
temperature=body.temperature,
max_tokens=body.max_tokens,
source=body.source,
)
return ok(resp.model_dump())
@router.get("/usage", dependencies=[Depends(require_perm("system:executor:view"))])
async def list_usage(
db: DbDep,
page: int = Query(1, ge=1),
size: int = Query(20, ge=1, le=200),
provider_id: int | None = None,
source: str | None = None,
) -> dict:
rows, total = await llm_service.paginate_usage(db, page, size, provider_id, source)
return ok({
"list": [UsageRead.model_validate(r).model_dump(mode="json") for r in rows],
"total": total,
"page": page,
"size": size,
})
@router.get("/usage/summary", dependencies=[Depends(require_perm("system:executor:view"))])
async def usage_summary(db: DbDep) -> dict:
return ok(await llm_service.usage_summary(db))