feat: Enhance Kol Generation Service with web search and knowledge group support
- Added `EnableWebSearch` and `KnowledgeGroupIDs` fields to `KolGenerationSubmitRequest`. - Updated `Submit` method in `KolGenerationService` to handle new request fields. - Integrated web search and knowledge group validation based on card configuration. - Introduced caching mechanisms in `KolPackageService`, `KolPromptService`, and `KolSubscriptionAdminService` to improve performance. - Implemented knowledge context resolution in `KolGenerationWorker` to enrich prompts with relevant knowledge snippets. - Added utility functions for handling card configuration in both backend and frontend. - Created tests for knowledge extraction and rendering to ensure accuracy and reliability.
This commit is contained in:
@@ -71,6 +71,7 @@ type ArticleListParams struct {
|
||||
SourceType *string
|
||||
GenerationMode *string
|
||||
TemplateID *int64
|
||||
KolPromptID *int64
|
||||
PromptRuleID *int64
|
||||
Keyword *string
|
||||
CreatedFrom *time.Time
|
||||
@@ -147,7 +148,7 @@ func (s *ArticleService) Detail(ctx context.Context, id int64) (*ArticleDetailRe
|
||||
}
|
||||
|
||||
func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, params ArticleListParams) (*ArticleListResponse, error) {
|
||||
sourceType := params.SourceType
|
||||
sourceTypes := normalizeArticleSourceTypes(params.SourceType)
|
||||
|
||||
if params.Page < 1 {
|
||||
params.Page = 1
|
||||
@@ -182,11 +183,7 @@ func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, param
|
||||
countArgs = append(countArgs, *params.PublishStatus)
|
||||
argIdx++
|
||||
}
|
||||
if sourceType != nil {
|
||||
countQuery += ` AND a.source_type = $` + strconv.Itoa(argIdx)
|
||||
countArgs = append(countArgs, *sourceType)
|
||||
argIdx++
|
||||
}
|
||||
countQuery, countArgs, argIdx = appendArticleSourceTypeFilter(countQuery, countArgs, argIdx, sourceTypes)
|
||||
if params.GenerationMode != nil {
|
||||
countQuery += ` AND a.source_type = 'custom_generation' AND COALESCE(NULLIF(gt.input_params_json ->> 'generation_mode', ''), 'instant') = $` + strconv.Itoa(argIdx)
|
||||
countArgs = append(countArgs, *params.GenerationMode)
|
||||
@@ -197,6 +194,11 @@ func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, param
|
||||
countArgs = append(countArgs, *params.TemplateID)
|
||||
argIdx++
|
||||
}
|
||||
if params.KolPromptID != nil {
|
||||
countQuery += ` AND a.kol_prompt_id = $` + strconv.Itoa(argIdx)
|
||||
countArgs = append(countArgs, *params.KolPromptID)
|
||||
argIdx++
|
||||
}
|
||||
if params.PromptRuleID != nil {
|
||||
countQuery += ` AND a.prompt_rule_id = $` + strconv.Itoa(argIdx)
|
||||
countArgs = append(countArgs, *params.PromptRuleID)
|
||||
@@ -223,7 +225,8 @@ func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, param
|
||||
}
|
||||
|
||||
listQuery := `SELECT a.id, a.source_type, a.template_id, a.kol_prompt_id, a.prompt_rule_id, a.generate_status, a.publish_status, a.created_at,
|
||||
COALESCE(av.title, NULLIF(a.wizard_state_json ->> 'title', ''), NULLIF(gt.input_params_json ->> 'title', '')), gt.error_message, COALESCE(av.word_count, 0), av.source_label, t.template_name, pr.name, a.wizard_state_json, gt.input_params_json
|
||||
COALESCE(av.title, NULLIF(a.wizard_state_json ->> 'title', ''), NULLIF(gt.input_params_json ->> 'title', '')), gt.error_message, COALESCE(av.word_count, 0), av.source_label,
|
||||
COALESCE(t.template_name, NULLIF(gt.input_params_json ->> 'prompt_name', ''), NULLIF(gt.input_params_json ->> 'package_name', '')), pr.name, a.wizard_state_json, gt.input_params_json
|
||||
FROM articles a
|
||||
LEFT JOIN article_versions av ON av.id = a.current_version_id
|
||||
LEFT JOIN article_templates t ON t.id = a.template_id
|
||||
@@ -249,11 +252,7 @@ func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, param
|
||||
listArgs = append(listArgs, *params.PublishStatus)
|
||||
listIdx++
|
||||
}
|
||||
if sourceType != nil {
|
||||
listQuery += ` AND a.source_type = $` + strconv.Itoa(listIdx)
|
||||
listArgs = append(listArgs, *sourceType)
|
||||
listIdx++
|
||||
}
|
||||
listQuery, listArgs, listIdx = appendArticleSourceTypeFilter(listQuery, listArgs, listIdx, sourceTypes)
|
||||
if params.GenerationMode != nil {
|
||||
listQuery += ` AND a.source_type = 'custom_generation' AND COALESCE(NULLIF(gt.input_params_json ->> 'generation_mode', ''), 'instant') = $` + strconv.Itoa(listIdx)
|
||||
listArgs = append(listArgs, *params.GenerationMode)
|
||||
@@ -264,6 +263,11 @@ func (s *ArticleService) loadArticles(ctx context.Context, tenantID int64, param
|
||||
listArgs = append(listArgs, *params.TemplateID)
|
||||
listIdx++
|
||||
}
|
||||
if params.KolPromptID != nil {
|
||||
listQuery += ` AND a.kol_prompt_id = $` + strconv.Itoa(listIdx)
|
||||
listArgs = append(listArgs, *params.KolPromptID)
|
||||
listIdx++
|
||||
}
|
||||
if params.PromptRuleID != nil {
|
||||
listQuery += ` AND a.prompt_rule_id = $` + strconv.Itoa(listIdx)
|
||||
listArgs = append(listArgs, *params.PromptRuleID)
|
||||
@@ -1009,6 +1013,55 @@ func resolveWordCount(markdown *string, stored int) int {
|
||||
return stored
|
||||
}
|
||||
|
||||
func normalizeArticleSourceTypes(sourceType *string) []string {
|
||||
if sourceType == nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
parts := strings.Split(*sourceType, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
seen := make(map[string]struct{}, len(parts))
|
||||
for _, part := range parts {
|
||||
value := strings.TrimSpace(part)
|
||||
if value == "" {
|
||||
continue
|
||||
}
|
||||
if _, exists := seen[value]; exists {
|
||||
continue
|
||||
}
|
||||
seen[value] = struct{}{}
|
||||
out = append(out, value)
|
||||
}
|
||||
|
||||
return out
|
||||
}
|
||||
|
||||
func appendArticleSourceTypeFilter(
|
||||
query string,
|
||||
args []interface{},
|
||||
argIdx int,
|
||||
sourceTypes []string,
|
||||
) (string, []interface{}, int) {
|
||||
if len(sourceTypes) == 0 {
|
||||
return query, args, argIdx
|
||||
}
|
||||
|
||||
placeholders := make([]string, 0, len(sourceTypes))
|
||||
for _, sourceType := range sourceTypes {
|
||||
placeholders = append(placeholders, `$`+strconv.Itoa(argIdx))
|
||||
args = append(args, sourceType)
|
||||
argIdx++
|
||||
}
|
||||
|
||||
if len(placeholders) == 1 {
|
||||
query += ` AND a.source_type = ` + placeholders[0]
|
||||
} else {
|
||||
query += ` AND a.source_type IN (` + strings.Join(placeholders, ", ") + `)`
|
||||
}
|
||||
|
||||
return query, args, argIdx
|
||||
}
|
||||
|
||||
func resolveArticleGenerationMode(sourceType string, inputParamsJSON []byte) *string {
|
||||
if sourceType != "custom_generation" {
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user