fix
This commit is contained in:
@@ -160,3 +160,76 @@ func parseDescriptionFormula(template any) (DescriptionFormula, bool) {
|
||||
return f, true
|
||||
}
|
||||
}
|
||||
|
||||
// EffectiveDescriptionFormula returns the stored description_template when it has
|
||||
// sections; otherwise derives sections from the category enhance prompt Description
|
||||
// role (legacy HTML <H2>{…}</H2><p>{…}</p> overlays). That is how A1 and tenants
|
||||
// author HTML structure in /categories/.../prompt — without this, enhance accepts
|
||||
// plain prose and never runs the formula quality gate.
|
||||
func EffectiveDescriptionFormula(stored any, categoryPrompt string) DescriptionFormula {
|
||||
if f, ok := parseDescriptionFormula(stored); ok && len(f.Sections) > 0 {
|
||||
return f
|
||||
}
|
||||
body := ExtractEnhanceSectionBody(categoryPrompt, SectionDescriptionStart, SectionDescriptionEnd)
|
||||
if body == "" {
|
||||
body = strings.TrimSpace(categoryPrompt)
|
||||
}
|
||||
if body == "" || !reLegacyHTMLBlock.MatchString(body) {
|
||||
if f, ok := parseDescriptionFormula(stored); ok {
|
||||
return f
|
||||
}
|
||||
return DescriptionFormula{}
|
||||
}
|
||||
return DeriveDescriptionFormulaFromLegacyParts(LegacyEnhanceParts{
|
||||
DescriptionRules: body,
|
||||
WasLegacy: true,
|
||||
})
|
||||
}
|
||||
|
||||
// EffectiveDescriptionTemplateAny is EffectiveDescriptionFormula as a JSON object
|
||||
// for processing.ProductInput.DescriptionTemplate (nil when empty).
|
||||
func EffectiveDescriptionTemplateAny(stored any, categoryPrompt string) any {
|
||||
f := EffectiveDescriptionFormula(stored, categoryPrompt)
|
||||
if len(f.Sections) == 0 && strings.TrimSpace(f.MetaTitle) == "" && strings.TrimSpace(f.MetaDescription) == "" {
|
||||
return nil
|
||||
}
|
||||
b, err := json.Marshal(f)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
var out map[string]any
|
||||
if err := json.Unmarshal(b, &out); err != nil {
|
||||
return nil
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// CategoryTitlePromptRequiresRewrite reports whether the Title role instructs a
|
||||
// new retail name (not keep/echo supplier title). Used to reject "Matched" copy-paste.
|
||||
func CategoryTitlePromptRequiresRewrite(categoryPrompt string) bool {
|
||||
body := ExtractEnhanceSectionBody(categoryPrompt, SectionTitleStart, SectionTitleEnd)
|
||||
if body == "" {
|
||||
body = strings.TrimSpace(categoryPrompt)
|
||||
}
|
||||
if body == "" {
|
||||
return false
|
||||
}
|
||||
lower := strings.ToLower(body)
|
||||
cues := []string{
|
||||
"napiši novo ime",
|
||||
"napisi novo ime",
|
||||
"novo ime izdelka",
|
||||
"po formuli",
|
||||
"write a new",
|
||||
"new product name",
|
||||
"rename",
|
||||
"title formula",
|
||||
"sentence case",
|
||||
}
|
||||
for _, c := range cues {
|
||||
if strings.Contains(lower, c) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -54,3 +54,53 @@ GPT predloga:
|
||||
t.Fatalf("derived template should be OK: %s", raw)
|
||||
}
|
||||
}
|
||||
|
||||
func TestEffectiveDescriptionFormula_fromPromptDescriptionSection(t *testing.T) {
|
||||
t.Parallel()
|
||||
prompt := strings.Join([]string{
|
||||
SectionTitleStart,
|
||||
`Napiši novo ime izdelka po formuli: "tip izdelka sentence case", "znamka". Ne uporabljaj vejic.`,
|
||||
SectionTitleEnd,
|
||||
"",
|
||||
SectionDescriptionStart,
|
||||
`<H2>{Napiši Novo ime izdelka in izpostavi en benefit}</H2>`,
|
||||
`<p>{Napiši odstavek, ki je dolg 100 besed, ki NE vsebuje Novo ime izdelka.}</p>`,
|
||||
`<H2>{Izpostavi en benefit, in NE napiši Novo ime izdelka}</H2>`,
|
||||
`<p>{Napiši odstavek, ki je dolg 100 besed in VKLJUČI tudi tip izdelka lowercase}</p>`,
|
||||
`<b>{Tehnične specifikacije}</b><ul><li>{Napiši 3-10 tehničnih specifikacij v alinejah}</li></ul>`,
|
||||
SectionDescriptionEnd,
|
||||
}, "\n")
|
||||
f := EffectiveDescriptionFormula(nil, prompt)
|
||||
if len(f.Sections) < 4 {
|
||||
t.Fatalf("want HTML sections from Description role, got %#v", f.Sections)
|
||||
}
|
||||
if f.Sections[0].Type != "h2" || f.Sections[1].Type != "p" {
|
||||
t.Fatalf("unexpected order: %#v", f.Sections)
|
||||
}
|
||||
last := f.Sections[len(f.Sections)-1]
|
||||
if last.Type != "ul" {
|
||||
t.Fatalf("last should be ul specs, got %#v", last)
|
||||
}
|
||||
anyTpl := EffectiveDescriptionTemplateAny(nil, prompt)
|
||||
if anyTpl == nil {
|
||||
t.Fatal("expected non-nil template any")
|
||||
}
|
||||
if !CategoryTitlePromptRequiresRewrite(prompt) {
|
||||
t.Fatal("Title section should require rewrite")
|
||||
}
|
||||
if CategoryTitlePromptRequiresRewrite("--- Title ---\nKeep supplier name.\n--- End Title ---") {
|
||||
t.Fatal("keep-only Title must not require rewrite")
|
||||
}
|
||||
}
|
||||
|
||||
func TestExtractEnhanceSectionBody(t *testing.T) {
|
||||
t.Parallel()
|
||||
prompt := SectionTitleStart + "\nHello\n" + SectionTitleEnd + "\n" +
|
||||
SectionDescriptionStart + "\nBody here\n" + SectionDescriptionEnd
|
||||
if got := ExtractEnhanceSectionBody(prompt, SectionTitleStart, SectionTitleEnd); got != "Hello" {
|
||||
t.Fatalf("title body=%q", got)
|
||||
}
|
||||
if got := ExtractEnhanceSectionBody(prompt, SectionDescriptionStart, SectionDescriptionEnd); got != "Body here" {
|
||||
t.Fatalf("desc body=%q", got)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,6 +110,31 @@ func BuildCategoryEnhanceOverlay(parts LegacyEnhanceParts) string {
|
||||
return strings.TrimSpace(b.String())
|
||||
}
|
||||
|
||||
// ExtractEnhanceSectionBody returns the text between start/end markers
|
||||
// (case-insensitive markers, body preserved). Empty when the start marker is missing.
|
||||
func ExtractEnhanceSectionBody(prompt, start, end string) string {
|
||||
raw := strings.ReplaceAll(strings.ReplaceAll(prompt, "\r\n", "\n"), "\r", "\n")
|
||||
lower := strings.ToLower(raw)
|
||||
startL := strings.ToLower(strings.TrimSpace(start))
|
||||
endL := strings.ToLower(strings.TrimSpace(end))
|
||||
if startL == "" {
|
||||
return ""
|
||||
}
|
||||
startIdx := strings.Index(lower, startL)
|
||||
if startIdx < 0 {
|
||||
return ""
|
||||
}
|
||||
bodyStart := startIdx + len(startL)
|
||||
rest := raw[bodyStart:]
|
||||
restLower := lower[bodyStart:]
|
||||
if endL != "" {
|
||||
if endIdx := strings.Index(restLower, endL); endIdx >= 0 {
|
||||
rest = rest[:endIdx]
|
||||
}
|
||||
}
|
||||
return strings.TrimSpace(strings.TrimPrefix(strings.TrimSuffix(rest, "\n"), "\n"))
|
||||
}
|
||||
|
||||
func cleanLegacyInstruction(s string) string {
|
||||
s = modernizeLegacyPlaceholders(s)
|
||||
s = reDoubledQuotes.ReplaceAllString(s, `"`)
|
||||
|
||||
Reference in New Issue
Block a user