diff --git a/.env.example b/.env.example index 96570a3d..925f1278 100644 --- a/.env.example +++ b/.env.example @@ -57,4 +57,6 @@ LIVEKIT_API_SECRET= AI_PROVIDER=anthropic AI_MODEL=claude-sonnet-4-20250514 AI_EFFORT=medium -AI_API_KEY= \ No newline at end of file +AI_API_KEY= +# If blank default is used +OPENAI_BASE_URL=https://openrouter.ai/api/v1 diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index 81da7475..d5a9c765 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -178,68 +178,105 @@ export class ServerAI extends System { class OpenAIClient { constructor(apiKey, model, effort) { - this.client = new OpenAI({ apiKey }) + const config = { apiKey } + + // Check for custom base URL override + const baseURL = process.env.OPENAI_BASE_URL + if (baseURL) { + config.baseURL = baseURL + } + + this.client = new OpenAI(config) this.model = model this.effort = effort } + async create(prompt) { - const resp = await this.client.responses.create({ + const resp = await this.client.chat.completions.create({ model: this.model, - reasoning: { effort: this.effort }, - // max_output_tokens: 8192, - instructions: ` - ${docs} - =============== - You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, - input: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, + max_tokens: 8192, + messages: [ + { + role: 'system', + content: ` + ${docs} + =============== + You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, + }, + { + role: 'user', + content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, + }, + ], }) - return resp.output_text + return resp.choices[0].message.content } async edit(code, prompt) { - const resp = await this.client.responses.create({ + const resp = await this.client.chat.completions.create({ model: this.model, - reasoning: { effort: this.effort }, - // max_output_tokens: 8192, - instructions: ` - ${docs} - =============== - You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting. - Here is the existing script that you will be working with: - =============== - ${code}`, - input: `Please edit the code above to satisfy the following request:\n\n"${prompt}"`, + max_tokens: 8192, + messages: [ + { + role: 'system', + content: ` + ${docs} + =============== + You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting. + Here is the existing script that you will be working with: + =============== + ${code}`, + }, + { + role: 'user', + content: `Please edit the code above to satisfy the following request:\n\n"${prompt}"`, + }, + ], }) - return resp.output_text + return resp.choices[0].message.content } async fix(code, error) { - const resp = await this.client.responses.create({ + const resp = await this.client.chat.completions.create({ model: this.model, - reasoning: { effort: this.effort }, - // max_output_tokens: 8192, - instructions: ` - ${docs} - =============== - You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting. - Here is the existing script that you will be working with: - =============== - ${code}`, - input: `This code has an error please fix it:\n\n"${JSON.stringify(error, null, 2)}"`, + max_tokens: 8192, + messages: [ + { + role: 'system', + content: ` + ${docs} + =============== + You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting. + Here is the existing script that you will be working with: + =============== + ${code}`, + }, + { + role: 'user', + content: `This code has an error please fix it:\n\n"${JSON.stringify(error, null, 2)}"`, + }, + ], }) - return resp.output_text + return resp.choices[0].message.content } async classify(prompt) { - const resp = await this.client.responses.create({ + const resp = await this.client.chat.completions.create({ model: this.model, - reasoning: { effort: this.effort }, - // max_output_tokens: 8192, - instructions: `You are a classifier. We will give you a prompt that a user has entered to generate a 3D object and your job is respond with a short name for the object. For example if someone prompts "a cool gamer desk with neon lights" you would respond with something like "Gamer Desk" because it is a short descriptive name that captures the essence of the object.`, - input: `Please classify the following prompt:\n\n"${prompt}"`, + max_tokens: 8192, + messages: [ + { + role: 'system', + content: `You are a classifier. We will give you a prompt that a user has entered to generate a 3D object and your job is respond with a short name for the object. For example if someone prompts "a cool gamer desk with neon lights" you would respond with something like "Gamer Desk" because it is a short descriptive name that captures the essence of the object.`, + }, + { + role: 'user', + content: `Please classify the following prompt:\n\n"${prompt}"`, + }, + ], }) - return resp.output_text + return resp.choices[0].message.content } } @@ -552,4 +589,4 @@ class XAIClient { const data = await resp.json() return data.choices[0].message.content } -} +} \ No newline at end of file