Spaces:
Running
Running
| # appv1.py | |
| # A RAG rendszer grafikus felhasználói felülete Streamlit segítségével. | |
| # JAVÍTOTT VERZIÓ: A modern, cloud-kompatibilis backendv1.py-hoz igazítva. | |
| import streamlit as st | |
| import sys | |
| import os | |
| # --- Backend Importálása --- | |
| # A backendv1.py-nak ebben a mappában kell lennie. | |
| try: | |
| from backendv1 import ( | |
| initialize_backend, | |
| process_query, | |
| index_feedback, | |
| get_all_feedback, | |
| delete_feedback_by_id, | |
| update_feedback_comment, | |
| CONFIG | |
| ) | |
| except ImportError: | |
| st.error("Hiba: A 'backendv1.py' fájl nem található. Győződj meg róla, hogy ugyanabban a mappában van, mint ez a script.") | |
| st.stop() | |
| # --- Oldal Konfiguráció --- | |
| st.set_page_config(page_title="Dunaelektronika AI", layout="wide") | |
| st.title("🤖 Dunaelektronika AI Asszisztens") | |
| # --- Backend Betöltése (gyorsítótárazva, hogy ne töltődjön be minden interakciónál újra) --- | |
| def load_backend_components(): | |
| """ | |
| Betölti a backendet (AI modellek, DB kapcsolat). | |
| A @st.cache_resource biztosítja, hogy ez a lassú folyamat csak egyszer fusson le. | |
| """ | |
| print("Backend komponensek inicializálása...") | |
| backend_data = initialize_backend() | |
| if backend_data: | |
| print("Backend sikeresen betöltve.") | |
| else: | |
| print("Hiba a backend betöltésekor.") | |
| return backend_data | |
| # Backend betöltése és hibakezelés | |
| backend = load_backend_components() | |
| if not backend: | |
| st.error( | |
| "A háttérrendszer (AI modellek vagy adatbázis kapcsolat) nem tudott elindulni. " | |
| "Ellenőrizd a konzol logját a hiba okáért, és hogy a környezeti változók (pl. .env fájl) helyesen vannak-e beállítva." | |
| ) | |
| st.stop() | |
| # --- Session State Inicializálása (az adatok tárolására a böngészőben) --- | |
| if "messages" not in st.session_state: | |
| st.session_state.messages = [] | |
| if "last_confidence_score" not in st.session_state: | |
| st.session_state.last_confidence_score = "N/A" | |
| if "page" not in st.session_state: | |
| st.session_state.page = "Chat" | |
| # --- Navigáció az Oldalsávon --- | |
| with st.sidebar: | |
| st.header("Menü") | |
| if st.button("💬 Chat", use_container_width=True, type="primary" if st.session_state.page == "Chat" else "secondary"): | |
| st.session_state.page = "Chat" | |
| st.rerun() | |
| if st.button("⚙️ Feedback Adminisztráció", use_container_width=True, type="primary" if st.session_state.page == "Admin" else "secondary"): | |
| st.session_state.page = "Admin" | |
| st.rerun() | |
| st.write("---") | |
| # ============================================================================== | |
| # = CHAT OLDAL LOGIKÁJA = | |
| # ============================================================================== | |
| if st.session_state.page == "Chat": | |
| with st.sidebar: | |
| st.header("Beállítások") | |
| confidence_threshold = st.slider("Minimális pontossági küszöb", min_value=-5.0, max_value=5.0, value=0.1, step=0.1) | |
| fallback_message = st.text_area("Válasz alacsony pontosságnál", "A rendelkezésre álló információk alapján sajnos nem tudok egyértelmű választ adni a kérdésre.", height=100) | |
| CONFIG["GENERATION_TEMPERATURE"] = st.slider("Kreativitás (Temperature)", 0.0, 1.0, 0.6, 0.05) | |
| st.write("---") | |
| st.subheader("Utolsó Válasz Elemzése") | |
| score = st.session_state.last_confidence_score | |
| if score == "N/A": | |
| level, help_text = "N/A", "Tegyen fel egy kérdést a megbízhatóság méréséhez." | |
| elif score is None: | |
| level, help_text = "Alap Rangsor (RRF)", "A Cross-Encoder bizonytalan volt." | |
| elif score == 10.0: | |
| level, help_text = "Kurált Válasz", "Ez egy korábban megadott, pontosított válasz." | |
| else: | |
| help_text = f"Nyers pontszám: {score:.4f}" | |
| if score > 1.0: level = "Magas" | |
| elif score >= -1.5: level = "Közepes" | |
| else: level = "Alacsony" | |
| st.metric(label="Keresési Magabiztosság", value=level, help=help_text) | |
| # Chat Előzmények Megjelenítése | |
| for i, message in enumerate(st.session_state.messages): | |
| with st.chat_message(message["role"]): | |
| st.markdown(message["content"].replace('$', '\\$')) | |
| if message["role"] == "assistant": | |
| score_value = message.get("score") | |
| if score_value is not None: | |
| score_display = "Kurált válasz (legmagasabb)" if score_value == 10.0 else f"{score_value:.4f}" | |
| st.caption(f"A válasz legjobb score értéke: **{score_display}**") | |
| if message.get("sources"): | |
| with st.expander("Felhasznált források"): | |
| for source in message["sources"]: | |
| st.caption(f"Forrás: {source.get('url', 'N/A')}") | |
| st.markdown(f"> {source.get('content', '')[:250]}...") | |
| feedback_key_prefix = f"feedback_{i}" | |
| if not message.get("rated"): | |
| st.write("---") | |
| cols = st.columns(7) | |
| if cols[0].button("👍 Jó", key=f"{feedback_key_prefix}_good"): | |
| message["rated"] = "good"; st.toast("Köszönjük a visszajelzést!"); st.rerun() | |
| if cols[1].button("👎 Rossz", key=f"{feedback_key_prefix}_bad"): | |
| message["rated"] = "bad"; st.rerun() | |
| if message.get("rated") == "bad": | |
| with st.form(key=f"{feedback_key_prefix}_form"): | |
| correction_text = st.text_area("Javítás:", key=f"{feedback_key_prefix}_text", value=message.get("correction", "")) | |
| if st.form_submit_button("Javítás elküldése"): | |
| index_feedback(backend["es_client"], backend["embedding_model"], message["original_question"], correction_text) | |
| st.success("Javításodat rögzítettük!"); message["rated"] = "corrected"; st.rerun() | |
| # Felhasználói Kérdés Feldolgozása | |
| if prompt := st.chat_input("Kérdezz valamit a Dunaelektronikáról..."): | |
| st.session_state.messages.append({"role": "user", "content": prompt}) | |
| with st.spinner("Keresek és gondolkodom..."): | |
| response_data = process_query(prompt, st.session_state.messages, backend, confidence_threshold, fallback_message) | |
| st.session_state.last_confidence_score = response_data.get("confidence_score") | |
| st.session_state.messages.append({ | |
| "role": "assistant", | |
| "content": response_data.get("answer", "Hiba történt."), | |
| "sources": response_data.get("sources", []), | |
| "original_question": prompt, | |
| "rated": False, | |
| "score": response_data.get("confidence_score") | |
| }) | |
| st.rerun() | |
| # ============================================================================== | |
| # = ADMIN OLDAL LOGIKÁJA = | |
| # ============================================================================== | |
| elif st.session_state.page == "Admin": | |
| st.header("Rögzített Visszajelzések Kezelése") | |
| if st.button("Lista frissítése"): | |
| st.cache_data.clear() | |
| def get_cached_feedback(): | |
| return get_all_feedback(backend["es_client"], CONFIG["FEEDBACK_INDEX_NAME"]) | |
| feedback_list = get_cached_feedback() | |
| if not feedback_list: | |
| st.warning("Nincsenek rögzített visszajelzések.") | |
| else: | |
| st.info(f"Összesen {len(feedback_list)} visszajelzés található.") | |
| for item in feedback_list: | |
| doc_id = item["_id"] | |
| source = item["_source"] | |
| with st.container(border=True): | |
| st.markdown(f"**Kérdés:** `{source.get('question_text', 'N/A')}`") | |
| with st.form(key=f"edit_form_{doc_id}"): | |
| new_comment = st.text_area("Javítás/Megjegyzés:", value=source.get('correction_text', ''), key=f"text_{doc_id}", label_visibility="collapsed") | |
| col1, col2 = st.columns([4, 1]) | |
| with col1: | |
| if st.form_submit_button("💾 Mentés"): | |
| if update_feedback_comment(backend["es_client"], CONFIG["FEEDBACK_INDEX_NAME"], doc_id, new_comment): | |
| st.success("Sikeresen frissítve!"); st.cache_data.clear(); st.rerun() | |
| else: st.error("Hiba történt a frissítés során.") | |
| with col2: | |
| if st.form_submit_button("🗑️ Törlés"): | |
| if delete_feedback_by_id(backend["es_client"], CONFIG["FEEDBACK_INDEX_NAME"], doc_id): | |
| st.success(f"Sikeresen törölve!"); st.cache_data.clear(); st.rerun() | |
| else: st.error("Hiba történt a törlés során.") | |
| st.caption(f"Elasticsearch ID: {doc_id} | Időbélyeg: {source.get('timestamp', 'N/A')}") | |