105 lines
3.4 KiB
Python
105 lines
3.4 KiB
Python
from __future__ import annotations
|
|
|
|
from typing import Optional
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from fastapi.responses import JSONResponse
|
|
from pydantic import BaseModel, Field
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from ...core.database import get_db
|
|
from ...core.response import error_response, success_response
|
|
from ...dependencies import require_manager_user
|
|
from ...models import User
|
|
from ...services.semantic_fact_service import SemanticFactService
|
|
|
|
router = APIRouter(prefix="/semantic-facts", tags=["semantic_facts"])
|
|
|
|
|
|
class SemanticFactsBackfillRequest(BaseModel):
|
|
entity_types: Optional[list[str]] = Field(default=None)
|
|
only_missing: bool = Field(default=True)
|
|
limit_per_type: int = Field(default=200, ge=1, le=1000)
|
|
|
|
|
|
@router.get("/admin/overview")
|
|
async def get_semantic_facts_overview(
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_manager_user),
|
|
):
|
|
service = SemanticFactService(db, tenant_id=int(current_user.tenant_id))
|
|
return success_response(await service.get_admin_overview())
|
|
|
|
|
|
@router.get("/admin/objects")
|
|
async def list_semantic_fact_objects(
|
|
entity_type: str | None = Query(default=None),
|
|
q: str | None = Query(default=None),
|
|
status: str | None = Query(default=None),
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_manager_user),
|
|
):
|
|
service = SemanticFactService(db, tenant_id=int(current_user.tenant_id))
|
|
items = await service.list_admin_objects(
|
|
entity_types=[entity_type] if entity_type else None,
|
|
q=q,
|
|
status=status,
|
|
)
|
|
return success_response({"items": items})
|
|
|
|
|
|
@router.get("/admin/objects/{entity_type}/{entity_id}")
|
|
async def get_semantic_fact_object_detail(
|
|
entity_type: str,
|
|
entity_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_manager_user),
|
|
):
|
|
service = SemanticFactService(db, tenant_id=int(current_user.tenant_id))
|
|
try:
|
|
detail = await service.get_admin_detail(entity_type=entity_type, entity_id=int(entity_id))
|
|
except ValueError as exc:
|
|
return JSONResponse(status_code=404, content=error_response(404, str(exc)))
|
|
return success_response(detail)
|
|
|
|
|
|
@router.post("/admin/objects/{entity_type}/{entity_id}/reextract")
|
|
async def reextract_semantic_fact_object(
|
|
entity_type: str,
|
|
entity_id: int,
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_manager_user),
|
|
):
|
|
service = SemanticFactService(db, tenant_id=int(current_user.tenant_id))
|
|
row = await service.enqueue_entity_event(
|
|
entity_type=entity_type,
|
|
entity_id=int(entity_id),
|
|
operation="extract",
|
|
trigger_type="manual_retry",
|
|
)
|
|
await db.commit()
|
|
return success_response(
|
|
{
|
|
"queued": True,
|
|
"event_id": int(row.id),
|
|
"entity_type": str(entity_type),
|
|
"entity_id": int(entity_id),
|
|
}
|
|
)
|
|
|
|
|
|
@router.post("/admin/backfill")
|
|
async def enqueue_semantic_fact_backfill(
|
|
body: SemanticFactsBackfillRequest,
|
|
db: AsyncSession = Depends(get_db),
|
|
current_user: User = Depends(require_manager_user),
|
|
):
|
|
service = SemanticFactService(db, tenant_id=int(current_user.tenant_id))
|
|
result = await service.enqueue_backfill(
|
|
entity_types=body.entity_types,
|
|
only_missing=bool(body.only_missing),
|
|
limit_per_type=int(body.limit_per_type),
|
|
)
|
|
await db.commit()
|
|
return success_response(result)
|