Spaces:
Running
Running
File size: 5,974 Bytes
0fd4af6 7f2a14a 0fd4af6 7f2a14a 0ded4c9 3ffbc23 0ded4c9 0fd4af6 0ded4c9 0fd4af6 3ffbc23 0ded4c9 3ffbc23 0ded4c9 3ffbc23 0ded4c9 0fd4af6 0ded4c9 0fd4af6 0ded4c9 0fd4af6 0ded4c9 0fd4af6 3ffbc23 0ded4c9 0fd4af6 7f2a14a 0ded4c9 7f2a14a 0ded4c9 7f2a14a 0fd4af6 0ded4c9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
// server/index.js
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 });
// بخش خواندن دستورالعملهای شخصیت از Secrets
const instructionSecretNames = {
default: 'PERSONALITY_DEFAULT',
teacher: 'PERSONALITY_TEACHER',
poetic: 'PERSONALITY_POETIC',
funny: 'PERSONALITY_FUNNY',
};
const personalityInstructions = {};
console.log('در حال خواندن دستورالعملهای شخصیت از Secrets...');
Object.keys(instructionSecretNames).forEach(key => {
const secretName = instructionSecretNames[key];
const instruction = process.env[secretName];
if (instruction) {
personalityInstructions[key] = instruction;
console.log(`- دستورالعمل '${key}' با موفقیت خوانده شد.`);
} else {
personalityInstructions[key] = `دستورالعمل '${key}' از سرور بارگذاری نشد.`;
console.warn(`** هشدار: Secret با نام '${secretName}' یافت نشد! **`);
}
});
// بخش مدیریت کلیدهای API (کد هوشمند شما بدون تغییر)
const apiKeysEnv = process.env.ALL_GEMINI_API_KEYS;
const apiKeys = apiKeysEnv ? apiKeysEnv.split(',').map(key => key.trim()).filter(key => key) : [];
if (apiKeys.length === 0) {
console.error('🔴 خطای حیاتی: Secret با نام ALL_GEMINI_API_KEYS یافت نشد!');
process.exit(1);
}
console.log(`✅ تعداد ${apiKeys.length} کلید API بارگذاری شد.`);
let currentKeyIndex = 0;
const getStartingKeyIndex = () => {
const index = currentKeyIndex % apiKeys.length;
currentKeyIndex++;
return index;
};
// توابع attachGeminiEventHandlers و tryConnectToGemini شما اینجا بدون تغییر قرار میگیرند.
// ... (برای کوتاهی اینجا حذف شده، اما شما باید آنها را نگه دارید) ...
function attachGeminiEventHandlers(clientWs, geminiWs, apiKeyUsed) {
geminiWs.on('message', data => clientWs.readyState === WebSocket.OPEN && clientWs.send(data, { binary: true }));
geminiWs.on('error', error => {
console.error(`🔴 خطای WebSocket جیمینای (کلید ...${apiKeyUsed.slice(-4)}):`, error.message);
clientWs.readyState === WebSocket.OPEN && clientWs.close();
});
geminiWs.on('close', code => {
if (code !== 1000) console.log(`🟡 اتصال جیمینای بسته شد (کلید ...${apiKeyUsed.slice(-4)}). کد: ${code}`);
clientWs.readyState === WebSocket.OPEN && clientWs.close();
});
}
async function tryConnectToGemini(clientWs, setupData, startIndex, attemptCount = 0) {
if (attemptCount >= apiKeys.length) {
console.error(`🔴 تمام ${apiKeys.length} کلید API ناموفق بودند.`);
if (clientWs.readyState === WebSocket.OPEN) clientWs.send(JSON.stringify({ error: "خطای داخلی سرور." })) && clientWs.close();
return null;
}
const keyIndexToTry = (startIndex + attemptCount) % apiKeys.length;
const apiKey = apiKeys[keyIndexToTry];
return new Promise(resolve => {
const geminiWs = new WebSocket(`wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${apiKey}`);
const timeout = setTimeout(() => {
geminiWs.removeAllListeners() && geminiWs.close();
console.warn(`🟡 اتصال با کلید ...${apiKey.slice(-4)} زمانبر شد. امتحان کلید بعدی...`);
resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
}, 8000);
geminiWs.on('open', () => {
clearTimeout(timeout);
console.log(`✅ اتصال با کلید اندیس ${keyIndexToTry} موفق بود.`);
try {
geminiWs.send(JSON.stringify(setupData));
} catch (e) {
clientWs.close();
resolve(null);
return;
}
attachGeminiEventHandlers(clientWs, geminiWs, apiKey);
resolve(geminiWs);
});
geminiWs.on('error', () => {
clearTimeout(timeout);
geminiWs.removeAllListeners();
console.warn(`🟡 اتصال با کلید ...${apiKey.slice(-4)} ناموفق بود. امتحان کلید بعدی...`);
resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
});
});
}
// سرو کردن فایلهای استاتیک
app.use(express.static(path.join(__dirname, '../build')));
// API Endpoint جدید برای ارسال دستورالعملها
app.get('/api/instructions', (req, res) => res.json(personalityInstructions));
// مدیریت اتصال WebSocket کلاینت (بدون تغییر)
wss.on('connection', ws => {
const startingKeyIndex = getStartingKeyIndex();
console.log(`🔌 کلاینت جدید متصل شد. کلید شروع: اندیس ${startingKeyIndex}`);
let geminiWs = null;
ws.on('message', async message => {
try {
const data = JSON.parse(message.toString());
if (data.setup) {
if (geminiWs) return;
geminiWs = await tryConnectToGemini(ws, data, startingKeyIndex);
} else if (geminiWs?.readyState === WebSocket.OPEN) {
geminiWs.send(JSON.stringify(data));
}
} catch (e) { /* خطا */ }
});
ws.on('close', () => console.log(`🔌 کلاینت با کلید شروع اندیس ${startingKeyIndex} قطع شد.`) && geminiWs?.close());
ws.on('error', error => console.error(`🔴 خطای WebSocket کلاینت:`, error) && geminiWs?.close());
});
// رسیدگی به سایر درخواستها
app.get('*', (req, res) => res.sendFile(path.join(__dirname, '../build', 'index.html')));
const PORT = process.env.PORT || 3001;
server.listen(PORT, () => console.log(`🚀 سرور در حال اجرا روی پورت ${PORT}`)); |