Spaces:
Running
Running
| const express = require('express'); | |
| const path = require('node:path'); | |
| const { WebSocketServer, WebSocket } = require('ws'); | |
| const http = require('node:http'); | |
| require('dotenv').config(); | |
| const app = express(); | |
| const server = http.createServer(app); | |
| const wss = new WebSocketServer({ server }); | |
| // Serve static files from the React app build directory | |
| app.use(express.static(path.join(__dirname, '../build'))); | |
| // Make API key available to the WebSocket server but not to the client | |
| const GEMINI_API_KEY = process.env.GEMINI_API_KEY; | |
| if (!GEMINI_API_KEY) { | |
| console.error('GEMINI_API_KEY environment variable is not set!'); | |
| process.exit(1); | |
| } | |
| // Create a WebSocket connection to Gemini for each client | |
| const createGeminiWebSocket = (clientWs) => { | |
| const geminiWs = new WebSocket( | |
| `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${GEMINI_API_KEY}` | |
| ); | |
| // Set up event handlers before connecting | |
| geminiWs.on('open', () => { | |
| console.log('Connected to Gemini API'); | |
| // If there's a pending setup message, send it now | |
| if (geminiWs.pendingSetup) { | |
| console.log('Sending pending setup:', geminiWs.pendingSetup); | |
| geminiWs.send(JSON.stringify(geminiWs.pendingSetup)); | |
| geminiWs.pendingSetup = null; | |
| } | |
| }); | |
| geminiWs.on('message', (data) => { | |
| try { | |
| // Convert the message to a Blob before sending to client | |
| const message = data.toString(); | |
| console.log('Received from Gemini:', message); | |
| // Create a Blob from the message | |
| const blob = Buffer.from(message); | |
| clientWs.send(blob, { binary: true }); | |
| } catch (error) { | |
| console.error('Error handling Gemini message:', error); | |
| } | |
| }); | |
| geminiWs.on('error', (error) => { | |
| console.error('Gemini WebSocket error:', error); | |
| }); | |
| geminiWs.on('close', (code, reason) => { | |
| console.log('Gemini WebSocket closed:', code, reason.toString()); | |
| }); | |
| return geminiWs; | |
| }; | |
| wss.on('connection', (ws) => { | |
| console.log('Client connected'); | |
| let geminiWs = null; | |
| ws.on('message', async (message) => { | |
| try { | |
| const data = JSON.parse(message); | |
| console.log('Received from client:', data); | |
| // Initialize Gemini connection when receiving setup message | |
| if (data.setup) { | |
| console.log('Initializing Gemini connection with config:', data.setup); | |
| geminiWs = createGeminiWebSocket(ws); | |
| // Store setup message to send once connection is established | |
| if (geminiWs.readyState !== WebSocket.OPEN) { | |
| geminiWs.pendingSetup = data; | |
| } else { | |
| geminiWs.send(JSON.stringify(data)); | |
| } | |
| return; | |
| } | |
| // Forward message to Gemini if connection exists | |
| if (geminiWs && geminiWs.readyState === WebSocket.OPEN) { | |
| console.log('Forwarding to Gemini:', data); | |
| geminiWs.send(JSON.stringify(data)); | |
| } else if (geminiWs) { | |
| console.log('Waiting for Gemini connection to be ready...'); | |
| } else { | |
| console.error('No Gemini connection established'); | |
| } | |
| } catch (error) { | |
| console.error('Error processing message:', error); | |
| } | |
| }); | |
| ws.on('close', () => { | |
| console.log('Client disconnected'); | |
| if (geminiWs) { | |
| geminiWs.close(); | |
| } | |
| }); | |
| }); | |
| // Handle any remaining requests by returning the React app | |
| app.get('*', (req, res) => { | |
| res.sendFile(path.join(__dirname, '../build', 'index.html')); | |
| }); | |
| const PORT = process.env.PORT || 3001; | |
| server.listen(PORT, () => { | |
| console.log(`Server is running on port ${PORT}`); | |
| }); | |