AnesKAM commited on
Commit
d0b0cea
·
verified ·
1 Parent(s): 3d403fb

Create js/main.js

Browse files
Files changed (1) hide show
  1. frontend/js/main.js +285 -0
frontend/js/main.js ADDED
@@ -0,0 +1,285 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // State Management
2
+ let currentConversationId = 'default';
3
+ let currentLanguage = localStorage.getItem('language') || 'en';
4
+ let currentTheme = localStorage.getItem('theme') || 'light';
5
+
6
+ // Initialize
7
+ document.addEventListener('DOMContentLoaded', function() {
8
+ initializeApp();
9
+ loadConversations();
10
+ applyTheme(currentTheme);
11
+ applyLanguage(currentLanguage);
12
+ });
13
+
14
+ function initializeApp() {
15
+ // Set language
16
+ document.getElementById('language-select').value = currentLanguage;
17
+
18
+ // Keyboard shortcut for sending messages
19
+ document.getElementById('message-input').addEventListener('keypress', function(e) {
20
+ if (e.key === 'Enter' && !e.shiftKey) {
21
+ e.preventDefault();
22
+ sendMessage();
23
+ }
24
+ });
25
+ }
26
+
27
+ // Chat Functions
28
+ async function sendMessage() {
29
+ const input = document.getElementById('message-input');
30
+ const message = input.value.trim();
31
+
32
+ if (!message) return;
33
+
34
+ // Disable button
35
+ document.querySelector('.send-btn').disabled = true;
36
+ document.getElementById('loading-indicator').classList.remove('hidden');
37
+
38
+ // Add user message to UI
39
+ addMessageToUI('user', message);
40
+ input.value = '';
41
+ input.focus();
42
+
43
+ try {
44
+ const response = await fetch('/api/chat', {
45
+ method: 'POST',
46
+ headers: {
47
+ 'Content-Type': 'application/json',
48
+ },
49
+ body: JSON.stringify({
50
+ message: message,
51
+ conversation_id: currentConversationId,
52
+ language: currentLanguage
53
+ })
54
+ });
55
+
56
+ const data = await response.json();
57
+
58
+ if (data.success) {
59
+ addMessageToUI('assistant', data.message);
60
+ updateChatTitle(message);
61
+ loadConversations();
62
+ } else {
63
+ addMessageToUI('assistant', `خطأ / Error: ${data.error}`);
64
+ }
65
+ } catch (error) {
66
+ addMessageToUI('assistant', `خطأ في الاتصال / Connection Error: ${error.message}`);
67
+ } finally {
68
+ document.querySelector('.send-btn').disabled = false;
69
+ document.getElementById('loading-indicator').classList.add('hidden');
70
+ }
71
+ }
72
+
73
+ function addMessageToUI(role, content) {
74
+ const container = document.getElementById('messages-container');
75
+
76
+ // Remove welcome message if exists
77
+ const welcome = container.querySelector('.welcome-message');
78
+ if (welcome) welcome.remove();
79
+
80
+ const messageDiv = document.createElement('div');
81
+ messageDiv.className = `message ${role}`;
82
+
83
+ const contentDiv = document.createElement('div');
84
+ contentDiv.className = 'message-content';
85
+
86
+ // Format content (markdown, code, tables, etc.)
87
+ contentDiv.innerHTML = formatContent(content);
88
+
89
+ messageDiv.appendChild(contentDiv);
90
+ container.appendChild(messageDiv);
91
+
92
+ // Scroll to bottom
93
+ container.scrollTop = container.scrollHeight;
94
+ }
95
+
96
+ function formatContent(content) {
97
+ let html = content;
98
+
99
+ // Code blocks
100
+ html = html.replace(/```(\w+)?\n([\s\S]*?)```/g, (match, lang, code) => {
101
+ const language = lang || 'plaintext';
102
+ const escaped = escapeHtml(code.trim());
103
+ return `<pre><code class="language-${language}">${escaped}</code><button class="copy-code-btn" onclick="copyCode(this)">نسخ / Copy</button></pre>`;
104
+ });
105
+
106
+ // Inline code
107
+ html = html.replace(/`([^`]+)`/g, '<code>$1</code>');
108
+
109
+ // Bold
110
+ html = html.replace(/\*\*([^*]+)\*\*/g, '<strong>$1</strong>');
111
+
112
+ // Italic
113
+ html = html.replace(/\*([^*]+)\*/g, '<em>$1</em>');
114
+
115
+ // Line breaks
116
+ html = html.replace(/\n/g, '<br>');
117
+
118
+ return html;
119
+ }
120
+
121
+ function escapeHtml(text) {
122
+ const map = {
123
+ '&': '&amp;',
124
+ '<': '&lt;',
125
+ '>': '&gt;',
126
+ '"': '&quot;',
127
+ "'": '&#039;'
128
+ };
129
+ return text.replace(/[&<>"']/g, m => map[m]);
130
+ }
131
+
132
+ function copyCode(button) {
133
+ const code = button.previousSibling.textContent;
134
+ navigator.clipboard.writeText(code);
135
+ button.textContent = '✓ نسخ / Copied';
136
+ setTimeout(() => {
137
+ button.textContent = 'نسخ / Copy';
138
+ }, 2000);
139
+ }
140
+
141
+ // Conversation Management
142
+ async function loadConversations() {
143
+ try {
144
+ const response = await fetch('/api/conversations');
145
+ const data = await response.json();
146
+
147
+ const container = document.getElementById('conversations-container');
148
+ container.innerHTML = '';
149
+
150
+ if (data.conversations.length === 0) {
151
+ container.innerHTML = '<p style="color: #999; font-size: 12px;">لا توجد محادثات / No conversations</p>';
152
+ return;
153
+ }
154
+
155
+ data.conversations.forEach(conv => {
156
+ const item = document.createElement('div');
157
+ item.className = 'conversation-item';
158
+ item.textContent = conv.title;
159
+ item.onclick = () => loadConversation(conv.id);
160
+ container.appendChild(item);
161
+ });
162
+ } catch (error) {
163
+ console.error('Error loading conversations:', error);
164
+ }
165
+ }
166
+
167
+ async function loadConversation(conversationId) {
168
+ currentConversationId = conversationId;
169
+
170
+ try {
171
+ const response = await fetch(`/api/conversation/${conversationId}`);
172
+ const data = await response.json();
173
+
174
+ const container = document.getElementById('messages-container');
175
+ container.innerHTML = '';
176
+
177
+ if (data.messages.length === 0) {
178
+ container.innerHTML = '<div class="welcome-message">No messages in this conversation</div>';
179
+ return;
180
+ }
181
+
182
+ data.messages.forEach(msg => {
183
+ addMessageToUI(msg.role, msg.content);
184
+ });
185
+ } catch (error) {
186
+ console.error('Error loading conversation:', error);
187
+ }
188
+ }
189
+
190
+ function newChat() {
191
+ currentConversationId = 'conv_' + Date.now();
192
+ document.getElementById('messages-container').innerHTML = `
193
+ <div class="welcome-message">
194
+ <img src="https://copilot.microsoft.com/th/id/BCO.f29916dd-b0c1-4089-87cd-43d099a7d1a6.png" alt="Welcome">
195
+ <h2>مرحبا / Welcome</h2>
196
+ <p>أنا Genisi، مساعد ذكي متطور. كيف يمكنني مساعدتك؟</p>
197
+ <p>I'm Genisi, an advanced AI assistant. How can I help you?</p>
198
+ </div>
199
+ `;
200
+ document.getElementById('chat-title').textContent = 'Genisi Assistant';
201
+ }
202
+
203
+ function updateChatTitle(message) {
204
+ const title = message.substring(0, 50) + (message.length > 50 ? '...' : '');
205
+ document.getElementById('chat-title').textContent = title;
206
+ }
207
+
208
+ // Settings
209
+ function openSettings() {
210
+ document.getElementById('settings-modal').classList.add('show');
211
+ }
212
+
213
+ function closeSettings() {
214
+ document.getElementById('settings-modal').classList.remove('show');
215
+ }
216
+
217
+ function saveSettings() {
218
+ const language = document.getElementById('settings-language').value;
219
+ const theme = document.getElementById('settings-theme').value;
220
+ const temperature = document.getElementById('settings-temperature').value;
221
+
222
+ localStorage.setItem('language', language);
223
+ localStorage.setItem('theme', theme);
224
+ localStorage.setItem('temperature', temperature);
225
+
226
+ currentLanguage = language;
227
+ currentTheme = theme;
228
+
229
+ applyLanguage(language);
230
+ applyTheme(theme);
231
+ }
232
+
233
+ // Theme Management
234
+ function toggleTheme() {
235
+ currentTheme = currentTheme === 'light' ? 'dark' : 'light';
236
+ localStorage.setItem('theme', currentTheme);
237
+ applyTheme(currentTheme);
238
+ }
239
+
240
+ function applyTheme(theme) {
241
+ const body = document.body;
242
+
243
+ if (theme === 'dark') {
244
+ body.classList.add('dark-mode');
245
+ document.querySelector('.theme-toggle').textContent = '☀️';
246
+ } else {
247
+ body.classList.remove('dark-mode');
248
+ document.querySelector('.theme-toggle').textContent = '🌙';
249
+ }
250
+
251
+ if (document.getElementById('settings-theme')) {
252
+ document.getElementById('settings-theme').value = theme;
253
+ }
254
+ }
255
+
256
+ // Language Management
257
+ function changeLanguage(lang) {
258
+ currentLanguage = lang;
259
+ localStorage.setItem('language', lang);
260
+ applyLanguage(lang);
261
+ }
262
+
263
+ function applyLanguage(lang) {
264
+ const isRTL = lang === 'ar';
265
+ document.documentElement.dir = isRTL ? 'rtl' : 'ltr';
266
+
267
+ if (document.getElementById('settings-language')) {
268
+ document.getElementById('settings-language').value = lang;
269
+ }
270
+ }
271
+
272
+ function clearHistory() {
273
+ if (confirm('هل أنت متأكد؟ / Are you sure?')) {
274
+ localStorage.clear();
275
+ location.reload();
276
+ }
277
+ }
278
+
279
+ // Handle keyboard shortcuts
280
+ document.addEventListener('keydown', function(e) {
281
+ if (e.ctrlKey && e.key === 'k') {
282
+ e.preventDefault();
283
+ newChat();
284
+ }
285
+ });