File size: 6,425 Bytes
44a12cc
43f2b89
 
 
 
 
 
 
 
 
 
 
44a12cc
43f2b89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44a12cc
43f2b89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44a12cc
 
 
43f2b89
44a12cc
 
43f2b89
 
 
 
 
44a12cc
43f2b89
 
44a12cc
43f2b89
 
 
 
1965e4e
 
 
 
 
c410f41
 
 
 
 
 
 
 
 
 
 
43f2b89
 
c410f41
43f2b89
 
 
44a12cc
43f2b89
44a12cc
 
43f2b89
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
44a12cc
43f2b89
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
import streamlit as st
import pandas as pd
from datetime import datetime
from RAG import answer_question, retrieve_chunks, embed_question, build_context

# Configuration de la page
st.set_page_config(
    page_title="Tindle RAG Chat", 
    page_icon="💬", 
    layout="wide",
    initial_sidebar_state="expanded"
)

# CSS personnalisé pour le thème
st.markdown("""
<style>
    .stApp {
        background-color: var(--background-color);
    }
    .chat-message {
        padding: 1rem;
        border-radius: 0.5rem;
        margin-bottom: 1rem;
        border: 1px solid var(--border-color);
    }
    .source-preview {
        background-color: var(--secondary-background-color);
        padding: 0.5rem;
        border-radius: 0.25rem;
        margin: 0.5rem 0;
        border-left: 3px solid #1f77b4;
    }
    .export-button {
        margin: 1rem 0;
    }
</style>
""", unsafe_allow_html=True)

# Sidebar pour les paramètres
with st.sidebar:
    st.title("⚙️ Paramètres")
    
    # Sélecteur de thème
    theme = st.selectbox(
        "🎨 Thème",
        ["Clair", "Sombre"],
        index=0
    )
    
    # Appliquer le thème
    if theme == "Sombre":
        st.markdown("""
        <style>
            .stApp {
                background-color: #0e1117;
                color: #fafafa;
            }
            .stChatMessage {
                background-color: #262730;
            }
        </style>
        """, unsafe_allow_html=True)
    
    # Paramètres RAG
    st.subheader("🔍 Paramètres de recherche")
    top_k = st.slider("Nombre de passages à récupérer", 5, 20, 10)
    show_sources = st.checkbox("Afficher les sources", value=True)
    
    # Statistiques
    st.subheader("📊 Statistiques")
    if "messages" in st.session_state:
        st.metric("Questions posées", len([m for m in st.session_state["messages"] if m["role"] == "user"]))
    
    # Bouton de réinitialisation
    if st.button("🗑️ Effacer l'historique"):
        st.session_state["messages"] = []
        st.session_state["sources"] = []
        st.rerun()

# Titre principal
st.title("💬 Tindle RAG Chat")
st.markdown("Posez une question sur le droit fiscal, l'assistant RAG vous répondra en s'appuyant sur les sources indexées.")

# Initialisation des variables de session
if "messages" not in st.session_state:
    st.session_state["messages"] = []
if "sources" not in st.session_state:
    st.session_state["sources"] = []

# Affichage de l'historique du chat avec sources
for i, msg in enumerate(st.session_state["messages"]):
    if msg["role"] == "user":
        with st.chat_message("user"):
            st.markdown(msg["content"])
    else:
        with st.chat_message("assistant"):
            st.markdown(msg["content"])
            
            # Afficher les sources si disponibles et demandées
            # Correction de l'index : on cherche les sources pour cette réponse spécifique
            source_index = len([m for m in st.session_state["messages"][:i] if m["role"] == "assistant"])
            if show_sources and source_index < len(st.session_state["sources"]) and st.session_state["sources"][source_index]:
                with st.expander(f"📚 Sources utilisées ({len(st.session_state['sources'][source_index])} passages)"):
                    for j, source in enumerate(st.session_state["sources"][source_index], 1):
                        # Construire la section métadonnées
                        metadata_parts = []
                        for key, value in source["metadata"].items():
                            metadata_parts.append(f"{key}: {value}")
                        
                        metadata_str = f" | ".join(metadata_parts) if metadata_parts else ""
                        source_info = f"<strong>Source {j}:</strong> {source['id']}"
                        if metadata_str:
                            source_info += f" | {metadata_str}"
                        source_info += f" <em>(score: {source['score']:.3f})</em>"
                        
                        st.markdown(f"""
                        <div class="source-preview">
                        {source_info}<br>
                        {source['text']}
                        </div>
                        """, unsafe_allow_html=True)

# Saisie utilisateur avec indicateurs de chargement détaillés
if prompt := st.chat_input("Votre question..."):
    st.session_state["messages"].append({"role": "user", "content": prompt})
    
    # Affichage des étapes de traitement
    progress_bar = st.progress(0)
    status_text = st.empty()
    
    try:
        # Étape 1: Embedding
        status_text.text("🔄 Création de l'embedding de la question...")
        progress_bar.progress(25)
        q_emb = embed_question(prompt)
        
        # Étape 2: Récupération des passages
        status_text.text("🔍 Recherche des passages pertinents...")
        progress_bar.progress(50)
        top_chunks = retrieve_chunks(q_emb, top_k)
        st.session_state["sources"].append(top_chunks)
        
        # Étape 3: Construction du contexte
        status_text.text("📝 Construction du contexte...")
        progress_bar.progress(75)
        context = build_context(top_chunks)
        
        # Étape 4: Génération de la réponse
        status_text.text("🤖 Génération de la réponse...")
        progress_bar.progress(90)
        response = answer_question(prompt, top_k)
        
        # Finalisation
        progress_bar.progress(100)
        status_text.text("✅ Réponse générée avec succès!")
        
        st.session_state["messages"].append({"role": "assistant", "content": response})
        
    except Exception as e:
        status_text.text("❌ Erreur lors du traitement")
        response = f"Erreur lors de l'appel au RAG : {e}"
        st.session_state["messages"].append({"role": "assistant", "content": response})
        st.session_state["sources"].append([])
    
    # Nettoyage des indicateurs
    progress_bar.empty()
    status_text.empty()
    
    st.rerun()

# Footer avec informations
st.markdown("---")
st.markdown("""
<div style='text-align: center; color: #666;'>
    <small>
        💡 Conseil: Plus votre question est précise, plus la réponse sera pertinente.<br>
        🔍 Les sources utilisées sont affichées pour chaque réponse.
    </small>
</div>
""", unsafe_allow_html=True)