49 lines
1.6 KiB
TypeScript
49 lines
1.6 KiB
TypeScript
import { z } from "zod";
|
|
import { openai, SCRIPT_MODEL } from "./openai";
|
|
import type { TokenUsage } from "./types";
|
|
|
|
const seasonSchema = z.object({
|
|
title: z.string().min(1),
|
|
description: z.string().min(1),
|
|
episodes: z
|
|
.array(z.object({ title: z.string().min(1), topic: z.string().min(1), summary: z.string().min(1) }))
|
|
.min(1),
|
|
});
|
|
|
|
export type SeasonPlan = z.infer<typeof seasonSchema>;
|
|
|
|
export async function planSeason(input: {
|
|
theme: string;
|
|
count: number;
|
|
tone: string;
|
|
audience?: string;
|
|
language: string;
|
|
}): Promise<{ plan: SeasonPlan; usage: TokenUsage }> {
|
|
const res = await openai().chat.completions.create({
|
|
model: SCRIPT_MODEL,
|
|
messages: [
|
|
{
|
|
role: "system",
|
|
content:
|
|
"You are a podcast showrunner planning a cohesive season. Return STRICT JSON: { \"title\": string, \"description\": string, \"episodes\": [{ \"title\": string, \"topic\": string, \"summary\": string }] }.",
|
|
},
|
|
{
|
|
role: "user",
|
|
content: `Plan a ${input.count}-episode podcast season about: ${input.theme}.
|
|
Tone: ${input.tone}. ${input.audience ? `Audience: ${input.audience}.` : ""} Language: ${input.language}.
|
|
Give the season a title and short description, then ${input.count} episodes, each with a catchy title, a specific topic to cover, and a one-sentence summary.`,
|
|
},
|
|
],
|
|
response_format: { type: "json_object" },
|
|
temperature: 0.85,
|
|
});
|
|
const plan = seasonSchema.parse(JSON.parse(res.choices[0]?.message?.content ?? "{}"));
|
|
return {
|
|
plan,
|
|
usage: {
|
|
inputTokens: res.usage?.prompt_tokens ?? 0,
|
|
outputTokens: res.usage?.completion_tokens ?? 0,
|
|
},
|
|
};
|
|
}
|