Spaces:
Sleeping
Sleeping
| """CRUD operations for analysis history.""" | |
| from datetime import datetime | |
| from typing import Optional | |
| from bson import ObjectId | |
| from motor.motor_asyncio import AsyncIOMotorDatabase | |
| from backend.core.schema import EnsembleResult | |
| from backend.db.models import AnalysisHistoryDocument, AnalysisHistoryResponse | |
| async def save_analysis( | |
| db: AsyncIOMotorDatabase, | |
| filename: str, | |
| result: EnsembleResult, | |
| ) -> str: | |
| """Save analysis result to MongoDB.""" | |
| doc = AnalysisHistoryDocument.from_ensemble_result(filename, result) | |
| doc_dict = doc.model_dump(by_alias=False, exclude={"id"}) | |
| result = await db.analysis_history.insert_one(doc_dict) | |
| return str(result.inserted_id) | |
| async def get_analysis_by_id( | |
| db: AsyncIOMotorDatabase, | |
| analysis_id: str, | |
| ) -> Optional[dict]: | |
| """Get analysis by ID.""" | |
| try: | |
| oid = ObjectId(analysis_id) | |
| except Exception: | |
| return None | |
| return await db.analysis_history.find_one({"_id": oid}) | |
| async def get_analysis_history( | |
| db: AsyncIOMotorDatabase, | |
| limit: int = 100, | |
| skip: int = 0, | |
| verdict: Optional[str] = None, | |
| ) -> list[dict]: | |
| """Get analysis history with optional filtering.""" | |
| query = {} | |
| if verdict: | |
| query["verdict"] = verdict | |
| cursor = db.analysis_history.find(query).sort("created_at", -1).skip(skip).limit(limit) | |
| return await cursor.to_list(length=limit) | |
| async def get_history_stats(db: AsyncIOMotorDatabase) -> dict: | |
| """Get summary statistics from analysis history.""" | |
| pipeline = [ | |
| { | |
| "$group": { | |
| "_id": "$verdict", | |
| "count": {"$sum": 1}, | |
| "avg_confidence": {"$avg": "$confidence"}, | |
| "avg_p_fake": {"$avg": "$p_fake"}, | |
| } | |
| } | |
| ] | |
| stats = await db.analysis_history.aggregate(pipeline).to_list(length=None) | |
| return {item["_id"]: { | |
| "count": item["count"], | |
| "avg_confidence": round(item["avg_confidence"], 3), | |
| "avg_p_fake": round(item["avg_p_fake"], 3), | |
| } for item in stats} | |
| async def delete_analysis(db: AsyncIOMotorDatabase, analysis_id: str) -> bool: | |
| """Delete analysis by ID.""" | |
| try: | |
| oid = ObjectId(analysis_id) | |
| except Exception: | |
| return False | |
| result = await db.analysis_history.delete_one({"_id": oid}) | |
| return result.deleted_count > 0 | |