75 lines
2.5 KiB
TypeScript
75 lines
2.5 KiB
TypeScript
|
|
import { z } from "zod";
|
|||
|
|
import type { ProviderApiKeys } from "./keys";
|
|||
|
|
import { generateStructuredObject } from "./generate-structured";
|
|||
|
|
import { getModel } from "./provider";
|
|||
|
|
import { HASHTAG_WRITING_RULES } from "./hashtag-rules";
|
|||
|
|
import { buildSystemPrompt } from "./prompts";
|
|||
|
|
import { THREADS_MAX_CHARS } from "@/lib/utils";
|
|||
|
|
|
|||
|
|
export type OptimizeMode = "polish" | "hook" | "shorter" | "engaging" | "custom";
|
|||
|
|
|
|||
|
|
const MODE_INSTRUCTIONS: Record<Exclude<OptimizeMode, "custom">, string> = {
|
|||
|
|
polish: "整體潤飾:改善語氣流暢度、可讀性與說服力,保留核心觀點。",
|
|||
|
|
hook: "強化開頭 hook:讓前 1–2 句更有吸引力,讓人想停下來看。",
|
|||
|
|
shorter: "精簡篇幅:刪除贅字,保留重點,盡量壓到更短但不失完整。",
|
|||
|
|
engaging: "提升互動感:加入引發留言的問句、觀點或行動呼籲,但不過度推銷。",
|
|||
|
|
};
|
|||
|
|
|
|||
|
|
const optimizeSchema = z.object({
|
|||
|
|
text: z.string().max(THREADS_MAX_CHARS),
|
|||
|
|
summary: z.string(),
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
export interface OptimizeInput {
|
|||
|
|
text: string;
|
|||
|
|
mode?: OptimizeMode;
|
|||
|
|
instruction?: string | null;
|
|||
|
|
persona?: string | null;
|
|||
|
|
angle?: string | null;
|
|||
|
|
aiProvider: string;
|
|||
|
|
aiModel: string;
|
|||
|
|
apiKeys?: ProviderApiKeys;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
export async function optimizePost(input: OptimizeInput) {
|
|||
|
|
const mode = input.mode ?? "polish";
|
|||
|
|
const modeInstruction =
|
|||
|
|
mode === "custom"
|
|||
|
|
? input.instruction?.trim() || "依照使用者指示優化貼文。"
|
|||
|
|
: MODE_INSTRUCTIONS[mode];
|
|||
|
|
|
|||
|
|
const model = getModel(input.aiProvider, input.aiModel, input.apiKeys ?? {});
|
|||
|
|
|
|||
|
|
const object = await generateStructuredObject({
|
|||
|
|
model,
|
|||
|
|
provider: input.aiProvider,
|
|||
|
|
modelId: input.aiModel,
|
|||
|
|
schema: optimizeSchema,
|
|||
|
|
system: `${buildSystemPrompt(input.persona)}
|
|||
|
|
|
|||
|
|
你現在的任務是「優化既有 Threads 貼文草稿」,不是從零重寫。
|
|||
|
|
- 保留原文核心觀點與事實,不要捏造
|
|||
|
|
- 優化後必須更符合上方人設,尤其語氣與代表句範例的語感
|
|||
|
|
- 保留或補上結尾的 1~3 個 #話題標籤,不要優化掉
|
|||
|
|
${HASHTAG_WRITING_RULES}
|
|||
|
|
- 輸出繁體中文台灣用語
|
|||
|
|
- 字數必須 ≤ ${THREADS_MAX_CHARS}
|
|||
|
|
- summary 用 1–2 句話說明你做了什麼調整`,
|
|||
|
|
prompt: `請優化以下 Threads 貼文草稿。
|
|||
|
|
|
|||
|
|
優化方向:${modeInstruction}
|
|||
|
|
${input.angle ? `切入角度:${input.angle}` : ""}
|
|||
|
|
|
|||
|
|
原文:
|
|||
|
|
"""
|
|||
|
|
${input.text}
|
|||
|
|
"""
|
|||
|
|
|
|||
|
|
請輸出優化後的貼文(text)與調整說明(summary)。`,
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
return {
|
|||
|
|
text: object.text.slice(0, THREADS_MAX_CHARS),
|
|||
|
|
summary: object.summary,
|
|||
|
|
};
|
|||
|
|
}
|