feat(ai): 助手浮窗聚焦日志查询页,携带当前查询结果对话
CI / Backend (go vet + test) (push) Waiting to run
CI / Frontend (lint + build + test) (push) Waiting to run

- 浮球只在 /logs 渲染(产品定位:辅助分析正在查看的查询结果,其它页面不打扰)
- /logs 查询成功后写入 AI 上下文:LogQL、时间范围、结果条数、error 行数、
  最新 20 条样本(去 CRI 包装);对话请求自动携带
- 后端 /ai/chat 接收 context:截断 6000 字 + RedactTextOnly 统一脱敏后并入 system
  (ECHO 假模型实测注入完整);空态文案改为查询导向
This commit is contained in:
opsx committed 2026-11-01 00:31:48 +08:00
1 parent 2efbed882a
commit c216bdfdd4
8 files changed
+59 -6

No files matched your search

+2 -1
View File
@@ -161,6 +161,7 @@ func (ctrl *AIController) Chat(c *gin.Context) {
History []services.ChatMessage `json:"history" binding:"required,min=1,max=40"`
Page string `json:"page"`
RangeMinutes int `json:"rangeMinutes"`
Context string `json:"context"`
}
if !utils.BindAndValidate(c, &req) {
return
@@ -174,7 +175,7 @@ func (ctrl *AIController) Chat(c *gin.Context) {
if rangeMinutes <= 0 || rangeMinutes > 120 {
rangeMinutes = 15
}
reply, err := services.RunAIChat(c.Request.Context(), cfg, src, c.GetUint("userId"), c.GetString("role") == "admin", req.History, req.Page, rangeMinutes)
reply, err := services.RunAIChat(c.Request.Context(), cfg, src, c.GetUint("userId"), c.GetString("role") == "admin", req.History, req.Page, rangeMinutes, req.Context)
if err != nil {
utils.Error(c, 400, err.Error())
return
+8 -1
View File
@@ -155,7 +155,7 @@ type ChatMessage struct {
// RunAIChat 全站 AI 助手浮窗:多轮对话 + 当前页面上下文注入(轻量信号摘要)。
// 与整页分析共享配置/配额/脱敏/Pro 闸门;context 里的 sourceId 可选,带了就注入日志摘要。
func RunAIChat(ctx context.Context, cfg models.AIConfig, src *models.LogSource, userID uint, admin bool, history []ChatMessage, page string, rangeMinutes int) (string, error) {
func RunAIChat(ctx context.Context, cfg models.AIConfig, src *models.LogSource, userID uint, admin bool, history []ChatMessage, page string, rangeMinutes int, pageContext string) (string, error) {
if !cfg.Enabled {
return "", fmt.Errorf("AI 未启用:请先在「智能运维 → 模型配置」中开启并保存")
}
@@ -191,6 +191,13 @@ func RunAIChat(ctx context.Context, cfg models.AIConfig, src *models.LogSource,
}
}
// 页面上下文(如 /logs 刚执行的查询与样本日志):截断并统一脱敏后并入 system
if trimmed := strings.TrimSpace(pageContext); trimmed != "" {
if len([]rune(trimmed)) > 6000 {
trimmed = string([]rune(trimmed)[:6000])
}
system += "\n\n" + RedactTextOnly(trimmed, cfg.RedactExtra)
}
msgs := []aiMessage{{Role: "system", Content: system}}
for _, m := range history {
msgs = append(msgs, aiMessage{Role: m.Role, Content: m.Content})