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

100 lines
3.8 KiB
TypeScript
Raw Permalink Normal View History

2026-06-21 12:50:31 +00:00
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;
}