296 lines
12 KiB
Python

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, LANGUAGE_MAPPING
from utils.katex_script import KATEX_CSS_JS
def update_ui_language_elements(language):
"""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,
reset_conversation_fn,
change_model_fn,
change_collection_fn,
update_ui_language_fn
):
"""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:
title_md = gr.Markdown(f"# {ui_elements['title']}")
with gr.Row():
with gr.Column(scale=2):
chat_interface = gr.Chatbot(
height=600,
show_label=False,
layout="bubble",
elem_id="chatbot",
type="messages" # Ajoutez cette ligne
)
with gr.Row():
msg = gr.Textbox(
show_label=False,
placeholder=ui_elements['placeholder'],
container=False,
scale=4
)
submit_btn = gr.Button(ui_elements['send_btn'], variant="primary", scale=1)
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 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=ui_elements['model_label'],
info=ui_elements['model_info']
)
model_status = gr.Markdown(f"{ui_elements['model_current_prefix']}: **{DEFAULT_MODEL}**")
# Sélecteur de langue pour les réponses
language_selector = gr.Dropdown(
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=ui_elements['collection_label'],
info=ui_elements['collection_info']
)
collection_status = gr.Markdown(f"{ui_elements['collection_current_prefix']}: **{QDRANT_COLLECTION_NAME}**")
# Bouton pour appliquer la collection
apply_collection_btn = gr.Button(ui_elements['apply_btn'])
# Options de streaming et sources
streaming = gr.Checkbox(
label=ui_elements['streaming_label'],
value=True,
info=ui_elements['streaming_info']
)
show_sources = gr.Checkbox(label=ui_elements['sources_label'], value=True)
max_images = gr.Slider(
minimum=1,
maximum=10,
value=3,
step=1,
label=ui_elements['max_images_label']
)
gr.Markdown("---")
images_title = gr.Markdown(f"### {ui_elements['images_title']}")
image_gallery = gr.Gallery(
label=ui_elements['images_title'],
show_label=False,
columns=2,
height=300,
object_fit="contain"
)
tables_title = gr.Markdown(f"### {ui_elements['tables_title']}")
tables_display = gr.HTML()
# 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
def clear_input():
return ""
# Configuration des actions principales
msg.submit(
process_query_fn,
inputs=[msg, chat_interface, streaming, show_sources, max_images, language_selector],
outputs=[chat_interface, source_info, image_gallery, tables_display]
).then(clear_input, None, msg)
submit_btn.click(
process_query_fn,
inputs=[msg, chat_interface, streaming, show_sources, max_images, language_selector],
outputs=[chat_interface, source_info, image_gallery, tables_display]
).then(clear_input, None, msg)
clear_btn.click(
reset_conversation_fn,
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>
.gradio-container {max-width: 1200px !important}
#chatbot {height: 600px; overflow-y: auto;}
#sources_info {margin-top: 10px; color: #666;}
/* Improved styles for equations */
.katex { font-size: 1.1em !important; }
.math-inline { background: #f8f9fa; padding: 2px 5px; border-radius: 4px; }
.math-display { background: #f8f9f9; margin: 10px 0; padding: 10px; border-radius: 5px; overflow-x: auto; text-align: center; }
/* Table styles */
table {
border-collapse: collapse;
width: 100%;
margin: 15px 0;
font-size: 0.9em;
}
table, th, td {
border: 1px solid #ddd;
}
th, td {
padding: 8px 12px;
text-align: left;
}
th {
background-color: #f2f2f2;
}
tr:nth-child(even) {
background-color: #f9f9f9;
}
.table-container {
overflow-x: auto;
margin-top: 10px;
}
</style>
<!-- Loading KaTeX -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.css">
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/katex.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/katex@0.16.8/dist/contrib/auto-render.min.js"></script>
<script>
// Script pour rendre les équations mathématiques avec KaTeX
document.addEventListener('DOMContentLoaded', function() {
setTimeout(function() {
if (window.renderMathInElement) {
renderMathInElement(document.body, {
delimiters: [
{left: '$$', right: '$$', display: true},
{left: '$', right: '$', display: false}
],
throwOnError: false
});
}
}, 1000);
});
</script>
""")
return interface