160 lines
5.0 KiB
Python
160 lines
5.0 KiB
Python
"""Fine-Tune Pool Endpoints."""
|
|
|
|
import logging
|
|
from typing import Annotated
|
|
|
|
from fastapi import APIRouter, HTTPException, Query
|
|
|
|
from backend.web.core.auth import AdminTokenDep, FineTunePoolRepoDep, DocumentRepoDep
|
|
from backend.web.schemas.admin.pool import (
|
|
PoolAddRequest,
|
|
PoolEntryItem,
|
|
PoolEntryResponse,
|
|
PoolListResponse,
|
|
PoolStatsResponse,
|
|
)
|
|
|
|
from ._utils import _validate_uuid
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def register_pool_routes(router: APIRouter) -> None:
|
|
"""Register fine-tune pool endpoints on the router."""
|
|
|
|
@router.post(
|
|
"/pool",
|
|
response_model=PoolEntryResponse,
|
|
summary="Add document to fine-tune pool",
|
|
description="Add a labeled document to the fine-tune pool for future fine-tuning.",
|
|
)
|
|
async def add_to_pool(
|
|
request: PoolAddRequest,
|
|
admin_token: AdminTokenDep,
|
|
pool: FineTunePoolRepoDep,
|
|
docs: DocumentRepoDep,
|
|
) -> PoolEntryResponse:
|
|
"""Add a document to the fine-tune pool."""
|
|
_validate_uuid(request.document_id, "document_id")
|
|
|
|
# Verify document exists
|
|
doc = docs.get(request.document_id)
|
|
if not doc:
|
|
raise HTTPException(status_code=404, detail="Document not found")
|
|
|
|
# Check if already in pool
|
|
existing = pool.get_by_document(request.document_id)
|
|
if existing:
|
|
raise HTTPException(
|
|
status_code=409,
|
|
detail=f"Document already in fine-tune pool (entry_id: {existing.entry_id})",
|
|
)
|
|
|
|
entry = pool.add_document(
|
|
document_id=request.document_id,
|
|
added_by=admin_token,
|
|
reason=request.reason,
|
|
)
|
|
|
|
return PoolEntryResponse(
|
|
entry_id=str(entry.entry_id),
|
|
message="Document added to fine-tune pool",
|
|
)
|
|
|
|
@router.get(
|
|
"/pool",
|
|
response_model=PoolListResponse,
|
|
summary="List fine-tune pool entries",
|
|
)
|
|
async def list_pool_entries(
|
|
admin_token: AdminTokenDep,
|
|
pool: FineTunePoolRepoDep,
|
|
verified_only: Annotated[bool, Query(description="Filter to verified only")] = False,
|
|
limit: Annotated[int, Query(ge=1, le=100)] = 20,
|
|
offset: Annotated[int, Query(ge=0)] = 0,
|
|
) -> PoolListResponse:
|
|
"""List entries in the fine-tune pool."""
|
|
entries, total = pool.get_paginated(
|
|
verified_only=verified_only,
|
|
limit=limit,
|
|
offset=offset,
|
|
)
|
|
|
|
return PoolListResponse(
|
|
total=total,
|
|
limit=limit,
|
|
offset=offset,
|
|
entries=[
|
|
PoolEntryItem(
|
|
entry_id=str(e.entry_id),
|
|
document_id=str(e.document_id),
|
|
added_by=e.added_by,
|
|
reason=e.reason,
|
|
is_verified=e.is_verified,
|
|
verified_at=e.verified_at,
|
|
verified_by=e.verified_by,
|
|
created_at=e.created_at,
|
|
)
|
|
for e in entries
|
|
],
|
|
)
|
|
|
|
@router.get(
|
|
"/pool/stats",
|
|
response_model=PoolStatsResponse,
|
|
summary="Get fine-tune pool statistics",
|
|
)
|
|
async def get_pool_stats(
|
|
admin_token: AdminTokenDep,
|
|
pool: FineTunePoolRepoDep,
|
|
) -> PoolStatsResponse:
|
|
"""Get statistics about the fine-tune pool."""
|
|
total = pool.get_pool_count(verified_only=False)
|
|
verified = pool.get_pool_count(verified_only=True)
|
|
|
|
return PoolStatsResponse(
|
|
total_entries=total,
|
|
verified_entries=verified,
|
|
unverified_entries=total - verified,
|
|
is_ready=verified >= 50,
|
|
)
|
|
|
|
@router.post(
|
|
"/pool/{entry_id}/verify",
|
|
response_model=PoolEntryResponse,
|
|
summary="Verify a pool entry",
|
|
description="Mark a pool entry as verified (human-reviewed).",
|
|
)
|
|
async def verify_pool_entry(
|
|
entry_id: str,
|
|
admin_token: AdminTokenDep,
|
|
pool: FineTunePoolRepoDep,
|
|
) -> PoolEntryResponse:
|
|
"""Mark a pool entry as verified."""
|
|
_validate_uuid(entry_id, "entry_id")
|
|
entry = pool.verify_entry(entry_id, verified_by=admin_token)
|
|
if not entry:
|
|
raise HTTPException(status_code=404, detail="Pool entry not found")
|
|
|
|
return PoolEntryResponse(
|
|
entry_id=str(entry.entry_id),
|
|
message="Pool entry verified",
|
|
)
|
|
|
|
@router.delete(
|
|
"/pool/{entry_id}",
|
|
summary="Remove from fine-tune pool",
|
|
)
|
|
async def remove_from_pool(
|
|
entry_id: str,
|
|
admin_token: AdminTokenDep,
|
|
pool: FineTunePoolRepoDep,
|
|
) -> dict:
|
|
"""Remove a document from the fine-tune pool."""
|
|
_validate_uuid(entry_id, "entry_id")
|
|
success = pool.remove_entry(entry_id)
|
|
if not success:
|
|
raise HTTPException(status_code=404, detail="Pool entry not found")
|
|
|
|
return {"message": "Entry removed from fine-tune pool"}
|