Files
app_03_pregnancy/backend/app/routers/analysis.py
Karlcarlo 409dabafb5 feat: 初始化孕育无忧全栈项目基础代码结构
完成项目初始搭建,包含后端FastAPI+MongoDB服务、前端React+Vite项目的完整基础结构,添加各类配置文件与依赖清单,涵盖核心业务初始框架。
2026-05-21 00:46:48 +08:00

148 lines
4.8 KiB
Python

import logging
from datetime import datetime, timezone
from fastapi import APIRouter, Depends, HTTPException
from app.middleware.auth import get_current_user
from app.models.analysis import (
Analysis,
CategoryInterpretation,
IndicatorInterpretation,
ActionItem,
)
from app.models.report import Report
from app.models.user import User
from app.services.ai_service import analyze_report
from app.routers.calendar import link_report_to_checkup
from app.utils.helpers import parse_object_id
logger = logging.getLogger(__name__)
router = APIRouter()
@router.post("/{report_id}/generate")
async def generate_analysis(
report_id: str, user: User = Depends(get_current_user)
):
"""生成 AI 解读"""
oid = parse_object_id(report_id)
report = await Report.get(oid)
if not report or report.user_id != user.id:
raise HTTPException(status_code=404, detail="报告不存在")
# Check if analysis already exists
existing = await Analysis.find_one(Analysis.report_id == report.id)
if existing:
return _analysis_to_dict(existing)
# Call Claude API
try:
result = await analyze_report(report, user)
except Exception:
logger.exception("AI 解读失败 report_id=%s", report_id)
raise HTTPException(status_code=502, detail="AI 解读服务暂时不可用,请稍后重试")
# Save analysis
categories = []
for cat in result.get("categories", []):
indicators = [
IndicatorInterpretation(**ind) for ind in cat.get("indicators", [])
]
categories.append(
CategoryInterpretation(
category=cat.get("category", ""),
status=cat.get("status", "normal"),
indicators=indicators,
)
)
action_items = [ActionItem(**a) for a in result.get("action_items", [])]
analysis = Analysis(
report_id=report.id,
user_id=user.id,
overall_status=result.get("overall_status", "normal"),
risk_level=result.get("risk_level", "low"),
overall_summary=result.get("overall_summary", ""),
emotional_summary=result.get("emotional_summary", ""),
categories=categories,
action_items=action_items,
tips=result.get("tips", []),
)
await analysis.insert()
# Update report status
report.status = "analyzed"
report.overall_status = analysis.overall_status
report.updated_at = datetime.now(timezone.utc)
await report.save()
# Auto-link report to the nearest calendar checkup
if report.pregnancy_week:
try:
await link_report_to_checkup(user.id, str(report.id), report.pregnancy_week)
except Exception:
logger.warning("自动关联日历失败 report_id=%s", report_id)
return _analysis_to_dict(analysis)
@router.get("/{report_id}")
async def get_analysis(report_id: str, user: User = Depends(get_current_user)):
"""获取报告的 AI 解读结果"""
oid = parse_object_id(report_id)
report = await Report.get(oid)
if not report or report.user_id != user.id:
raise HTTPException(status_code=404, detail="报告不存在")
analysis = await Analysis.find_one(Analysis.report_id == report.id)
if not analysis:
raise HTTPException(status_code=404, detail="暂无解读结果,请先生成")
return _analysis_to_dict(analysis)
def _analysis_to_dict(analysis: Analysis) -> dict:
return {
"id": str(analysis.id),
"report_id": str(analysis.report_id),
"overall_status": analysis.overall_status,
"risk_level": analysis.risk_level,
"overall_summary": analysis.overall_summary,
"emotional_summary": analysis.emotional_summary,
"categories": [
{
"category": cat.category,
"status": cat.status,
"indicators": [
{
"name": ind.name,
"nickname": ind.nickname,
"value": ind.value,
"unit": "",
"reference_range": "",
"status": ind.status,
"what_is_it": ind.what_is_it,
"baby_impact": ind.impact,
"suggestion": ind.suggestion,
"follow_up": ind.recheck_reminder or "",
}
for ind in cat.indicators
],
}
for cat in analysis.categories
],
"action_items": [
{
"priority": a.priority,
"title": a.content,
"description": a.category,
"timeframe": "",
}
for a in analysis.action_items
],
"tips": analysis.tips,
"created_at": analysis.created_at.isoformat(),
}