File size: 5,591 Bytes
7f2a14a
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
29e9955
 
 
 
 
 
7f2a14a
 
 
 
 
29e9955
 
 
 
7f2a14a
 
 
 
29e9955
7f2a14a
29e9955
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7f2a14a
29e9955
 
 
 
 
 
 
 
 
 
 
 
7f2a14a
 
 
 
 
29e9955
7f2a14a
 
 
 
29e9955
7f2a14a
 
 
 
 
 
 
 
 
 
 
 
29e9955
7f2a14a
 
29e9955
 
 
7f2a14a
 
 
 
29e9955
7f2a14a
 
29e9955
7f2a14a
 
29e9955
7f2a14a
 
 
 
 
29e9955
 
 
 
 
 
7f2a14a
 
 
 
 
 
 
 
 
 
29e9955
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
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
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 });

app.use(express.static(path.join(__dirname, '../build')));

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);
}

// کلمات ممنوعه (حساس به حروف بزرگ/کوچک با استفاده از Regex)
const forbiddenWordsRegex = [/گوگل/gi, /جمینای/gi, /google/gi, /gemini/gi];
// متن جایگزین ثابت
const replacementText = "من چت بات صوتی برنامه هوش مصنوعی پیشرفته هستم.";

const createGeminiWebSocket = (clientWs, initialSetupData) => {
  const geminiWs = new WebSocket(
    `wss://generativelanguage.googleapis.com/ws/google.ai.generativelanguage.v1alpha.GenerativeService.BidiGenerateContent?key=${GEMINI_API_KEY}`
  );

  geminiWs.on('open', () => {
    console.log('Server: Connected to Gemini API');
    if (initialSetupData) {
       console.log('Server: Sending initial setup to Gemini:', initialSetupData);
       geminiWs.send(JSON.stringify(initialSetupData));
    }
  });

  geminiWs.on('message', (data) => {
    let finalMessageString;
    try {
      const messageString = data.toString();
      let messageObject = JSON.parse(messageString);
      let modified = false;

      // --- 👇 منطق بررسی و جایگزینی متن 👇 ---
      if (messageObject.serverContent && messageObject.serverContent.modelTurn && messageObject.serverContent.modelTurn.parts) {
        messageObject.serverContent.modelTurn.parts = messageObject.serverContent.modelTurn.parts.map(part => {
          if (part.text) {
            // بررسی وجود کلمات ممنوعه در متن این پارت
            const containsForbidden = forbiddenWordsRegex.some(regex => {
              regex.lastIndex = 0; // ریست کردن ایندکس برای تست مجدد
              return regex.test(part.text);
            });

            if (containsForbidden) {
              console.log(`Server: Detected forbidden word in part: "${part.text}". Replacing with fixed response.`);
              // کل متن این پارت را با متن جایگزین عوض می‌کنیم
              part.text = replacementText;
              modified = true;
            }
          }
          return part;
        });
      }
      // --- 👆 پایان منطق بررسی 👆 ---

      // اگر تغییری ایجاد شده، آبجکت را دوباره به رشته تبدیل کن
      finalMessageString = modified ? JSON.stringify(messageObject) : messageString;
      if (modified) {
           console.log('Server: Sending modified message to client:', finalMessageString);
      } else {
           // console.log('Server: Forwarding original message from Gemini:', finalMessageString); // برای دیباگ می‌توانید این لاگ را فعال کنید
      }

    } catch (error) {
      console.error('Server: Error processing/modifying Gemini message:', error);
      // در صورت خطا، سعی می‌کنیم پیام اصلی را بفرستیم
      finalMessageString = data.toString();
      console.log('Server: Forwarding original message due to error.');
    }

    // ارسال پیام نهایی (اصلی یا ویرایش شده) به کلاینت
    try {
        const blob = Buffer.from(finalMessageString);
        clientWs.send(blob, { binary: true });
    } catch (sendError) {
        console.error('Server: Error sending message to client:', sendError);
    }
  });

  geminiWs.on('error', (error) => {
    console.error('Gemini WebSocket error:', error);
    if (clientWs.readyState === WebSocket.OPEN) clientWs.close();
  });

  geminiWs.on('close', (code, reason) => {
    console.log('Gemini WebSocket closed:', code, reason.toString());
    if (clientWs.readyState === WebSocket.OPEN) clientWs.close();
  });

  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('Server: Received from client:', data); // برای دیباگ

      if (data.setup) {
        console.log('Server: Received setup from client:', data.setup);
        if (geminiWs) geminiWs.close();
        geminiWs = createGeminiWebSocket(ws, data);
        return;
      }

      if (geminiWs && geminiWs.readyState === WebSocket.OPEN) {
        // console.log('Server: Forwarding client message to Gemini:', data); // برای دیباگ
        geminiWs.send(JSON.stringify(data));
      } else {
        console.warn('Server: Gemini connection not ready or non-existent. Message from client ignored.');
      }
    } catch (error) {
      console.error('Server: Error processing message from client:', error);
    }
  });

  ws.on('close', () => {
    console.log('Client disconnected');
    if (geminiWs) geminiWs.close();
  });

  ws.on('error', (error) => {
    console.error('Client WebSocket error:', error);
    if (geminiWs) 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(`Server is running on port ${PORT}`);
});