joermd commited on
Commit
6746921
·
verified ·
1 Parent(s): bbf482a

Update index.html

Browse files
Files changed (1) hide show
  1. index.html +310 -237
index.html CHANGED
@@ -53,6 +53,10 @@
53
  color: #e5e5e5;
54
  }
55
 
 
 
 
 
56
  .dark-mode .action-button {
57
  color: #e5e5e5;
58
  background-color: #404040;
@@ -152,6 +156,10 @@
152
  transform: translateY(0);
153
  }
154
  }
 
 
 
 
155
  </style>
156
  </head>
157
  <body class="text-lg light-mode">
@@ -160,6 +168,21 @@
160
  <div class="flex items-center flex-1">
161
  <span class="text-2xl font-bold text-indigo-600">Speedy</span>
162
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
163
  <button id="darkModeToggle" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
164
  <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
165
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
@@ -200,6 +223,12 @@
200
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path>
201
  </svg>
202
  </a>
 
 
 
 
 
 
203
  <select id="styleSelect" class="style-select bg-gray-50 border border-gray-200 text-gray-600 text-sm rounded-lg pl-8 pr-2 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-200">
204
  <option value="short">⚡ ردود قصيرة</option>
205
  <option value="normal" selected>◯ عادي</option>
@@ -209,249 +238,293 @@
209
  </div>
210
  </div>
211
  </footer>
212
- <script>
213
- const API_URL = 'https://j8fp9mu44k547j-7777.proxy.runpod.net/proxy/8000/chat';
214
- const messagesContainer = document.getElementById('messagesContainer');
215
- const messageInput = document.getElementById('messageInput');
216
- const sendButton = document.getElementById('sendMessage');
217
- const clearButton = document.getElementById('clearChat');
218
- const styleSelect = document.getElementById('styleSelect');
219
- const darkModeToggle = document.getElementById('darkModeToggle');
220
- let chatHistory = [];
221
- let currentStyle = 'normal';
222
- let currentController = null;
223
-
224
- // Dark mode toggle
225
- darkModeToggle.addEventListener('click', () => {
226
- document.body.classList.toggle('dark-mode');
227
- document.body.classList.toggle('light-mode');
228
- });
229
-
230
- styleSelect.addEventListener('change', (e) => {
231
- currentStyle = e.target.value;
232
- });
233
-
234
- function createUserMessage(text) {
235
- let prefix = '';
236
- if (currentStyle === 'short') {
237
- prefix = 'اعطني رد باختصار وسرعة: ';
238
- } else if (currentStyle === 'long') {
239
- prefix = 'اعطني رد مفصل وموسع: ';
240
- }
241
-
242
- return `
243
- <div class="message flex justify-end mb-4">
244
- <div class="max-w-[80%]">
245
- <div class="bg-indigo-500 text-white rounded-lg p-4 shadow-sm">
246
- <p class="text-lg">${text}</p>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
247
  </div>
248
- </div>
249
- </div>
250
- `;
251
- }
252
-
253
- function createBotMessage(text, messageId) {
254
- return `
255
- <div class="message flex justify-start mb-4">
256
- <div class="flex-shrink-0 mt-1">
257
- <img src="https://ufastpro.com/wp-content/uploads/2024/12/3.png" alt="Bot Avatar" class="bot-avatar">
258
- </div>
259
- <div class="max-w-[80%] mr-3">
260
- <div class="bot-message bg-white rounded-lg p-4 shadow-sm">
261
- <p id="${messageId}" class="text-gray-700"></p>
262
- <div class="message-actions">
263
- <button class="action-button copy-button" data-message-id="${messageId}">
264
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
265
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path>
266
- </svg>
267
- نسخ
268
- </button>
269
- <button class="action-button regenerate-button" data-message-id="${messageId}">
270
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
271
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
272
- </svg>
273
- إعادة التوليد
274
- </button>
275
- <button class="action-button like-button" data-message-id="${messageId}">
276
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
277
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"></path>
278
- </svg>
279
- أعجبني
280
- </button>
281
- <button class="action-button dislike-button" data-message-id="${messageId}">
282
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
283
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.736 3h4.018c.163 0 .326.02.485.06L17 4m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5 0v2a2 2 0 01-2 2h-2.5"></path>
284
- </svg>
285
- لم يعجبني
286
- </button>
287
  </div>
288
  </div>
289
- </div>
290
- </div>
291
- `;
292
- }
293
-
294
- async function typeText(elementId, text) {
295
- const element = document.getElementById(elementId);
296
- element.innerHTML = '';
297
- const words = text.split(' ');
298
-
299
- for (let i = 0; i < words.length; i++) {
300
- const span = document.createElement('span');
301
- span.textContent = words[i] + ' ';
302
- span.className = 'typing-animation';
303
- element.appendChild(span);
304
- await new Promise(resolve => setTimeout(resolve, 50));
305
- }
306
- }
307
-
308
- function toggleSendButton(isGenerating) {
309
- const sendButton = document.getElementById('sendMessage');
310
- if (isGenerating) {
311
- sendButton.classList.add('stop-generation');
312
- sendButton.innerHTML = `
313
- <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
314
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
315
- </svg>
316
- `;
317
- } else {
318
- sendButton.classList.remove('stop-generation');
319
- sendButton.innerHTML = `
320
- <svg class="w-6 h-6 transform rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24">
321
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
322
- </svg>
323
- `;
324
- }
325
- }
326
-
327
- async function sendMessage() {
328
- const message = messageInput.value.trim();
329
- if (!message) return;
330
-
331
- if (currentController) {
332
- currentController.abort();
333
- currentController = null;
334
- toggleSendButton(false);
335
- return;
336
- }
337
-
338
- messageInput.value = '';
339
- adjustTextareaHeight();
340
-
341
- const messageId = 'msg-' + Date.now();
342
- let actualMessage = message;
343
-
344
- if (currentStyle === 'short') {
345
- actualMessage = 'اعطني رد باختصار وسرعة: ' + message;
346
- } else if (currentStyle === 'long') {
347
- actualMessage = 'اعطني رد مفصل وموسع: ' + message;
348
- }
349
-
350
- messagesContainer.insertAdjacentHTML('beforeend', createUserMessage(message));
351
- messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', messageId));
352
- scrollToBottom();
353
-
354
- try {
355
- currentController = new AbortController();
356
- toggleSendButton(true);
357
-
358
- const response = await fetch(API_URL, {
359
- method: 'POST',
360
- headers: { 'Content-Type': 'application/json' },
361
- body: JSON.stringify({
362
- message: actualMessage,
363
- history: chatHistory
364
- }),
365
- signal: currentController.signal
366
- });
367
 
368
- const data = await response.json();
369
- await typeText(messageId, data.response);
370
-
371
- chatHistory.push({
372
- human: actualMessage,
373
- assistant: data.response
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
374
  });
375
- } catch (error) {
376
- if (error.name === 'AbortError') {
377
- document.getElementById(messageId).textContent = 'تم إيقاف التوليد.';
378
- } else {
379
- document.getElementById(messageId).textContent = 'عذراً، حدث خطأ في المعالجة.';
 
380
  }
381
- } finally {
382
- currentController = null;
383
- toggleSendButton(false);
384
- }
385
- scrollToBottom();
386
- }
387
-
388
- // Event Listeners for Message Actions
389
- document.addEventListener('click', async (e) => {
390
- if (e.target.closest('.copy-button')) {
391
- const messageId = e.target.closest('.copy-button').dataset.messageId;
392
- const text = document.getElementById(messageId).textContent;
393
- await navigator.clipboard.writeText(text);
394
- e.target.closest('.copy-button').textContent = 'تم النسخ!';
395
- setTimeout(() => {
396
- e.target.closest('.copy-button').innerHTML = `
397
- <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
398
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path>
399
- </svg>
400
- نسخ
401
- `;
402
- }, 2000);
403
- }
404
-
405
- if (e.target.closest('.regenerate-button')) {
406
- const messageId = e.target.closest('.regenerate-button').dataset.messageId;
407
- // إعادة إرسال آخر رسالة في المحادثة
408
- if (chatHistory.length > 0) {
409
- const lastMessage = chatHistory[chatHistory.length - 1].human;
410
- messageInput.value = lastMessage;
411
- sendMessage();
412
  }
413
- }
414
-
415
- if (e.target.closest('.like-button')) {
416
- const button = e.target.closest('.like-button');
417
- button.classList.toggle('text-green-500');
418
- }
419
-
420
- if (e.target.closest('.dislike-button')) {
421
- const button = e.target.closest('.dislike-button');
422
- button.classList.toggle('text-red-500');
423
- }
424
- });
425
-
426
- function scrollToBottom() {
427
- window.scrollTo({
428
- top: document.documentElement.scrollHeight,
429
- behavior: 'smooth'
430
- });
431
- }
432
-
433
- function adjustTextareaHeight() {
434
- messageInput.style.height = 'auto';
435
- messageInput.style.height = messageInput.scrollHeight + 'px';
436
- }
437
-
438
- sendButton.addEventListener('click', sendMessage);
439
- messageInput.addEventListener('keypress', (e) => {
440
- if (e.key === 'Enter' && !e.shiftKey) {
441
- e.preventDefault();
442
- sendMessage();
443
- }
444
- });
445
- messageInput.addEventListener('input', adjustTextareaHeight);
446
- clearButton.addEventListener('click', () => {
447
- messagesContainer.innerHTML = '';
448
- chatHistory = [];
449
- });
450
-
451
- // Initial welcome message
452
- const initialMessageId = 'msg-initial';
453
- messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', initialMessageId));
454
- typeText(initialMessageId, 'مرحباً! كيف يمكنني مساعدتك اليوم؟');
455
- </script>
456
  </body>
457
  </html>
 
53
  color: #e5e5e5;
54
  }
55
 
56
+ .dark-mode .bot-message p {
57
+ color: #ffffff !important;
58
+ }
59
+
60
  .dark-mode .action-button {
61
  color: #e5e5e5;
62
  background-color: #404040;
 
156
  transform: translateY(0);
157
  }
158
  }
159
+
160
+ #fileInput {
161
+ display: none;
162
+ }
163
  </style>
164
  </head>
165
  <body class="text-lg light-mode">
 
168
  <div class="flex items-center flex-1">
169
  <span class="text-2xl font-bold text-indigo-600">Speedy</span>
170
  </div>
171
+ <a href="ufastpro.com" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
172
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
173
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-6 0a1 1 0 001-1v-4a1 1 0 011-1h2a1 1 0 011 1v4a1 1 0 001 1m-6 0h6"></path>
174
+ </svg>
175
+ </a>
176
+ <a href="/profile" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
177
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
178
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M16 7a4 4 0 11-8 0 4 4 0 018 0zM12 14a7 7 0 00-7 7h14a7 7 0 00-7-7z"></path>
179
+ </svg>
180
+ </a>
181
+ <a href="https://joermd-mostasharak.static.hf.space" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
182
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
183
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M3 6l3 1m0 0l-3 9a5.002 5.002 0 006.001 0M6 7l3 9M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9m-3-9l-6-2M6 7l-3-1m3 1l3 9a5.002 5.002 0 006.001 0M6 7l6-2m6 2l3-1m-3 1l-3 9a5.002 5.002 0 006.001 0M18 7l3 9"></path>
184
+ </svg>
185
+ </a>
186
  <button id="darkModeToggle" class="text-gray-500 hover:bg-gray-50 p-2 rounded-full transition-colors mr-2">
187
  <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
188
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M20.354 15.354A9 9 0 018.646 3.646 9.003 9.003 0 0012 21a9.003 9.003 0 008.354-5.646z"></path>
 
223
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19 11a7 7 0 01-7 7m0 0a7 7 0 01-7-7m7 7v4m0 0H8m4 0h4m-4-8a3 3 0 01-3-3V5a3 3 0 116 0v6a3 3 0 01-3 3z"></path>
224
  </svg>
225
  </a>
226
+ <input type="file" id="fileInput" multiple />
227
+ <button id="fileButton" class="bg-blue-500 hover:bg-blue-600 text-white rounded-full p-2 transition-colors">
228
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
229
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M15.172 7l-6.586 6.586a2 2 0 102.828 2.828l6.414-6.586a4 4 0 00-5.656-5.656l-6.415 6.585a6 6 0 108.486 8.486L20.5 13"></path>
230
+ </svg>
231
+ </button>
232
  <select id="styleSelect" class="style-select bg-gray-50 border border-gray-200 text-gray-600 text-sm rounded-lg pl-8 pr-2 py-2 focus:outline-none focus:ring-2 focus:ring-indigo-200">
233
  <option value="short">⚡ ردود قصيرة</option>
234
  <option value="normal" selected>◯ عادي</option>
 
238
  </div>
239
  </div>
240
  </footer>
241
+
242
+ <script>
243
+ // Previous JavaScript code remains the same until the file handling section
244
+ const API_URL = 'https://j8fp9mu44k547j-7777.proxy.runpod.net/proxy/8000/chat';
245
+ const messagesContainer = document.getElementById('messagesContainer');
246
+ const messageInput = document.getElementById('messageInput');
247
+ const sendButton = document.getElementById('sendMessage');
248
+ const clearButton = document.getElementById('clearChat');
249
+ const styleSelect = document.getElementById('styleSelect');
250
+ const darkModeToggle = document.getElementById('darkModeToggle');
251
+ const fileInput = document.getElementById('fileInput');
252
+ const fileButton = document.getElementById('fileButton');
253
+ let chatHistory = [];
254
+ let currentStyle = 'normal';
255
+ let currentController = null;
256
+
257
+ // File handling
258
+ fileButton.addEventListener('click', () => {
259
+ fileInput.click();
260
+ });
261
+
262
+ // ... (previous code remains the same until the file handling event listener)
263
+
264
+ fileInput.addEventListener('change', async (e) => {
265
+ const files = Array.from(e.target.files);
266
+ const formData = new FormData();
267
+
268
+ files.forEach(file => {
269
+ formData.append('files', file);
270
+ });
271
+
272
+ try {
273
+ const response = await fetch(`${API_URL}/upload`, {
274
+ method: 'POST',
275
+ body: formData
276
+ });
277
+
278
+ if (!response.ok) {
279
+ throw new Error('File upload failed');
280
+ }
281
+
282
+ const data = await response.json();
283
+
284
+ // Create a message showing the uploaded files
285
+ const fileNames = files.map(file => file.name).join(', ');
286
+ messageInput.value = `تم رفع الملفات: ${fileNames}`;
287
+ sendMessage();
288
+
289
+ // Clear the file input
290
+ fileInput.value = '';
291
+ } catch (error) {
292
+ console.error('Error uploading files:', error);
293
+ messageInput.value = 'عذراً، حدث خطأ أثناء رفع الملفات.';
294
+ sendMessage();
295
+ }
296
+ });
297
+
298
+ // Dark mode toggle
299
+ darkModeToggle.addEventListener('click', () => {
300
+ document.body.classList.toggle('dark-mode');
301
+ document.body.classList.toggle('light-mode');
302
+ });
303
+
304
+ styleSelect.addEventListener('change', (e) => {
305
+ currentStyle = e.target.value;
306
+ });
307
+
308
+ function createUserMessage(text) {
309
+ let prefix = '';
310
+ if (currentStyle === 'short') {
311
+ prefix = 'اعطني رد باختصار وسرعة: ';
312
+ } else if (currentStyle === 'long') {
313
+ prefix = 'اعطني رد مفصل وموسع: ';
314
+ }
315
+
316
+ return `
317
+ <div class="message flex justify-end mb-4">
318
+ <div class="max-w-[80%]">
319
+ <div class="bg-indigo-500 text-white rounded-lg p-4 shadow-sm">
320
+ <p class="text-lg">${text}</p>
321
+ </div>
322
+ </div>
323
  </div>
324
+ `;
325
+ }
326
+
327
+ function createBotMessage(text, messageId) {
328
+ return `
329
+ <div class="message flex justify-start mb-4">
330
+ <div class="flex-shrink-0 mt-1">
331
+ <img src="https://ufastpro.com/wp-content/uploads/2024/12/3.png" alt="Bot Avatar" class="bot-avatar">
332
+ </div>
333
+ <div class="max-w-[80%] mr-3">
334
+ <div class="bot-message bg-white rounded-lg p-4 shadow-sm">
335
+ <p id="${messageId}" class="text-gray-700"></p>
336
+ <div class="message-actions">
337
+ <button class="action-button copy-button" data-message-id="${messageId}">
338
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
339
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path>
340
+ </svg>
341
+ نسخ
342
+ </button>
343
+ <button class="action-button regenerate-button" data-message-id="${messageId}">
344
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
345
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
346
+ </svg>
347
+ إعادة التوليد
348
+ </button>
349
+ <button class="action-button like-button" data-message-id="${messageId}">
350
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
351
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 10h4.764a2 2 0 011.789 2.894l-3.5 7A2 2 0 0115.263 21h-4.017c-.163 0-.326-.02-.485-.06L7 20m7-10V5a2 2 0 00-2-2h-.095c-.5 0-.905.405-.905.905 0 .714-.211 1.412-.608 2.006L7 11v9m7-10h-2M7 20H5a2 2 0 01-2-2v-6a2 2 0 012-2h2.5"></path>
352
+ </svg>
353
+ أعجبني
354
+ </button>
355
+ <button class="action-button dislike-button" data-message-id="${messageId}">
356
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
357
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M10 14H5.236a2 2 0 01-1.789-2.894l3.5-7A2 2 0 018.736 3h4.018c.163 0 .326.02.485.06L17 4m-7 10v5a2 2 0 002 2h.095c.5 0 .905-.405.905-.905 0-.714.211-1.412.608-2.006L17 13V4m-7 10h2m5 0v2a2 2 0 01-2 2h-2.5"></path>
358
+ </svg>
359
+ لم يعجبني
360
+ </button>
361
+ </div>
362
+ </div>
363
  </div>
364
  </div>
365
+ `;
366
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
 
368
+ async function typeText(elementId, text) {
369
+ const element = document.getElementById(elementId);
370
+ element.innerHTML = '';
371
+ const words = text.split(' ');
372
+
373
+ for (let i = 0; i < words.length; i++) {
374
+ const span = document.createElement('span');
375
+ span.textContent = words[i] + ' ';
376
+ span.className = 'typing-animation';
377
+ element.appendChild(span);
378
+ await new Promise(resolve => setTimeout(resolve, 50));
379
+ }
380
+ }
381
+
382
+ function toggleSendButton(isGenerating) {
383
+ const sendButton = document.getElementById('sendMessage');
384
+ if (isGenerating) {
385
+ sendButton.classList.add('stop-generation');
386
+ sendButton.innerHTML = `
387
+ <svg class="w-6 h-6" fill="none" stroke="currentColor" viewBox="0 0 24 24">
388
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
389
+ </svg>
390
+ `;
391
+ } else {
392
+ sendButton.classList.remove('stop-generation');
393
+ sendButton.innerHTML = `
394
+ <svg class="w-6 h-6 transform rotate-90" fill="none" stroke="currentColor" viewBox="0 0 24 24">
395
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 10l7-7m0 0l7 7m-7-7v18"></path>
396
+ </svg>
397
+ `;
398
+ }
399
+ }
400
+
401
+ async function sendMessage() {
402
+ const message = messageInput.value.trim();
403
+ if (!message) return;
404
+
405
+ if (currentController) {
406
+ currentController.abort();
407
+ currentController = null;
408
+ toggleSendButton(false);
409
+ return;
410
+ }
411
+
412
+ messageInput.value = '';
413
+ adjustTextareaHeight();
414
+
415
+ const messageId = 'msg-' + Date.now();
416
+ let actualMessage = message;
417
+
418
+ if (currentStyle === 'short') {
419
+ actualMessage = 'اعطني رد باختصار وسرعة: ' + message;
420
+ } else if (currentStyle === 'long') {
421
+ actualMessage = 'اعطني رد مفصل وموسع: ' + message;
422
+ }
423
+
424
+ messagesContainer.insertAdjacentHTML('beforeend', createUserMessage(message));
425
+ messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', messageId));
426
+ scrollToBottom();
427
+
428
+ try {
429
+ currentController = new AbortController();
430
+ toggleSendButton(true);
431
+
432
+ const response = await fetch(API_URL, {
433
+ method: 'POST',
434
+ headers: { 'Content-Type': 'application/json' },
435
+ body: JSON.stringify({
436
+ message: actualMessage,
437
+ history: chatHistory
438
+ }),
439
+ signal: currentController.signal
440
+ });
441
+
442
+ const data = await response.json();
443
+ await typeText(messageId, data.response);
444
+
445
+ chatHistory.push({
446
+ human: actualMessage,
447
+ assistant: data.response
448
+ });
449
+ } catch (error) {
450
+ if (error.name === 'AbortError') {
451
+ document.getElementById(messageId).textContent = 'تم إيقاف التوليد.';
452
+ } else {
453
+ document.getElementById(messageId).textContent = 'عذراً، حدث خطأ في المعالجة.';
454
+ }
455
+ } finally {
456
+ currentController = null;
457
+ toggleSendButton(false);
458
+ }
459
+ scrollToBottom();
460
+ }
461
+
462
+ // Event Listeners for Message Actions
463
+ document.addEventListener('click', async (e) => {
464
+ if (e.target.closest('.copy-button')) {
465
+ const messageId = e.target.closest('.copy-button').dataset.messageId;
466
+ const text = document.getElementById(messageId).textContent;
467
+ await navigator.clipboard.writeText(text);
468
+ e.target.closest('.copy-button').textContent = 'تم النسخ!';
469
+ setTimeout(() => {
470
+ e.target.closest('.copy-button').innerHTML = `
471
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
472
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 5H6a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2v-1M8 5a2 2 0 002 2h2a2 2 0 002-2M8 5a2 2 0 012-2h2a2 2 0 012 2m0 0h2a2 2 0 012 2v3m2 4H10m0 0l3-3m-3 3l3 3"></path>
473
+ </svg>
474
+ نسخ
475
+ `;
476
+ }, 2000);
477
+ }
478
+
479
+ if (e.target.closest('.regenerate-button')) {
480
+ const messageId = e.target.closest('.regenerate-button').dataset.messageId;
481
+ if (chatHistory.length > 0) {
482
+ const lastMessage = chatHistory[chatHistory.length - 1].human;
483
+ messageInput.value = lastMessage;
484
+ sendMessage();
485
+ }
486
+ }
487
+
488
+ if (e.target.closest('.like-button')) {
489
+ const button = e.target.closest('.like-button');
490
+ button.classList.toggle('text-green-500');
491
+ }
492
+
493
+ if (e.target.closest('.dislike-button')) {
494
+ const button = e.target.closest('.dislike-button');
495
+ button.classList.toggle('text-red-500');
496
+ }
497
  });
498
+
499
+ function scrollToBottom() {
500
+ window.scrollTo({
501
+ top: document.documentElement.scrollHeight,
502
+ behavior: 'smooth'
503
+ });
504
  }
505
+
506
+ function adjustTextareaHeight() {
507
+ messageInput.style.height = 'auto';
508
+ messageInput.style.height = messageInput.scrollHeight + 'px';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
509
  }
510
+
511
+ sendButton.addEventListener('click', sendMessage);
512
+ messageInput.addEventListener('keypress', (e) => {
513
+ if (e.key === 'Enter' && !e.shiftKey) {
514
+ e.preventDefault();
515
+ sendMessage();
516
+ }
517
+ });
518
+ messageInput.addEventListener('input', adjustTextareaHeight);
519
+ clearButton.addEventListener('click', () => {
520
+ messagesContainer.innerHTML = '';
521
+ chatHistory = [];
522
+ });
523
+
524
+ // Initial welcome message
525
+ const initialMessageId = 'msg-initial';
526
+ messagesContainer.insertAdjacentHTML('beforeend', createBotMessage('', initialMessageId));
527
+ typeText(initialMessageId, 'مرحباً! كيف يمكنني مساعدتك اليوم؟');
528
+ </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
529
  </body>
530
  </html>