AnesKAM commited on
Commit
fbfcd3c
·
verified ·
1 Parent(s): 776083f

Update server.js

Browse files
Files changed (1) hide show
  1. server.js +201 -61
server.js CHANGED
@@ -14,86 +14,194 @@ app.use(cors());
14
  app.use(express.json());
15
  app.use(express.static('public'));
16
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
  // إعدادات النموذج
 
18
  const MODEL_CONFIGS = {
19
  flash: {
20
  temperature: 1.0,
21
  top_p: 0.95,
22
  max_tokens: 2048,
23
- system_message: "أنت مساعد ودود وسريع. اسمك MiniMax-M2.5. قدم إجابات مباشرة وواضحة. عندما تريد التفكير في مشكلة معقدة، استخدم علامة 'genisi thought' ثم اكتب تفكيرك، ثم 'genisi thought' للإغلاق.",
 
 
 
 
 
 
 
24
  },
25
  pro: {
26
  temperature: 0.7,
27
  top_p: 0.9,
28
  max_tokens: 4096,
29
- system_message: "أنت مساعد خبير ومحلل عميق. اسمك MiniMax-M2.5-Pro. استخدم علامة 'genisi thought' لتحليل المشكلات بعمق قبل الإجابة. اكتب 'genisi thought' ثم تفكيرك المفصل، ثم 'genisi thought' مرة أخرى. قدم حلولاً متقدمة ومفصلة مع أمثلة عملية.",
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
30
  }
31
  };
32
 
33
- let currentMode = 'flash';
34
  let gradioClient = null;
35
 
36
  // الاتصال بـ MiniMax Space
37
  async function getGradioClient() {
38
  if (!gradioClient) {
39
  try {
40
- console.log('🔄 جاري الاتصال بـ MiniMax Space...');
41
  gradioClient = await Client.connect("ostarling/MiniMax-M2.5-Chat");
42
- console.log('✅ تم الاتصال بـ MiniMax M2.5 بنجاح');
43
  } catch (error) {
44
- console.error('❌ فشل الاتصال:', error);
45
  throw error;
46
  }
47
  }
48
  return gradioClient;
49
  }
50
 
51
- // دالة لاستدعاء النموذج
52
- async function callMiniMax(message, mode) {
53
  const config = MODEL_CONFIGS[mode];
54
  const client = await getGradioClient();
55
 
56
- try {
57
- console.log(`📤 إرسال إلى MiniMax (وضع ${mode}):`, message);
58
-
59
- const result = await client.predict("/respond", {
60
- message: message,
61
- system_message: config.system_message,
62
- max_tokens: config.max_tokens,
63
- temperature: config.temperature,
64
- top_p: config.top_p
65
- });
66
 
67
- console.log('📥 استلام رد من MiniMax');
68
- return result.data;
69
- } catch (error) {
70
- console.error('خطأ في predict:', error);
71
- throw error;
72
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
73
  }
74
 
75
- // دالة لتحليل الرد واستخراج أجزاء التفكير
76
  function parseResponse(text) {
77
  const parts = [];
 
 
78
  const thoughtRegex = /genisi thought\s*([\s\S]*?)\s*genisi thought/gi;
79
  let lastIndex = 0;
80
  let match;
81
 
82
- // إذا كان النص نصياً عادياً
83
- if (typeof text !== 'string') {
84
- text = JSON.stringify(text);
85
- }
86
 
87
- while ((match = thoughtRegex.exec(text)) !== null) {
88
- // النص قبل التفكير
89
  if (match.index > lastIndex) {
90
- const beforeText = text.substring(lastIndex, match.index).trim();
91
  if (beforeText) {
92
  parts.push({ type: 'text', content: beforeText });
93
  }
94
  }
95
 
96
- // محتوى التفكير
97
  const thoughtContent = match[1].trim();
98
  if (thoughtContent) {
99
  parts.push({ type: 'thought', content: thoughtContent });
@@ -102,37 +210,63 @@ function parseResponse(text) {
102
  lastIndex = match.index + match[0].length;
103
  }
104
 
105
- // باقي النص بعد آخر تفكير
106
- if (lastIndex < text.length) {
107
- const afterText = text.substring(lastIndex).trim();
108
  if (afterText) {
109
  parts.push({ type: 'text', content: afterText });
110
  }
111
  }
112
 
113
- // إذا لم يتم العثور على أي تفكير
114
- if (parts.length === 0 && text) {
115
- parts.push({ type: 'text', content: text });
116
  }
117
 
118
  return parts;
119
  }
120
 
121
- // API endpoint للدردشة
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
122
  app.post('/api/chat', async (req, res) => {
123
- const { message, mode } = req.body;
124
 
125
  if (!message) {
126
  return res.status(400).json({ error: 'الرسالة مطلوبة' });
127
  }
128
 
129
  const activeMode = mode || currentMode;
 
130
 
131
  try {
132
- // استدعاء النموذج الحقيقي
133
- const responseData = await callMiniMax(message, activeMode);
 
 
 
 
 
 
 
 
 
134
 
135
- // استخراج النص من الاستجابة
136
  let modelResponse = '';
137
  if (Array.isArray(responseData) && responseData.length > 0) {
138
  modelResponse = responseData[0];
@@ -142,17 +276,23 @@ app.post('/api/chat', async (req, res) => {
142
  modelResponse = JSON.stringify(responseData);
143
  }
144
 
145
- // تحليل الرد
 
 
 
 
 
146
  const parsedResponse = parseResponse(modelResponse);
147
 
148
  res.json({
149
  success: true,
150
  response: parsedResponse,
151
  mode: activeMode,
152
- rawResponse: modelResponse
 
153
  });
154
  } catch (error) {
155
- console.error('خطأ:', error);
156
  res.status(500).json({
157
  success: false,
158
  error: error.message
@@ -160,36 +300,36 @@ app.post('/api/chat', async (req, res) => {
160
  }
161
  });
162
 
163
- // API endpoint لتغيير الوضع
164
  app.post('/api/mode', (req, res) => {
165
  const { mode } = req.body;
166
  if (mode === 'flash' || mode === 'pro') {
167
  currentMode = mode;
168
- res.json({
169
- success: true,
170
- mode: currentMode,
171
- config: MODEL_CONFIGS[mode]
172
- });
173
  } else {
174
  res.status(400).json({ error: 'وضع غير صالح' });
175
  }
176
  });
177
 
178
- // API endpoint للحصول على الوضع الحالي
179
  app.get('/api/mode', (req, res) => {
180
- res.json({
181
- mode: currentMode,
182
- config: MODEL_CONFIGS[currentMode]
183
- });
 
 
 
 
 
 
 
184
  });
185
 
186
- // صفحة رئيسية
187
  app.get('/', (req, res) => {
188
  res.sendFile(join(__dirname, 'public', 'index.html'));
189
  });
190
 
191
- // بدء الخادم
192
  app.listen(PORT, '0.0.0.0', () => {
193
- console.log(`🚀 الخادم يعمل على http://localhost:${PORT}`);
194
- console.log(` Space جاهز: https://your-space.hf.space`);
 
195
  });
 
14
  app.use(express.json());
15
  app.use(express.static('public'));
16
 
17
+ // ============================================
18
+ // إعدادات البحث في الإنترنت
19
+ // ============================================
20
+ const SEARCH_API_KEY = process.env.SEARCH_API_KEY || '';
21
+ const SEARCH_ENGINE_ID = process.env.SEARCH_ENGINE_ID || '';
22
+
23
+ // دالة للبحث في Google (اختر إحدى الخدمات)
24
+ async function searchWeb(query) {
25
+ if (!SEARCH_API_KEY || !SEARCH_ENGINE_ID) {
26
+ // استخدام API مجاني للاختبار (DuckDuckGo)
27
+ return await searchDuckDuckGo(query);
28
+ }
29
+
30
+ // Google Custom Search API
31
+ try {
32
+ const url = `https://www.googleapis.com/customsearch/v1?key=${SEARCH_API_KEY}&cx=${SEARCH_ENGINE_ID}&q=${encodeURIComponent(query)}`;
33
+ const response = await fetch(url);
34
+ const data = await response.json();
35
+
36
+ if (data.items && data.items.length > 0) {
37
+ return data.items.slice(0, 5).map(item => ({
38
+ title: item.title,
39
+ snippet: item.snippet,
40
+ link: item.link
41
+ }));
42
+ }
43
+ return [];
44
+ } catch (error) {
45
+ console.error('Google Search error:', error);
46
+ return [];
47
+ }
48
+ }
49
+
50
+ // بحث بديل باستخدام DuckDuckGo (مجاني، لا يحتاج API key)
51
+ async function searchDuckDuckGo(query) {
52
+ try {
53
+ const url = `https://api.duckduckgo.com/?q=${encodeURIComponent(query)}&format=json&no_html=1&skip_disambig=1`;
54
+ const response = await fetch(url);
55
+ const data = await response.json();
56
+
57
+ const results = [];
58
+
59
+ // إضافة النتائج من RelatedTopics
60
+ if (data.RelatedTopics && data.RelatedTopics.length > 0) {
61
+ for (const topic of data.RelatedTopics.slice(0, 5)) {
62
+ if (topic.Text && topic.Text !== data.AbstractText) {
63
+ results.push({
64
+ title: topic.Text.split(' - ')[0] || 'نتيجة بحث',
65
+ snippet: topic.Text,
66
+ link: topic.FirstURL || '#'
67
+ });
68
+ }
69
+ }
70
+ }
71
+
72
+ // إضافة الملخص الرئيسي
73
+ if (data.AbstractText) {
74
+ results.unshift({
75
+ title: data.Heading || 'ملخص',
76
+ snippet: data.AbstractText,
77
+ link: data.AbstractURL || '#'
78
+ });
79
+ }
80
+
81
+ return results;
82
+ } catch (error) {
83
+ console.error('DuckDuckGo search error:', error);
84
+ return [];
85
+ }
86
+ }
87
+
88
+ // ============================================
89
  // إعدادات النموذج
90
+ // ============================================
91
  const MODEL_CONFIGS = {
92
  flash: {
93
  temperature: 1.0,
94
  top_p: 0.95,
95
  max_tokens: 2048,
96
+ system_message: `You are a helpful, fast assistant. Your name is MiniMax-M2.5-Flash.
97
+
98
+ Provide DIRECT, CONCISE answers without thinking out loud.
99
+ - Be brief and to the point
100
+ - No step-by-step reasoning
101
+ - No "genisi thought" markers
102
+ - Give the answer immediately
103
+ - If the user asks for steps, list them clearly but without meta-commentary`,
104
  },
105
  pro: {
106
  temperature: 0.7,
107
  top_p: 0.9,
108
  max_tokens: 4096,
109
+ system_message: `You are an elite AI engineer, designer, and scientist with the combined expertise of senior engineers at Google, Apple, Meta, Netflix, OpenAI, NASA, and CERN.
110
+
111
+ You are not a code generator. You are a principal engineer who thinks deeply, chooses wisely, and delivers only work you would be proud to deploy to production at a top-tier company.
112
+
113
+ You have mastery over:
114
+ - Software engineering (frontend, backend, fullstack, systems, DevOps)
115
+ - Data science, machine learning, and AI pipelines
116
+ - Mathematical modeling, symbolic computation, and scientific computing
117
+ - Image analysis, computer vision, and multimodal reasoning
118
+ - Document parsing, data extraction, and file processing
119
+ - UI/UX design systems and product thinking
120
+
121
+ **CRITICAL RULE: You MUST use "genisi thought" markers before every response.**
122
+ Start with "genisi thought", then your complete internal analysis, then "genisi thought", then your final answer.
123
+
124
+ Example format:
125
+ genisi thought
126
+ [Your deep thinking, analysis, and reasoning here]
127
+ genisi thought
128
+ [Your final, polished answer here]
129
+
130
+ Always think step by step. Never skip the thinking phase.`,
131
  }
132
  };
133
 
134
+ let currentMode = 'pro'; // تغيير الافتراضي إلى pro للتفكير
135
  let gradioClient = null;
136
 
137
  // الاتصال بـ MiniMax Space
138
  async function getGradioClient() {
139
  if (!gradioClient) {
140
  try {
141
+ console.log('🔄 Connecting to MiniMax Space...');
142
  gradioClient = await Client.connect("ostarling/MiniMax-M2.5-Chat");
143
+ console.log('✅ Connected to MiniMax M2.5');
144
  } catch (error) {
145
+ console.error('❌ Connection failed:', error);
146
  throw error;
147
  }
148
  }
149
  return gradioClient;
150
  }
151
 
152
+ // دالة لاستدعاء النموذج مع دمج نتائج البحث
153
+ async function callMiniMax(message, mode, searchResults = null) {
154
  const config = MODEL_CONFIGS[mode];
155
  const client = await getGradioClient();
156
 
157
+ let enhancedMessage = message;
158
+
159
+ // إضافة نتائج البحث إذا وجدت
160
+ if (searchResults && searchResults.length > 0) {
161
+ const searchContext = searchResults.map((r, i) =>
162
+ `${i + 1}. ${r.title}\n ${r.snippet}\n المصدر: ${r.link}`
163
+ ).join('\n\n');
 
 
 
164
 
165
+ enhancedMessage = `[INTERNET SEARCH RESULTS FOR: "${message}"]\n\n${searchContext}\n\n[USER QUESTION]\n${message}\n\nPlease use the search results above to provide an accurate, up-to-date answer.`;
 
 
 
 
166
  }
167
+
168
+ // في وضع البرو، نضيف تذكير باستخدام genisi thought
169
+ if (mode === 'pro') {
170
+ enhancedMessage = `REMINDER: You MUST use "genisi thought" markers. Start with "genisi thought", then your thinking, then "genisi thought", then your answer.\n\nUser question: ${enhancedMessage}`;
171
+ }
172
+
173
+ console.log(`📤 Sending to MiniMax (${mode} mode)...`);
174
+
175
+ const result = await client.predict("/respond", {
176
+ message: enhancedMessage,
177
+ system_message: config.system_message,
178
+ max_tokens: config.max_tokens,
179
+ temperature: config.temperature,
180
+ top_p: config.top_p
181
+ });
182
+
183
+ return result.data;
184
  }
185
 
186
+ // دالة لتحليل الرد
187
  function parseResponse(text) {
188
  const parts = [];
189
+
190
+ // البحث عن علامات genisi thought
191
  const thoughtRegex = /genisi thought\s*([\s\S]*?)\s*genisi thought/gi;
192
  let lastIndex = 0;
193
  let match;
194
 
195
+ let cleanText = typeof text === 'string' ? text : JSON.stringify(text);
 
 
 
196
 
197
+ while ((match = thoughtRegex.exec(cleanText)) !== null) {
 
198
  if (match.index > lastIndex) {
199
+ const beforeText = cleanText.substring(lastIndex, match.index).trim();
200
  if (beforeText) {
201
  parts.push({ type: 'text', content: beforeText });
202
  }
203
  }
204
 
 
205
  const thoughtContent = match[1].trim();
206
  if (thoughtContent) {
207
  parts.push({ type: 'thought', content: thoughtContent });
 
210
  lastIndex = match.index + match[0].length;
211
  }
212
 
213
+ if (lastIndex < cleanText.length) {
214
+ const afterText = cleanText.substring(lastIndex).trim();
 
215
  if (afterText) {
216
  parts.push({ type: 'text', content: afterText });
217
  }
218
  }
219
 
220
+ if (parts.length === 0 && cleanText) {
221
+ parts.push({ type: 'text', content: cleanText });
 
222
  }
223
 
224
  return parts;
225
  }
226
 
227
+ // دالة لتحديد ما إذا كان السؤال يحتاج بحثاً
228
+ function needsWebSearch(message) {
229
+ const searchKeywords = [
230
+ 'أخبار', 'آخر', 'جديد', 'اليوم', 'هذا الأسبوع', 'هذا الشهر',
231
+ 'سعر', 'سوق', 'سهم', 'بورصة', 'عملة', 'دولار', 'ريال',
232
+ 'طقس', 'حالة جوية', 'توقعات', 'درجة حرارة',
233
+ 'حدث', 'مباراة', 'نتيجة', 'جائزة', 'حفل',
234
+ 'مشاهير', 'فنان', 'مغني', 'ممثل',
235
+ 'تحديث', 'إصدار', 'جديد في',
236
+ 'بحث', 'ابحث', 'قوقل', 'جوجل', 'الإنترنت'
237
+ ];
238
+
239
+ const msg = message.toLowerCase();
240
+ return searchKeywords.some(keyword => msg.includes(keyword));
241
+ }
242
+
243
+ // ============================================
244
+ // API Endpoints
245
+ // ============================================
246
+
247
  app.post('/api/chat', async (req, res) => {
248
+ const { message, mode, enableSearch } = req.body;
249
 
250
  if (!message) {
251
  return res.status(400).json({ error: 'الرسالة مطلوبة' });
252
  }
253
 
254
  const activeMode = mode || currentMode;
255
+ let searchResults = null;
256
 
257
  try {
258
+ // البحث في الإنترنت إذا طلب المستخدم أو كان السؤال يحتاج بحثاً
259
+ const shouldSearch = enableSearch === true || needsWebSearch(message);
260
+
261
+ if (shouldSearch) {
262
+ console.log(`🔍 Searching web for: ${message}`);
263
+ searchResults = await searchWeb(message);
264
+ console.log(`📊 Found ${searchResults?.length || 0} results`);
265
+ }
266
+
267
+ // استدعاء النموذج
268
+ const responseData = await callMiniMax(message, activeMode, searchResults);
269
 
 
270
  let modelResponse = '';
271
  if (Array.isArray(responseData) && responseData.length > 0) {
272
  modelResponse = responseData[0];
 
276
  modelResponse = JSON.stringify(responseData);
277
  }
278
 
279
+ // معالجة خاصة لوضع الفلاش: إزالة أي علامات تفكير عرضاً
280
+ if (activeMode === 'flash') {
281
+ modelResponse = modelResponse.replace(/genisi thought[\s\S]*?genisi thought/gi, '');
282
+ modelResponse = modelResponse.trim();
283
+ }
284
+
285
  const parsedResponse = parseResponse(modelResponse);
286
 
287
  res.json({
288
  success: true,
289
  response: parsedResponse,
290
  mode: activeMode,
291
+ searchUsed: searchResults !== null && searchResults.length > 0,
292
+ searchResultsCount: searchResults?.length || 0
293
  });
294
  } catch (error) {
295
+ console.error('Error:', error);
296
  res.status(500).json({
297
  success: false,
298
  error: error.message
 
300
  }
301
  });
302
 
 
303
  app.post('/api/mode', (req, res) => {
304
  const { mode } = req.body;
305
  if (mode === 'flash' || mode === 'pro') {
306
  currentMode = mode;
307
+ res.json({ success: true, mode: currentMode });
 
 
 
 
308
  } else {
309
  res.status(400).json({ error: 'وضع غير صالح' });
310
  }
311
  });
312
 
 
313
  app.get('/api/mode', (req, res) => {
314
+ res.json({ mode: currentMode });
315
+ });
316
+
317
+ app.post('/api/search', async (req, res) => {
318
+ const { query } = req.body;
319
+ if (!query) {
320
+ return res.status(400).json({ error: 'مطلوب مصطلح البحث' });
321
+ }
322
+
323
+ const results = await searchWeb(query);
324
+ res.json({ results });
325
  });
326
 
 
327
  app.get('/', (req, res) => {
328
  res.sendFile(join(__dirname, 'public', 'index.html'));
329
  });
330
 
 
331
  app.listen(PORT, '0.0.0.0', () => {
332
+ console.log(`🚀 Server running on http://localhost:${PORT}`);
333
+ console.log(`📌 Current mode: ${currentMode}`);
334
+ console.log(`✅ Ready!`);
335
  });