fixes
This commit is contained in:
@@ -12,6 +12,7 @@ import (
|
||||
"strings"
|
||||
"unicode"
|
||||
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/aiprompts"
|
||||
"github.com/descrybe/descrybe-v2/apps/api/internal/security"
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5/pgxpool"
|
||||
@@ -28,8 +29,9 @@ type categoryPromptsFile struct {
|
||||
}
|
||||
|
||||
type categoryPromptEntry struct {
|
||||
Name string `json:"name"`
|
||||
Prompt string `json:"prompt"`
|
||||
Name string `json:"name"`
|
||||
UniqueID string `json:"unique_id,omitempty"`
|
||||
Prompt string `json:"prompt"`
|
||||
}
|
||||
|
||||
var (
|
||||
@@ -145,26 +147,43 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
|
||||
}
|
||||
|
||||
byNorm := make(map[string]string, len(file.Entries))
|
||||
for _, e := range file.Entries {
|
||||
name := strings.TrimSpace(e.Name)
|
||||
prompt := prepareCategoryPrompt(e.Prompt)
|
||||
if name == "" || prompt == "" {
|
||||
out.Skipped++
|
||||
continue
|
||||
}
|
||||
key := normalizeCategoryName(name)
|
||||
if key == "" {
|
||||
out.Skipped++
|
||||
continue
|
||||
}
|
||||
byNorm[key] = prompt
|
||||
byUnique := make(map[string]string, len(file.Entries))
|
||||
// Overlay sets the shared JSON-compatible enhance user template (not legacy HTML).
|
||||
// Seed JSON selects which categories get a prompt (prefer unique_id, else name).
|
||||
// Unique title/description 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")
|
||||
}
|
||||
if len(byNorm) == 0 {
|
||||
for _, e := range file.Entries {
|
||||
uid := strings.TrimSpace(e.UniqueID)
|
||||
name := strings.TrimSpace(e.Name)
|
||||
if uid == "" && name == "" {
|
||||
out.Skipped++
|
||||
continue
|
||||
}
|
||||
if uid != "" {
|
||||
byUnique[strings.ToLower(uid)] = canonical
|
||||
}
|
||||
if name != "" {
|
||||
key := normalizeCategoryName(name)
|
||||
if key == "" {
|
||||
if uid == "" {
|
||||
out.Skipped++
|
||||
}
|
||||
continue
|
||||
}
|
||||
byNorm[key] = canonical
|
||||
}
|
||||
}
|
||||
if len(byNorm) == 0 && len(byUnique) == 0 {
|
||||
return out, fmt.Errorf("no usable category prompts in %s", promptsPath)
|
||||
}
|
||||
|
||||
rows, err := pg.Query(ctx, `
|
||||
SELECT id, name
|
||||
SELECT id, COALESCE(unique_id, ''), name
|
||||
FROM categories
|
||||
WHERE company_id = $1`, companyID)
|
||||
if err != nil {
|
||||
@@ -172,22 +191,34 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
ids := make([]uuid.UUID, 0, len(byNorm))
|
||||
prompts := make([]string, 0, len(byNorm))
|
||||
matchedKeys := make(map[string]struct{}, len(byNorm))
|
||||
ids := make([]uuid.UUID, 0, len(byNorm)+len(byUnique))
|
||||
prompts := make([]string, 0, len(byNorm)+len(byUnique))
|
||||
matchedNorm := make(map[string]struct{}, len(byNorm))
|
||||
matchedUID := make(map[string]struct{}, len(byUnique))
|
||||
|
||||
for rows.Next() {
|
||||
var id uuid.UUID
|
||||
var name string
|
||||
if err := rows.Scan(&id, &name); err != nil {
|
||||
var uniqueID, name string
|
||||
if err := rows.Scan(&id, &uniqueID, &name); err != nil {
|
||||
return out, err
|
||||
}
|
||||
key := normalizeCategoryName(name)
|
||||
prompt, ok := byNorm[key]
|
||||
if !ok {
|
||||
prompt := ""
|
||||
if uidKey := strings.ToLower(strings.TrimSpace(uniqueID)); uidKey != "" {
|
||||
if p, ok := byUnique[uidKey]; ok {
|
||||
prompt = p
|
||||
matchedUID[uidKey] = struct{}{}
|
||||
}
|
||||
}
|
||||
if prompt == "" {
|
||||
key := normalizeCategoryName(name)
|
||||
if p, ok := byNorm[key]; ok {
|
||||
prompt = p
|
||||
matchedNorm[key] = struct{}{}
|
||||
}
|
||||
}
|
||||
if prompt == "" {
|
||||
continue
|
||||
}
|
||||
matchedKeys[key] = struct{}{}
|
||||
ids = append(ids, id)
|
||||
prompts = append(prompts, prompt)
|
||||
}
|
||||
@@ -195,22 +226,28 @@ func applyCategoryPrompts(ctx context.Context, pg *pgxpool.Pool, companyID uuid.
|
||||
return out, err
|
||||
}
|
||||
|
||||
for key := range byUnique {
|
||||
if _, ok := matchedUID[key]; !ok {
|
||||
out.Unmatched = append(out.Unmatched, "uid:"+key)
|
||||
}
|
||||
}
|
||||
for key := range byNorm {
|
||||
if _, ok := matchedKeys[key]; !ok {
|
||||
out.Unmatched = append(out.Unmatched, key)
|
||||
if _, ok := matchedNorm[key]; !ok {
|
||||
// Name unmatched is noise when unique_id matched the same row; still report for seed hygiene.
|
||||
out.Unmatched = append(out.Unmatched, "name:"+key)
|
||||
}
|
||||
}
|
||||
sort.Strings(out.Unmatched)
|
||||
|
||||
if len(ids) == 0 {
|
||||
return out, fmt.Errorf("no A1 categories matched any of %d seed prompts (check names)", len(byNorm))
|
||||
return out, fmt.Errorf("no A1 categories matched any of %d seed prompts (check unique_id/names)", len(byNorm)+len(byUnique))
|
||||
}
|
||||
|
||||
// Single parameterized batch update — company_id gate prevents cross-tenant writes.
|
||||
// ASSUMPTION: A1 seed company content language is Slovenian ("sl").
|
||||
// sl + * = prompt->>'sl' and company.LangPromptAny ({{language}} at render).
|
||||
tag, err := pg.Exec(ctx, `
|
||||
UPDATE categories AS c
|
||||
SET prompt = jsonb_build_object('sl', v.prompt), updated_at = now()
|
||||
SET prompt = jsonb_build_object('sl', v.prompt, '*', v.prompt), updated_at = now()
|
||||
FROM (
|
||||
SELECT * FROM unnest($1::uuid[], $2::text[]) AS t(id, prompt)
|
||||
) AS v
|
||||
|
||||
Reference in New Issue
Block a user