| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- """Formal decode API routes."""
- from __future__ import annotations
- from typing import Any
- from uuid import UUID
- from fastapi import APIRouter, Body, Depends, HTTPException
- from app.dependencies import _env_file, get_acquisition_repository, get_decode_repository
- from app.schemas import (
- CandidateItemSchema,
- DecodeResultSchema,
- IngestItemRequest,
- IngestItemResponse,
- IngestItemResultSchema,
- IngestRecordSchema,
- KnowledgeParticleSchema,
- MediaAssetSchema,
- PayloadDraftSchema,
- ScopeResultSchema,
- )
- from core.config import IngestApiConfig
- from decode_content.ingest import KnowledgeIngestClient, ingest_payload_draft
- router = APIRouter(prefix="/api/decode", tags=["decode"])
- @router.get("/items/{item_id}/result", response_model=DecodeResultSchema)
- def decode_result(
- item_id: UUID,
- repo: Any = Depends(get_decode_repository),
- ) -> DecodeResultSchema:
- getter = getattr(repo, "get_decode_result_for_item", None)
- if getter is None:
- raise HTTPException(status_code=501, detail="decode result reader is not implemented")
- return DecodeResultSchema.model_validate(getter(item_id))
- @router.get("/items/{item_id}/detail")
- def decode_item_detail(
- item_id: UUID,
- acquisition_repo: Any = Depends(get_acquisition_repository),
- decode_repo: Any = Depends(get_decode_repository),
- ) -> dict[str, Any]:
- try:
- item = acquisition_repo.get_candidate_item(item_id)
- media = acquisition_repo.list_media_assets_for_item(item_id)
- except Exception as exc:
- raise HTTPException(status_code=404, detail=f"candidate item not found: {exc}") from exc
- try:
- result = decode_repo.get_decode_result_for_item(item_id)
- except Exception as exc:
- result = None
- list_particles = getattr(decode_repo, "list_knowledge_particles", None)
- list_scopes = getattr(decode_repo, "list_scope_results", None)
- list_payloads = getattr(decode_repo, "list_payload_drafts", None)
- list_ingests = getattr(decode_repo, "list_ingest_records", None)
- raw_item = item.model_dump() if hasattr(item, "model_dump") else dict(item)
- item_payload = CandidateItemSchema.model_validate(
- {
- **raw_item,
- "media_assets": [
- MediaAssetSchema.model_validate(row).model_dump(mode="json")
- for row in media
- ],
- }
- ).model_dump(mode="json")
- return {
- "item": item_payload,
- "decode_result": (
- DecodeResultSchema.model_validate(result).model_dump(mode="json")
- if result is not None
- else None
- ),
- "knowledge_particles": [
- KnowledgeParticleSchema.model_validate(row).model_dump(mode="json")
- for row in (list_particles(item_id=item_id) if list_particles else [])
- ],
- "scope_results": [
- ScopeResultSchema.model_validate(row).model_dump(mode="json")
- for row in (list_scopes(item_id=item_id) if list_scopes else [])
- ],
- "payload_drafts": [
- PayloadDraftSchema.model_validate(row).model_dump(mode="json")
- for row in (list_payloads(item_id=item_id) if list_payloads else [])
- ],
- "ingest_records": [
- IngestRecordSchema.model_validate(row).model_dump(mode="json")
- for row in (list_ingests(item_id=item_id) if list_ingests else [])
- ],
- }
- @router.post("/items/{item_id}/jobs")
- def enqueue_decode_job(
- item_id: UUID,
- repo: Any = Depends(get_decode_repository),
- ) -> dict[str, Any]:
- create = getattr(repo, "create_decode_job", None)
- if create is None:
- raise HTTPException(status_code=501, detail="decode job writer is not implemented")
- job = create(item_id=item_id, status="pending")
- return {"job": job.model_dump(mode="json") if hasattr(job, "model_dump") else job}
- @router.post("/items/{item_id}/ingest", response_model=IngestItemResponse)
- def ingest_item_payloads(
- item_id: UUID,
- request: IngestItemRequest | None = Body(default=None),
- repo: Any = Depends(get_decode_repository),
- ) -> IngestItemResponse:
- request = request or IngestItemRequest()
- list_payloads = getattr(repo, "list_payload_drafts", None)
- if list_payloads is None:
- raise HTTPException(status_code=501, detail="payload draft reader is not implemented")
- drafts = list_payloads(item_id=item_id)
- client = None
- if not request.dry_run:
- config = IngestApiConfig.from_env(_env_file())
- if not config.url:
- raise HTTPException(status_code=400, detail="CK_INGEST_API_URL 未配置,真实 ingest 已关闭")
- client = KnowledgeIngestClient(config)
- records = []
- for draft in drafts:
- records.append(ingest_payload_draft(repo, draft, dry_run=request.dry_run, client=client))
- results = [
- IngestItemResultSchema(
- payload_draft_id=record.payload_draft_id,
- ingest_record=IngestRecordSchema.model_validate(record),
- )
- for record in records
- ]
- ingested_count = sum(1 for record in records if record.status == "ingested")
- failed_count = sum(1 for record in records if record.status == "failed")
- return IngestItemResponse(
- item_id=item_id,
- dry_run=request.dry_run,
- total=len(drafts),
- ingested_count=ingested_count,
- failed_count=failed_count,
- results=results,
- )
|