Mark-Lasfar commited on
Commit
4b15bb2
·
1 Parent(s): 0181299
Files changed (3) hide show
  1. static/css/chat/style.css +4 -2
  2. static/js/chat.js +69 -54
  3. templates/chat.html +157 -188
static/css/chat/style.css CHANGED
@@ -44,10 +44,11 @@ html {
44
  word-wrap: break-word;
45
  word-break: break-word;
46
  max-width: 100%;
 
47
  }
48
 
49
  #chatBox {
50
- display: flex; /* غير display: none إلى flex ليظهر */
51
  flex-direction: column;
52
  width: 100%;
53
  height: 100%;
@@ -58,4 +59,5 @@ html {
58
  overflow-wrap: break-word;
59
  word-wrap: break-word;
60
  word-break: break-word;
61
- }
 
 
44
  word-wrap: break-word;
45
  word-break: break-word;
46
  max-width: 100%;
47
+ opacity: 1 !important; /* إضافة لضمان الظهور */
48
  }
49
 
50
  #chatBox {
51
+ display: flex;
52
  flex-direction: column;
53
  width: 100%;
54
  height: 100%;
 
59
  overflow-wrap: break-word;
60
  word-wrap: break-word;
61
  word-break: break-word;
62
+ opacity: 1 !important; /* إضافة لضمان الظهور */
63
+ }
static/js/chat.js CHANGED
@@ -47,6 +47,7 @@ let audioChunks = [];
47
  let streamMsg = null;
48
  let currentAssistantText = '';
49
  let isSidebarOpen = window.innerWidth >= 768;
 
50
 
51
  // Initialize AOS and load initial conversation
52
  document.addEventListener('DOMContentLoaded', async () => {
@@ -69,6 +70,7 @@ document.addEventListener('DOMContentLoaded', async () => {
69
  });
70
  } else {
71
  console.log('No conversation history or ID, starting fresh');
 
72
  }
73
 
74
  autoResizeTextarea();
@@ -161,7 +163,7 @@ function renderMarkdown(el) {
161
  });
162
  }
163
  el.style.display = 'block'; // إجبار عرض الفقاعة
164
- }
165
 
166
  // Toggle chat view
167
  function enterChatView() {
@@ -174,8 +176,8 @@ function enterChatView() {
174
  }
175
  if (uiElements.chatArea) {
176
  uiElements.chatArea.classList.remove('hidden');
177
- uiElements.chatArea.style.display = 'flex'; // إجبار العرض
178
- uiElements.chatArea.style.opacity = '1'; // إضافة الشفافية للتأكد
179
  }
180
  if (uiElements.chatBox) {
181
  uiElements.chatBox.classList.remove('hidden');
@@ -183,7 +185,12 @@ function enterChatView() {
183
  uiElements.chatBox.style.opacity = '1';
184
  }
185
  if (uiElements.initialContent) uiElements.initialContent.classList.add('hidden');
 
 
 
 
186
  }
 
187
  // Toggle home view
188
  function leaveChatView() {
189
  if (uiElements.chatHeader) {
@@ -192,6 +199,7 @@ function leaveChatView() {
192
  }
193
  if (uiElements.chatBox) uiElements.chatBox.classList.add('hidden');
194
  if (uiElements.initialContent) uiElements.initialContent.classList.remove('hidden');
 
195
  }
196
 
197
  // Add chat bubble
@@ -204,7 +212,7 @@ function addMsg(who, text) {
204
  div.style.display = 'block';
205
  if (uiElements.chatBox) {
206
  uiElements.chatBox.appendChild(div);
207
- uiElements.chatBox.classList.remove('hidden');
208
  } else {
209
  console.error('chatBox is not found in DOM');
210
  }
@@ -232,7 +240,7 @@ function clearAllMessages() {
232
  currentConversationId = null;
233
  currentConversationTitle = null;
234
  if (uiElements.conversationTitle) uiElements.conversationTitle.textContent = 'MGZon AI Assistant';
235
- enterChatView();
236
  autoResizeTextarea();
237
  }
238
 
@@ -330,9 +338,7 @@ async function submitAudioMessage(formData) {
330
 
331
  try {
332
  const response = await sendRequest('/api/audio-transcription', formData);
333
- if (!response.ok) {
334
- throw new Error(`Request failed with status ${response.status}`);
335
- }
336
  const data = await response.json();
337
  if (!data.transcription) throw new Error('No transcription received from server');
338
  const transcription = data.transcription || 'Error: No transcription generated.';
@@ -412,8 +418,12 @@ function finalizeRequest() {
412
  streamMsg = null;
413
  isRequestActive = false;
414
  abortController = null;
415
- if (uiElements.sendBtn) uiElements.sendBtn.style.display = 'inline-flex';
 
 
 
416
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
 
417
  }
418
 
419
  // Helper to handle request errors
@@ -437,8 +447,12 @@ function handleRequestError(error) {
437
  if (!(checkAuth())) {
438
  sessionStorage.setItem('conversationHistory', JSON.stringify(conversationHistory));
439
  }
440
- if (uiElements.sendBtn) uiElements.sendBtn.style.display = 'inline-flex';
 
 
 
441
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
 
442
  }
443
 
444
  // Load conversations for sidebar
@@ -689,6 +703,8 @@ async function submitMessage() {
689
  // إظهار واجهة المحادثة عند أول رسالة
690
  if (uiElements.initialContent && !uiElements.initialContent.classList.contains('hidden')) {
691
  enterChatView();
 
 
692
  }
693
 
694
  if (uiElements.fileInput?.files.length > 0) {
@@ -725,12 +741,12 @@ async function submitMessage() {
725
  headers['Content-Type'] = 'application/json';
726
  }
727
 
728
- addMsg('user', message); // أضف رسالة المستخدم
729
  if (!(await checkAuth())) {
730
  conversationHistory.push({ role: 'user', content: message });
731
  sessionStorage.setItem('conversationHistory', JSON.stringify(conversationHistory));
732
  }
733
- streamMsg = addMsg('assistant', ''); // أضف رسالة المساعد الفارغة
734
  const loadingEl = document.createElement('span');
735
  loadingEl.className = 'loading';
736
  streamMsg.appendChild(loadingEl);
@@ -750,48 +766,48 @@ async function submitMessage() {
750
  const data = await response.json();
751
  responseText = data.image_analysis || 'Error: No analysis generated.';
752
  } else {
753
- const contentType = response.headers.get('Content-Type');
754
- if (contentType?.includes('application/json')) {
755
- const data = await response.json();
756
- responseText = data.response || 'Error: No response generated.';
757
- if (data.conversation_id) {
758
- currentConversationId = data.conversation_id;
759
- currentConversationTitle = data.conversation_title || 'Untitled Conversation';
760
- if (uiElements.conversationTitle) uiElements.conversationTitle.textContent = currentConversationTitle;
761
- history.pushState(null, '', `/chat/${currentConversationId}`);
762
- await loadConversations();
763
- }
764
- } else {
765
- const reader = response.body.getReader();
766
- const decoder = new TextDecoder();
767
- let buffer = '';
768
- streamMsg.dataset.text = '';
769
- streamMsg.querySelector('.loading')?.remove();
770
-
771
- while (true) {
772
- const { done, value } = await reader.read();
773
- if (done) {
774
- if (!buffer.trim()) throw new Error('Empty response from server');
775
- break;
776
- }
777
- const chunk = decoder.decode(value, { stream: true });
778
- buffer += chunk;
779
- console.log('Received chunk:', chunk);
780
-
781
- if (streamMsg) {
782
- streamMsg.dataset.text = buffer;
783
- currentAssistantText = buffer;
784
- renderMarkdown(streamMsg);
785
- streamMsg.style.opacity = '1'; // إجبار الظهور
786
- if (uiElements.chatBox) {
787
- uiElements.chatBox.style.display = 'flex';
788
- uiElements.chatBox.scrollTop = uiElements.chatBox.scrollHeight; // تمرير إجباري
789
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
790
  }
791
  }
792
- responseText = buffer;
793
- }
794
- }
795
 
796
  if (streamMsg) {
797
  streamMsg.dataset.text = responseText;
@@ -827,6 +843,7 @@ function stopStream(forceCancel = false) {
827
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
828
  if (uiElements.sendBtn) uiElements.sendBtn.style.display = 'inline-flex';
829
  if (uiElements.stopBtn) uiElements.stopBtn.style.pointerEvents = 'auto';
 
830
  }
831
 
832
  // Logout handler
@@ -1074,8 +1091,6 @@ if (uiElements.newConversationBtn) {
1074
  });
1075
  }
1076
 
1077
-
1078
-
1079
  // Debug localStorage
1080
  const originalRemoveItem = localStorage.removeItem;
1081
  localStorage.removeItem = function (key) {
@@ -1102,7 +1117,7 @@ function autoResizeTextarea() {
1102
  if (uiElements.input) {
1103
  uiElements.input.style.height = 'auto';
1104
  uiElements.input.style.height = `${uiElements.input.scrollHeight}px`;
1105
- updateSendButtonState(); // تحديث حالة الزر بعد تغيير الحجم
1106
  }
1107
  }
1108
 
 
47
  let streamMsg = null;
48
  let currentAssistantText = '';
49
  let isSidebarOpen = window.innerWidth >= 768;
50
+ let abortController = null;
51
 
52
  // Initialize AOS and load initial conversation
53
  document.addEventListener('DOMContentLoaded', async () => {
 
70
  });
71
  } else {
72
  console.log('No conversation history or ID, starting fresh');
73
+ enterChatView(); // تأكيد إظهار المحادثة حتى لو فارغة
74
  }
75
 
76
  autoResizeTextarea();
 
163
  });
164
  }
165
  el.style.display = 'block'; // إجبار عرض الفقاعة
166
+ }
167
 
168
  // Toggle chat view
169
  function enterChatView() {
 
176
  }
177
  if (uiElements.chatArea) {
178
  uiElements.chatArea.classList.remove('hidden');
179
+ uiElements.chatArea.style.display = 'flex';
180
+ uiElements.chatArea.style.opacity = '1';
181
  }
182
  if (uiElements.chatBox) {
183
  uiElements.chatBox.classList.remove('hidden');
 
185
  uiElements.chatBox.style.opacity = '1';
186
  }
187
  if (uiElements.initialContent) uiElements.initialContent.classList.add('hidden');
188
+ if (uiElements.form) {
189
+ uiElements.form.classList.remove('hidden');
190
+ uiElements.form.style.display = 'flex';
191
+ }
192
  }
193
+
194
  // Toggle home view
195
  function leaveChatView() {
196
  if (uiElements.chatHeader) {
 
199
  }
200
  if (uiElements.chatBox) uiElements.chatBox.classList.add('hidden');
201
  if (uiElements.initialContent) uiElements.initialContent.classList.remove('hidden');
202
+ if (uiElements.form) uiElements.form.classList.add('hidden');
203
  }
204
 
205
  // Add chat bubble
 
212
  div.style.display = 'block';
213
  if (uiElements.chatBox) {
214
  uiElements.chatBox.appendChild(div);
215
+ uiElements.chatBox.scrollTop = uiElements.chatBox.scrollHeight; // تمرير تلقائي
216
  } else {
217
  console.error('chatBox is not found in DOM');
218
  }
 
240
  currentConversationId = null;
241
  currentConversationTitle = null;
242
  if (uiElements.conversationTitle) uiElements.conversationTitle.textContent = 'MGZon AI Assistant';
243
+ enterChatView(); // تأكيد إظهار المحادثة بعد المسح
244
  autoResizeTextarea();
245
  }
246
 
 
338
 
339
  try {
340
  const response = await sendRequest('/api/audio-transcription', formData);
341
+ if (!response.ok) throw new Error(`Request failed with status ${response.status}`);
 
 
342
  const data = await response.json();
343
  if (!data.transcription) throw new Error('No transcription received from server');
344
  const transcription = data.transcription || 'Error: No transcription generated.';
 
418
  streamMsg = null;
419
  isRequestActive = false;
420
  abortController = null;
421
+ if (uiElements.sendBtn) {
422
+ uiElements.sendBtn.style.display = 'inline-flex';
423
+ uiElements.sendBtn.disabled = false;
424
+ }
425
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
426
+ updateSendButtonState();
427
  }
428
 
429
  // Helper to handle request errors
 
447
  if (!(checkAuth())) {
448
  sessionStorage.setItem('conversationHistory', JSON.stringify(conversationHistory));
449
  }
450
+ if (uiElements.sendBtn) {
451
+ uiElements.sendBtn.style.display = 'inline-flex';
452
+ uiElements.sendBtn.disabled = false;
453
+ }
454
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
455
+ enterChatView(); // إعادة إظهار المحادثة بعد الخطأ
456
  }
457
 
458
  // Load conversations for sidebar
 
703
  // إظهار واجهة المحادثة عند أول رسالة
704
  if (uiElements.initialContent && !uiElements.initialContent.classList.contains('hidden')) {
705
  enterChatView();
706
+ } else {
707
+ enterChatView(); // تأكيد إظهار المحادثة في كل مرة
708
  }
709
 
710
  if (uiElements.fileInput?.files.length > 0) {
 
741
  headers['Content-Type'] = 'application/json';
742
  }
743
 
744
+ addMsg('user', message);
745
  if (!(await checkAuth())) {
746
  conversationHistory.push({ role: 'user', content: message });
747
  sessionStorage.setItem('conversationHistory', JSON.stringify(conversationHistory));
748
  }
749
+ streamMsg = addMsg('assistant', '');
750
  const loadingEl = document.createElement('span');
751
  loadingEl.className = 'loading';
752
  streamMsg.appendChild(loadingEl);
 
766
  const data = await response.json();
767
  responseText = data.image_analysis || 'Error: No analysis generated.';
768
  } else {
769
+ const contentType = response.headers.get('Content-Type');
770
+ if (contentType?.includes('application/json')) {
771
+ const data = await response.json();
772
+ responseText = data.response || 'Error: No response generated.';
773
+ if (data.conversation_id) {
774
+ currentConversationId = data.conversation_id;
775
+ currentConversationTitle = data.conversation_title || 'Untitled Conversation';
776
+ if (uiElements.conversationTitle) uiElements.conversationTitle.textContent = currentConversationTitle;
777
+ history.pushState(null, '', `/chat/${currentConversationId}`);
778
+ await loadConversations();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
779
  }
780
+ } else {
781
+ const reader = response.body.getReader();
782
+ const decoder = new TextDecoder();
783
+ let buffer = '';
784
+ streamMsg.dataset.text = '';
785
+ streamMsg.querySelector('.loading')?.remove();
786
+
787
+ while (true) {
788
+ const { done, value } = await reader.read();
789
+ if (done) {
790
+ if (!buffer.trim()) throw new Error('Empty response from server');
791
+ break;
792
+ }
793
+ const chunk = decoder.decode(value, { stream: true });
794
+ buffer += chunk;
795
+ console.log('Received chunk:', chunk);
796
+
797
+ if (streamMsg) {
798
+ streamMsg.dataset.text = buffer;
799
+ currentAssistantText = buffer;
800
+ renderMarkdown(streamMsg);
801
+ streamMsg.style.opacity = '1';
802
+ if (uiElements.chatBox) {
803
+ uiElements.chatBox.style.display = 'flex';
804
+ uiElements.chatBox.scrollTop = uiElements.chatBox.scrollHeight;
805
+ }
806
+ }
807
+ }
808
+ responseText = buffer;
809
  }
810
  }
 
 
 
811
 
812
  if (streamMsg) {
813
  streamMsg.dataset.text = responseText;
 
843
  if (uiElements.stopBtn) uiElements.stopBtn.style.display = 'none';
844
  if (uiElements.sendBtn) uiElements.sendBtn.style.display = 'inline-flex';
845
  if (uiElements.stopBtn) uiElements.stopBtn.style.pointerEvents = 'auto';
846
+ enterChatView(); // إعادة إظهار المحادثة بعد الإلغاء
847
  }
848
 
849
  // Logout handler
 
1091
  });
1092
  }
1093
 
 
 
1094
  // Debug localStorage
1095
  const originalRemoveItem = localStorage.removeItem;
1096
  localStorage.removeItem = function (key) {
 
1117
  if (uiElements.input) {
1118
  uiElements.input.style.height = 'auto';
1119
  uiElements.input.style.height = `${uiElements.input.scrollHeight}px`;
1120
+ updateSendButtonState();
1121
  }
1122
  }
1123
 
templates/chat.html CHANGED
@@ -3,12 +3,9 @@
3
 
4
  <head>
5
  <meta charset="UTF-8">
6
- <meta name="viewport"
7
- content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
8
- <meta name="description"
9
- content="Chat with MGZon Chatbot, an AI-powered tool for coding, analysis, and e-commerce queries. Supports text, image, and audio inputs." />
10
- <meta name="keywords"
11
- content="MGZon Chatbot, AI chatbot, code generation, DeepSeek, Gradio, FastAPI, e-commerce, programming, Mark Al-Asfar" />
12
  <meta name="author" content="Mark Al-Asfar" />
13
  <meta name="robots" content="index, follow" />
14
  <title>MGZon Chatbot – AI Assistant</title>
@@ -17,30 +14,20 @@
17
  <link rel="apple-touch-icon" href="/static/images/mg.svg" />
18
  <!-- Open Graph -->
19
  <meta property="og:title" content="MGZon Chatbot – AI Assistant" />
20
- <!-- manifest for Android/Chrome -->
21
  <link rel="manifest" href="/static/manifest.json">
22
-
23
- <!-- iOS Web App Support -->
24
  <link rel="apple-touch-icon" sizes="180x180" href="/static/images/icons/mg-180.png">
25
  <meta name="apple-mobile-web-app-capable" content="yes">
26
  <meta name="apple-mobile-web-app-title" content="MGZon">
27
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
28
-
29
- <!-- General Theme -->
30
  <meta name="theme-color" content="#2d3748">
31
-
32
- <meta property="og:description"
33
- content="Chat with MGZon Chatbot for coding, analysis, and e-commerce queries with text, image, and audio support." />
34
  <meta property="og:image" content="/static/images/mg.svg" />
35
  <meta property="og:url" content="https://mgzon-mgzon-app.hf.space/chat" />
36
  <meta property="og:type" content="website" />
37
- <!-- Twitter Card -->
38
  <meta name="twitter:card" content="summary_large_image" />
39
  <meta name="twitter:title" content="MGZon Chatbot – AI Assistant" />
40
- <meta name="twitter:description"
41
- content="Chat with MGZon Chatbot for coding, analysis, and e-commerce queries with text, image, and audio support." />
42
  <meta name="twitter:image" content="/static/images/mg.svg" />
43
- <!-- JSON-LD -->
44
  <script type="application/ld+json">
45
  {
46
  "@context": "https://schema.org",
@@ -50,29 +37,21 @@
50
  "description": "An AI-powered chatbot for coding, analysis, and e-commerce queries."
51
  }
52
  </script>
53
- <!-- Fonts & Styles -->
54
  <link rel="preconnect" href="https://fonts.googleapis.com" />
55
- <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap"
56
- rel="stylesheet" />
57
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
58
  <script src="https://cdn.tailwindcss.com"></script>
59
- <!-- Markdown & Syntax Highlight -->
60
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
61
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" />
62
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
63
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
64
- <!-- Animations -->
65
  <script src="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js"></script>
66
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" />
67
- <!-- Carousel -->
68
  <script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script>
69
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css" />
70
- <!-- Smooth Scroll -->
71
  <script src="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.js"></script>
72
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.css" />
73
- <!-- Hammer.js for touch gestures -->
74
  <script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
75
- <!-- Project-Specific Styles -->
76
  <link rel="stylesheet" href="/static/css/animation/style.css" />
77
  <link rel="stylesheet" href="/static/css/button.css" />
78
  <link rel="stylesheet" href="/static/css/chat/bubble.css" />
@@ -95,7 +74,6 @@
95
  <link rel="stylesheet" href="/static/css/style.css" />
96
  <link rel="stylesheet" href="/static/css/webkit.css" />
97
  <link rel="stylesheet" href="/static/css/sidebar.css" />
98
- <!-- Preload Resources -->
99
  <link rel="preload" href="/static/js/chat.js" as="script">
100
  <link rel="preload" href="/static/css/chat/style.css" as="style">
101
  <link rel="preload" href="/static/images/mg.svg" as="image">
@@ -104,8 +82,7 @@
104
 
105
  <body class="min-h-screen flex flex-col bg-gradient-to-br from-gray-900 via-teal-900 to-emerald-900">
106
  <!-- Sidebar -->
107
- <aside id="sidebar"
108
- class="fixed inset-y-0 left-0 w-64 bg-gray-800/90 backdrop-blur-md transform -translate-x-full md:translate-x-0 transition-transform duration-300 ease-in-out z-50">
109
  <div class="flex items-center justify-between p-4 border-b border-gray-700">
110
  <div class="flex items-center">
111
  <img src="/static/images/mg.svg" alt="MGZon Logo" class="w-10 h-10 mr-2 animate-pulse" />
@@ -121,8 +98,7 @@
121
  <ul class="space-y-2">
122
  <li>
123
  <a href="/" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
124
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
125
- xmlns="http://www.w3.org/2000/svg">
126
  <path d="M3 11.5L12 4l9 7.5M5 21V11.5h14V21"></path>
127
  </svg>
128
  Home
@@ -130,56 +106,41 @@
130
  </li>
131
  <li>
132
  <a href="/about" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
133
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
134
- xmlns="http://www.w3.org/2000/svg">
135
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
136
- d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
137
  </svg>
138
  About
139
  </a>
140
  </li>
141
  <li>
142
  <a href="/blog" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
143
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
144
- xmlns="http://www.w3.org/2000/svg">
145
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
146
- d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 006 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25">
147
- </path>
148
  </svg>
149
  Blog
150
  </a>
151
  </li>
152
  <li>
153
  <a href="/docs" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
154
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
155
- xmlns="http://www.w3.org/2000/svg">
156
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
157
- d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z">
158
- </path>
159
  </svg>
160
  Docs
161
  </a>
162
  </li>
163
  {% if user %}
164
  <li>
165
- <button id="settingsBtn"
166
- class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
167
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
168
- xmlns="http://www.w3.org/2000/svg">
169
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
170
- d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4">
171
- </path>
172
  </svg>
173
  Settings
174
  </button>
175
  </li>
176
  <li>
177
- <button id="logoutBtn"
178
- class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
179
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
180
- xmlns="http://www.w3.org/2000/svg">
181
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
182
- d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
183
  </svg>
184
  Logout
185
  </button>
@@ -187,10 +148,8 @@
187
  {% else %}
188
  <li>
189
  <a href="/login" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
190
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
191
- xmlns="http://www.w3.org/2000/svg">
192
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
193
- d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"></path>
194
  </svg>
195
  Login
196
  </a>
@@ -202,18 +161,14 @@
202
  <div class="flex justify-between items-center px-2 mb-2">
203
  <h3 class="text-sm font-semibold text-white">Conversations</h3>
204
  <button id="newConversationBtn" class="text-white hover:bg-gray-700 p-1 rounded" title="New Conversation">
205
- <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"
206
- xmlns="http://www.w3.org/2000/svg">
207
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
208
  </svg>
209
  </button>
210
  </div>
211
- <button id="historyToggle"
212
- class="md:hidden flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
213
- <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24"
214
- xmlns="http://www.w3.org/2000/svg">
215
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2"
216
- d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
217
  </svg>
218
  Show History
219
  </button>
@@ -239,8 +194,7 @@
239
  </div>
240
  <div class="chat-controls flex gap-2">
241
  <button id="clearBtn" class="icon-btn" aria-label="Clear All Messages" title="Clear All Messages">
242
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6"
243
- stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
244
  <path d="M3 6h18" />
245
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
246
  <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
@@ -253,7 +207,7 @@
253
 
254
  <!-- Chat Area -->
255
  <main class="flex-1 flex flex-col">
256
- <div id="initialContent" class="flex flex-col items-center justify-center text-center h-full">
257
  <div class="title mb-4 gradient-text text-3xl font-bold">
258
  How can I help you today?
259
  </div>
@@ -265,9 +219,7 @@
265
  <div class="prompts w-full max-w-md mx-auto grid gap-2">
266
  <div class="prompt-item" data-prompt="What's the capital of France?">
267
  <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
268
- <path
269
- d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M18.66 18.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M18.66 5.34l1.41-1.41"
270
- stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
271
  <circle cx="12" cy="12" r="4" stroke-width="2" />
272
  </svg>
273
  <span>What's the capital of France?</span>
@@ -292,53 +244,49 @@
292
  </div>
293
  </div>
294
  <div id="messageLimitWarning" class="text-red-500 text-center hidden mt-4">
295
- You have reached the message limit. Please <a href="/login" class="text-blue-300 underline">login</a> to
296
- continue.
297
  </div>
298
  </div>
299
- <div id="chatArea" class="flex-1 overflow-y-auto hidden" aria-live="polite">
300
- <div id="chatBox" class="flex flex-col w-full" aria-live="polite"></div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
301
  </div>
 
302
  </div>
303
- <!-- Footer Form -->
304
- <form id="footerForm" class="flex p-4">
305
- <div id="inputContainer" class="w-full">
306
- <textarea id="userInput" placeholder="Ask anything..." required></textarea>
307
- <div id="rightIconGroup" class="flex gap-2">
308
- <button type="button" id="fileBtn" class="icon-btn" aria-label="Upload File" title="Upload File">
309
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
310
- stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
311
- <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
312
- <path d="M14 2v6h6" />
313
- </svg>
314
- </button>
315
- <input type="file" id="fileInput" accept="image/*,.mp3,.wav" style="display: none;" />
316
- <button type="button" id="audioBtn" class="icon-btn" aria-label="Upload Audio File" title="Upload Audio File">
317
- <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8"
318
- stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
319
- <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
320
- <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
321
- <path d="M12 19v4" />
322
- </svg>
323
- </button>
324
- <input type="file" id="audioInput" accept="audio/*" style="display: none;" />
325
- <button type="submit" id="sendBtn" class="icon-btn" disabled aria-label="Send or Hold to Record"
326
- title="Click to Send or Hold to Record Voice">
327
- <svg id="sendIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
328
- <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7-7 7M3 12h11" />
329
- </svg>
330
- </button>
331
- <button id="stopBtn" class="icon-btn" aria-label="Stop" title="Stop" style="display: none;">
332
- <svg width="20" height="20" viewBox="0 0 24 24" fill="white" xmlns="http://www.w3.org/2000/svg">
333
- <rect x="6" y="6" width="12" height="12" rx="2" fill="white" />
334
- </svg>
335
- </button>
336
- </div>
337
- </div>
338
- <div id="filePreview" class="upload-preview" style="display: none;"></div>
339
- <div id="audioPreview" class="audio-preview" style="display: none;"></div>
340
- </form>
341
- </main>
342
 
343
  <!-- Settings Modal -->
344
  <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
@@ -379,8 +327,7 @@
379
  </div>
380
  <div>
381
  <label for="additional_info" class="block text-sm text-gray-300">Additional Info</label>
382
- <textarea id="additional_info" name="additional_info"
383
- class="w-full p-2 bg-gray-700 text-white rounded"></textarea>
384
  </div>
385
  <div>
386
  <label for="conversation_style" class="block text-sm text-gray-300">Conversation Style</label>
@@ -403,86 +350,108 @@
403
  <div class="text-center text-xs text-gray-400 py-2">
404
  © 2025 Mark Al-Asfar & MGZon AI. All rights reserved.
405
  </div>
 
406
  <!-- Install Button -->
407
- <button id="installAppBtn" style="display: none;"
408
- class="fixed bottom-4 right-4 bg-blue-600 text-white px-4 py-2 rounded shadow-lg z-50">
409
  📲 Install MG Chat
410
  </button>
 
411
  <!-- PWA Install Instructions -->
412
  <div id="pwa-instructions" class="fixed bottom-4 left-4 right-4 bg-blue-600 text-white p-4 rounded-lg z-50 hidden">
413
- <p><strong>Add to Home Screen:</strong> Tap the share button in your browser, then "Add to Home Screen" for a
414
- native-like experience!</p>
415
- <button onclick="document.getElementById('pwa-instructions').classList.add('hidden')"
416
- class="ml-2 text-sm">Close</button>
417
- </div>
418
  </div>
 
419
 
420
- <!-- Scripts -->
421
- <script src="/static/js/chat.js?v=1.2"></script>
422
- <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
423
 
424
- <script>
425
- // تهيئة مكتبة AOS
426
- AOS.init();
427
 
428
- // تمرير conversation_id و conversation_title إذا كانا موجودين
429
- {% if conversation_id %}
430
- window.conversationId = "{{ conversation_id }}";
431
- window.conversationTitle = "{{ conversation_title }}";
432
- if (window.loadConversation) {
433
- window.loadConversation("{{ conversation_id }}");
434
- }
435
- {% endif %}
436
 
437
- // تسجيل Service Worker لتفعيل الـ PWA
438
- if ('serviceWorker' in navigator) {
439
- navigator.serviceWorker.register('/static/js/sw.js')
440
- .then(function (reg) {
441
- console.log('✅ Service Worker Registered', reg);
442
- }).catch(function (err) {
443
- console.error('❌ Service Worker registration failed', err);
444
- });
445
- }
446
 
447
- // التعامل مع حدث beforeinstallprompt لتثبيت التطبيق
448
- let deferredPrompt;
449
- window.addEventListener('beforeinstallprompt', (e) => {
450
- e.preventDefault();
451
- deferredPrompt = e;
452
- const installBtn = document.getElementById('installAppBtn');
453
- if (installBtn) {
454
- installBtn.style.display = 'block';
455
- installBtn.addEventListener('click', () => {
456
- deferredPrompt.prompt();
457
- deferredPrompt.userChoice.then(choice => {
458
- if (choice.outcome === 'accepted') {
459
- console.log('✅ User accepted the install prompt');
460
- } else {
461
- console.log('❌ User dismissed the install prompt');
462
- }
463
- deferredPrompt = null;
464
- });
465
  });
466
- }
467
- });
468
-
469
- // Show PWA instructions on first visit
470
- if (localStorage.getItem('pwa-instructions-shown') !== 'true') {
471
- document.getElementById('pwa-instructions').classList.remove('hidden');
472
- localStorage.setItem('pwa-instructions-shown', 'true');
473
  }
 
474
 
475
- // Enhance touch gestures for sidebar
476
- const sidebar = document.getElementById('sidebar');
477
- const hammer = new Hammer(sidebar);
478
- hammer.on('swipeleft', () => {
479
- sidebar.classList.remove('open');
480
- });
481
- hammer.on('swiperight', () => {
482
- sidebar.classList.add('open');
483
- });
484
- </script>
485
 
486
- </body>
 
 
 
 
 
 
 
 
 
487
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
488
  </html>
 
3
 
4
  <head>
5
  <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover">
7
+ <meta name="description" content="Chat with MGZon Chatbot, an AI-powered tool for coding, analysis, and e-commerce queries. Supports text, image, and audio inputs." />
8
+ <meta name="keywords" content="MGZon Chatbot, AI chatbot, code generation, DeepSeek, Gradio, FastAPI, e-commerce, programming, Mark Al-Asfar" />
 
 
 
9
  <meta name="author" content="Mark Al-Asfar" />
10
  <meta name="robots" content="index, follow" />
11
  <title>MGZon Chatbot – AI Assistant</title>
 
14
  <link rel="apple-touch-icon" href="/static/images/mg.svg" />
15
  <!-- Open Graph -->
16
  <meta property="og:title" content="MGZon Chatbot – AI Assistant" />
 
17
  <link rel="manifest" href="/static/manifest.json">
 
 
18
  <link rel="apple-touch-icon" sizes="180x180" href="/static/images/icons/mg-180.png">
19
  <meta name="apple-mobile-web-app-capable" content="yes">
20
  <meta name="apple-mobile-web-app-title" content="MGZon">
21
  <meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
 
 
22
  <meta name="theme-color" content="#2d3748">
23
+ <meta property="og:description" content="Chat with MGZon Chatbot for coding, analysis, and e-commerce queries with text, image, and audio support." />
 
 
24
  <meta property="og:image" content="/static/images/mg.svg" />
25
  <meta property="og:url" content="https://mgzon-mgzon-app.hf.space/chat" />
26
  <meta property="og:type" content="website" />
 
27
  <meta name="twitter:card" content="summary_large_image" />
28
  <meta name="twitter:title" content="MGZon Chatbot – AI Assistant" />
29
+ <meta name="twitter:description" content="Chat with MGZon Chatbot for coding, analysis, and e-commerce queries with text, image, and audio support." />
 
30
  <meta name="twitter:image" content="/static/images/mg.svg" />
 
31
  <script type="application/ld+json">
32
  {
33
  "@context": "https://schema.org",
 
37
  "description": "An AI-powered chatbot for coding, analysis, and e-commerce queries."
38
  }
39
  </script>
 
40
  <link rel="preconnect" href="https://fonts.googleapis.com" />
41
+ <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&display=swap" rel="stylesheet" />
 
42
  <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet" />
43
  <script src="https://cdn.tailwindcss.com"></script>
 
44
  <script src="https://cdn.jsdelivr.net/npm/marked/marked.min.js"></script>
45
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" />
46
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
47
  <script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
 
48
  <script src="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.js"></script>
49
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/aos@2.3.4/dist/aos.css" />
 
50
  <script src="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/js/splide.min.js"></script>
51
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/@splidejs/splide@4.1.4/dist/css/splide.min.css" />
 
52
  <script src="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.js"></script>
53
  <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/locomotive-scroll@4.1.4/dist/locomotive-scroll.min.css" />
 
54
  <script src="https://cdn.jsdelivr.net/npm/hammerjs@2.0.8/hammer.min.js"></script>
 
55
  <link rel="stylesheet" href="/static/css/animation/style.css" />
56
  <link rel="stylesheet" href="/static/css/button.css" />
57
  <link rel="stylesheet" href="/static/css/chat/bubble.css" />
 
74
  <link rel="stylesheet" href="/static/css/style.css" />
75
  <link rel="stylesheet" href="/static/css/webkit.css" />
76
  <link rel="stylesheet" href="/static/css/sidebar.css" />
 
77
  <link rel="preload" href="/static/js/chat.js" as="script">
78
  <link rel="preload" href="/static/css/chat/style.css" as="style">
79
  <link rel="preload" href="/static/images/mg.svg" as="image">
 
82
 
83
  <body class="min-h-screen flex flex-col bg-gradient-to-br from-gray-900 via-teal-900 to-emerald-900">
84
  <!-- Sidebar -->
85
+ <aside id="sidebar" class="fixed inset-y-0 left-0 w-64 bg-gray-800/90 backdrop-blur-md transform -translate-x-full md:translate-x-0 transition-transform duration-300 ease-in-out z-50">
 
86
  <div class="flex items-center justify-between p-4 border-b border-gray-700">
87
  <div class="flex items-center">
88
  <img src="/static/images/mg.svg" alt="MGZon Logo" class="w-10 h-10 mr-2 animate-pulse" />
 
98
  <ul class="space-y-2">
99
  <li>
100
  <a href="/" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
101
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 
102
  <path d="M3 11.5L12 4l9 7.5M5 21V11.5h14V21"></path>
103
  </svg>
104
  Home
 
106
  </li>
107
  <li>
108
  <a href="/about" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
109
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
110
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M13 16h-1v-4h-1m1-4h.01M21 12a9 9 0 11-18 0 9 9 0 0118 0z"></path>
 
 
111
  </svg>
112
  About
113
  </a>
114
  </li>
115
  <li>
116
  <a href="/blog" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
117
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
118
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6.042A8.967 8.967 0 006 3.75c-1.052 0-2.062.18-3 .512v14.25A8.987 8.987 0 006 18c2.305 0 4.408.867 6 2.292m0-14.25a8.966 8.966 0 016-2.292c1.052 0 2.062.18 3 .512v14.25A8.987 8.987 0 0018 18a8.967 8.967 0 00-6 2.292m0-14.25v14.25"></path>
 
 
 
119
  </svg>
120
  Blog
121
  </a>
122
  </li>
123
  <li>
124
  <a href="/docs" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
125
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
126
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 12h6m-6 4h6m2 5H7a2 2 0 01-2-2V5a2 2 0 012-2h5.586a1 1 0 01.707.293l5.414 5.414a1 1 0 01.293.707V19a2 2 0 01-2 2z"></path>
 
 
 
127
  </svg>
128
  Docs
129
  </a>
130
  </li>
131
  {% if user %}
132
  <li>
133
+ <button id="settingsBtn" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
134
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
135
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 6V4m0 2a2 2 0 100 4m0-4a2 2 0 110 4m-6 8a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4m6 6v10m6-2a2 2 0 100-4m0 4a2 2 0 110-4m0 4v2m0-6V4"></path>
 
 
 
 
136
  </svg>
137
  Settings
138
  </button>
139
  </li>
140
  <li>
141
+ <button id="logoutBtn" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
142
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
143
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M17 16l4-4m0 0l-4-4m4 4H7m6 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h4a3 3 0 013 3v1"></path>
 
 
 
144
  </svg>
145
  Logout
146
  </button>
 
148
  {% else %}
149
  <li>
150
  <a href="/login" class="flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors">
151
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
152
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M11 16l-4-4m0 0l4-4m-4 4h14m-5 4v1a3 3 0 01-3 3H6a3 3 0 01-3-3V7a3 3 0 013-3h7a3 3 0 013 3v1"></path>
 
 
153
  </svg>
154
  Login
155
  </a>
 
161
  <div class="flex justify-between items-center px-2 mb-2">
162
  <h3 class="text-sm font-semibold text-white">Conversations</h3>
163
  <button id="newConversationBtn" class="text-white hover:bg-gray-700 p-1 rounded" title="New Conversation">
164
+ <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
 
165
  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4"></path>
166
  </svg>
167
  </button>
168
  </div>
169
+ <button id="historyToggle" class="md:hidden flex items-center text-white hover:bg-gray-700 p-2 rounded transition-colors w-full text-left">
170
+ <svg class="w-5 h-5 mr-2" fill="none" stroke="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
171
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"></path>
 
 
 
172
  </svg>
173
  Show History
174
  </button>
 
194
  </div>
195
  <div class="chat-controls flex gap-2">
196
  <button id="clearBtn" class="icon-btn" aria-label="Clear All Messages" title="Clear All Messages">
197
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
 
198
  <path d="M3 6h18" />
199
  <path d="M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2" />
200
  <path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6" />
 
207
 
208
  <!-- Chat Area -->
209
  <main class="flex-1 flex flex-col">
210
+ <div id="initialContent" class="flex flex-col items-center justify-center text-center h-full show">
211
  <div class="title mb-4 gradient-text text-3xl font-bold">
212
  How can I help you today?
213
  </div>
 
219
  <div class="prompts w-full max-w-md mx-auto grid gap-2">
220
  <div class="prompt-item" data-prompt="What's the capital of France?">
221
  <svg class="icon" viewBox="0 0 24 24" fill="none" stroke="currentColor">
222
+ <path d="M12 2v2M12 20v2M4.93 4.93l1.41 1.41M18.66 18.66l1.41 1.41M2 12h2M20 12h2M4.93 19.07l1.41-1.41M18.66 5.34l1.41-1.41" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
 
 
223
  <circle cx="12" cy="12" r="4" stroke-width="2" />
224
  </svg>
225
  <span>What's the capital of France?</span>
 
244
  </div>
245
  </div>
246
  <div id="messageLimitWarning" class="text-red-500 text-center hidden mt-4">
247
+ You have reached the message limit. Please <a href="/login" class="text-blue-300 underline">login</a> to continue.
 
248
  </div>
249
  </div>
250
+ <div id="chatArea" class="flex-1 overflow-y-auto hide">
251
+ <div id="chatBox" class="flex flex-col w-full"></div>
252
+ <!-- Footer Form moved inside chatArea -->
253
+ <form id="footerForm" class="flex p-4">
254
+ <div id="inputContainer" class="w-full">
255
+ <textarea id="userInput" placeholder="Ask anything..." required></textarea>
256
+ <div id="rightIconGroup" class="flex gap-2">
257
+ <button type="button" id="fileBtn" class="icon-btn" aria-label="Upload File" title="Upload File">
258
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
259
+ <path d="M14 2H6a2 2 0 0 0-2 2v16a2 2 0 0 0 2 2h12a2 2 0 0 0 2-2V8z" />
260
+ <path d="M14 2v6h6" />
261
+ </svg>
262
+ </button>
263
+ <input type="file" id="fileInput" accept="image/*,.mp3,.wav" style="display: none;" />
264
+ <button type="button" id="audioBtn" class="icon-btn" aria-label="Upload Audio File" title="Upload Audio File">
265
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" stroke-linejoin="round" xmlns="http://www.w3.org/2000/svg">
266
+ <path d="M12 1a3 3 0 0 0-3 3v8a3 3 0 0 0 6 0V4a3 3 0 0 0-3-3z" />
267
+ <path d="M19 10v2a7 7 0 0 1-14 0v-2" />
268
+ <path d="M12 19v4" />
269
+ </svg>
270
+ </button>
271
+ <input type="file" id="audioInput" accept="audio/*" style="display: none;" />
272
+ <button type="submit" id="sendBtn" class="icon-btn" disabled aria-label="Send or Hold to Record" title="Click to Send or Hold to Record Voice">
273
+ <svg id="sendIcon" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
274
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M14 5l7 7-7 7M3 12h11" />
275
+ </svg>
276
+ </button>
277
+ <button id="stopBtn" class="icon-btn" aria-label="Stop" title="Stop" style="display: none;">
278
+ <svg width="20" height="20" viewBox="0 0 24 24" fill="white" xmlns="http://www.w3.org/2000/svg">
279
+ <rect x="6" y="6" width="12" height="12" rx="2" fill="white" />
280
+ </svg>
281
+ </button>
282
+ </div>
283
+ </div>
284
+ <div id="filePreview" class="upload-preview" style="display: none;"></div>
285
+ <div id="audioPreview" class="audio-preview" style="display: none;"></div>
286
+ </form>
287
  </div>
288
+ </main>
289
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
290
 
291
  <!-- Settings Modal -->
292
  <div id="settingsModal" class="fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 hidden">
 
327
  </div>
328
  <div>
329
  <label for="additional_info" class="block text-sm text-gray-300">Additional Info</label>
330
+ <textarea id="additional_info" name="additional_info" class="w-full p-2 bg-gray-700 text-white rounded"></textarea>
 
331
  </div>
332
  <div>
333
  <label for="conversation_style" class="block text-sm text-gray-300">Conversation Style</label>
 
350
  <div class="text-center text-xs text-gray-400 py-2">
351
  © 2025 Mark Al-Asfar & MGZon AI. All rights reserved.
352
  </div>
353
+
354
  <!-- Install Button -->
355
+ <button id="installAppBtn" style="display: none;" class="fixed bottom-4 right-4 bg-blue-600 text-white px-4 py-2 rounded shadow-lg z-50">
 
356
  📲 Install MG Chat
357
  </button>
358
+
359
  <!-- PWA Install Instructions -->
360
  <div id="pwa-instructions" class="fixed bottom-4 left-4 right-4 bg-blue-600 text-white p-4 rounded-lg z-50 hidden">
361
+ <p><strong>Add to Home Screen:</strong> Tap the share button in your browser, then "Add to Home Screen" for a native-like experience!</p>
362
+ <button onclick="document.getElementById('pwa-instructions').classList.add('hidden')" class="ml-2 text-sm">Close</button>
 
 
 
363
  </div>
364
+ </div>
365
 
366
+ <!-- Scripts -->
367
+ <script src="/static/js/chat.js?v=1.2"></script>
368
+ <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
369
 
370
+ <script>
371
+ // تهيئة مكتبة AOS
372
+ AOS.init();
373
 
374
+ // تمرير conversation_id و conversation_title إذا كانا موجودين
375
+ {% if conversation_id %}
376
+ window.conversationId = "{{ conversation_id }}";
377
+ window.conversationTitle = "{{ conversation_title }}";
378
+ if (window.loadConversation) {
379
+ window.loadConversation("{{ conversation_id }}");
380
+ }
381
+ {% endif %}
382
 
383
+ // تسجيل Service Worker لتفعيل الـ PWA
384
+ if ('serviceWorker' in navigator) {
385
+ navigator.serviceWorker.register('/static/js/sw.js')
386
+ .then(function (reg) {
387
+ console.log('✅ Service Worker Registered', reg);
388
+ }).catch(function (err) {
389
+ console.error('❌ Service Worker registration failed', err);
390
+ });
391
+ }
392
 
393
+ // التعامل مع حدث beforeinstallprompt لتثبيت التطبيق
394
+ let deferredPrompt;
395
+ window.addEventListener('beforeinstallprompt', (e) => {
396
+ e.preventDefault();
397
+ deferredPrompt = e;
398
+ const installBtn = document.getElementById('installAppBtn');
399
+ if (installBtn) {
400
+ installBtn.style.display = 'block';
401
+ installBtn.addEventListener('click', () => {
402
+ deferredPrompt.prompt();
403
+ deferredPrompt.userChoice.then(choice => {
404
+ if (choice.outcome === 'accepted') {
405
+ console.log('✅ User accepted the install prompt');
406
+ } else {
407
+ console.log('❌ User dismissed the install prompt');
408
+ }
409
+ deferredPrompt = null;
 
410
  });
411
+ });
 
 
 
 
 
 
412
  }
413
+ });
414
 
415
+ // Show PWA instructions on first visit
416
+ if (localStorage.getItem('pwa-instructions-shown') !== 'true') {
417
+ document.getElementById('pwa-instructions').classList.remove('hidden');
418
+ localStorage.setItem('pwa-instructions-shown', 'true');
419
+ }
 
 
 
 
 
420
 
421
+ // Enhance touch gestures for sidebar
422
+ const sidebar = document.getElementById('sidebar');
423
+ const hammer = new Hammer(sidebar);
424
+ hammer.on('swipeleft', () => {
425
+ sidebar.classList.remove('open');
426
+ });
427
+ hammer.on('swiperight', () => {
428
+ sidebar.classList.add('open');
429
+ });
430
+ </script>
431
 
432
+ <style>
433
+ .show {
434
+ display: flex;
435
+ opacity: 1;
436
+ transition: opacity 0.3s ease-in-out;
437
+ }
438
+ .hide {
439
+ display: none;
440
+ opacity: 0;
441
+ transition: opacity 0.3s ease-in-out;
442
+ }
443
+ #chatArea.show {
444
+ display: flex;
445
+ opacity: 1;
446
+ }
447
+ #initialContent.hide {
448
+ display: none;
449
+ opacity: 0;
450
+ }
451
+ #footerForm {
452
+ display: flex !important;
453
+ opacity: 1 !important;
454
+ }
455
+ </style>
456
+ </body>
457
  </html>