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,
|
|||
|
|
},
|
|||
|
|
};
|
|||
|
|
}
|