export type CtaType = 'none' | 'link' | 'dm' | 'follow' export type ProductContextFields = { brand: string product: string features: string placementTone?: string ctaType?: CtaType ctaUrl?: string } export const CTA_TYPE_OPTIONS: Array<{ value: CtaType; label: string }> = [ { value: 'none', label: '(無)不主動帶 CTA' }, { value: 'link', label: '連結(可填網址)' }, { value: 'dm', label: '私訊' }, { value: 'follow', label: '追蹤' }, ] export const EMPTY_PRODUCT_CONTEXT: ProductContextFields = { brand: '', product: '', features: '', placementTone: '', ctaType: 'none', ctaUrl: '', } function normalizeCtaType(value: unknown): CtaType { return value === 'link' || value === 'dm' || value === 'follow' ? value : 'none' } export function parseProductContext(raw: string | null | undefined): ProductContextFields { if (!raw?.trim()) return { ...EMPTY_PRODUCT_CONTEXT } try { const parsed = JSON.parse(raw) as Partial if (parsed && typeof parsed === 'object') { return { brand: parsed.brand?.trim() ?? '', product: parsed.product?.trim() ?? '', features: parsed.features?.trim() ?? '', placementTone: parsed.placementTone?.trim() ?? '', ctaType: normalizeCtaType(parsed.ctaType), ctaUrl: parsed.ctaUrl?.trim() ?? '', } } } catch { return { ...EMPTY_PRODUCT_CONTEXT, features: raw.trim() } } return { ...EMPTY_PRODUCT_CONTEXT } } export function serializeProductContext(fields: ProductContextFields): string { const brand = fields.brand.trim() const product = fields.product.trim() const features = fields.features.trim() const placementTone = fields.placementTone?.trim() ?? '' const ctaType = normalizeCtaType(fields.ctaType) const ctaUrl = fields.ctaUrl?.trim() ?? '' if (!brand && !product && !features && !placementTone && ctaType === 'none' && !ctaUrl) { return '' } return JSON.stringify({ brand, product, features, placementTone, ctaType, ctaUrl }) } export function hasProductContext(raw: string | null | undefined): boolean { const fields = parseProductContext(raw) return !!(fields.brand || fields.product || fields.features) } export function summarizeProductContext(raw: string | null | undefined): string | null { const fields = parseProductContext(raw) const parts = [fields.brand, fields.product, fields.features].filter(Boolean) return parts.length > 0 ? parts.join(' · ') : null } export function formatProductContextForPrompt(raw: string | null | undefined): string { const fields = parseProductContext(raw) const lines: string[] = [] if (fields.brand) lines.push(`品牌:${fields.brand}`) if (fields.product) lines.push(`產品:${fields.product}`) if (fields.features) lines.push(`特色/能幫上忙的地方:${fields.features}`) if (fields.placementTone) lines.push(`置入語氣偏好:${fields.placementTone}`) if (fields.ctaType === 'link' && fields.ctaUrl) lines.push(`留言 CTA 連結:${fields.ctaUrl}`) else if (fields.ctaType === 'dm') lines.push('留言 CTA:引導私訊') else if (fields.ctaType === 'follow') lines.push('留言 CTA:引導追蹤') return lines.join('\n') }