import streamlit as st import requests import uuid import os import json from pathlib import Path from dotenv import load_dotenv # --- CONFIGURATION --- load_dotenv() API_BASE_URL = os.getenv("MINDNET_API_URL", "http://localhost:8002") CHAT_ENDPOINT = f"{API_BASE_URL}/chat" FEEDBACK_ENDPOINT = f"{API_BASE_URL}/feedback" HISTORY_FILE = Path("data/logs/search_history.jsonl") # Timeout Strategy timeout_setting = os.getenv("MINDNET_API_TIMEOUT") or os.getenv("MINDNET_LLM_TIMEOUT") API_TIMEOUT = float(timeout_setting) if timeout_setting else 300.0 # --- PAGE SETUP --- st.set_page_config(page_title="mindnet v2.3.1", page_icon="🧠", layout="wide") # --- CSS STYLING --- st.markdown(""" """, unsafe_allow_html=True) # --- SESSION STATE --- if "messages" not in st.session_state: st.session_state.messages = [] if "user_id" not in st.session_state: st.session_state.user_id = str(uuid.uuid4()) if "draft_note" not in st.session_state: st.session_state.draft_note = {"title": "", "content": "", "type": "concept"} # --- HELPER FUNCTIONS --- def load_history_from_logs(limit=10): """Liest die letzten N Queries aus dem Logfile.""" queries = [] if HISTORY_FILE.exists(): try: with open(HISTORY_FILE, "r", encoding="utf-8") as f: lines = f.readlines() for line in reversed(lines): try: entry = json.loads(line) q = entry.get("query_text") if q and q not in queries: queries.append(q) if len(queries) >= limit: break except: continue except Exception as e: st.sidebar.warning(f"Log-Fehler: {e}") return queries def send_chat_message(message: str, top_k: int, explain: bool): try: response = requests.post( CHAT_ENDPOINT, json={"message": message, "top_k": top_k, "explain": explain}, timeout=API_TIMEOUT ) response.raise_for_status() return response.json() except Exception as e: return {"error": str(e)} def submit_feedback(query_id, node_id, score, comment=None): try: requests.post(FEEDBACK_ENDPOINT, json={"query_id": query_id, "node_id": node_id, "score": score, "comment": comment}, timeout=2) target = "Antwort" if node_id == "generated_answer" else "Quelle" st.toast(f"Feedback für {target} gespeichert! (Score: {score})") except: pass # --- UI COMPONENTS --- def render_sidebar(): with st.sidebar: st.title("🧠 mindnet") st.caption("v2.3.1 | WP-10 UI") mode = st.radio("Modus", ["💬 Chat", "📝 Neuer Eintrag (WP-07)"], index=0) st.divider() st.subheader("⚙️ Settings") top_k = st.slider("Quellen (Top-K)", 1, 10, 5) explain = st.toggle("Explanation Layer", True) st.divider() st.subheader("🕒 Verlauf") history = load_history_from_logs(8) if not history: st.caption("Noch keine Einträge.") for q in history: if st.button(f"🔎 {q[:30]}...", key=f"hist_{q}", help=q, use_container_width=True): st.session_state.messages.append({"role": "user", "content": q}) st.rerun() return mode, top_k, explain def render_chat_interface(top_k, explain): # Render History for msg in st.session_state.messages: with st.chat_message(msg["role"]): if msg["role"] == "assistant": # Intent Badge MIT SOURCE (Fix für Debugging) if "intent" in msg: icon = {"EMPATHY": "❤️", "DECISION": "⚖️", "CODING": "💻", "FACT": "📚"}.get(msg["intent"], "🧠") source_info = msg.get("intent_source", "Unknown") # Hier wird die Quelle wieder angezeigt: st.markdown(f'