Adisri99's picture
Upload 26 files
1ce499f verified
import json
from fastapi import APIRouter, Depends, HTTPException
from app.database import get_db
from app.feature_engineering import normalize_object
from app.services import score_pair
from app.repository import list_high_risk_pairs, get_pair, get_pair_history, pairs_in_same_shell, object_pairs
router=APIRouter(prefix="/api/v1", tags=["pairs"])
@router.post("/score/pair")
def score_pair_route(payload:dict, db=Depends(get_db)): return score_pair(db, normalize_object(payload["primary"]), normalize_object(payload["secondary"]))
@router.get("/pairs/high-risk")
def high_risk(limit:int=50, db=Depends(get_db)):
rows=list_high_risk_pairs(db, limit)
return [{"pair_id":r.pair_id,"risk_score":r.risk_score,"anomaly_score":r.anomaly_score,"final_score":r.final_score,"risk_label":r.risk_label,"recurrence_count":r.recurrence_count,"trend_delta_24h":r.trend_delta_24h,"shell_key":r.shell_key,"top_factors":json.loads(r.top_factors_json)} for r in rows]
@router.get("/pairs/{pair_id}")
def pair_detail(pair_id:str, db=Depends(get_db)):
row=get_pair(db, pair_id)
if not row: raise HTTPException(status_code=404, detail="Pair not found")
payload=json.loads(row.feature_payload_json)
return {"pair_id":row.pair_id,"primary_object_id":row.primary_object_id,"secondary_object_id":row.secondary_object_id,"risk_score":row.risk_score,"anomaly_score":row.anomaly_score,"final_score":row.final_score,"risk_label":row.risk_label,"recurrence_count":row.recurrence_count,"trend_delta_24h":row.trend_delta_24h,"shell_key":row.shell_key,"top_factors":json.loads(row.top_factors_json),"features":payload,"analyst_summary":payload.get("analyst_summary",""),"structured_explanation":payload.get("structured_explanation",{})}
@router.get("/pairs/{pair_id}/history")
def pair_history(pair_id:str, limit:int=20, db=Depends(get_db)):
rows=get_pair_history(db, pair_id, limit)
return [{"history_id":r.history_id,"run_id":r.run_id,"risk_score":r.risk_score,"anomaly_score":r.anomaly_score,"final_score":r.final_score,"created_at":r.created_at} for r in rows]
@router.get("/pairs/{pair_id}/neighbors")
def pair_neighbors(pair_id:str, limit:int=20, db=Depends(get_db)):
row=get_pair(db, pair_id)
if not row: raise HTTPException(status_code=404, detail="Pair not found")
shell_rows=pairs_in_same_shell(db, row.shell_key or "unknown", row.pair_id, limit)
object_related=object_pairs(db, row.primary_object_id, limit)+object_pairs(db, row.secondary_object_id, limit)
seen={pair_id}; related=[]
for r in shell_rows+object_related:
if r.pair_id in seen: continue
seen.add(r.pair_id); related.append({"pair_id":r.pair_id,"final_score":r.final_score,"risk_label":r.risk_label,"top_factors":json.loads(r.top_factors_json)})
if len(related)>=limit: break
return related