From 4cd82d1d2b1d1808c34e9108fc1213efb582510e Mon Sep 17 00:00:00 2001 From: Lars Date: Fri, 12 Dec 2025 17:31:03 +0100 Subject: [PATCH] ui fix --- app/frontend/ui.py | 65 ++++++++++++++++++++++++++-------------------- 1 file changed, 37 insertions(+), 28 deletions(-) diff --git a/app/frontend/ui.py b/app/frontend/ui.py index a21278e..ee7051f 100644 --- a/app/frontend/ui.py +++ b/app/frontend/ui.py @@ -1,3 +1,9 @@ +# app/frontend/ui.py + +# ... (Imports und Setup bleiben gleich) ... + +# Ersetze die gesamte Datei mit diesem Inhalt: + import streamlit as st import requests import uuid @@ -54,15 +60,6 @@ st.markdown(""" background-color: white; font-family: -apple-system,BlinkMacSystemFont,"Segoe UI",Helvetica,Arial,sans-serif; } - - .suggestion-card { - border-left: 3px solid #1a73e8; - background-color: #ffffff; - padding: 10px; - margin-bottom: 8px; - border-radius: 4px; - box-shadow: 0 1px 3px rgba(0,0,0,0.1); - } """, unsafe_allow_html=True) @@ -77,9 +74,9 @@ def slugify(value): Erzeugt saubere Dateinamen (German-Aware). z.B. "Müller & Söhne" -> "mueller-und-soehne" """ + if not value: return "" value = str(value).lower() - # Deutsche Umlaute manuell ersetzen, da NFKD sie oft nur strippt - replacements = {'ä': 'ae', 'ö': 'oe', 'ü': 'ue', 'ß': 'ss', '&': 'und'} + replacements = {'ä': 'ae', 'ö': 'oe', 'ü': 'ue', 'ß': 'ss', '&': 'und', '+': 'und'} for k, v in replacements.items(): value = value.replace(k, v) @@ -130,19 +127,16 @@ def normalize_meta_and_body(meta, body): return clean_meta, final_body def parse_markdown_draft(full_text): - """ - Klassischer Parser (mit YAML-Fixes). - Funktioniert am besten, wenn Struktur grob eingehalten wird. - """ + """Robustes Parsing + Sanitization (YAML + Fallbacks).""" clean_text = full_text.strip() - # Code Blocks entfernen + # 1. Markdown Code-Blöcke entfernen pattern_block = r"```(?:markdown|md|yaml)?\s*(.*?)\s*```" match_block = re.search(pattern_block, clean_text, re.DOTALL | re.IGNORECASE) if match_block: clean_text = match_block.group(1).strip() - # Split an '---' + # 2. Split YAML / Body parts = re.split(r"^---+\s*$", clean_text, maxsplit=2, flags=re.MULTILINE) meta = {} @@ -152,9 +146,8 @@ def parse_markdown_draft(full_text): yaml_str = parts[1] body_candidate = parts[2] - # YAML Cleanup: Entferne '#' innerhalb der YAML-Sektion + # YAML Cleanup yaml_str_clean = yaml_str.replace("#", "") - try: parsed = yaml.safe_load(yaml_str_clean) if isinstance(parsed, dict): @@ -180,7 +173,6 @@ def parse_markdown_draft(full_text): def build_markdown_doc(meta, body): """Baut das finale Dokument zusammen.""" if "id" not in meta or meta["id"] == "generated_on_save": - # Hier nutzen wir jetzt die verbesserte slugify Funktion raw_title = meta.get('title', 'note') clean_slug = slugify(raw_title)[:50] or "note" meta["id"] = f"{datetime.now().strftime('%Y%m%d')}-{clean_slug}" @@ -266,7 +258,7 @@ def submit_feedback(query_id, node_id, score, comment=None): def render_sidebar(): with st.sidebar: st.title("🧠 mindnet") - st.caption("v2.4.3 | Filename Fix") + st.caption("v2.4.4 | Smart Filename") mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0) st.divider() st.subheader("⚙️ Settings") @@ -297,7 +289,7 @@ def render_draft_editor(msg): if f"{key_base}_init" not in st.session_state: meta, body = parse_markdown_draft(msg["content"]) if "type" not in meta: meta["type"] = "default" - if "title" not in meta: meta["title"] = "" + if "title" not in meta: meta["title"] = "" # Kann leer sein tags = meta.get("tags", []) meta["tags_str"] = ", ".join(tags) if isinstance(tags, list) else str(tags) @@ -306,7 +298,7 @@ def render_draft_editor(msg): st.session_state[data_sugg_key] = [] st.session_state[data_body_key] = body.strip() - # Init Widgets Keys (Resurrection) + # Init Widgets Keys st.session_state[f"{key_base}_wdg_title"] = meta["title"] st.session_state[f"{key_base}_wdg_type"] = meta["type"] st.session_state[f"{key_base}_wdg_tags"] = meta["tags_str"] @@ -420,16 +412,25 @@ def render_draft_editor(msg): final_tags_str = st.session_state.get(f"{key_base}_wdg_tags", "") final_tags = [t.strip() for t in final_tags_str.split(",") if t.strip()] - # WICHTIG: Hier ziehen wir die Daten explizit aus dem Widget-State + # Live Daten aus Widget (dies ist die Wahrheit!) final_meta = { "id": "generated_on_save", "type": st.session_state.get(f"{key_base}_wdg_type", "default"), - "title": st.session_state.get(f"{key_base}_wdg_title", "Untitled"), + "title": st.session_state.get(f"{key_base}_wdg_title", "").strip(), "status": "draft", "tags": final_tags } final_body = st.session_state.get(widget_body_key, st.session_state[data_body_key]) + + # 1. Update Title in Meta (damit es im YAML landet) + if not final_meta["title"]: + # Fallback auf H1 im Text + h1_match = re.search(r"^#\s+(.*)$", final_body, re.MULTILINE) + if h1_match: + final_meta["title"] = h1_match.group(1).strip() + + # 2. Build Doc final_doc = build_markdown_doc(final_meta, final_body) with tab_view: @@ -444,12 +445,20 @@ def render_draft_editor(msg): if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"): with st.spinner("Speichere im Vault..."): - # DATEINAMEN-LOGIK (Fix) - raw_title = final_meta.get("title", "draft") - safe_title = slugify(raw_title)[:50] + # --- DATEINAMEN INTELLIGENZ --- + # Prio 1: Meta Titel + title_for_slug = final_meta.get("title", "") + + # Prio 2: Body Snippet (wenn Titel immer noch leer) + if not title_for_slug: + clean_body = re.sub(r"[#*_\[\]()]", "", final_body).strip() + title_for_slug = clean_body[:40] if clean_body else "draft" + + safe_title = slugify(title_for_slug)[:60] if not safe_title: safe_title = "draft" fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md" + # ----------------------------- result = save_draft_to_vault(final_doc, filename=fname) if "error" in result: