import gradio as gr import os from pathlib import Path def load_css(): """Load CSS content for the application""" return """ /* Main wrapper styling */ #main-wrapper { min-height: 100vh; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); position: relative; } /* Header row styling */ #header-row { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); border-bottom: 1px solid rgba(255, 255, 255, 0.2); padding: 1rem; border-radius: 0 0 15px 15px; margin-bottom: 2rem; } /* Theme column styling */ #theme-col { background: rgba(255, 255, 255, 0.05); } /* Info box styling */ .info-box { background: rgba(255, 255, 255, 0.1); backdrop-filter: blur(10px); padding: 0.75rem; border-radius: 12px; border: 1px solid rgba(255, 255, 255, 0.2); margin-bottom: 1rem; } .info-box.success { border-left: 4px solid #38a169; } .info-box.warning { border-left: 4px solid #d69e2e; } .info-box.info { border-left: 4px solid #4299e1; } .info-box-content { padding: 1rem; } """ def chat_wrapper(message, chat_history, first_time): """Wrapper function for chat interactions""" if not message: return message, chat_history, first_time # Add user message chat_history.append({"role": "user", "content": message}) # Simulate Steve's response steve_response = f"Ah, {message}! Das klingt nach einem guten Projekt!" # Add assistant message chat_history.append({"role": "assistant", "content": steve_response}) # If this is the first question, hide the info boxes if first_time: first_time = False return "", chat_history, first_time def show_intro_info(first_time): """Show introductory information boxes if first time""" return first_time def update_intro_visibility(first_time): """Update the visibility of the intro boxes based on first_time state""" return gr.update(visible=first_time) def main(): css_content = load_css() custom_theme = gr.themes.Soft( primary_hue="blue", secondary_hue="indigo", neutral_hue="slate", font=gr.themes.GoogleFont("Inter"), text_size="lg", spacing_size="lg", radius_size="md" ).set( button_primary_background_fill="*primary_600", button_primary_background_fill_hover="*primary_700", block_title_text_weight="600", button_primary_text_color="white" ) # JavaScript commands for theme switching js_set_default = """ function(x) { document.documentElement.setAttribute('data-theme', 'default'); return x; """ js_set_night = """ function(x) { document.documentElement.setAttribute('data-theme', 'night'); return x; """ js_set_forest = """ function(x) { document.documentElement.setAttribute('data-theme', 'forest'); return x; """ with gr.Blocks() as demo: # State variables menu_visible = gr.State(False) first_time = gr.State(True) with gr.Column(elem_id="main-wrapper"): with gr.Row(elem_id="header-row"): with gr.Column(scale=1, min_width=150, elem_id="theme-col"): theme_btn = gr.Button("Themes", elem_id="theme-btn") with gr.Group(visible=False, elem_id="theme-menu-group") as theme_menu: btn_default = gr.Button("Tag", size="sm", elem_classes=["menu-btn"]) btn_night = gr.Button("Nacht", size="sm", elem_classes=["menu-btn"]) btn_forest = gr.Button("Wald", size="sm", elem_classes=["menu-btn"]) with gr.Column(scale=4): pass with gr.Column(scale=1, min_width=80, elem_id="crafting-col"): gr.Image( value="./chatbot/assets/crafting_table.png", elem_id="crafting-table", show_label=False, show_download_button=False, container=False, interactive=False ) # Chat Area chatbot = gr.Chatbot( value=[], type="messages", elem_id="minecraft-chat", show_label=False, bubble_full_width=False, ) # Introductory Information Boxes (Visible only on first load) with gr.Column(visible=True) as intro_boxes: with gr.Group(elem_classes=["info-box", "success"]): gr.Markdown(""" # 🎮 Willkommen beim Minecraft-Chatbot! ### ℹ️ Wichtige Informationen: - **Steve** ist hier, um dir zu helfen! - Du kannst über alles fragen - Crafting, Bauen, oder Abenteuer """, elem_classes=["info-box-content"] ) with gr.Group(elem_classes=["info-box", "warning"]): gr.Markdown(""" **⚠️ Achtung:** Diese Info-Boxen verschwinden nach deiner ersten Frage! """, elem_classes=["info-box-content"] ) with gr.Group(elem_classes=["info-box", "info"]): gr.Markdown(""" 💡 **Tipp:** Frag mich nach: - Crafting-Rezepten - Bau-Ideen - Minecraft-Tipps """, elem_classes=["info-box-content"] ) with gr.Group(elem_id="footer-area"): with gr.Row(elem_id="input-row"): msg_box = gr.Textbox( placeholder="Was möchtest du craften?", show_label=False, container=False, elem_id="minecraft-input", autofocus=True, scale=1 ) send_btn = gr.Button("Senden", elem_id="minecraft-send-btn", scale=0) # --- EVENT LOGIK FOR THE MENU --- # 1. Menu open/close def toggle_menu(is_visible): return not is_visible, gr.update(visible=not is_visible) theme_btn.click( fn=toggle_menu, inputs=[menu_visible], outputs=[menu_visible, theme_menu], api_visibility="public" ) # 2. Theme Buttons: Execute JS AND close the menu btn_default.click( fn=None, inputs=None, outputs=[menu_visible, theme_menu], js=js_set_default, api_visibility="public" ).then( fn=lambda: (False, gr.update(visible=False)), outputs=[menu_visible, theme_menu], api_visibility="public" ) btn_night.click( fn=None, inputs=None, outputs=[menu_visible, theme_menu], api_visibility="public" ).then( fn=lambda: (False, gr.update(visible=False)), outputs=[menu_visible, theme_menu], api_visibility="public" ) btn_forest.click( fn=None, inputs=None, outputs=[menu_visible, theme_menu], api_visibility="public" ) # --- CHAT EVENTS --- msg_box.submit( chat_wrapper, inputs=[msg_box, chatbot, first_time], outputs=[msg_box, chatbot, first_time], api_visibility="public" ) send_btn.click( chat_wrapper, inputs=[msg_box, chatbot, first_time], outputs=[msg_box, chatbot, first_time], api_visibility="public" ) # Hide intro boxes when first_time becomes False first_time.change( fn=update_intro_visibility, inputs=[first_time], outputs=[intro_boxes], api_visibility="public" ) demo.launch( inbrowser=True, allowed_paths=["./chatbot/assets"], theme=custom_theme, css=css_content, footer_links=[{"label": "Built with anycoder", "url": "https://huggingface.co/spaces/akhaliq/anycoder"}] ) if __name__ == "__main__": main()