feat: 增强FAQ搜索功能,支持指定搜索字段(标准问题/相似问法/答案)
This commit is contained in:
@@ -139,7 +139,7 @@ func (t *GetDocumentInfoTool) Execute(ctx context.Context, args map[string]inter
|
||||
ListPagedChunksByKnowledgeID(ctx, t.tenantID, id, &types.Pagination{
|
||||
Page: 1,
|
||||
PageSize: 1000,
|
||||
}, []types.ChunkType{"text"}, "", "", "")
|
||||
}, []types.ChunkType{"text"}, "", "", "", "")
|
||||
if err != nil {
|
||||
mu.Lock()
|
||||
results[id] = &docInfo{
|
||||
|
||||
@@ -1052,7 +1052,7 @@ func (t *KnowledgeSearchTool) formatOutput(
|
||||
_, total, err := t.chunkService.GetRepository().ListPagedChunksByKnowledgeID(ctx,
|
||||
t.tenantID, result.KnowledgeID,
|
||||
&types.Pagination{Page: 1, PageSize: 1},
|
||||
[]types.ChunkType{types.ChunkTypeText}, "", "", "",
|
||||
[]types.ChunkType{types.ChunkTypeText}, "", "", "", "",
|
||||
)
|
||||
if err != nil {
|
||||
logger.Warnf(
|
||||
|
||||
@@ -117,7 +117,7 @@ func (t *ListKnowledgeChunksTool) Execute(ctx context.Context, args map[string]i
|
||||
}
|
||||
|
||||
chunks, total, err := t.chunkService.GetRepository().ListPagedChunksByKnowledgeID(ctx,
|
||||
t.tenantID, knowledgeID, pagination, []types.ChunkType{types.ChunkTypeText, types.ChunkTypeFAQ}, "", "", "")
|
||||
t.tenantID, knowledgeID, pagination, []types.ChunkType{types.ChunkTypeText, types.ChunkTypeFAQ}, "", "", "", "")
|
||||
if err != nil {
|
||||
return &types.ToolResult{
|
||||
Success: false,
|
||||
|
||||
@@ -80,6 +80,7 @@ func (r *chunkRepository) ListPagedChunksByKnowledgeID(
|
||||
chunkType []types.ChunkType,
|
||||
tagID string,
|
||||
keyword string,
|
||||
searchField string,
|
||||
sortOrder string,
|
||||
) ([]*types.Chunk, int64, error) {
|
||||
var chunks []*types.Chunk
|
||||
@@ -97,7 +98,20 @@ func (r *chunkRepository) ListPagedChunksByKnowledgeID(
|
||||
}
|
||||
if keyword != "" {
|
||||
like := "%" + keyword + "%"
|
||||
db = db.Where("(content LIKE ? OR metadata::text LIKE ?)", like, like)
|
||||
switch searchField {
|
||||
case "standard_question":
|
||||
// Search only in standard_question field of metadata
|
||||
db = db.Where("metadata->>'standard_question' ILIKE ?", like)
|
||||
case "similar_questions":
|
||||
// Search in similar_questions array of metadata
|
||||
db = db.Where("metadata->'similar_questions'::text ILIKE ?", like)
|
||||
case "answers":
|
||||
// Search in answers array of metadata
|
||||
db = db.Where("metadata->'answers'::text ILIKE ?", like)
|
||||
default:
|
||||
// Search in all fields (content and metadata)
|
||||
db = db.Where("(content ILIKE ? OR metadata::text ILIKE ?)", like, like)
|
||||
}
|
||||
}
|
||||
return db
|
||||
}
|
||||
|
||||
@@ -337,7 +337,7 @@ func (s *agentService) getKnowledgeBaseInfos(ctx context.Context, kbIDs []string
|
||||
pageResult, err := s.knowledgeService.ListFAQEntries(ctx, kbID, &types.Pagination{
|
||||
Page: 1,
|
||||
PageSize: 10,
|
||||
}, "", "", "")
|
||||
}, "", "", "", "")
|
||||
if err == nil && pageResult != nil {
|
||||
docCount = int(pageResult.Total)
|
||||
if entries, ok := pageResult.Data.([]*types.FAQEntry); ok {
|
||||
|
||||
@@ -152,6 +152,7 @@ func (s *chunkService) ListPagedChunksByKnowledgeID(ctx context.Context,
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
)
|
||||
if err != nil {
|
||||
logger.ErrorWithFields(ctx, err, map[string]interface{}{
|
||||
|
||||
@@ -2549,6 +2549,7 @@ func (s *knowledgeService) CloneChunk(ctx context.Context, src, dst *types.Knowl
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
)
|
||||
chunkPage++
|
||||
if err != nil {
|
||||
@@ -2643,7 +2644,7 @@ func (s *knowledgeService) CloneChunk(ctx context.Context, src, dst *types.Knowl
|
||||
|
||||
// ListFAQEntries lists FAQ entries under a FAQ knowledge base.
|
||||
func (s *knowledgeService) ListFAQEntries(ctx context.Context,
|
||||
kbID string, page *types.Pagination, tagID string, keyword string, sortOrder string,
|
||||
kbID string, page *types.Pagination, tagID string, keyword string, searchField string, sortOrder string,
|
||||
) (*types.PageResult, error) {
|
||||
if page == nil {
|
||||
page = &types.Pagination{}
|
||||
@@ -2663,7 +2664,7 @@ func (s *knowledgeService) ListFAQEntries(ctx context.Context,
|
||||
}
|
||||
chunkType := []types.ChunkType{types.ChunkTypeFAQ}
|
||||
chunks, total, err := s.chunkRepo.ListPagedChunksByKnowledgeID(
|
||||
ctx, tenantID, faqKnowledge.ID, page, chunkType, tagID, keyword, sortOrder,
|
||||
ctx, tenantID, faqKnowledge.ID, page, chunkType, tagID, keyword, searchField, sortOrder,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -28,12 +28,13 @@ func NewFAQHandler(knowledgeService interfaces.KnowledgeService) *FAQHandler {
|
||||
// @Tags FAQ管理
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param id path string true "知识库ID"
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "每页数量"
|
||||
// @Param tag_id query string false "标签ID筛选"
|
||||
// @Param keyword query string false "关键词搜索"
|
||||
// @Param sort_order query string false "排序方式: asc(按更新时间正序), 默认按更新时间倒序"
|
||||
// @Param id path string true "知识库ID"
|
||||
// @Param page query int false "页码"
|
||||
// @Param page_size query int false "每页数量"
|
||||
// @Param tag_id query string false "标签ID筛选"
|
||||
// @Param keyword query string false "关键词搜索"
|
||||
// @Param search_field query string false "搜索字段: standard_question(标准问题), similar_questions(相似问法), answers(答案), 默认搜索全部"
|
||||
// @Param sort_order query string false "排序方式: asc(按更新时间正序), 默认按更新时间倒序"
|
||||
// @Success 200 {object} map[string]interface{} "FAQ列表"
|
||||
// @Failure 400 {object} errors.AppError "请求参数错误"
|
||||
// @Security Bearer
|
||||
@@ -50,9 +51,10 @@ func (h *FAQHandler) ListEntries(c *gin.Context) {
|
||||
|
||||
tagID := secutils.SanitizeForLog(c.Query("tag_id"))
|
||||
keyword := secutils.SanitizeForLog(c.Query("keyword"))
|
||||
searchField := secutils.SanitizeForLog(c.Query("search_field"))
|
||||
sortOrder := secutils.SanitizeForLog(c.Query("sort_order"))
|
||||
|
||||
result, err := h.knowledgeService.ListFAQEntries(ctx, secutils.SanitizeForLog(c.Param("id")), &page, tagID, keyword, sortOrder)
|
||||
result, err := h.knowledgeService.ListFAQEntries(ctx, secutils.SanitizeForLog(c.Param("id")), &page, tagID, keyword, searchField, sortOrder)
|
||||
if err != nil {
|
||||
logger.ErrorWithFields(ctx, err, nil)
|
||||
c.Error(err)
|
||||
|
||||
@@ -19,6 +19,7 @@ type ChunkRepository interface {
|
||||
// ListPagedChunksByKnowledgeID lists paged chunks by knowledge id.
|
||||
// When tagID is non-empty, results are filtered by tag_id.
|
||||
// sortOrder: "asc" for time ascending (updated_at ASC), default is time descending (updated_at DESC)
|
||||
// searchField: specifies which field to search in (for FAQ: "standard_question", "similar_questions", "answers", "" for all)
|
||||
ListPagedChunksByKnowledgeID(
|
||||
ctx context.Context,
|
||||
tenantID uint64,
|
||||
@@ -27,6 +28,7 @@ type ChunkRepository interface {
|
||||
chunkType []types.ChunkType,
|
||||
tagID string,
|
||||
keyword string,
|
||||
searchField string,
|
||||
sortOrder string,
|
||||
) ([]*types.Chunk, int64, error)
|
||||
ListChunkByParentID(ctx context.Context, tenantID uint64, parentID string) ([]*types.Chunk, error)
|
||||
|
||||
@@ -74,6 +74,7 @@ type KnowledgeService interface {
|
||||
UpdateImageInfo(ctx context.Context, knowledgeID string, chunkID string, imageInfo string) error
|
||||
// ListFAQEntries lists FAQ entries under a FAQ knowledge base.
|
||||
// When tagID is non-empty, results are filtered by tag_id on FAQ chunks.
|
||||
// searchField: specifies which field to search in ("standard_question", "similar_questions", "answers", "" for all)
|
||||
// sortOrder: "asc" for time ascending (updated_at ASC), default is time descending (updated_at DESC)
|
||||
ListFAQEntries(
|
||||
ctx context.Context,
|
||||
@@ -81,6 +82,7 @@ type KnowledgeService interface {
|
||||
page *types.Pagination,
|
||||
tagID string,
|
||||
keyword string,
|
||||
searchField string,
|
||||
sortOrder string,
|
||||
) (*types.PageResult, error)
|
||||
// UpsertFAQEntries imports or appends FAQ entries asynchronously.
|
||||
|
||||
Reference in New Issue
Block a user