File: //opt/textanalyse/main_streamlit.py
import streamlit as st
import os
import sys
import logging
import random
import time
import concurrent.futures
# Debugging-Konfiguration
logging.basicConfig(level=logging.DEBUG)
logger = logging.getLogger(__name__)
def parse_markdown_table(md_text):
lines = md_text.strip().split('\n')
if len(lines) < 2:
return None, []
header_line = lines[0]
separator_line = lines[1]
if not header_line.startswith('|') or not separator_line.startswith('|') or '---' not in separator_line:
return None, []
headers = [h.strip() for h in header_line.strip('|').split('|')]
data = []
for line in lines[2:]:
if line.strip().startswith('|'):
row = [r.strip() for r in line.strip('|').split('|')]
if len(row) == len(headers):
data.append(dict(zip(headers, row)))
else:
break
return headers, data
def load_coordinator():
import config
sys.path.insert(0, os.path.dirname(__file__))
import_error = None
try:
from team.proofreading_team import proofreading_coordinator, specialist_agents_instance
except Exception as e:
logger.error(f"Failed to import proofreading_team: {e}", exc_info=True)
import_error = str(e)
proofreading_coordinator = None
specialist_agents_instance = []
return proofreading_coordinator, specialist_agents_instance, import_error
def run_agent_task(agent, text, agent_name=None, retry_count=3, retry_delay=2):
if not agent:
return agent_name or "Unknown", None, "Agent nicht initialisiert"
for attempt in range(retry_count):
try:
response = agent.run(text)
return agent_name or getattr(agent, 'name', "Unknown"), response, None
except Exception as e:
error_message = f"Fehler: {e}"
if "429" in error_message and attempt < retry_count - 1:
delay = retry_delay * (1 + random.random())
logger.info(f"Rate limit for {agent_name}. Retrying in {delay:.2f}s ({attempt+1}/{retry_count})")
time.sleep(delay)
retry_delay = min(retry_delay * 2, 10)
continue
return agent_name or getattr(agent, 'name', "Unknown"), None, error_message
def run_agents_parallel(agents, text, max_concurrent=3):
results = {name: {"status":"waiting","response":None,"error":None} for _,name in agents}
max_workers = min(max_concurrent, len(agents))
with concurrent.futures.ThreadPoolExecutor(max_workers=max_workers) as executor:
future_to_name = {}
for i,(agent,name) in enumerate(agents):
if i>0:
time.sleep(1 + random.random() * 2)
results[name]["status"] = "running"
future = executor.submit(run_agent_task, agent, text, name)
future_to_name[future] = name
for fut in concurrent.futures.as_completed(future_to_name):
agent_name, resp, err = fut.result()
results[agent_name] = {"status": "error" if err else "complete", "response": resp, "error": err}
return results
def render_sidebar(specialist_agents, import_error):
debug = st.sidebar.expander("DEBUG-INFORMATIONEN", expanded=False)
with debug:
if import_error:
st.error(f"Koordinator Importfehler: {import_error}")
else:
st.write("**Spezialistenagenten:**")
for idx, agent in enumerate(specialist_agents):
st.write(f"{idx+1}. {getattr(agent, 'name', 'Unknown')} - Typ: {type(agent)}")
st.sidebar.header("Anleitung")
st.sidebar.info(
"Geben Sie den zu korrigierenden Text ein und klicken Sie auf 'Korrektur starten'."
)
st.sidebar.markdown("---")
st.sidebar.header("Konfiguration")
import config
st.sidebar.write(f"**Modellanbieter:** `{config.MODEL_PROVIDER}`")
st.sidebar.write(f"**Modell-ID:** `{config.SELECTED_MODEL_ID}`")
st.sidebar.write(f"**Wörterbuch:** `{config.DICTIONARY_FILE_PATH.name}`")
def handle_coordination_input(coordinator):
if 'coord_chat' not in st.session_state:
st.session_state['coord_chat'] = []
student = st.text_area("Schülerlösung eingeben:", height=200, key="student_solution")
task = st.text_area("Aufgabenbeschreibung für Korrekturassistent:", height=200, key="task_description")
if st.button("Korrektur starten", key="start_coord"):
if coordinator:
st.session_state['coord_chat'] = []
prompt = f"Aufgabenbeschreibung: {task}\n\nSchülerlösung:\n{student}"
with st.spinner("Korrekturassistent läuft..."):
try:
res = coordinator.run(prompt)
st.session_state['coord_chat'].append({'sender':'user','message':prompt})
st.session_state['coord_chat'].append({'sender':'agent','message': getattr(res,'content',str(res))})
except Exception as e:
st.error(f"Fehler beim Korrekturassistent: {e}")
else:
st.error("Korrekturassistent nicht verfügbar.")
def render_coordination_chat():
for entry in st.session_state.get('coord_chat', []):
if entry['sender'] == 'user':
st.markdown(f"👤 **Du:** {entry['message']}")
else:
st.markdown(f"🤖 **Korrekturassistent:** {entry['message']}")
def handle_follow_up(coordinator):
if not st.session_state.get('coord_chat'):
return
if 'chat_mode' not in st.session_state:
st.session_state['chat_mode'] = None
col1, _ = st.columns(2)
with col1:
if st.button("💬 Text-Chat", key="select_text_chat"):
st.session_state['chat_mode'] = 'text'
if st.session_state.get('chat_mode') == 'text':
if 'follow_up' not in st.session_state:
st.session_state['follow_up'] = ''
follow = st.text_input("Nachricht an Korrekturassistent:", key="follow_up", value=st.session_state['follow_up'])
def _send():
if coordinator:
with st.spinner("Korrekturassistent denkt..."):
reply = coordinator.run(st.session_state['follow_up'])
st.session_state['coord_chat'].append({'sender':'user','message':st.session_state['follow_up']})
st.session_state['coord_chat'].append({'sender':'agent','message': getattr(reply,'content',str(reply))})
st.session_state['follow_up'] = ''
else:
st.error("Korrekturassistent nicht verfügbar.")
st.button("Senden", key="send_follow_up", on_click=_send)
def main():
st.set_page_config(layout="wide", page_title="Korrekturassistent")
st.title("📚 Korrekturassistent")
coordinator, agents, err = load_coordinator()
render_sidebar(agents, err)
handle_coordination_input(coordinator)
render_coordination_chat()
handle_follow_up(coordinator)
if __name__ == "__main__":
main()