haixunMaster/lib/ai/generate-account-strategy.ts

100 lines
3.8 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { z } from "zod";
import type { ProviderApiKeys } from "./keys";
import { generateStructuredObject } from "./generate-structured";
import { getModel } from "./provider";
const nullableText = z.string().nullable().default(null);
const style8DSchema = z.object({
d1Tone: nullableText,
d2Structure: nullableText,
d3Interaction: nullableText,
d4Topics: nullableText,
d5Rhythm: nullableText,
d6Visual: nullableText,
d7Conversion: nullableText,
d8Risk: nullableText,
}).default({});
const accountStrategySchema = z.object({
message: z.string().default("我已依照你的方向更新帳號策略。"),
fields: z.object({
displayName: nullableText,
username: nullableText,
brief: nullableText,
persona: nullableText,
targetAudience: nullableText,
productBrief: nullableText,
goals: nullableText,
style8D: style8DSchema,
}).default({}),
});
export type AccountStrategyFields = z.infer<typeof accountStrategySchema>["fields"];
function normalizeAccountStrategy(value: unknown): unknown {
if (!value || typeof value !== "object") return value;
let root = value as Record<string, unknown>;
for (const key of ["result", "data", "output", "strategy"]) {
const nested = root[key];
if (nested && typeof nested === "object" && !Array.isArray(nested)) {
root = nested as Record<string, unknown>;
break;
}
}
const fieldsValue = root.fields ?? root.form ?? root.account ?? root;
const fields = fieldsValue && typeof fieldsValue === "object" && !Array.isArray(fieldsValue)
? { ...(fieldsValue as Record<string, unknown>) }
: {};
fields.style8D ??= fields.style8d ?? root.style8D ?? root.style8d;
return {
message: root.message ?? root.reply ?? root.summary,
fields,
};
}
export async function generateAccountStrategy(input: {
instruction: string;
current: Partial<AccountStrategyFields> & {
style8D?: Partial<AccountStrategyFields["style8D"]>;
};
aiProvider: string;
aiModel: string;
apiKeys?: ProviderApiKeys;
}) {
const model = getModel(input.aiProvider, input.aiModel, input.apiKeys ?? {});
const object = await generateStructuredObject({
model,
provider: input.aiProvider,
modelId: input.aiModel,
schema: accountStrategySchema,
system: `你是 Threads 帳號策略顧問,也是產品 onboarding 助手。
你的任務:根據使用者自然語言,幫他把「帳號策略表單」補成可直接使用的內容。
填寫原則:
- 使用繁體中文、台灣語感
- 內容要具體、可執行,不要空泛
- 不要使用誇大承諾或保證結果
- 如果使用者提到醫療、健康、營養、心理等高敏感領域,語氣要合規:避免療效保證、診斷語氣、恐嚇式行銷;可以強調衛教、陪伴、風險提醒、就醫建議
- 優先補齊空欄位;已有內容可優化,但不要完全無視原本方向
- username 不確定時回傳 null不要亂編
- displayName 可用使用者描述推測一個給自己看的名稱
- 使用者提到 8D、語氣、結構、互動、主題、節奏、視覺、轉換或風險時直接更新 fields.style8D 對應欄位
- 沒有要求修改的 8D 維度回傳 null不要覆蓋現有內容
- message 用 1-2 句說明你幫他補了什麼`,
prompt: `目前表單內容:
${JSON.stringify(input.current, null, 2)}
使用者跟小幫手說:
${input.instruction}
請回傳可套用到表單的欄位。`,
normalize: normalizeAccountStrategy,
jsonPromptSuffix: `\n\n只回傳以下 JSON不要 markdown\n{"message":"","fields":{"displayName":null,"username":null,"brief":null,"persona":null,"targetAudience":null,"productBrief":null,"goals":null,"style8D":{"d1Tone":null,"d2Structure":null,"d3Interaction":null,"d4Topics":null,"d5Rhythm":null,"d6Visual":null,"d7Conversion":null,"d8Risk":null}}}`,
});
return object;
}