初始化
This commit is contained in:
211
internal/handler/emr_handler.go
Normal file
211
internal/handler/emr_handler.go
Normal file
@@ -0,0 +1,211 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"tcm-agent/internal/agent"
|
||||
"tcm-agent/internal/model/entity"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// ========================================================================
|
||||
// 病历 HTTP 接口处理器
|
||||
// ========================================================================
|
||||
// 职责链:
|
||||
// HTTP 请求 → 参数校验 → 调用 Agent → 持久化 → 响应封装
|
||||
// ========================================================================
|
||||
|
||||
// EMRHandler 病历接口处理器
|
||||
type EMRHandler struct {
|
||||
agentRunner *agent.Runner
|
||||
emrAgent *agent.EMRGenerator
|
||||
}
|
||||
|
||||
// NewEMRHandler 创建病历处理器
|
||||
//
|
||||
// 参数:
|
||||
//
|
||||
// runner - Agent 引擎
|
||||
// scene - 场景名(对应 config.yaml 中 routes 的 key)
|
||||
// 为空则使用默认值 "emr-generator"
|
||||
func NewEMRHandler(runner *agent.Runner, scene string) *EMRHandler {
|
||||
return &EMRHandler{
|
||||
agentRunner: runner,
|
||||
emrAgent: agent.NewEMRGenerator(runner, scene),
|
||||
}
|
||||
}
|
||||
|
||||
// GenerateRequest 生成病历请求体
|
||||
type GenerateRequest struct {
|
||||
PatientID string `json:"patient_id" binding:"required"`
|
||||
ChiefComplaint string `json:"chief_complaint" binding:"required"`
|
||||
HistoryNotes string `json:"history_notes"`
|
||||
Allergies []string `json:"allergies"`
|
||||
PastIllness []string `json:"past_illness"`
|
||||
}
|
||||
|
||||
// Generate 根据主诉+病史生成病历
|
||||
//
|
||||
// POST /api/v1/emr/generate
|
||||
//
|
||||
// 完整生命周期:
|
||||
// 1. 参数校验
|
||||
// 2. Agent 感知 → 规划 → 检索 → 工具 → 反思 → 输出
|
||||
// 3. 规则引擎质控
|
||||
// 4. 持久化到数据库
|
||||
// 5. 返回结构化响应
|
||||
func (h *EMRHandler) Generate(c *gin.Context) {
|
||||
// ===== ① 参数校验 =====
|
||||
var req GenerateRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": "参数错误",
|
||||
"detail": err.Error(),
|
||||
"example": `{"patient_id":"P001","chief_complaint":"反复头晕3个月","history_notes":"...","allergies":[],"past_illness":[]}`,
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
doctorID := c.GetString("user_id")
|
||||
|
||||
// ===== ②~⑤ 调用 Agent =====
|
||||
agentReq := &agent.EMRRequest{
|
||||
PatientID: req.PatientID,
|
||||
ChiefComplaint: req.ChiefComplaint,
|
||||
HistoryNotes: req.HistoryNotes,
|
||||
Allergies: req.Allergies,
|
||||
PastIllness: req.PastIllness,
|
||||
}
|
||||
|
||||
resp, err := h.emrAgent.Generate(c.Request.Context(), agentReq)
|
||||
if err != nil {
|
||||
c.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": "病历生成失败",
|
||||
"detail": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// ===== ⑥ 持久化 =====
|
||||
emr := &entity.EMR{
|
||||
PatientID: req.PatientID,
|
||||
DoctorID: doctorID,
|
||||
Draft: resp.Draft,
|
||||
Structured: resp.Structured,
|
||||
Status: resp.Status,
|
||||
SessionID: resp.SessionID,
|
||||
CreatedAt: time.Now(),
|
||||
UpdatedAt: time.Now(),
|
||||
}
|
||||
// dao.EMR.Create(emr) // 实际项目取消注释
|
||||
|
||||
// ===== ⑦ 返回响应 =====
|
||||
c.JSON(http.StatusOK, gin.H{
|
||||
"code": 200,
|
||||
"message": "病历生成成功",
|
||||
"data": gin.H{
|
||||
"session_id": resp.SessionID,
|
||||
"draft": resp.Draft,
|
||||
"structured": resp.Structured,
|
||||
"issues": resp.Issues,
|
||||
"status": resp.Status,
|
||||
"emr_id": emr.ID,
|
||||
"next_action": getNextAction(resp.Status),
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// KnowledgeQA 病历书写规范问答
|
||||
//
|
||||
// POST /api/v1/emr/qa
|
||||
func (h *EMRHandler) KnowledgeQA(c *gin.Context) {
|
||||
var req struct {
|
||||
Question string `json:"question" binding:"required"`
|
||||
}
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
c.JSON(400, gin.H{"error": "问题不能为空"})
|
||||
return
|
||||
}
|
||||
|
||||
answer, err := h.agentRunner.MaxKB().Chat(c.Request.Context(), req.Question)
|
||||
if err != nil {
|
||||
c.JSON(500, gin.H{"error": "知识库查询失败", "detail": err.Error()})
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"data": gin.H{
|
||||
"question": req.Question,
|
||||
"answer": answer,
|
||||
"source": "MaxKB 知识库",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// GetByID 查询病历详情
|
||||
//
|
||||
// GET /api/v1/emr/:id
|
||||
func (h *EMRHandler) GetByID(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"data": gin.H{
|
||||
"id": id,
|
||||
"note": "实际项目从数据库查询",
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// Update 更新病历(医生人工修改后保存)
|
||||
//
|
||||
// PUT /api/v1/emr/:id
|
||||
func (h *EMRHandler) Update(c *gin.Context) {
|
||||
idStr := c.Param("id")
|
||||
id, _ := strconv.ParseInt(idStr, 10, 64)
|
||||
|
||||
var req struct {
|
||||
Draft string `json:"draft"`
|
||||
IsFinal bool `json:"is_final"`
|
||||
}
|
||||
c.ShouldBindJSON(&req)
|
||||
|
||||
userID := c.GetString("user_id")
|
||||
logAudit("emr_update", userID, idStr, req.Draft)
|
||||
|
||||
c.JSON(200, gin.H{
|
||||
"code": 200,
|
||||
"message": "病历已更新",
|
||||
"data": gin.H{
|
||||
"id": id,
|
||||
"is_final": req.IsFinal,
|
||||
"updated_by": userID,
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
// getNextAction 根据状态给出下一步建议
|
||||
func getNextAction(status string) string {
|
||||
switch status {
|
||||
case "success":
|
||||
return "病历生成完成,请医生审核确认"
|
||||
case "need_revision":
|
||||
return "病历存在质控问题,请查看 issues 列表并修改"
|
||||
default:
|
||||
return "请检查输入信息是否完整"
|
||||
}
|
||||
}
|
||||
|
||||
// logAudit 审计日志
|
||||
func logAudit(action, userID, targetID, detail string) {
|
||||
// 实际项目:写入审计表
|
||||
_ = action
|
||||
_ = userID
|
||||
_ = targetID
|
||||
_ = detail
|
||||
}
|
||||
Reference in New Issue
Block a user