diff --git a/.env.demo b/.env.demo index 2989d1a..554a865 100644 --- a/.env.demo +++ b/.env.demo @@ -6,7 +6,9 @@ # SERVER_PORT_HTTP=8080 ENV_NAME=demo -TTS_API_URL=https://api.tts.d-popov.com/asr +# TTS_API_URL=https://api.tts.d-popov.com/asr +# TTS_API_URL=https://api.tts.d-popov.com/asr +# TTS_BACKEND=http://192.168.0.11:9009/asr # LLN_MODEL=qwen2 # LNN_API_URL=https://ollama.d-popov.com/api/generate @@ -17,7 +19,7 @@ LNN_API_URL=https://ollama.d-popov.com/api/generate GROQ_API_KEY=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 OPENAI_API_KEY=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 -PUBLIC_WS_URL=wss://ws.tts.d-popov.com -PUBLIC_HOSTNAME=tts.d-popov.com -SERVER_PORT_HTTP=28080 -SERVER_PORT_WS=28081 \ No newline at end of file +# PUBLIC_WS_URL=wss://ws.tts.d-popov.com +# PUBLIC_HOSTNAME=tts.d-popov.com +# SERVER_PORT_HTTP=28080 +# SERVER_PORT_WS=28081 \ No newline at end of file diff --git a/docker-compose.demo.yml b/docker-compose.demo.yml index 0b97d0c..03ab51c 100644 --- a/docker-compose.demo.yml +++ b/docker-compose.demo.yml @@ -1,16 +1,22 @@ -version: '3.8' - services: - node-app: - container_name: node-voice-chat - build: - context: . - dockerfile: web/deploy/demo.Dockerfile - ports: - - "28880:8080" - - "28881:8081" + chat-server: + image: node:20-alpine + container_name: ml-voice-chat-server + working_dir: /usr/src/app volumes: - - .:/usr/src/app # Mounts the current directory to /usr/src/app in the container + - /mnt/apps/DEV/REPOS/git.d-popov.com/ai-kevin:/usr/src/app + command: > + sh -c "npm install && node web/chat-server.js" environment: - NODE_ENV: demo # Sets the environment variable NODE_ENV to development - command: npm run start:demo-chat # Runs npm start when the container starts + NODE_ENV: demo + #TTS_BACKEND_URL: https://api.tts.d-popov.com/asr + TTS_API_URL: http://192.168.0.11:9009/asr + WS_URL: wss://ws.tts.d-popov.com + SERVER_PORT_HTTP: 8080 + SERVER_PORT_WS: 8082 + ports: + - 28080:8080 + - 28081:8082 + dns: + - 8.8.8.8 + - 8.8.4.4 \ No newline at end of file diff --git a/web/chat-server.js b/web/chat-server.js index 8cf4449..1e9c3e1 100644 --- a/web/chat-server.js +++ b/web/chat-server.js @@ -1,403 +1,479 @@ -const express = require('express'); -const bodyParser = require('body-parser'); -const WebSocket = require('ws'); -const storage = require('node-persist'); -const request = require('request'); -const fs = require('fs'); -const path = require('path'); -const dotenv = require('dotenv'); -const ollama = require('ollama'); -const axios = require('axios'); -const OpenAI = require('openai'); -const Groq = require('groq-sdk'); +const express = require('express') +const bodyParser = require('body-parser') +const WebSocket = require('ws') +const storage = require('node-persist') +const request = require('request') +const fs = require('fs') +const path = require('path') +const dotenv = require('dotenv') +const ollama = require('ollama') +const axios = require('axios') +const OpenAI = require('openai') +const Groq = require('groq-sdk') // Load environment variables -dotenv.config({ path: `.env${process.env.NODE_ENV === 'development' ? '.development' :'.'+ process.env.NODE_ENV }` }); +dotenv.config({ + path: `.env${ + process.env.NODE_ENV === 'development' + ? '.development' + : '.' + process.env.NODE_ENV + }` +}) +console.log(`loaded env file: ${process.env.NODE_ENV}`) // Initialize services -const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }); -const groq = new Groq({ apiKey: process.env.GROQ_API_KEY }); +const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY }) +const groq = new Groq({ apiKey: process.env.GROQ_API_KEY }) // Express setup -const app = express(); -app.use(bodyParser.json()); +const app = express() +app.use(bodyParser.json()) // Configuration constants -const PORT_HTTP = process.env.SERVER_PORT_HTTP || 3000; -const PORT_WS = process.env.SERVER_PORT_WS || 8080; -const TTS_API_URL = process.env.TTS_API_URL; -const LNN_API_URL = process.env.LNN_API_URL; -const LLN_MODEL = process.env.LLN_MODEL; +const PORT_HTTP = process.env.SERVER_PORT_HTTP || 3000 +const PORT_WS = process.env.SERVER_PORT_WS || 8082 +const TTS_API_URL = process.env.TTS_API_URL +const LNN_API_URL = process.env.LNN_API_URL +const LLN_MODEL = process.env.LLN_MODEL +console.log(`TTS API URL: ${TTS_API_URL}`) -let language = "en"; -let storeRecordings = false; -let queueCounter = 0; +let language = 'en' +let storeRecordings = false +let queueCounter = 0 -const sessions = new Map(); -const chats = new Map(); // Store chat rooms +const sessions = new Map() +const chats = new Map() // Store chat rooms // Initialize storage and load initial values -async function initStorage() { - await storage.init(); - language = await storage.getItem('language') || language; - storeRecordings = await storage.getItem('storeRecordings') || storeRecordings; +async function initStorage () { + await storage.init() + language = (await storage.getItem('language')) || language + storeRecordings = + (await storage.getItem('storeRecordings')) || storeRecordings - const storedChats = await storage.getItem('chats') || []; - storedChats.forEach(chat => chats.set(chat.id, chat)); + const storedChats = (await storage.getItem('chats')) || [] + storedChats.forEach(chat => chats.set(chat.id, chat)) - const storedSessions = await storage.getItem('sessions') || []; - storedSessions.forEach(session => sessions.set(session.sessionId, session)); + const storedSessions = (await storage.getItem('sessions')) || [] + storedSessions.forEach(session => sessions.set(session.sessionId, session)) } -initStorage(); +initStorage() // WebSocket Server -const wss = new WebSocket.Server({ port: PORT_WS }); +const wss = new WebSocket.Server({ port: PORT_WS }) wss.on('connection', ws => { - ws.on('message', async message => handleMessage(ws, message)); - ws.on('close', () => handleClose(ws)); -}); + ws.on('message', async message => handleMessage(ws, message)) + ws.on('close', () => handleClose(ws)) +}) // Handle WebSocket messages -async function handleMessage(ws, message) { - let data; - try { - data = JSON.parse(message); - } catch { - return handleAudioData(ws, message); - } +async function handleMessage (ws, message) { + let data + try { + data = JSON.parse(message) + } catch { + return handleAudioData(ws, message) + } - try { - switch (data.type) { - case 'sessionId': - await handleSessionId(ws); - break; - case 'join': - await handleJoin(ws, data); - break; - case 'startChat': - await handleStartChat(ws, data); - break; - case 'enterChat': - await handleEnterChat(ws, data); - break; - case 'reconnect': - await handleReconnect(ws, data); - break; - default: - console.log('Unknown message type:', data.type); - } - } catch (err) { - console.error('Failed to handle message', err); + try { + switch (data.type) { + case 'sessionId': + await handleSessionId(ws) + break + case 'join': + await handleJoin(ws, data) + break + case 'startChat': + await handleStartChat(ws, data) + break + case 'enterChat': + await handleEnterChat(ws, data) + break + case 'reconnect': + await handleReconnect(ws, data) + break + default: + console.log('Unknown message type:', data.type) } + } catch (err) { + console.error('Failed to handle message', err) + } } -function handleClose(ws) { - sessions.delete(ws.sessionId); - broadcastUserList(); +function handleClose (ws) { + sessions.delete(ws.sessionId) + broadcastUserList() } // Handlers for specific message types -async function handleSessionId(ws) { - ws.sessionId = generateSessionId(); - sessions.set(ws.sessionId, { language: 'en' }); - await storage.setItem('sessions', Array.from(sessions.values())); +async function handleSessionId (ws) { + ws.sessionId = generateSessionId() + sessions.set(ws.sessionId, { language: 'en' }) + await storage.setItem('sessions', Array.from(sessions.values())) } -async function handleJoin(ws, { username, language }) { - sessions.set(ws.sessionId, { username, sessionId: ws.sessionId, language }); - ws.send(JSON.stringify({ type: 'sessionId', sessionId: ws.sessionId, language, storeRecordings })); +async function handleJoin (ws, { username, language }) { + sessions.set(ws.sessionId, { username, sessionId: ws.sessionId, language }) + ws.send( + JSON.stringify({ + type: 'sessionId', + sessionId: ws.sessionId, + language, + storeRecordings + }) + ) - const userChats = Array.from(chats.values()).filter(chat => chat.participants.includes(ws.sessionId)); - ws.send(JSON.stringify({ type: 'chats', chats: userChats })); + const userChats = Array.from(chats.values()).filter(chat => + chat.participants.includes(ws.sessionId) + ) + ws.send(JSON.stringify({ type: 'chats', chats: userChats })) - broadcastUserList(); + broadcastUserList() } -async function handleStartChat(ws, { users }) { - const chatId = generateChatId(); - let participants = [ws.sessionId, ...users]; - participants = [...new Set(participants)]; +async function handleStartChat (ws, { users }) { + const chatId = generateChatId() + let participants = [ws.sessionId, ...users] + participants = [...new Set(participants)] - chats.set(chatId, { participants, messages: [] }); - await storage.setItem('chats', Array.from(chats.values())); + chats.set(chatId, { participants, messages: [] }) + await storage.setItem('chats', Array.from(chats.values())) - notifyParticipants(participants); - broadcastUserList(); + notifyParticipants(participants) + broadcastUserList() } -async function handleEnterChat(ws, { chatId }) { - const enteredChat = chats.get(chatId); - const currentSession = sessions.get(ws.sessionId); - currentSession.currentChat = chatId; - if (enteredChat && enteredChat.participants.includes(ws.sessionId)) { - ws.send(JSON.stringify({ type: 'chat', chat: enteredChat })); - } +async function handleEnterChat (ws, { chatId }) { + const enteredChat = chats.get(chatId) + const currentSession = sessions.get(ws.sessionId) + currentSession.currentChat = chatId + if (enteredChat && enteredChat.participants.includes(ws.sessionId)) { + ws.send(JSON.stringify({ type: 'chat', chat: enteredChat })) + } } -async function handleReconnect(ws, { sessionId }) { - const userSession = sessions.get(sessionId); - if (userSession) { - sessions.set(ws.sessionId, userSession); - ws.sessionId = sessionId; - const userChats = Array.from(chats.values()).filter(chat => chat.participants.includes(ws.sessionId)); - ws.send(JSON.stringify({ type: 'chats', chats: userChats })); - } else { - console.log('Session not found:', sessionId); - } - broadcastUserList(); +async function handleReconnect (ws, { sessionId }) { + const userSession = sessions.get(sessionId) + if (userSession) { + sessions.set(ws.sessionId, userSession) + ws.sessionId = sessionId + const userChats = Array.from(chats.values()).filter(chat => + chat.participants.includes(ws.sessionId) + ) + ws.send(JSON.stringify({ type: 'chats', chats: userChats })) + } else { + console.log('Session not found:', sessionId) + } + broadcastUserList() } // Utility functions -function generateSessionId() { - return Math.random().toString(36).substring(2); +function generateSessionId () { + return Math.random().toString(36).substring(2) } -function generateChatId() { - return Math.random().toString(36).substring(2); +function generateChatId () { + return Math.random().toString(36).substring(2) } -function broadcastUserList() { - const userList = Array.from(sessions.values()).map(user => ({ - username: user.username, - sessionId: user.sessionId, - currentChat: user.currentChat, - language: user.language - })); +function broadcastUserList () { + const userList = Array.from(sessions.values()).map(user => ({ + username: user.username, + sessionId: user.sessionId, + currentChat: user.currentChat, + language: user.language + })) - wss.clients.forEach(client => { - if (client.readyState === WebSocket.OPEN) { - client.send(JSON.stringify({ type: 'userList', users: userList })); - } - }); -} - -function notifyParticipants(participants) { - participants.forEach(sessionId => { - const participantSocket = Array.from(wss.clients).find(client => client.sessionId === sessionId); - if (participantSocket && participantSocket.readyState === WebSocket.OPEN) { - const userChats = Array.from(chats.entries()) - .filter(([id, chat]) => chat.participants.includes(sessionId)) - .map(([id, chat]) => ({ id, participants: chat.participants })); - participantSocket.send(JSON.stringify({ type: 'chats', chats: userChats })); - } - }); -} - -async function handleAudioData(ws, data) { - const sessionData = sessions.get(ws.sessionId); - let { language, task } = sessionData; - - const formData = { - task: task || 'transcribe', - language, - vad_filter: 'true', - output: 'json', - audio_file: { - value: data, - options: { filename: 'audio.ogg', contentType: 'audio/ogg' } - } - }; - - if (!language || language === 'auto') { - await detectLanguage(ws, formData); - } else { - await transcribeAudio(ws, formData, sessionData); + wss.clients.forEach(client => { + if (client.readyState === WebSocket.OPEN) { + client.send(JSON.stringify({ type: 'userList', users: userList })) } + }) } -async function detectLanguage(ws, formData) { - try { - const result = await requestPromise({ - method: 'POST', - url: TTS_API_URL.replace('/asr', '/detect-language'), - formData - }); - const { language_code } = JSON.parse(result); - if (language_code) { - const sessionData = sessions.get(ws.sessionId); - sessionData.language = language_code; - ws.send(JSON.stringify({ type: 'languageDetected', languageDetected: language_code })); - await transcribeAudio(ws, formData, sessionData); - } - } catch (err) { - console.error('Language detection failed:', err); +function notifyParticipants (participants) { + participants.forEach(sessionId => { + const participantSocket = Array.from(wss.clients).find( + client => client.sessionId === sessionId + ) + if (participantSocket && participantSocket.readyState === WebSocket.OPEN) { + const userChats = Array.from(chats.entries()) + .filter(([id, chat]) => chat.participants.includes(sessionId)) + .map(([id, chat]) => ({ id, participants: chat.participants })) + participantSocket.send( + JSON.stringify({ type: 'chats', chats: userChats }) + ) } + }) } -async function transcribeAudio(ws, formData, sessionData) { - const start = new Date().getTime(); - queueCounter++; +async function handleAudioData (ws, data) { + const sessionData = sessions.get(ws.sessionId) + let { language, task } = sessionData - try { - if(sessionData.language) { - formData.language = sessionData.language; - } - formData.vad_filter = 'true'; - const body = await requestPromise({ method: 'POST', url: TTS_API_URL, formData }); - queueCounter--; - - const duration = new Date().getTime() - start; - ws.send(JSON.stringify({ - type: 'text', - queueCounter, - duration, - language: sessionData.language, - text: body - })); - - await handleChatTranscription(ws, body, sessionData); - - } catch (err) { - console.error('Transcription failed:', err); + const formData = { + task: task || 'transcribe', + language, + vad_filter: 'true', + output: 'json', + audio_file: { + value: data, + options: { filename: 'audio.ogg', contentType: 'audio/ogg' } } + } - if (storeRecordings) { - const timestamp = Date.now(); - fs.mkdir('rec', { recursive: true }, err => { - if (err) console.error(err); - else { - fs.writeFile(`rec/audio${timestamp}.ogg`, formData.audio_file.value, err => { - if (err) console.error(err); - else console.log(`Audio data saved to rec/audio${timestamp}.ogg`); - }); + if (!language || language === 'auto') { + await detectLanguage(ws, formData) + } else { + await transcribeAudio(ws, formData, sessionData) + } +} + +async function detectLanguage (ws, formData) { + try { + const result = await requestPromise({ + method: 'POST', + url: TTS_API_URL.replace('/asr', '/detect-language'), + formData + }) + const { language_code } = JSON.parse(result) + if (language_code) { + const sessionData = sessions.get(ws.sessionId) + sessionData.language = language_code + ws.send( + JSON.stringify({ + type: 'languageDetected', + languageDetected: language_code + }) + ) + await transcribeAudio(ws, formData, sessionData) + } + } catch (err) { + console.error('Language detection failed:', err) + } +} + +async function transcribeAudio (ws, formData, sessionData) { + const start = new Date().getTime() + queueCounter++ + + try { + if (sessionData.language) { + formData.language = sessionData.language + } + formData.vad_filter = 'true' + const body = await requestPromise({ + method: 'POST', + url: TTS_API_URL, + formData + }) + queueCounter-- + + const duration = new Date().getTime() - start + ws.send( + JSON.stringify({ + type: 'text', + queueCounter, + duration, + language: sessionData.language, + text: body + }) + ) + + await handleChatTranscription(ws, body, sessionData) + } catch (err) { + console.error('Transcription failed:', err) + } + + if (storeRecordings) { + const timestamp = Date.now() + fs.mkdir('rec', { recursive: true }, err => { + if (err) console.error(err) + else { + fs.writeFile( + `rec/audio${timestamp}.ogg`, + formData.audio_file.value, + err => { + if (err) console.error(err) + else console.log(`Audio data saved to rec/audio${timestamp}.ogg`) + } + ) + } + }) + } +} + +async function handleChatTranscription (ws, body, sessionData) { + if (sessionData.currentChat) { + const chat = chats.get(sessionData.currentChat) + if (chat) { + let msg = { sender: sessionData.username, text: body, translations: [] } + chat.messages.push(msg) + + for (let sessionId of chat.participants) { + if (sessionId !== ws.sessionId) { + const targetLang = sessions.get(sessionId)?.language || 'en' + if (targetLang !== sessionData.language) { + const translation = await translateText( + body, + sessionData.language, + targetLang + ) + msg.translations.push({ language: targetLang, text: translation }) + + const participantSocket = Array.from(wss.clients).find( + client => client.sessionId === sessionId + ) + if ( + participantSocket && + participantSocket.readyState === WebSocket.OPEN + ) { + participantSocket.send( + JSON.stringify({ + type: 'text', + text: `${sessionData.username}: ${translation}` + }) + ) + const audioBuffer = await generateSpeech(translation) + participantSocket.send( + JSON.stringify({ + type: 'audio', + audio: audioBuffer.toString('base64') + }) + ) } - }); - } -} - -async function handleChatTranscription(ws, body, sessionData) { - if (sessionData.currentChat) { - const chat = chats.get(sessionData.currentChat); - if (chat) { - let msg = { sender: sessionData.username, text: body, translations: [] }; - chat.messages.push(msg); - - for (let sessionId of chat.participants) { - if (sessionId !== ws.sessionId) { - const targetLang = sessions.get(sessionId)?.language || 'en'; - if (targetLang !== sessionData.language) { - const translation = await translateText(body, sessionData.language, targetLang); - msg.translations.push({ language: targetLang, text: translation }); - - const participantSocket = Array.from(wss.clients).find(client => client.sessionId === sessionId); - if (participantSocket && participantSocket.readyState === WebSocket.OPEN) { - participantSocket.send(JSON.stringify({ type: 'text', text: `${sessionData.username}: ${translation}` })); - const audioBuffer = await generateSpeech(translation); - participantSocket.send(JSON.stringify({ type: 'audio', audio: audioBuffer.toString('base64') })); - } - } else { - const participantSocket = Array.from(wss.clients).find(client => client.sessionId === sessionId); - if (participantSocket && participantSocket.readyState === WebSocket.OPEN) { - participantSocket.send(JSON.stringify({ type: 'text', text: `${sessionData.username}: ${body}` })); - participantSocket.send(JSON.stringify({ type: 'audio', audio: formData.toString('base64') })); - } - } - } + } else { + const participantSocket = Array.from(wss.clients).find( + client => client.sessionId === sessionId + ) + if ( + participantSocket && + participantSocket.readyState === WebSocket.OPEN + ) { + participantSocket.send( + JSON.stringify({ + type: 'text', + text: `${sessionData.username}: ${body}` + }) + ) + participantSocket.send( + JSON.stringify({ + type: 'audio', + audio: formData.toString('base64') + }) + ) } + } } + } } + } } -async function translateText(originalText, originalLanguage, targetLanguage) { - const prompt = `Translate this text from ${originalLanguage} to ${targetLanguage}: ${originalText}`; +async function translateText (originalText, originalLanguage, targetLanguage) { + const prompt = `Translate this text from ${originalLanguage} to ${targetLanguage}: ${originalText}` - const response = await groq.chat.completions.create({ - messages: [ - { - role: "system", - content: `You are translating voice transcriptions from '${originalLanguage}' to '${targetLanguage}'. Reply with just the translation.`, - }, - { - role: "user", - content: originalText, - }, - ], - model: "llama3-8b-8192", - }); + const response = await groq.chat.completions.create({ + messages: [ + { + role: 'system', + content: `You are translating voice transcriptions from '${originalLanguage}' to '${targetLanguage}'. Reply with just the translation.` + }, + { + role: 'user', + content: originalText + } + ], + model: 'llama3-8b-8192' + }) - return response.choices[0]?.message?.content || ""; + return response.choices[0]?.message?.content || '' } -async function generateSpeech(text) { - const mp3 = await openai.audio.speech.create({ - model: "tts-1", - voice: "alloy", - input: text, - }); - return Buffer.from(await mp3.arrayBuffer()); +async function generateSpeech (text) { + const mp3 = await openai.audio.speech.create({ + model: 'tts-1', + voice: 'alloy', + input: text + }) + return Buffer.from(await mp3.arrayBuffer()) } // HTTP Server app.get('/', (req, res) => { - res.sendFile(path.join(__dirname, 'chat-client.html')); -}); + res.sendFile(path.join(__dirname, 'chat-client.html')) +}) app.get('/audio.js', (req, res) => { - res.sendFile(path.join(__dirname, 'audio.js')); -}); + res.sendFile(path.join(__dirname, 'audio.js')) +}) app.post('/log', (req, res) => { - console.log(`[LOG ${new Date().toISOString()}] ${req.body.message}`); - res.status(200).send('OK'); -}); + console.log(`[LOG ${new Date().toISOString()}] ${req.body.message}`) + res.status(200).send('OK') +}) app.get('/wsurl', (req, res) => { - // if(process.env.PUBLIC_HOSTNAME){ - // process.env.WS_URL = `wss://${process.env.PUBLIC_HOSTNAME}` - // } - console.log('Request for WS URL resolved with:', process.env.PUBLIC_WS_URL ); - res.status(200).send(process.env.PUBLIC_WS_URL); -}); + // if(process.env.PUBLIC_HOSTNAME){ + // process.env.WS_URL = `wss://${process.env.PUBLIC_HOSTNAME}` + // } + console.log('Request for WS URL resolved with:', process.env.WS_URL) + res.status(200).send(process.env.WS_URL) +}) app.get('/settings', async (req, res) => { - if (req.query.language) { - language = req.query.language; - await storage.setItem('language', language); - } - if (req.query.storeRecordings) { - storeRecordings = req.query.storeRecordings; - await storage.setItem('storeRecordings', storeRecordings); - } - res.status(200).send({ language, storeRecordings }); -}); + if (req.query.language) { + language = req.query.language + await storage.setItem('language', language) + } + if (req.query.storeRecordings) { + storeRecordings = req.query.storeRecordings + await storage.setItem('storeRecordings', storeRecordings) + } + res.status(200).send({ language, storeRecordings }) +}) app.post('/settings', async (req, res) => { - const { sessionId, language, storeRecordings, task } = req.body; - const sessionData = sessions.get(sessionId); - if (language) sessionData.language = language; - if (storeRecordings !== undefined) sessionData.storeRecordings = storeRecordings; - if (task) sessionData.task = task; - res.status(200).send('OK'); -}); + const { sessionId, language, storeRecordings, task } = req.body + const sessionData = sessions.get(sessionId) + if (language) sessionData.language = language + if (storeRecordings !== undefined) + sessionData.storeRecordings = storeRecordings + if (task) sessionData.task = task + res.status(200).send('OK') +}) app.post('/upload', (req, res) => { - const timestamp = Date.now(); - console.log('Received audio data:', timestamp); - fs.mkdir('rec', { recursive: true }, err => { - if (err) return res.status(500).send('ERROR'); - const file = fs.createWriteStream(`rec/audio_slice_${timestamp}.ogg`); - req.pipe(file); - file.on('finish', () => res.status(200).send('OK')); - }); -}); + const timestamp = Date.now() + console.log('Received audio data:', timestamp) + fs.mkdir('rec', { recursive: true }, err => { + if (err) return res.status(500).send('ERROR') + const file = fs.createWriteStream(`rec/audio_slice_${timestamp}.ogg`) + req.pipe(file) + file.on('finish', () => res.status(200).send('OK')) + }) +}) app.get('/chats', (req, res) => { - const { username } = req.query; - const userChats = Array.from(chats.values()).filter(chat => chat.participants.includes(username)); - res.status(200).send({ chats: userChats }); -}); + const { username } = req.query + const userChats = Array.from(chats.values()).filter(chat => + chat.participants.includes(username) + ) + res.status(200).send({ chats: userChats }) +}) app.listen(PORT_HTTP, () => { - console.log(`Server listening on port ${PORT_HTTP}`); -}); + console.log(`Server listening on port ${PORT_HTTP}`) + console.log(process.env.TTS_BACKEND_URL) +}) // Helper to wrap request in a promise -function requestPromise(options) { - return new Promise((resolve, reject) => { - request(options, (error, response, body) => { - if (error) return reject(error); - resolve(body); - }); - }); +function requestPromise (options) { + return new Promise((resolve, reject) => { + request(options, (error, response, body) => { + if (error) return reject(error) + resolve(body) + }) + }) }