diff --git a/.env.demo b/.env.demo index fea3dc7..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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 -WS_URL=wss://tts.d-popov.com -PUBLIC_HOSTNAME=tts.d-popov.com -SERVER_PORT_HTTP=8080 -SERVER_PORT_WS=8081 \ 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/.gitignore b/.gitignore index 188cd7f..707c6db 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ agent-mAId/output.wav agent-mAId/build/* agent-mAId/dist/main.exe agent-mAId/output.wav +.node-persist/storage/* \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index 3cb3638..5cb5705 100644 --- a/Dockerfile +++ b/Dockerfile @@ -90,5 +90,6 @@ RUN . /venv/bin/activate && pip install --upgrade pip && pip install -r agent-py # CMD ["npm", "start"] -CMD ["npm", "run", "start:demo"] +# CMD ["npm", "run", "start:demo"] +CMD ["npm", "run", "start:demo-chat"] #CMD ["npm", "run", "start:tele"] \ No newline at end of file diff --git a/_doc/_notes/readme.md b/_doc/_notes/readme.md index 25e9ed8..1179cb1 100644 --- a/_doc/_notes/readme.md +++ b/_doc/_notes/readme.md @@ -1,3 +1,7 @@ +# .10: /mnt/apps/DEV/REPOS/git.d-popov.com/ai-kevin/ +# run +export NODE_ENV=demo && npm run start:demo-chat + # build: docker build -t kevin-ai . # start the project in container: diff --git a/crypto/sol/app.py b/crypto/sol/app.py index f334c9d..5c895de 100644 --- a/crypto/sol/app.py +++ b/crypto/sol/app.py @@ -1,25 +1,157 @@ from flask import Flask, render_template, request, jsonify -from solana.rpc.api import Client +from solana.rpc.async_api import AsyncClient +from solana.rpc.commitment import Confirmed +from solders.pubkey import Pubkey +from dexscreener import DexscreenerClient +import asyncio +from telegram import Bot +from telegram.constants import ParseMode +import datetime app = Flask(__name__) -solana_client = Client("https://api.mainnet-beta.solana.com") + +# Use the production Solana RPC endpoint +solana_client = AsyncClient("https://api.mainnet-beta.solana.com") +dexscreener_client = DexscreenerClient() + +# Configuration +DEVELOPER_CHAT_ID = "777826553" +FOLLOWED_WALLET = "9U7D916zuQ8qcL9kQZqkcroWhHGho5vD8VNekvztrutN" +YOUR_WALLET = "65nzyZXTLC81MthTo52a2gRJjqryTizWVqpK2fDKLye5" +TELEGRAM_BOT_TOKEN = "6805059978:AAHNJKuOeazMSJHc3-BXRCsFfEVyFHeFnjw" + +# Initialize Telegram Bot +bot = Bot(token=TELEGRAM_BOT_TOKEN) + +# Token addresses (to be populated dynamically) +TOKEN_ADDRESSES = {} + +async def get_token_balance(wallet_address, token_address): + try: + balance = await solana_client.get_token_account_balance( + Pubkey.from_string(token_address), + commitment=Confirmed + ) + return float(balance['result']['value']['uiAmount']) + except Exception as e: + print(f"Error getting balance for {token_address}: {str(e)}") + return 0 + +async def send_telegram_message(message): + try: + await bot.send_message(chat_id=DEVELOPER_CHAT_ID, text=message, parse_mode=ParseMode.HTML) + except Exception as e: + print(f"Error sending Telegram message: {str(e)}") @app.route('/') def index(): return render_template('index.html') @app.route('/tokens', methods=['GET']) -def get_tokens(): - # Here you would add logic to fetch new tokens or token data - return jsonify(['SOL', 'USDC']) # Example token list +async def get_tokens(): + balances = await get_wallet_balances(YOUR_WALLET) + return jsonify(list(balances.keys())) -@app.route('/swap', methods=['POST']) -def swap_tokens(): - data = request.json - token_name = data['token_name'] - amount = data['amount'] - # Here you would add logic to perform the token swap - return jsonify({'status': 'success', 'message': f'Swapped {amount} of {token_name}'}) +@app.route('/balances', methods=['GET']) +async def get_balances(): + balances = await get_wallet_balances(YOUR_WALLET) + return jsonify(balances) + +@app.route('/follow_move', methods=['POST']) +async def follow_move(): + move = request.json + followed_balances = await get_wallet_balances(FOLLOWED_WALLET) + your_balances = await get_wallet_balances(YOUR_WALLET) + + if move['token'] not in followed_balances or move['token'] not in your_balances: + return jsonify({'status': 'error', 'message': 'Invalid token'}) + + followed_balance = followed_balances[move['token']] + your_balance = your_balances[move['token']] + + proportion = your_balance / followed_balance if followed_balance > 0 else 0 + amount_to_swap = move['amount'] * proportion + + if your_balance >= amount_to_swap: + # Implement actual swap logic here + pair = dexscreener_client.get_token_pair("solana", move['token']) + price = float(pair['priceUsd']) + received_amount = amount_to_swap * price + + await send_telegram_message( + f"Move Followed:\n" + f"Swapped {amount_to_swap:.6f} {move['token']} " + f"for {received_amount:.6f} {move['to_token']}" + ) + + return jsonify({ + 'status': 'success', + 'message': f"Swapped {amount_to_swap:.6f} {move['token']} for {received_amount:.6f} {move['to_token']}" + }) + else: + await send_telegram_message( + f"Move Failed:\n" + f"Insufficient balance to swap {amount_to_swap:.6f} {move['token']}" + ) + + return jsonify({ + 'status': 'error', + 'message': f"Insufficient balance to swap {amount_to_swap:.6f} {move['token']}" + }) + +async def get_wallet_balances(wallet_address): + balances = {} + for token, address in TOKEN_ADDRESSES.items(): + balances[token] = await get_token_balance(wallet_address, address) + return balances + +async def get_non_zero_token_balances(wallet_address): + non_zero_balances = {} + for token, address in TOKEN_ADDRESSES.items(): + balance = await get_token_balance(wallet_address, address) + if balance > 0: + non_zero_balances[token] = address + return non_zero_balances + +async def list_initial_wallet_states(): + global TOKEN_ADDRESSES + + followed_wallet_balances = await get_wallet_balances(FOLLOWED_WALLET) + your_wallet_balances = await get_wallet_balances(YOUR_WALLET) + + followed_non_zero = await get_non_zero_token_balances(FOLLOWED_WALLET) + your_non_zero = await get_non_zero_token_balances(YOUR_WALLET) + + TOKEN_ADDRESSES = {**followed_non_zero, **your_non_zero} + + followed_wallet_state = "\n".join([f"{token}: {amount:.6f}" for token, amount in followed_wallet_balances.items() if amount > 0]) + your_wallet_state = "\n".join([f"{token}: {amount:.6f}" for token, amount in your_wallet_balances.items() if amount > 0]) + + message = ( + "Initial Wallet States (Non-zero balances):\n\n" + f"Followed Wallet ({FOLLOWED_WALLET}):\n" + f"{followed_wallet_state}\n\n" + f"Your Wallet ({YOUR_WALLET}):\n" + f"{your_wallet_state}\n\n" + f"Monitored Tokens:\n" + f"{', '.join(TOKEN_ADDRESSES.keys())}" + ) + + await send_telegram_message(message) + +async def send_startup_message(): + current_time = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") + message = ( + f"Solana Agent Application Started\n\n" + f"Startup Time: {current_time}\n" + f"Followed Wallet: {FOLLOWED_WALLET}\n" + f"Your Wallet: {YOUR_WALLET}\n\n" + "The application is now running and ready to monitor wallet activities." + ) + await send_telegram_message(message) if __name__ == '__main__': - app.run(debug=True) + asyncio.run(send_startup_message()) + asyncio.run(list_initial_wallet_states()) + print(f"Monitored Tokens: {', '.join(TOKEN_ADDRESSES.keys())}") + app.run(host='0.0.0.0', port=3009) \ No newline at end of file diff --git a/crypto/sol/readme.md b/crypto/sol/readme.md new file mode 100644 index 0000000..130732b --- /dev/null +++ b/crypto/sol/readme.md @@ -0,0 +1,14 @@ +`Conda activate trade` +To run this Python Solana agent: + +Install the required libraries: + +`pip install flask solana dexscreener python-telegram-bot` + +Replace REPLACE_WITH_WALLET_ADDRESS with the wallet address you want to follow. +Replace REPLACE_WITH_YOUR_WALLET_ADDRESS with your own wallet address. +Save the code in a file, e.g., solana_agent.py. + +Run the Flask application: + +`python app.py` \ No newline at end of file diff --git a/docker-compose.demo.yml b/docker-compose.demo.yml index 0cc78d3..03ab51c 100644 --- a/docker-compose.demo.yml +++ b/docker-compose.demo.yml @@ -1,15 +1,22 @@ -version: '3.8' - services: - node-app: - container_name: node-voice-chat - build: - context: . - dockerfile: web/deploy/demo.Dockerfile - ports: - - "8880:8080" # Exposes port 3000 on the host and maps it to port 3000 on the container + 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 e102945..2082c16 100644 --- a/web/chat-server.js +++ b/web/chat-server.js @@ -15,30 +15,37 @@ const { PrismaClient } = require('@prisma/client'); const prisma = new PrismaClient(); // 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 @@ -70,58 +77,73 @@ app.post('/register', async (req, res) => { }); +// // Initialize storage and load initial values +// 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 storedSessions = (await storage.getItem('sessions')) || [] +// storedSessions.forEach(session => sessions.set(session.sessionId, session)) +// } + +// 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())) } // Modified handleJoin function @@ -177,26 +199,28 @@ async function handleEnterChat(ws, { chatId }) { } } -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) } async function broadcastUserList() { @@ -229,220 +253,272 @@ function notifyParticipants(participants) { }); } -async function handleAudioData(ws, data) { - const sessionData = sessions.get(ws.sessionId); - let { language, task } = sessionData; +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); + 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) + } } -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 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++; +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); + try { + if (sessionData.language) { + formData.language = sessionData.language } + formData.vad_filter = 'true' + const body = await requestPromise({ + method: 'POST', + url: TTS_API_URL, + formData + }) + queueCounter-- - 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`); - }); + 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.WS_URL ); - res.status(200).send(process.env.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) + }) + }) } diff --git a/web/deploy/demo.Dockerfile b/web/deploy/demo.Dockerfile index 484a3ad..48a281c 100644 --- a/web/deploy/demo.Dockerfile +++ b/web/deploy/demo.Dockerfile @@ -4,6 +4,8 @@ FROM node:20 # Create and change to the app directory WORKDIR /usr/src/app +ENV NODE_ENV=demo + # Copy the package.json and package-lock.json files COPY package*.json ./ @@ -13,8 +15,8 @@ RUN npm install # Copy the rest of the application code COPY . . -# Expose port 3000 EXPOSE 8880 +EXPOSE 8881 # Start the application CMD ["npm", "run", "start:demo-chat"]