feat(creatives): Canva Agua Miia post / story / LinkedIn
Mapea EAHYK-l1SFM, EAHYK9p_MlY y EAHYK_ylNJo por formato y plataforma en RRSS. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -190,6 +190,13 @@ export async function POST(req: NextRequest) {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const platformFromBody =
|
||||||
|
typeof body.platform === 'string'
|
||||||
|
? body.platform
|
||||||
|
: calendarPiece?.platform
|
||||||
|
? String(calendarPiece.platform)
|
||||||
|
: null;
|
||||||
|
|
||||||
const brief = buildRrssGenerationBrief({
|
const brief = buildRrssGenerationBrief({
|
||||||
tenantId,
|
tenantId,
|
||||||
clientSlug: tenant?.slug || 'cliente',
|
clientSlug: tenant?.slug || 'cliente',
|
||||||
@@ -202,6 +209,7 @@ export async function POST(req: NextRequest) {
|
|||||||
notes: notesBase,
|
notes: notesBase,
|
||||||
pillar,
|
pillar,
|
||||||
month,
|
month,
|
||||||
|
platform: platformFromBody,
|
||||||
scheduledAt:
|
scheduledAt:
|
||||||
typeof body.scheduled_at === 'string' ? body.scheduled_at : null,
|
typeof body.scheduled_at === 'string' ? body.scheduled_at : null,
|
||||||
calendarPiece: calendarPiece
|
calendarPiece: calendarPiece
|
||||||
@@ -222,9 +230,7 @@ export async function POST(req: NextRequest) {
|
|||||||
hashtags: calendarPiece.hashtags
|
hashtags: calendarPiece.hashtags
|
||||||
? String(calendarPiece.hashtags)
|
? String(calendarPiece.hashtags)
|
||||||
: null,
|
: null,
|
||||||
platform: calendarPiece.platform
|
platform: platformFromBody || 'instagram',
|
||||||
? String(calendarPiece.platform)
|
|
||||||
: 'instagram',
|
|
||||||
}
|
}
|
||||||
: null,
|
: null,
|
||||||
recentPipeline: (recentRows || []).map((r) => ({
|
recentPipeline: (recentRows || []).map((r) => ({
|
||||||
|
|||||||
@@ -124,10 +124,13 @@ export default function ClientCreativeStylePanel({
|
|||||||
const [driveFolderId, setDriveFolderId] = useState('');
|
const [driveFolderId, setDriveFolderId] = useState('');
|
||||||
const [defaultLandingUrl, setDefaultLandingUrl] = useState('');
|
const [defaultLandingUrl, setDefaultLandingUrl] = useState('');
|
||||||
const [canvaTemplates, setCanvaTemplates] = useState<{
|
const [canvaTemplates, setCanvaTemplates] = useState<{
|
||||||
|
post?: string;
|
||||||
'foto-con-franja'?: string;
|
'foto-con-franja'?: string;
|
||||||
tipografico?: string;
|
tipografico?: string;
|
||||||
'dato-grande'?: string;
|
'dato-grande'?: string;
|
||||||
stories_9_16?: string;
|
stories_9_16?: string;
|
||||||
|
story?: string;
|
||||||
|
linkedin?: string;
|
||||||
landscape_1_91?: string;
|
landscape_1_91?: string;
|
||||||
default?: string;
|
default?: string;
|
||||||
}>({});
|
}>({});
|
||||||
@@ -225,6 +228,16 @@ export default function ClientCreativeStylePanel({
|
|||||||
const id = parseCanvaTemplateId(v);
|
const id = parseCanvaTemplateId(v);
|
||||||
if (id) normalizedCanva[k] = id;
|
if (id) normalizedCanva[k] = id;
|
||||||
}
|
}
|
||||||
|
// Keep legacy layout keys aligned with Post / Story slots
|
||||||
|
if (normalizedCanva.post) {
|
||||||
|
if (!normalizedCanva['foto-con-franja']) {
|
||||||
|
normalizedCanva['foto-con-franja'] = normalizedCanva.post;
|
||||||
|
}
|
||||||
|
if (!normalizedCanva.default) normalizedCanva.default = normalizedCanva.post;
|
||||||
|
}
|
||||||
|
if (normalizedCanva.stories_9_16 && !normalizedCanva.story) {
|
||||||
|
normalizedCanva.story = normalizedCanva.stories_9_16;
|
||||||
|
}
|
||||||
if (Object.keys(normalizedCanva).length > 0) {
|
if (Object.keys(normalizedCanva).length > 0) {
|
||||||
setCanvaTemplates(normalizedCanva);
|
setCanvaTemplates(normalizedCanva);
|
||||||
}
|
}
|
||||||
@@ -1727,47 +1740,47 @@ export default function ClientCreativeStylePanel({
|
|||||||
{/* Plantillas de Canva */}
|
{/* Plantillas de Canva */}
|
||||||
<div className="space-y-3 pt-2 border-t border-gray-200">
|
<div className="space-y-3 pt-2 border-t border-gray-200">
|
||||||
<h4 className="text-xs font-bold uppercase tracking-wider text-gray-700">
|
<h4 className="text-xs font-bold uppercase tracking-wider text-gray-700">
|
||||||
Plantillas Canva WF5 · 4:5 feed + 9:16 Stories + 1.91:1 landscape
|
Plantillas Canva · Post + Story + LinkedIn (+ layouts Ads)
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-[11px] text-gray-500">
|
<p className="text-[11px] text-gray-500">
|
||||||
Pega el ID Canva (p. ej. EAHYK-l1SFM) o la URL completa de Brand
|
Pega el ID Canva o la URL de Brand Template. Post / Story /
|
||||||
Template. Se usa en Ads y RRSS al generar creatividades.
|
LinkedIn mandan en RRSS; el resto cubre variantes Ads.
|
||||||
</p>
|
</p>
|
||||||
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-6 gap-3">
|
<div className="grid grid-cols-1 md:grid-cols-3 lg:grid-cols-6 gap-3">
|
||||||
{(
|
{(
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
key: 'foto-con-franja' as const,
|
key: 'post' as const,
|
||||||
label: '4:5 · foto-con-franja',
|
label: 'Post (feed)',
|
||||||
placeholder: 'EAHYK-l1SFM o URL Canva',
|
placeholder: 'EAHYK-l1SFM o URL',
|
||||||
className:
|
className:
|
||||||
'w-full rounded-lg border border-gray-300 px-2.5 py-1.5 text-xs font-mono',
|
'w-full rounded-lg border border-emerald-300 bg-emerald-50/40 px-2.5 py-1.5 text-xs font-mono',
|
||||||
labelClass: 'block text-[11px] font-semibold text-gray-600 mb-1',
|
labelClass: 'block text-[11px] font-semibold text-emerald-800 mb-1',
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'tipografico' as const,
|
|
||||||
label: '4:5 · tipografico',
|
|
||||||
placeholder: 'EAH... o URL Canva',
|
|
||||||
className:
|
|
||||||
'w-full rounded-lg border border-gray-300 px-2.5 py-1.5 text-xs font-mono',
|
|
||||||
labelClass: 'block text-[11px] font-semibold text-gray-600 mb-1',
|
|
||||||
},
|
|
||||||
{
|
|
||||||
key: 'dato-grande' as const,
|
|
||||||
label: '4:5 · dato-grande',
|
|
||||||
placeholder: 'EAH... o URL Canva',
|
|
||||||
className:
|
|
||||||
'w-full rounded-lg border border-gray-300 px-2.5 py-1.5 text-xs font-mono',
|
|
||||||
labelClass: 'block text-[11px] font-semibold text-gray-600 mb-1',
|
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
key: 'stories_9_16' as const,
|
key: 'stories_9_16' as const,
|
||||||
label: '9:16 · Stories / Reels',
|
label: 'Story / Reels 9:16',
|
||||||
placeholder: 'EAH... (9:16)',
|
placeholder: 'EAHYK9p_MlY o URL',
|
||||||
className:
|
className:
|
||||||
'w-full rounded-lg border border-brand-300 bg-brand-50/30 px-2.5 py-1.5 text-xs font-mono',
|
'w-full rounded-lg border border-brand-300 bg-brand-50/30 px-2.5 py-1.5 text-xs font-mono',
|
||||||
labelClass: 'block text-[11px] font-semibold text-brand-700 mb-1',
|
labelClass: 'block text-[11px] font-semibold text-brand-700 mb-1',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
key: 'linkedin' as const,
|
||||||
|
label: 'LinkedIn',
|
||||||
|
placeholder: 'EAHYK_ylNJo o URL',
|
||||||
|
className:
|
||||||
|
'w-full rounded-lg border border-violet-300 bg-violet-50/40 px-2.5 py-1.5 text-xs font-mono',
|
||||||
|
labelClass: 'block text-[11px] font-semibold text-violet-800 mb-1',
|
||||||
|
},
|
||||||
|
{
|
||||||
|
key: 'foto-con-franja' as const,
|
||||||
|
label: '4:5 · foto-con-franja',
|
||||||
|
placeholder: 'EAH... (Ads)',
|
||||||
|
className:
|
||||||
|
'w-full rounded-lg border border-gray-300 px-2.5 py-1.5 text-xs font-mono',
|
||||||
|
labelClass: 'block text-[11px] font-semibold text-gray-600 mb-1',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
key: 'landscape_1_91' as const,
|
key: 'landscape_1_91' as const,
|
||||||
label: '1.91:1 · Landscape',
|
label: '1.91:1 · Landscape',
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
* Recommended structure (1 Brand Kit + 2 template groups):
|
* Recommended structure (1 Brand Kit + 2 template groups):
|
||||||
* canva_templates: {
|
* canva_templates: {
|
||||||
* ads: { "foto-con-franja", "tipografico", "dato-grande", "stories_9_16", "landscape_1_91", "default" },
|
* ads: { "foto-con-franja", "tipografico", "dato-grande", "stories_9_16", "landscape_1_91", "default" },
|
||||||
* rrss: { "foto-con-franja", "tipografico", "dato-grande", "stories_9_16", "default" },
|
* rrss: { "post", "foto-con-franja", "tipografico", "dato-grande", "stories_9_16", "story", "linkedin", "default" },
|
||||||
* // flat legacy keys still work as fallback for both
|
* // flat legacy keys still work as fallback for both
|
||||||
* }
|
* }
|
||||||
*
|
*
|
||||||
@@ -31,10 +31,13 @@ const ADS_KEYS = [
|
|||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const RRSS_KEYS = [
|
const RRSS_KEYS = [
|
||||||
|
'post',
|
||||||
'foto-con-franja',
|
'foto-con-franja',
|
||||||
'tipografico',
|
'tipografico',
|
||||||
'dato-grande',
|
'dato-grande',
|
||||||
'stories_9_16',
|
'stories_9_16',
|
||||||
|
'story',
|
||||||
|
'linkedin',
|
||||||
'default',
|
'default',
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
@@ -111,43 +114,84 @@ export function resolveCanvaTemplatesForChannel(
|
|||||||
|
|
||||||
export function canvaTemplateKeyForLayout(
|
export function canvaTemplateKeyForLayout(
|
||||||
layout: string | null | undefined,
|
layout: string | null | undefined,
|
||||||
channel: 'ads' | 'rrss'
|
channel: 'ads' | 'rrss',
|
||||||
|
platform?: string | null
|
||||||
): string {
|
): string {
|
||||||
const l = String(layout || '').toLowerCase();
|
const l = String(layout || '').toLowerCase();
|
||||||
|
const p = String(platform || '').toLowerCase();
|
||||||
|
if (channel === 'rrss' && p.includes('linkedin')) return 'linkedin';
|
||||||
if (l.includes('tipograf')) return 'tipografico';
|
if (l.includes('tipograf')) return 'tipografico';
|
||||||
if (l.includes('dato')) return 'dato-grande';
|
if (l.includes('dato')) return 'dato-grande';
|
||||||
if (channel === 'rrss' && (l.includes('stor') || l.includes('reel'))) {
|
if (channel === 'rrss' && (l.includes('stor') || l.includes('reel'))) {
|
||||||
return 'stories_9_16';
|
return 'stories_9_16';
|
||||||
}
|
}
|
||||||
return 'foto-con-franja';
|
if (channel === 'rrss' && (l.includes('post') || l.includes('feed') || !l)) {
|
||||||
|
return 'post';
|
||||||
|
}
|
||||||
|
return channel === 'rrss' ? 'post' : 'foto-con-franja';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Resolve canva_templates for n8n payloads.
|
* Resolve canva_templates for n8n payloads.
|
||||||
* Prefer nested ads/rrss; fall back to flat keys; BPS gets env default.
|
* Prefer nested ads/rrss; fall back to flat keys; BPS gets env default.
|
||||||
*/
|
*/
|
||||||
/** Known Brand Template defaults per client (Canva Brand Kit → Brand Templates). */
|
/** Single-ID fallback (all slots share one Brand Template). */
|
||||||
const TENANT_DEFAULT_CANVA: Record<string, string> = {
|
const TENANT_DEFAULT_CANVA: Record<string, string> = {
|
||||||
bps: process.env.BPS_CANVA_TEMPLATE_ID || 'EAHRb38v_WY',
|
bps: process.env.BPS_CANVA_TEMPLATE_ID || 'EAHRb38v_WY',
|
||||||
/** Agua Miia · https://www.canva.com/brand/brand-templates/EAHYK-l1SFM */
|
};
|
||||||
'agua-miia':
|
|
||||||
process.env.AGUA_MIIA_CANVA_TEMPLATE_ID || 'EAHYK-l1SFM',
|
/**
|
||||||
|
* Multi-template defaults per client (post / story / LinkedIn).
|
||||||
|
* Agua Miia:
|
||||||
|
* post https://www.canva.com/brand/brand-templates/EAHYK-l1SFM
|
||||||
|
* linkedin https://www.canva.com/brand/brand-templates/EAHYK_ylNJo
|
||||||
|
* story https://www.canva.com/brand/brand-templates/EAHYK9p_MlY
|
||||||
|
*/
|
||||||
|
const TENANT_DEFAULT_CANVA_MAPS: Record<string, CanvaTemplateMap> = {
|
||||||
|
'agua-miia': {
|
||||||
|
post: process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
'foto-con-franja': process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
tipografico: process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
'dato-grande': process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
default: process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
landscape_1_91: process.env.AGUA_MIIA_CANVA_POST_ID || 'EAHYK-l1SFM',
|
||||||
|
stories_9_16: process.env.AGUA_MIIA_CANVA_STORY_ID || 'EAHYK9p_MlY',
|
||||||
|
story: process.env.AGUA_MIIA_CANVA_STORY_ID || 'EAHYK9p_MlY',
|
||||||
|
linkedin: process.env.AGUA_MIIA_CANVA_LINKEDIN_ID || 'EAHYK_ylNJo',
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
function fillDefaultsFromId(templateId: string, channel: 'ads' | 'rrss'): CanvaTemplateMap {
|
function fillDefaultsFromId(templateId: string, channel: 'ads' | 'rrss'): CanvaTemplateMap {
|
||||||
const id = parseCanvaTemplateId(templateId);
|
const id = parseCanvaTemplateId(templateId);
|
||||||
if (!id) return {};
|
if (!id) return {};
|
||||||
const base: CanvaTemplateMap = {
|
const base: CanvaTemplateMap = {
|
||||||
|
post: id,
|
||||||
'foto-con-franja': id,
|
'foto-con-franja': id,
|
||||||
tipografico: id,
|
tipografico: id,
|
||||||
'dato-grande': id,
|
'dato-grande': id,
|
||||||
stories_9_16: id,
|
stories_9_16: id,
|
||||||
|
story: id,
|
||||||
default: id,
|
default: id,
|
||||||
};
|
};
|
||||||
if (channel === 'ads') base.landscape_1_91 = id;
|
if (channel === 'ads') base.landscape_1_91 = id;
|
||||||
return base;
|
return base;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function fillDefaultsFromMap(
|
||||||
|
defaults: CanvaTemplateMap,
|
||||||
|
channel: 'ads' | 'rrss'
|
||||||
|
): CanvaTemplateMap {
|
||||||
|
const out: CanvaTemplateMap = {};
|
||||||
|
for (const [k, v] of Object.entries(defaults)) {
|
||||||
|
const id = parseCanvaTemplateId(v);
|
||||||
|
if (id) out[k] = id;
|
||||||
|
}
|
||||||
|
if (channel === 'rrss') {
|
||||||
|
delete out.landscape_1_91;
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
export function resolveTenantCanvaTemplates(
|
export function resolveTenantCanvaTemplates(
|
||||||
raw: unknown,
|
raw: unknown,
|
||||||
opts?: { slug?: string | null; channel?: 'ads' | 'rrss' }
|
opts?: { slug?: string | null; channel?: 'ads' | 'rrss' }
|
||||||
@@ -155,11 +199,20 @@ export function resolveTenantCanvaTemplates(
|
|||||||
const channel = opts?.channel || 'ads';
|
const channel = opts?.channel || 'ads';
|
||||||
let map = resolveCanvaTemplatesForChannel(raw, channel);
|
let map = resolveCanvaTemplatesForChannel(raw, channel);
|
||||||
const slug = (opts?.slug || '').toLowerCase();
|
const slug = (opts?.slug || '').toLowerCase();
|
||||||
|
const mapDefaults = TENANT_DEFAULT_CANVA_MAPS[slug];
|
||||||
const fallbackId = TENANT_DEFAULT_CANVA[slug];
|
const fallbackId = TENANT_DEFAULT_CANVA[slug];
|
||||||
if (fallbackId && (!map || Object.keys(map).length === 0)) {
|
|
||||||
|
if (mapDefaults) {
|
||||||
|
const filled = fillDefaultsFromMap(mapDefaults, channel);
|
||||||
|
if (!map || Object.keys(map).length === 0) {
|
||||||
|
map = filled;
|
||||||
|
} else {
|
||||||
|
// Fill any missing slots (e.g. linkedin/story) from tenant defaults
|
||||||
|
map = { ...filled, ...map };
|
||||||
|
}
|
||||||
|
} else if (fallbackId && (!map || Object.keys(map).length === 0)) {
|
||||||
map = fillDefaultsFromId(fallbackId, channel);
|
map = fillDefaultsFromId(fallbackId, channel);
|
||||||
} else if (fallbackId && map && !map.default && !map['foto-con-franja']) {
|
} else if (fallbackId && map && !map.default && !map['foto-con-franja'] && !map.post) {
|
||||||
// Partial config: ensure at least default + feed layout
|
|
||||||
map = { ...fillDefaultsFromId(fallbackId, channel), ...map };
|
map = { ...fillDefaultsFromId(fallbackId, channel), ...map };
|
||||||
}
|
}
|
||||||
return map;
|
return map;
|
||||||
|
|||||||
@@ -14,11 +14,18 @@ export type RrssPlacement = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/** Placements per RRSS format (not the Ads triple 4:5+9:16+1.91:1). */
|
/** Placements per RRSS format (not the Ads triple 4:5+9:16+1.91:1). */
|
||||||
export function rrssBriefAspectFields(format: RrssPipelineFormat): {
|
export function rrssBriefAspectFields(
|
||||||
|
format: RrssPipelineFormat,
|
||||||
|
platform?: string | null
|
||||||
|
): {
|
||||||
aspect_ratio: string;
|
aspect_ratio: string;
|
||||||
aspect_ratios: string[];
|
aspect_ratios: string[];
|
||||||
required_placements: RrssPlacement[];
|
required_placements: RrssPlacement[];
|
||||||
} {
|
} {
|
||||||
|
const isLinkedIn = String(platform || '')
|
||||||
|
.toLowerCase()
|
||||||
|
.includes('linkedin');
|
||||||
|
|
||||||
if (format === 'story') {
|
if (format === 'story') {
|
||||||
const p: RrssPlacement = {
|
const p: RrssPlacement = {
|
||||||
aspect_ratio: '9:16',
|
aspect_ratio: '9:16',
|
||||||
@@ -39,13 +46,23 @@ export function rrssBriefAspectFields(format: RrssPipelineFormat): {
|
|||||||
};
|
};
|
||||||
return { aspect_ratio: '9:16', aspect_ratios: ['9:16'], required_placements: [p] };
|
return { aspect_ratio: '9:16', aspect_ratios: ['9:16'], required_placements: [p] };
|
||||||
}
|
}
|
||||||
|
if (isLinkedIn) {
|
||||||
|
const p: RrssPlacement = {
|
||||||
|
aspect_ratio: '1:1',
|
||||||
|
role: 'linkedin',
|
||||||
|
size: '1080x1080',
|
||||||
|
meta_key: 'asset_url',
|
||||||
|
canva_template_key: 'linkedin',
|
||||||
|
};
|
||||||
|
return { aspect_ratio: '1:1', aspect_ratios: ['1:1'], required_placements: [p] };
|
||||||
|
}
|
||||||
if (format === 'carrusel') {
|
if (format === 'carrusel') {
|
||||||
const p: RrssPlacement = {
|
const p: RrssPlacement = {
|
||||||
aspect_ratio: '4:5',
|
aspect_ratio: '4:5',
|
||||||
role: 'carousel_slide',
|
role: 'carousel_slide',
|
||||||
size: '1080x1350',
|
size: '1080x1350',
|
||||||
meta_key: 'asset_url',
|
meta_key: 'asset_url',
|
||||||
canva_template_key: 'foto-con-franja',
|
canva_template_key: 'post',
|
||||||
};
|
};
|
||||||
return {
|
return {
|
||||||
aspect_ratio: '4:5',
|
aspect_ratio: '4:5',
|
||||||
@@ -53,13 +70,13 @@ export function rrssBriefAspectFields(format: RrssPipelineFormat): {
|
|||||||
required_placements: [p],
|
required_placements: [p],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
// post feed
|
// post feed (IG/FB)
|
||||||
const p: RrssPlacement = {
|
const p: RrssPlacement = {
|
||||||
aspect_ratio: '4:5',
|
aspect_ratio: '4:5',
|
||||||
role: 'feed',
|
role: 'feed',
|
||||||
size: '1080x1350',
|
size: '1080x1350',
|
||||||
meta_key: 'asset_url',
|
meta_key: 'asset_url',
|
||||||
canva_template_key: 'foto-con-franja',
|
canva_template_key: 'post',
|
||||||
};
|
};
|
||||||
return { aspect_ratio: '4:5', aspect_ratios: ['4:5'], required_placements: [p] };
|
return { aspect_ratio: '4:5', aspect_ratios: ['4:5'], required_placements: [p] };
|
||||||
}
|
}
|
||||||
@@ -99,6 +116,7 @@ export type RrssGenerationBriefInput = {
|
|||||||
pillar?: string | null;
|
pillar?: string | null;
|
||||||
month?: string | null;
|
month?: string | null;
|
||||||
scheduledAt?: string | null;
|
scheduledAt?: string | null;
|
||||||
|
platform?: string | null;
|
||||||
calendarPiece?: RrssCalendarPieceBrief | null;
|
calendarPiece?: RrssCalendarPieceBrief | null;
|
||||||
/** Recent pipeline captions/titles for style continuity */
|
/** Recent pipeline captions/titles for style continuity */
|
||||||
recentPipeline?: Array<{ title: string; format: string; caption?: string | null }>;
|
recentPipeline?: Array<{ title: string; format: string; caption?: string | null }>;
|
||||||
@@ -113,8 +131,12 @@ export type RrssGenerationBriefInput = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export function buildRrssGenerationBrief(input: RrssGenerationBriefInput) {
|
export function buildRrssGenerationBrief(input: RrssGenerationBriefInput) {
|
||||||
const aspects = rrssBriefAspectFields(input.format);
|
|
||||||
const cal = input.calendarPiece || {};
|
const cal = input.calendarPiece || {};
|
||||||
|
const platform =
|
||||||
|
input.platform ||
|
||||||
|
(typeof cal.platform === 'string' ? cal.platform : null) ||
|
||||||
|
null;
|
||||||
|
const aspects = rrssBriefAspectFields(input.format, platform);
|
||||||
return {
|
return {
|
||||||
channel: 'rrss' as const,
|
channel: 'rrss' as const,
|
||||||
tenant_id: input.tenantId,
|
tenant_id: input.tenantId,
|
||||||
@@ -127,6 +149,7 @@ export function buildRrssGenerationBrief(input: RrssGenerationBriefInput) {
|
|||||||
source_pipeline_id: input.pipelineId,
|
source_pipeline_id: input.pipelineId,
|
||||||
calendar_piece_id: input.calendarPieceId || cal.id || null,
|
calendar_piece_id: input.calendarPieceId || cal.id || null,
|
||||||
format: input.format,
|
format: input.format,
|
||||||
|
platform,
|
||||||
skill_format: mapRrssFormatToSkillFormat(input.format),
|
skill_format: mapRrssFormatToSkillFormat(input.format),
|
||||||
...aspects,
|
...aspects,
|
||||||
variants_requested: Number(input.variantsRequested || 2),
|
variants_requested: Number(input.variantsRequested || 2),
|
||||||
|
|||||||
Reference in New Issue
Block a user