This commit is contained in:
2026-08-17 00:39:25 +02:00
parent 92f046b542
commit 93dc70123c
54 changed files with 25528 additions and 20666 deletions
+59 -8
View File
@@ -13,6 +13,7 @@ import (
"unicode"
"github.com/descrybe/descrybe-v2/apps/api/internal/aiprompts"
"github.com/descrybe/descrybe-v2/apps/api/internal/catalog"
"github.com/descrybe/descrybe-v2/apps/api/internal/security"
"github.com/google/uuid"
"github.com/jackc/pgx/v5/pgxpool"
@@ -41,6 +42,10 @@ var (
)
func defaultCategoryPromptsPath(archivePath string) string {
// Prefer live WP dump when present (Sync A1 / seed share the same source of truth).
if p := catalog.ResolveWPCategoryPromptsPath(""); p != "" {
return p
}
if strings.TrimSpace(archivePath) != "" {
return filepath.Join(filepath.Dir(archivePath), "a1-category-prompts.json")
}
@@ -52,6 +57,10 @@ func loadCategoryPromptsFile(path string) (categoryPromptsFile, error) {
if path == "" || path == "." {
return categoryPromptsFile{}, fmt.Errorf("category prompts path is empty")
}
base := strings.ToLower(filepath.Base(path))
if strings.HasPrefix(base, "wp_product_categories") && strings.HasSuffix(base, ".sql") {
return loadCategoryPromptsFromWPSQL(path)
}
// Allowlist the committed seed filename (blocks accidental reads of unrelated dumps).
if filepath.Base(path) != "a1-category-prompts.json" {
return categoryPromptsFile{}, fmt.Errorf("refusing unexpected category prompts file name %q", filepath.Base(path))
@@ -76,6 +85,36 @@ func loadCategoryPromptsFile(path string) (categoryPromptsFile, error) {
return f, nil
}
func loadCategoryPromptsFromWPSQL(path string) (categoryPromptsFile, error) {
raw, err := os.ReadFile(path)
if err != nil {
return categoryPromptsFile{}, fmt.Errorf("read wp category prompts: %w", err)
}
if len(raw) > 16<<20 {
return categoryPromptsFile{}, fmt.Errorf("wp category prompts file too large (%d bytes)", len(raw))
}
parsed, err := catalog.ParseWPProductCategoriesSQL(string(raw))
if err != nil {
return categoryPromptsFile{}, err
}
entries := make([]categoryPromptEntry, 0, len(parsed))
for _, e := range parsed {
entries = append(entries, categoryPromptEntry{
Name: e.Name,
UniqueID: e.UniqueID,
Prompt: e.Prompt,
})
}
if len(entries) == 0 {
return categoryPromptsFile{}, fmt.Errorf("wp category prompts file has no entries")
}
return categoryPromptsFile{
Version: 1,
Source: filepath.Base(path),
Entries: entries,
}, nil
}
// modernizeLegacyPromptPlaceholders rewrites v1 {""OPIS IZDELKA""} tokens to {{description}} / {{name}}.
func modernizeLegacyPromptPlaceholders(prompt string) string {
prompt = reLegacyDesc.ReplaceAllString(prompt, "{{description}}")
@@ -148,16 +187,11 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
byNorm := make(map[string]string, len(file.Entries))
byUnique := make(map[string]string, len(file.Entries))
// Overlay sets the shared role-sectioned enhance user template
// (aiprompts.CategoryEnhanceUserTemplate — title/description/meta/attributes).
// Seed JSON selects which categories get a prompt (prefer unique_id, else name).
// Unique title/description/meta formulas stay in title_template / description_template.
// Overlay: split each legacy combined Name+Description prompt into role-sectioned
// enhance USER text (Title / Description / Meta / Attributes). Unique title /
// description / meta formulas stay in title_template / description_template.
// Stored under "sl" + "*" so prompt->>'sl' and LangPromptAny both resolve;
// language stays via {{language}}.
canonical := prepareCategoryPrompt(aiprompts.CategoryEnhanceUserTemplate)
if canonical == "" {
return out, fmt.Errorf("CategoryEnhanceUserTemplate sanitized to empty")
}
for _, e := range file.Entries {
uid := strings.TrimSpace(e.UniqueID)
name := strings.TrimSpace(e.Name)
@@ -165,6 +199,23 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
out.Skipped++
continue
}
raw := strings.TrimSpace(e.Prompt)
var canonical string
if raw == "" {
out.Skipped++
continue
}
if aiprompts.IsLegacyCombinedEnhancePrompt(raw) {
canonical = prepareCategoryPrompt(aiprompts.SplitLegacyCombinedEnhancePrompt(raw))
} else if aiprompts.CategoryEnhanceHasRoleSections(raw) {
canonical = prepareCategoryPrompt(raw)
} else {
canonical = prepareCategoryPrompt(aiprompts.CategoryEnhanceUserTemplate)
}
if canonical == "" {
out.Skipped++
continue
}
if uid != "" {
byUnique[strings.ToLower(uid)] = canonical
}