From 0f50997c3ea4bf27c07e916a20bdde855227989f Mon Sep 17 00:00:00 2001 From: Howie Duhzit <127010826+HowieDuhzit@users.noreply.github.com> Date: Fri, 22 Aug 2025 03:33:49 -0400 Subject: [PATCH 1/6] Update .env.example --- .env.example | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) 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 From ddbb127593fd9a2e31d2ee0c5772c7ca9d6d4f93 Mon Sep 17 00:00:00 2001 From: Howie Duhzit <127010826+HowieDuhzit@users.noreply.github.com> Date: Fri, 22 Aug 2025 03:35:12 -0400 Subject: [PATCH 2/6] Update ServerAI.js add OpenAI base URL --- src/core/systems/ServerAI.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index 81da7475..2922977d 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -178,11 +178,20 @@ 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({ model: this.model, From 0eb6b268de3c5c79fc16b9e23113c9b775489baa Mon Sep 17 00:00:00 2001 From: HowieDuhzit Date: Fri, 22 Aug 2025 03:50:32 -0400 Subject: [PATCH 3/6] Enhance error handling and logging in ServerAI.js - Added detailed error logging for AI client initialization and operations. - Improved configuration status logging for AI system setup. - Wrapped AI operations in try-catch blocks to handle and log errors effectively. - Ensured consistent error handling across create, edit, fix, and classify methods. --- src/core/systems/ServerAI.js | 596 +++++++++++++++++++++++------------ 1 file changed, 392 insertions(+), 204 deletions(-) diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index 2922977d..447daba3 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -27,15 +27,34 @@ export class ServerAI extends System { this.model = process.env.AI_MODEL || null this.effort = process.env.AI_EFFORT || 'minimal' this.apiKey = process.env.AI_API_KEY || null - if (this.provider && this.model && this.apiKey) { - if (this.provider === 'openai') { - this.client = new OpenAIClient(this.apiKey, this.model, this.effort) - } - if (this.provider === 'anthropic') { - this.client = new AnthropicClient(this.apiKey, this.model) + + // Log AI configuration status + if (!this.provider || !this.model || !this.apiKey) { + console.log('[ai] AI system disabled - missing configuration:') + if (!this.provider) console.log('[ai] - AI_PROVIDER not set') + if (!this.model) console.log('[ai] - AI_MODEL not set') + if (!this.apiKey) console.log('[ai] - AI_API_KEY not set') + } else { + console.log(`[ai] AI system configured with provider: ${this.provider}, model: ${this.model}`) + if (this.provider === 'openai' && process.env.OPENAI_BASE_URL) { + console.log(`[ai] Using custom OpenAI endpoint: ${process.env.OPENAI_BASE_URL}`) } - if (this.provider === 'xai') { - this.client = new XAIClient(this.apiKey, this.model) + } + + if (this.provider && this.model && this.apiKey) { + try { + if (this.provider === 'openai') { + this.client = new OpenAIClient(this.apiKey, this.model, this.effort) + } + if (this.provider === 'anthropic') { + this.client = new AnthropicClient(this.apiKey, this.model) + } + if (this.provider === 'xai') { + this.client = new XAIClient(this.apiKey, this.model) + } + } catch (error) { + console.error('[ai] Error initializing AI client:', error.message) + this.client = null } } this.enabled = !!this.client @@ -68,111 +87,161 @@ export class ServerAI extends System { } async create({ blueprintId, appId, prompt }) { - console.log('[ai] creating...') - // classify prompt to a short descriptive name for the app - this.classify({ blueprintId, prompt }) - // send prompt to ai to generate code - const startAt = performance.now() - const output = await this.client.create(prompt) - const code = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(code) - console.log(`[ai] created in ${elapsed}s`) - // convert new code to asset - const file = new File([code], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - const blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) + try { + console.log('[ai] creating...') + // classify prompt to a short descriptive name for the app + await this.classify({ blueprintId, prompt }) + // send prompt to ai to generate code + const startAt = performance.now() + const output = await this.client.create(prompt) + const code = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(code) + console.log(`[ai] created in ${elapsed}s`) + // convert new code to asset + const file = new File([code], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + const blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) + } catch (error) { + console.error('[ai] Error creating:', error.message) + if (error.status) { + console.error('[ai] HTTP Status:', error.status) + } + if (error.code) { + console.error('[ai] Error Code:', error.code) + } + throw error + } } async edit({ blueprintId, appId, prompt }) { - console.log('[ai] editing...') - // get existing blueprint - let blueprint = this.world.blueprints.get(blueprintId) - if (!blueprint) return console.error('[ai] edit blueprint but blueprint not found') - // get code to edit - let script = this.world.loader.get('script', blueprint.script) - if (!script) script = await this.world.loader.load('script', blueprint.script) - // send prompt to ai to generate code - const startAt = performance.now() - const code = script.code.replace(prefix, '') - const output = await this.client.edit(code, prompt) - const newCode = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(`[ai] edited in ${elapsed}s`) - // convert new code to asset - const file = new File([newCode], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) + try { + console.log('[ai] editing...') + // get existing blueprint + let blueprint = this.world.blueprints.get(blueprintId) + if (!blueprint) { + console.error('[ai] edit blueprint but blueprint not found') + return + } + // get code to edit + let script = this.world.loader.get('script', blueprint.script) + if (!script) script = await this.world.loader.load('script', blueprint.script) + // send prompt to ai to generate code + const startAt = performance.now() + const code = script.code.replace(prefix, '') + const output = await this.client.edit(code, prompt) + const newCode = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(`[ai] edited in ${elapsed}s`) + // convert new code to asset + const file = new File([newCode], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) + } catch (error) { + console.error('[ai] Error editing:', error.message) + if (error.status) { + console.error('[ai] HTTP Status:', error.status) + } + if (error.code) { + console.error('[ai] Error Code:', error.code) + } + throw error + } } async fix({ blueprintId, appId, error }) { - console.log('[ai] fixing...') - // get existing blueprint - let blueprint = this.world.blueprints.get(blueprintId) - if (!blueprint) return console.error('[ai] fix blueprint but blueprint not found') - // get code to fix - let script = this.world.loader.get('script', blueprint.script) - if (!script) script = await this.world.loader.load('script', blueprint.script) - // send prompt to ai to generate code - const startAt = performance.now() - const code = script.code.replace(prefix, '') - const output = await this.client.fix(code, error) - const newCode = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(`[ai] fixed in ${elapsed}s`) - // convert new code to asset - const file = new File([newCode], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() // or file.text() for string - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) + try { + console.log('[ai] fixing...') + // get existing blueprint + let blueprint = this.world.blueprints.get(blueprintId) + if (!blueprint) { + console.error('[ai] fix blueprint but blueprint not found') + return + } + // get code to fix + let script = this.world.loader.get('script', blueprint.script) + if (!script) script = await this.world.loader.load('script', blueprint.script) + // send prompt to ai to generate code + const startAt = performance.now() + const code = script.code.replace(prefix, '') + const output = await this.client.fix(code, error) + const newCode = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(`[ai] fixed in ${elapsed}s`) + // convert new code to asset + const file = new File([newCode], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() // or file.text() for string + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) + } catch (error) { + console.error('[ai] Error fixing:', error.message) + if (error.status) { + console.error('[ai] HTTP Status:', error.status) + } + if (error.code) { + console.error('[ai] Error Code:', error.code) + } + throw error + } } async classify({ blueprintId, prompt }) { - // get a name for the object - const name = await this.client.classify(prompt) - // update name - const blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, name } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) + try { + // get a name for the object + const name = await this.client.classify(prompt) + // update name + const blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, name } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) + } catch (error) { + console.error('[ai] Error classifying:', error.message) + if (error.status) { + console.error('[ai] HTTP Status:', error.status) + } + if (error.code) { + console.error('[ai] Error Code:', error.code) + } + throw error + } } } @@ -191,64 +260,135 @@ class OpenAIClient { this.effort = effort } - async create(prompt) { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text + try { + const resp = await this.client.responses.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}"`, + }) + return resp.output_text + } catch (error) { + console.error('[ai] OpenAI create error:', error.message) + if (error.status) { + console.error('[ai] OpenAI HTTP Status:', error.status) + if (error.status === 401) { + console.error('[ai] Invalid API key or authentication failed') + } else if (error.status === 404) { + console.error('[ai] Model not found or endpoint not available') + } else if (error.status >= 500) { + console.error('[ai] Server error - endpoint may be down') + } + } + if (error.code) { + console.error('[ai] OpenAI Error Code:', error.code) + } + throw error + } } async edit(code, prompt) { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text + try { + const resp = await this.client.responses.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}"`, + }) + return resp.output_text + } catch (error) { + console.error('[ai] OpenAI edit error:', error.message) + if (error.status) { + console.error('[ai] OpenAI HTTP Status:', error.status) + if (error.status === 401) { + console.error('[ai] Invalid API key or authentication failed') + } else if (error.status === 404) { + console.error('[ai] Model not found or endpoint not available') + } else if (error.status >= 500) { + console.error('[ai] Server error - endpoint may be down') + } + } + if (error.code) { + console.error('[ai] OpenAI Error Code:', error.code) + } + throw error + } } async fix(code, error) { - const resp = await this.client.responses.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)}"`, - }) - return resp.output_text + try { + const resp = await this.client.responses.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)}"`, + }) + return resp.output_text + } catch (error) { + console.error('[ai] OpenAI fix error:', error.message) + if (error.status) { + console.error('[ai] OpenAI HTTP Status:', error.status) + if (error.status === 401) { + console.error('[ai] Invalid API key or authentication failed') + } else if (error.status === 404) { + console.error('[ai] Model not found or endpoint not available') + } else if (error.status >= 500) { + console.error('[ai] Server error - endpoint may be down') + } + } + if (error.code) { + console.error('[ai] OpenAI Error Code:', error.code) + } + throw error + } } async classify(prompt) { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text + try { + const resp = await this.client.responses.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}"`, + }) + return resp.output_text + } catch (error) { + console.error('[ai] OpenAI classify error:', error.message) + if (error.status) { + console.error('[ai] OpenAI HTTP Status:', error.status) + if (error.status === 401) { + console.error('[ai] Invalid API key or authentication failed') + } else if (error.status === 404) { + console.error('[ai] Model not found or endpoint not available') + } else if (error.status >= 500) { + console.error('[ai] Server error - endpoint may be down') + } + } + if (error.code) { + console.error('[ai] OpenAI Error Code:', error.code) + } + throw error + } } } @@ -260,21 +400,39 @@ class AnthropicClient { } async create(prompt) { - const resp = await this.client.messages.create({ - model: this.model, - max_tokens: this.maxTokens, - system: ` - ${docs} - =============== - You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, - messages: [ - { - role: 'user', - content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, - }, - ], - }) - return resp.content[0].text + try { + const resp = await this.client.messages.create({ + model: this.model, + max_tokens: this.maxTokens, + system: ` + ${docs} + =============== + You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, + messages: [ + { + role: 'user', + content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, + }, + ], + }) + return resp.content[0].text + } catch (error) { + console.error('[ai] Anthropic create error:', error.message) + if (error.status) { + console.error('[ai] Anthropic HTTP Status:', error.status) + if (error.status === 401) { + console.error('[ai] Invalid API key or authentication failed') + } else if (error.status === 404) { + console.error('[ai] Model not found or endpoint not available') + } else if (error.status >= 500) { + console.error('[ai] Server error - endpoint may be down') + } + } + if (error.code) { + console.error('[ai] Anthropic Error Code:', error.code) + } + throw error + } } async edit(code, prompt) { @@ -343,17 +501,32 @@ class Comput3Client { } async exec(data) { - const resp = await fetch('https://api.comput3.ai/v1/chat/completions', { - method: 'POST', - headers: { - Authorization: `Bearer ${this.apiKey}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }) - const json = await resp.json() - console.log(JSON.stringify(json, null, 2)) - return json.choices[0].message.content + try { + const resp = await fetch('https://api.comput3.ai/v1/chat/completions', { + method: 'POST', + headers: { + Authorization: `Bearer ${this.apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + + if (!resp.ok) { + const errorText = await resp.text() + console.error('[ai] Comput3 API error:', resp.status, errorText) + throw new Error(`Comput3 API error: ${resp.status} - ${errorText}`) + } + + const json = await resp.json() + console.log(JSON.stringify(json, null, 2)) + return json.choices[0].message.content + } catch (error) { + console.error('[ai] Comput3 exec error:', error.message) + if (error.message.includes('fetch')) { + console.error('[ai] Network error - check internet connection') + } + throw error + } } async create(prompt) { @@ -444,32 +617,47 @@ class XAIClient { } async create(prompt) { - const resp = await fetch(this.url, { - method: 'POST', - headers: { - Authorization: `Bearer ${this.apiKey}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: this.model, - stream: false, - 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}"`, - }, - ], - }), - }) - const data = await resp.json() - return data.choices[0].message.content + try { + const resp = await fetch(this.url, { + method: 'POST', + headers: { + Authorization: `Bearer ${this.apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: this.model, + stream: false, + 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}"`, + }, + ], + }), + }) + + if (!resp.ok) { + const errorText = await resp.text() + console.error('[ai] XAI API error:', resp.status, errorText) + throw new Error(`XAI API error: ${resp.status} - ${errorText}`) + } + + const data = await resp.json() + return data.choices[0].message.content + } catch (error) { + console.error('[ai] XAI create error:', error.message) + if (error.message.includes('fetch')) { + console.error('[ai] Network error - check internet connection') + } + throw error + } } async edit(code, prompt) { From e194762341cafae91c78f4f5f0d89ee0624e06a0 Mon Sep 17 00:00:00 2001 From: HowieDuhzit Date: Fri, 22 Aug 2025 04:09:28 -0400 Subject: [PATCH 4/6] fix: ensure newline at end of file in ServerAI.js --- src/core/systems/ServerAI.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index 447daba3..f6e18263 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -749,4 +749,4 @@ class XAIClient { const data = await resp.json() return data.choices[0].message.content } -} +} \ No newline at end of file From cd53cf47d8fd26fc4aa60b879b4fa9d4f52dfa2b Mon Sep 17 00:00:00 2001 From: HowieDuhzit Date: Fri, 22 Aug 2025 04:17:57 -0400 Subject: [PATCH 5/6] refactor: streamline AI client initialization and method implementations in ServerAI.js - Removed redundant error handling in AI client initialization. - Simplified logging for AI configuration status. - Enhanced method implementations for create, edit, fix, and classify by removing try-catch blocks and directly handling errors. - Improved readability and maintainability of the code. --- src/core/systems/ServerAI.js | 596 ++++++++++++----------------------- 1 file changed, 204 insertions(+), 392 deletions(-) diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index f6e18263..bec6d7fa 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -27,34 +27,15 @@ export class ServerAI extends System { this.model = process.env.AI_MODEL || null this.effort = process.env.AI_EFFORT || 'minimal' this.apiKey = process.env.AI_API_KEY || null - - // Log AI configuration status - if (!this.provider || !this.model || !this.apiKey) { - console.log('[ai] AI system disabled - missing configuration:') - if (!this.provider) console.log('[ai] - AI_PROVIDER not set') - if (!this.model) console.log('[ai] - AI_MODEL not set') - if (!this.apiKey) console.log('[ai] - AI_API_KEY not set') - } else { - console.log(`[ai] AI system configured with provider: ${this.provider}, model: ${this.model}`) - if (this.provider === 'openai' && process.env.OPENAI_BASE_URL) { - console.log(`[ai] Using custom OpenAI endpoint: ${process.env.OPENAI_BASE_URL}`) - } - } - if (this.provider && this.model && this.apiKey) { - try { - if (this.provider === 'openai') { - this.client = new OpenAIClient(this.apiKey, this.model, this.effort) - } - if (this.provider === 'anthropic') { - this.client = new AnthropicClient(this.apiKey, this.model) - } - if (this.provider === 'xai') { - this.client = new XAIClient(this.apiKey, this.model) - } - } catch (error) { - console.error('[ai] Error initializing AI client:', error.message) - this.client = null + if (this.provider === 'openai') { + this.client = new OpenAIClient(this.apiKey, this.model, this.effort) + } + if (this.provider === 'anthropic') { + this.client = new AnthropicClient(this.apiKey, this.model) + } + if (this.provider === 'xai') { + this.client = new XAIClient(this.apiKey, this.model) } } this.enabled = !!this.client @@ -87,161 +68,111 @@ export class ServerAI extends System { } async create({ blueprintId, appId, prompt }) { - try { - console.log('[ai] creating...') - // classify prompt to a short descriptive name for the app - await this.classify({ blueprintId, prompt }) - // send prompt to ai to generate code - const startAt = performance.now() - const output = await this.client.create(prompt) - const code = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(code) - console.log(`[ai] created in ${elapsed}s`) - // convert new code to asset - const file = new File([code], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - const blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) - } catch (error) { - console.error('[ai] Error creating:', error.message) - if (error.status) { - console.error('[ai] HTTP Status:', error.status) - } - if (error.code) { - console.error('[ai] Error Code:', error.code) - } - throw error - } + console.log('[ai] creating...') + // classify prompt to a short descriptive name for the app + this.classify({ blueprintId, prompt }) + // send prompt to ai to generate code + const startAt = performance.now() + const output = await this.client.create(prompt) + const code = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(code) + console.log(`[ai] created in ${elapsed}s`) + // convert new code to asset + const file = new File([code], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + const blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) } async edit({ blueprintId, appId, prompt }) { - try { - console.log('[ai] editing...') - // get existing blueprint - let blueprint = this.world.blueprints.get(blueprintId) - if (!blueprint) { - console.error('[ai] edit blueprint but blueprint not found') - return - } - // get code to edit - let script = this.world.loader.get('script', blueprint.script) - if (!script) script = await this.world.loader.load('script', blueprint.script) - // send prompt to ai to generate code - const startAt = performance.now() - const code = script.code.replace(prefix, '') - const output = await this.client.edit(code, prompt) - const newCode = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(`[ai] edited in ${elapsed}s`) - // convert new code to asset - const file = new File([newCode], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) - } catch (error) { - console.error('[ai] Error editing:', error.message) - if (error.status) { - console.error('[ai] HTTP Status:', error.status) - } - if (error.code) { - console.error('[ai] Error Code:', error.code) - } - throw error - } + console.log('[ai] editing...') + // get existing blueprint + let blueprint = this.world.blueprints.get(blueprintId) + if (!blueprint) return console.error('[ai] edit blueprint but blueprint not found') + // get code to edit + let script = this.world.loader.get('script', blueprint.script) + if (!script) script = await this.world.loader.load('script', blueprint.script) + // send prompt to ai to generate code + const startAt = performance.now() + const code = script.code.replace(prefix, '') + const output = await this.client.edit(code, prompt) + const newCode = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(`[ai] edited in ${elapsed}s`) + // convert new code to asset + const file = new File([newCode], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) } async fix({ blueprintId, appId, error }) { - try { - console.log('[ai] fixing...') - // get existing blueprint - let blueprint = this.world.blueprints.get(blueprintId) - if (!blueprint) { - console.error('[ai] fix blueprint but blueprint not found') - return - } - // get code to fix - let script = this.world.loader.get('script', blueprint.script) - if (!script) script = await this.world.loader.load('script', blueprint.script) - // send prompt to ai to generate code - const startAt = performance.now() - const code = script.code.replace(prefix, '') - const output = await this.client.fix(code, error) - const newCode = prefix + output - const elapsed = (performance.now() - startAt) / 1000 - console.log(`[ai] fixed in ${elapsed}s`) - // convert new code to asset - const file = new File([newCode], 'script.js', { type: 'text/plain' }) - const fileContent = await file.arrayBuffer() // or file.text() for string - const hash = await hashFile(Buffer.from(fileContent)) - const filename = `${hash}.js` - const url = `asset://${filename}` - // upload new script asset - await this.assets.upload(file) - // modify blueprint locally - blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, script: url } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) - } catch (error) { - console.error('[ai] Error fixing:', error.message) - if (error.status) { - console.error('[ai] HTTP Status:', error.status) - } - if (error.code) { - console.error('[ai] Error Code:', error.code) - } - throw error - } + console.log('[ai] fixing...') + // get existing blueprint + let blueprint = this.world.blueprints.get(blueprintId) + if (!blueprint) return console.error('[ai] fix blueprint but blueprint not found') + // get code to fix + let script = this.world.loader.get('script', blueprint.script) + if (!script) script = await this.world.loader.load('script', blueprint.script) + // send prompt to ai to generate code + const startAt = performance.now() + const code = script.code.replace(prefix, '') + const output = await this.client.fix(code, error) + const newCode = prefix + output + const elapsed = (performance.now() - startAt) / 1000 + console.log(`[ai] fixed in ${elapsed}s`) + // convert new code to asset + const file = new File([newCode], 'script.js', { type: 'text/plain' }) + const fileContent = await file.arrayBuffer() // or file.text() for string + const hash = await hashFile(Buffer.from(fileContent)) + const filename = `${hash}.js` + const url = `asset://${filename}` + // upload new script asset + await this.assets.upload(file) + // modify blueprint locally + blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, script: url } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) } async classify({ blueprintId, prompt }) { - try { - // get a name for the object - const name = await this.client.classify(prompt) - // update name - const blueprint = this.world.blueprints.get(blueprintId) - const version = blueprint.version + 1 - const change = { id: blueprint.id, version, name } - this.world.blueprints.modify(change) - // send blueprint update to all clients - this.world.network.send('blueprintModified', change) - this.world.network.dirtyBlueprints.add(change.id) - } catch (error) { - console.error('[ai] Error classifying:', error.message) - if (error.status) { - console.error('[ai] HTTP Status:', error.status) - } - if (error.code) { - console.error('[ai] Error Code:', error.code) - } - throw error - } + // get a name for the object + const name = await this.client.classify(prompt) + // update name + const blueprint = this.world.blueprints.get(blueprintId) + const version = blueprint.version + 1 + const change = { id: blueprint.id, version, name } + this.world.blueprints.modify(change) + // send blueprint update to all clients + this.world.network.send('blueprintModified', change) + this.world.network.dirtyBlueprints.add(change.id) } } @@ -260,135 +191,64 @@ class OpenAIClient { this.effort = effort } + async create(prompt) { - try { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text - } catch (error) { - console.error('[ai] OpenAI create error:', error.message) - if (error.status) { - console.error('[ai] OpenAI HTTP Status:', error.status) - if (error.status === 401) { - console.error('[ai] Invalid API key or authentication failed') - } else if (error.status === 404) { - console.error('[ai] Model not found or endpoint not available') - } else if (error.status >= 500) { - console.error('[ai] Server error - endpoint may be down') - } - } - if (error.code) { - console.error('[ai] OpenAI Error Code:', error.code) - } - throw error - } + const resp = await this.client.responses.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}"`, + }) + return resp.output_text } async edit(code, prompt) { - try { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text - } catch (error) { - console.error('[ai] OpenAI edit error:', error.message) - if (error.status) { - console.error('[ai] OpenAI HTTP Status:', error.status) - if (error.status === 401) { - console.error('[ai] Invalid API key or authentication failed') - } else if (error.status === 404) { - console.error('[ai] Model not found or endpoint not available') - } else if (error.status >= 500) { - console.error('[ai] Server error - endpoint may be down') - } - } - if (error.code) { - console.error('[ai] OpenAI Error Code:', error.code) - } - throw error - } + const resp = await this.client.responses.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}"`, + }) + return resp.output_text } async fix(code, error) { - try { - const resp = await this.client.responses.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)}"`, - }) - return resp.output_text - } catch (error) { - console.error('[ai] OpenAI fix error:', error.message) - if (error.status) { - console.error('[ai] OpenAI HTTP Status:', error.status) - if (error.status === 401) { - console.error('[ai] Invalid API key or authentication failed') - } else if (error.status === 404) { - console.error('[ai] Model not found or endpoint not available') - } else if (error.status >= 500) { - console.error('[ai] Server error - endpoint may be down') - } - } - if (error.code) { - console.error('[ai] OpenAI Error Code:', error.code) - } - throw error - } + const resp = await this.client.responses.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)}"`, + }) + return resp.output_text } async classify(prompt) { - try { - const resp = await this.client.responses.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}"`, - }) - return resp.output_text - } catch (error) { - console.error('[ai] OpenAI classify error:', error.message) - if (error.status) { - console.error('[ai] OpenAI HTTP Status:', error.status) - if (error.status === 401) { - console.error('[ai] Invalid API key or authentication failed') - } else if (error.status === 404) { - console.error('[ai] Model not found or endpoint not available') - } else if (error.status >= 500) { - console.error('[ai] Server error - endpoint may be down') - } - } - if (error.code) { - console.error('[ai] OpenAI Error Code:', error.code) - } - throw error - } + const resp = await this.client.responses.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}"`, + }) + return resp.output_text } } @@ -400,39 +260,21 @@ class AnthropicClient { } async create(prompt) { - try { - const resp = await this.client.messages.create({ - model: this.model, - max_tokens: this.maxTokens, - system: ` - ${docs} - =============== - You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, - messages: [ - { - role: 'user', - content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, - }, - ], - }) - return resp.content[0].text - } catch (error) { - console.error('[ai] Anthropic create error:', error.message) - if (error.status) { - console.error('[ai] Anthropic HTTP Status:', error.status) - if (error.status === 401) { - console.error('[ai] Invalid API key or authentication failed') - } else if (error.status === 404) { - console.error('[ai] Model not found or endpoint not available') - } else if (error.status >= 500) { - console.error('[ai] Server error - endpoint may be down') - } - } - if (error.code) { - console.error('[ai] Anthropic Error Code:', error.code) - } - throw error - } + const resp = await this.client.messages.create({ + model: this.model, + max_tokens: this.maxTokens, + system: ` + ${docs} + =============== + You are an artist and code generator. Always respond with raw code only, never use markdown code blocks or any other formatting.`, + messages: [ + { + role: 'user', + content: `Respond with the javascript needed to generate the following:\n\n"${prompt}"`, + }, + ], + }) + return resp.content[0].text } async edit(code, prompt) { @@ -501,32 +343,17 @@ class Comput3Client { } async exec(data) { - try { - const resp = await fetch('https://api.comput3.ai/v1/chat/completions', { - method: 'POST', - headers: { - Authorization: `Bearer ${this.apiKey}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify(data), - }) - - if (!resp.ok) { - const errorText = await resp.text() - console.error('[ai] Comput3 API error:', resp.status, errorText) - throw new Error(`Comput3 API error: ${resp.status} - ${errorText}`) - } - - const json = await resp.json() - console.log(JSON.stringify(json, null, 2)) - return json.choices[0].message.content - } catch (error) { - console.error('[ai] Comput3 exec error:', error.message) - if (error.message.includes('fetch')) { - console.error('[ai] Network error - check internet connection') - } - throw error - } + const resp = await fetch('https://api.comput3.ai/v1/chat/completions', { + method: 'POST', + headers: { + Authorization: `Bearer ${this.apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify(data), + }) + const json = await resp.json() + console.log(JSON.stringify(json, null, 2)) + return json.choices[0].message.content } async create(prompt) { @@ -617,47 +444,32 @@ class XAIClient { } async create(prompt) { - try { - const resp = await fetch(this.url, { - method: 'POST', - headers: { - Authorization: `Bearer ${this.apiKey}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: this.model, - stream: false, - 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}"`, - }, - ], - }), - }) - - if (!resp.ok) { - const errorText = await resp.text() - console.error('[ai] XAI API error:', resp.status, errorText) - throw new Error(`XAI API error: ${resp.status} - ${errorText}`) - } - - const data = await resp.json() - return data.choices[0].message.content - } catch (error) { - console.error('[ai] XAI create error:', error.message) - if (error.message.includes('fetch')) { - console.error('[ai] Network error - check internet connection') - } - throw error - } + const resp = await fetch(this.url, { + method: 'POST', + headers: { + Authorization: `Bearer ${this.apiKey}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: this.model, + stream: false, + 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}"`, + }, + ], + }), + }) + const data = await resp.json() + return data.choices[0].message.content } async edit(code, prompt) { From 299a4e639ed275805a1050c658976065940f4ecf Mon Sep 17 00:00:00 2001 From: HowieDuhzit Date: Fri, 22 Aug 2025 04:29:35 -0400 Subject: [PATCH 6/6] refactor: update AI interaction methods in ServerAI.js to use chat completions - Changed API calls from responses.create to chat.completions.create for improved functionality. - Updated method implementations for create, edit, fix, and classify to utilize message-based input format. - Enhanced response handling to return content from the new API structure. --- src/core/systems/ServerAI.js | 106 ++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 39 deletions(-) diff --git a/src/core/systems/ServerAI.js b/src/core/systems/ServerAI.js index bec6d7fa..d5a9c765 100644 --- a/src/core/systems/ServerAI.js +++ b/src/core/systems/ServerAI.js @@ -193,62 +193,90 @@ class OpenAIClient { 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 } }