function asString(value: unknown): string { if (typeof value === "string") return value.trim(); if (typeof value === "number" || typeof value === "boolean") return String(value); return ""; } function asNumber(value: unknown, fallback: number): number { if (typeof value === "number" && Number.isFinite(value)) return value; const raw = asString(value); if (!raw) return fallback; const parsed = Number(raw); return Number.isFinite(parsed) ? parsed : fallback; } function pickDraftText(obj: Record): string { return asString( obj.text ?? obj.comment ?? obj.reply ?? obj.content ?? obj.message ?? obj.body ?? obj.draft ?? obj.留言 ?? obj.回覆 ); } function coerceOutreachDraftItem(value: unknown): { text: string; angle: string; rationale: string; } | null { if (typeof value === "string") { const text = value.trim(); if (!text) return null; return { text, angle: "置入留言", rationale: "AI 產生的留言草稿" }; } if (!value || typeof value !== "object") return null; const obj = value as Record; const text = pickDraftText(obj); if (!text) return null; return { text, angle: asString(obj.angle ?? obj.strategy ?? obj.type ?? obj.approach ?? obj.切角) || "置入留言", rationale: asString(obj.rationale ?? obj.reason ?? obj.explanation ?? obj.說明 ?? obj.note) || "符合貼文情境的自然留言", }; } function coerceInboundDraftItem(value: unknown): { text: string; rationale: string } | null { if (typeof value === "string") { const text = value.trim(); if (!text) return null; return { text, rationale: "AI 產生的回覆草稿" }; } if (!value || typeof value !== "object") return null; const obj = value as Record; const text = pickDraftText(obj); if (!text) return null; return { text, rationale: asString(obj.rationale ?? obj.reason ?? obj.explanation ?? obj.說明) || "回覆這則留言", }; } function coerceDraftsArray( value: unknown, coerceItem: (item: unknown) => T | null, count: number ): T[] { const items: T[] = []; if (Array.isArray(value)) { for (const item of value) { const coerced = coerceItem(item); if (coerced) items.push(coerced); if (items.length >= count) return items; } } if (value && typeof value === "object" && !Array.isArray(value)) { for (const item of Object.values(value as Record)) { const coerced = coerceItem(item); if (coerced) items.push(coerced); if (items.length >= count) return items; } } return items; } export function coerceOutreachDraftsRaw(parsed: unknown, count = 2) { const root = parsed && typeof parsed === "object" ? (parsed as Record) : {}; const nested = root.result && typeof root.result === "object" ? (root.result as Record) : root; const relevance = Math.min( 1, Math.max(0, asNumber(nested.relevance ?? nested.score ?? nested.fit, 0.65)) ); const reason = asString(nested.reason ?? nested.summary ?? nested.why ?? nested.評估) || "符合置入情境"; const drafts = coerceDraftsArray( nested.drafts ?? nested.comments ?? nested.replies ?? nested.options ?? nested.草稿, coerceOutreachDraftItem, count ); return { relevance, reason, drafts }; } export function coerceInboundReplyDraftsRaw(parsed: unknown, count = 2) { const root = parsed && typeof parsed === "object" ? (parsed as Record) : {}; const nested = root.result && typeof root.result === "object" ? (root.result as Record) : root; const sentimentRaw = asString(nested.sentiment ?? nested.tone ?? nested.情緒).toLowerCase(); const sentiment = sentimentRaw === "positive" || sentimentRaw === "neutral" || sentimentRaw === "negative" || sentimentRaw === "question" || sentimentRaw === "lead" ? sentimentRaw : "neutral"; const intent = asString(nested.intent ?? nested.intention ?? nested.意圖) || "一般互動"; const drafts = coerceDraftsArray( nested.drafts ?? nested.replies ?? nested.responses ?? nested.options ?? nested.草稿, coerceInboundDraftItem, count ); return { sentiment, intent, drafts }; }