feat: 初始化孕育无忧全栈项目基础代码结构
完成项目初始搭建,包含后端FastAPI+MongoDB服务、前端React+Vite项目的完整基础结构,添加各类配置文件与依赖清单,涵盖核心业务初始框架。
This commit is contained in:
147
backend/app/routers/analysis.py
Normal file
147
backend/app/routers/analysis.py
Normal file
@@ -0,0 +1,147 @@
|
||||
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(),
|
||||
}
|
||||
Reference in New Issue
Block a user