import os import glob import uuid import asyncio import logging import streamlit as st # Import the new Orchestrator Pattern from src.chatbot_v2.patterns.orchestrator import ChatbotOrchestrator # ----------------------------- # Configuration & Utils # ----------------------------- st.set_page_config( page_title="Layered AI Assistant", layout="wide", page_icon="🧠" ) def load_prompts(folder="prompts"): prompts = [] prompt_labels = [] if os.path.exists(folder): for file_path in glob.glob(os.path.join(folder, "*.txt")): with open(file_path, "r", encoding="utf-8") as f: content = f.read().strip() if content: prompts.append(content) prompt_labels.append(os.path.basename(file_path).replace("_", " ").replace(".txt", "").title()) return prompts, prompt_labels prompts, prompt_labels = load_prompts() # ----------------------------- # Session State # ----------------------------- if "messages" not in st.session_state: st.session_state.messages = [] # Initialize the Agent if "agent" not in st.session_state: st.session_state.agent = ChatbotOrchestrator() # ----------------------------- # Premium Styling # ----------------------------- st.markdown(""" """, unsafe_allow_html=True) # ----------------------------- # Logic # ----------------------------- async def get_ai_response(prompt: str) -> str: try: agent: ChatbotOrchestrator = st.session_state.agent # We pass the *previous* history (messages excluding the latest one which we just appended) # Actually, st.session_state.messages ALREADY has the new user message appended below. # So we pass messages[:-1] as "history" history = st.session_state.messages[:-1] result = await agent.run(user_input=prompt, external_history=history) return result except Exception as e: return f"❌ **Error**: {str(e)}" # ----------------------------- # Sidebar - Quick Actions # ----------------------------- with st.sidebar: st.markdown("### ⚡ Quick Starters") st.markdown("Select a prompt to start:") # We use a trick with st.button to act as input triggers # If a button is clicked, we'll handle it in the main loop logic selected_prompt = None for idx, prompt_text in enumerate(prompts): label = prompt_labels[idx] if idx < len(prompt_labels) else f"Prompt {idx+1}" if st.button(label, key=f"sidebar_btn_{idx}", use_container_width=True): # Reset conversation st.session_state.messages = [] st.session_state.agent = ChatbotOrchestrator() # Reset agent memory too selected_prompt = prompt_text st.markdown("---") if st.button("🗑️ Clear Conversation", use_container_width=True): st.session_state.messages = [] st.session_state.agent = ChatbotOrchestrator() st.rerun() # ----------------------------- # Main Content # ----------------------------- # Hero Banner (Always visible & Sticky) st.markdown(""" """, unsafe_allow_html=True) # Display Chat History for message in st.session_state.messages: with st.chat_message(message["role"]): st.markdown(message["content"], unsafe_allow_html=True) # Chat Input Handling # We handle both the chat input widget and the sidebar selection here if prompt := (st.chat_input("Type your message...") or selected_prompt): # User Message st.session_state.messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) # Assistant Response with st.chat_message("assistant"): with st.spinner("🧠 Thinking (Layers Active)..."): response_text = asyncio.run(get_ai_response(prompt)) st.markdown(response_text, unsafe_allow_html=True) st.session_state.messages.append({"role": "assistant", "content": response_text}) if selected_prompt: st.rerun()