Shirpi commited on
Commit
9d4f5aa
·
verified ·
1 Parent(s): ec25b17

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +66 -86
app.py CHANGED
@@ -109,7 +109,6 @@ def generate_with_retry(prompt, image_data=None, file_text=None, history_message
109
  return "⚠️ System Busy. Please try again."
110
 
111
  # --- UI TEMPLATE ---
112
- # (Idhu HTML string variable dhaan, HTML file finish aagura edam idhu)
113
  HTML_TEMPLATE = """
114
  <!DOCTYPE html>
115
  <html lang="en">
@@ -143,13 +142,13 @@ HTML_TEMPLATE = """
143
  }
144
  * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
145
 
 
146
  body, html {
147
  margin: 0; padding: 0; height: 100dvh; width: 100%; max-width: 100%;
148
  background: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif;
149
  overflow: hidden;
150
  font-size: 17px;
151
 
152
- /* No Selection Allowed */
153
  -webkit-user-select: none;
154
  -moz-user-select: none;
155
  -ms-user-select: none;
@@ -164,7 +163,6 @@ HTML_TEMPLATE = """
164
  -webkit-touch-callout: default !important;
165
  }
166
 
167
- /* Prevent long press on content */
168
  .user-content, .ai-content, code, pre, p, h1, h2, span, div {
169
  -webkit-user-select: none !important;
170
  user-select: none !important;
@@ -173,10 +171,8 @@ HTML_TEMPLATE = """
173
 
174
  #app-container {
175
  display: flex; flex-direction: column;
176
- height: 100dvh;
177
- width: 100%;
178
- position: relative;
179
- overflow-x: hidden;
180
  }
181
 
182
  header {
@@ -194,6 +190,7 @@ HTML_TEMPLATE = """
194
  .menu-btn:active { transform: scale(0.95); background: #222; }
195
  .app-title { font-size: 24px; font-weight: 800; letter-spacing: -0.5px; color: #fff; }
196
 
 
197
  #sidebar {
198
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
199
  background: var(--bg); z-index: 100;
@@ -201,27 +198,33 @@ HTML_TEMPLATE = """
201
  padding-top: calc(70px + env(safe-area-inset-top));
202
  transform: translateY(-100%);
203
  transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
 
204
  }
205
  #sidebar.open { transform: translateY(0); }
206
 
207
- .user-info { margin-bottom: 30px; font-size: 20px; font-weight: 700; color: #fff; display: flex; align-items: center; gap: 15px; }
 
 
 
 
 
 
 
 
208
  .new-chat-btn {
209
  width: 100%; padding: 15px; background: #fff; color: #000; border: none;
210
- border-radius: 12px; font-weight: 700; font-size: 16px; cursor: pointer; margin-bottom: 25px;
211
  }
212
 
213
- .history-label { color: var(--dim); font-size: 13px; font-weight: 600; margin-bottom: 10px; letter-spacing: 1px; text-transform: uppercase; }
214
 
215
- #history-list {
216
- flex: 1; overflow-y: auto; padding: 10px 0;
217
- }
218
  .history-item {
219
  display: flex; justify-content: space-between; align-items: center;
220
  padding: 15px; margin-bottom: 12px;
221
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
222
  cursor: pointer; color: #a1a1aa; font-size: 15px; transition: 0.2s;
223
  }
224
- .history-item:last-child { margin-bottom: 0; }
225
  .history-item:active { background: #222; color: #fff; border-color: #444; }
226
 
227
  .h-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; flex: 1; margin-right: 10px; }
@@ -229,67 +232,30 @@ HTML_TEMPLATE = """
229
  .history-item.active-mode .h-actions { display: flex; }
230
  .h-icon { font-size: 16px; color: #fff; padding: 5px; }
231
 
232
- /* --- NEW STYLE FOR INLINE RENAME INPUT --- */
233
  .rename-input {
234
- background: transparent;
235
- border: none;
236
- border-bottom: 1px solid #fff;
237
- color: #fff;
238
- font-family: 'Outfit', sans-serif;
239
- font-size: 15px;
240
- width: 100%;
241
- outline: none;
242
- padding: 0;
243
- }
244
-
245
- .brand-section { text-align: center; margin-top: 20px; padding-bottom: env(safe-area-inset-bottom); }
246
  .brand-name { font-family: 'Outfit', sans-serif; font-weight: 600; font-size: 12px; color: var(--dim); letter-spacing: 2px; margin-bottom: 10px; opacity: 0.6; }
247
  .logout-btn { color: #ef4444; cursor: pointer; font-size: 15px; font-weight: 600; padding: 10px; }
248
 
249
  #chat-box {
250
- flex: 1;
251
- overflow-y: auto;
252
- padding: 20px 5%;
253
- padding-bottom: 80px;
254
- display: flex;
255
- flex-direction: column;
256
- gap: 25px;
257
- -webkit-overflow-scrolling: touch;
258
- overscroll-behavior-y: contain;
259
- min-height: 0;
260
  }
261
 
262
- .msg {
263
- width: 100%;
264
- line-height: 1.7;
265
- font-size: 17px;
266
- opacity: 0;
267
- animation: fadeInstant 0.3s forwards;
268
- display: flex;
269
- flex-direction: column;
270
- }
271
  @keyframes fadeInstant { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
272
 
273
  .user-msg { align-items: flex-end; }
274
-
275
- .user-content {
276
- display: inline-block;
277
- width: fit-content;
278
- max-width: 85%;
279
- background: var(--user-msg);
280
- padding: 10px 16px;
281
- border-radius: 18px 18px 4px 18px;
282
- text-align: left;
283
- color: #fff;
284
- word-wrap: break-word;
285
- }
286
 
287
  .ai-msg { align-items: flex-start; }
288
- .ai-content {
289
- width: 100%;
290
- color: #d4d4d8;
291
- word-wrap: break-word;
292
- }
293
  .ai-content strong { color: #fff; font-weight: 700; }
294
  .ai-content h1, .ai-content h2 { margin-top: 20px; color: #fff; font-weight: 700; }
295
 
@@ -298,7 +264,6 @@ HTML_TEMPLATE = """
298
 
299
  pre { background: #1e1e1e !important; border-radius: 12px; padding: 15px; overflow-x: auto; margin: 15px 0; border: 1px solid #333; max-width: 100%; }
300
  code { font-family: 'JetBrains Mono', monospace; font-size: 14px; }
301
-
302
  .mjx-chtml { background: #18181b; padding: 10px; border-radius: 8px; border: 1px solid #333; overflow-x: auto; margin: 10px 0; text-align: center; max-width: 100%; }
303
  .mermaid { background: #111; padding: 15px; border-radius: 10px; text-align: center; margin: 15px 0; overflow-x: auto; }
304
 
@@ -309,11 +274,7 @@ HTML_TEMPLATE = """
309
  .action-icon:hover { color: #fff; transform: scale(1.1); }
310
 
311
  .input-wrapper { background: var(--bg); padding: 15px; border-top: 1px solid var(--border); flex-shrink: 0; z-index: 60; padding-bottom: max(15px, env(safe-area-inset-bottom)); }
312
- .input-container {
313
- max-width: 900px; margin: 0 auto; background: var(--card);
314
- border: 1px solid var(--border); border-radius: 24px; padding: 8px 12px;
315
- display: flex; align-items: flex-end; gap: 12px;
316
- }
317
  textarea { flex: 1; background: transparent; border: none; color: #fff; font-size: 17px; max-height: 120px; padding: 10px 5px; resize: none; outline: none; font-family: 'Outfit', sans-serif; }
318
 
319
  .icon-btn { width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: none; background: transparent; color: #a1a1aa; cursor: pointer; font-size: 18px; }
@@ -323,22 +284,25 @@ HTML_TEMPLATE = """
323
  #preview-area { position: absolute; bottom: 85px; left: 20px; display: none; z-index: 70; }
324
  .preview-box { width: 60px; height: 60px; border-radius: 12px; border: 2px solid #fff; background: #222; overflow: hidden; position: relative; box-shadow: 0 4px 12px rgba(0,0,0,0.5); }
325
  .preview-img { width: 100%; height: 100%; object-fit: cover; }
326
- .preview-file-icon { width: 100%; height: 100%; display: flex; align-items: center; justify-content: center; font-size: 24px; color: #fff; }
327
  .remove-preview { position: absolute; top: -8px; right: -8px; background: red; color: white; border-radius: 50%; width: 20px; height: 20px; font-size: 12px; cursor: pointer; border: none; display: flex; align-items: center; justify-content: center; }
328
 
329
- #login-overlay { position: fixed; inset: 0; background: #000; z-index: 2000; display: flex; align-items: center; justify-content: center; }
330
- .login-box { width: 90%; max-width: 350px; text-align: center; padding: 40px; border: 1px solid var(--border); border-radius: 20px; background: #0a0a0a; }
331
-
332
- #image-modal {
333
- position: fixed; top: 0; left: 0; width: 100%; height: 100%;
334
- background: rgba(0,0,0,0.9); z-index: 3000;
335
- display: none; align-items: center; justify-content: center;
336
- opacity: 0; transition: opacity 0.3s;
337
  }
338
- #image-modal img {
339
- max-width: 95%; max-height: 90%; border-radius: 8px;
340
- box-shadow: 0 0 20px rgba(0,0,0,0.8);
 
 
 
341
  }
 
 
 
342
  #image-modal.active { opacity: 1; }
343
  </style>
344
  </head>
@@ -357,7 +321,7 @@ HTML_TEMPLATE = """
357
  </div>
358
 
359
  <div id="sidebar">
360
- <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px;">
361
  <div class="user-info"><span id="display-name">User</span></div>
362
  <div class="menu-btn" onclick="toggleSidebar()"><i class="fas fa-times"></i></div>
363
  </div>
@@ -409,29 +373,45 @@ HTML_TEMPLATE = """
409
  return `<div class="msg ai-msg"><div class="ai-content"><h1>Hi ${name},</h1><p>Ready to master your studies today?</p></div></div>`;
410
  }
411
 
412
- // --- AUTH LOGIC ---
413
  function checkLogin() {
414
  try {
415
  const stored = localStorage.getItem("student_ai_user");
416
- if (stored) { currentUser = stored; showApp(); }
 
 
 
 
417
  } catch(e) { console.log("Storage access denied"); }
418
  }
 
419
  function handleLogin() {
420
  const input = document.getElementById("username-input");
421
  const name = input.value.trim();
422
  if(name) {
423
  try { localStorage.setItem("student_ai_user", name); } catch(e){}
424
  currentUser = name;
 
425
  showApp();
426
  } else {
427
  input.style.border = "1px solid red";
428
  setTimeout(() => input.style.border = "1px solid #333", 2000);
429
  }
430
  }
431
- function handleLogout() { localStorage.removeItem("student_ai_user"); location.reload(); }
 
 
 
 
 
 
 
 
 
 
 
432
 
433
  function showApp() {
434
- document.getElementById("login-overlay").style.display = "none";
435
  document.getElementById("display-name").innerText = "Hi " + currentUser;
436
  loadHistory();
437
  if(!currentChatId) {
 
109
  return "⚠️ System Busy. Please try again."
110
 
111
  # --- UI TEMPLATE ---
 
112
  HTML_TEMPLATE = """
113
  <!DOCTYPE html>
114
  <html lang="en">
 
142
  }
143
  * { box-sizing: border-box; -webkit-tap-highlight-color: transparent; }
144
 
145
+ /* FIX: Prevent Horizontal Scroll & Disable Select */
146
  body, html {
147
  margin: 0; padding: 0; height: 100dvh; width: 100%; max-width: 100%;
148
  background: var(--bg); color: var(--text); font-family: 'Outfit', sans-serif;
149
  overflow: hidden;
150
  font-size: 17px;
151
 
 
152
  -webkit-user-select: none;
153
  -moz-user-select: none;
154
  -ms-user-select: none;
 
163
  -webkit-touch-callout: default !important;
164
  }
165
 
 
166
  .user-content, .ai-content, code, pre, p, h1, h2, span, div {
167
  -webkit-user-select: none !important;
168
  user-select: none !important;
 
171
 
172
  #app-container {
173
  display: flex; flex-direction: column;
174
+ height: 100dvh; width: 100%;
175
+ position: relative; overflow-x: hidden;
 
 
176
  }
177
 
178
  header {
 
190
  .menu-btn:active { transform: scale(0.95); background: #222; }
191
  .app-title { font-size: 24px; font-weight: 800; letter-spacing: -0.5px; color: #fff; }
192
 
193
+ /* --- FIXED SIDEBAR FOR ROTATION & DESKTOP --- */
194
  #sidebar {
195
  position: fixed; top: 0; left: 0; width: 100%; height: 100%;
196
  background: var(--bg); z-index: 100;
 
198
  padding-top: calc(70px + env(safe-area-inset-top));
199
  transform: translateY(-100%);
200
  transition: transform 0.6s cubic-bezier(0.25, 1, 0.5, 1);
201
+ overflow-y: auto; /* Scrollable sidebar */
202
  }
203
  #sidebar.open { transform: translateY(0); }
204
 
205
+ /* Media Query for Desktop/Landscape */
206
+ @media (min-width: 768px) {
207
+ #sidebar { width: 350px; transform: translateX(-100%); transition: transform 0.4s ease; border-right: 1px solid var(--border); }
208
+ #sidebar.open { transform: translateX(0); }
209
+ .input-container { max-width: 800px; }
210
+ #chat-box { padding: 20px 15%; }
211
+ }
212
+
213
+ .user-info { margin-bottom: 30px; font-size: 20px; font-weight: 700; color: #fff; display: flex; align-items: center; gap: 15px; flex-shrink: 0; }
214
  .new-chat-btn {
215
  width: 100%; padding: 15px; background: #fff; color: #000; border: none;
216
+ border-radius: 12px; font-weight: 700; font-size: 16px; cursor: pointer; margin-bottom: 25px; flex-shrink: 0;
217
  }
218
 
219
+ .history-label { color: var(--dim); font-size: 13px; font-weight: 600; margin-bottom: 10px; letter-spacing: 1px; text-transform: uppercase; flex-shrink: 0; }
220
 
221
+ #history-list { flex: 1; overflow-y: auto; padding: 10px 0; min-height: 100px; }
 
 
222
  .history-item {
223
  display: flex; justify-content: space-between; align-items: center;
224
  padding: 15px; margin-bottom: 12px;
225
  background: var(--card); border: 1px solid var(--border); border-radius: 12px;
226
  cursor: pointer; color: #a1a1aa; font-size: 15px; transition: 0.2s;
227
  }
 
228
  .history-item:active { background: #222; color: #fff; border-color: #444; }
229
 
230
  .h-title { white-space: nowrap; overflow: hidden; text-overflow: ellipsis; max-width: 200px; flex: 1; margin-right: 10px; }
 
232
  .history-item.active-mode .h-actions { display: flex; }
233
  .h-icon { font-size: 16px; color: #fff; padding: 5px; }
234
 
 
235
  .rename-input {
236
+ background: transparent; border: none; border-bottom: 1px solid #fff;
237
+ color: #fff; font-family: 'Outfit', sans-serif; font-size: 15px;
238
+ width: 100%; outline: none; padding: 0;
239
+ }
240
+
241
+ .brand-section { text-align: center; margin-top: 20px; padding-bottom: env(safe-area-inset-bottom); flex-shrink: 0; }
 
 
 
 
 
 
242
  .brand-name { font-family: 'Outfit', sans-serif; font-weight: 600; font-size: 12px; color: var(--dim); letter-spacing: 2px; margin-bottom: 10px; opacity: 0.6; }
243
  .logout-btn { color: #ef4444; cursor: pointer; font-size: 15px; font-weight: 600; padding: 10px; }
244
 
245
  #chat-box {
246
+ flex: 1; overflow-y: auto; padding: 20px 5%; padding-bottom: 80px;
247
+ display: flex; flex-direction: column; gap: 25px;
248
+ -webkit-overflow-scrolling: touch; overscroll-behavior-y: contain; min-height: 0;
 
 
 
 
 
 
 
249
  }
250
 
251
+ .msg { width: 100%; line-height: 1.7; font-size: 17px; opacity: 0; animation: fadeInstant 0.3s forwards; display: flex; flex-direction: column; }
 
 
 
 
 
 
 
 
252
  @keyframes fadeInstant { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } }
253
 
254
  .user-msg { align-items: flex-end; }
255
+ .user-content { display: inline-block; width: fit-content; max-width: 85%; background: var(--user-msg); padding: 10px 16px; border-radius: 18px 18px 4px 18px; text-align: left; color: #fff; word-wrap: break-word; }
 
 
 
 
 
 
 
 
 
 
 
256
 
257
  .ai-msg { align-items: flex-start; }
258
+ .ai-content { width: 100%; color: #d4d4d8; word-wrap: break-word; }
 
 
 
 
259
  .ai-content strong { color: #fff; font-weight: 700; }
260
  .ai-content h1, .ai-content h2 { margin-top: 20px; color: #fff; font-weight: 700; }
261
 
 
264
 
265
  pre { background: #1e1e1e !important; border-radius: 12px; padding: 15px; overflow-x: auto; margin: 15px 0; border: 1px solid #333; max-width: 100%; }
266
  code { font-family: 'JetBrains Mono', monospace; font-size: 14px; }
 
267
  .mjx-chtml { background: #18181b; padding: 10px; border-radius: 8px; border: 1px solid #333; overflow-x: auto; margin: 10px 0; text-align: center; max-width: 100%; }
268
  .mermaid { background: #111; padding: 15px; border-radius: 10px; text-align: center; margin: 15px 0; overflow-x: auto; }
269
 
 
274
  .action-icon:hover { color: #fff; transform: scale(1.1); }
275
 
276
  .input-wrapper { background: var(--bg); padding: 15px; border-top: 1px solid var(--border); flex-shrink: 0; z-index: 60; padding-bottom: max(15px, env(safe-area-inset-bottom)); }
277
+ .input-container { max-width: 900px; margin: 0 auto; background: var(--card); border: 1px solid var(--border); border-radius: 24px; padding: 8px 12px; display: flex; align-items: flex-end; gap: 12px; }
 
 
 
 
278
  textarea { flex: 1; background: transparent; border: none; color: #fff; font-size: 17px; max-height: 120px; padding: 10px 5px; resize: none; outline: none; font-family: 'Outfit', sans-serif; }
279
 
280
  .icon-btn { width: 38px; height: 38px; display: flex; align-items: center; justify-content: center; border-radius: 50%; border: none; background: transparent; color: #a1a1aa; cursor: pointer; font-size: 18px; }
 
284
  #preview-area { position: absolute; bottom: 85px; left: 20px; display: none; z-index: 70; }
285
  .preview-box { width: 60px; height: 60px; border-radius: 12px; border: 2px solid #fff; background: #222; overflow: hidden; position: relative; box-shadow: 0 4px 12px rgba(0,0,0,0.5); }
286
  .preview-img { width: 100%; height: 100%; object-fit: cover; }
 
287
  .remove-preview { position: absolute; top: -8px; right: -8px; background: red; color: white; border-radius: 50%; width: 20px; height: 20px; font-size: 12px; cursor: pointer; border: none; display: flex; align-items: center; justify-content: center; }
288
 
289
+ /* --- UPDATED LOGIN OVERLAY (FIXED) --- */
290
+ #login-overlay {
291
+ position: fixed; inset: 0; background: #000; z-index: 2000;
292
+ display: flex; align-items: center; justify-content: center;
293
+ transition: opacity 0.5s ease, visibility 0.5s ease;
294
+ opacity: 1; visibility: visible;
 
 
295
  }
296
+ #login-overlay.hidden { opacity: 0; visibility: hidden; pointer-events: none; }
297
+
298
+ .login-box {
299
+ width: 90%; max-width: 350px; text-align: center;
300
+ padding: 40px; border: 1px solid var(--border); border-radius: 20px; background: #0a0a0a;
301
+ transform: translateY(0); transition: transform 0.3s;
302
  }
303
+
304
+ #image-modal { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.9); z-index: 3000; display: none; align-items: center; justify-content: center; opacity: 0; transition: opacity 0.3s; }
305
+ #image-modal img { max-width: 95%; max-height: 90%; border-radius: 8px; box-shadow: 0 0 20px rgba(0,0,0,0.8); }
306
  #image-modal.active { opacity: 1; }
307
  </style>
308
  </head>
 
321
  </div>
322
 
323
  <div id="sidebar">
324
+ <div style="display:flex; justify-content:space-between; align-items:center; margin-bottom:20px; flex-shrink:0;">
325
  <div class="user-info"><span id="display-name">User</span></div>
326
  <div class="menu-btn" onclick="toggleSidebar()"><i class="fas fa-times"></i></div>
327
  </div>
 
373
  return `<div class="msg ai-msg"><div class="ai-content"><h1>Hi ${name},</h1><p>Ready to master your studies today?</p></div></div>`;
374
  }
375
 
376
+ // --- AUTH LOGIC (SMOOTH TRANSITION) ---
377
  function checkLogin() {
378
  try {
379
  const stored = localStorage.getItem("student_ai_user");
380
+ if (stored) {
381
+ currentUser = stored;
382
+ document.getElementById("login-overlay").classList.add('hidden');
383
+ showApp();
384
+ }
385
  } catch(e) { console.log("Storage access denied"); }
386
  }
387
+
388
  function handleLogin() {
389
  const input = document.getElementById("username-input");
390
  const name = input.value.trim();
391
  if(name) {
392
  try { localStorage.setItem("student_ai_user", name); } catch(e){}
393
  currentUser = name;
394
+ document.getElementById("login-overlay").classList.add('hidden');
395
  showApp();
396
  } else {
397
  input.style.border = "1px solid red";
398
  setTimeout(() => input.style.border = "1px solid #333", 2000);
399
  }
400
  }
401
+
402
+ function handleLogout() {
403
+ try { localStorage.removeItem("student_ai_user"); } catch(e){}
404
+ const overlay = document.getElementById("login-overlay");
405
+ overlay.classList.remove('hidden'); // Fade in
406
+ document.getElementById('sidebar').classList.remove('open');
407
+ setTimeout(() => {
408
+ document.getElementById('chat-box').innerHTML = "";
409
+ currentChatId = null;
410
+ document.getElementById("username-input").value = "";
411
+ }, 500);
412
+ }
413
 
414
  function showApp() {
 
415
  document.getElementById("display-name").innerText = "Hi " + currentUser;
416
  loadHistory();
417
  if(!currentChatId) {