This repository has been archived on 2026-08-12. You can view files and clone it. You cannot open issues or pull requests or push a commit.
Files
Cyrene/backend/gateway/internal/handler/memory_handler.go
T
AskaEth 186513f381 feat: 多功能升级 — 流式逐字渲染、对话缓存、会话组织优化、记忆管理修复、性能仪表盘
- 前端消息流式逐字渲染 (AI-Core ChatStream → SSE → Gateway → WebSocket stream_chunk → fadeInUp + cursorBlink)
- 后端对话缓存 (conversationCache sync.Map, GET /sessions/:id/messages)
- 前端侧边栏历史多轮对话显示
- DevTools 性能监控图标移至首页仪表盘
- DevTools 用户记忆查询/删减功能修复 (补全 DELETE 数据链路)
- 后端和 DevTools 按用户分类组织实时活动会话 (map[userID]map[sessionID]*Client)
- 新增 docs/api-reference/ 路由参考文档
- 新增 docs/message-flow-architecture.md 消息链路架构文档
2026-05-16 17:44:03 +08:00

160 lines
3.8 KiB
Go

package handler
import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
"github.com/gin-gonic/gin"
"github.com/yourname/cyrene-ai/gateway/internal/middleware"
)
// MemoryHandler 记忆查询处理器 — 代理到 AI-Core
type MemoryHandler struct {
aiCoreURL string
client *http.Client
}
// NewMemoryHandler 创建记忆处理器
func NewMemoryHandler(aiCoreURL string) *MemoryHandler {
return &MemoryHandler{
aiCoreURL: aiCoreURL,
client: &http.Client{
Timeout: 15 * time.Second,
},
}
}
// Query 搜索用户记忆 — 代理 GET /api/v1/memory/search?user_id=...&q=...
func (h *MemoryHandler) Query(c *gin.Context) {
userID := middleware.GetUserID(c)
query := c.Query("q")
if query == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "查询参数q不能为空"})
return
}
url := fmt.Sprintf("%s/api/v1/memory/search?user_id=%s&q=%s",
h.aiCoreURL, userID, query)
resp, err := h.client.Get(url)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result interface{}
json.Unmarshal(body, &result)
c.JSON(resp.StatusCode, result)
}
// List 列出用户所有记忆 — 代理 GET /api/v1/memory?user_id=...
func (h *MemoryHandler) List(c *gin.Context) {
userID := middleware.GetUserID(c)
url := fmt.Sprintf("%s/api/v1/memory?user_id=%s", h.aiCoreURL, userID)
resp, err := h.client.Get(url)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result interface{}
json.Unmarshal(body, &result)
c.JSON(resp.StatusCode, result)
}
// Add 手动添加记忆 — 代理 POST /api/v1/memory
func (h *MemoryHandler) Add(c *gin.Context) {
userID := middleware.GetUserID(c)
var req struct {
Content string `json:"content" binding:"required"`
Category string `json:"category"`
Priority int `json:"priority"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": "请求参数无效"})
return
}
if req.Category == "" {
req.Category = "other"
}
if req.Priority <= 0 {
req.Priority = 1
}
// 转发到 AI-Core
aiReq := map[string]interface{}{
"user_id": userID,
"content": req.Content,
"category": req.Category,
"priority": req.Priority,
}
reqBody, _ := json.Marshal(aiReq)
url := fmt.Sprintf("%s/api/v1/memory", h.aiCoreURL)
httpReq, err := http.NewRequest("POST", url, bytes.NewReader(reqBody))
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "构建请求失败"})
return
}
httpReq.Header.Set("Content-Type", "application/json")
resp, err := h.client.Do(httpReq)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result interface{}
json.Unmarshal(body, &result)
c.JSON(resp.StatusCode, result)
}
// Delete 删除单条记忆 — 代理 DELETE /api/v1/memory?id=...
func (h *MemoryHandler) Delete(c *gin.Context) {
memoryID := c.Query("id")
if memoryID == "" {
c.JSON(http.StatusBadRequest, gin.H{"error": "缺少 id 参数"})
return
}
url := fmt.Sprintf("%s/api/v1/memory?id=%s", h.aiCoreURL, memoryID)
req, err := http.NewRequest("DELETE", url, nil)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "构建请求失败"})
return
}
resp, err := h.client.Do(req)
if err != nil {
c.JSON(http.StatusBadGateway, gin.H{"error": fmt.Sprintf("AI-Core 不可达: %v", err)})
return
}
defer resp.Body.Close()
body, _ := io.ReadAll(resp.Body)
var result interface{}
json.Unmarshal(body, &result)
c.JSON(resp.StatusCode, result)
}