""" app.py — RoCodex (Streamlit version) ──────────────────────────────────────── Run locally: streamlit run app.py Deploy to HuggingFace Spaces: - Set SDK to "Streamlit" in your Space settings - Upload this file + rag.py + data/ folder - Set GROQ_API_KEY as a Space secret Install: pip install streamlit groq """ import os import random import streamlit as st from rag import answer as rag_answer # ── Page config ─────────────────────────────────────────────────────────────── st.set_page_config( page_title="RoCodex — Asistent Juridic", page_icon="⚖️", layout="centered", ) GROQ_API_KEY = os.environ.get("GROQ_API_KEY", "") # ── SVG logo ────────────────────────────────── # Used in: hero screen, sidebar, assistant chat avatar BASE_DIR = os.path.dirname(os.path.abspath(__file__)) with open(os.path.join(BASE_DIR, "app_logo.svg"), "r", encoding="utf-8") as f: LOGO_SVG = f.read() import base64 LOGO_B64 = base64.b64encode(LOGO_SVG.encode()).decode() LOGO_URI = f"data:image/svg+xml;base64,{LOGO_B64}" # ── Welcome messages ────────────────────────────────────────────────────────── WELCOME_MESSAGES = [ "Bine ai venit! Pune orice întrebare despre legislația română.", "Salut! Sunt aici să te ajut să înțelegi legile din România.", "Salut! Întreabă-mă orice despre drepturile tale legale.", "Salut! Explorează legislația română cu ajutorul meu.", ] EXAMPLES = [ "Ce drepturi are un salariat la concediu de odihnă?", "Care sunt obligațiile angajatorului față de salariat?", "Ce este prezumția de nevinovăție?", "Cum se calculează indemnizația de concediu?", ] # ── CSS ─────────────────────────────────────────────────────────────────────── st.markdown(f""" """, unsafe_allow_html=True) # ── Sidebar ─────────────────────────────────────────────────────────────────── with st.sidebar: st.markdown(f"""
RoCodex logo
RoCodex
""", unsafe_allow_html=True) st.divider() api_key = st.text_input( "🔑 Groq API Key", value=GROQ_API_KEY, type="password", placeholder="gsk_...", help="Cheie gratuită la console.groq.com", ) st.caption("Cheia nu este salvată nicăieri.") st.divider() st.markdown(""" **Legislație acoperită:** - 📋 Codul Muncii - 📋 Codul Civil - ⚖️ Codul Penal - 🏛️ Cod Procedură Civilă - 🏛️ Cod Procedură Penală - 🏢 Legea Societăților """) st.divider() st.caption( "⚠️ RoCodex oferă informații juridice generale. " "Nu constituie consultanță juridică. " "Consultați un avocat pentru situații specifice." ) # ── Session state ───────────────────────────────────────────────────────────── if "messages" not in st.session_state: # Each message: {"role": "user"|"assistant", "content": str, "sources": list|None} st.session_state.messages = [] if "welcome_msg" not in st.session_state: st.session_state.welcome_msg = random.choice(WELCOME_MESSAGES) # ── Helper: render one assistant message (text + collapsible sources) ───────── def render_assistant(content: str, sources: list): st.markdown(content) if sources: with st.expander("📚 Surse folosite", expanded=False): for i, src in enumerate(sources, 1): score_pct = int(src["score"] * 100) st.markdown( f"**[{i}] {src['law_title']} — {src['article_number']}** " f"`{score_pct}% relevanță`" ) st.caption( src["text"][:300] + ("…" if len(src["text"]) > 300 else "") ) if i < len(sources): st.divider() # ── HERO SCREEN ─────────────────────────────────────────────────────────────── if not st.session_state.messages: st.markdown(f"""
RoCodex
Asistent juridic bazat pe legislația română
{st.session_state.welcome_msg}
""", unsafe_allow_html=True) st.markdown("**Încearcă una din întrebările de mai jos:**") cols = st.columns(2) for i, example in enumerate(EXAMPLES): with cols[i % 2]: if st.button(example, key=f"ex_{i}", use_container_width=True): st.session_state.prefill = example st.rerun() # ── CHAT SCREEN ─────────────────────────────────────────────────────────────── else: for msg in st.session_state.messages: if msg["role"] == "user": with st.chat_message("user"): st.markdown(msg["content"]) else: with st.chat_message("assistant"): render_assistant(msg["content"], msg.get("sources", [])) # ── Chat input ──────────────────────────────────────────────────────────────── prefill_value = st.session_state.pop("prefill", "") user_input = st.chat_input("Scrie întrebarea ta juridică...") question = user_input or prefill_value if question: question = question.strip() # Save & display user message st.session_state.messages.append({ "role": "user", "content": question, "sources": None }) # Check key key = api_key.strip() if api_key.strip() else GROQ_API_KEY if not key: st.session_state.messages.append({ "role": "assistant", "content": "⚠️ Lipsește Groq API key. Introdu cheia în sidebar.", "sources": [], }) st.rerun() # Call RAG with st.spinner("Caut în legislație..."): try: result = rag_answer(question, groq_api_key=key) reply = result["answer"] sources = result["sources"] except Exception as e: reply = f"❌ Eroare: {e}" sources = [] # Save assistant message WITH sources separately st.session_state.messages.append({ "role": "assistant", "content": reply, "sources": sources, }) st.rerun()