87 lines
3.2 KiB
Go
87 lines
3.2 KiB
Go
package catalog
|
|
|
|
import (
|
|
"context"
|
|
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/aiprompts"
|
|
"github.com/descrybe/descrybe-v2/apps/api/internal/company"
|
|
"github.com/google/uuid"
|
|
"github.com/jackc/pgx/v5/pgconn"
|
|
)
|
|
|
|
// DefaultFormulaTarget is one freshly created category to seed formulas onto.
|
|
type DefaultFormulaTarget struct {
|
|
ID uuid.UUID
|
|
UniqueID string
|
|
Name string
|
|
}
|
|
|
|
// pgxExecer is the subset of pgxpool.Pool / pgx.Tx used here so the helper works
|
|
// inside the CSV import transaction as well as on the plain pool.
|
|
type pgxExecer interface {
|
|
Exec(ctx context.Context, sql string, args ...any) (pgconn.CommandTag, error)
|
|
}
|
|
|
|
// applyDefaultCategoryFormulasSQL fills prompt / title_template / description_template
|
|
// on newly created categories. Only empty columns are written, so a tenant that
|
|
// already authored a formula (or an A1 category carrying its Slovenian legacy
|
|
// prompt) is never overwritten.
|
|
const applyDefaultCategoryFormulasSQL = `
|
|
UPDATE categories AS c SET
|
|
prompt = CASE
|
|
WHEN c.prompt IS NULL OR c.prompt = '{}'::jsonb
|
|
THEN v.prompt::jsonb ELSE c.prompt END,
|
|
title_template = CASE
|
|
WHEN c.title_template IS NULL OR c.title_template::text IN ('null', '{}')
|
|
THEN NULLIF(v.title_template, '')::jsonb ELSE c.title_template END,
|
|
description_template = CASE
|
|
WHEN c.description_template IS NULL OR c.description_template::text IN ('null', '{}')
|
|
THEN NULLIF(v.description_template, '')::jsonb ELSE c.description_template END,
|
|
updated_at = now()
|
|
FROM (
|
|
SELECT * FROM unnest($2::uuid[], $3::text[], $4::text[], $5::text[])
|
|
AS t(id, prompt, title_template, description_template)
|
|
) AS v
|
|
WHERE c.id = v.id AND c.company_id = $1`
|
|
|
|
// ApplyDefaultCategoryFormulas gives newly created categories the platform-default
|
|
// formulas (English, same style as the A1 legacy templates) when they have none.
|
|
//
|
|
// New categories get a working title/description/meta formula out of the box
|
|
// instead of falling through to generic "1-3 paragraphs" copy. Existing rows are
|
|
// untouched — this only runs at create time. A1 categories keep their Slovenian
|
|
// prompts because seed-a1 writes them and the SQL never overwrites a set column.
|
|
func ApplyDefaultCategoryFormulas(ctx context.Context, db pgxExecer, companyID uuid.UUID, targets ...DefaultFormulaTarget) error {
|
|
if db == nil || len(targets) == 0 {
|
|
return nil
|
|
}
|
|
ids := make([]uuid.UUID, 0, len(targets))
|
|
prompts := make([]string, 0, len(targets))
|
|
titles := make([]string, 0, len(targets))
|
|
descs := make([]string, 0, len(targets))
|
|
for _, t := range targets {
|
|
if t.ID == uuid.Nil {
|
|
continue
|
|
}
|
|
def := aiprompts.DefaultCategoryFormula(t.UniqueID, t.Name)
|
|
if def.Overlay == "" {
|
|
continue
|
|
}
|
|
// "*" applies to every content language: the formula text is English while
|
|
// {{language}} still selects the output language at render time.
|
|
promptJSON, err := company.EncodeLangPromptMap(company.LangPromptMap{"*": def.Overlay})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
ids = append(ids, t.ID)
|
|
prompts = append(prompts, string(promptJSON))
|
|
titles = append(titles, def.TitleTemplateJSON)
|
|
descs = append(descs, def.DescriptionTemplateJSON)
|
|
}
|
|
if len(ids) == 0 {
|
|
return nil
|
|
}
|
|
_, err := db.Exec(ctx, applyDefaultCategoryFormulasSQL, companyID, ids, prompts, titles, descs)
|
|
return err
|
|
}
|