first commit
This commit is contained in:
+69
@@ -0,0 +1,69 @@
|
||||
import { z } from "zod";
|
||||
|
||||
const SYSTEM_PROMPT = `You are a film research assistant for an international audience.
|
||||
You MUST respond in English with valid JSON only — no markdown fences, no commentary.
|
||||
Use a clear, neutral tone. If uncertain about a scene or timestamp, state uncertainty and set confidence to "low".
|
||||
Do not invent scenes, quotes, or timestamps. Base answers on the movie context provided.`;
|
||||
|
||||
export async function generateStructuredResponse<T extends z.ZodType>(
|
||||
schema: T,
|
||||
userPrompt: string,
|
||||
): Promise<z.infer<T>> {
|
||||
const apiKey = process.env.LLM_API_KEY;
|
||||
if (!apiKey) {
|
||||
throw new Error("LLM_API_KEY is not set");
|
||||
}
|
||||
|
||||
const baseUrl = process.env.LLM_BASE_URL ?? "https://api.openai.com/v1";
|
||||
const model = process.env.LLM_MODEL ?? "gpt-4o-mini";
|
||||
|
||||
const headers: Record<string, string> = {
|
||||
Authorization: `Bearer ${apiKey}`,
|
||||
"Content-Type": "application/json",
|
||||
};
|
||||
|
||||
if (process.env.LLM_HTTP_REFERER) {
|
||||
headers["HTTP-Referer"] = process.env.LLM_HTTP_REFERER;
|
||||
}
|
||||
|
||||
if (process.env.LLM_APP_TITLE) {
|
||||
headers["X-Title"] = process.env.LLM_APP_TITLE;
|
||||
}
|
||||
|
||||
const response = await fetch(`${baseUrl}/chat/completions`, {
|
||||
method: "POST",
|
||||
headers,
|
||||
body: JSON.stringify({
|
||||
model,
|
||||
temperature: 0.2,
|
||||
response_format: { type: "json_object" },
|
||||
messages: [
|
||||
{ role: "system", content: SYSTEM_PROMPT },
|
||||
{ role: "user", content: userPrompt },
|
||||
],
|
||||
}),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorText = await response.text();
|
||||
throw new Error(`LLM request failed: ${response.status} ${errorText}`);
|
||||
}
|
||||
|
||||
const data = (await response.json()) as {
|
||||
choices: Array<{ message: { content: string } }>;
|
||||
};
|
||||
|
||||
const content = data.choices[0]?.message?.content;
|
||||
if (!content) {
|
||||
throw new Error("LLM returned empty content");
|
||||
}
|
||||
|
||||
let parsed: unknown;
|
||||
try {
|
||||
parsed = JSON.parse(content);
|
||||
} catch {
|
||||
throw new Error("LLM returned invalid JSON");
|
||||
}
|
||||
|
||||
return schema.parse(parsed);
|
||||
}
|
||||
Reference in New Issue
Block a user