From 00eb514efcd4e65c45d3280b86c1841dcf91b950 Mon Sep 17 00:00:00 2001 From: liangxu Date: Wed, 20 May 2026 02:16:45 +0800 Subject: [PATCH] feat(imitation): simplify form fields and make brand_name required Remove industry, target_audience, content_goal, tone, and length_goal from the imitation form; brand_name is now mandatory with autocomplete from brand library, keywords are pre-populated from the selected brand's search keywords, and output length is hardcoded to ~2000 characters in the prompt. Co-Authored-By: Claude Sonnet 4.6 (1M context) --- apps/admin-web/src/i18n/messages/en-US.ts | 19 +--- apps/admin-web/src/i18n/messages/zh-CN.ts | 17 +--- .../src/views/ImitationGenerateView.vue | 99 +++++++++---------- deploy/k3s/config/prompts.yml | 9 +- deploy/prompts.yml | 9 +- packages/shared-types/src/index.ts | 7 +- server/configs/prompts.yml | 9 +- .../tenant/app/article_imitation_service.go | 22 +---- 8 files changed, 67 insertions(+), 124 deletions(-) diff --git a/apps/admin-web/src/i18n/messages/en-US.ts b/apps/admin-web/src/i18n/messages/en-US.ts index f128efe..900b75a 100644 --- a/apps/admin-web/src/i18n/messages/en-US.ts +++ b/apps/admin-web/src/i18n/messages/en-US.ts @@ -723,14 +723,9 @@ const enUS = { sourceURL: 'Article URL', sourceTitle: 'Source title', language: 'Article language', - industry: 'Industry / scenario', brandName: 'Brand / subject', region: 'Region', - targetAudience: 'Target audience', - contentGoal: 'Content goal', - tone: 'Tone', - lengthGoal: 'Length', - keywords: 'Keywords', + keywords: 'Optimization keywords', preservePoints: 'Keep / emphasize', avoidPoints: 'Avoid', extraRequirements: 'Extra requirements', @@ -743,21 +738,17 @@ const enUS = { 'Selected groups are retrieved in the backend and passed to generation as reference context.', sourceURLPlaceholder: 'https://example.com/article', sourceTitlePlaceholder: 'Optional. Citation titles are prefilled automatically.', - industryPlaceholder: 'For example: home improvement, education, SaaS, healthcare', - brandNamePlaceholder: 'Optional. Helps the article fit a specific brand or subject.', + brandNamePlaceholder: 'Required. Type the target subject, or choose from the brand library.', regionPlaceholder: 'For example: Shanghai, East China, nationwide, North America', - targetAudiencePlaceholder: - 'For example: first-time buyers, channel partners, procurement leads', - contentGoalPlaceholder: 'For example: education, conversion, brand trust, selection advice', - tonePlaceholder: 'For example: professional, conversational, comparative, news analysis', - lengthGoalPlaceholder: 'For example: around 1200 words, short post, long-form guide', - keywordsPlaceholder: 'Type keywords and press Enter', + keywordsPlaceholder: + 'Type optimization keywords and press Enter. Brand-library options appear after choosing a subject.', preservePointsPlaceholder: 'List facts, data, arguments, or examples that must be kept.', avoidPointsPlaceholder: 'List claims, competitors, compliance risks, or wording to avoid.', extraRequirementsPlaceholder: 'Add channel, structure, title style, or industry-specific instructions.', queued: 'Rewrite task submitted and queued.', sourceURLRequired: 'Enter the source article URL first.', + brandNameRequired: 'Enter the brand / subject first.', submitError: 'Failed to submit rewrite task.', backToList: 'Back to rewrites', }, diff --git a/apps/admin-web/src/i18n/messages/zh-CN.ts b/apps/admin-web/src/i18n/messages/zh-CN.ts index 7e7fd3d..d25e8dd 100644 --- a/apps/admin-web/src/i18n/messages/zh-CN.ts +++ b/apps/admin-web/src/i18n/messages/zh-CN.ts @@ -691,14 +691,9 @@ const zhCN = { sourceURL: "文章 URL", sourceTitle: "来源标题", language: "文章语言", - industry: "行业/场景", brandName: "品牌/主体", region: "地域", - targetAudience: "目标读者", - contentGoal: "内容目标", - tone: "语气风格", - lengthGoal: "篇幅要求", - keywords: "关键词", + keywords: "优化关键词", preservePoints: "必须保留/强调", avoidPoints: "需要规避", extraRequirements: "其他要求", @@ -709,19 +704,15 @@ const zhCN = { knowledgeBaseHint: "选择后,后台会检索相关知识片段并作为生成参考,未选择则只基于来源文章和当前设置生成。", sourceURLPlaceholder: "https://example.com/article", sourceTitlePlaceholder: "可选,引用来源标题会自动带入", - industryPlaceholder: "例如:家居建材、教育培训、SaaS、医疗健康", - brandNamePlaceholder: "可选,填写后文章会自然贴合该品牌或主体", + brandNamePlaceholder: "必填,可输入目标达成词,或从品牌库选择", regionPlaceholder: "例如:上海、华东、全国、北美市场", - targetAudiencePlaceholder: "例如:首次购买用户、渠道代理、企业采购负责人", - contentGoalPlaceholder: "例如:科普说明、转化种草、品牌信任、选型建议", - tonePlaceholder: "例如:专业可信、轻松口语、评测对比、新闻解读", - lengthGoalPlaceholder: "例如:1200字左右、短文、深度长文", - keywordsPlaceholder: "输入关键词后回车,可多选", + keywordsPlaceholder: "输入优化关键词后回车,可多选;选择品牌库主体后会显示搜索词候选", preservePointsPlaceholder: "列出必须保留的事实、数据、观点或案例", avoidPointsPlaceholder: "列出不能出现的说法、竞品、合规禁区或表达方式", extraRequirementsPlaceholder: "补充行业、渠道、结构、标题风格等自由要求", queued: "仿写任务已提交,正在排队生成", sourceURLRequired: "请先填写来源文章 URL", + brandNameRequired: "请先填写品牌/主体", submitError: "仿写任务提交失败", backToList: "返回仿写列表", }, diff --git a/apps/admin-web/src/views/ImitationGenerateView.vue b/apps/admin-web/src/views/ImitationGenerateView.vue index 17b37ce..ec7c090 100644 --- a/apps/admin-web/src/views/ImitationGenerateView.vue +++ b/apps/admin-web/src/views/ImitationGenerateView.vue @@ -1,13 +1,13 @@ @@ -204,17 +230,11 @@ function submit(): void {
- - -
- -
- - {{ t('imitation.create.brandName') }} +
@@ -227,44 +247,13 @@ function submit(): void { />
-
- - -
- -
- - -
- -
- - -
- -
- - -
-
diff --git a/deploy/k3s/config/prompts.yml b/deploy/k3s/config/prompts.yml index c33ae3a..4c96e65 100644 --- a/deploy/k3s/config/prompts.yml +++ b/deploy/k3s/config/prompts.yml @@ -278,7 +278,8 @@ runtime: - 文章结构不动,文章分析核心维度不动,只动目标达成词(也就是brand_name) - 保留源文章中的事实信息、论证逻辑和可复用观点。 - 不要逐句同义替换,不要复制源文的独特措辞,不要编造源文、知识库和补充要求之外的事实。 - - 如果给出了地域、品牌、目标读者或内容目标,标题和正文都要自然贴合这些上下文。 + - 如果给出了地域、品牌/主体或优化关键词,标题和正文都要自然贴合这些上下文。 + - 全文篇幅控制在 2000 字左右。 %s 输出格式:Markdown。正文结构清晰,可直接进入文章编辑器。 @@ -301,14 +302,10 @@ runtime: zh-CN: "输出语言:中文简体。" en-US: "Output language: English." article_imitation_setting_labels: - industry: "行业/场景" brand_name: "品牌/主体" region: "地域" - target_audience: "目标读者" - content_goal: "内容目标" - tone: "语气风格" length_goal: "篇幅要求" - keywords: "关键词" + keywords: "优化关键词" preserve_points: "必须保留/强调" avoid_points: "需要规避" extra_requirements: "其他要求" diff --git a/deploy/prompts.yml b/deploy/prompts.yml index c33ae3a..4c96e65 100644 --- a/deploy/prompts.yml +++ b/deploy/prompts.yml @@ -278,7 +278,8 @@ runtime: - 文章结构不动,文章分析核心维度不动,只动目标达成词(也就是brand_name) - 保留源文章中的事实信息、论证逻辑和可复用观点。 - 不要逐句同义替换,不要复制源文的独特措辞,不要编造源文、知识库和补充要求之外的事实。 - - 如果给出了地域、品牌、目标读者或内容目标,标题和正文都要自然贴合这些上下文。 + - 如果给出了地域、品牌/主体或优化关键词,标题和正文都要自然贴合这些上下文。 + - 全文篇幅控制在 2000 字左右。 %s 输出格式:Markdown。正文结构清晰,可直接进入文章编辑器。 @@ -301,14 +302,10 @@ runtime: zh-CN: "输出语言:中文简体。" en-US: "Output language: English." article_imitation_setting_labels: - industry: "行业/场景" brand_name: "品牌/主体" region: "地域" - target_audience: "目标读者" - content_goal: "内容目标" - tone: "语气风格" length_goal: "篇幅要求" - keywords: "关键词" + keywords: "优化关键词" preserve_points: "必须保留/强调" avoid_points: "需要规避" extra_requirements: "其他要求" diff --git a/packages/shared-types/src/index.ts b/packages/shared-types/src/index.ts index e13d627..e065b76 100644 --- a/packages/shared-types/src/index.ts +++ b/packages/shared-types/src/index.ts @@ -748,13 +748,8 @@ export interface GenerateImitationRequest { source_url: string source_title?: string locale?: string - industry?: string - brand_name?: string + brand_name: string region?: string - target_audience?: string - content_goal?: string - tone?: string - length_goal?: string keywords?: string[] preserve_points?: string avoid_points?: string diff --git a/server/configs/prompts.yml b/server/configs/prompts.yml index c33ae3a..4c96e65 100644 --- a/server/configs/prompts.yml +++ b/server/configs/prompts.yml @@ -278,7 +278,8 @@ runtime: - 文章结构不动,文章分析核心维度不动,只动目标达成词(也就是brand_name) - 保留源文章中的事实信息、论证逻辑和可复用观点。 - 不要逐句同义替换,不要复制源文的独特措辞,不要编造源文、知识库和补充要求之外的事实。 - - 如果给出了地域、品牌、目标读者或内容目标,标题和正文都要自然贴合这些上下文。 + - 如果给出了地域、品牌/主体或优化关键词,标题和正文都要自然贴合这些上下文。 + - 全文篇幅控制在 2000 字左右。 %s 输出格式:Markdown。正文结构清晰,可直接进入文章编辑器。 @@ -301,14 +302,10 @@ runtime: zh-CN: "输出语言:中文简体。" en-US: "Output language: English." article_imitation_setting_labels: - industry: "行业/场景" brand_name: "品牌/主体" region: "地域" - target_audience: "目标读者" - content_goal: "内容目标" - tone: "语气风格" length_goal: "篇幅要求" - keywords: "关键词" + keywords: "优化关键词" preserve_points: "必须保留/强调" avoid_points: "需要规避" extra_requirements: "其他要求" diff --git a/server/internal/tenant/app/article_imitation_service.go b/server/internal/tenant/app/article_imitation_service.go index 4a833e9..bd4c8f1 100644 --- a/server/internal/tenant/app/article_imitation_service.go +++ b/server/internal/tenant/app/article_imitation_service.go @@ -47,13 +47,8 @@ type GenerateImitationRequest struct { SourceURL string `json:"source_url" binding:"required"` SourceTitle string `json:"source_title"` Locale string `json:"locale"` - Industry string `json:"industry"` BrandName string `json:"brand_name"` Region string `json:"region"` - TargetAudience string `json:"target_audience"` - ContentGoal string `json:"content_goal"` - Tone string `json:"tone"` - LengthGoal string `json:"length_goal"` Keywords []string `json:"keywords"` PreservePoints string `json:"preserve_points"` AvoidPoints string `json:"avoid_points"` @@ -135,6 +130,9 @@ func (s *ArticleImitationService) Generate(ctx context.Context, req GenerateImit if err != nil { return nil, err } + if strings.TrimSpace(req.BrandName) == "" { + return nil, response.ErrBadRequest(40001, "brand_name_required", "brand_name is required") + } quotaRepo := repository.NewQuotaRepository(s.pool) balance, err := quotaRepo.GetCurrentBalance(ctx, actor.TenantID, "article_generation") @@ -587,13 +585,9 @@ func buildImitationInputParams(sourceURL string, req GenerateImitationRequest) m "source_url": sourceURL, "source_title": strings.TrimSpace(req.SourceTitle), "locale": normalizeImitationLocale(req.Locale), - "industry": strings.TrimSpace(req.Industry), "brand_name": strings.TrimSpace(req.BrandName), "region": strings.TrimSpace(req.Region), - "target_audience": strings.TrimSpace(req.TargetAudience), - "content_goal": strings.TrimSpace(req.ContentGoal), - "tone": strings.TrimSpace(req.Tone), - "length_goal": strings.TrimSpace(req.LengthGoal), + "length_goal": "2000字左右", "keywords": normalizeImitationKeywords(req.Keywords), "preserve_points": strings.TrimSpace(req.PreservePoints), "avoid_points": strings.TrimSpace(req.AvoidPoints), @@ -631,12 +625,8 @@ func buildImitationGenerationPrompt(params map[string]interface{}, sourceContent } var settings strings.Builder - appendPromptLine(&settings, "industry", extractString(params, "industry")) appendPromptLine(&settings, "brand_name", extractString(params, "brand_name")) appendPromptLine(&settings, "region", extractString(params, "region")) - appendPromptLine(&settings, "target_audience", extractString(params, "target_audience")) - appendPromptLine(&settings, "content_goal", extractString(params, "content_goal")) - appendPromptLine(&settings, "tone", extractString(params, "tone")) appendPromptLine(&settings, "length_goal", extractString(params, "length_goal")) if len(keywords) > 0 { appendPromptLine(&settings, "keywords", strings.Join(keywords, "、")) @@ -674,12 +664,8 @@ func buildImitationKnowledgeQuery(params map[string]interface{}) string { } appendValue(extractString(params, "source_title")) - appendValue(extractString(params, "industry")) appendValue(extractString(params, "brand_name")) appendValue(extractString(params, "region")) - appendValue(extractString(params, "target_audience")) - appendValue(extractString(params, "content_goal")) - appendValue(extractString(params, "tone")) appendValue(strings.Join(extractStringList(params["keywords"], 16), "\n")) appendValue(extractString(params, "extra_requirements"))