Update UI language handling and improve .gitignore for Python artifacts

This commit is contained in:
2025-03-09 09:06:54 +01:00
parent cb43b1176f
commit 9d142c269d
7 changed files with 705 additions and 88 deletions

View File

@@ -155,9 +155,36 @@ def change_collection(collection_name, language="Français"):
return f"❌ Erreur: {str(e)}"
# Fonction de traitement de requête
def convert_to_messages_format(history):
"""Convertit différents formats d'historique au format messages."""
messages = []
# Vérifier si nous avons déjà le format messages
if history and isinstance(history[0], dict) and "role" in history[0]:
return history
# Format tuples [(user_msg, assistant_msg), ...]
try:
for item in history:
if isinstance(item, tuple) and len(item) == 2:
user_msg, assistant_msg = item
messages.append({"role": "user", "content": user_msg})
if assistant_msg: # Éviter les messages vides
messages.append({"role": "assistant", "content": assistant_msg})
except ValueError:
# Journaliser l'erreur pour le débogage
print(f"Format d'historique non reconnu: {history}")
# Retourner un historique vide en cas d'erreur
return []
return messages
def process_query(message, history, streaming, show_sources, max_images, language):
global current_images, current_tables
# Debug plus clair
print(f"Langue sélectionnée pour la réponse: {language} -> {LANGUAGE_MAPPING.get(language, 'français')}")
if not message.strip():
return history, "", None, None
@@ -168,8 +195,10 @@ def process_query(message, history, streaming, show_sources, max_images, languag
try:
if streaming:
# Version avec streaming dans Gradio
history = history + [(message, "")]
# Convertir history en format messages pour l'affichage
messages_history = convert_to_messages_format(history)
messages_history.append({"role": "user", "content": message})
messages_history.append({"role": "assistant", "content": ""})
# 1. Récupérer les documents pertinents
docs = rag_bot._retrieve_relevant_documents(message)
@@ -180,50 +209,39 @@ def process_query(message, history, streaming, show_sources, max_images, languag
# 3. Préparer le prompt
prompt_template = ChatPromptTemplate.from_template("""
Tu es un assistant documentaire spécialisé qui utilise toutes les informations disponibles dans le contexte fourni.
Tu es un assistant documentaire spécialisé qui utilise le contexte fourni.
TRÈS IMPORTANT: Tu dois répondre EXCLUSIVEMENT en {language}. Ne réponds JAMAIS dans une autre langue.
===== INSTRUCTION CRUCIALE SUR LA LANGUE =====
RÉPONDS UNIQUEMENT EN {language}. C'est une exigence ABSOLUE.
NE RÉPONDS JAMAIS dans une autre langue que {language}, quelle que soit la langue de la question.
==============================================
Instructions spécifiques:
1. Pour chaque image mentionnée dans le contexte, inclue TOUJOURS dans ta réponse:
- La légende/caption exacte de l'image
- La source et le numéro de page
- Une description brève de ce qu'elle montre
2. Pour chaque tableau mentionné dans le contexte, inclue TOUJOURS:
- Le titre/caption exact du tableau
- La source et le numéro de page
- Ce que contient et signifie le tableau
3. Lorsque tu cites des équations mathématiques:
- Utilise la syntaxe LaTeX exacte comme dans le document ($...$ ou $$...$$)
- Reproduis-les fidèlement sans modification
4. IMPORTANT: Ne pas inventer d'informations - si une donnée n'est pas explicitement fournie dans le contexte,
indique clairement que cette information n'est pas disponible dans les documents fournis.
5. Cite précisément les sources pour chaque élément d'information (format: [Source, Page]).
6. CRUCIAL: Ta réponse doit être UNIQUEMENT et INTÉGRALEMENT en {language}, quelle que soit la langue de la question.
1. Pour chaque image mentionnée: inclure la légende, source, page et description
2. Pour chaque tableau: inclure titre, source, page et signification
3. Pour les équations: utiliser la syntaxe LaTeX exacte
4. Ne pas inventer d'informations hors du contexte fourni
5. Citer précisément les sources
Historique de conversation:
{chat_history}
Contexte (à utiliser pour répondre):
Contexte:
{context}
Question: {question}
Réponds de façon structurée et précise en intégrant activement les images, tableaux et équations disponibles dans le contexte.
Ta réponse doit être exclusivement en {language}.
Réponds de façon structurée en intégrant les images, tableaux et équations disponibles.
TA RÉPONSE DOIT ÊTRE UNIQUEMENT ET ENTIÈREMENT EN {language}. CETTE RÈGLE EST ABSOLUE.
""")
# 4. Formater les messages pour le LLM
# Assurer que la langue est bien passée dans le format du prompt
selected_language = LANGUAGE_MAPPING.get(language, "français")
messages = prompt_template.format_messages(
chat_history=history_text,
context=context,
question=message,
language=LANGUAGE_MAPPING.get(language, "français")
language=selected_language
)
# 5. Créer un handler de streaming personnalisé
@@ -255,8 +273,9 @@ def process_query(message, history, streaming, show_sources, max_images, languag
# Nettoyer la réponse uniquement pour l'affichage (pas pour l'historique interne)
clean_response = clean_llm_response(partial_response)
history[-1] = (message, clean_response)
yield history, "", None, None
# Mettre à jour le dernier message (assistant)
messages_history[-1]["content"] = clean_response
yield messages_history, "", None, None
except queue.Empty:
continue
@@ -310,17 +329,25 @@ def process_query(message, history, streaming, show_sources, max_images, languag
# 13. Retourner les résultats finaux
images_display = display_images()
tables_display = display_tables()
yield history, source_info, images_display, tables_display
yield messages_history, source_info, images_display, tables_display
else:
# Version sans streaming
print("Mode non-streaming activé")
source_info = ""
result = rag_bot.chat(message, stream=False)
result = rag_bot.chat(
message,
stream=False,
language=LANGUAGE_MAPPING.get(language, "français") # Vérifiez que cette ligne existe
)
# Nettoyer la réponse des balises <think>
result["response"] = clean_llm_response(result["response"])
history = history + [(message, result["response"])]
# Convertir l'historique au format messages
messages_history = convert_to_messages_format(history)
messages_history.append({"role": "user", "content": message})
messages_history.append({"role": "assistant", "content": result["response"]})
# Mise à jour de l'historique interne
rag_bot.chat_history.append({"role": "user", "content": message})
@@ -364,7 +391,7 @@ def process_query(message, history, streaming, show_sources, max_images, languag
"description": table.get("description", "")
})
yield history, source_info, display_images(), display_tables()
yield messages_history, source_info, display_images(), display_tables()
except Exception as e:
error_msg = f"Une erreur est survenue: {str(e)}"
@@ -382,4 +409,5 @@ def reset_conversation():
rag_bot.clear_history()
# Retourner une liste vide au format messages
return [], "", None, None

View File

@@ -1,11 +1,58 @@
import gradio as gr
from config.settings import DEFAULT_MODEL, QDRANT_COLLECTION_NAME, AVAILABLE_MODELS
from translations.lang_mappings import UI_TRANSLATIONS, UI_SUPPORTED_LANGUAGES
from translations.lang_mappings import UI_TRANSLATIONS, UI_SUPPORTED_LANGUAGES, LANGUAGE_MAPPING
from utils.katex_script import KATEX_CSS_JS
def update_ui_language_elements(language):
"""Met à jour les éléments de l'interface utilisateur en fonction de la langue sélectionnée"""
pass # Implémentez selon vos besoins
"""Met à jour tous les éléments de l'interface avec la langue sélectionnée"""
# Vérifier si la langue est supportée par l'interface
if language not in UI_SUPPORTED_LANGUAGES:
language = "Français" # Langue par défaut
# Récupérer les traductions pour la langue sélectionnée
translations = UI_TRANSLATIONS[language]
# Créer un dictionnaire pour stocker tous les éléments modifiés
ui_elements = {}
# Mettre à jour le titre
ui_elements["title"] = translations["title"]
# Mettre à jour le placeholder et les boutons
ui_elements["placeholder"] = translations["placeholder"]
ui_elements["send_btn"] = translations["send_btn"]
ui_elements["clear_btn"] = translations["clear_btn"]
# Ajouter les traductions pour la langue de l'interface
ui_elements["ui_language_label"] = translations["ui_language_label"]
ui_elements["ui_language_info"] = translations["ui_language_info"]
# Mettre à jour les libellés des options
ui_elements["options_label"] = "Options" # Ce texte pourrait aussi être traduit
ui_elements["model_label"] = translations["model_selector"]
ui_elements["model_info"] = translations["model_info"]
ui_elements["model_current_prefix"] = translations["model_current"]
ui_elements["language_label"] = translations["language_selector"]
ui_elements["language_info"] = translations["language_info"]
ui_elements["collection_label"] = translations["collection_input"]
ui_elements["collection_info"] = translations["collection_info"]
ui_elements["collection_current_prefix"] = translations["collection_current"]
ui_elements["apply_btn"] = translations["apply_btn"]
ui_elements["streaming_label"] = translations["streaming_label"]
ui_elements["streaming_info"] = translations["streaming_info"]
ui_elements["sources_label"] = translations["sources_label"]
ui_elements["max_images_label"] = translations["max_images_label"]
ui_elements["images_title"] = translations["images_title"]
ui_elements["tables_title"] = translations["tables_title"]
return ui_elements
def build_interface(
process_query_fn,
@@ -14,102 +61,139 @@ def build_interface(
change_collection_fn,
update_ui_language_fn
):
"""Construit l'interface utilisateur avec Gradio."""
"""Construit l'interface utilisateur avec Gradio"""
print("Initialisation de l'interface")
print("AVAILABLE_MODELS chargé dans ui.py:", AVAILABLE_MODELS)
# Initialiser avec la langue par défaut (Français)
ui_elements = update_ui_language_elements("Français")
with gr.Blocks(css=KATEX_CSS_JS, theme=gr.themes.Soft(primary_hue="blue")) as interface:
gr.Markdown("# 📚 Assistant documentaire intelligent")
title_md = gr.Markdown(f"# {ui_elements['title']}")
with gr.Row():
with gr.Column(scale=2):
# Chatbot principal
chat_interface = gr.Chatbot(
height=600,
show_label=False,
layout="bubble",
elem_id="chatbot"
elem_id="chatbot",
type="messages" # Ajoutez cette ligne
)
with gr.Row():
msg = gr.Textbox(
show_label=False,
placeholder="Posez votre question...",
placeholder=ui_elements['placeholder'],
container=False,
scale=4
)
submit_btn = gr.Button("Envoyer", variant="primary", scale=1)
submit_btn = gr.Button(ui_elements['send_btn'], variant="primary", scale=1)
clear_btn = gr.Button("Effacer la conversation")
clear_btn = gr.Button(ui_elements['clear_btn'])
source_info = gr.Markdown("", elem_id="sources_info")
with gr.Column(scale=1):
with gr.Accordion("Options", open=True):
# Sélecteur de modèle
# Sélecteur de langue pour l'interface
language_ui_selector = gr.Dropdown(
choices=UI_SUPPORTED_LANGUAGES,
value="Français",
label=ui_elements['ui_language_label'], # Utiliser une clé différente
info=ui_elements['ui_language_info']
)
# Sélecteur de modèle - assurez-vous que cette section est présente
model_selector = gr.Dropdown(
choices=AVAILABLE_MODELS,
value=DEFAULT_MODEL,
label="Modèle Ollama",
info="Choisir le modèle de language à utiliser"
label=ui_elements['model_label'],
info=ui_elements['model_info']
)
model_status = gr.Markdown(f"Modèle actuel: **{DEFAULT_MODEL}**")
model_status = gr.Markdown(f"{ui_elements['model_current_prefix']}: **{DEFAULT_MODEL}**")
# Sélecteur de langue
# Sélecteur de langue pour les réponses
language_selector = gr.Dropdown(
choices=UI_SUPPORTED_LANGUAGES,
value=UI_SUPPORTED_LANGUAGES[0],
label="Langue des réponses",
info="Choisir la langue dans laquelle l'assistant répondra"
choices=list(LANGUAGE_MAPPING.keys()),
value="Français",
label=ui_elements['language_label'],
info=ui_elements['language_info']
)
# Sélecteur de collection Qdrant
collection_name_input = gr.Textbox(
value=QDRANT_COLLECTION_NAME,
label="Collection Qdrant",
info="Nom de la collection de documents à utiliser"
label=ui_elements['collection_label'],
info=ui_elements['collection_info']
)
collection_status = gr.Markdown(f"Collection actuelle: **{QDRANT_COLLECTION_NAME}**")
collection_status = gr.Markdown(f"{ui_elements['collection_current_prefix']}: **{QDRANT_COLLECTION_NAME}**")
# Bouton d'application de la collection
apply_collection_btn = gr.Button("Appliquer la collection")
# Bouton pour appliquer la collection
apply_collection_btn = gr.Button(ui_elements['apply_btn'])
# Options de streaming et sources
streaming = gr.Checkbox(
label="Mode streaming",
label=ui_elements['streaming_label'],
value=True,
info="Voir les réponses s'afficher progressivement"
info=ui_elements['streaming_info']
)
show_sources = gr.Checkbox(label="Afficher les sources", value=True)
show_sources = gr.Checkbox(label=ui_elements['sources_label'], value=True)
max_images = gr.Slider(
minimum=1,
maximum=10,
value=3,
step=1,
label="Nombre max d'images"
label=ui_elements['max_images_label']
)
gr.Markdown("---")
gr.Markdown("### 🖼️ Images pertinentes")
images_title = gr.Markdown(f"### {ui_elements['images_title']}")
image_gallery = gr.Gallery(
label="Images pertinentes",
label=ui_elements['images_title'],
show_label=False,
columns=2,
height=300,
object_fit="contain"
)
gr.Markdown("### 📊 Tableaux")
tables_title = gr.Markdown(f"### {ui_elements['tables_title']}")
tables_display = gr.HTML()
# Connecter le changement de modèle
model_selector.change(
fn=change_model_fn,
inputs=model_selector,
outputs=model_status
)
# Connecter le changement de collection
apply_collection_btn.click(
fn=change_collection_fn,
inputs=collection_name_input,
outputs=collection_status
# Ajouter cette fonction juste avant de connecter le changement de langue
def preserve_models_wrapper(language):
"""Préserve la liste des modèles lors du changement de langue"""
# Obtenir les mises à jour depuis la fonction d'origine
updates = update_ui_language_fn(language)
# Force la liste complète des modèles disponibles (position 5 dans les sorties)
# Cela garantit que quelles que soient les mises à jour, la liste des modèles reste intacte
if isinstance(updates[5], dict) and "choices" in updates[5]:
print("Préservation de la liste des modèles:", AVAILABLE_MODELS)
updates[5]["choices"] = AVAILABLE_MODELS
return updates
# Puis modifier la connexion du language_ui_selector.change comme suit :
language_ui_selector.change(
fn=preserve_models_wrapper, # Utiliser notre wrapper au lieu de la fonction directe
inputs=language_ui_selector,
outputs=[
title_md,
msg,
submit_btn,
clear_btn,
language_ui_selector,
model_selector,
model_status,
language_selector,
collection_name_input,
collection_status,
apply_collection_btn,
streaming,
show_sources,
max_images,
images_title,
tables_title
]
)
# Fonction pour effacer l'entrée
@@ -134,6 +218,20 @@ def build_interface(
outputs=[chat_interface, source_info, image_gallery, tables_display]
)
# Connecter le changement de modèle
model_selector.change(
fn=change_model_fn,
inputs=model_selector,
outputs=model_status
)
# Connecter le changement de collection
apply_collection_btn.click(
fn=change_collection_fn,
inputs=collection_name_input,
outputs=collection_status
)
# Style KaTeX et amélioration du design
gr.Markdown("""
<style>