// import express from "express"; // import http from "http"; // import { Server } from "socket.io"; // import { GoogleGenAI, Modality } from "@google/genai"; // import path from "path"; // import { fileURLToPath } from "url"; // const __filename = fileURLToPath(import.meta.url); // const __dirname = path.dirname(__filename); // const app = express(); // const server = http.createServer(app); // const io = new Server(server, { // cors: { // origin: "*", // methods: ["GET", "POST"] // } // }); // app.use(express.static(path.join(__dirname, "public"))); // // ⚠️ کلید API خود را اینجا قرار دهید // const ai = new GoogleGenAI({ // apiKey: "AIzaSyC9kWntTutd2jnUvY7IqMAozZAOeZ47QUE" // }); // // مدل مناسب برای Gemini Live // const model = "gemini-2.5-flash-native-audio-preview-09-2025"; // const config = { // responseModalities: [Modality.AUDIO], // systemInstruction: "You are a helpful voice assistant. Always respond with audio. You are called 'دستیار صوتی هوشمند دیدوان'. Respond concisely in the same language as the user." // }; // io.on("connection", async (socket) => { // console.log("✅ Client connected:", socket.id); // let session; // let audioChunkCount = 0; // let receivedChunkCount = 0; // try { // // اتصال به Gemini Live API // session = await ai.live.connect({ // model, // config, // callbacks: { // onmessage: (msg) => { // // Log complete message structure for debugging // if (msg?.setupComplete) { // console.log("📩 Gemini: Setup Complete"); // return; // } // if (msg?.toolCall || msg?.toolCallCancellation) { // console.log("📩 Gemini: Tool call (ignoring)"); // return; // } // console.log("📩 Raw Gemini Message:", JSON.stringify(msg).substring(0, 500)); // // ✅ بررسی مسیر اول: msg.data (برای استریم‌های مستقیم صوتی) // if (msg?.data) { // const base64Audio = msg.data; // audioChunkCount++; // console.log("🔊 [Route 1] Sending audio chunk #" + audioChunkCount + ": " + base64Audio.length + " chars"); // socket.emit("gemini_audio_chunk", base64Audio); // return; // } // // ✅ بررسی مسیر دوم: msg.serverContent.modelTurn.parts // if (msg?.serverContent?.modelTurn?.parts) { // console.log("📦 Found serverContent.modelTurn.parts, checking for audio..."); // const parts = msg.serverContent.modelTurn.parts; // for (const part of parts) { // // Log part structure // console.log(" Part keys:", Object.keys(part)); // if (part.text) { // console.log(" 📝 Text part:", part.text); // } // if (part.inlineData) { // console.log(" 💾 InlineData mimeType:", part.inlineData.mimeType); // console.log(" 💾 InlineData size:", part.inlineData.data?.length || 0, "chars"); // if (part.inlineData.mimeType?.startsWith("audio/")) { // const base64Audio = part.inlineData.data; // const mimeType = part.inlineData.mimeType; // audioChunkCount++; // console.log("🔊 [Route 2] Sending audio chunk #" + audioChunkCount + ": " + base64Audio.length + " chars, mime: " + mimeType); // // ارسال به کلاینت با اطلاعات mime // socket.emit("gemini_audio_chunk", { // data: base64Audio, // mimeType: mimeType // }); // } // } // } // } // // ✅ بررسی پایان نوبت // if (msg?.serverContent?.turnComplete) { // console.log("✅ Gemini turn complete"); // } // }, // onerror: (e) => { // console.error("❌ Gemini Session Error:", e); // socket.emit("error", "Gemini connection error"); // }, // onclose: (event) => { // console.log("🔒 Gemini session closed:", event?.code, event?.reason); // } // } // }); // console.log("✨ Gemini Session Connected for client:", socket.id); // } catch (e) { // console.error("🔥 Failed to connect to Gemini:", e); // socket.emit("error", "Failed to connect to AI service"); // return; // } // // ✅ دریافت صدا از کلاینت فلاتر // socket.on("audio_chunk", async (base64Chunk) => { // if (!session) { // console.error("⚠️ No active Gemini session"); // return; // } // receivedChunkCount++; // console.log("📥 Received chunk #" + receivedChunkCount + " from client: " + base64Chunk.length + " chars"); // try { // // ✅ فرمت صحیح برای ارسال به Gemini Live API // await session.sendRealtimeInput([{ // mimeType: "audio/pcm;rate=16000", // data: base64Chunk // }]); // console.log("✅ Sent chunk #" + receivedChunkCount + " to Gemini"); // // Gemini should auto-detect turn completion based on audio silence // } catch (e) { // console.error("❌ Error sending chunk to Gemini:", e.message, e.stack); // } // }); // socket.on("disconnect", () => { // console.log("❌ Client disconnected: " + socket.id); // console.log("📊 Stats - Received: " + receivedChunkCount + " chunks, Sent: " + audioChunkCount + " chunks"); // if (session) { // session.close(); // session = null; // } // }); // }); // const PORT = 3001; // server.listen(PORT, "0.0.0.0", () => { // console.log(`🚀 Server running on port ${PORT}`); // console.log(`🌐 Access from network: http://:${PORT}`); // });