UI Texteditor merkt sich den Inhalt bei Umschalten
This commit is contained in:
parent
b815f6235f
commit
00aecf692d
|
|
@ -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.9", page_icon="🧠", layout="wide")
|
st.set_page_config(page_title="mindnet v2.3.10", page_icon="🧠", layout="wide")
|
||||||
|
|
||||||
# --- CSS STYLING ---
|
# --- CSS STYLING ---
|
||||||
st.markdown("""
|
st.markdown("""
|
||||||
|
|
@ -207,7 +207,7 @@ def save_draft_to_vault(markdown_content: str, filename: str = None):
|
||||||
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 # Indizierung kann dauern
|
timeout=60
|
||||||
)
|
)
|
||||||
response.raise_for_status()
|
response.raise_for_status()
|
||||||
return response.json()
|
return response.json()
|
||||||
|
|
@ -225,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.9 | Stable ID Fix")
|
st.caption("v2.3.10 | Mode Switch Fix")
|
||||||
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")
|
||||||
|
|
@ -240,10 +240,7 @@ def render_sidebar():
|
||||||
return mode, top_k, explain
|
return mode, top_k, explain
|
||||||
|
|
||||||
def render_draft_editor(msg):
|
def render_draft_editor(msg):
|
||||||
# --- STABLE ID FIX (Der entscheidende Teil) ---
|
# Ensure ID Stability
|
||||||
# Wir prüfen, ob die Nachricht schon eine ID hat. Wenn nicht, erzeugen wir eine
|
|
||||||
# und SPEICHERN sie zurück in das msg-Objekt (das Teil von session_state ist).
|
|
||||||
# So bleibt die ID über Reruns hinweg identisch.
|
|
||||||
if "query_id" not in msg or not msg["query_id"]:
|
if "query_id" not in msg or not msg["query_id"]:
|
||||||
msg["query_id"] = str(uuid.uuid4())
|
msg["query_id"] = str(uuid.uuid4())
|
||||||
|
|
||||||
|
|
@ -256,42 +253,44 @@ def render_draft_editor(msg):
|
||||||
widget_body_key = f"{key_base}_widget_body"
|
widget_body_key = f"{key_base}_widget_body"
|
||||||
data_body_key = f"{key_base}_data_body"
|
data_body_key = f"{key_base}_data_body"
|
||||||
|
|
||||||
# --- 1. INIT STATE (Nur einmalig pro stabiler ID) ---
|
# --- 1. INIT STATE (Nur beim allerersten Laden der Message) ---
|
||||||
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"])
|
||||||
|
|
||||||
# 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)
|
||||||
|
|
||||||
# Persistent Data
|
# Persistent Data (Source of Truth)
|
||||||
st.session_state[data_meta_key] = meta
|
st.session_state[data_meta_key] = meta
|
||||||
st.session_state[data_sugg_key] = []
|
st.session_state[data_sugg_key] = []
|
||||||
st.session_state[data_body_key] = body.strip()
|
st.session_state[data_body_key] = body.strip()
|
||||||
|
|
||||||
# Widget Init (wichtig: Hier wird der "Default Value" des Widgets gesetzt)
|
|
||||||
st.session_state[widget_body_key] = body.strip()
|
|
||||||
|
|
||||||
st.session_state[f"{key_base}_init"] = True
|
st.session_state[f"{key_base}_init"] = True
|
||||||
|
|
||||||
|
# --- 2. RESURRECTION FIX (WICHTIG!) ---
|
||||||
|
# Wenn wir vom Manuellen Editor zurückkommen, wurde der widget_key von Streamlit gelöscht.
|
||||||
|
# Wir müssen ihn aus dem persistenten data_body_key wiederherstellen.
|
||||||
|
if widget_body_key not in st.session_state and data_body_key in st.session_state:
|
||||||
|
st.session_state[widget_body_key] = st.session_state[data_body_key]
|
||||||
|
|
||||||
# --- CALLBACKS ---
|
# --- CALLBACKS ---
|
||||||
def _sync_body():
|
def _sync_body():
|
||||||
# Sync vom Widget zurück in den persistenten Speicher
|
# Sync Widget -> Data (Source of Truth)
|
||||||
st.session_state[data_body_key] = st.session_state[widget_body_key]
|
st.session_state[data_body_key] = st.session_state[widget_body_key]
|
||||||
|
|
||||||
def _insert_text(text_to_insert):
|
def _insert_text(text_to_insert):
|
||||||
# Einfügen in Widget State
|
# Insert in Widget Key und Sync Data
|
||||||
current = st.session_state[widget_body_key]
|
current = st.session_state.get(widget_body_key, "")
|
||||||
st.session_state[widget_body_key] = f"{current}\n\n{text_to_insert}"
|
new_text = f"{current}\n\n{text_to_insert}"
|
||||||
# Sync auch data_body
|
st.session_state[widget_body_key] = new_text
|
||||||
st.session_state[data_body_key] = st.session_state[widget_body_key]
|
st.session_state[data_body_key] = new_text
|
||||||
|
|
||||||
def _remove_text(text_to_remove):
|
def _remove_text(text_to_remove):
|
||||||
current = st.session_state[widget_body_key]
|
current = st.session_state.get(widget_body_key, "")
|
||||||
st.session_state[widget_body_key] = current.replace(text_to_remove, "").strip()
|
new_text = current.replace(text_to_remove, "").strip()
|
||||||
st.session_state[data_body_key] = st.session_state[widget_body_key]
|
st.session_state[widget_body_key] = new_text
|
||||||
|
st.session_state[data_body_key] = new_text
|
||||||
|
|
||||||
# --- 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)
|
||||||
|
|
@ -301,22 +300,29 @@ def render_draft_editor(msg):
|
||||||
meta_ref = st.session_state[data_meta_key]
|
meta_ref = st.session_state[data_meta_key]
|
||||||
c1, c2 = st.columns([2, 1])
|
c1, c2 = st.columns([2, 1])
|
||||||
with c1:
|
with c1:
|
||||||
meta_ref["title"] = st.text_input("Titel", key=f"{key_base}_wdg_title", value=meta_ref["title"])
|
# Auch hier Keys für Widgets nutzen, um Resets zu vermeiden
|
||||||
|
title_key = f"{key_base}_wdg_title"
|
||||||
|
if title_key not in st.session_state: st.session_state[title_key] = meta_ref["title"]
|
||||||
|
meta_ref["title"] = st.text_input("Titel", key=title_key)
|
||||||
|
|
||||||
with c2:
|
with c2:
|
||||||
known_types = ["concept", "project", "decision", "experience", "journal", "value", "goal", "principle"]
|
known_types = ["concept", "project", "decision", "experience", "journal", "value", "goal", "principle"]
|
||||||
curr = meta_ref["type"]
|
curr = meta_ref["type"]
|
||||||
if curr not in known_types: known_types.append(curr)
|
if curr not in known_types: known_types.append(curr)
|
||||||
meta_ref["type"] = st.selectbox("Typ", known_types, index=known_types.index(curr), key=f"{key_base}_wdg_type")
|
type_key = f"{key_base}_wdg_type"
|
||||||
|
if type_key not in st.session_state: st.session_state[type_key] = meta_ref["type"]
|
||||||
|
meta_ref["type"] = st.selectbox("Typ", known_types, index=known_types.index(curr) if curr in known_types else 0, key=type_key)
|
||||||
|
|
||||||
meta_ref["tags_str"] = st.text_input("Tags", key=f"{key_base}_wdg_tags", value=meta_ref.get("tags_str", ""))
|
tags_key = f"{key_base}_wdg_tags"
|
||||||
|
if tags_key not in st.session_state: st.session_state[tags_key] = meta_ref.get("tags_str", "")
|
||||||
|
meta_ref["tags_str"] = st.text_input("Tags", key=tags_key)
|
||||||
|
|
||||||
# Tabs
|
# Tabs
|
||||||
tab_edit, tab_intel, tab_view = st.tabs(["✏️ Inhalt", "🧠 Intelligence", "👁️ Vorschau"])
|
tab_edit, tab_intel, tab_view = st.tabs(["✏️ Inhalt", "🧠 Intelligence", "👁️ Vorschau"])
|
||||||
|
|
||||||
# --- TAB 1: EDITOR ---
|
# --- TAB 1: EDITOR ---
|
||||||
with tab_edit:
|
with tab_edit:
|
||||||
# Hier kein 'value=' übergeben, wenn der Key im Session State ist.
|
# Hier kein 'value' Argument mehr, da wir den Key oben (Resurrection) initialisiert haben.
|
||||||
# Streamlit nimmt automatisch den Wert aus session_state[widget_body_key].
|
|
||||||
st.text_area(
|
st.text_area(
|
||||||
"Body",
|
"Body",
|
||||||
key=widget_body_key,
|
key=widget_body_key,
|
||||||
|
|
@ -330,11 +336,10 @@ 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 suggestions
|
|
||||||
st.session_state[data_sugg_key] = []
|
st.session_state[data_sugg_key] = []
|
||||||
|
|
||||||
# 2. Text DIREKT aus dem Widget State lesen (das ist der aktuellste Stand im Browser)
|
# Lese vom Widget (aktuell) oder Data (Fallback)
|
||||||
text_to_analyze = st.session_state[widget_body_key]
|
text_to_analyze = st.session_state.get(widget_body_key, st.session_state.get(data_body_key, ""))
|
||||||
|
|
||||||
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"])
|
||||||
|
|
@ -352,7 +357,7 @@ def render_draft_editor(msg):
|
||||||
# Render List
|
# Render List
|
||||||
suggestions = st.session_state[data_sugg_key]
|
suggestions = st.session_state[data_sugg_key]
|
||||||
if suggestions:
|
if suggestions:
|
||||||
current_text_state = st.session_state[widget_body_key]
|
current_text_state = st.session_state.get(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', '')
|
||||||
|
|
@ -383,8 +388,8 @@ def render_draft_editor(msg):
|
||||||
"status": "draft",
|
"status": "draft",
|
||||||
"tags": final_tags
|
"tags": final_tags
|
||||||
}
|
}
|
||||||
# Nimm den Widget Content
|
# Final Doc aus Data
|
||||||
final_body = st.session_state[widget_body_key]
|
final_body = st.session_state.get(widget_body_key, st.session_state[data_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:
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue
Block a user