feat(imitation): accept pasted source content as an alternative to URL

- Make source_url optional and add source_content to the request; the
  two are normalized into a source kind ("url" | "content"), URL wins
  when both are present, and missing both returns source_required
- Skip web fetching in the generation worker when pasted content is
  provided; truncate it to the same 24,000-rune cap
- Label untitled pasted-content jobs with a locale-aware display title
  and mark the source kind in wizard state and prompt metadata
- Cover source normalization, truncation, and display title with tests
This commit is contained in:
2026-07-21 08:41:55 +08:00
parent 403ff91789
commit d62f7b3c91
3 changed files with 151 additions and 22 deletions
@@ -0,0 +1,87 @@
package app
import (
"strings"
"testing"
)
func TestNormalizeImitationSourcePrefersURL(t *testing.T) {
t.Parallel()
sourceURL, sourceContent, sourceKind, err := normalizeImitationSource(GenerateImitationRequest{
SourceURL: " https://example.com/article ",
SourceContent: "pasted content should be ignored",
})
if err != nil {
t.Fatalf("normalizeImitationSource() error = %v", err)
}
if sourceURL != "https://example.com/article" {
t.Fatalf("sourceURL = %q, want normalized URL", sourceURL)
}
if sourceContent != "" {
t.Fatalf("sourceContent = %q, want empty when URL is present", sourceContent)
}
if sourceKind != articleImitationSourceURL {
t.Fatalf("sourceKind = %q, want %q", sourceKind, articleImitationSourceURL)
}
}
func TestNormalizeImitationSourceAcceptsPastedContent(t *testing.T) {
t.Parallel()
sourceURL, sourceContent, sourceKind, err := normalizeImitationSource(GenerateImitationRequest{
SourceContent: " article body ",
})
if err != nil {
t.Fatalf("normalizeImitationSource() error = %v", err)
}
if sourceURL != "" {
t.Fatalf("sourceURL = %q, want empty", sourceURL)
}
if sourceContent != "article body" {
t.Fatalf("sourceContent = %q, want trimmed content", sourceContent)
}
if sourceKind != articleImitationSourceContent {
t.Fatalf("sourceKind = %q, want %q", sourceKind, articleImitationSourceContent)
}
}
func TestNormalizeImitationSourceRejectsMissingSource(t *testing.T) {
t.Parallel()
_, _, _, err := normalizeImitationSource(GenerateImitationRequest{})
if err == nil {
t.Fatal("normalizeImitationSource() error = nil, want source_required")
}
if err.Error() != "source_required" {
t.Fatalf("normalizeImitationSource() error = %q, want source_required", err.Error())
}
}
func TestNormalizeImitationSourceTruncatesPastedContent(t *testing.T) {
t.Parallel()
_, sourceContent, _, err := normalizeImitationSource(GenerateImitationRequest{
SourceContent: strings.Repeat("文", maxImitationSourceContentRunes+100),
})
if err != nil {
t.Fatalf("normalizeImitationSource() error = %v", err)
}
if got := len([]rune(sourceContent)); got != maxImitationSourceContentRunes {
t.Fatalf("source content rune count = %d, want %d", got, maxImitationSourceContentRunes)
}
}
func TestImitationSourceDisplayTitleLabelsUntitledPastedContent(t *testing.T) {
t.Parallel()
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "", "zh-CN"); got != "粘贴正文" {
t.Fatalf("Chinese display title = %q, want 粘贴正文", got)
}
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "", "en-US"); got != "Pasted content" {
t.Fatalf("English display title = %q, want Pasted content", got)
}
if got := imitationSourceDisplayTitle(articleImitationSourceContent, "Original title", "en-US"); got != "Original title" {
t.Fatalf("explicit display title = %q, want Original title", got)
}
}