Hamed744 commited on
Commit
9e404a1
·
verified ·
1 Parent(s): affece8

Upload index.js

Browse files
Files changed (1) hide show
  1. server/index.js +90 -182
server/index.js CHANGED
@@ -9,211 +9,119 @@ const app = express();
9
  const server = http.createServer(app);
10
  const wss = new WebSocketServer({ server });
11
 
12
- // --------------------------------------------------------------------------
13
- // 1. تنظیمات و متغیرها
14
- // --------------------------------------------------------------------------
15
  const instructionSecretNames = {
16
- default: 'PERSONALITY_DEFAULT',
17
- teacher: 'PERSONALITY_TEACHER',
18
- poetic: 'PERSONALITY_POETIC',
19
- funny: 'PERSONALITY_FUNNY',
20
  };
21
-
22
  const personalityInstructions = {};
23
- console.log('🔄 در حال بارگذاری تنظیمات...');
24
  Object.keys(instructionSecretNames).forEach(key => {
25
- const secretName = instructionSecretNames[key];
26
- const instruction = process.env[secretName];
27
- if (instruction) {
28
- personalityInstructions[key] = instruction;
29
- } else {
30
- personalityInstructions[key] = ""; // مقدار پیش‌فرض خالی برای جلوگیری از خطا
31
- }
 
 
32
  });
33
 
34
- // مدیریت کلیدهای API
35
  const apiKeysEnv = process.env.ALL_GEMINI_API_KEYS;
36
  const apiKeys = apiKeysEnv ? apiKeysEnv.split(',').map(key => key.trim()).filter(key => key) : [];
37
-
38
  if (apiKeys.length === 0) {
39
- console.error('🔴 خطای حیاتی: کلید API یافت نشد. لطفاً ALL_GEMINI_API_KEYS را در تنظیمات اسپیس وارد کنید.');
40
- // سرور را متوقف نمیکنیم تا حداقل صفحه بالا بیاید و خطا دهد
41
- } else {
42
- console.log(`✅ تعداد ${apiKeys.length} کلید API شناسایی شد.`);
43
  }
44
-
45
  let currentKeyIndex = 0;
46
- const getNextKeyIndex = () => {
47
- const index = currentKeyIndex;
48
- currentKeyIndex = (currentKeyIndex + 1) % apiKeys.length;
49
- return index;
50
  };
51
-
52
- // --------------------------------------------------------------------------
53
- // 2. توابع کمکی جیمینای
54
- // --------------------------------------------------------------------------
55
-
56
  function attachGeminiEventHandlers(clientWs, geminiWs, apiKeyUsed) {
57
- // وقتی پیامی از جیمینای آمد، به کلاینت (کاربر) بفرست
58
- const handleGeminiMessage = (data) => {
59
- if (clientWs.readyState === WebSocket.OPEN) {
60
- // نکته مهم: ارسال به صورت باینری (Blob) تا کلاینت بتواند پردازش کند
61
- clientWs.send(data, { binary: true });
62
- }
63
- };
64
-
65
- const handleGeminiError = (error) => {
66
- console.error(`🔴 خطای جیمینای:`, error.message);
67
- if (clientWs.readyState === WebSocket.OPEN) {
68
- clientWs.close();
69
- }
70
- };
71
-
72
- const handleGeminiClose = () => {
73
- if (clientWs.readyState === WebSocket.OPEN) {
74
- clientWs.close();
75
- }
76
- };
77
-
78
- geminiWs.on('message', handleGeminiMessage);
79
- geminiWs.on('error', handleGeminiError);
80
- geminiWs.on('close', handleGeminiClose);
81
-
82
- // *** بخش مهم برای رفع نشت حافظه ***
83
- // وقتی کلاینت قطع شد، تمام لیسنرهای جیمینای را پاک کن و اتصال را ببند
84
- clientWs.on('close', () => {
85
- geminiWs.off('message', handleGeminiMessage);
86
- geminiWs.off('error', handleGeminiError);
87
- geminiWs.off('close', handleGeminiClose);
88
-
89
- if (geminiWs.readyState === WebSocket.OPEN || geminiWs.readyState === WebSocket.CONNECTING) {
90
- geminiWs.close();
91
- }
92
- });
93
  }
94
-
95
  async function tryConnectToGemini(clientWs, setupData, startIndex, attemptCount = 0) {
96
- if (attemptCount >= apiKeys.length) {
97
- console.error(`❌ همه کلیدها تست شدند و ناموفق بودند.`);
98
- return null;
99
- }
100
-
101
- const keyIndexToTry = (startIndex + attemptCount) % apiKeys.length;
102
- const apiKey = apiKeys[keyIndexToTry];
103
-
104
- return new Promise(resolve => {
105
- const url = `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${apiKey}`;
106
-
107
- let geminiWs;
108
- try {
109
- geminiWs = new WebSocket(url);
110
- } catch (e) {
111
- console.error("خطا در ایجاد سوکت:", e);
112
- resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
113
- return;
114
- }
115
-
116
- // تایم‌اوت اتصال (10 ثانیه)
117
- const timeout = setTimeout(() => {
118
- console.warn(`⏳ تایم‌اوت اتصال (کلید ${keyIndexToTry}). امتحان کلید بعدی...`);
119
- try { geminiWs.close(); } catch(e){}
120
- resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
121
- }, 10000);
122
-
123
- geminiWs.on('open', () => {
124
- clearTimeout(timeout);
125
-
126
- // اگر کاربر در حین اتصال قطع شد
127
- if (clientWs.readyState !== WebSocket.OPEN) {
128
- geminiWs.close();
129
- resolve(null);
130
- return;
131
- }
132
-
133
- console.log(`🔗 متصل به جیمینای (کلید ${keyIndexToTry})`);
134
-
135
- try {
136
- geminiWs.send(JSON.stringify(setupData));
137
- attachGeminiEventHandlers(clientWs, geminiWs, apiKey);
138
- resolve(geminiWs);
139
- } catch (e) {
140
- console.error("خطا در ارسال Setup:", e);
141
- geminiWs.close();
142
- resolve(null);
143
- }
144
- });
145
-
146
- geminiWs.on('error', (err) => {
147
- clearTimeout(timeout);
148
- console.warn(`⚠️ خطا در اتصال (کلید ${keyIndexToTry}):`, err.message);
149
- resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
150
- });
151
  });
 
 
 
 
 
 
 
152
  }
153
 
154
- // --------------------------------------------------------------------------
155
- // 3. سرور و سوکت اصلی
156
- // --------------------------------------------------------------------------
157
-
158
  app.use(express.static(path.join(__dirname, '../build')));
159
- app.get('/api/instructions', (req, res) => res.json(personalityInstructions));
160
-
161
- wss.on('connection', function connection(ws) {
162
- const myKeyIndex = getNextKeyIndex();
163
- console.log(`🔌 کلاینت جدید وصل شد.`);
164
-
165
- let geminiWs = null;
166
 
167
- ws.on('message', async (message) => {
168
- try {
169
- // اگر پیام باینری است (مثل داده‌های صوتی)، مستقیماً بفرست
170
- if (Buffer.isBuffer(message)) {
171
- if (geminiWs && geminiWs.readyState === WebSocket.OPEN) {
172
- geminiWs.send(message);
173
- }
174
- return;
175
- }
176
-
177
- // پیام‌های متنی (JSON)
178
- const strMsg = message.toString();
179
- let data;
180
- try {
181
- data = JSON.parse(strMsg);
182
- } catch (e) {
183
- // اگر JSON نیست، شاید پیام متنی ساده باشد، بفرست بره
184
- if (geminiWs && geminiWs.readyState === WebSocket.OPEN) {
185
- geminiWs.send(strMsg);
186
- }
187
- return;
188
- }
189
-
190
- // اگر پیام Setup (شروع مکالمه) است
191
- if (data.setup) {
192
- if (geminiWs) return; // اگر قبلاً وصل شده، دوباره وصل نشو
193
-
194
- geminiWs = await tryConnectToGemini(ws, data, myKeyIndex);
195
- }
196
- // سایر پیام‌های JSON
197
- else if (geminiWs && geminiWs.readyState === WebSocket.OPEN) {
198
- geminiWs.send(strMsg);
199
- }
200
-
201
- } catch (error) {
202
- console.error("خطا در پردازش پیام:", error);
203
- }
204
- });
205
-
206
- ws.on('close', () => {
207
- console.log(`👋 کلاینت قطع شد.`);
208
- if (geminiWs) {
209
- try { geminiWs.close(); } catch(e){}
210
- }
211
- });
212
 
213
- ws.on('error', (err) => console.error('خطای سوکت کلاینت:', err));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
214
  });
215
 
 
216
  app.get('*', (req, res) => res.sendFile(path.join(__dirname, '../build', 'index.html')));
217
 
218
  const PORT = process.env.PORT || 3001;
219
- server.listen(PORT, () => console.log(`🚀 سرور روی پورت ${PORT} اجرا شد.`));
 
9
  const server = http.createServer(app);
10
  const wss = new WebSocketServer({ server });
11
 
12
+ // بخش خواندن دستورالعمل‌های شخصیت از Secrets
 
 
13
  const instructionSecretNames = {
14
+ default: 'PERSONALITY_DEFAULT',
15
+ teacher: 'PERSONALITY_TEACHER',
16
+ poetic: 'PERSONALITY_POETIC',
17
+ funny: 'PERSONALITY_FUNNY',
18
  };
 
19
  const personalityInstructions = {};
20
+ console.log('در حال خواندن دستورالعمل‌های شخصیت از Secrets...');
21
  Object.keys(instructionSecretNames).forEach(key => {
22
+ const secretName = instructionSecretNames[key];
23
+ const instruction = process.env[secretName];
24
+ if (instruction) {
25
+ personalityInstructions[key] = instruction;
26
+ console.log(`- دستورالعمل '${key}' با موفقیت خوانده شد.`);
27
+ } else {
28
+ personalityInstructions[key] = `دستورالعمل '${key}' از سرور بارگذاری نشد.`;
29
+ console.warn(`** هشدار: Secret با نام '${secretName}' یافت نشد! **`);
30
+ }
31
  });
32
 
33
+ // بخش مدیریت کلیدهای API (کد هوشمند شما بدون تغییر)
34
  const apiKeysEnv = process.env.ALL_GEMINI_API_KEYS;
35
  const apiKeys = apiKeysEnv ? apiKeysEnv.split(',').map(key => key.trim()).filter(key => key) : [];
 
36
  if (apiKeys.length === 0) {
37
+ console.error('🔴 خطای حیاتی: Secret با نام ALL_GEMINI_API_KEYS یافت نشد!');
38
+ process.exit(1);
 
 
39
  }
40
+ console.log(`✅ تعداد ${apiKeys.length} کلید API بارگذاری شد.`);
41
  let currentKeyIndex = 0;
42
+ const getStartingKeyIndex = () => {
43
+ const index = currentKeyIndex % apiKeys.length;
44
+ currentKeyIndex++;
45
+ return index;
46
  };
47
+ // توابع attachGeminiEventHandlers و tryConnectToGemini شما اینجا بدون تغییر قرار می‌گیرند.
48
+ // ... (برای کوتاهی اینجا حذف شده، اما شما باید آنها را نگه دارید) ...
 
 
 
49
  function attachGeminiEventHandlers(clientWs, geminiWs, apiKeyUsed) {
50
+ geminiWs.on('message', data => clientWs.readyState === WebSocket.OPEN && clientWs.send(data, { binary: true }));
51
+ geminiWs.on('error', error => {
52
+ console.error(`🔴 خطای WebSocket جیمینای (کلید ...${apiKeyUsed.slice(-4)}):`, error.message);
53
+ clientWs.readyState === WebSocket.OPEN && clientWs.close();
54
+ });
55
+ geminiWs.on('close', code => {
56
+ if (code !== 1000) console.log(`🟡 اتصال جیمینای بسته شد (کلید ...${apiKeyUsed.slice(-4)}). کد: ${code}`);
57
+ clientWs.readyState === WebSocket.OPEN && clientWs.close();
58
+ });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
59
  }
 
60
  async function tryConnectToGemini(clientWs, setupData, startIndex, attemptCount = 0) {
61
+ if (attemptCount >= apiKeys.length) {
62
+ console.error(`🔴 تمام ${apiKeys.length} کلید API ناموفق بودند.`);
63
+ if (clientWs.readyState === WebSocket.OPEN) clientWs.send(JSON.stringify({ error: "خطای داخلی سرور." })) && clientWs.close();
64
+ return null;
65
+ }
66
+ const keyIndexToTry = (startIndex + attemptCount) % apiKeys.length;
67
+ const apiKey = apiKeys[keyIndexToTry];
68
+ return new Promise(resolve => {
69
+ const geminiWs = new WebSocket(`wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${apiKey}`);
70
+ const timeout = setTimeout(() => {
71
+ geminiWs.removeAllListeners() && geminiWs.close();
72
+ console.warn(`🟡 اتصال با کلید ...${apiKey.slice(-4)} زمان‌بر شد. امتحان کلید بعدی...`);
73
+ resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
74
+ }, 8000);
75
+ geminiWs.on('open', () => {
76
+ clearTimeout(timeout);
77
+ console.log(`✅ اتصال با کلید اندیس ${keyIndexToTry} موفق بود.`);
78
+ try {
79
+ geminiWs.send(JSON.stringify(setupData));
80
+ } catch (e) {
81
+ clientWs.close();
82
+ resolve(null);
83
+ return;
84
+ }
85
+ attachGeminiEventHandlers(clientWs, geminiWs, apiKey);
86
+ resolve(geminiWs);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
87
  });
88
+ geminiWs.on('error', () => {
89
+ clearTimeout(timeout);
90
+ geminiWs.removeAllListeners();
91
+ console.warn(`🟡 اتصال با کلید ...${apiKey.slice(-4)} ناموفق بود. امتحان کلید بعدی...`);
92
+ resolve(tryConnectToGemini(clientWs, setupData, startIndex, attemptCount + 1));
93
+ });
94
+ });
95
  }
96
 
97
+ // سرو کردن فایل‌های استاتیک
 
 
 
98
  app.use(express.static(path.join(__dirname, '../build')));
 
 
 
 
 
 
 
99
 
100
+ // API Endpoint جدید برای ارسال دستورالعمل‌ها
101
+ app.get('/api/instructions', (req, res) => res.json(personalityInstructions));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
 
103
+ // مدیریت اتصال WebSocket کلاینت (بدون تغییر)
104
+ wss.on('connection', ws => {
105
+ const startingKeyIndex = getStartingKeyIndex();
106
+ console.log(`🔌 کلاینت جدید متصل شد. کلید شروع: اندیس ${startingKeyIndex}`);
107
+ let geminiWs = null;
108
+ ws.on('message', async message => {
109
+ try {
110
+ const data = JSON.parse(message.toString());
111
+ if (data.setup) {
112
+ if (geminiWs) return;
113
+ geminiWs = await tryConnectToGemini(ws, data, startingKeyIndex);
114
+ } else if (geminiWs?.readyState === WebSocket.OPEN) {
115
+ geminiWs.send(JSON.stringify(data));
116
+ }
117
+ } catch (e) { /* خطا */ }
118
+ });
119
+ ws.on('close', () => console.log(`🔌 کلاینت با کلید شروع اندیس ${startingKeyIndex} قطع شد.`) && geminiWs?.close());
120
+ ws.on('error', error => console.error(`🔴 خطای WebSocket کلاینت:`, error) && geminiWs?.close());
121
  });
122
 
123
+ // رسیدگی به سایر درخواست‌ها
124
  app.get('*', (req, res) => res.sendFile(path.join(__dirname, '../build', 'index.html')));
125
 
126
  const PORT = process.env.PORT || 3001;
127
+ server.listen(PORT, () => console.log(`🚀 سرور در حال اجرا روی پورت ${PORT}`));