mindnet/app/frontend/ui_chat.py

87 lines
3.9 KiB
Python
Raw Permalink Normal View History

2025-12-15 15:40:39 +01:00
"""
FILE: app/frontend/ui_chat.py
DESCRIPTION: Chat-UI. Rendert Nachrichtenverlauf, Quellen-Expanders mit Feedback-Buttons und delegiert bei Bedarf an den Editor.
VERSION: 2.6.0
STATUS: Active
DEPENDENCIES: streamlit, ui_api, ui_editor
LAST_ANALYSIS: 2025-12-15
"""
2025-12-14 12:50:54 +01:00
import streamlit as st
from ui_api import send_chat_message, submit_feedback
from ui_editor import render_draft_editor
def render_chat_interface(top_k, explain):
2025-12-14 13:23:16 +01:00
"""
Rendert das Chat-Interface.
Zeigt Nachrichten an und behandelt User-Input.
"""
# 1. Verlauf anzeigen
2025-12-14 12:50:54 +01:00
for idx, msg in enumerate(st.session_state.messages):
with st.chat_message(msg["role"]):
if msg["role"] == "assistant":
2025-12-14 13:23:16 +01:00
# Intent Badge
2025-12-14 12:50:54 +01:00
intent = msg.get("intent", "UNKNOWN")
st.markdown(f'<div class="intent-badge">Intent: {intent}</div>', unsafe_allow_html=True)
2025-12-14 13:23:16 +01:00
# Debugging (optional, gut für Entwicklung)
2025-12-14 12:50:54 +01:00
with st.expander("🐞 Payload", expanded=False):
st.json(msg)
2025-12-14 13:23:16 +01:00
# Unterscheidung: Normaler Text oder Editor-Modus (Interview)
2025-12-14 12:50:54 +01:00
if intent == "INTERVIEW":
render_draft_editor(msg)
else:
st.markdown(msg["content"])
2025-12-14 13:23:16 +01:00
# Quellen anzeigen
2025-12-14 12:50:54 +01:00
if "sources" in msg and msg["sources"]:
for hit in msg["sources"]:
2025-12-14 13:23:16 +01:00
score = hit.get('total_score', 0)
# Wenn score None ist, 0.0 annehmen
if score is None: score = 0.0
with st.expander(f"📄 {hit.get('note_id', '?')} ({score:.2f})"):
2025-12-14 12:50:54 +01:00
st.markdown(f"_{hit.get('source', {}).get('text', '')[:300]}..._")
2025-12-14 13:23:16 +01:00
# Explanation Layer
2025-12-14 12:50:54 +01:00
if hit.get('explanation'):
st.caption(f"Grund: {hit['explanation']['reasons'][0]['message']}")
2025-12-14 13:23:16 +01:00
# Feedback Buttons pro Source
2025-12-14 12:50:54 +01:00
def _cb(qid=msg.get("query_id"), nid=hit.get('node_id')):
val = st.session_state.get(f"fb_src_{qid}_{nid}")
if val is not None: submit_feedback(qid, nid, val+1)
2025-12-14 13:23:16 +01:00
2025-12-14 12:50:54 +01:00
st.feedback("faces", key=f"fb_src_{msg.get('query_id')}_{hit.get('node_id')}", on_change=_cb)
2025-12-14 13:23:16 +01:00
# Globales Feedback für die Antwort
2025-12-14 12:50:54 +01:00
if "query_id" in msg:
qid = msg["query_id"]
st.feedback("stars", key=f"fb_glob_{qid}", on_change=lambda: submit_feedback(qid, "generated_answer", st.session_state[f"fb_glob_{qid}"]+1))
else:
2025-12-14 13:23:16 +01:00
# User Nachricht
2025-12-14 12:50:54 +01:00
st.markdown(msg["content"])
2025-12-14 13:23:16 +01:00
# 2. Input Feld
2025-12-14 12:50:54 +01:00
if prompt := st.chat_input("Frage Mindnet..."):
st.session_state.messages.append({"role": "user", "content": prompt})
st.rerun()
2025-12-14 13:23:16 +01:00
# 3. Antwort generieren (wenn letzte Nachricht vom User ist)
2025-12-14 12:50:54 +01:00
if len(st.session_state.messages) > 0 and st.session_state.messages[-1]["role"] == "user":
with st.chat_message("assistant"):
with st.spinner("Thinking..."):
resp = send_chat_message(st.session_state.messages[-1]["content"], top_k, explain)
2025-12-14 13:23:16 +01:00
2025-12-14 12:50:54 +01:00
if "error" in resp:
st.error(resp["error"])
else:
st.session_state.messages.append({
"role": "assistant",
"content": resp.get("answer"),
"intent": resp.get("intent", "FACT"),
"sources": resp.get("sources", []),
"query_id": resp.get("query_id")
})
st.rerun()