prepare fastapi root layout for server deployment
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""FastAPI 路由模块。"""
|
||||
@@ -0,0 +1,31 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.db.session import get_db
|
||||
from app.schemas.agent import AgentHelloResponse, AgentHelloUser
|
||||
from app.services.audit_service import AuditService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/agent/hello", response_model=ApiResponse[AgentHelloResponse])
|
||||
def hello(ctx: UserContext = Depends(get_user_context), db: Session = Depends(get_db)):
|
||||
"""Agent Hello:读取宿主用户上下文并返回 Demo 功能配置。"""
|
||||
AuditService(db).log(ctx, "agent.hello", "agent")
|
||||
db.commit()
|
||||
return ok(
|
||||
AgentHelloResponse(
|
||||
user=AgentHelloUser(
|
||||
user_id=ctx.user_id,
|
||||
tenant_id=ctx.tenant_id,
|
||||
role=ctx.role,
|
||||
source=ctx.auth_source,
|
||||
username=ctx.username,
|
||||
display_name=ctx.display_name,
|
||||
),
|
||||
features=settings.as_public_dict(),
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,52 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.schemas.auth import AuthMeResponse
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/me", response_model=ApiResponse[AuthMeResponse])
|
||||
async def auth_me(ctx: UserContext = Depends(get_user_context)):
|
||||
"""当前用户:转发 Authorization 到 Django 用户中心,并返回标准化后的用户信息。"""
|
||||
profile = ctx.profile or {}
|
||||
return ok(
|
||||
AuthMeResponse(
|
||||
user_id=ctx.user_id,
|
||||
source=ctx.auth_source,
|
||||
username=ctx.username,
|
||||
display_name=ctx.display_name,
|
||||
tenant_id=ctx.tenant_id,
|
||||
role=ctx.role,
|
||||
phone=profile.get("phone"),
|
||||
avatar=profile.get("avatar"),
|
||||
gender=profile.get("gender"),
|
||||
institution=profile.get("institution") or profile.get("institution_id"),
|
||||
institution_id=profile.get("institution_id") or profile.get("institution"),
|
||||
institution_name=profile.get("institution_name"),
|
||||
department=profile.get("department") or profile.get("department_id"),
|
||||
department_id=profile.get("department_id") or profile.get("department"),
|
||||
department_name=profile.get("department_name"),
|
||||
title_name=profile.get("title_name"),
|
||||
major=profile.get("major"),
|
||||
training_stage=profile.get("training_stage"),
|
||||
learning_target=profile.get("learning_target"),
|
||||
competency_profile=profile.get("competency_profile"),
|
||||
weak_dimensions=profile.get("weak_dimensions"),
|
||||
strong_dimensions=profile.get("strong_dimensions"),
|
||||
ai_preference=profile.get("ai_preference"),
|
||||
total_training_count=profile.get("total_training_count"),
|
||||
total_case_count=profile.get("total_case_count"),
|
||||
current_level=profile.get("current_level"),
|
||||
status=profile.get("status"),
|
||||
last_login=profile.get("last_login"),
|
||||
last_login_time=profile.get("last_login_time"),
|
||||
is_superuser=profile.get("is_superuser"),
|
||||
is_staff=profile.get("is_staff"),
|
||||
is_active=profile.get("is_active"),
|
||||
date_joined=profile.get("date_joined"),
|
||||
created_at=profile.get("created_at"),
|
||||
updated_at=profile.get("updated_at"),
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,59 @@
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.db.session import get_db
|
||||
from app.schemas.case import (
|
||||
CaseDeletePreviewResponse,
|
||||
CaseDeleteRequest,
|
||||
CaseDeleteResponse,
|
||||
CaseDetailResponse,
|
||||
CaseListResponse,
|
||||
)
|
||||
from app.services.case_service import CaseService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=ApiResponse[CaseListResponse])
|
||||
def list_cases(
|
||||
_: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
department_id: int | None = Query(default=None),
|
||||
training_type: str | None = Query(default=None),
|
||||
mode: str | None = Query(default=None),
|
||||
):
|
||||
"""病例列表:返回当前可用的激活病例,不暴露标准答案。"""
|
||||
return ok(CaseService(db).list_cases(department_id=department_id, training_type=training_type, mode=mode))
|
||||
|
||||
|
||||
@router.get("/{case_id}", response_model=ApiResponse[CaseDetailResponse])
|
||||
def get_case_detail(
|
||||
case_id: int,
|
||||
_: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""病例详情:返回训练入口信息和可申请检查类型。"""
|
||||
return ok(CaseService(db).get_case_detail(case_id))
|
||||
|
||||
|
||||
@router.get("/{case_id}/delete-preview", response_model=ApiResponse[CaseDeletePreviewResponse])
|
||||
def get_case_delete_preview(
|
||||
case_id: int,
|
||||
_: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""病例删除预览:返回删除该病例会影响的训练与病例数据数量。"""
|
||||
return ok(CaseService(db).get_delete_preview(case_id))
|
||||
|
||||
|
||||
@router.delete("/{case_id}", response_model=ApiResponse[CaseDeleteResponse])
|
||||
def delete_case(
|
||||
case_id: int,
|
||||
payload: CaseDeleteRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""病例删除:确认后级联删除病例、扩展表、评分规则、检查项和关联训练数据。"""
|
||||
return ok(CaseService(db).delete_case(case_id, payload, ctx))
|
||||
@@ -0,0 +1,39 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.db.session import get_db
|
||||
from app.schemas.evaluation import EvaluationDetailResponse, EvaluationListResponse, ExportPdfResponse
|
||||
from app.services.evaluation_service import EvaluationService
|
||||
from app.services.pdf_export_service import PdfExportService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("", response_model=ApiResponse[EvaluationListResponse])
|
||||
def list_evaluations(ctx: UserContext = Depends(get_user_context), db: Session = Depends(get_db)):
|
||||
"""历史评价:基于 user_id 查询完整训练后的评价记录。"""
|
||||
return ok(EvaluationService(db).list_history(ctx.user_id))
|
||||
|
||||
|
||||
@router.get("/{evaluation_id}", response_model=ApiResponse[EvaluationDetailResponse])
|
||||
def get_evaluation_detail(
|
||||
evaluation_id: int,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""评价详情:校验 user_id 后返回完整评价报告。"""
|
||||
return ok(EvaluationService(db).get_detail(evaluation_id, ctx.user_id))
|
||||
|
||||
|
||||
@router.post("/{evaluation_id}/export-pdf", response_model=ApiResponse[ExportPdfResponse])
|
||||
def export_pdf(
|
||||
evaluation_id: int,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""PDF 导出:生成评价报告 PDF 并保存导出记录。"""
|
||||
export = PdfExportService(db).export(evaluation_id, ctx.user_id)
|
||||
db.commit()
|
||||
return ok(ExportPdfResponse(export_id=export.id, file_path=export.file_path))
|
||||
@@ -0,0 +1,56 @@
|
||||
from fastapi import APIRouter
|
||||
from fastapi.responses import JSONResponse
|
||||
from sqlalchemy import text
|
||||
|
||||
from app.core.config import settings
|
||||
from app.core.response import ok
|
||||
from app.db.session import SessionLocal
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/live")
|
||||
def live():
|
||||
"""存活检查:确认 FastAPI 进程已启动并可以响应请求。"""
|
||||
return ok({"status": "live", "environment": settings.app_env})
|
||||
|
||||
|
||||
@router.get("/ready")
|
||||
def ready():
|
||||
"""就绪检查:验证生产配置、MySQL 和 Redis 是否支持核心业务运行。"""
|
||||
checks: dict[str, object] = {
|
||||
"configuration": {"ok": True, "errors": []},
|
||||
"mysql": {"ok": False},
|
||||
"redis": {"ok": False},
|
||||
}
|
||||
|
||||
config_errors = settings.deployment_config_errors()
|
||||
checks["configuration"] = {"ok": not config_errors, "errors": config_errors}
|
||||
|
||||
try:
|
||||
with SessionLocal() as db:
|
||||
db.execute(text("SELECT 1"))
|
||||
checks["mysql"] = {"ok": True}
|
||||
except Exception:
|
||||
checks["mysql"] = {"ok": False, "message": "database connection failed"}
|
||||
|
||||
try:
|
||||
import redis
|
||||
|
||||
redis.Redis.from_url(
|
||||
settings.redis_url,
|
||||
decode_responses=True,
|
||||
socket_connect_timeout=2,
|
||||
socket_timeout=2,
|
||||
).ping()
|
||||
checks["redis"] = {"ok": True}
|
||||
except Exception:
|
||||
checks["redis"] = {"ok": False, "message": "redis connection failed"}
|
||||
|
||||
is_ready = all(bool(item.get("ok")) for item in checks.values() if isinstance(item, dict))
|
||||
payload = {
|
||||
"code": "OK" if is_ready else "SERVICE_NOT_READY",
|
||||
"message": "success" if is_ready else "service dependencies are not ready",
|
||||
"data": {"status": "ready" if is_ready else "not_ready", "checks": checks},
|
||||
}
|
||||
return JSONResponse(status_code=200 if is_ready else 503, content=payload)
|
||||
@@ -0,0 +1,26 @@
|
||||
from fastapi import APIRouter, Depends, File, UploadFile
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.schemas.imports import CaseSqlImportApplyResponse, CaseSqlImportPreviewResponse
|
||||
from app.services.case_sql_import_service import CaseSqlImportService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/case-sql/preview", response_model=ApiResponse[CaseSqlImportPreviewResponse])
|
||||
async def preview_case_sql(
|
||||
file: UploadFile = File(...),
|
||||
_: UserContext = Depends(get_user_context),
|
||||
):
|
||||
"""病例 SQL 预检:上传接口 SQL 文件,解析可导入病例数据但不写入数据库。"""
|
||||
return ok(await CaseSqlImportService().preview(file))
|
||||
|
||||
|
||||
@router.post("/case-sql/apply", response_model=ApiResponse[CaseSqlImportApplyResponse])
|
||||
async def apply_case_sql(
|
||||
file: UploadFile = File(...),
|
||||
_: UserContext = Depends(get_user_context),
|
||||
):
|
||||
"""病例 SQL 导入:确认后把 SQL 中的病例表数据映射写入当前本地数据库。"""
|
||||
return ok(await CaseSqlImportService().apply(file))
|
||||
@@ -0,0 +1,24 @@
|
||||
from fastapi import APIRouter, Depends, Query
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.db.session import get_db
|
||||
from app.schemas.knowledge import KnowledgeSearchResponse
|
||||
from app.services.knowledge_service import KnowledgeService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.get("/search", response_model=ApiResponse[KnowledgeSearchResponse])
|
||||
def search_knowledge(
|
||||
_: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
department_id: int = Query(...),
|
||||
training_type: str = Query(...),
|
||||
q: str = Query(default=""),
|
||||
):
|
||||
"""知识检索:按科室、训练类别和关键词检索评分参考指南。"""
|
||||
keywords = [item.strip() for item in q.split(",") if item.strip()]
|
||||
result = KnowledgeService(db).search_guidelines(department_id, training_type, keywords)
|
||||
return ok(KnowledgeSearchResponse(**result))
|
||||
@@ -0,0 +1,108 @@
|
||||
import time
|
||||
|
||||
from fastapi import APIRouter, Depends
|
||||
|
||||
from app.agents.llm_adapter import OpenAICompatibleLLMClient
|
||||
from app.core.config import settings
|
||||
from app.core.exceptions import AppError
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.schemas.llm import LLMTestRequest, LLMTestResponse
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("/deepseek-fast", response_model=ApiResponse[LLMTestResponse])
|
||||
async def test_deepseek_fast(
|
||||
payload: LLMTestRequest,
|
||||
_: UserContext = Depends(get_user_context),
|
||||
):
|
||||
"""Fast 模型测试:验证快速模型的非流式响应耗时。"""
|
||||
client = OpenAICompatibleLLMClient()
|
||||
response = await client.chat(
|
||||
[{"role": "user", "content": payload.message}],
|
||||
settings.llm_fast_model,
|
||||
thinking_enabled=settings.llm_fast_thinking_enabled,
|
||||
max_tokens=min(settings.llm_fast_max_tokens, 256),
|
||||
)
|
||||
return ok(
|
||||
LLMTestResponse(
|
||||
model=response.model,
|
||||
total_latency_ms=response.latency_ms,
|
||||
stream=False,
|
||||
mock_mode=client.is_mock_mode,
|
||||
fallback_used=response.model.startswith("mock-fallback"),
|
||||
thinking_enabled=settings.llm_fast_thinking_enabled,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
@router.post("/deepseek-reason", response_model=ApiResponse[LLMTestResponse])
|
||||
async def test_deepseek_reason(
|
||||
payload: LLMTestRequest,
|
||||
_: UserContext = Depends(get_user_context),
|
||||
):
|
||||
"""Reason 模型测试:优先验证流式耗时,流式不兼容时降级为真实非流式测试。"""
|
||||
client = OpenAICompatibleLLMClient()
|
||||
messages = [{"role": "user", "content": payload.message}]
|
||||
first_token_ms = None
|
||||
start = time.perf_counter()
|
||||
|
||||
try:
|
||||
async for chunk in client.stream_chat(
|
||||
messages,
|
||||
settings.llm_reason_model,
|
||||
thinking_enabled=settings.llm_reason_thinking_enabled,
|
||||
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
|
||||
max_tokens=min(settings.llm_fast_max_tokens, 256),
|
||||
):
|
||||
if first_token_ms is None and chunk.first_token_ms is not None:
|
||||
first_token_ms = chunk.first_token_ms
|
||||
if chunk.done:
|
||||
return ok(
|
||||
LLMTestResponse(
|
||||
model=chunk.model or (settings.llm_reason_model if not client.is_mock_mode else f"mock-{settings.llm_reason_model}"),
|
||||
first_token_ms=first_token_ms,
|
||||
total_latency_ms=chunk.total_latency_ms or int((time.perf_counter() - start) * 1000),
|
||||
stream=True,
|
||||
mock_mode=client.is_mock_mode,
|
||||
fallback_used=chunk.fallback_used,
|
||||
thinking_enabled=settings.llm_reason_thinking_enabled,
|
||||
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
|
||||
)
|
||||
)
|
||||
except AppError as exc:
|
||||
if exc.code != "LLM_STREAM_FAILED":
|
||||
raise
|
||||
response = await client.chat(
|
||||
messages,
|
||||
settings.llm_reason_model,
|
||||
thinking_enabled=settings.llm_reason_thinking_enabled,
|
||||
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
|
||||
max_tokens=min(settings.llm_fast_max_tokens, 256),
|
||||
)
|
||||
return ok(
|
||||
LLMTestResponse(
|
||||
model=response.model,
|
||||
first_token_ms=None,
|
||||
total_latency_ms=response.latency_ms,
|
||||
stream=False,
|
||||
mock_mode=client.is_mock_mode,
|
||||
fallback_used=response.model.startswith("mock-fallback"),
|
||||
thinking_enabled=settings.llm_reason_thinking_enabled,
|
||||
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
|
||||
)
|
||||
)
|
||||
|
||||
return ok(
|
||||
LLMTestResponse(
|
||||
model=settings.llm_reason_model,
|
||||
first_token_ms=first_token_ms,
|
||||
total_latency_ms=int((time.perf_counter() - start) * 1000),
|
||||
stream=True,
|
||||
mock_mode=client.is_mock_mode,
|
||||
fallback_used=False,
|
||||
thinking_enabled=settings.llm_reason_thinking_enabled,
|
||||
reasoning_effort=settings.llm_reasoning_effort if settings.llm_reason_thinking_enabled else None,
|
||||
)
|
||||
)
|
||||
@@ -0,0 +1,13 @@
|
||||
from fastapi import APIRouter
|
||||
|
||||
from app.api import agent, auth, cases, evaluations, imports, knowledge, llm_test, sessions
|
||||
|
||||
api_router = APIRouter()
|
||||
api_router.include_router(agent.router, tags=["agent"])
|
||||
api_router.include_router(auth.router, prefix="/auth", tags=["auth"])
|
||||
api_router.include_router(cases.router, prefix="/cases", tags=["cases"])
|
||||
api_router.include_router(sessions.router, prefix="/sessions", tags=["sessions"])
|
||||
api_router.include_router(evaluations.router, prefix="/evaluations", tags=["evaluations"])
|
||||
api_router.include_router(knowledge.router, prefix="/knowledge", tags=["knowledge"])
|
||||
api_router.include_router(llm_test.router, prefix="/llm/test", tags=["llm-test"])
|
||||
api_router.include_router(imports.router, prefix="/imports", tags=["imports"])
|
||||
@@ -0,0 +1,162 @@
|
||||
from fastapi import APIRouter, Depends
|
||||
from sqlalchemy.orm import Session
|
||||
from starlette.responses import StreamingResponse
|
||||
|
||||
from app.core.response import ApiResponse, ok
|
||||
from app.core.user_context import UserContext, get_user_context
|
||||
from app.db.session import get_db
|
||||
from app.schemas.evaluation import CreateEvaluationRequest, EvaluationResponse
|
||||
from app.schemas.session import (
|
||||
ChatRequest,
|
||||
ChatResponse,
|
||||
CreateOrderRequest,
|
||||
CreateOrderResponse,
|
||||
CreateSessionRequest,
|
||||
CreateSessionResponse,
|
||||
OrderItemsResponse,
|
||||
SessionStatusResponse,
|
||||
SubmitDiagnosisRequest,
|
||||
SubmitDiagnosisResponse,
|
||||
SubmitTreatmentRequest,
|
||||
SubmitTreatmentResponse,
|
||||
HintRequest,
|
||||
HintResponse,
|
||||
)
|
||||
from app.services.evaluation_service import EvaluationService
|
||||
from app.services.order_service import OrderService
|
||||
from app.services.session_service import SessionService
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
@router.post("", response_model=ApiResponse[CreateSessionResponse])
|
||||
def create_session(
|
||||
payload: CreateSessionRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""创建训练会话:初始化 user_id 隔离的训练会话和短期 memory。"""
|
||||
result = SessionService(db).create_session(ctx, payload)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/chat", response_model=ApiResponse[ChatResponse])
|
||||
async def chat(
|
||||
session_id: int,
|
||||
payload: ChatRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""非流式问诊:发送医生问题并返回 AI 病人回复。"""
|
||||
result = await SessionService(db).chat(ctx, session_id, payload.message)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/chat/stream", response_class=StreamingResponse)
|
||||
async def chat_stream(
|
||||
session_id: int,
|
||||
payload: ChatRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""流式问诊:返回 SSE 格式的 AI 病人增量回复。"""
|
||||
response = await SessionService(db).stream_chat(ctx, session_id, payload.message)
|
||||
db.commit()
|
||||
return StreamingResponse(
|
||||
response,
|
||||
media_type="text/event-stream",
|
||||
headers={
|
||||
"Cache-Control": "no-cache",
|
||||
"Connection": "keep-alive",
|
||||
"X-Accel-Buffering": "no",
|
||||
},
|
||||
)
|
||||
|
||||
|
||||
@router.get("/{session_id}/order-items", response_model=ApiResponse[OrderItemsResponse])
|
||||
def list_order_items(
|
||||
session_id: int,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""检查项目列表:返回当前病例可申请项目,不返回检查结果。"""
|
||||
return ok(OrderService(db).list_order_items(session_id, ctx.user_id))
|
||||
|
||||
|
||||
@router.post("/{session_id}/orders", response_model=ApiResponse[CreateOrderResponse])
|
||||
def create_order(
|
||||
session_id: int,
|
||||
payload: CreateOrderRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""申请检查检验:从数据库读取并返回结构化结果。"""
|
||||
result = OrderService(db).create_order(session_id, ctx.user_id, payload.item_code)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/complete-inquiry", response_model=ApiResponse[SessionStatusResponse])
|
||||
def complete_inquiry(
|
||||
session_id: int,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""完成问诊:从问诊阶段进入诊断阶段。"""
|
||||
result = SessionService(db).complete_inquiry(ctx, session_id)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/hints", response_model=ApiResponse[HintResponse])
|
||||
async def generate_hints(
|
||||
session_id: int,
|
||||
payload: HintRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""新手模式提示:根据当前问诊上下文生成缺失维度和下一步问题。"""
|
||||
result = await SessionService(db).generate_hints(ctx, session_id, payload)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/diagnosis", response_model=ApiResponse[SubmitDiagnosisResponse])
|
||||
def submit_diagnosis(
|
||||
session_id: int,
|
||||
payload: SubmitDiagnosisRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""提交诊断:保存主要诊断、鉴别诊断和诊断依据。"""
|
||||
result = SessionService(db).submit_diagnosis(ctx, session_id, payload)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/treatment", response_model=ApiResponse[SubmitTreatmentResponse])
|
||||
def submit_treatment(
|
||||
session_id: int,
|
||||
payload: SubmitTreatmentRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""提交治疗方案:保存治疗、风险、沟通和随访内容。"""
|
||||
result = SessionService(db).submit_treatment(ctx, session_id, payload)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
|
||||
|
||||
@router.post("/{session_id}/evaluation", response_model=ApiResponse[EvaluationResponse])
|
||||
async def create_evaluation(
|
||||
session_id: int,
|
||||
payload: CreateEvaluationRequest,
|
||||
ctx: UserContext = Depends(get_user_context),
|
||||
db: Session = Depends(get_db),
|
||||
):
|
||||
"""生成评价报告:检索指南并调用 Scoring Agent 生成结构化评价。"""
|
||||
result = await EvaluationService(db).create_evaluation(ctx, session_id, payload)
|
||||
db.commit()
|
||||
return ok(result)
|
||||
Reference in New Issue
Block a user