package handler import ( "encoding/json" "log" "net/http" "time" "github.com/gin-gonic/gin" "github.com/gorilla/websocket" "github.com/yourname/cyrene-ai/gateway/internal/config" "github.com/yourname/cyrene-ai/gateway/internal/middleware" "github.com/yourname/cyrene-ai/gateway/internal/ws" ) // ChatHandler 聊天处理器 type ChatHandler struct { cfg *config.Config hub *ws.Hub upgrader websocket.Upgrader } // NewChatHandler 创建聊天处理器 func NewChatHandler(cfg *config.Config, hub *ws.Hub) *ChatHandler { return &ChatHandler{ cfg: cfg, hub: hub, upgrader: websocket.Upgrader{ ReadBufferSize: 1024, WriteBufferSize: 1024, CheckOrigin: func(r *http.Request) bool { return true // 开发阶段允许所有来源 }, }, } } // HandleWebSocket 处理WebSocket升级和消息路由 func (h *ChatHandler) HandleWebSocket(c *gin.Context) { // 从query参数获取token和session_id token := c.Query("token") sessionID := c.Query("session_id") if token == "" { // 也尝试从Authorization头读取 authHeader := c.GetHeader("Authorization") if len(authHeader) > 7 && authHeader[:7] == "Bearer " { token = authHeader[7:] } } if token == "" { c.JSON(http.StatusUnauthorized, gin.H{"error": "需要认证令牌"}) return } // 验证token userID, err := h.cfg.ValidateToken(token) if err != nil { c.JSON(http.StatusUnauthorized, gin.H{"error": "认证令牌无效"}) return } if sessionID == "" { sessionID = "session_" + generateID() } // 升级WebSocket连接 conn, err := h.upgrader.Upgrade(c.Writer, c.Request, nil) if err != nil { log.Printf("[WS] 升级连接失败: %v", err) return } // 创建客户端 client := ws.NewClient(h.hub, conn, userID, sessionID) // 注册到Hub h.hub.register <- client // 启动读写协程 go client.WritePump() go client.ReadPump(func(client *ws.Client, msg ws.ClientMessage) { h.handleMessage(client, msg) }) } // handleMessage 处理WebSocket消息 func (h *ChatHandler) handleMessage(client *ws.Client, msg ws.ClientMessage) { switch msg.Type { case "message": h.handleChatMessage(client, msg) case "voice_input": h.handleVoiceInput(client, msg) default: log.Printf("[WS] 未知消息类型: %s from user=%s", msg.Type, client.UserID) } } // handleChatMessage 处理文字聊天消息 func (h *ChatHandler) handleChatMessage(client *ws.Client, msg ws.ClientMessage) { mode := msg.Mode if mode == "" { mode = "text" } // MVP阶段:生成模拟回复(后续对接AI-Core) // 实际部署时,这里应转发消息到AI-Core并等待响应 response := ws.ServerMessage{ Type: "response", MessageID: "msg_" + generateID(), Text: h.generateMockResponse(msg.Content, mode), ResponseMode: mode, Timestamp: time.Now().UnixMilli(), } // 发送响应给客户端 if err := client.SendMessage(response); err != nil { log.Printf("[WS] 发送响应失败: %v", err) } } // handleVoiceInput 处理语音输入 func (h *ChatHandler) handleVoiceInput(client *ws.Client, msg ws.ClientMessage) { // MVP阶段:返回提示 response := ws.ServerMessage{ Type: "error", MessageID: "msg_" + generateID(), Error: "语音处理功能将在后续版本中启用", Timestamp: time.Now().UnixMilli(), } client.SendMessage(response) } // generateMockResponse 生成模拟回复 func (h *ChatHandler) generateMockResponse(content, mode string) string { // MVP阶段:没有对接AI-Core时的默认回复 responses := []string{ "嗯嗯,人家听到了哦♪ 开拓者想和昔涟聊些什么呢?", "嘻嘻,开拓者说的话真有趣呢♪ 让我想想怎么回答……", "啊,这个问题很有意思呢!虽然人家现在还在学习阶段,但我很乐意倾听开拓者说的每一句话哦♡", } // 简单hash选一条 hash := 0 for _, c := range content { hash += int(c) } return responses[hash%len(responses)] } // SendSystemMessage 向用户发送系统消息(用于主动通知) func (h *ChatHandler) SendSystemMessage(userID, sessionID, text string) error { msg := ws.ServerMessage{ Type: "response", MessageID: "sys_" + generateID(), Text: text, Timestamp: time.Now().UnixMilli(), } data, err := json.Marshal(msg) if err != nil { return err } h.hub.SendToSession(userID, sessionID, data) return nil } func generateID() string { return time.Now().Format("20060102150405") + randomStr(6) } func randomStr(n int) string { const letters = "abcdefghijklmnopqrstuvwxyz0123456789" b := make([]byte, n) for i := range b { b[i] = letters[time.Now().UnixNano()%int64(len(letters))] } return string(b) } // 确保未使用变量不报错 var _ = middleware.GetUserID