uumerrr684 commited on
Commit
02b76be
·
verified ·
1 Parent(s): 1aa5a0c

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +314 -40
app.py CHANGED
@@ -16,15 +16,24 @@
16
  0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8,0,1,1); }
17
  50% { transform: none; animation-timing-function: cubic-bezier(0,0,0.2,1); }
18
  }
 
 
19
  .loading-dot-1 { animation-delay: 0s; }
20
  .loading-dot-2 { animation-delay: 0.1s; }
21
  .loading-dot-3 { animation-delay: 0.2s; }
22
  </style>
23
  </head>
24
  <body class="bg-gray-900 text-white h-screen overflow-hidden">
25
- <div class="flex h-screen">
26
  <!-- Sidebar -->
27
- <div class="w-80 bg-gray-800 border-r border-gray-700 flex flex-col">
 
 
 
 
 
 
 
28
  <!-- Header -->
29
  <div class="p-4 border-b border-gray-700">
30
  <div class="flex items-center gap-3 mb-4">
@@ -35,7 +44,7 @@
35
  </div>
36
  <h1 class="text-xl font-semibold">Chat Flow</h1>
37
  </div>
38
- <button id="newChatBtn" class="w-full flex items-center gap-2 px-4 py-2 bg-blue-600 hover:bg-blue-700 rounded-lg transition-colors">
39
  <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
40
  <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
41
  </svg>
@@ -43,8 +52,27 @@
43
  </button>
44
  </div>
45
 
 
 
 
 
 
 
 
 
 
 
 
46
  <!-- Settings -->
47
- <div class="p-4 border-t border-gray-700 space-y-4 flex-1">
 
 
 
 
 
 
 
 
48
  <!-- Online Users -->
49
  <div>
50
  <h3 class="text-sm font-medium text-gray-400 mb-2">👥 Who's Online</h3>
@@ -80,23 +108,25 @@
80
  </div>
81
 
82
  <!-- Controls -->
83
- <div class="flex gap-2">
84
- <button id="clearBtn" class="flex-1 flex items-center justify-center px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors text-sm" title="Clear Chat">
85
- <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
86
- <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
87
  </svg>
 
88
  </button>
89
- <button id="refreshBtn" class="flex-1 flex items-center justify-center px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg transition-colors text-sm" title="Refresh">
90
- <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
91
- <path d="M17.65 6.35C16.2 4.9 14.21 4 12 4c-4.42 0-7.99 3.58-7.99 8s3.57 8 7.99 8c3.73 0 6.84-2.55 7.73-6h-2.08c-.82 2.33-3.04 4-5.65 4-3.31 0-6-2.69-6-6s2.69-6 6-6c1.66 0 3.14.69 4.22 1.78L13 11h7V4l-2.35 2.35z"/>
92
  </svg>
 
93
  </button>
94
  </div>
95
  </div>
96
  </div>
97
 
98
  <!-- Main Chat Area -->
99
- <div class="flex-1 flex flex-col">
100
  <!-- Chat Messages -->
101
  <div id="messagesContainer" class="flex-1 overflow-y-auto chat-scroll">
102
  <!-- Welcome Screen -->
@@ -151,9 +181,12 @@
151
 
152
  // Global variables
153
  let messages = [];
 
154
  let selectedModel = 'openai/gpt-3.5-turbo';
155
  let isLoading = false;
156
  let userId = 'User-' + Math.random().toString(36).substr(2, 8);
 
 
157
 
158
  const models = {
159
  'openai/gpt-3.5-turbo': 'GPT-3.5 Turbo',
@@ -169,14 +202,19 @@
169
  };
170
 
171
  // Initialize app
172
- document.addEventListener('DOMContentLoaded', function() {
173
  console.log('App starting...');
174
  setupEventListeners();
 
175
  updateUserDisplay();
 
176
  console.log('App ready!');
177
  });
178
 
179
  function setupEventListeners() {
 
 
 
180
  // Send button
181
  document.getElementById('sendBtn').onclick = function() {
182
  console.log('Send button clicked');
@@ -206,6 +244,11 @@
206
  console.log('New chat started');
207
  };
208
 
 
 
 
 
 
209
  // Clear chat
210
  document.getElementById('clearBtn').onclick = function() {
211
  messages = [];
@@ -213,14 +256,83 @@
213
  console.log('Chat cleared');
214
  };
215
 
216
- // Refresh
217
- document.getElementById('refreshBtn').onclick = function() {
218
- window.location.reload();
219
  };
220
 
221
  console.log('Event listeners setup complete');
222
  }
223
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
224
  async function sendMessage() {
225
  const input = document.getElementById('messageInput');
226
  const message = input.value.trim();
@@ -243,12 +355,8 @@
243
  setLoading(true);
244
 
245
  try {
246
- const response = await getAIResponse(message);
247
- messages.push({
248
- role: 'assistant',
249
- content: response
250
- });
251
- updateDisplay();
252
  } catch (error) {
253
  console.error('Error:', error);
254
  messages.push({
@@ -261,15 +369,25 @@
261
  setLoading(false);
262
  }
263
 
264
- async function getAIResponse(userMessage) {
265
- console.log('Getting AI response...');
 
 
 
 
 
 
 
266
 
 
 
267
  const apiMessages = [{
268
  role: "system",
269
- content: "You are a helpful AI assistant."
270
  }];
271
 
272
- messages.forEach(msg => {
 
273
  if (msg.role !== 'assistant' || !msg.content.includes('Response created by:')) {
274
  apiMessages.push({
275
  role: msg.role,
@@ -289,6 +407,7 @@
289
  body: JSON.stringify({
290
  model: selectedModel,
291
  messages: apiMessages,
 
292
  max_tokens: 2000,
293
  temperature: 0.7
294
  })
@@ -298,11 +417,77 @@
298
  throw new Error('API Error: ' + response.status);
299
  }
300
 
301
- const data = await response.json();
302
- const aiResponse = data.choices[0].message.content;
303
- const modelName = models[selectedModel] || "AI";
304
-
305
- return aiResponse + "\n\n---\n*Response created by: **" + modelName + "***";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
306
  }
307
 
308
  function updateDisplay() {
@@ -361,18 +546,107 @@
361
 
362
  btn.disabled = loading;
363
  input.disabled = loading;
364
-
365
- if (loading) {
366
- btn.innerHTML = '<div class="w-4 h-4 border-2 border-white border-t-transparent rounded-full animate-spin"></div> Loading...';
367
- } else {
368
- btn.innerHTML = '<svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M2.01 21L23 12 2.01 3 2 10l15 2-15 2z"/></svg> Send';
369
- }
370
  }
371
 
372
  function updateUserDisplay() {
373
  document.getElementById('currentUser').textContent = 'You: ' + userId;
374
  document.getElementById('onlineStatus').textContent = 'Just you online';
375
  }
376
- </script>
377
- </body>
378
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  0%, 100% { transform: translateY(-25%); animation-timing-function: cubic-bezier(0.8,0,1,1); }
17
  50% { transform: none; animation-timing-function: cubic-bezier(0,0,0.2,1); }
18
  }
19
+ .sidebar-transition { transition: transform 0.3s ease-in-out; }
20
+ .sidebar-hidden { transform: translateX(-100%); }
21
  .loading-dot-1 { animation-delay: 0s; }
22
  .loading-dot-2 { animation-delay: 0.1s; }
23
  .loading-dot-3 { animation-delay: 0.2s; }
24
  </style>
25
  </head>
26
  <body class="bg-gray-900 text-white h-screen overflow-hidden">
27
+ <div class="flex h-screen relative">
28
  <!-- Sidebar -->
29
+ <div id="sidebar" class="w-80 bg-gray-800 border-r border-gray-700 flex flex-col sidebar-transition z-10">
30
+ <!-- Sidebar Toggle Button -->
31
+ <button id="sidebarToggle" class="absolute -right-8 top-4 bg-black text-white p-2 rounded-r-lg hover:bg-gray-800 transition-colors z-20">
32
+ <svg id="toggleIcon" class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
33
+ <path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>
34
+ </svg>
35
+ </button>
36
+
37
  <!-- Header -->
38
  <div class="p-4 border-b border-gray-700">
39
  <div class="flex items-center gap-3 mb-4">
 
44
  </div>
45
  <h1 class="text-xl font-semibold">Chat Flow</h1>
46
  </div>
47
+ <button id="newChatBtn" class="w-full flex items-center gap-2 px-4 py-2 bg-black text-white hover:bg-gray-800 rounded-lg transition-colors">
48
  <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24">
49
  <path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
50
  </svg>
 
52
  </button>
53
  </div>
54
 
55
+ <!-- Chat History -->
56
+ <div class="flex-1 overflow-y-auto p-4 chat-scroll">
57
+ <h3 class="text-sm font-medium text-gray-400 mb-3">💬 Chat History</h3>
58
+ <div id="chatHistoryList" class="space-y-2">
59
+ <p class="text-gray-500 text-sm">No saved chats yet</p>
60
+ </div>
61
+ <button id="saveCurrentChatBtn" class="w-full mt-3 px-3 py-2 bg-black text-white hover:bg-gray-800 rounded-lg transition-colors text-sm">
62
+ 💾 Save Current Chat
63
+ </button>
64
+ </div>
65
+
66
  <!-- Settings -->
67
+ <div class="p-4 border-t border-gray-700 space-y-4">
68
+ <!-- Location Info -->
69
+ <div>
70
+ <h3 class="text-sm font-medium text-gray-400 mb-2">📍 Your Location</h3>
71
+ <div class="bg-gray-700 rounded-lg p-2 text-xs">
72
+ <div id="locationInfo" class="text-green-400">🌍 Getting location...</div>
73
+ </div>
74
+ </div>
75
+
76
  <!-- Online Users -->
77
  <div>
78
  <h3 class="text-sm font-medium text-gray-400 mb-2">👥 Who's Online</h3>
 
108
  </div>
109
 
110
  <!-- Controls -->
111
+ <div class="grid grid-cols-2 gap-2">
112
+ <button id="downloadBtn" class="flex items-center justify-center px-3 py-2 bg-black text-white hover:bg-gray-800 rounded-lg transition-colors text-sm" title="Download History">
113
+ <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 24 24">
114
+ <path d="M19 9h-4V3H9v6H5l7 7 7-7zM5 18v2h14v-2H5z"/>
115
  </svg>
116
+ Download
117
  </button>
118
+ <button id="clearBtn" class="flex items-center justify-center px-3 py-2 bg-black text-white hover:bg-gray-800 rounded-lg transition-colors text-sm" title="Clear Chat">
119
+ <svg class="w-4 h-4 mr-1" fill="currentColor" viewBox="0 0 24 24">
120
+ <path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/>
121
  </svg>
122
+ Clear
123
  </button>
124
  </div>
125
  </div>
126
  </div>
127
 
128
  <!-- Main Chat Area -->
129
+ <div id="mainArea" class="flex-1 flex flex-col transition-all duration-300">
130
  <!-- Chat Messages -->
131
  <div id="messagesContainer" class="flex-1 overflow-y-auto chat-scroll">
132
  <!-- Welcome Screen -->
 
181
 
182
  // Global variables
183
  let messages = [];
184
+ let savedChats = JSON.parse(localStorage.getItem('chatHistory') || '[]');
185
  let selectedModel = 'openai/gpt-3.5-turbo';
186
  let isLoading = false;
187
  let userId = 'User-' + Math.random().toString(36).substr(2, 8);
188
+ let userLocation = { city: 'Unknown', country: 'Unknown' };
189
+ let sidebarVisible = true;
190
 
191
  const models = {
192
  'openai/gpt-3.5-turbo': 'GPT-3.5 Turbo',
 
202
  };
203
 
204
  // Initialize app
205
+ document.addEventListener('DOMContentLoaded', async function() {
206
  console.log('App starting...');
207
  setupEventListeners();
208
+ await getUserLocation();
209
  updateUserDisplay();
210
+ updateChatHistory();
211
  console.log('App ready!');
212
  });
213
 
214
  function setupEventListeners() {
215
+ // Sidebar toggle
216
+ document.getElementById('sidebarToggle').onclick = toggleSidebar;
217
+
218
  // Send button
219
  document.getElementById('sendBtn').onclick = function() {
220
  console.log('Send button clicked');
 
244
  console.log('New chat started');
245
  };
246
 
247
+ // Save current chat
248
+ document.getElementById('saveCurrentChatBtn').onclick = function() {
249
+ saveCurrentChat();
250
+ };
251
+
252
  // Clear chat
253
  document.getElementById('clearBtn').onclick = function() {
254
  messages = [];
 
256
  console.log('Chat cleared');
257
  };
258
 
259
+ // Download chat
260
+ document.getElementById('downloadBtn').onclick = function() {
261
+ downloadCurrentChat();
262
  };
263
 
264
  console.log('Event listeners setup complete');
265
  }
266
 
267
+ function toggleSidebar() {
268
+ const sidebar = document.getElementById('sidebar');
269
+ const mainArea = document.getElementById('mainArea');
270
+ const toggleIcon = document.getElementById('toggleIcon');
271
+
272
+ sidebarVisible = !sidebarVisible;
273
+
274
+ if (sidebarVisible) {
275
+ sidebar.classList.remove('sidebar-hidden');
276
+ toggleIcon.innerHTML = '<path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/>';
277
+ } else {
278
+ sidebar.classList.add('sidebar-hidden');
279
+ toggleIcon.innerHTML = '<path d="M8.59 16.59L10 18l6-6-6-6-1.41 1.41L13.17 12z"/>';
280
+ }
281
+ }
282
+
283
+ // Get user's real location (like your Streamlit code)
284
+ async function getUserLocation() {
285
+ try {
286
+ if (navigator.geolocation) {
287
+ const position = await new Promise((resolve, reject) => {
288
+ navigator.geolocation.getCurrentPosition(resolve, reject, {
289
+ timeout: 10000,
290
+ enableHighAccuracy: false
291
+ });
292
+ });
293
+
294
+ const { latitude, longitude } = position.coords;
295
+
296
+ // Use reverse geocoding
297
+ try {
298
+ const response = await fetch(`https://api.bigdatacloud.net/data/reverse-geocode-client?latitude=${latitude}&longitude=${longitude}&localityLanguage=en`);
299
+ const data = await response.json();
300
+
301
+ userLocation = {
302
+ city: data.city || data.locality || 'Unknown',
303
+ country: data.countryName || 'Unknown'
304
+ };
305
+ } catch (geocodeError) {
306
+ await getLocationByIP();
307
+ }
308
+ } else {
309
+ await getLocationByIP();
310
+ }
311
+ } catch (error) {
312
+ await getLocationByIP();
313
+ }
314
+
315
+ updateLocationDisplay();
316
+ }
317
+
318
+ async function getLocationByIP() {
319
+ try {
320
+ const response = await fetch('https://ipapi.co/json/');
321
+ const data = await response.json();
322
+
323
+ userLocation = {
324
+ city: data.city || 'Unknown',
325
+ country: data.country_name || 'Unknown'
326
+ };
327
+ } catch (error) {
328
+ userLocation = { city: 'Unknown', country: 'Unknown' };
329
+ }
330
+ }
331
+
332
+ function updateLocationDisplay() {
333
+ document.getElementById('locationInfo').textContent = `📍 ${userLocation.city}, ${userLocation.country}`;
334
+ }
335
+
336
  async function sendMessage() {
337
  const input = document.getElementById('messageInput');
338
  const message = input.value.trim();
 
355
  setLoading(true);
356
 
357
  try {
358
+ // Start streaming response - like your Streamlit code
359
+ await streamAIResponse(message);
 
 
 
 
360
  } catch (error) {
361
  console.error('Error:', error);
362
  messages.push({
 
369
  setLoading(false);
370
  }
371
 
372
+ // Streaming implementation like your Streamlit code
373
+ async function streamAIResponse(userMessage) {
374
+ console.log('Starting stream...');
375
+
376
+ // Add empty assistant message for streaming
377
+ messages.push({
378
+ role: 'assistant',
379
+ content: ''
380
+ });
381
 
382
+ updateDisplay();
383
+
384
  const apiMessages = [{
385
  role: "system",
386
+ content: "You are a helpful AI assistant. Provide clear and helpful responses."
387
  }];
388
 
389
+ // Build conversation history (like your Streamlit extend)
390
+ messages.slice(0, -1).forEach(msg => {
391
  if (msg.role !== 'assistant' || !msg.content.includes('Response created by:')) {
392
  apiMessages.push({
393
  role: msg.role,
 
407
  body: JSON.stringify({
408
  model: selectedModel,
409
  messages: apiMessages,
410
+ stream: true, // Enable streaming like Streamlit
411
  max_tokens: 2000,
412
  temperature: 0.7
413
  })
 
417
  throw new Error('API Error: ' + response.status);
418
  }
419
 
420
+ const reader = response.body.getReader();
421
+ const decoder = new TextDecoder();
422
+ let fullResponse = '';
423
+
424
+ try {
425
+ while (true) {
426
+ const { done, value } = await reader.read();
427
+ if (done) break;
428
+
429
+ const chunk = decoder.decode(value, { stream: true });
430
+ const lines = chunk.split('\n');
431
+
432
+ for (const line of lines) {
433
+ if (line.trim() === '') continue;
434
+
435
+ if (line.startsWith('data: ')) {
436
+ const data = line.slice(6).trim();
437
+
438
+ if (data === '[DONE]') {
439
+ // Finalize response with attribution (like Streamlit)
440
+ const modelName = models[selectedModel] || "AI";
441
+ const finalResponse = fullResponse + "\n\n---\n*Response created by: **" + modelName + "***";
442
+ messages[messages.length - 1].content = finalResponse;
443
+ updateDisplay();
444
+ return;
445
+ }
446
+
447
+ if (data === '') continue;
448
+
449
+ try {
450
+ const parsed = JSON.parse(data);
451
+ const delta = parsed.choices?.[0]?.delta?.content;
452
+
453
+ if (delta) {
454
+ fullResponse += delta;
455
+ // Update display in real-time (like Streamlit placeholder.markdown)
456
+ updateStreamingMessage(fullResponse);
457
+ }
458
+ } catch (e) {
459
+ continue;
460
+ }
461
+ }
462
+ }
463
+ }
464
+ } finally {
465
+ reader.releaseLock();
466
+ }
467
+ }
468
+
469
+ function updateStreamingMessage(partialResponse) {
470
+ // Update the last message with streaming content + cursor
471
+ if (messages.length > 0) {
472
+ const lastMessage = messages[messages.length - 1];
473
+ if (lastMessage.role === 'assistant') {
474
+ lastMessage.content = partialResponse;
475
+
476
+ // Update display with cursor (like Streamlit "▌")
477
+ const messagesArea = document.getElementById('messagesArea');
478
+ const messageElements = messagesArea.children;
479
+
480
+ if (messageElements.length > 0) {
481
+ const lastMessageElement = messageElements[messageElements.length - 1];
482
+ const contentDiv = lastMessageElement.querySelector('.whitespace-pre-wrap');
483
+ if (contentDiv) {
484
+ contentDiv.textContent = partialResponse + " ▌";
485
+ }
486
+ }
487
+
488
+ messagesArea.scrollTop = messagesArea.scrollHeight;
489
+ }
490
+ }
491
  }
492
 
493
  function updateDisplay() {
 
546
 
547
  btn.disabled = loading;
548
  input.disabled = loading;
 
 
 
 
 
 
549
  }
550
 
551
  function updateUserDisplay() {
552
  document.getElementById('currentUser').textContent = 'You: ' + userId;
553
  document.getElementById('onlineStatus').textContent = 'Just you online';
554
  }
555
+
556
+ // Chat save functionality (like your Streamlit save_chat_history)
557
+ function saveCurrentChat() {
558
+ if (messages.length === 0) {
559
+ alert('No messages to save!');
560
+ return;
561
+ }
562
+
563
+ const title = generateChatTitle();
564
+ const chatData = {
565
+ id: Date.now(),
566
+ title: title,
567
+ messages: JSON.parse(JSON.stringify(messages)),
568
+ createdAt: new Date().toISOString(),
569
+ location: userLocation
570
+ };
571
+
572
+ savedChats.unshift(chatData);
573
+ localStorage.setItem('chatHistory', JSON.stringify(savedChats));
574
+ updateChatHistory();
575
+
576
+ alert('Chat saved successfully!');
577
+ }
578
+
579
+ function generateChatTitle() {
580
+ const firstUserMessage = messages.find(m => m.role === 'user');
581
+ if (!firstUserMessage) return 'Empty Chat';
582
+
583
+ const content = firstUserMessage.content;
584
+ return content.length > 30 ? content.substring(0, 30) + '...' : content;
585
+ }
586
+
587
+ function updateChatHistory() {
588
+ const historyList = document.getElementById('chatHistoryList');
589
+
590
+ if (savedChats.length === 0) {
591
+ historyList.innerHTML = '<p class="text-gray-500 text-sm">No saved chats yet</p>';
592
+ return;
593
+ }
594
+
595
+ let html = '';
596
+ savedChats.slice(0, 10).forEach(chat => { // Show last 10 chats
597
+ const date = new Date(chat.createdAt).toLocaleDateString();
598
+ html += `
599
+ <div class="group flex items-center gap-2">
600
+ <button onclick="loadChat(${chat.id})" class="flex-1 text-left px-3 py-2 bg-gray-700 hover:bg-gray-600 rounded-lg text-gray-300 transition-colors">
601
+ <div class="text-sm font-medium truncate">${chat.title}</div>
602
+ <div class="text-xs text-gray-400">${date}</div>
603
+ </button>
604
+ <button onclick="deleteChat(${chat.id})" class="opacity-0 group-hover:opacity-100 p-1 text-gray-400 hover:text-red-400 transition-all">
605
+ <svg class="w-4 h-4" fill="currentColor" viewBox="0 0 24 24"><path d="M6 19c0 1.1.9 2 2 2h8c1.1 0 2-.9 2-2V7H6v12zM19 4h-3.5l-1-1h-5l-1 1H5v2h14V4z"/></svg>
606
+ </button>
607
+ </div>
608
+ `;
609
+ });
610
+
611
+ historyList.innerHTML = html;
612
+ }
613
+
614
+ function loadChat(chatId) {
615
+ const chat = savedChats.find(c => c.id === chatId);
616
+ if (chat) {
617
+ messages = JSON.parse(JSON.stringify(chat.messages));
618
+ updateDisplay();
619
+ console.log('Chat loaded:', chat.title);
620
+ }
621
+ }
622
+
623
+ function deleteChat(chatId) {
624
+ if (confirm('Delete this chat?')) {
625
+ savedChats = savedChats.filter(c => c.id !== chatId);
626
+ localStorage.setItem('chatHistory', JSON.stringify(savedChats));
627
+ updateChatHistory();
628
+ }
629
+ }
630
+
631
+ function downloadCurrentChat() {
632
+ if (messages.length === 0) {
633
+ alert('No messages to download!');
634
+ return;
635
+ }
636
+
637
+ const chatData = {
638
+ title: generateChatTitle(),
639
+ messages: messages,
640
+ exportedAt: new Date().toISOString(),
641
+ location: userLocation,
642
+ userId: userId
643
+ };
644
+
645
+ const dataStr = JSON.stringify(chatData, null, 2);
646
+ const dataBlob = new Blob([dataStr], { type: 'application/json' });
647
+ const url = URL.createObjectURL(dataBlob);
648
+ const link = document.createElement('a');
649
+ link.href = url;
650
+ link.download = `chat_${new Date().toISOString().split('T')[0]}.json`;
651
+ link.click();
652
+ URL.revokeObjectURL(url);