floodd commited on
Commit
2aeb5a1
Β·
verified Β·
1 Parent(s): a9ac993

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +22 -39
app.py CHANGED
@@ -98,7 +98,7 @@ HEAD_HTML = """
98
  .gradio-tabs > div[role="tablist"] > button:hover { background-color: var(--content-background-color) !important; color: var(--primary-color) !important; }
99
  .gradio-tabs > div[role="tablist"] > button.selected { color: var(--primary-color) !important; border-bottom: 3px solid var(--primary-color) !important; background-color: var(--content-background-color) !important; }
100
  .tabitem { background-color: transparent !important; border: none !important; padding: 0 !important; }
101
- .gradio-row.panel, .gradio-accordion { background-color: var(--content-background-color) !important; border: 1px solid var(--border-color) !important; border-radius: var(--border-radius) !important; padding: 24px !important; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
102
  .gradio-accordion { margin-top: 1rem; }
103
  .gradio-button.primary { background: linear-gradient(90deg, var(--primary-color), #00c6ff) !important; color: #ffffff !important; font-weight: 600 !important; font-size: 1.1em !important; border-radius: 8px !important; border: none !important; padding: 12px 24px !important; transition: all 0.3s ease; box-shadow: var(--shadow-light); }
104
  .gradio-button.primary:hover { transform: translateY(-2px); box-shadow: var(--shadow-strong); }
@@ -122,6 +122,7 @@ HEAD_HTML = """
122
  #chatbot-display .message { border-radius: 18px !important; padding: 12px 18px !important; box-shadow: none !important; max-width: 80%; }
123
  #chatbot-display .user { background-color: var(--primary-color) !important; color: white !important; align-self: flex-end; border-bottom-right-radius: 5px !important; }
124
  #chatbot-display .bot { background-color: var(--content-background-color) !important; border: 1px solid var(--border-color) !important; align-self: flex-start; border-bottom-left-radius: 5px !important; }
 
125
  #chat-history-sidebar .gradio-radio > div { display: flex; flex-direction: column; gap: 8px; }
126
  #chat-history-sidebar .gradio-radio label { width: 100%; text-align: left; padding: 10px; border: 1px solid var(--border-color); border-radius: 8px; transition: all 0.2s ease; }
127
  #chat-history-sidebar .gradio-radio input:checked + label { border-color: var(--primary-color); background-color: rgba(0, 170, 255, 0.1); color: var(--primary-color); font-weight: 600; }
@@ -182,7 +183,7 @@ if Swin2SRForImageSuperResolution:
182
  upscaler_processor = Swin2SRImageProcessor.from_pretrained("caidas/swin2sr-realworld-sr-x4-64-bsrgan-psnr")
183
  print("βœ… Model AI Upscaler berhasil dimuat.")
184
  except Exception as e:
185
- print(f"❌ Gagal memuat model Upscaler: {e}. Fitur upscale akan dinonaktifkan.")
186
 
187
  # --- KELAS UNTUK CHATBOT GEMINI ---
188
 
@@ -215,13 +216,15 @@ class GeminiChat:
215
  genai.configure(api_key=selected_key)
216
  model = genai.GenerativeModel('gemini-2.5-flash')
217
 
218
- # Membangun konteks dari riwayat untuk API
219
- chat_session = model.start_chat(
220
- history=[{"role": "user" if i % 2 == 0 else "model", "parts": [msg]} for i, (user_msg, model_msg) in enumerate(history) for msg in ([user_msg] if user_msg else []) + ([model_msg] if model_msg else [])]
221
- )
 
 
222
 
223
  full_prompt = message
224
- if system_prompt and not history: # Terapkan system prompt hanya di awal
225
  full_prompt = f"{system_prompt}\n\nUser query: {message}"
226
 
227
  response = chat_session.send_message(full_prompt)
@@ -296,7 +299,7 @@ def update_visitor_monitor(time_filter: str):
296
  column_names = ["Timestamp", "IP Address", "User Agent"]
297
  df = pd.read_csv(VISITOR_LOG_FILE, header=None, names=column_names)
298
 
299
- if df.iloc[0]['Timestamp'] == 'Timestamp':
300
  df = df.iloc[1:].reset_index(drop=True)
301
 
302
  if df.empty: return "## πŸ“ˆ 0", pd.DataFrame({"Timestamp": [], "Total Pengunjung": []})
@@ -511,17 +514,14 @@ def handle_user_message(user_message, chat_id, all_chats_history):
511
  if not chat_id or chat_id not in all_chats_history:
512
  all_chats_history, chat_id, current_history, _ = add_new_chat({})
513
 
514
- # Tambah pesan pengguna ke riwayat
515
  current_history = all_chats_history[chat_id]['history']
516
 
517
- # Hapus pesan sambutan awal jika ini pesan pertama
518
  if len(current_history) == 1 and current_history[0][0] is None:
519
  current_history = []
520
 
521
  current_history.append((user_message, None))
522
  all_chats_history[chat_id]['history'] = current_history
523
 
524
- # Update judul jika ini pesan pertama
525
  if len(current_history) == 1:
526
  new_title = user_message[:30] + '...' if len(user_message) > 30 else user_message
527
  all_chats_history[chat_id]['title'] = new_title
@@ -530,8 +530,7 @@ def handle_user_message(user_message, chat_id, all_chats_history):
530
 
531
  yield all_chats_history, current_history, gr.update(choices=history_titles, value=all_chats_history[chat_id]['title']), gr.update(value=""), gr.update(visible=False)
532
 
533
- # Dapatkan respons dari bot
534
- bot_response = gemini_bot.chat(user_message, current_history)
535
  current_history[-1] = (user_message, bot_response)
536
  all_chats_history[chat_id]['history'] = current_history
537
 
@@ -540,7 +539,6 @@ def handle_user_message(user_message, chat_id, all_chats_history):
540
  def switch_chat(selected_title, all_chats_history):
541
  if not selected_title: return None, [], gr.update(visible=False)
542
 
543
- # Cari ID berdasarkan judul
544
  selected_id = None
545
  for chat_id, info in all_chats_history.items():
546
  if info['title'] == selected_title:
@@ -558,7 +556,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
558
  gr.Markdown("# πŸš€ RenXploit's Creative AI Suite 🌌", elem_id="main-title")
559
  gr.Markdown("Sebuah platform lengkap untuk kreativitas Anda, ditenagai oleh AI.", elem_id="main-subtitle")
560
 
561
- # State untuk menyimpan semua data sesi
562
  chat_history_state = gr.State({})
563
  current_chat_id_state = gr.State(None)
564
 
@@ -589,8 +586,10 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
589
  with gr.Column(scale=1, min_width=250) as sidebar:
590
  gr.Markdown("### πŸ—‚οΈ Riwayat Chat")
591
  new_chat_btn = gr.Button("βž• Obrolan Baru", variant="primary")
592
- with gr.Box(elem_id="chat-history-sidebar"):
 
593
  chat_history_list = gr.Radio(label="Pilih Obrolan", choices=[], interactive=True)
 
594
  with gr.Row(visible=False) as chat_action_buttons:
595
  share_chat_btn = gr.Button("πŸ”— Bagikan Chat")
596
  share_chat_output = gr.Textbox(label="Salin Konten Chat", lines=10, interactive=True, show_copy_button=True, visible=False)
@@ -606,7 +605,7 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
606
  user_chat_input = gr.Textbox(show_label=False, placeholder="Ketik pesan Anda di sini...", scale=5)
607
  send_chat_btn = gr.Button("Kirim", variant="secondary", scale=1)
608
 
609
- # --- TAB 3: PROMPT ENHANCER ---
610
  with gr.TabItem("✨ Prompt Enhancer", id=2):
611
  with gr.Row(variant='panel'):
612
  with gr.Column():
@@ -616,7 +615,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
616
  enhanced_prompt_output = gr.Textbox(label="Prompt yang Disempurnakan", lines=5, interactive=True, show_copy_button=True)
617
  send_to_gen_btn = gr.Button("➑️ Kirim & Pindah ke Generator")
618
 
619
- # --- TAB 4: AI IMAGE UPSCALER ---
620
  with gr.TabItem("πŸš€ AI Image Upscaler", id=3):
621
  with gr.Row(variant='panel', equal_height=False):
622
  with gr.Column():
@@ -629,7 +627,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
629
  upscaled_image_output = gr.Image(label="Gambar Hasil Upscale", interactive=False, show_download_button=True)
630
  upscale_status_text = gr.Markdown("Status: Menunggu gambar...")
631
 
632
- # --- TAB 5 (BARU): GALERI & RIWAYAT (dengan Share) ---
633
  with gr.TabItem("πŸ–ΌοΈ Galeri & Riwayat", id=4) as history_tab:
634
  with gr.Row(variant='panel'):
635
  with gr.Column(scale=2):
@@ -646,7 +643,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
646
  share_history_btn = gr.Button("πŸ”— Bagikan Detail")
647
  share_history_output = gr.Textbox(label="URL & Detail untuk Dibagikan", lines=8, interactive=True, show_copy_button=True, visible=False)
648
 
649
- # --- TAB 6 (BARU): IMAGE EDITOR ---
650
  with gr.TabItem("οΏ½οΏ½οΏ½ Image Editor", id=5):
651
  with gr.Row(variant='panel'):
652
  with gr.Column(scale=1):
@@ -663,7 +659,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
663
  gr.Markdown("### **Hasil Editing**")
664
  editor_output_image = gr.Image(label="Hasil Akhir", interactive=False, show_download_button=True)
665
 
666
- # --- TAB 7: VISITOR MONITOR ---
667
  with gr.TabItem("πŸ“Š Visitor Monitor", id=6):
668
  with gr.Row(variant='panel'):
669
  with gr.Column():
@@ -675,7 +670,6 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
675
  refresh_btn = gr.Button("πŸ”„ Segarkan Manual", variant="secondary")
676
  visitor_plot = gr.LinePlot(x="Timestamp", y="Total Pengunjung", title="Grafik Pertumbuhan Pengunjung", tooltip=['Timestamp', 'Total Pengunjung'], height=500, interactive=True)
677
 
678
- # --- TAB 8: SYSTEM & SETTINGS ---
679
  with gr.TabItem("βš™οΈ System & Settings", id=7):
680
  with gr.Row(variant='panel'):
681
  with gr.Column():
@@ -689,14 +683,13 @@ with gr.Blocks(theme=gr.themes.Base(), head=HEAD_HTML) as demo:
689
  value="FP16 (Cepat, Kualitas Baik)" if device == "cuda" else "FP32 (Lambat, Kualitas Terbaik)",
690
  label="Presisi Model Generator", interactive=False, info="Terkunci. Ditentukan saat aplikasi dimulai.")
691
 
692
- # --- TAB-TAB STATIS ---
693
  with gr.TabItem("πŸ’‘ Panduan Prompting", id=8):
694
  with gr.Row(variant='panel'): gr.Markdown("""## Cara Menjadi "Art Director" yang Hebat untuk AI...\n (Konten panduan Anda di sini)""")
695
  with gr.TabItem("πŸ“– Blog & Updates", id=9):
696
  with gr.Row(variant='panel'): gr.Markdown("""### Perkembangan Terbaru dari RenXploit's AI Suite
697
- v2.7 (Pembaruan Terkini): Perombakan total UI Chatbot menjadi lebih profesional dengan fitur riwayat percakapan, new chat, dan share chat. Menambahkan fitur share detail gambar dari galeri.
698
- v2.6: Perbaikan final untuk bug KeyError: 'Timestamp' pada Visitor Monitor, membuatnya lebih tahan banting.
699
- v2.5: Menambahkan Galeri & Riwayat Generasi dan Image Editor untuk pasca-produksi.
700
  Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpainting/Outpainting.""")
701
  with gr.TabItem("ℹ️ About & Support", id=10):
702
  with gr.Row(variant='panel'):
@@ -704,15 +697,13 @@ Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpa
704
  gr.Markdown("### Tentang Proyek dan Dukungan")
705
  with gr.Accordion("Tentang RenXploit's Creative AI Suite", open=True):
706
  gr.Markdown("""
707
- RenXploit's Creative AI Suite adalah proyek pribadi yang dibuat untuk mengeksplorasi kemampuan AI generatif dalam sebuah antarmuka yang mudah digunakan dan profesional.
708
- Aplikasi ini terus dikembangkan dengan fitur-fitur baru untuk memberdayakan kreativitas Anda.
709
-
710
- Jika Anda memiliki masukan, menemukan bug, atau ingin berdiskusi, jangan ragu untuk menghubungi saya melalui website portofolio di: ngoprek.xyz/contact
711
  """)
712
  with gr.Accordion("Laporkan Masalah atau Beri Masukan"):
713
  report_name = gr.Textbox(label="Nama Anda")
714
  report_email = gr.Textbox(label="Email Anda (Opsional)")
715
- report_message = gr.Textbox(label="Pesan Anda", lines=5, placeholder="Jelaskan masalah yang Anda temui atau ide yang Anda miliki...")
716
  report_btn = gr.Button("Kirim Laporan", variant="primary")
717
  report_status = gr.Markdown(visible=False)
718
 
@@ -720,15 +711,12 @@ Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpa
720
 
721
  # --- PENANGANAN EVENT (EVENT HANDLERS) ---
722
 
723
- # 0. Event Utama App
724
  demo.load(log_visitor, inputs=None, outputs=None)
725
  demo.load(fn=add_new_chat, inputs=[chat_history_state], outputs=[chat_history_state, current_chat_id_state, chatbot_display, chat_history_list])
726
 
727
- # 1. Event Image Generator
728
  random_seed_btn.click(lambda: -1, outputs=seed_input)
729
  generate_btn.click(fn=genie_wrapper, inputs=[prompt_input, negative_prompt_input, steps_slider, seed_input, num_images_slider], outputs=[output_gallery, loader_html, generate_btn, info_box])
730
 
731
- # 2. Event Chatbot (UPGRADED)
732
  new_chat_btn.click(fn=add_new_chat, inputs=[chat_history_state], outputs=[chat_history_state, current_chat_id_state, chatbot_display, chat_history_list])
733
 
734
  send_chat_btn.click(
@@ -752,12 +740,10 @@ Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpa
752
  outputs=[share_chat_output]
753
  )
754
 
755
- # 3. Event Fitur Lainnya
756
  enhance_btn.click(fn=enhance_prompt, inputs=[simple_prompt_input], outputs=[enhanced_prompt_output])
757
  send_to_gen_btn.click(fn=lambda prompt: (prompt, gr.Tabs(selected=0)), inputs=[enhanced_prompt_output], outputs=[prompt_input, tabs])
758
  upscale_btn.click(fn=upscale_image, inputs=[image_to_upscale_input, clarity_slider], outputs=[upscaled_image_output, upscale_status_text])
759
 
760
- # 4. Event untuk Galeri, Editor & Share
761
  history_tab.select(fn=load_history, inputs=None, outputs=[history_gallery, history_df_state, history_details_md])
762
  refresh_history_btn.click(fn=load_history, inputs=None, outputs=[history_gallery, history_df_state, history_details_md])
763
  history_gallery.select(fn=show_history_details, inputs=[history_df_state], outputs=[history_details_md, history_action_buttons, share_history_output])
@@ -771,7 +757,6 @@ Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpa
771
  filter_radio.change(fn=apply_image_edits, inputs=editor_inputs, outputs=editor_output_image)
772
  editor_input_image.change(fn=apply_image_edits, inputs=editor_inputs, outputs=editor_output_image)
773
 
774
- # 5. Event Monitor
775
  demo.load(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
776
  refresh_btn.click(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
777
  time_filter_radio.change(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
@@ -779,10 +764,8 @@ Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpa
779
  system_info_trigger_btn.click(fn=update_system_info, inputs=None, outputs=system_info_md)
780
  demo.load(fn=update_system_info, inputs=None, outputs=system_info_md)
781
 
782
- # 6. Event Support
783
  report_btn.click(fn=submit_report, inputs=[report_name, report_email, report_message], outputs=[report_status])
784
 
785
-
786
  # --- Menjalankan Aplikasi ---
787
 
788
  if __name__ == "__main__":
 
98
  .gradio-tabs > div[role="tablist"] > button:hover { background-color: var(--content-background-color) !important; color: var(--primary-color) !important; }
99
  .gradio-tabs > div[role="tablist"] > button.selected { color: var(--primary-color) !important; border-bottom: 3px solid var(--primary-color) !important; background-color: var(--content-background-color) !important; }
100
  .tabitem { background-color: transparent !important; border: none !important; padding: 0 !important; }
101
+ .gradio-row.panel, .gradio-accordion, .gradio-group { background-color: var(--content-background-color) !important; border: 1px solid var(--border-color) !important; border-radius: var(--border-radius) !important; padding: 24px !important; box-shadow: 0 4px 6px rgba(0,0,0,0.1); }
102
  .gradio-accordion { margin-top: 1rem; }
103
  .gradio-button.primary { background: linear-gradient(90deg, var(--primary-color), #00c6ff) !important; color: #ffffff !important; font-weight: 600 !important; font-size: 1.1em !important; border-radius: 8px !important; border: none !important; padding: 12px 24px !important; transition: all 0.3s ease; box-shadow: var(--shadow-light); }
104
  .gradio-button.primary:hover { transform: translateY(-2px); box-shadow: var(--shadow-strong); }
 
122
  #chatbot-display .message { border-radius: 18px !important; padding: 12px 18px !important; box-shadow: none !important; max-width: 80%; }
123
  #chatbot-display .user { background-color: var(--primary-color) !important; color: white !important; align-self: flex-end; border-bottom-right-radius: 5px !important; }
124
  #chatbot-display .bot { background-color: var(--content-background-color) !important; border: 1px solid var(--border-color) !important; align-self: flex-start; border-bottom-left-radius: 5px !important; }
125
+ #chat-history-sidebar { background-color: transparent !important; border: none !important; padding: 0 !important; box-shadow: none !important; } /* Styling for gr.Group */
126
  #chat-history-sidebar .gradio-radio > div { display: flex; flex-direction: column; gap: 8px; }
127
  #chat-history-sidebar .gradio-radio label { width: 100%; text-align: left; padding: 10px; border: 1px solid var(--border-color); border-radius: 8px; transition: all 0.2s ease; }
128
  #chat-history-sidebar .gradio-radio input:checked + label { border-color: var(--primary-color); background-color: rgba(0, 170, 255, 0.1); color: var(--primary-color); font-weight: 600; }
 
183
  upscaler_processor = Swin2SRImageProcessor.from_pretrained("caidas/swin2sr-realworld-sr-x4-64-bsrgan-psnr")
184
  print("βœ… Model AI Upscaler berhasil dimuat.")
185
  except Exception as e:
186
+ print(f"❌ Gagal memuat model Upscaler: {e}. Fitur upscale akan dinaktifkan.")
187
 
188
  # --- KELAS UNTUK CHATBOT GEMINI ---
189
 
 
216
  genai.configure(api_key=selected_key)
217
  model = genai.GenerativeModel('gemini-2.5-flash')
218
 
219
+ chat_history_for_api = []
220
+ for user_msg, model_msg in history:
221
+ if user_msg: chat_history_for_api.append({"role": "user", "parts": [user_msg]})
222
+ if model_msg: chat_history_for_api.append({"role": "model", "parts": [model_msg]})
223
+
224
+ chat_session = model.start_chat(history=chat_history_for_api)
225
 
226
  full_prompt = message
227
+ if system_prompt and not history:
228
  full_prompt = f"{system_prompt}\n\nUser query: {message}"
229
 
230
  response = chat_session.send_message(full_prompt)
 
299
  column_names = ["Timestamp", "IP Address", "User Agent"]
300
  df = pd.read_csv(VISITOR_LOG_FILE, header=None, names=column_names)
301
 
302
+ if not df.empty and df.iloc[0]['Timestamp'] == 'Timestamp':
303
  df = df.iloc[1:].reset_index(drop=True)
304
 
305
  if df.empty: return "## πŸ“ˆ 0", pd.DataFrame({"Timestamp": [], "Total Pengunjung": []})
 
514
  if not chat_id or chat_id not in all_chats_history:
515
  all_chats_history, chat_id, current_history, _ = add_new_chat({})
516
 
 
517
  current_history = all_chats_history[chat_id]['history']
518
 
 
519
  if len(current_history) == 1 and current_history[0][0] is None:
520
  current_history = []
521
 
522
  current_history.append((user_message, None))
523
  all_chats_history[chat_id]['history'] = current_history
524
 
 
525
  if len(current_history) == 1:
526
  new_title = user_message[:30] + '...' if len(user_message) > 30 else user_message
527
  all_chats_history[chat_id]['title'] = new_title
 
530
 
531
  yield all_chats_history, current_history, gr.update(choices=history_titles, value=all_chats_history[chat_id]['title']), gr.update(value=""), gr.update(visible=False)
532
 
533
+ bot_response = gemini_bot.chat(user_message, [h for h in current_history if h[0] is not None])
 
534
  current_history[-1] = (user_message, bot_response)
535
  all_chats_history[chat_id]['history'] = current_history
536
 
 
539
  def switch_chat(selected_title, all_chats_history):
540
  if not selected_title: return None, [], gr.update(visible=False)
541
 
 
542
  selected_id = None
543
  for chat_id, info in all_chats_history.items():
544
  if info['title'] == selected_title:
 
556
  gr.Markdown("# πŸš€ RenXploit's Creative AI Suite 🌌", elem_id="main-title")
557
  gr.Markdown("Sebuah platform lengkap untuk kreativitas Anda, ditenagai oleh AI.", elem_id="main-subtitle")
558
 
 
559
  chat_history_state = gr.State({})
560
  current_chat_id_state = gr.State(None)
561
 
 
586
  with gr.Column(scale=1, min_width=250) as sidebar:
587
  gr.Markdown("### πŸ—‚οΈ Riwayat Chat")
588
  new_chat_btn = gr.Button("βž• Obrolan Baru", variant="primary")
589
+ # === PERBAIKAN DI SINI: MENGGUNAKAN gr.Group BUKAN gr.Box ===
590
+ with gr.Group(elem_id="chat-history-sidebar"):
591
  chat_history_list = gr.Radio(label="Pilih Obrolan", choices=[], interactive=True)
592
+ # ==========================================================
593
  with gr.Row(visible=False) as chat_action_buttons:
594
  share_chat_btn = gr.Button("πŸ”— Bagikan Chat")
595
  share_chat_output = gr.Textbox(label="Salin Konten Chat", lines=10, interactive=True, show_copy_button=True, visible=False)
 
605
  user_chat_input = gr.Textbox(show_label=False, placeholder="Ketik pesan Anda di sini...", scale=5)
606
  send_chat_btn = gr.Button("Kirim", variant="secondary", scale=1)
607
 
608
+ # --- TAB-TAB LAINNYA (TETAP SAMA) ---
609
  with gr.TabItem("✨ Prompt Enhancer", id=2):
610
  with gr.Row(variant='panel'):
611
  with gr.Column():
 
615
  enhanced_prompt_output = gr.Textbox(label="Prompt yang Disempurnakan", lines=5, interactive=True, show_copy_button=True)
616
  send_to_gen_btn = gr.Button("➑️ Kirim & Pindah ke Generator")
617
 
 
618
  with gr.TabItem("πŸš€ AI Image Upscaler", id=3):
619
  with gr.Row(variant='panel', equal_height=False):
620
  with gr.Column():
 
627
  upscaled_image_output = gr.Image(label="Gambar Hasil Upscale", interactive=False, show_download_button=True)
628
  upscale_status_text = gr.Markdown("Status: Menunggu gambar...")
629
 
 
630
  with gr.TabItem("πŸ–ΌοΈ Galeri & Riwayat", id=4) as history_tab:
631
  with gr.Row(variant='panel'):
632
  with gr.Column(scale=2):
 
643
  share_history_btn = gr.Button("πŸ”— Bagikan Detail")
644
  share_history_output = gr.Textbox(label="URL & Detail untuk Dibagikan", lines=8, interactive=True, show_copy_button=True, visible=False)
645
 
 
646
  with gr.TabItem("οΏ½οΏ½οΏ½ Image Editor", id=5):
647
  with gr.Row(variant='panel'):
648
  with gr.Column(scale=1):
 
659
  gr.Markdown("### **Hasil Editing**")
660
  editor_output_image = gr.Image(label="Hasil Akhir", interactive=False, show_download_button=True)
661
 
 
662
  with gr.TabItem("πŸ“Š Visitor Monitor", id=6):
663
  with gr.Row(variant='panel'):
664
  with gr.Column():
 
670
  refresh_btn = gr.Button("πŸ”„ Segarkan Manual", variant="secondary")
671
  visitor_plot = gr.LinePlot(x="Timestamp", y="Total Pengunjung", title="Grafik Pertumbuhan Pengunjung", tooltip=['Timestamp', 'Total Pengunjung'], height=500, interactive=True)
672
 
 
673
  with gr.TabItem("βš™οΈ System & Settings", id=7):
674
  with gr.Row(variant='panel'):
675
  with gr.Column():
 
683
  value="FP16 (Cepat, Kualitas Baik)" if device == "cuda" else "FP32 (Lambat, Kualitas Terbaik)",
684
  label="Presisi Model Generator", interactive=False, info="Terkunci. Ditentukan saat aplikasi dimulai.")
685
 
 
686
  with gr.TabItem("πŸ’‘ Panduan Prompting", id=8):
687
  with gr.Row(variant='panel'): gr.Markdown("""## Cara Menjadi "Art Director" yang Hebat untuk AI...\n (Konten panduan Anda di sini)""")
688
  with gr.TabItem("πŸ“– Blog & Updates", id=9):
689
  with gr.Row(variant='panel'): gr.Markdown("""### Perkembangan Terbaru dari RenXploit's AI Suite
690
+ v2.8 (Perbaikan): Mengganti komponen `gr.Box` dengan `gr.Group` untuk kompatibilitas dengan versi Gradio yang lebih lama.
691
+ v2.7: Perombakan total UI Chatbot menjadi lebih profesional dengan fitur riwayat percakapan, new chat, dan share chat. Menambahkan fitur share detail gambar dari galeri.
692
+ v2.6: Perbaikan final untuk bug KeyError: 'Timestamp' pada Visitor Monitor.
693
  Rencana Berikutnya: Menjajaki model generator gambar yang berbeda dan fitur Inpainting/Outpainting.""")
694
  with gr.TabItem("ℹ️ About & Support", id=10):
695
  with gr.Row(variant='panel'):
 
697
  gr.Markdown("### Tentang Proyek dan Dukungan")
698
  with gr.Accordion("Tentang RenXploit's Creative AI Suite", open=True):
699
  gr.Markdown("""
700
+ RenXploit's Creative AI Suite adalah proyek pribadi untuk mengeksplorasi AI generatif.
701
+ Hubungi saya melalui: ngoprek.xyz/contact
 
 
702
  """)
703
  with gr.Accordion("Laporkan Masalah atau Beri Masukan"):
704
  report_name = gr.Textbox(label="Nama Anda")
705
  report_email = gr.Textbox(label="Email Anda (Opsional)")
706
+ report_message = gr.Textbox(label="Pesan Anda", lines=5, placeholder="Jelaskan masalah atau ide Anda...")
707
  report_btn = gr.Button("Kirim Laporan", variant="primary")
708
  report_status = gr.Markdown(visible=False)
709
 
 
711
 
712
  # --- PENANGANAN EVENT (EVENT HANDLERS) ---
713
 
 
714
  demo.load(log_visitor, inputs=None, outputs=None)
715
  demo.load(fn=add_new_chat, inputs=[chat_history_state], outputs=[chat_history_state, current_chat_id_state, chatbot_display, chat_history_list])
716
 
 
717
  random_seed_btn.click(lambda: -1, outputs=seed_input)
718
  generate_btn.click(fn=genie_wrapper, inputs=[prompt_input, negative_prompt_input, steps_slider, seed_input, num_images_slider], outputs=[output_gallery, loader_html, generate_btn, info_box])
719
 
 
720
  new_chat_btn.click(fn=add_new_chat, inputs=[chat_history_state], outputs=[chat_history_state, current_chat_id_state, chatbot_display, chat_history_list])
721
 
722
  send_chat_btn.click(
 
740
  outputs=[share_chat_output]
741
  )
742
 
 
743
  enhance_btn.click(fn=enhance_prompt, inputs=[simple_prompt_input], outputs=[enhanced_prompt_output])
744
  send_to_gen_btn.click(fn=lambda prompt: (prompt, gr.Tabs(selected=0)), inputs=[enhanced_prompt_output], outputs=[prompt_input, tabs])
745
  upscale_btn.click(fn=upscale_image, inputs=[image_to_upscale_input, clarity_slider], outputs=[upscaled_image_output, upscale_status_text])
746
 
 
747
  history_tab.select(fn=load_history, inputs=None, outputs=[history_gallery, history_df_state, history_details_md])
748
  refresh_history_btn.click(fn=load_history, inputs=None, outputs=[history_gallery, history_df_state, history_details_md])
749
  history_gallery.select(fn=show_history_details, inputs=[history_df_state], outputs=[history_details_md, history_action_buttons, share_history_output])
 
757
  filter_radio.change(fn=apply_image_edits, inputs=editor_inputs, outputs=editor_output_image)
758
  editor_input_image.change(fn=apply_image_edits, inputs=editor_inputs, outputs=editor_output_image)
759
 
 
760
  demo.load(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
761
  refresh_btn.click(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
762
  time_filter_radio.change(fn=update_visitor_monitor, inputs=[time_filter_radio], outputs=[visitor_count_display, visitor_plot])
 
764
  system_info_trigger_btn.click(fn=update_system_info, inputs=None, outputs=system_info_md)
765
  demo.load(fn=update_system_info, inputs=None, outputs=system_info_md)
766
 
 
767
  report_btn.click(fn=submit_report, inputs=[report_name, report_email, report_message], outputs=[report_status])
768
 
 
769
  # --- Menjalankan Aplikasi ---
770
 
771
  if __name__ == "__main__":