dev 分支暂存

This commit is contained in:
2026-05-16 08:26:56 +08:00
parent 58c8caa570
commit eb4129176c
71 changed files with 8474 additions and 214 deletions
@@ -0,0 +1,186 @@
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