Ricky01anjay commited on
Commit
90f933d
Β·
verified Β·
1 Parent(s): cdbaca4

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +78 -16
app.py CHANGED
@@ -246,7 +246,8 @@ def apply_tools_call(files: dict, ai_response: str) -> dict:
246
  raise ValueError(f"Tool tidak dikenal '{name}' pada blok ke-{i+1}. Gunakan write_file atau edit_file.")
247
 
248
  action_label = f"Diperbarui ({success_count} operasi){' ✨ Auto-Fix' if is_fuzzy else ''}"
249
- return {"files": temp_files, "message": respond_text, "action_label": action_label}
 
250
 
251
 
252
  # ─────────────────────────────────────────────
@@ -405,18 +406,44 @@ HTML = r"""<!DOCTYPE html>
405
  <div x-data="aiEditor()" class="w-full max-w-md h-full bg-white shadow-2xl relative flex flex-col">
406
 
407
  <!-- Header -->
408
- <header class="flex-shrink-0 bg-indigo-600 text-white p-4 flex justify-between items-center shadow-md z-10">
409
  <h1 class="text-lg font-bold flex items-center gap-2">
410
  <i class="fa-solid fa-wand-magic-sparkles"></i> AI Editor
411
  </h1>
412
- <div class="flex gap-2">
413
- <button @click="downloadCode" class="bg-indigo-500 hover:bg-indigo-400 p-2 rounded text-sm transition font-medium shadow">
414
- <i class="fa-solid fa-file-download"></i> Simpan
 
 
 
415
  </button>
416
- <label class="cursor-pointer bg-indigo-500 hover:bg-indigo-400 p-2 rounded text-sm transition font-medium shadow">
417
- <i class="fa-solid fa-file-upload"></i> Upload
418
- <input type="file" class="hidden" @change="uploadFile">
419
- </label>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
420
  </div>
421
  </header>
422
 
@@ -435,6 +462,17 @@ HTML = r"""<!DOCTYPE html>
435
  ? 'bg-indigo-600 text-white rounded-tr-none'
436
  : 'bg-white text-gray-800 border border-gray-200 rounded-tl-none'">
437
  <p class="whitespace-pre-wrap leading-relaxed" x-text="msg.content"></p>
 
 
 
 
 
 
 
 
 
 
 
438
  <template x-if="msg.action">
439
  <div class="mt-2 pt-2 border-t border-gray-100/30 flex items-center gap-1">
440
  <span class="text-[10px] px-2 py-0.5 rounded-full font-bold flex items-center gap-1 bg-emerald-100 text-emerald-700">
@@ -570,13 +608,13 @@ HTML = r"""<!DOCTYPE html>
570
 
571
  <!-- ═══ PREVIEW PAGE ═══ -->
572
  <div x-show="tab === 'preview'" class="h-full flex flex-col bg-white" x-transition.opacity style="display:none">
573
- <div class="flex-shrink-0 bg-gray-200 text-gray-700 text-xs px-4 py-2 flex justify-between items-center border-b border-gray-300">
574
- <span class="font-semibold flex items-center gap-2">
575
- <i class="fa-solid fa-eye text-indigo-500"></i> Hasil Render
576
- <span class="text-gray-400 font-normal">β€” debug via Eruda (pojok bawah)</span>
577
  </span>
578
- <button @click="updatePreview" class="hover:text-indigo-600 transition flex items-center gap-1">
579
- <i class="fa-solid fa-rotate-right"></i> Refresh
580
  </button>
581
  </div>
582
  <div class="flex-1 min-h-0 w-full relative">
@@ -622,6 +660,7 @@ HTML = r"""<!DOCTYPE html>
622
  document.addEventListener('alpine:init', () => {
623
  Alpine.data('aiEditor', () => ({
624
  tab: 'chat',
 
625
  files: {
626
  'index.html': `<!DOCTYPE html>\n<html>\n<head>\n <title>Halo Dunia</title>\n</head>\n<body>\n <h1>Halo Dunia!</h1>\n <button onclick="showAlert()">Klik Saya</button>\n <script>\n function showAlert() {\n alert('Halo!');\n }\n <\/script>\n</body>\n</html>`
627
  },
@@ -728,6 +767,28 @@ HTML = r"""<!DOCTYPE html>
728
  }
729
  },
730
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
731
  /* ─── Preview (Eruda only) ─── */
732
 
733
  updatePreview() {
@@ -806,6 +867,7 @@ HTML = r"""<!DOCTYPE html>
806
  role: 'ai',
807
  content: data.result.message,
808
  action: data.result.action_label,
 
809
  });
810
  } else {
811
  this.chatHistory.push({
@@ -835,4 +897,4 @@ def index():
835
 
836
 
837
  if __name__ == "__main__":
838
- app.run(host="0.0.0.0", port=7860)
 
246
  raise ValueError(f"Tool tidak dikenal '{name}' pada blok ke-{i+1}. Gunakan write_file atau edit_file.")
247
 
248
  action_label = f"Diperbarui ({success_count} operasi){' ✨ Auto-Fix' if is_fuzzy else ''}"
249
+ reasons = [t.get('reason', '') for t in tools if t.get('reason')]
250
+ return {"files": temp_files, "message": respond_text, "action_label": action_label, "reasons": reasons}
251
 
252
 
253
  # ─────────────────────────────────────────────
 
406
  <div x-data="aiEditor()" class="w-full max-w-md h-full bg-white shadow-2xl relative flex flex-col">
407
 
408
  <!-- Header -->
409
+ <header class="flex-shrink-0 bg-indigo-600 text-white px-4 py-3 flex justify-between items-center shadow-md z-10">
410
  <h1 class="text-lg font-bold flex items-center gap-2">
411
  <i class="fa-solid fa-wand-magic-sparkles"></i> AI Editor
412
  </h1>
413
+ <!-- Hamburger Menu -->
414
+ <div class="relative">
415
+ <button @click="showMenu = !showMenu"
416
+ class="bg-indigo-500 hover:bg-indigo-400 w-9 h-9 rounded flex items-center justify-center transition shadow"
417
+ :class="showMenu ? 'bg-indigo-400' : ''">
418
+ <i class="fa-solid fa-bars text-base"></i>
419
  </button>
420
+ <!-- Dropdown -->
421
+ <div x-show="showMenu"
422
+ @click.away="showMenu = false"
423
+ x-transition:enter="transition ease-out duration-100"
424
+ x-transition:enter-start="opacity-0 scale-95"
425
+ x-transition:enter-end="opacity-100 scale-100"
426
+ x-transition:leave="transition ease-in duration-75"
427
+ x-transition:leave-start="opacity-100 scale-100"
428
+ x-transition:leave-end="opacity-0 scale-95"
429
+ class="absolute right-0 top-full mt-2 w-44 bg-white rounded-xl shadow-2xl border border-gray-100 overflow-hidden z-50 text-gray-700"
430
+ style="display:none">
431
+ <button @click="downloadZip(); showMenu=false"
432
+ class="w-full text-left px-4 py-3 text-sm hover:bg-indigo-50 flex items-center gap-3 transition border-b border-gray-100">
433
+ <i class="fa-solid fa-file-zipper text-indigo-500 w-4"></i>
434
+ <span class="font-medium">Download ZIP</span>
435
+ </button>
436
+ <button @click="downloadCode(); showMenu=false"
437
+ class="w-full text-left px-4 py-3 text-sm hover:bg-indigo-50 flex items-center gap-3 transition border-b border-gray-100">
438
+ <i class="fa-solid fa-file-arrow-down text-emerald-500 w-4"></i>
439
+ <span class="font-medium">Simpan File</span>
440
+ </button>
441
+ <label class="w-full text-left px-4 py-3 text-sm hover:bg-indigo-50 flex items-center gap-3 transition cursor-pointer">
442
+ <i class="fa-solid fa-file-arrow-up text-orange-500 w-4"></i>
443
+ <span class="font-medium">Upload File</span>
444
+ <input type="file" class="hidden" @change="uploadFile($event); showMenu=false">
445
+ </label>
446
+ </div>
447
  </div>
448
  </header>
449
 
 
462
  ? 'bg-indigo-600 text-white rounded-tr-none'
463
  : 'bg-white text-gray-800 border border-gray-200 rounded-tl-none'">
464
  <p class="whitespace-pre-wrap leading-relaxed" x-text="msg.content"></p>
465
+ <!-- Reasons dari tool calls -->
466
+ <template x-if="msg.reasons && msg.reasons.length">
467
+ <div class="mt-2 space-y-1">
468
+ <template x-for="(r, ri) in msg.reasons" :key="ri">
469
+ <div class="text-xs bg-indigo-50 border border-indigo-100 rounded-lg px-2 py-1.5 text-indigo-700 flex items-start gap-1.5">
470
+ <i class="fa-solid fa-pencil text-indigo-400 mt-0.5 flex-shrink-0 text-[10px]"></i>
471
+ <span x-text="r" class="leading-snug"></span>
472
+ </div>
473
+ </template>
474
+ </div>
475
+ </template>
476
  <template x-if="msg.action">
477
  <div class="mt-2 pt-2 border-t border-gray-100/30 flex items-center gap-1">
478
  <span class="text-[10px] px-2 py-0.5 rounded-full font-bold flex items-center gap-1 bg-emerald-100 text-emerald-700">
 
608
 
609
  <!-- ═══ PREVIEW PAGE ═══ -->
610
  <div x-show="tab === 'preview'" class="h-full flex flex-col bg-white" x-transition.opacity style="display:none">
611
+ <div class="flex-shrink-0 bg-gray-100 text-gray-500 px-3 py-1.5 flex justify-between items-center border-b border-gray-200">
612
+ <span class="text-xs flex items-center gap-1.5">
613
+ <i class="fa-solid fa-bug text-indigo-400"></i>
614
+ <span class="text-gray-400">Eruda</span>
615
  </span>
616
+ <button @click="updatePreview" class="text-xs hover:text-indigo-600 transition flex items-center gap-1 px-2 py-1 rounded hover:bg-white">
617
+ <i class="fa-solid fa-rotate-right"></i>
618
  </button>
619
  </div>
620
  <div class="flex-1 min-h-0 w-full relative">
 
660
  document.addEventListener('alpine:init', () => {
661
  Alpine.data('aiEditor', () => ({
662
  tab: 'chat',
663
+ showMenu: false,
664
  files: {
665
  'index.html': `<!DOCTYPE html>\n<html>\n<head>\n <title>Halo Dunia</title>\n</head>\n<body>\n <h1>Halo Dunia!</h1>\n <button onclick="showAlert()">Klik Saya</button>\n <script>\n function showAlert() {\n alert('Halo!');\n }\n <\/script>\n</body>\n</html>`
666
  },
 
767
  }
768
  },
769
 
770
+ async downloadZip() {
771
+ try {
772
+ const JSZip = (await import('https://cdn.jsdelivr.net/npm/jszip@3.10.1/+esm')).default;
773
+ const zip = new JSZip();
774
+ for (const [fname, content] of Object.entries(this.files)) {
775
+ zip.file(fname, content);
776
+ }
777
+ const blob = await zip.generateAsync({ type: 'blob' });
778
+ const url = URL.createObjectURL(blob);
779
+ const a = document.createElement('a');
780
+ a.href = url;
781
+ a.download = 'project.zip';
782
+ document.body.appendChild(a);
783
+ a.click();
784
+ document.body.removeChild(a);
785
+ URL.revokeObjectURL(url);
786
+ this.showToast(`ZIP berhasil diunduh (${Object.keys(this.files).length} file)!`);
787
+ } catch (e) {
788
+ this.showToast('Gagal membuat ZIP.');
789
+ }
790
+ },
791
+
792
  /* ─── Preview (Eruda only) ─── */
793
 
794
  updatePreview() {
 
867
  role: 'ai',
868
  content: data.result.message,
869
  action: data.result.action_label,
870
+ reasons: data.result.reasons || [],
871
  });
872
  } else {
873
  this.chatHistory.push({
 
897
 
898
 
899
  if __name__ == "__main__":
900
+ app.run(host="0.0.0.0", port=7860)