# ./app.py """ The Interface Skeleton - The code sets up the navigation panel and the multimodal chat interface The .then() chain: Previously, the save happened "in the background." Now, handle_save explicitly returns the new load_history() results to the history_list component, causing it to "re-render" with the new chat visible. The chat_id_state: By passing this back and forth, the app knows if it should update an existing file in the HF Dataset or create a new one. history_list.click: This is the bridge that makes the sidebar interactive. Without this event, clicking the "Recent Conversations" wouldn't do anything. """ import gradio as gr from core_logic import chat_function from storage import save_chat, load_history, get_chat_content with gr.Blocks() as demo: # This state keeps track of the filename for the current session chat_id_state = gr.State("") with gr.Row(): # --- Sidebar --- with gr.Column(scale=1, variant="secondary"): gr.Markdown("### 🛠️ Silicon Architect") new_btn = gr.Button("➕ New Chat", variant="primary") # The sidebar component history_list = gr.Dataset( components=[gr.Textbox(visible=False)], label="Recent Conversations", samples=load_history(), type="values" # Ensures we get the string value when clicked ) # --- Main Chat --- with gr.Column(scale=4): chatbot = gr.Chatbot(show_label=False, height=700) chat_input = gr.MultimodalTextbox( interactive=True, placeholder="Discuss architecture or upload code...", show_label=False ) # --- LOGIC FUNCTIONS --- def bot_response(message, history, chat_id): user_content = message["text"] history.append({"role": "user", "content": user_content}) history.append({"role": "assistant", "content": ""}) for partial_resp in chat_function(message, history[:-1]): history[-1]["content"] = partial_resp yield history """ def handle_save(history, chat_id): # Saves the chat and returns the updated list for the sidebar new_id = save_chat(chat_id, history) return new_id, load_history() """ def handle_save(history, chat_id): # 1. Save the actual data new_id = save_chat(chat_id, history) # 2. Get the latest from hub current_list = load_history() # 3. Ensure the current one is definitely at the top if [new_id] not in current_list: current_list.insert(0, [new_id]) return new_id, gr.update(samples=current_list) def load_past_chat(selected_list): # selected_list comes as [ 'chat_id' ] chat_id = selected_list[0] content = get_chat_content(chat_id) return content, chat_id # --- EVENT HANDLERS --- # 1. Submit Chat -> Stream Response -> Save -> Refresh Sidebar chat_input.submit( bot_response, [chat_input, chatbot, chat_id_state], [chatbot] ).then( handle_save, [chatbot, chat_id_state], [chat_id_state, history_list] ) # 2. Click Sidebar Item -> Load Content history_list.click( load_past_chat, [history_list], [chatbot, chat_id_state] ) # 3. New Chat Button new_btn.click( lambda: ([], "", load_history()), None, [chatbot, chat_id_state, history_list] ) # 4. "Force Refresh" # In Gradio, a component's samples are often cached at the moment of the initial load. To ensure the sidebar is truly dynamic, we need to update the gr.Dataset definition and the refresh logic # To update history_list definition, we add samples_per_page explicitly, ensuring it's not cutting off the list early history_list = gr.Dataset( components=[gr.Textbox(visible=False)], label="Recent Conversations", samples=load_history(), type="values", samples_per_page=20 # Increase this to see more at once ) demo.launch(theme=gr.themes.Soft(), css="styles.css")