54 lines
2.2 KiB
TypeScript
54 lines
2.2 KiB
TypeScript
import { z } from "zod";
|
||
import { openai, SCRIPT_MODEL } from "@/lib/ai/openai";
|
||
import type { StructuredScript, TokenUsage } from "@/lib/ai/types";
|
||
|
||
export type RepurposeFormat = "blog" | "social_thread" | "newsletter";
|
||
|
||
const FORMAT_PROMPTS: Record<RepurposeFormat, string> = {
|
||
blog: "Write an engaging, SEO-friendly blog post based on this episode. Include a compelling title and well-structured markdown body with headings and a short conclusion.",
|
||
social_thread:
|
||
"Write a punchy social thread (6–10 posts, numbered) summarizing the episode's best insights. Start with a strong hook. Put the whole thread in the markdown body.",
|
||
newsletter:
|
||
"Write a friendly email newsletter edition about this episode: a subject line as the title, a short intro, 3–4 key takeaways as bullets, and a call-to-action to listen. Markdown body.",
|
||
};
|
||
|
||
const outputSchema = z.object({ title: z.string().min(1), body: z.string().min(1) });
|
||
export type RepurposedOutput = z.infer<typeof outputSchema>;
|
||
|
||
function scriptToText(script: StructuredScript): string {
|
||
return script.sections
|
||
.map((s) => `## ${s.title}\n` + s.turns.map((t) => t.text).join("\n"))
|
||
.join("\n\n");
|
||
}
|
||
|
||
export async function repurposeScript(
|
||
script: StructuredScript,
|
||
format: RepurposeFormat
|
||
): Promise<{ content: RepurposedOutput; usage: TokenUsage }> {
|
||
const transcript = scriptToText(script).slice(0, 9000);
|
||
const res = await openai().chat.completions.create({
|
||
model: SCRIPT_MODEL,
|
||
messages: [
|
||
{
|
||
role: "system",
|
||
content:
|
||
"You are a content marketer who repurposes podcast episodes into other formats. Return STRICT JSON: { \"title\": string, \"body\": string } where body is markdown.",
|
||
},
|
||
{
|
||
role: "user",
|
||
content: `${FORMAT_PROMPTS[format]}\n\nEpisode title: ${script.title}\n\nTranscript:\n${transcript}`,
|
||
},
|
||
],
|
||
response_format: { type: "json_object" },
|
||
temperature: 0.7,
|
||
});
|
||
const content = outputSchema.parse(JSON.parse(res.choices[0]?.message?.content ?? "{}"));
|
||
return {
|
||
content,
|
||
usage: {
|
||
inputTokens: res.usage?.prompt_tokens ?? 0,
|
||
outputTokens: res.usage?.completion_tokens ?? 0,
|
||
},
|
||
};
|
||
}
|