From 2d19645c4ed0171bb4e1e8dfd8928334247aa130 Mon Sep 17 00:00:00 2001 From: valadaptive Date: Mon, 4 Dec 2023 12:53:17 -0500 Subject: [PATCH] Use Express router for openai endpoint --- server.js | 2 +- src/endpoints/openai.js | 372 ++++++++++++++++++++-------------------- 2 files changed, 184 insertions(+), 190 deletions(-) diff --git a/server.js b/server.js index a0b24bb5b..cd61026e1 100644 --- a/server.js +++ b/server.js @@ -3576,7 +3576,7 @@ async function fetchJSON(url, args = {}) { // ** END ** // OpenAI API -require('./src/endpoints/openai').registerEndpoints(app, jsonParser, urlencodedParser); +app.use('/api/openai', require('./src/endpoints/openai').router); // Tokenizers require('./src/endpoints/tokenizers').registerEndpoints(app, jsonParser); diff --git a/src/endpoints/openai.js b/src/endpoints/openai.js index 974027b0d..25c91b8c6 100644 --- a/src/endpoints/openai.js +++ b/src/endpoints/openai.js @@ -1,216 +1,210 @@ const { readSecret, SECRET_KEYS } = require('./secrets'); const fetch = require('node-fetch').default; +const express = require('express'); const FormData = require('form-data'); const fs = require('fs'); +const { jsonParser, urlencodedParser } = require('../express-common'); -/** - * Registers the OpenAI endpoints. - * @param {import("express").Express} app Express app - * @param {any} jsonParser JSON parser - * @param {any} urlencodedParser Form data parser - */ -function registerEndpoints(app, jsonParser, urlencodedParser) { - app.post('/api/openai/caption-image', jsonParser, async (request, response) => { - try { - let key = ''; +const router = express.Router(); - if (request.body.api === 'openai') { - key = readSecret(SECRET_KEYS.OPENAI); - } +router.post('/caption-image', jsonParser, async (request, response) => { + try { + let key = ''; - if (request.body.api === 'openrouter') { - key = readSecret(SECRET_KEYS.OPENROUTER); - } + if (request.body.api === 'openai') { + key = readSecret(SECRET_KEYS.OPENAI); + } - if (!key) { - console.log('No key found for API', request.body.api); - return response.sendStatus(401); - } + if (request.body.api === 'openrouter') { + key = readSecret(SECRET_KEYS.OPENROUTER); + } - const body = { - model: request.body.model, - messages: [ - { - role: 'user', - content: [ - { type: 'text', text: request.body.prompt }, - { type: 'image_url', image_url: { 'url': request.body.image } }, - ], - }, - ], - max_tokens: 500, - }; + if (!key) { + console.log('No key found for API', request.body.api); + return response.sendStatus(401); + } - console.log('Multimodal captioning request', body); - - let apiUrl = ''; - let headers = {}; - - if (request.body.api === 'openrouter') { - apiUrl = 'https://openrouter.ai/api/v1/chat/completions'; - headers['HTTP-Referer'] = request.headers.referer; - } - - if (request.body.api === 'openai') { - apiUrl = 'https://api.openai.com/v1/chat/completions'; - } - - const result = await fetch(apiUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${key}`, - ...headers, + const body = { + model: request.body.model, + messages: [ + { + role: 'user', + content: [ + { type: 'text', text: request.body.prompt }, + { type: 'image_url', image_url: { 'url': request.body.image } }, + ], }, - body: JSON.stringify(body), - timeout: 0, - }); + ], + max_tokens: 500, + }; - if (!result.ok) { - const text = await result.text(); - console.log('Multimodal captioning request failed', result.statusText, text); - return response.status(500).send(text); - } + console.log('Multimodal captioning request', body); - const data = await result.json(); - console.log('Multimodal captioning response', data); - const caption = data?.choices[0]?.message?.content; + let apiUrl = ''; + let headers = {}; - if (!caption) { - return response.status(500).send('No caption found'); - } - - return response.json({ caption }); + if (request.body.api === 'openrouter') { + apiUrl = 'https://openrouter.ai/api/v1/chat/completions'; + headers['HTTP-Referer'] = request.headers.referer; } - catch (error) { - console.error(error); - response.status(500).send('Internal server error'); + + if (request.body.api === 'openai') { + apiUrl = 'https://api.openai.com/v1/chat/completions'; } - }); - app.post('/api/openai/transcribe-audio', urlencodedParser, async (request, response) => { - try { - const key = readSecret(SECRET_KEYS.OPENAI); + const result = await fetch(apiUrl, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${key}`, + ...headers, + }, + body: JSON.stringify(body), + timeout: 0, + }); - if (!key) { - console.log('No OpenAI key found'); - return response.sendStatus(401); - } - - if (!request.file) { - console.log('No audio file found'); - return response.sendStatus(400); - } - - const formData = new FormData(); - console.log('Processing audio file', request.file.path); - formData.append('file', fs.createReadStream(request.file.path), { filename: 'audio.wav', contentType: 'audio/wav' }); - formData.append('model', request.body.model); - - if (request.body.language) { - formData.append('language', request.body.language); - } - - const result = await fetch('https://api.openai.com/v1/audio/transcriptions', { - method: 'POST', - headers: { - 'Authorization': `Bearer ${key}`, - ...formData.getHeaders(), - }, - body: formData, - }); - - if (!result.ok) { - const text = await result.text(); - console.log('OpenAI request failed', result.statusText, text); - return response.status(500).send(text); - } - - fs.rmSync(request.file.path); - const data = await result.json(); - console.log('OpenAI transcription response', data); - return response.json(data); - } catch (error) { - console.error('OpenAI transcription failed', error); - response.status(500).send('Internal server error'); + if (!result.ok) { + const text = await result.text(); + console.log('Multimodal captioning request failed', result.statusText, text); + return response.status(500).send(text); } - }); - app.post('/api/openai/generate-voice', jsonParser, async (request, response) => { - try { - const key = readSecret(SECRET_KEYS.OPENAI); + const data = await result.json(); + console.log('Multimodal captioning response', data); + const caption = data?.choices[0]?.message?.content; - if (!key) { - console.log('No OpenAI key found'); - return response.sendStatus(401); - } - - const result = await fetch('https://api.openai.com/v1/audio/speech', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${key}`, - }, - body: JSON.stringify({ - input: request.body.text, - response_format: 'mp3', - voice: request.body.voice ?? 'alloy', - speed: request.body.speed ?? 1, - model: request.body.model ?? 'tts-1', - }), - }); - - if (!result.ok) { - const text = await result.text(); - console.log('OpenAI request failed', result.statusText, text); - return response.status(500).send(text); - } - - const buffer = await result.arrayBuffer(); - response.setHeader('Content-Type', 'audio/mpeg'); - return response.send(Buffer.from(buffer)); - } catch (error) { - console.error('OpenAI TTS generation failed', error); - response.status(500).send('Internal server error'); + if (!caption) { + return response.status(500).send('No caption found'); } - }); - app.post('/api/openai/generate-image', jsonParser, async (request, response) => { - try { - const key = readSecret(SECRET_KEYS.OPENAI); + return response.json({ caption }); + } + catch (error) { + console.error(error); + response.status(500).send('Internal server error'); + } +}); - if (!key) { - console.log('No OpenAI key found'); - return response.sendStatus(401); - } +router.post('/transcribe-audio', urlencodedParser, async (request, response) => { + try { + const key = readSecret(SECRET_KEYS.OPENAI); - console.log('OpenAI request', request.body); - - const result = await fetch('https://api.openai.com/v1/images/generations', { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${key}`, - }, - body: JSON.stringify(request.body), - timeout: 0, - }); - - if (!result.ok) { - const text = await result.text(); - console.log('OpenAI request failed', result.statusText, text); - return response.status(500).send(text); - } - - const data = await result.json(); - return response.json(data); - } catch (error) { - console.error(error); - response.status(500).send('Internal server error'); + if (!key) { + console.log('No OpenAI key found'); + return response.sendStatus(401); } - }); -} -module.exports = { - registerEndpoints, -}; + if (!request.file) { + console.log('No audio file found'); + return response.sendStatus(400); + } + + const formData = new FormData(); + console.log('Processing audio file', request.file.path); + formData.append('file', fs.createReadStream(request.file.path), { filename: 'audio.wav', contentType: 'audio/wav' }); + formData.append('model', request.body.model); + + if (request.body.language) { + formData.append('language', request.body.language); + } + + const result = await fetch('https://api.openai.com/v1/audio/transcriptions', { + method: 'POST', + headers: { + 'Authorization': `Bearer ${key}`, + ...formData.getHeaders(), + }, + body: formData, + }); + + if (!result.ok) { + const text = await result.text(); + console.log('OpenAI request failed', result.statusText, text); + return response.status(500).send(text); + } + + fs.rmSync(request.file.path); + const data = await result.json(); + console.log('OpenAI transcription response', data); + return response.json(data); + } catch (error) { + console.error('OpenAI transcription failed', error); + response.status(500).send('Internal server error'); + } +}); + +router.post('/generate-voice', jsonParser, async (request, response) => { + try { + const key = readSecret(SECRET_KEYS.OPENAI); + + if (!key) { + console.log('No OpenAI key found'); + return response.sendStatus(401); + } + + const result = await fetch('https://api.openai.com/v1/audio/speech', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${key}`, + }, + body: JSON.stringify({ + input: request.body.text, + response_format: 'mp3', + voice: request.body.voice ?? 'alloy', + speed: request.body.speed ?? 1, + model: request.body.model ?? 'tts-1', + }), + }); + + if (!result.ok) { + const text = await result.text(); + console.log('OpenAI request failed', result.statusText, text); + return response.status(500).send(text); + } + + const buffer = await result.arrayBuffer(); + response.setHeader('Content-Type', 'audio/mpeg'); + return response.send(Buffer.from(buffer)); + } catch (error) { + console.error('OpenAI TTS generation failed', error); + response.status(500).send('Internal server error'); + } +}); + +router.post('/generate-image', jsonParser, async (request, response) => { + try { + const key = readSecret(SECRET_KEYS.OPENAI); + + if (!key) { + console.log('No OpenAI key found'); + return response.sendStatus(401); + } + + console.log('OpenAI request', request.body); + + const result = await fetch('https://api.openai.com/v1/images/generations', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + Authorization: `Bearer ${key}`, + }, + body: JSON.stringify(request.body), + timeout: 0, + }); + + if (!result.ok) { + const text = await result.text(); + console.log('OpenAI request failed', result.statusText, text); + return response.status(500).send(text); + } + + const data = await result.json(); + return response.json(data); + } catch (error) { + console.error(error); + response.status(500).send('Internal server error'); + } +}); + +module.exports = { router };