RAG_Backend / backend /app /api /analysis.py
Madhesh4124's picture
Refactored the codebase and implemented stateless
e8cd7a9
Raw
History Blame Contribute Delete
3.57 kB
import uuid
import os
from fastapi import APIRouter, Depends, HTTPException
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select
from app.database import get_db
from app.auth import get_current_user
from app.models.user import User
from app.models.chat import ChatMessage
from app.models.evaluation import EvaluationResult
from app.models.metrics import Metrics
from app.services.analysis import RetrievalAnalyzer
router = APIRouter(prefix="/api/analysis", tags=["analysis"])
@router.get("/{message_id}")
async def analyze_message(message_id: uuid.UUID, current_user: User = Depends(get_current_user), db: AsyncSession = Depends(get_db)):
# 1. Fetch the message natively mapped
stmt_msg = select(ChatMessage).where(ChatMessage.id == message_id, ChatMessage.user_id == current_user.id)
msg = (await db.execute(stmt_msg)).scalars().first()
if not msg:
raise HTTPException(status_code=404, detail="Message not found")
if msg.role != "assistant":
raise HTTPException(status_code=400, detail="Analysis is logically only available for assistant messages")
# 2. Fetch associated metrics (if any timer payloads caught mapped traces securely)
stmt = select(Metrics).where(Metrics.message_id == message_id)
metrics_record = (await db.execute(stmt)).scalars().first()
eval_stmt = (
select(EvaluationResult)
.where(EvaluationResult.message_id == message_id)
.order_by(EvaluationResult.created_at.desc())
)
eval_record = (await db.execute(eval_stmt)).scalars().first()
# 3. Parse retrieved chunks and instantly leverage our abstract Analyzer class seamlessly
chunks_data = msg.retrieved_chunks or []
confidence_threshold = float(os.getenv("ANALYSIS_CONFIDENCE_THRESHOLD", "0.5"))
analyzer = RetrievalAnalyzer(chunks_data, confidence_threshold=confidence_threshold)
summary = analyzer.summary_stats()
# Construct structured insight payload natively mapped
return {
"message_id": message_id,
"total_chunks_retrieved": summary["total_chunks_retrieved"],
"avg_similarity": summary["avg_similarity"],
"warning_flag": summary["warning_flag"],
"confidence_threshold": summary["confidence_threshold"],
"score_distribution": summary["score_distribution"],
"chunk_diversity": summary["chunk_diversity"],
"top_contributors": summary["top_contributors"],
"ranked_chunks": summary["ranked_chunks"],
"summary_stats": summary,
"evaluation": {
"faithfulness": eval_record.faithfulness if eval_record else None,
"answer_relevancy": eval_record.answer_relevancy if eval_record else None,
"context_precision": eval_record.context_precision if eval_record else None,
"context_recall": eval_record.context_recall if eval_record else None,
} if eval_record else None,
"timing_breakdown": {
"chunking_time_ms": metrics_record.chunking_time_ms if metrics_record else None,
"embedding_time_ms": metrics_record.embedding_time_ms if metrics_record else None,
"retrieval_time_ms": metrics_record.retrieval_time_ms if metrics_record else None,
"reranking_time_ms": metrics_record.reranking_time_ms if metrics_record else None,
"llm_time_ms": metrics_record.llm_time_ms if metrics_record else None,
"total_time_ms": metrics_record.total_time_ms if metrics_record else None,
} if metrics_record else None
}