AnesKAM commited on
Commit
fe1cdda
·
verified ·
1 Parent(s): f82b4a2

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +118 -63
index.html CHANGED
@@ -6,18 +6,13 @@
6
  <title>Dual Mode AI</title>
7
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
9
- <!-- ✅ G4F Library للوضع السريع -->
10
- <script type="module">
11
- import { createClient } from 'https://g4f.dev/dist/js/providers.js';
12
- window.g4fClient = createClient('default');
13
- </script>
14
 
15
  <style>
16
  :root {
17
  --bg: #0d1117;
18
  --sidebar: #161b22;
19
- --fast: #238636; /* أخضر للسريع */
20
- --think: #a371f7; /* بنفسجي للمفكر */
21
  --border: #30363d;
22
  --text: #c9d1d9;
23
  }
@@ -80,6 +75,17 @@
80
  .mode-info.fast { background: rgba(35,134,54,0.1); border: 1px solid var(--fast); }
81
  .mode-info.think { background: rgba(163,113,247,0.1); border: 1px solid var(--think); }
82
 
 
 
 
 
 
 
 
 
 
 
 
83
  .chat-container {
84
  flex: 1;
85
  display: flex;
@@ -115,8 +121,9 @@
115
  }
116
 
117
  .message.fast .avatar { background: var(--fast); color: white; }
118
- .message.think .avatar { background: var(--think); color: white; animation: pulse 2s infinite; }
119
 
 
120
  @keyframes pulse {
121
  0%, 100% { box-shadow: 0 0 0 0 rgba(163,113,247,0.4); }
122
  50% { box-shadow: 0 0 0 10px rgba(163,113,247,0); }
@@ -128,17 +135,12 @@
128
  }
129
 
130
  .user .bubble { background: #21262d; }
131
- .ai.fast .bubble { border-color: var(--fast); }
132
- .ai.think .bubble { border-color: var(--think); }
133
 
134
- /* مؤشر التفكير */
135
  .thinking-indicator {
136
- display: flex;
137
- align-items: center;
138
- gap: 8px;
139
- color: var(--think);
140
- font-size: 13px;
141
- margin-bottom: 8px;
142
  }
143
 
144
  .thinking-indicator i { animation: spin 1s linear infinite; }
@@ -149,15 +151,12 @@
149
  bottom: 30px;
150
  left: 50%;
151
  transform: translateX(-50%);
152
- width: 75%;
153
- max-width: 800px;
154
  background: var(--sidebar);
155
  border: 1px solid var(--border);
156
  border-radius: 12px;
157
  padding: 12px;
158
- display: flex;
159
- align-items: center;
160
- gap: 12px;
161
  }
162
 
163
  #userInput {
@@ -174,6 +173,16 @@
174
  .send-btn.fast { background: var(--fast); }
175
  .send-btn.think { background: var(--think); }
176
  .send-btn:disabled { background: #30363d !important; cursor: not-allowed; }
 
 
 
 
 
 
 
 
 
 
177
  </style>
178
  </head>
179
  <body>
@@ -191,13 +200,16 @@
191
  </div>
192
 
193
  <div class="mode-info fast" id="modeInfo">
194
- <strong>G4F Mode</strong><br>
 
 
 
195
  مجاني • فوري • بدون API Key<br>
196
- يستخدم providers متعددة للرد السريع
197
  </div>
198
 
199
  <div style="margin-top: auto; font-size: 11px; color: #8b949e;">
200
- <div id="currentMode">الوضع الحالي: سريع (G4F)</div>
201
  </div>
202
  </aside>
203
 
@@ -207,56 +219,88 @@
207
  <div class="avatar"><i class="fas fa-robot"></i></div>
208
  <div class="bubble">
209
  مرحباً! اختر الوضع المناسب:<br><br>
210
- ⚡ <strong>الوضع السريع:</strong> ردود فورية مجانية عبر G4F<br>
211
- 🧠 <strong>الوضع المفكر:</strong> تحليل عميق عبر Kimi (��حتاج Poe API)
212
  </div>
213
  </div>
214
  </div>
215
 
216
  <div class="input-wrapper">
217
  <input type="text" id="userInput" placeholder="اكتب رسالتك..." autocomplete="off">
218
- <button class="send-btn fast" id="sendBtn" onclick="handleSend()">
219
  <i class="fas fa-paper-plane"></i>
220
  </button>
221
  </div>
222
  </main>
223
 
224
- <script>
225
- let currentMode = 'fast'; // 'fast' أو 'think'
 
 
226
 
227
- function setMode(mode) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
228
  currentMode = mode;
229
 
230
- // تحديث الأزرار
231
  document.querySelectorAll('.mode-btn').forEach(btn => btn.classList.remove('active'));
232
  document.querySelector(`.mode-btn.${mode}`).classList.add('active');
233
 
234
- // تحديث المعلومات
235
  const info = document.getElementById('modeInfo');
236
  const btn = document.getElementById('sendBtn');
237
  const status = document.getElementById('currentMode');
238
 
239
  if (mode === 'fast') {
240
  info.className = 'mode-info fast';
241
- info.innerHTML = '<strong>G4F Mode</strong><br>مجاني • فوري • بدون API Key';
242
  btn.className = 'send-btn fast';
243
  status.textContent = 'الوضع الحالي: سريع (G4F)';
 
 
 
 
 
 
 
 
244
  } else {
245
  info.className = 'mode-info think';
246
- info.innerHTML = '<strong>Kimi Think Mode</strong><br>يبحث ويفكر قبل الإجابة<br>يحتاج Poe API Key في السيرفر';
247
  btn.className = 'send-btn think';
248
  status.textContent = 'الوضع الحالي: مفكر (Kimi)';
249
  }
250
- }
251
 
252
- async function handleSend() {
253
  const input = document.getElementById('userInput');
254
  const btn = document.getElementById('sendBtn');
255
  const text = input.value.trim();
256
 
257
  if (!text) return;
258
 
259
- // إضافة رسالة المستخدم
260
  addMessage(text, 'user');
261
  input.value = '';
262
  input.disabled = true;
@@ -271,17 +315,25 @@
271
  input.disabled = false;
272
  btn.disabled = false;
273
  input.focus();
274
- }
275
 
276
- // ✅ الوضع السريع: G4F مباشرة في المتصفح
277
  async function sendFast(text) {
278
  const msgId = addMessage('', 'ai', 'fast');
279
  const bubble = document.getElementById(msgId).querySelector('.bubble');
280
 
 
 
 
 
 
 
 
 
281
  try {
282
- // استخدام G4F client المستورد من CDN
283
- const result = await window.g4fClient.chat.completions.create({
284
- model: 'auto', // يختار أفضل provider تلقائياً
 
285
  messages: [{ role: 'user', content: text }]
286
  });
287
 
@@ -289,22 +341,22 @@
289
  bubble.innerHTML = marked.parse(content);
290
 
291
  } catch (err) {
292
- bubble.innerHTML = `<span style="color:#f85149">خطأ في G4F: ${err.message}</span>`;
 
293
  }
294
  }
295
 
296
- // ✅ الوضع المفكر: Poe API مع Kimi وإظهار التفكير
297
  async function sendThink(text) {
298
  const msgId = addMessage('', 'ai', 'think');
299
- const container = document.getElementById(msgId);
300
- const bubble = container.querySelector('.bubble');
301
 
302
  // إضافة مؤشر التفكير
303
- const thinkingDiv = document.createElement('div');
304
- thinkingDiv.className = 'thinking-indicator';
305
- thinkingDiv.id = `thinking-${msgId}`;
306
- thinkingDiv.innerHTML = '<i class="fas fa-circle-notch"></i> يفكر...';
307
- container.insertBefore(thinkingDiv, bubble);
308
 
309
  try {
310
  const res = await fetch('/api/think', {
@@ -316,7 +368,7 @@
316
  const reader = res.body.getReader();
317
  const decoder = new TextDecoder();
318
  let fullText = "";
319
- let isResponding = false;
320
 
321
  while (true) {
322
  const { done, value } = await reader.read();
@@ -334,27 +386,27 @@
334
  try {
335
  const json = JSON.parse(data);
336
 
337
- // إخفاء مؤشر التفكير عند بدء الرد
338
- if (json.status === 'responding' && !isResponding) {
339
- isResponding = true;
340
- const indicator = document.getElementById(`thinking-${msgId}`);
341
- if (indicator) indicator.style.display = 'none';
342
  }
343
 
344
  if (json.content) {
345
  fullText += json.content;
346
  bubble.innerHTML = marked.parse(fullText);
 
 
347
  }
348
  } catch (e) {}
349
  }
350
  }
351
 
352
  } catch (err) {
353
- bubble.innerHTML = `<span style="color:#f85149">خطأ: ${err.message}</span>`;
354
  } finally {
355
- // إخفاء المؤشر إذا بقي ظاهراً
356
- const indicator = document.getElementById(`thinking-${msgId}`);
357
- if (indicator) indicator.style.display = 'none';
358
  }
359
  }
360
 
@@ -377,8 +429,11 @@
377
  }
378
 
379
  document.getElementById('userInput').addEventListener('keypress', (e) => {
380
- if (e.key === 'Enter') handleSend();
381
  });
 
 
 
382
  </script>
383
  </body>
384
  </html>
 
6
  <title>Dual Mode AI</title>
7
  <link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
8
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
 
 
 
 
 
9
 
10
  <style>
11
  :root {
12
  --bg: #0d1117;
13
  --sidebar: #161b22;
14
+ --fast: #238636;
15
+ --think: #a371f7;
16
  --border: #30363d;
17
  --text: #c9d1d9;
18
  }
 
75
  .mode-info.fast { background: rgba(35,134,54,0.1); border: 1px solid var(--fast); }
76
  .mode-info.think { background: rgba(163,113,247,0.1); border: 1px solid var(--think); }
77
 
78
+ .status-badge {
79
+ display: inline-block;
80
+ font-size: 10px;
81
+ padding: 2px 6px;
82
+ border-radius: 4px;
83
+ margin-right: 6px;
84
+ }
85
+ .status-badge.ready { background: var(--fast); color: white; }
86
+ .status-badge.loading { background: #d29922; color: black; }
87
+ .status-badge.error { background: #f85149; color: white; }
88
+
89
  .chat-container {
90
  flex: 1;
91
  display: flex;
 
121
  }
122
 
123
  .message.fast .avatar { background: var(--fast); color: white; }
124
+ .message.think .avatar { background: var(--think); color: white; }
125
 
126
+ .thinking .avatar { animation: pulse 2s infinite; }
127
  @keyframes pulse {
128
  0%, 100% { box-shadow: 0 0 0 0 rgba(163,113,247,0.4); }
129
  50% { box-shadow: 0 0 0 10px rgba(163,113,247,0); }
 
135
  }
136
 
137
  .user .bubble { background: #21262d; }
138
+ .ai.fast .bubble { border-color: rgba(35,134,54,0.3); }
139
+ .ai.think .bubble { border-color: rgba(163,113,247,0.3); }
140
 
 
141
  .thinking-indicator {
142
+ display: flex; align-items: center; gap: 8px;
143
+ color: var(--think); font-size: 13px; margin-bottom: 8px;
 
 
 
 
144
  }
145
 
146
  .thinking-indicator i { animation: spin 1s linear infinite; }
 
151
  bottom: 30px;
152
  left: 50%;
153
  transform: translateX(-50%);
154
+ width: 75%; max-width: 800px;
 
155
  background: var(--sidebar);
156
  border: 1px solid var(--border);
157
  border-radius: 12px;
158
  padding: 12px;
159
+ display: flex; align-items: center; gap: 12px;
 
 
160
  }
161
 
162
  #userInput {
 
173
  .send-btn.fast { background: var(--fast); }
174
  .send-btn.think { background: var(--think); }
175
  .send-btn:disabled { background: #30363d !important; cursor: not-allowed; }
176
+
177
+ .error-box {
178
+ background: rgba(248,81,73,0.1);
179
+ border: 1px solid #f85149;
180
+ color: #f85149;
181
+ padding: 8px 12px;
182
+ border-radius: 6px;
183
+ font-size: 12px;
184
+ margin-top: 8px;
185
+ }
186
  </style>
187
  </head>
188
  <body>
 
200
  </div>
201
 
202
  <div class="mode-info fast" id="modeInfo">
203
+ <strong>
204
+ G4F Mode
205
+ <span class="status-badge loading" id="g4fStatus">جاري التحميل...</span>
206
+ </strong><br>
207
  مجاني • فوري • بدون API Key<br>
208
+ <div id="g4fError"></div>
209
  </div>
210
 
211
  <div style="margin-top: auto; font-size: 11px; color: #8b949e;">
212
+ <div id="currentMode">الوضع الحالي: سريع</div>
213
  </div>
214
  </aside>
215
 
 
219
  <div class="avatar"><i class="fas fa-robot"></i></div>
220
  <div class="bubble">
221
  مرحباً! اختر الوضع المناسب:<br><br>
222
+ ⚡ <strong>الوضع السريع:</strong> ردود فورية مجانية<br>
223
+ 🧠 <strong>الوضع المفكر:</strong> تحليل عميق عبر Kimi
224
  </div>
225
  </div>
226
  </div>
227
 
228
  <div class="input-wrapper">
229
  <input type="text" id="userInput" placeholder="اكتب رسالتك..." autocomplete="off">
230
+ <button class="send-btn fast" id="sendBtn" onclick="handleSend()" disabled>
231
  <i class="fas fa-paper-plane"></i>
232
  </button>
233
  </div>
234
  </main>
235
 
236
+ <script type="module">
237
+ // استيراد G4F بشكل صحيح كـ ES Module
238
+ let g4fClient = null;
239
+ let g4fReady = false;
240
 
241
+ // محاولة تحميل G4F
242
+ async function initG4F() {
243
+ try {
244
+ const { createClient } = await import('https://g4f.dev/dist/js/providers.js');
245
+ g4fClient = createClient('azure');
246
+ g4fReady = true;
247
+
248
+ document.getElementById('g4fStatus').textContent = 'جاهز';
249
+ document.getElementById('g4fStatus').className = 'status-badge ready';
250
+ document.getElementById('sendBtn').disabled = false;
251
+
252
+ console.log('✅ G4F Client Ready');
253
+ } catch (err) {
254
+ console.error('❌ G4F Error:', err);
255
+ document.getElementById('g4fStatus').textContent = 'خطأ';
256
+ document.getElementById('g4fStatus').className = 'status-badge error';
257
+ document.getElementById('g4fError').innerHTML =
258
+ `<div class="error-box">فشل تحميل G4F. سيتم استخدام الوضع المفكر فقط.</div>`;
259
+
260
+ // تفعيل الوضع المفكر تلقائياً إذا فشل G4F
261
+ setMode('think');
262
+ document.getElementById('sendBtn').disabled = false;
263
+ }
264
+ }
265
+
266
+ let currentMode = 'fast';
267
+
268
+ window.setMode = function(mode) {
269
  currentMode = mode;
270
 
 
271
  document.querySelectorAll('.mode-btn').forEach(btn => btn.classList.remove('active'));
272
  document.querySelector(`.mode-btn.${mode}`).classList.add('active');
273
 
 
274
  const info = document.getElementById('modeInfo');
275
  const btn = document.getElementById('sendBtn');
276
  const status = document.getElementById('currentMode');
277
 
278
  if (mode === 'fast') {
279
  info.className = 'mode-info fast';
 
280
  btn.className = 'send-btn fast';
281
  status.textContent = 'الوضع الحالي: سريع (G4F)';
282
+
283
+ if (!g4fReady) {
284
+ info.innerHTML = `
285
+ <strong>G4F Mode</strong>
286
+ <span class="status-badge error">غير متوفر</span><br>
287
+ فشل الاتصال بـ G4F
288
+ `;
289
+ }
290
  } else {
291
  info.className = 'mode-info think';
 
292
  btn.className = 'send-btn think';
293
  status.textContent = 'الوضع الحالي: مفكر (Kimi)';
294
  }
295
+ };
296
 
297
+ window.handleSend = async function() {
298
  const input = document.getElementById('userInput');
299
  const btn = document.getElementById('sendBtn');
300
  const text = input.value.trim();
301
 
302
  if (!text) return;
303
 
 
304
  addMessage(text, 'user');
305
  input.value = '';
306
  input.disabled = true;
 
315
  input.disabled = false;
316
  btn.disabled = false;
317
  input.focus();
318
+ };
319
 
 
320
  async function sendFast(text) {
321
  const msgId = addMessage('', 'ai', 'fast');
322
  const bubble = document.getElementById(msgId).querySelector('.bubble');
323
 
324
+ // التحقق من توفر G4F
325
+ if (!g4fReady || !g4fClient) {
326
+ bubble.innerHTML = `<span style="color:#f85149">
327
+ ⚠️ G4F غير متوفر. <button onclick="setMode('think'); handleSend()" style="background:var(--think);border:none;color:white;padding:4px 8px;border-radius:4px;cursor:pointer;">التبديل للوضع المفكر</button>
328
+ </span>`;
329
+ return;
330
+ }
331
+
332
  try {
333
+ bubble.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i> جاري الرد...';
334
+
335
+ const result = await g4fClient.chat.completions.create({
336
+ model: 'auto',
337
  messages: [{ role: 'user', content: text }]
338
  });
339
 
 
341
  bubble.innerHTML = marked.parse(content);
342
 
343
  } catch (err) {
344
+ console.error('G4F Error:', err);
345
+ bubble.innerHTML = `<span style="color:#f85149">خطأ في G4F: ${err.message}. <a href="#" onclick="setMode('think')" style="color:var(--think)">جرب الوضع المفكر</a></span>`;
346
  }
347
  }
348
 
 
349
  async function sendThink(text) {
350
  const msgId = addMessage('', 'ai', 'think');
351
+ const msgElement = document.getElementById(msgId);
352
+ const bubble = msgElement.querySelector('.bubble');
353
 
354
  // إضافة مؤشر التفكير
355
+ msgElement.classList.add('thinking');
356
+ const indicator = document.createElement('div');
357
+ indicator.className = 'thinking-indicator';
358
+ indicator.innerHTML = '<i class="fas fa-circle-notch"></i> يفكر...';
359
+ bubble.parentNode.insertBefore(indicator, bubble);
360
 
361
  try {
362
  const res = await fetch('/api/think', {
 
368
  const reader = res.body.getReader();
369
  const decoder = new TextDecoder();
370
  let fullText = "";
371
+ let respondingStarted = false;
372
 
373
  while (true) {
374
  const { done, value } = await reader.read();
 
386
  try {
387
  const json = JSON.parse(data);
388
 
389
+ if (json.status === 'responding' && !respondingStarted) {
390
+ respondingStarted = true;
391
+ indicator.style.display = 'none';
392
+ msgElement.classList.remove('thinking');
 
393
  }
394
 
395
  if (json.content) {
396
  fullText += json.content;
397
  bubble.innerHTML = marked.parse(fullText);
398
+ } else if (json.error) {
399
+ bubble.innerHTML = `<span style="color:#f85149">خطأ: ${json.error}</span>`;
400
  }
401
  } catch (e) {}
402
  }
403
  }
404
 
405
  } catch (err) {
406
+ bubble.innerHTML = `<span style="color:#f85149">فشل الاتصال بالسيرفر: ${err.message}</span>`;
407
  } finally {
408
+ indicator.style.display = 'none';
409
+ msgElement.classList.remove('thinking');
 
410
  }
411
  }
412
 
 
429
  }
430
 
431
  document.getElementById('userInput').addEventListener('keypress', (e) => {
432
+ if (e.key === 'Enter') window.handleSend();
433
  });
434
+
435
+ // ✅ بدء التحميل
436
+ initG4F();
437
  </script>
438
  </body>
439
  </html>