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}