Files
xly/server/internal/handler/http.go

91 lines
2.2 KiB
Go

package handler
import (
"errors"
"net/http"
"strings"
"github.com/gin-gonic/gin"
"xly/server/internal/model"
"xly/server/internal/service"
)
// HTTPHandler 负责注册 HTTP 路由。
// 控制层只做参数校验和响应包装,不承担上游调用逻辑。
type HTTPHandler struct {
ai *service.AIService
}
// NewHTTPHandler 创建 HTTP 控制器。
func NewHTTPHandler(ai *service.AIService) *HTTPHandler {
return &HTTPHandler{ai: ai}
}
// Register 将接口注册到 Gin 路由树。
func (h *HTTPHandler) Register(router gin.IRouter) {
router.GET("/healthz", h.healthz)
router.GET("/api/v1/ai/status", h.aiStatus)
router.POST("/api/v1/ai/interpret", h.aiInterpret)
}
func (h *HTTPHandler) healthz(ctx *gin.Context) {
ctx.JSON(http.StatusOK, model.APIResponse[map[string]string]{
Data: &map[string]string{
"status": "ok",
},
Message: "service is healthy",
})
}
func (h *HTTPHandler) aiStatus(ctx *gin.Context) {
status := h.ai.Status()
ctx.JSON(http.StatusOK, model.APIResponse[model.AIStatusResponse]{
Data: &status,
Message: "ok",
})
}
func (h *HTTPHandler) aiInterpret(ctx *gin.Context) {
var request model.InterpretRequest
if err := ctx.ShouldBindJSON(&request); err != nil {
ctx.JSON(http.StatusBadRequest, model.APIResponse[model.InterpretResponse]{
Message: "请求体无效,请检查解卦上下文是否完整。",
})
return
}
request.Question = strings.TrimSpace(request.Question)
if request.Question == "" {
ctx.JSON(http.StatusBadRequest, model.APIResponse[model.InterpretResponse]{
Message: "所问之事不能为空。",
})
return
}
content, err := h.ai.Interpret(ctx.Request.Context(), request)
if err != nil {
statusCode := http.StatusBadGateway
message := "AI 解卦失败。"
switch {
case errors.Is(err, service.ErrAIUnavailable):
statusCode = http.StatusServiceUnavailable
message = "后端 AI 服务尚未完成配置。"
default:
message = err.Error()
}
ctx.JSON(statusCode, model.APIResponse[model.InterpretResponse]{
Message: message,
})
return
}
response := model.InterpretResponse{Content: content}
ctx.JSON(http.StatusOK, model.APIResponse[model.InterpretResponse]{
Data: &response,
Message: "ok",
})
}