prepare fastapi root layout for server deployment
This commit is contained in:
@@ -0,0 +1 @@
|
||||
"""Pydantic 入参和出参模型。"""
|
||||
@@ -0,0 +1,19 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AgentHelloUser(BaseModel):
|
||||
"""Hello 用户信息:返回宿主系统传入的上下文。"""
|
||||
|
||||
user_id: str
|
||||
tenant_id: str | None = None
|
||||
role: str | None = None
|
||||
source: str | None = None
|
||||
username: str | None = None
|
||||
display_name: str | None = None
|
||||
|
||||
|
||||
class AgentHelloResponse(BaseModel):
|
||||
"""Hello 响应:返回用户上下文和 Demo 能力开关。"""
|
||||
|
||||
user: AgentHelloUser
|
||||
features: dict
|
||||
@@ -0,0 +1,43 @@
|
||||
from typing import Any
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class AuthMeResponse(BaseModel):
|
||||
"""认证用户响应:返回医疗问诊 Agent 标准化后的当前用户信息。"""
|
||||
|
||||
user_id: str
|
||||
source: str
|
||||
username: str | None = None
|
||||
display_name: str | None = None
|
||||
tenant_id: str | None = None
|
||||
role: str | None = None
|
||||
phone: str | None = None
|
||||
avatar: str | None = None
|
||||
gender: int | None = None
|
||||
institution: int | None = None
|
||||
institution_id: int | None = None
|
||||
institution_name: str | None = None
|
||||
department: int | None = None
|
||||
department_id: int | None = None
|
||||
department_name: str | None = None
|
||||
title_name: str | None = None
|
||||
major: str | None = None
|
||||
training_stage: str | None = None
|
||||
learning_target: str | None = None
|
||||
competency_profile: dict[str, Any] | None = None
|
||||
weak_dimensions: list[Any] | None = None
|
||||
strong_dimensions: list[Any] | None = None
|
||||
ai_preference: dict[str, Any] | None = None
|
||||
total_training_count: int | None = None
|
||||
total_case_count: int | None = None
|
||||
current_level: str | None = None
|
||||
status: int | None = None
|
||||
last_login: str | None = None
|
||||
last_login_time: str | None = None
|
||||
is_superuser: bool | None = None
|
||||
is_staff: bool | None = None
|
||||
is_active: bool | None = None
|
||||
date_joined: str | None = None
|
||||
created_at: str | None = None
|
||||
updated_at: str | None = None
|
||||
@@ -0,0 +1,76 @@
|
||||
from pydantic import BaseModel, ConfigDict
|
||||
|
||||
|
||||
class CaseListItem(BaseModel):
|
||||
"""病例列表项:不暴露标准答案和隐藏信息。"""
|
||||
|
||||
id: int
|
||||
case_code: str
|
||||
department_id: int
|
||||
title: str
|
||||
difficulty: str
|
||||
chief_complaint: str | None = None
|
||||
supported_training_type: str
|
||||
supported_mode: str
|
||||
has_teaching_video: bool
|
||||
has_knowledge_points: bool
|
||||
has_quiz: bool
|
||||
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
class CaseListResponse(BaseModel):
|
||||
"""病例列表响应:返回激活病例集合。"""
|
||||
|
||||
items: list[CaseListItem]
|
||||
|
||||
|
||||
class CasePatientInfo(BaseModel):
|
||||
"""患者展示信息:用于病例详情页。"""
|
||||
|
||||
name: str | None = None
|
||||
age: int | None = None
|
||||
gender: str | None = None
|
||||
occupation: str | None = None
|
||||
|
||||
|
||||
class CaseDetailResponse(BaseModel):
|
||||
"""病例详情响应:展示训练入口需要的信息。"""
|
||||
|
||||
id: int
|
||||
case_code: str
|
||||
title: str
|
||||
department: str
|
||||
difficulty: str
|
||||
patient: CasePatientInfo
|
||||
chief_complaint: str | None = None
|
||||
supported_training_type: str
|
||||
supported_mode: str
|
||||
has_teaching_video: bool
|
||||
has_knowledge_points: bool
|
||||
has_quiz: bool
|
||||
order_item_types: list[str]
|
||||
|
||||
|
||||
class CaseDeletePreviewResponse(BaseModel):
|
||||
"""病例删除预览:返回删除该病例会影响的业务数据数量。"""
|
||||
|
||||
case_id: int
|
||||
case_title: str
|
||||
can_delete: bool
|
||||
affected: dict[str, int]
|
||||
|
||||
|
||||
class CaseDeleteRequest(BaseModel):
|
||||
"""病例删除请求:前端必须显式确认,并默认同时删除该病例训练数据。"""
|
||||
|
||||
confirm: bool = False
|
||||
delete_training_data: bool = True
|
||||
|
||||
|
||||
class CaseDeleteResponse(BaseModel):
|
||||
"""病例删除结果:返回已删除的各表记录数量。"""
|
||||
|
||||
deleted: bool
|
||||
case_id: int
|
||||
deleted_counts: dict[str, int]
|
||||
@@ -0,0 +1,84 @@
|
||||
from datetime import datetime
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CreateEvaluationRequest(BaseModel):
|
||||
"""评价生成入参:指定输出分数类型。"""
|
||||
|
||||
score_type: str = Field(default="percentage", pattern="^(percentage|five_point)$")
|
||||
|
||||
|
||||
class DimensionScore(BaseModel):
|
||||
"""维度评分:保存单个评分维度的分数、满分和评价。"""
|
||||
|
||||
dimension: str
|
||||
score: float
|
||||
max_score: float
|
||||
comment: str
|
||||
evidence: list[str] = Field(default_factory=list)
|
||||
deductions: list[str] = Field(default_factory=list)
|
||||
improvement: str = ""
|
||||
|
||||
|
||||
class ScoreDetailItem(BaseModel):
|
||||
"""评分明细:对应 training_score_detail 的单条评分细则。"""
|
||||
|
||||
id: int | None = None
|
||||
record_id: int | None = None
|
||||
rule_id: int | None = None
|
||||
dimension: str
|
||||
score: float | None = None
|
||||
deducted_reason: str | None = None
|
||||
evidence_message_ids: list = Field(default_factory=list)
|
||||
ai_confidence: float | None = None
|
||||
comment: str | None = None
|
||||
|
||||
|
||||
class EvaluationResponse(BaseModel):
|
||||
"""评价报告响应:返回结构化 AI 评价报告。"""
|
||||
|
||||
evaluation_id: int
|
||||
score_type: str
|
||||
total_score: float
|
||||
dimension_scores: list[DimensionScore]
|
||||
score_details: list[ScoreDetailItem] = Field(default_factory=list)
|
||||
errors: list[dict]
|
||||
improvement_plan: list[str]
|
||||
evidence_summary: list[str]
|
||||
guideline_refs: list[dict]
|
||||
overall_comment: str
|
||||
|
||||
|
||||
class EvaluationListItem(BaseModel):
|
||||
"""历史评价列表项:按 user_id 查询完整训练后的评价记录。"""
|
||||
|
||||
evaluation_id: int
|
||||
case_title: str
|
||||
score_type: str
|
||||
total_score: float
|
||||
created_at: datetime
|
||||
pdf_exported: bool
|
||||
|
||||
|
||||
class EvaluationListResponse(BaseModel):
|
||||
"""历史评价列表响应。"""
|
||||
|
||||
items: list[EvaluationListItem]
|
||||
|
||||
|
||||
class ExportPdfResponse(BaseModel):
|
||||
"""PDF 导出响应:返回导出记录和本地文件路径。"""
|
||||
|
||||
export_id: int
|
||||
file_path: str
|
||||
|
||||
|
||||
class EvaluationDetailResponse(EvaluationResponse):
|
||||
"""评价详情响应:在报告详情页使用。"""
|
||||
|
||||
session_id: int
|
||||
case_id: int
|
||||
case_title: str
|
||||
created_at: datetime
|
||||
pdf_file_path: str | None = None
|
||||
@@ -0,0 +1,36 @@
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class CaseSqlPreviewCase(BaseModel):
|
||||
"""病例 SQL 预览病例:展示导入文件中识别到的病例摘要。"""
|
||||
|
||||
id: int
|
||||
title: str
|
||||
case_type: str
|
||||
difficulty: str
|
||||
|
||||
|
||||
class CaseSqlImportPreviewResponse(BaseModel):
|
||||
"""病例 SQL 预检响应:只展示解析结果,不写入数据库。"""
|
||||
|
||||
file_name: str
|
||||
encoding: str | None = None
|
||||
tables: dict[str, int] = Field(default_factory=dict)
|
||||
can_import: bool = False
|
||||
warnings: list[str] = Field(default_factory=list)
|
||||
errors: list[str] = Field(default_factory=list)
|
||||
preview_cases: list[CaseSqlPreviewCase] = Field(default_factory=list)
|
||||
|
||||
|
||||
class CaseSqlImportApplyResponse(BaseModel):
|
||||
"""病例 SQL 导入响应:展示实际写库结果。"""
|
||||
|
||||
imported: bool
|
||||
file_name: str
|
||||
encoding: str
|
||||
inserted_or_updated_cases: int
|
||||
imported_traditional_cases: int
|
||||
imported_teaching_cases: int
|
||||
imported_scoring_rules: int
|
||||
generated_exam_items: int
|
||||
warnings: list[str] = Field(default_factory=list)
|
||||
@@ -0,0 +1,9 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class KnowledgeSearchResponse(BaseModel):
|
||||
"""知识检索响应:返回评分参考指南片段和来源。"""
|
||||
|
||||
matched_chunks: list[dict]
|
||||
source_refs: list[dict]
|
||||
no_match: bool
|
||||
@@ -0,0 +1,20 @@
|
||||
from pydantic import BaseModel
|
||||
|
||||
|
||||
class LLMTestRequest(BaseModel):
|
||||
"""LLM 测试入参:用于快速模型和 reason 模型耗时验证。"""
|
||||
|
||||
message: str = "请用一句话说明医疗问诊训练 Demo 的用途。"
|
||||
|
||||
|
||||
class LLMTestResponse(BaseModel):
|
||||
"""LLM 测试响应:返回模型名、首 token 时间和总耗时。"""
|
||||
|
||||
model: str
|
||||
first_token_ms: int | None = None
|
||||
total_latency_ms: int
|
||||
stream: bool
|
||||
mock_mode: bool = False
|
||||
fallback_used: bool = False
|
||||
thinking_enabled: bool | None = None
|
||||
reasoning_effort: str | None = None
|
||||
@@ -0,0 +1,127 @@
|
||||
from pydantic import BaseModel, Field, field_validator
|
||||
|
||||
|
||||
class CreateSessionRequest(BaseModel):
|
||||
"""创建会话入参:选择病例、训练类别、模式和分数类型。"""
|
||||
|
||||
case_id: int
|
||||
training_type: str = Field(pattern="^(case_analysis|diagnosis_treatment|consultation)$")
|
||||
mode: str = Field(pattern="^(novice|practice|teaching)$")
|
||||
score_type: str = Field(default="percentage", pattern="^(percentage|five_point)$")
|
||||
|
||||
@field_validator("mode")
|
||||
@classmethod
|
||||
def normalize_mode(cls, value: str) -> str:
|
||||
"""训练模式:兼容旧 novice 请求,实际按 practice 练习模式处理。"""
|
||||
return "practice" if value == "novice" else value
|
||||
|
||||
|
||||
class CreateSessionResponse(BaseModel):
|
||||
"""创建会话响应:返回会话标识和 AI 病人开场白。"""
|
||||
|
||||
session_id: int
|
||||
session_code: str
|
||||
status: str
|
||||
patient_opening: str
|
||||
|
||||
|
||||
class ChatRequest(BaseModel):
|
||||
"""问诊消息入参:医生向 AI 病人发送的自然语言问题。"""
|
||||
|
||||
message: str = Field(min_length=1, max_length=2000)
|
||||
|
||||
|
||||
class ChatResponse(BaseModel):
|
||||
"""问诊消息响应:返回 AI 病人的非流式回复。"""
|
||||
|
||||
reply: str
|
||||
latency_ms: int
|
||||
model: str
|
||||
fallback_used: bool = False
|
||||
|
||||
|
||||
class OrderItemResponse(BaseModel):
|
||||
"""可申请检查项:只返回名称和类型,不返回结果。"""
|
||||
|
||||
item_code: str
|
||||
item_name: str
|
||||
item_type: str
|
||||
|
||||
|
||||
class OrderItemsResponse(BaseModel):
|
||||
"""可申请检查项列表响应。"""
|
||||
|
||||
items: list[OrderItemResponse]
|
||||
|
||||
|
||||
class CreateOrderRequest(BaseModel):
|
||||
"""检查申请入参:指定当前病例下的检查项目编码。"""
|
||||
|
||||
item_code: str = Field(min_length=1, max_length=64)
|
||||
|
||||
|
||||
class CreateOrderResponse(BaseModel):
|
||||
"""检查申请响应:返回数据库预设的结构化检查结果。"""
|
||||
|
||||
item_code: str
|
||||
item_name: str
|
||||
item_type: str
|
||||
result_text: str
|
||||
result_structured: dict | None = None
|
||||
is_key: bool
|
||||
is_abnormal: bool
|
||||
context_written: bool = True
|
||||
already_ordered: bool = False
|
||||
|
||||
|
||||
class SessionStatusResponse(BaseModel):
|
||||
"""会话状态响应:用于阶段流转接口。"""
|
||||
|
||||
session_id: int
|
||||
status: str
|
||||
|
||||
|
||||
class SubmitDiagnosisRequest(BaseModel):
|
||||
"""诊断提交入参:保存主要诊断、鉴别诊断和诊断依据。"""
|
||||
|
||||
primary_diagnosis: str = Field(min_length=1, max_length=2000)
|
||||
differential_diagnoses: list[str] = Field(default_factory=list)
|
||||
diagnosis_basis: str = Field(min_length=1, max_length=5000)
|
||||
|
||||
|
||||
class SubmitDiagnosisResponse(BaseModel):
|
||||
"""诊断提交响应:进入治疗阶段。"""
|
||||
|
||||
status: str
|
||||
|
||||
|
||||
class SubmitTreatmentRequest(BaseModel):
|
||||
"""治疗方案入参:保存治疗原则、措施、风险预案、沟通和随访。"""
|
||||
|
||||
treatment_principle: str = Field(min_length=1, max_length=3000)
|
||||
treatment_measures: str = Field(min_length=1, max_length=5000)
|
||||
risk_plan: str | None = Field(default=None, max_length=3000)
|
||||
communication: str | None = Field(default=None, max_length=3000)
|
||||
follow_up: str | None = Field(default=None, max_length=3000)
|
||||
|
||||
|
||||
class SubmitTreatmentResponse(BaseModel):
|
||||
"""治疗提交响应:进入评价阶段。"""
|
||||
|
||||
status: str
|
||||
|
||||
|
||||
class HintRequest(BaseModel):
|
||||
"""会话提示入参:基于当前会话上下文生成新手模式提醒。"""
|
||||
|
||||
last_user_message: str | None = Field(default=None, max_length=2000)
|
||||
scope: str = Field(default="current_conversation", pattern="^current_conversation$")
|
||||
|
||||
|
||||
class HintResponse(BaseModel):
|
||||
"""会话提示响应:返回缺失维度、下一步问题和轻量训练提示。"""
|
||||
|
||||
hints: list[str]
|
||||
missing_dimensions: list[str]
|
||||
next_questions: list[str]
|
||||
recommended_orders: list[dict] = Field(default_factory=list)
|
||||
Reference in New Issue
Block a user