GeoIntel release gates / Compile, test, contracts and builds (push) Successful in 1m49s
GeoIntel release gates / Python and npm vulnerability policy (push) Successful in 21s
GeoIntel release gates / Production AI image, SBOM and container scan (push) Successful in 5m39s
GeoIntel release gates / Deploy exact gated revision to Unraid (push) Failing after 58m43s
107 lines
3.3 KiB
Python
107 lines
3.3 KiB
Python
from __future__ import annotations
|
|
|
|
from uuid import UUID
|
|
|
|
from fastapi import APIRouter, Depends, Query
|
|
from sqlalchemy.orm import Session
|
|
|
|
from app.db.session import get_db
|
|
from app.schemas import Envelope, QualityEvidenceResponse
|
|
from app.schemas.detection_review import DetectionReviewList, DetectionReviewRead, DetectionReviewUpsert
|
|
from app.schemas.qa import QualityCheckList
|
|
from app.services.detection_review_service import DetectionReviewService
|
|
from app.services.quality_evidence_service import QualityEvidenceService
|
|
from app.services.quality_check_service import QualityCheckService
|
|
from app.utils.response import envelope
|
|
|
|
router = APIRouter(prefix="/projects/{project_id}", tags=["quality-checks"])
|
|
|
|
|
|
@router.get("/quality-checks", response_model=Envelope[QualityCheckList])
|
|
def list_quality_checks(
|
|
project_id: UUID,
|
|
limit: int = Query(default=50, ge=1, le=200),
|
|
offset: int = Query(default=0, ge=0),
|
|
db: Session = Depends(get_db),
|
|
) -> dict:
|
|
items, total = QualityCheckService.list_quality_checks(
|
|
db,
|
|
project_id=project_id,
|
|
limit=limit,
|
|
offset=offset,
|
|
)
|
|
return envelope(QualityCheckList(items=items, total=total, limit=limit, offset=offset).model_dump())
|
|
|
|
|
|
@router.get(
|
|
"/quality-checks/{quality_check_id}/evidence/geojson",
|
|
response_model=Envelope[QualityEvidenceResponse],
|
|
)
|
|
def get_quality_check_evidence_geojson(
|
|
project_id: UUID,
|
|
quality_check_id: UUID,
|
|
limit: int = Query(
|
|
default=QualityEvidenceService.DEFAULT_EVIDENCE_LIMIT,
|
|
ge=0,
|
|
le=100_000,
|
|
description="Maximum evidence features to draw; 0 returns everything. Misses and false positives first.",
|
|
),
|
|
db: Session = Depends(get_db),
|
|
) -> dict:
|
|
return envelope(
|
|
QualityEvidenceService.evidence_geojson(
|
|
db,
|
|
project_id=project_id,
|
|
quality_check_id=quality_check_id,
|
|
limit=limit,
|
|
)
|
|
)
|
|
|
|
|
|
@router.get(
|
|
"/quality-checks/{quality_check_id}/reviews",
|
|
response_model=Envelope[DetectionReviewList],
|
|
)
|
|
def list_detection_reviews(
|
|
project_id: UUID,
|
|
quality_check_id: UUID,
|
|
evidence_role: str | None = Query(default=None, pattern="^(false_positive|false_negative)$"),
|
|
decision: str | None = Query(default=None, max_length=64),
|
|
reviewed: bool | None = Query(default=None),
|
|
limit: int = Query(default=50, ge=1, le=200),
|
|
offset: int = Query(default=0, ge=0),
|
|
db: Session = Depends(get_db),
|
|
) -> dict:
|
|
return envelope(
|
|
DetectionReviewService.list_reviews(
|
|
db,
|
|
project_id=project_id,
|
|
quality_check_id=quality_check_id,
|
|
evidence_role=evidence_role,
|
|
decision=decision,
|
|
reviewed=reviewed,
|
|
limit=limit,
|
|
offset=offset,
|
|
).model_dump()
|
|
)
|
|
|
|
|
|
@router.post(
|
|
"/quality-checks/{quality_check_id}/reviews",
|
|
response_model=Envelope[DetectionReviewRead],
|
|
)
|
|
def upsert_detection_review(
|
|
project_id: UUID,
|
|
quality_check_id: UUID,
|
|
payload: DetectionReviewUpsert,
|
|
db: Session = Depends(get_db),
|
|
) -> dict:
|
|
return envelope(
|
|
DetectionReviewService.upsert_review(
|
|
db,
|
|
project_id=project_id,
|
|
quality_check_id=quality_check_id,
|
|
payload=payload,
|
|
).model_dump()
|
|
)
|