feat: 百科知识库存入向量

This commit is contained in:
Blizzard
2026-04-21 17:32:26 +08:00
parent ae0020aa71
commit b2e6e511cd
21 changed files with 802 additions and 35 deletions
+65
View File
@@ -0,0 +1,65 @@
package plant
import (
"sundynix-go/global"
"sundynix-go/model/commom/response"
"github.com/gin-gonic/gin"
"go.uber.org/zap"
)
type AiChatApi struct{}
// ChatStreamPlant 接收用户输入,基于植物百科 RAG 产生流式 SSE 回答
// @Summary 植物助手聊天(SSE 流式输出)
// @Tags Plant-AiChat
// @Param query query string true "用户提问内容"
// @Produce text/event-stream
// @Router /plant/chat/stream [get]
func (a *AiChatApi) ChatStreamPlant(c *gin.Context) {
query := c.Query("query")
if query == "" {
response.FailWithMsg("参数 query 不能为空", c)
return
}
// SSE Headers(微信小程序通过 enableChunked: true 配合实现打字机效果)
w := c.Writer
header := w.Header()
header.Set("Content-Type", "text/event-stream")
header.Set("Cache-Control", "no-cache")
header.Set("Connection", "keep-alive")
header.Set("Transfer-Encoding", "chunked")
w.WriteHeader(200)
err := aiRagService.PlantChatStreamRAG(c.Request.Context(), query, func(chunk string) error {
_, writeErr := w.WriteString("data: " + chunk + "\n\n")
w.Flush()
return writeErr
})
if err != nil {
global.Logger.Error("PlantChatStreamRAG error", zap.Error(err))
_, _ = w.WriteString("data: [ERROR]" + err.Error() + "\n\n")
w.Flush()
} else {
// 流结束标志
_, _ = w.WriteString("data: [DONE]\n\n")
w.Flush()
}
}
// SyncWikiToQdrant 手动触发全量植物百科同步到 Qdrant
// @Summary 同步植物百科数据到 Qdrant 向量库
// @Tags System-SysAiConfig
// @Produce json
// @Success 200 {object} response.Response
// @Router /plant/chat/sync [post]
func (a *AiChatApi) SyncWikiToQdrant(c *gin.Context) {
if err := aiRagService.SyncWikiToQdrant(); err != nil {
global.Logger.Error("SyncWikiToQdrant error", zap.Error(err))
response.FailWithMsg("同步失败: "+err.Error(), c)
return
}
response.OkWithMsg("同步成功", c)
}
+2
View File
@@ -14,6 +14,7 @@ type ApiGroup struct {
BadgeConfigApi
CallbackApi
ExchangeApi
AiChatApi
}
var (
@@ -28,4 +29,5 @@ var (
badgeConfigService = service.GroupApp.PlantServiceGroup.BadgeConfigService
callbackService = service.GroupApp.PlantServiceGroup.CallbackService
exchangeService = service.GroupApp.PlantServiceGroup.ExchangeService
aiRagService = service.GroupApp.PlantServiceGroup.AiRagService
)
+42
View File
@@ -139,6 +139,48 @@ func (a *WikiApi) DeleteWiki(c *gin.Context) {
response.OkWithMsg("删除成功", c)
}
// SyncWikiQdrant 单条百科同步到 Qdrant
// @Tags 百科
// @Summary 百科同步到Qdrant
// @Security BearerAuth
// @Produce application/json
// @Param data body common.GetById true "单条百科"
// @Router /wiki/sync-qdrant [post]
func (a *WikiApi) SyncWikiQdrant(c *gin.Context) {
var req common.GetById
if err := c.ShouldBindJSON(&req); err != nil {
response.FailWithMsg("请求参数错误", c)
return
}
if err := aiRagService.SyncSingleWiki(req.ID); err != nil {
global.Logger.Error("同步 Qdrant 失败", zap.Error(err))
response.FailWithMsg("同步失败: "+err.Error(), c)
return
}
response.OkWithMsg("同步成功", c)
}
// DeleteWikiQdrant 从 Qdrant 移除单条百科向量
// @Tags 百科
// @Summary 百科移除Qdrant
// @Security BearerAuth
// @Produce application/json
// @Param data body common.GetById true "单条百科"
// @Router /wiki/delete-qdrant [post]
func (a *WikiApi) DeleteWikiQdrant(c *gin.Context) {
var req common.GetById
if err := c.ShouldBindJSON(&req); err != nil {
response.FailWithMsg("请求参数错误", c)
return
}
if err := aiRagService.DeleteFromQdrant(req.ID); err != nil {
global.Logger.Error("从 Qdrant 删除向量失败", zap.Error(err))
response.FailWithMsg("移除失败: "+err.Error(), c)
return
}
response.OkWithMsg("移除成功", c)
}
// StarWiki 收藏百科
// @Tags 百科
// @Summary 收藏百科
+2
View File
@@ -10,6 +10,7 @@ type ApiGroup struct {
MenuApi
OperationRecordApi
OssApi
SysAiConfigApi
}
var (
@@ -20,4 +21,5 @@ var (
menuService = service.GroupApp.SystemServiceGroup.MenuService
operationRecordService = service.GroupApp.SystemServiceGroup.OperationRecordService
ossService = service.GroupApp.SystemServiceGroup.OssService
sysAiConfigService = service.GroupApp.SystemServiceGroup.SysAiConfigService
)
+98
View File
@@ -0,0 +1,98 @@
package system
import (
"github.com/gin-gonic/gin"
"go.uber.org/zap"
"sundynix-go/global"
"sundynix-go/model/commom/response"
"sundynix-go/model/system"
)
type SysAiConfigApi struct{}
// CreateAiConfig 创建 AI 配置
// @Summary 创建 AI 配置
// @Tags System-SysAiConfig
// @accept json
// @Produce json
// @Param data body system.SysAiConfig true "配置模型"
// @Success 200 {object} response.Response
// @Router /aiConfig/create [post]
func (a *SysAiConfigApi) CreateAiConfig(c *gin.Context) {
var cfg system.SysAiConfig
if err := c.ShouldBindJSON(&cfg); err != nil {
response.FailWithMsg("参数错误:"+err.Error(), c)
return
}
if err := sysAiConfigService.Create(&cfg); err != nil {
global.Logger.Error("创建AI配置失败", zap.Error(err))
response.FailWithMsg("创建失败:"+err.Error(), c)
return
}
response.OkWithMsg("创建成功", c)
}
// UpdateAiConfig 更新 AI 配置
// @Summary 更新 AI 配置
// @Tags System-SysAiConfig
// @accept json
// @Produce json
// @Param data body system.SysAiConfig true "配置模型"
// @Success 200 {object} response.Response
// @Router /aiConfig/update [put]
func (a *SysAiConfigApi) UpdateAiConfig(c *gin.Context) {
var cfg system.SysAiConfig
if err := c.ShouldBindJSON(&cfg); err != nil {
response.FailWithMsg("参数错误:"+err.Error(), c)
return
}
if err := sysAiConfigService.Update(&cfg); err != nil {
global.Logger.Error("更新AI配置失败", zap.Error(err))
response.FailWithMsg("更新失败:"+err.Error(), c)
return
}
response.OkWithMsg("更新成功", c)
}
// SetActive 设置激活配置
// @Summary 设置激活配置(同一时间只有一条激活)
// @Tags System-SysAiConfig
// @accept json
// @Produce json
// @Param data body object true "{ \"id\": \"xxx\" }"
// @Success 200 {object} response.Response
// @Router /aiConfig/setActive [post]
func (a *SysAiConfigApi) SetActive(c *gin.Context) {
var body struct {
Id string `json:"id" binding:"required"`
}
if err := c.ShouldBindJSON(&body); err != nil {
response.FailWithMsg("参数错误:"+err.Error(), c)
return
}
if err := sysAiConfigService.SetActive(body.Id); err != nil {
global.Logger.Error("设置激活AI配置失败", zap.Error(err))
response.FailWithMsg("设置失败:"+err.Error(), c)
return
}
response.OkWithMsg("设置成功", c)
}
// GetList 获取配置列表
// @Summary 获取 AI 配置列表
// @Tags System-SysAiConfig
// @Produce json
// @Success 200 {object} response.Response
// @Router /aiConfig/list [get]
func (a *SysAiConfigApi) GetList(c *gin.Context) {
list, err := sysAiConfigService.GetList()
if err != nil {
global.Logger.Error("获取AI配置列表失败", zap.Error(err))
response.FailWithMsg("获取失败:"+err.Error(), c)
return
}
response.OkWithData(response.PageResult{
List: list,
Total: int64(len(list)),
}, c)
}