bug fix ui
This commit is contained in:
parent
98c395b5de
commit
2677ad7269
|
|
@ -23,7 +23,7 @@ timeout_setting = os.getenv("MINDNET_API_TIMEOUT") or os.getenv("MINDNET_LLM_TIM
|
||||||
API_TIMEOUT = float(timeout_setting) if timeout_setting else 300.0
|
API_TIMEOUT = float(timeout_setting) if timeout_setting else 300.0
|
||||||
|
|
||||||
# --- PAGE SETUP ---
|
# --- PAGE SETUP ---
|
||||||
st.set_page_config(page_title="mindnet v2.3.7", page_icon="🧠", layout="wide")
|
st.set_page_config(page_title="mindnet v2.3.8", page_icon="🧠", layout="wide")
|
||||||
|
|
||||||
# --- CSS STYLING ---
|
# --- CSS STYLING ---
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
|
|
@ -112,6 +112,7 @@ def normalize_meta_and_body(meta, body):
|
||||||
def parse_markdown_draft(full_text):
|
def parse_markdown_draft(full_text):
|
||||||
"""Robustes Parsing + Sanitization."""
|
"""Robustes Parsing + Sanitization."""
|
||||||
clean_text = full_text
|
clean_text = full_text
|
||||||
|
|
||||||
pattern_block = r"```(?:markdown|md)?\s*(.*?)\s*```"
|
pattern_block = r"```(?:markdown|md)?\s*(.*?)\s*```"
|
||||||
match_block = re.search(pattern_block, full_text, re.DOTALL | re.IGNORECASE)
|
match_block = re.search(pattern_block, full_text, re.DOTALL | re.IGNORECASE)
|
||||||
if match_block:
|
if match_block:
|
||||||
|
|
@ -188,6 +189,7 @@ def send_chat_message(message: str, top_k: int, explain: bool):
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|
||||||
def analyze_draft_text(text: str, n_type: str):
|
def analyze_draft_text(text: str, n_type: str):
|
||||||
|
"""Ruft den neuen Intelligence-Service (WP-11) auf."""
|
||||||
try:
|
try:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
INGEST_ANALYZE_ENDPOINT,
|
INGEST_ANALYZE_ENDPOINT,
|
||||||
|
|
@ -200,11 +202,12 @@ def analyze_draft_text(text: str, n_type: str):
|
||||||
return {"error": str(e)}
|
return {"error": str(e)}
|
||||||
|
|
||||||
def save_draft_to_vault(markdown_content: str, filename: str = None):
|
def save_draft_to_vault(markdown_content: str, filename: str = None):
|
||||||
|
"""Ruft den neuen Persistence-Service (WP-11) auf."""
|
||||||
try:
|
try:
|
||||||
response = requests.post(
|
response = requests.post(
|
||||||
INGEST_SAVE_ENDPOINT,
|
INGEST_SAVE_ENDPOINT,
|
||||||
json={"markdown_content": markdown_content, "filename": filename},
|
json={"markdown_content": markdown_content, "filename": filename},
|
||||||
timeout=60
|
timeout=60 # Indizierung kann dauern
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
@ -222,7 +225,7 @@ def submit_feedback(query_id, node_id, score, comment=None):
|
||||||
def render_sidebar():
|
def render_sidebar():
|
||||||
with st.sidebar:
|
with st.sidebar:
|
||||||
st.title("🧠 mindnet")
|
st.title("🧠 mindnet")
|
||||||
st.caption("v2.3.7 | Stable State")
|
st.caption("v2.3.8 | Fixed State Sync")
|
||||||
mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0)
|
mode = st.radio("Modus", ["💬 Chat", "📝 Manueller Editor"], index=0)
|
||||||
st.divider()
|
st.divider()
|
||||||
st.subheader("⚙️ Settings")
|
st.subheader("⚙️ Settings")
|
||||||
|
|
@ -241,42 +244,38 @@ def render_draft_editor(msg):
|
||||||
key_base = f"draft_{qid}"
|
key_base = f"draft_{qid}"
|
||||||
|
|
||||||
# State Keys
|
# State Keys
|
||||||
data_body_key = f"{key_base}_data_body" # Persistenter Speicher
|
data_meta_key = f"{key_base}_data_meta"
|
||||||
data_meta_key = f"{key_base}_data_meta" # Metadaten
|
data_sugg_key = f"{key_base}_data_suggestions"
|
||||||
data_sugg_key = f"{key_base}_data_suggestions" # Vorschläge
|
widget_body_key = f"{key_base}_widget_body"
|
||||||
widget_body_key = f"{key_base}_widget_body" # Das Textfeld selbst
|
|
||||||
|
|
||||||
# --- 1. INIT STATE ---
|
# --- 1. INIT STATE (Nur einmalig) ---
|
||||||
if f"{key_base}_init" not in st.session_state:
|
if f"{key_base}_init" not in st.session_state:
|
||||||
meta, body = parse_markdown_draft(msg["content"])
|
meta, body = parse_markdown_draft(msg["content"])
|
||||||
|
|
||||||
# Metadata Defaults
|
# Defaults
|
||||||
if "type" not in meta: meta["type"] = "default"
|
if "type" not in meta: meta["type"] = "default"
|
||||||
if "title" not in meta: meta["title"] = ""
|
if "title" not in meta: meta["title"] = ""
|
||||||
tags = meta.get("tags", [])
|
tags = meta.get("tags", [])
|
||||||
meta["tags_str"] = ", ".join(tags) if isinstance(tags, list) else str(tags)
|
meta["tags_str"] = ", ".join(tags) if isinstance(tags, list) else str(tags)
|
||||||
|
|
||||||
# Init Session State
|
|
||||||
st.session_state[data_meta_key] = meta
|
st.session_state[data_meta_key] = meta
|
||||||
st.session_state[data_body_key] = body.strip()
|
|
||||||
st.session_state[data_sugg_key] = []
|
st.session_state[data_sugg_key] = []
|
||||||
|
|
||||||
|
# WICHTIG: Wir initialisieren den Widget Key direkt!
|
||||||
|
st.session_state[widget_body_key] = body.strip()
|
||||||
|
|
||||||
st.session_state[f"{key_base}_init"] = True
|
st.session_state[f"{key_base}_init"] = True
|
||||||
|
|
||||||
# --- CALLBACKS ---
|
# --- CALLBACKS (Modifizieren direkt den Widget-Key) ---
|
||||||
def _sync_body():
|
|
||||||
# Schreibt Widget-Inhalt in den Speicher
|
|
||||||
st.session_state[data_body_key] = st.session_state[widget_body_key]
|
|
||||||
|
|
||||||
def _insert_text(text_to_insert):
|
def _insert_text(text_to_insert):
|
||||||
# Liest vom Widget (aktuellster Stand!), fügt an, schreibt zurück
|
current = st.session_state[widget_body_key]
|
||||||
current = st.session_state[widget_body_key]
|
st.session_state[widget_body_key] = f"{current}\n\n{text_to_insert}"
|
||||||
st.session_state[data_body_key] = f"{current}\n\n{text_to_insert}"
|
# Kein Rerun nötig, Button-Klick macht das implizit
|
||||||
# Wichtig: Leere Vorschläge nach Insert, damit man nicht doppelt klickt
|
|
||||||
# st.session_state[data_sugg_key] = []
|
|
||||||
|
|
||||||
def _remove_text(text_to_remove):
|
def _remove_text(text_to_remove):
|
||||||
current = st.session_state[widget_body_key]
|
current = st.session_state[widget_body_key]
|
||||||
st.session_state[data_body_key] = current.replace(text_to_remove, "").strip()
|
st.session_state[widget_body_key] = current.replace(text_to_remove, "").strip()
|
||||||
|
|
||||||
# --- UI LAYOUT ---
|
# --- UI LAYOUT ---
|
||||||
st.markdown(f'<div class="draft-box">', unsafe_allow_html=True)
|
st.markdown(f'<div class="draft-box">', unsafe_allow_html=True)
|
||||||
|
|
@ -300,12 +299,11 @@ def render_draft_editor(msg):
|
||||||
|
|
||||||
# --- TAB 1: EDITOR ---
|
# --- TAB 1: EDITOR ---
|
||||||
with tab_edit:
|
with tab_edit:
|
||||||
# Value kommt aus Data, Änderungen gehen via Callback zurück in Data
|
# State-Fix: Wir übergeben KEIN 'value' Argument, wenn der Key existiert.
|
||||||
|
# So hat das Widget Vorrang vor veraltetem Code.
|
||||||
st.text_area(
|
st.text_area(
|
||||||
"Body",
|
"Body",
|
||||||
key=widget_body_key,
|
key=widget_body_key,
|
||||||
value=st.session_state[data_body_key],
|
|
||||||
on_change=_sync_body,
|
|
||||||
height=500,
|
height=500,
|
||||||
label_visibility="collapsed"
|
label_visibility="collapsed"
|
||||||
)
|
)
|
||||||
|
|
@ -315,16 +313,14 @@ def render_draft_editor(msg):
|
||||||
st.info("Klicke auf 'Analysieren', um Verknüpfungen für den AKTUELLEN Text zu finden.")
|
st.info("Klicke auf 'Analysieren', um Verknüpfungen für den AKTUELLEN Text zu finden.")
|
||||||
|
|
||||||
if st.button("🔍 Analyse starten", key=f"{key_base}_analyze"):
|
if st.button("🔍 Analyse starten", key=f"{key_base}_analyze"):
|
||||||
# 1. Reset
|
# 1. Reset suggestions
|
||||||
st.session_state[data_sugg_key] = []
|
st.session_state[data_sugg_key] = []
|
||||||
|
|
||||||
# 2. Text holen (HIER WAR DER FEHLER)
|
# 2. Text DIREKT aus dem Widget State lesen
|
||||||
# Wir holen ihn direkt aus dem Widget-Key, da dieser immer aktuell ist,
|
text_to_analyze = st.session_state[widget_body_key]
|
||||||
# auch wenn on_change noch nicht gefeuert hat.
|
|
||||||
text_to_analyze = st.session_state.get(widget_body_key, st.session_state[data_body_key])
|
|
||||||
|
|
||||||
# Debug (optional, damit du siehst was passiert)
|
# 3. Debug Output (optional)
|
||||||
# st.caption(f"Sende {len(text_to_analyze)} Zeichen an API...")
|
# st.info(f"Sende {len(text_to_analyze)} Zeichen an API...")
|
||||||
|
|
||||||
with st.spinner("Analysiere..."):
|
with st.spinner("Analysiere..."):
|
||||||
analysis = analyze_draft_text(text_to_analyze, meta_ref["type"])
|
analysis = analyze_draft_text(text_to_analyze, meta_ref["type"])
|
||||||
|
|
@ -335,7 +331,7 @@ def render_draft_editor(msg):
|
||||||
suggestions = analysis.get("suggestions", [])
|
suggestions = analysis.get("suggestions", [])
|
||||||
st.session_state[data_sugg_key] = suggestions
|
st.session_state[data_sugg_key] = suggestions
|
||||||
if not suggestions:
|
if not suggestions:
|
||||||
st.warning("Keine Vorschläge gefunden (Text zu kurz oder keine Matches).")
|
st.warning("Keine Vorschläge gefunden.")
|
||||||
else:
|
else:
|
||||||
st.success(f"{len(suggestions)} Vorschläge gefunden.")
|
st.success(f"{len(suggestions)} Vorschläge gefunden.")
|
||||||
|
|
||||||
|
|
@ -343,7 +339,7 @@ def render_draft_editor(msg):
|
||||||
suggestions = st.session_state[data_sugg_key]
|
suggestions = st.session_state[data_sugg_key]
|
||||||
if suggestions:
|
if suggestions:
|
||||||
# Hole aktuellen Text für Vergleich
|
# Hole aktuellen Text für Vergleich
|
||||||
current_text_state = st.session_state.get(widget_body_key, "")
|
current_text_state = st.session_state[widget_body_key]
|
||||||
|
|
||||||
for idx, sugg in enumerate(suggestions):
|
for idx, sugg in enumerate(suggestions):
|
||||||
link_text = sugg.get('suggested_markdown', '')
|
link_text = sugg.get('suggested_markdown', '')
|
||||||
|
|
@ -375,7 +371,7 @@ def render_draft_editor(msg):
|
||||||
"tags": final_tags
|
"tags": final_tags
|
||||||
}
|
}
|
||||||
# Auch hier: Nimm den aktuellsten Text für die Vorschau
|
# Auch hier: Nimm den aktuellsten Text für die Vorschau
|
||||||
final_body = st.session_state.get(widget_body_key, st.session_state[data_body_key])
|
final_body = st.session_state[widget_body_key]
|
||||||
final_doc = build_markdown_doc(final_meta, final_body)
|
final_doc = build_markdown_doc(final_meta, final_body)
|
||||||
|
|
||||||
with tab_view:
|
with tab_view:
|
||||||
|
|
@ -385,13 +381,25 @@ def render_draft_editor(msg):
|
||||||
|
|
||||||
st.markdown("---")
|
st.markdown("---")
|
||||||
|
|
||||||
if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"):
|
b1, b2 = st.columns([1, 1])
|
||||||
with st.spinner("Speichere..."):
|
with b1:
|
||||||
safe_title = re.sub(r'[^a-zA-Z0-9]', '-', meta_ref["title"]).lower()[:30] or "draft"
|
if st.button("💾 Speichern & Indizieren", type="primary", key=f"{key_base}_save"):
|
||||||
fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md"
|
with st.spinner("Speichere..."):
|
||||||
res = save_draft_to_vault(final_doc, filename=fname)
|
safe_title = re.sub(r'[^a-zA-Z0-9]', '-', meta_ref["title"]).lower()[:30] or "draft"
|
||||||
if "error" in res: st.error(f"Fehler: {res['error']}")
|
fname = f"{datetime.now().strftime('%Y%m%d')}-{safe_title}.md"
|
||||||
else: st.success(f"Gespeichert: {res.get('file_path')}")
|
|
||||||
|
# Sende das finale Dokument an die API
|
||||||
|
result = save_draft_to_vault(final_doc, filename=fname)
|
||||||
|
if "error" in result:
|
||||||
|
st.error(f"Fehler: {result['error']}")
|
||||||
|
else:
|
||||||
|
st.success(f"Gespeichert: {result.get('file_path')}")
|
||||||
|
st.balloons()
|
||||||
|
with b2:
|
||||||
|
if st.button("📋 Code anzeigen", key=f"{key_base}_btn_copy"):
|
||||||
|
st.code(final_doc, language="markdown")
|
||||||
|
|
||||||
|
st.markdown("</div>", unsafe_allow_html=True)
|
||||||
|
|
||||||
|
|
||||||
def render_chat_interface(top_k, explain):
|
def render_chat_interface(top_k, explain):
|
||||||
|
|
@ -453,11 +461,9 @@ def render_chat_interface(top_k, explain):
|
||||||
st.rerun()
|
st.rerun()
|
||||||
|
|
||||||
def render_manual_editor():
|
def render_manual_editor():
|
||||||
# Wir nutzen dieselbe Logik wie beim Interview, aber mit einem "leeren" Mock-Objekt
|
|
||||||
# Wichtig: Feste Query-ID für Manuellen Modus, damit der State persistent bleibt
|
|
||||||
mock_msg = {
|
mock_msg = {
|
||||||
"content": "---\ntype: concept\ntitle: Neue Notiz\nstatus: draft\ntags: []\n---\n# Titel\n",
|
"content": "---\ntype: concept\ntitle: Neue Notiz\nstatus: draft\ntags: []\n---\n# Titel\n",
|
||||||
"query_id": "manual_editor_fixed_v1"
|
"query_id": "manual_mode_v2"
|
||||||
}
|
}
|
||||||
render_draft_editor(mock_msg)
|
render_draft_editor(mock_msg)
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user