diff --git a/src/main.py b/src/main.py index b8d2484..77b2398 100644 --- a/src/main.py +++ b/src/main.py @@ -20,91 +20,22 @@ st.set_page_config( layout="wide" ) -st.markdown(""" """, unsafe_allow_html=True) - -# ---------------- CHAT PANEL INJECTION ---------------- -def inject_chat_panel(is_open: bool): - st.iframe(f""" - - """, height=1) +st.markdown(""" + +""", unsafe_allow_html=True) # ---------------- MAIN ---------------- def main(): file_manager = FileManager() navigation = FileNavigation() + chat = ChatInterface() chat_manager = ChatManager() execution_engine = ExecutionEngine() output_display = OutputDisplay() @@ -146,21 +77,19 @@ def main(): else: st.session_state.editor_content = "" - inject_chat_panel(st.session_state.chat_open) + chat.inject_panel(st.session_state.chat_open) # ---------------- MAIN UI ---------------- if st.session_state.active_file: - title_col, btn_col = st.columns([5, 1]) - with title_col: - st.subheader(f"✏️ {Path(st.session_state.active_file).name}") - with btn_col: - run_clicked = st.button("▶ Run", type="primary", use_container_width=True) + st.subheader(f"✏️ {Path(st.session_state.active_file).name}") editor = CodeEditor() - new_value = editor.display_code( + new_value, run_clicked = editor.display_code( st.session_state.editor_content, filename=st.session_state.active_file ) + + # ---------------- APPLY DETECTION ---------------- if new_value is not None: if new_value != st.session_state.last_applied_content: st.session_state.editor_content = new_value @@ -168,6 +97,7 @@ def main(): file_manager.save_file(st.session_state.active_file, new_value) st.success("Saved ✔") + # ---------------- RUN ---------------- if run_clicked: with st.spinner("Running…"): st.session_state.run_result = execution_engine.run_file( diff --git a/src/ui/chat.py b/src/ui/chat.py index a5711fd..c88dcc8 100644 --- a/src/ui/chat.py +++ b/src/ui/chat.py @@ -1,45 +1,116 @@ import streamlit as st + class ChatInterface: """ - Chat Interface für KI-Interaktion [1] + Chat Interface for AI interaction, including the right-side slide-out panel. """ - + def __init__(self): self.chat_messages = [] - + + # ---------------- PANEL INJECTION ---------------- + def inject_panel(self, is_open: bool): + """Injects or removes the fixed right-side AI chat panel via st.iframe.""" + st.iframe(f""" + + """, height=1) + + # ---------------- CHAT DISPLAY ---------------- def display_chat(self, chat_manager): - """ - Zeigt die Chat-Schnittstelle mit Konversationsverlauf [1] - """ - st.title("🤖 KI-Assistent") - - # Chat History anzeigen + """Renders the Streamlit chat interface (used when not in panel mode).""" + st.title("AI Assistant") + for message in self.chat_messages: with st.chat_message(message["role"]): st.markdown(message["content"]) - - # User Input - if prompt := st.chat_input("Frage zum Code stellen..."): - # User Nachricht anzeigen + + if prompt := st.chat_input("Ask about your code..."): self.chat_messages.append({"role": "user", "content": prompt}) with st.chat_message("user"): st.markdown(prompt) - - # AI Antwort generieren (via ChatManager) + with st.chat_message("assistant"): response = chat_manager.generate_response(prompt) st.markdown(response) self.chat_messages.append({"role": "assistant", "content": response}) - - def add_message(self, role, content): - """ - Fügt eine Nachricht zur Konversation hinzu - """ + + # ---------------- HELPERS ---------------- + def add_message(self, role: str, content: str): self.chat_messages.append({"role": role, "content": content}) - + def clear_history(self): - """ - Löscht den Chat-Verlauf - """ self.chat_messages.clear() \ No newline at end of file diff --git a/src/ui/editor.py b/src/ui/editor.py index 6798a03..ec7d1b8 100644 --- a/src/ui/editor.py +++ b/src/ui/editor.py @@ -1,29 +1,44 @@ from streamlit_ace import st_ace +import streamlit as st + class CodeEditor: - def detect_language(self, filename): - + def detect_language(self, filename: str) -> str: mapping = { - ".py": "python", - ".js": "javascript", + ".py": "python", + ".js": "javascript", ".html": "html", - ".css": "css", + ".css": "css", ".json": "json", - ".md": "markdown", + ".md": "markdown", } - for ext, lang in mapping.items(): if filename.endswith(ext): return lang - return "text" - def display_code(self, code_content, filename=""): - + def display_code(self, code_content: str, filename: str = "") -> tuple: + """ + Renders a toolbar row (Apply is built into st_ace, Run is next to it) + then the ACE editor below. + Returns (new_value, run_clicked) where new_value is None until Apply is hit. + """ language = self.detect_language(filename) - return st_ace( + # --- Toolbar: filename label + Run button aligned right --- + label_col, run_col = st.columns([6, 1]) + with label_col: + st.caption(f" {filename.split('/')[-1] or filename}" if filename else "") + with run_col: + run_clicked = st.button( + "▶ Run", + key=f"run_{filename}", + type="primary", + use_container_width=True + ) + + new_value = st_ace( value=code_content, language=language, theme="chrome", @@ -31,7 +46,9 @@ class CodeEditor: font_size=14, tab_size=4, wrap=False, - auto_update=False, + auto_update=False, show_gutter=True, - show_print_margin=False - ) \ No newline at end of file + show_print_margin=False, + ) + + return new_value, run_clicked \ No newline at end of file