Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import os | |
| # from llama_cpp import Llama # Nous n'utilisons plus llama-cpp-python | |
| # from ctransformers import AutoModelForCausalLM # Pas nécessaire pour l'intégration LangChain | |
| from langchain_community.llms import CTransformers # Correction de la dépréciation | |
| from langchain_community.vectorstores import FAISS | |
| from langchain_community.embeddings import HuggingFaceEmbeddings | |
| from langchain.docstore.document import Document | |
| import logging | |
| # Configuration du logging pour un meilleur débogage | |
| logging.basicConfig(level=logging.INFO) | |
| logger = logging.getLogger(__name__) | |
| # --- Configuration de la page Streamlit --- | |
| st.set_page_config(page_title="Votre Coach RAG", layout="wide") | |
| st.title("Votre Coach Expert") | |
| st.write("Posez une question sur vos documents, et je vous répondrai en me basant sur leur contenu.") | |
| # --- Fonctions de chargement mises en cache --- | |
| # Patch pour un problème de désérialisation | |
| def custom_setstate(self, state): | |
| if "__fields_set__" in state: | |
| del state["__fields_set__"] | |
| self.__dict__.update(state) | |
| Document.__setstate__ = custom_setstate | |
| def load_llm(): | |
| """ | |
| Charge le modèle LLM directement depuis le Hub Hugging Face. | |
| La configuration du cache est gérée par les variables d'environnement du Space. | |
| """ | |
| # NOTE : J'ai changé pour un modèle plus petit pour accélérer le premier chargement. | |
| # Vous pouvez remettre "TheBloke/Llama-2-7B-Chat-GGUF" si vous le souhaitez. | |
| model_repo_id = "TheBloke/Llama-2-7B-Chat-GGUF" | |
| model_filename = "llama-2-7b-chat.Q4_K_M.gguf" | |
| with st.spinner(f"Chargement du modèle '{model_filename}' en mémoire... (Ceci peut être long)"): | |
| try: | |
| # Le comportement du cache est maintenant contrôlé par les variables d'environnement | |
| # du Space, et non plus par le code. | |
| llm = CTransformers( | |
| model=model_repo_id, | |
| model_file=model_filename, | |
| model_type="llama", | |
| config={ | |
| 'max_new_tokens': 1500, | |
| 'temperature': 0.7, | |
| 'context_length': 4096 | |
| } | |
| ) | |
| logger.info("Modèle LLM chargé avec succès en mémoire.") | |
| return llm | |
| except Exception as e: | |
| st.error(f"Erreur critique lors du chargement du modèle depuis le Hub : {e}") | |
| logger.error(f"Erreur de chargement du modèle CTransformers : {e}") | |
| st.stop() | |
| def load_retriever(faiss_path, embeddings_path): | |
| """ | |
| Charge le retriever FAISS et le modèle d'embeddings. | |
| """ | |
| with st.spinner("Chargement de la base de connaissances (FAISS) et des embeddings..."): | |
| try: | |
| # Les modèles d'embeddings SONT mis en cache par défaut, mais dans un | |
| # emplacement autorisé par la plateforme. | |
| embeddings_model = HuggingFaceEmbeddings( | |
| model_name=embeddings_path, | |
| model_kwargs={'device': 'cpu'} | |
| ) | |
| vectorstore = FAISS.load_local( | |
| faiss_path, | |
| embeddings_model, | |
| allow_dangerous_deserialization=True | |
| ) | |
| logger.info("Retriever chargé avec succès.") | |
| return vectorstore.as_retriever(search_kwargs={"k": 5}) | |
| except Exception as e: | |
| st.error(f"Erreur lors du chargement du retriever : {e}") | |
| logger.error(f"Erreur de chargement du retriever : {e}") | |
| st.stop() | |
| # --- Chemins d'accès (relatifs à la racine de votre projet) --- | |
| DOSSIER_PROJET = os.path.dirname(__file__) | |
| CHEMIN_INDEX_FAISS = os.path.join(DOSSIER_PROJET, "faiss_index_wize") | |
| CHEMIN_MODELE_EMBEDDINGS = os.path.join(DOSSIER_PROJET, "embedding_model") | |
| if not os.path.exists(CHEMIN_INDEX_FAISS) or not os.path.exists(CHEMIN_MODELE_EMBEDDINGS): | |
| st.error(f"Erreur critique : Les dossiers 'faiss_index_wize' ou 'embedding_model' sont manquants dans votre dépôt.") | |
| st.stop() | |
| # --- Chargement principal --- | |
| try: | |
| llm = load_llm() | |
| retriever = load_retriever(CHEMIN_INDEX_FAISS, CHEMIN_MODELE_EMBEDDINGS) | |
| st.success("🎉 Les modèles sont chargés et prêts !") | |
| except Exception as e: | |
| st.error(f"Une erreur inattendue est survenue lors du chargement des modèles : {e}") | |
| logger.error(f"Erreur de chargement principale : {e}") | |
| st.stop() | |
| # --- Interface de Chat --- | |
| if "messages" not in st.session_state: | |
| st.session_state.messages = [] | |
| for message in st.session_state.messages: | |
| with st.chat_message(message["role"]): | |
| st.markdown(message["content"]) | |
| if prompt := st.chat_input("Posez votre question ici..."): | |
| st.session_state.messages.append({"role": "user", "content": prompt}) | |
| with st.chat_message("user"): | |
| st.markdown(prompt) | |
| with st.chat_message("assistant"): | |
| with st.spinner("Je réfléchis..."): | |
| try: | |
| docs = retriever.invoke(prompt) | |
| context = "\n".join([doc.dict().get("page_content", "") for doc in docs]) | |
| # Création du prompt pour CTransformers | |
| full_prompt = f"System: Vous êtes un coach expert. Répondez à la question en vous basant UNIQUEMENT sur le contexte fourni. Ne mentionnez pas le contexte dans votre réponse.\n\nContexte:\n{context}\n\nQuestion: {prompt}\n\nRéponse:" | |
| # Invocation du LLM | |
| answer = llm.invoke(full_prompt) | |
| st.markdown(answer) | |
| st.session_state.messages.append({"role": "assistant", "content": answer}) | |
| except Exception as e: | |
| answer = f"Désolé, une erreur est survenue lors de la génération de la réponse : {e}" | |
| st.error(answer) | |
| logger.error(f"Erreur de génération LLM : {e}") | |
| st.session_state.messages.append({"role": "assistant", "content": answer}) | |