refactor(ai): 砍掉 /aiops 整页,模型配置迁入系统设置,浮窗助手保留
评估结论落地:整页分析只喂聚合统计(模型看不到日志原文),结论价值低于 /analysis 图表自身;浮窗助手携带真实查询样本,价值成立。 - 删 /aiops 页面与路由(菜单去项);llmProviders 迁 lib 共用 - 模型配置重做为设置页「AI 模型接入」区:状态严谨映射——供应商/模型按已存 baseUrl/model 正确回显(自定义供应商显示 BaseURL 与自定义模型输入,不再重置), API Key 掩码占位、留空或掩码保存均沿用旧值(不回传掩码) - 后端删 /ai/analyze 与信号采集链路;/ai/chat 保留(上下文由前端日志样本注入)
This commit is contained in:
1 parent
c216bdfdd4
commit
fbbd3a3c27
14 files changed
+203
-919
No files matched your search
@@ -1,9 +1,7 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"lokistack/models"
|
||||
"lokistack/services"
|
||||
@@ -81,56 +79,6 @@ func containsMask(s string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// Analyze 执行一次日志分析。
|
||||
//
|
||||
// 时间范围在服务端收敛:最大 24 小时。理由不是性能(P0 全走索引,很快),
|
||||
// 而是"范围越大,信号越笼统,结论越没用",且 token 会线性增长。
|
||||
func (ctrl *AIController) Analyze(c *gin.Context) {
|
||||
var req struct {
|
||||
SourceID uint `json:"sourceId" binding:"required"`
|
||||
Start int64 `json:"start" binding:"required"`
|
||||
End int64 `json:"end" binding:"required"`
|
||||
Question string `json:"question"`
|
||||
App string `json:"app"`
|
||||
}
|
||||
if !utils.BindAndValidate(c, &req) {
|
||||
return
|
||||
}
|
||||
src := services.GetLogSource(req.SourceID)
|
||||
if src == nil {
|
||||
utils.BadRequest(c, "数据源不存在")
|
||||
return
|
||||
}
|
||||
from := time.Unix(0, req.Start)
|
||||
to := time.Unix(0, req.End)
|
||||
if !to.After(from) {
|
||||
utils.BadRequest(c, "时间范围无效:结束时间必须晚于开始时间")
|
||||
return
|
||||
}
|
||||
if to.Sub(from) > 24*time.Hour {
|
||||
utils.BadRequest(c, fmt.Sprintf("时间范围过大(%d 分钟):AI 分析最多支持 24 小时,建议用 15~60 分钟", int(to.Sub(from).Minutes())))
|
||||
return
|
||||
}
|
||||
// 长窗口必须指定应用:全命名空间聚合在 6h/24h 下数据量过大,查询会拖垮 Loki
|
||||
if to.Sub(from) > time.Hour && req.App == "" {
|
||||
utils.BadRequest(c, "超过 1 小时的分析必须指定应用(app):全命名空间长窗口聚合过慢,请先在应用排行里选一个 app 缩小范围")
|
||||
return
|
||||
}
|
||||
|
||||
userID := c.GetUint("userId")
|
||||
username := c.GetString("username")
|
||||
admin := c.GetString("role") == "admin"
|
||||
|
||||
cfg := services.GetAIConfig()
|
||||
outcome, err := services.RunAIAnalysis(c.Request.Context(), cfg, src, userID, username, admin, from, to, req.Question, req.App)
|
||||
if err != nil {
|
||||
// 未配置模型 / 配额用尽 / 上游报错:都给出具体原因,不包装成 500
|
||||
utils.Error(c, 400, err.Error())
|
||||
return
|
||||
}
|
||||
utils.Success(c, outcome)
|
||||
}
|
||||
|
||||
// ListRuns 审计历史(分页)。
|
||||
func (ctrl *AIController) ListRuns(c *gin.Context) {
|
||||
page, _ := strconv.Atoi(c.DefaultQuery("page", "1"))
|
||||
@@ -157,25 +105,15 @@ func (ctrl *AIController) GetRun(c *gin.Context) {
|
||||
// Chat 全站 AI 助手浮窗(多轮对话 + 页面上下文注入;Pro 闸门)
|
||||
func (ctrl *AIController) Chat(c *gin.Context) {
|
||||
var req struct {
|
||||
SourceID uint `json:"sourceId"`
|
||||
History []services.ChatMessage `json:"history" binding:"required,min=1,max=40"`
|
||||
Page string `json:"page"`
|
||||
RangeMinutes int `json:"rangeMinutes"`
|
||||
Context string `json:"context"`
|
||||
History []services.ChatMessage `json:"history" binding:"required,min=1,max=40"`
|
||||
Page string `json:"page"`
|
||||
Context string `json:"context"`
|
||||
}
|
||||
if !utils.BindAndValidate(c, &req) {
|
||||
return
|
||||
}
|
||||
cfg := services.GetAIConfig()
|
||||
var src *models.LogSource
|
||||
if req.SourceID > 0 {
|
||||
src = services.GetLogSource(req.SourceID)
|
||||
}
|
||||
rangeMinutes := req.RangeMinutes
|
||||
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, req.Context)
|
||||
reply, err := services.RunAIChat(c.Request.Context(), cfg, c.GetUint("userId"), req.History, req.Page, req.Context)
|
||||
if err != nil {
|
||||
utils.Error(c, 400, err.Error())
|
||||
return
|
||||
|
||||
Reference in new issue
Block a user