import OpenAI from "openai"; import { os } from "@orpc/server"; import { z } from "zod"; import { zodResponseFormat } from "../../lib/openai"; if (!process.env.OPENAI_BASE_URL) { throw new Error("OPENAI_BASE_URL is not set"); } if (!process.env.OPENAI_API_KEY) { throw new Error("OPENAI_API_KEY is not set"); } const openai = new OpenAI({ baseURL: process.env.OPENAI_BASE_URL, apiKey: process.env.OPENAI_API_KEY, }); if (!process.env.OPENAI_DEFAULT_MODEL) { throw new Error("OPENAI_DEFAULT_MODEL is not set"); } const DEFAULT_MODEL = process.env.OPENAI_DEFAULT_MODEL; const ChatCompletionInputSchema = z.object({ message: z.string(), systemPrompt: z.string().optional(), }); const GeneratePersonInputSchema = z.object({ prompt: z.string(), }); const complete = os .input(ChatCompletionInputSchema) .handler(async ({ input }) => { const { message, systemPrompt } = input; const completion = await openai.chat.completions.create({ model: DEFAULT_MODEL, messages: [ ...(systemPrompt ? [{ role: "system", content: systemPrompt }] : []), { role: "user", content: message }, ], }); return { response: completion.choices[0]?.message?.content || "", }; }); // Object generation schemas only support nullability, not optionality. // Use .nullable() instead of .optional() for fields that may not have values. const DemoSchema = z.object({ name: z.string().describe("The name of the person"), age: z.number().describe("The age of the person"), occupation: z.string().describe("The occupation of the person"), bio: z.string().describe("The bio of the person"), nickname: z .string() .nullable() .describe("The person's nickname, if they have one"), }); const generate = os .input(GeneratePersonInputSchema) .handler(async ({ input }) => { const completion = await openai.chat.completions.parse({ model: DEFAULT_MODEL, messages: [ { role: "user", content: `Generate a person based on this prompt: ${input.prompt}`, }, ], response_format: zodResponseFormat(DemoSchema, "person"), }); const person = completion.choices[0]?.message?.parsed; if (!person) { throw new Error("No parsed data received from OpenAI"); } return { person, }; }); export const router = { complete, generate, };