73 lines
2.7 KiB
TypeScript
73 lines
2.7 KiB
TypeScript
import { z } from "zod";
|
||
import type { ProviderApiKeys } from "./keys";
|
||
import { withAgentSystem } from "./agent";
|
||
import { generateStructuredObject } from "./generate-structured";
|
||
import { HASHTAG_USER_REMINDER, HASHTAG_WRITING_RULES } from "./hashtag-rules";
|
||
import { buildPersonaPromptBlock } from "./persona";
|
||
import { getModel } from "./provider";
|
||
import { THREADS_MAX_CHARS } from "@/lib/utils";
|
||
import type { ViralAnalysis } from "@/lib/types/viral";
|
||
|
||
const replicaSchema = z.object({
|
||
angle: z.string(),
|
||
hook: z.string(),
|
||
text: z.string().max(THREADS_MAX_CHARS),
|
||
imageBrief: z.string(),
|
||
rationale: z.string(),
|
||
structureNotes: z.string(),
|
||
});
|
||
|
||
export interface ReplicateViralInput {
|
||
originalText: string;
|
||
authorName?: string | null;
|
||
viralAnalysis: ViralAnalysis;
|
||
topicLabel: string;
|
||
topicBrief?: string | null;
|
||
persona?: string | null;
|
||
aiProvider: string;
|
||
aiModel: string;
|
||
apiKeys?: ProviderApiKeys;
|
||
}
|
||
|
||
export async function replicateViralPost(input: ReplicateViralInput) {
|
||
const model = getModel(input.aiProvider, input.aiModel, input.apiKeys ?? {});
|
||
|
||
const object = await generateStructuredObject({
|
||
model,
|
||
provider: input.aiProvider,
|
||
modelId: input.aiModel,
|
||
schema: replicaSchema,
|
||
system: withAgentSystem(`你是 Threads 爆款複製策略師。根據爆款分析報告,為使用者撰寫「同結構、同節奏、但完全原創」的貼文。
|
||
|
||
${buildPersonaPromptBlock(input.persona)}
|
||
|
||
規則:
|
||
- 複製的是「爆款公式」(hook 手法、情緒節奏、圖文配合),不是抄襲原文
|
||
- 文筆必須像創作者本人,不是只複製爆款語氣
|
||
- text ≤ 500 字(含 #話題標籤)
|
||
${HASHTAG_WRITING_RULES}
|
||
- imageBrief 描述要產出的配圖:版面、配色、圖上文字、風格(繁體中文台灣用語,具體可執行)`),
|
||
prompt: `主題:${input.topicLabel}
|
||
${input.topicBrief ? `Brief:${input.topicBrief}` : ""}
|
||
|
||
原文參考(@${input.authorName ?? "匿名"},只學結構不抄內容):
|
||
${input.originalText}
|
||
|
||
爆款分析:
|
||
- 爆紅原因:${input.viralAnalysis.whyViral.join(";")}
|
||
- Hook 手法:${input.viralAnalysis.hookPattern}
|
||
- 結構:${input.viralAnalysis.structurePattern}
|
||
- 情緒觸發:${input.viralAnalysis.emotionalTrigger}
|
||
- 留言共鳴:${input.viralAnalysis.commentInsights.whyPeopleEngage}
|
||
- 複製策略:${input.viralAnalysis.replicationStrategy}
|
||
- 圖文策略:${input.viralAnalysis.visualAnalysis.replicationTips.join(";")}
|
||
- 繪圖 prompt 參考:${input.viralAnalysis.visualAnalysis.imageGenPrompt}
|
||
|
||
請產出一篇可發布的複製版貼文 + 配圖製作說明。${HASHTAG_USER_REMINDER}`,
|
||
});
|
||
|
||
return {
|
||
...object,
|
||
text: object.text.slice(0, THREADS_MAX_CHARS),
|
||
};
|
||
} |