mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Use Express router for openai endpoint
This commit is contained in:
@ -3576,7 +3576,7 @@ async function fetchJSON(url, args = {}) {
|
|||||||
// ** END **
|
// ** END **
|
||||||
|
|
||||||
// OpenAI API
|
// OpenAI API
|
||||||
require('./src/endpoints/openai').registerEndpoints(app, jsonParser, urlencodedParser);
|
app.use('/api/openai', require('./src/endpoints/openai').router);
|
||||||
|
|
||||||
// Tokenizers
|
// Tokenizers
|
||||||
require('./src/endpoints/tokenizers').registerEndpoints(app, jsonParser);
|
require('./src/endpoints/tokenizers').registerEndpoints(app, jsonParser);
|
||||||
|
@ -1,216 +1,210 @@
|
|||||||
const { readSecret, SECRET_KEYS } = require('./secrets');
|
const { readSecret, SECRET_KEYS } = require('./secrets');
|
||||||
const fetch = require('node-fetch').default;
|
const fetch = require('node-fetch').default;
|
||||||
|
const express = require('express');
|
||||||
const FormData = require('form-data');
|
const FormData = require('form-data');
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
|
const { jsonParser, urlencodedParser } = require('../express-common');
|
||||||
|
|
||||||
/**
|
const router = express.Router();
|
||||||
* 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 = '';
|
|
||||||
|
|
||||||
if (request.body.api === 'openai') {
|
router.post('/caption-image', jsonParser, async (request, response) => {
|
||||||
key = readSecret(SECRET_KEYS.OPENAI);
|
try {
|
||||||
}
|
let key = '';
|
||||||
|
|
||||||
if (request.body.api === 'openrouter') {
|
if (request.body.api === 'openai') {
|
||||||
key = readSecret(SECRET_KEYS.OPENROUTER);
|
key = readSecret(SECRET_KEYS.OPENAI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!key) {
|
if (request.body.api === 'openrouter') {
|
||||||
console.log('No key found for API', request.body.api);
|
key = readSecret(SECRET_KEYS.OPENROUTER);
|
||||||
return response.sendStatus(401);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
const body = {
|
if (!key) {
|
||||||
model: request.body.model,
|
console.log('No key found for API', request.body.api);
|
||||||
messages: [
|
return response.sendStatus(401);
|
||||||
{
|
}
|
||||||
role: 'user',
|
|
||||||
content: [
|
|
||||||
{ type: 'text', text: request.body.prompt },
|
|
||||||
{ type: 'image_url', image_url: { 'url': request.body.image } },
|
|
||||||
],
|
|
||||||
},
|
|
||||||
],
|
|
||||||
max_tokens: 500,
|
|
||||||
};
|
|
||||||
|
|
||||||
console.log('Multimodal captioning request', body);
|
const body = {
|
||||||
|
model: request.body.model,
|
||||||
let apiUrl = '';
|
messages: [
|
||||||
let headers = {};
|
{
|
||||||
|
role: 'user',
|
||||||
if (request.body.api === 'openrouter') {
|
content: [
|
||||||
apiUrl = 'https://openrouter.ai/api/v1/chat/completions';
|
{ type: 'text', text: request.body.prompt },
|
||||||
headers['HTTP-Referer'] = request.headers.referer;
|
{ type: 'image_url', image_url: { 'url': request.body.image } },
|
||||||
}
|
],
|
||||||
|
|
||||||
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,
|
|
||||||
},
|
},
|
||||||
body: JSON.stringify(body),
|
],
|
||||||
timeout: 0,
|
max_tokens: 500,
|
||||||
});
|
};
|
||||||
|
|
||||||
if (!result.ok) {
|
console.log('Multimodal captioning request', body);
|
||||||
const text = await result.text();
|
|
||||||
console.log('Multimodal captioning request failed', result.statusText, text);
|
|
||||||
return response.status(500).send(text);
|
|
||||||
}
|
|
||||||
|
|
||||||
const data = await result.json();
|
let apiUrl = '';
|
||||||
console.log('Multimodal captioning response', data);
|
let headers = {};
|
||||||
const caption = data?.choices[0]?.message?.content;
|
|
||||||
|
|
||||||
if (!caption) {
|
if (request.body.api === 'openrouter') {
|
||||||
return response.status(500).send('No caption found');
|
apiUrl = 'https://openrouter.ai/api/v1/chat/completions';
|
||||||
}
|
headers['HTTP-Referer'] = request.headers.referer;
|
||||||
|
|
||||||
return response.json({ caption });
|
|
||||||
}
|
}
|
||||||
catch (error) {
|
|
||||||
console.error(error);
|
if (request.body.api === 'openai') {
|
||||||
response.status(500).send('Internal server error');
|
apiUrl = 'https://api.openai.com/v1/chat/completions';
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/openai/transcribe-audio', urlencodedParser, async (request, response) => {
|
const result = await fetch(apiUrl, {
|
||||||
try {
|
method: 'POST',
|
||||||
const key = readSecret(SECRET_KEYS.OPENAI);
|
headers: {
|
||||||
|
'Content-Type': 'application/json',
|
||||||
|
Authorization: `Bearer ${key}`,
|
||||||
|
...headers,
|
||||||
|
},
|
||||||
|
body: JSON.stringify(body),
|
||||||
|
timeout: 0,
|
||||||
|
});
|
||||||
|
|
||||||
if (!key) {
|
if (!result.ok) {
|
||||||
console.log('No OpenAI key found');
|
const text = await result.text();
|
||||||
return response.sendStatus(401);
|
console.log('Multimodal captioning request failed', result.statusText, text);
|
||||||
}
|
return response.status(500).send(text);
|
||||||
|
|
||||||
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');
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/openai/generate-voice', jsonParser, async (request, response) => {
|
const data = await result.json();
|
||||||
try {
|
console.log('Multimodal captioning response', data);
|
||||||
const key = readSecret(SECRET_KEYS.OPENAI);
|
const caption = data?.choices[0]?.message?.content;
|
||||||
|
|
||||||
if (!key) {
|
if (!caption) {
|
||||||
console.log('No OpenAI key found');
|
return response.status(500).send('No caption 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');
|
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
app.post('/api/openai/generate-image', jsonParser, async (request, response) => {
|
return response.json({ caption });
|
||||||
try {
|
}
|
||||||
const key = readSecret(SECRET_KEYS.OPENAI);
|
catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
response.status(500).send('Internal server error');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!key) {
|
router.post('/transcribe-audio', urlencodedParser, async (request, response) => {
|
||||||
console.log('No OpenAI key found');
|
try {
|
||||||
return response.sendStatus(401);
|
const key = readSecret(SECRET_KEYS.OPENAI);
|
||||||
}
|
|
||||||
|
|
||||||
console.log('OpenAI request', request.body);
|
if (!key) {
|
||||||
|
console.log('No OpenAI key found');
|
||||||
const result = await fetch('https://api.openai.com/v1/images/generations', {
|
return response.sendStatus(401);
|
||||||
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 = {
|
if (!request.file) {
|
||||||
registerEndpoints,
|
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 };
|
||||||
|
Reference in New Issue
Block a user