File size: 4,450 Bytes
b708f13 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 | from fastapi import APIRouter, Depends, HTTPException, BackgroundTasks, status
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from typing import List, Optional, Dict, Any # 🔥 Added Dict, Any
from app.api import deps
from app.schemas.veritas import (
VeritasScanRequest,
IntegrityReport,
VeritasQuickSummary,
VeritasScanResponse
)
# 🔥 Import the service classes needed for initialization
from app.services.veritas.engine import VeritasEngine
from app.services.veritas.shield_one import SemanticFingerprinterAsync
from app.services.veritas.shield_two import ParaphraseDetector
from app.services.veritas.shield_three import ClaimVerifier
from app.tasks.veritas_scan import run_veritas_task
from app.models.audit import AuditRecord
from app.core.config import settings
router = APIRouter()
# 🔥 FIXED: Initialize sub-services first, then pass to VeritasEngine
semantic_svc = SemanticFingerprinterAsync(index_path=settings.VERITAS_LOCAL_INDEX_PATH)
structural_svc = ParaphraseDetector()
fact_svc = ClaimVerifier()
veritas_engine = VeritasEngine(
semantic_service=semantic_svc,
structural_service=structural_svc,
fact_service=fact_svc
)
@router.post("/check", response_model=Dict[str, Any]) # 🔥 Changed to Dict since run_quick_check returns dict
async def check_originality(
request: VeritasScanRequest,
current_user = Depends(deps.get_current_active_user)
):
"""
Real-time 'Adaptive' integrity check.
Triggered during writing (Mode A/B). Returns a high-level summary
of originality and semantic matches without full structural analysis.
"""
# 🔥 FIXED: Changed from .check_integrity() to .run_quick_check()
# 🔥 REMOVED: mode parameter (not supported by run_quick_check)
result = await veritas_engine.run_quick_check(
text=request.text,
user_prior_work=request.user_prior_work
)
return result
@router.post("/deep-scan", status_code=status.HTTP_202_ACCEPTED)
async def trigger_deep_scan(
request: VeritasScanRequest,
background_tasks: BackgroundTasks,
db: AsyncSession = Depends(deps.get_db),
current_user = Depends(deps.get_current_active_user)
):
"""
Triggers a 'Doctoral-Grade' deep integrity audit.
Since this process involves cross-encoding and NLI claim verification
(10-30 seconds), it is executed as a background task.
"""
# 1. Create initial audit record
new_audit = AuditRecord(
user_id=current_user.id,
status="pending",
mode="deep"
)
db.add(new_audit)
await db.commit()
await db.refresh(new_audit)
# 2. Enqueue background task
background_tasks.add_task(
run_veritas_task,
document_id=new_audit.document_id,
text=request.text,
prior_work=request.user_prior_work
)
return {"document_id": new_audit.document_id, "status": "queued"}
@router.get("/report/{document_id}", response_model=IntegrityReport)
async def get_integrity_report(
document_id: str,
db: AsyncSession = Depends(deps.get_db),
current_user = Depends(deps.get_current_active_user)
):
"""
Retrieves the completed 'Doctoral-Grade' integrity report.
"""
result = await db.execute(
select(AuditRecord).where(
AuditRecord.document_id == document_id,
AuditRecord.user_id == current_user.id
)
)
audit = result.scalar_one_or_none()
if not audit:
raise HTTPException(status_code=404, detail="Report not found")
if audit.status != "completed":
raise HTTPException(
status_code=400,
detail=f"Report is not ready. Current status: {audit.status}"
)
return audit.report_json
@router.get("/status/{document_id}")
async def get_scan_status(
document_id: str,
db: AsyncSession = Depends(deps.get_db),
current_user = Depends(deps.get_current_active_user)
):
"""
Pollable endpoint for checking the progress of a deep scan.
"""
result = await db.execute(
select(AuditRecord.status, AuditRecord.overall_score).where(
AuditRecord.document_id == document_id,
AuditRecord.user_id == current_user.id
)
)
row = result.fetchone()
if not row:
raise HTTPException(status_code=404, detail="Audit not found")
return {"status": row.status, "score": row.overall_score}
|