feat(imitation): add article imitation create flow

Introduce 仿写创作: new list and create views, backend imitation service
and prompt templates, worker task routing for imitation jobs, and one-click
rewrite triggers from question citation sources. Surface source article
URL/title on article list/detail, and restrict failed articles to delete-only.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-04-25 21:36:44 +08:00
parent 46d0a7aea0
commit 40d9a6cc63
29 changed files with 2678 additions and 120 deletions
+3
View File
@@ -48,6 +48,9 @@ type runtimePromptsConfig struct {
PromptRuleTargetPlatformSupplementFormat string `yaml:"prompt_rule_target_platform_supplement_format"`
PromptRuleSupplementHeading string `yaml:"prompt_rule_supplement_heading"`
PromptRuleOutputRequirementsSection string `yaml:"prompt_rule_output_requirements_section"`
ArticleImitationPromptTemplate string `yaml:"article_imitation_prompt_template"`
ArticleImitationLocaleInstructions map[string]string `yaml:"article_imitation_locale_instructions"`
ArticleImitationSettingLabels map[string]string `yaml:"article_imitation_setting_labels"`
KnowledgePromptIntroLines []string `yaml:"knowledge_prompt_intro_lines"`
KnowledgeSnippetLabelFormat string `yaml:"knowledge_snippet_label_format"`
KnowledgeWebsiteMarkdown knowledgeWebsiteMarkdownConfig `yaml:"knowledge_website_markdown"`
+49
View File
@@ -136,6 +136,55 @@ func PromptRuleOutputRequirementsSection() string {
return trimPrompt(loadRuntimePrompts().PromptRuleOutputRequirementsSection)
}
func ArticleImitationPrompt(locale, sourceMeta, settingsBlock, knowledgeSection, sourceContent string) string {
runtime := loadRuntimePrompts()
template := trimPrompt(runtime.ArticleImitationPromptTemplate)
if template == "" {
template = `你是一名资深内容策略编辑,请基于给定源文章做高质量仿写创作。
%s
## 源文章
%s
## 仿写设置
%s
%s
## 源文章内容
%s
请开始输出仿写后的完整文章。`
}
return strings.TrimSpace(fmt.Sprintf(
template,
ArticleImitationLocaleInstruction(locale),
strings.TrimSpace(sourceMeta),
strings.TrimSpace(settingsBlock),
strings.TrimSpace(knowledgeSection),
strings.TrimSpace(sourceContent),
))
}
func ArticleImitationLocaleInstruction(locale string) string {
instructions := loadRuntimePrompts().ArticleImitationLocaleInstructions
if value, ok := instructions[strings.TrimSpace(locale)]; ok && strings.TrimSpace(value) != "" {
return strings.TrimSpace(value)
}
if strings.EqualFold(strings.TrimSpace(locale), "en-US") {
return "Output language: English."
}
return "输出语言:中文简体。"
}
func ArticleImitationSettingLabel(key string) string {
labels := loadRuntimePrompts().ArticleImitationSettingLabels
if value, ok := labels[strings.TrimSpace(key)]; ok && strings.TrimSpace(value) != "" {
return strings.TrimSpace(value)
}
return strings.TrimSpace(key)
}
func KnowledgePromptIntroLines() []string {
lines := loadRuntimePrompts().KnowledgePromptIntroLines
return append([]string(nil), lines...)