From 229ba53246a55ca4885dc878de653a04ef8eacaa Mon Sep 17 00:00:00 2001 From: sepehr Date: Fri, 7 Mar 2025 22:33:27 +0100 Subject: [PATCH] Add initial project structure with chatbot implementation and requirements --- .gitignore | 1 + README.md | 53 + __pycache__/rag_chatbot.cpython-313.pyc | Bin 0 -> 10619 bytes chat_bot_rag.code-workspace | 11 + cli.py | 70 + final_pdf.ipynb | 2295 +++++++++++++++++++++++ gradio_chatbot.py | 514 +++++ rag_chatbot.py | 286 +++ requirement.txt | 45 + 9 files changed, 3275 insertions(+) create mode 100644 .gitignore create mode 100644 __pycache__/rag_chatbot.cpython-313.pyc create mode 100644 chat_bot_rag.code-workspace create mode 100644 cli.py create mode 100644 final_pdf.ipynb create mode 100644 gradio_chatbot.py create mode 100644 rag_chatbot.py create mode 100644 requirement.txt diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..dbc9cfc --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +apigit.txt \ No newline at end of file diff --git a/README.md b/README.md index e69de29..5b8893d 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,53 @@ +# RAG Chatbot + +This repository contains a Retrieval Augmented Generation (RAG) chatbot implementation that can process data and answer questions based on the provided context. + +## Requirements + +### Python Version +⚠️ **Important**: This project requires Python version lower than 3.12. Python 3.11 works correctly. + +## Installation + +1. Clone this repository: +```bash +git clone +cd +``` + +2. Install the required dependencies: +```bash +pip install -r requirement.txt +``` + +## Usage + +### Command Line Interface +Run the chatbot in terminal mode: +```bash +python cli.py +``` + +### Web Interface +Launch the Gradio web interface: +```bash +python gradio_chatbot.py +``` + +### RAG Implementation +If you want to import the RAG functionality in your own Python script: +```python +from rag_chatbot import RagChatbot + +chatbot = RagChatbot() +response = chatbot.query("your question here") +``` + +## PDF Processing +The repository includes a Jupyter notebook [`final_pdf.ipynb`](final_pdf.ipynb) for processing PDF documents as knowledge sources for the chatbot. + +## Project Structure +- [`cli.py`](cli.py): Command-line interface implementation +- [`gradio_chatbot.py`](gradio_chatbot.py): Gradio web interface +- [`rag_chatbot.py`](rag_chatbot.py): Core RAG implementation +- [`final_pdf.ipynb`](final_pdf.ipynb): Jupyter notebook for PDF processing \ No newline at end of file diff --git a/__pycache__/rag_chatbot.cpython-313.pyc b/__pycache__/rag_chatbot.cpython-313.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3ec384199c9fe680c0cf0034f2a1443718f50244 GIT binary patch literal 10619 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 literal 0 HcmV?d00001 diff --git a/chat_bot_rag.code-workspace b/chat_bot_rag.code-workspace new file mode 100644 index 0000000..e77f2ca --- /dev/null +++ b/chat_bot_rag.code-workspace @@ -0,0 +1,11 @@ +{ + "folders": [ + { + "path": "." + }, + { + "path": "../Rag_Modeling/document" + } + ], + "settings": {} +} \ No newline at end of file diff --git a/cli.py b/cli.py new file mode 100644 index 0000000..5406477 --- /dev/null +++ b/cli.py @@ -0,0 +1,70 @@ +# cli.py +from rag_chatbot import MultimodalRAGChatbot + +def main(): + # Initialiser le chatbot + chatbot = MultimodalRAGChatbot( + qdrant_url="http://localhost:6333", + qdrant_collection_name="my_documents", + ollama_model="llama3.2" + ) + + print("Chatbot RAG Multimodal") + print("Tapez 'exit' pour quitter ou 'clear' pour effacer l'historique") + + while True: + # Récupérer la question + query = input("\nVotre question: ") + + # Quitter si demandé + if query.lower() in ["exit", "quit", "q"]: + break + + # Effacer l'historique si demandé + if query.lower() == "clear": + chatbot.clear_history() + print("Historique effacé") + continue + + # Demander si mode streaming + stream_mode = input("Mode streaming? (y/n): ").lower() == 'y' + + # Traitement de la requête + result = chatbot.chat(query, stream=stream_mode) + + # Si pas de streaming, afficher la réponse texte + if not stream_mode: + print("\n" + "="*50) + print("Réponse:") + print(result["response"]) + print("="*50) + + # Afficher les informations sur les sources + print("\nSources trouvées:") + print(f"- {len(result['texts'])} textes") + print(f"- {len(result['images'])} images") + print(f"- {len(result['tables'])} tableaux") + + # Afficher les images si demandé + if result["images"]: + show_images = input("\nAfficher les images? (y/n): ").lower() == 'y' + if show_images: + for i, img in enumerate(result["images"]): + print(f"\nImage {i+1}: {img['caption']} (Source: {img['source']}, Page: {img['page']})") + print(f"Description: {img['description']}") + chatbot.display_image(img["image_data"], img["caption"]) + + # Afficher les tableaux si demandé + if result["tables"]: + show_tables = input("\nAfficher les tableaux? (y/n): ").lower() == 'y' + if show_tables: + for i, table in enumerate(result["tables"]): + print(f"\nTableau {i+1}: {table['caption']} (Source: {table['source']}, Page: {table['page']})") + print(f"Description: {table['description']}") + print("\nContenu:") + print("```") + print(chatbot.format_table(table["table_data"])) + print("```") + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/final_pdf.ipynb b/final_pdf.ipynb new file mode 100644 index 0000000..b1d0b57 --- /dev/null +++ b/final_pdf.ipynb @@ -0,0 +1,2295 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 2, + "metadata": {}, + "outputs": [ + { + "ename": "ModuleNotFoundError", + "evalue": "No module named 'unstructured_inference'", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mModuleNotFoundError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[2]\u001b[39m\u001b[32m, line 25\u001b[39m\n\u001b[32m 14\u001b[39m \u001b[38;5;66;03m# Configuration du loader pour extraire images, tableaux et leurs métadonnées\u001b[39;00m\n\u001b[32m 15\u001b[39m loader = UnstructuredPDFLoader(\n\u001b[32m 16\u001b[39m path_pdf,\n\u001b[32m 17\u001b[39m infer_table_structure=\u001b[38;5;28;01mTrue\u001b[39;00m, \u001b[38;5;66;03m# Active l'inférence de la structure des tableaux\u001b[39;00m\n\u001b[32m (...)\u001b[39m\u001b[32m 23\u001b[39m extract_image_block_to_payload=\u001b[38;5;28;01mTrue\u001b[39;00m,\n\u001b[32m 24\u001b[39m )\n\u001b[32m---> \u001b[39m\u001b[32m25\u001b[39m documents = \u001b[43mloader\u001b[49m\u001b[43m.\u001b[49m\u001b[43mload\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32mf:\\Dev\\Rag\\chat_bot_rag\\.venv\\Lib\\site-packages\\langchain_core\\document_loaders\\base.py:32\u001b[39m, in \u001b[36mBaseLoader.load\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 30\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mload\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28mlist\u001b[39m[Document]:\n\u001b[32m 31\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Load data into Document objects.\"\"\"\u001b[39;00m\n\u001b[32m---> \u001b[39m\u001b[32m32\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mlist\u001b[39;49m\u001b[43m(\u001b[49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43mlazy_load\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mFile \u001b[39m\u001b[32mf:\\Dev\\Rag\\chat_bot_rag\\.venv\\Lib\\site-packages\\langchain_community\\document_loaders\\unstructured.py:107\u001b[39m, in \u001b[36mUnstructuredBaseLoader.lazy_load\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 105\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34mlazy_load\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> Iterator[Document]:\n\u001b[32m 106\u001b[39m \u001b[38;5;250m \u001b[39m\u001b[33;03m\"\"\"Load file.\"\"\"\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m107\u001b[39m elements = \u001b[38;5;28;43mself\u001b[39;49m\u001b[43m.\u001b[49m\u001b[43m_get_elements\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 108\u001b[39m \u001b[38;5;28mself\u001b[39m._post_process_elements(elements)\n\u001b[32m 109\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m.mode == \u001b[33m\"\u001b[39m\u001b[33melements\u001b[39m\u001b[33m\"\u001b[39m:\n", + "\u001b[36mFile \u001b[39m\u001b[32mf:\\Dev\\Rag\\chat_bot_rag\\.venv\\Lib\\site-packages\\langchain_community\\document_loaders\\pdf.py:92\u001b[39m, in \u001b[36mUnstructuredPDFLoader._get_elements\u001b[39m\u001b[34m(self)\u001b[39m\n\u001b[32m 91\u001b[39m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34m_get_elements\u001b[39m(\u001b[38;5;28mself\u001b[39m) -> \u001b[38;5;28mlist\u001b[39m:\n\u001b[32m---> \u001b[39m\u001b[32m92\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01munstructured\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mpartition\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mpdf\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m partition_pdf\n\u001b[32m 94\u001b[39m \u001b[38;5;28;01mreturn\u001b[39;00m partition_pdf(filename=\u001b[38;5;28mself\u001b[39m.file_path, **\u001b[38;5;28mself\u001b[39m.unstructured_kwargs)\n", + "\u001b[36mFile \u001b[39m\u001b[32mf:\\Dev\\Rag\\chat_bot_rag\\.venv\\Lib\\site-packages\\unstructured\\partition\\pdf.py:19\u001b[39m\n\u001b[32m 17\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mPIL\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m Image \u001b[38;5;28;01mas\u001b[39;00m PILImage\n\u001b[32m 18\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01mpypdf\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m PdfReader\n\u001b[32m---> \u001b[39m\u001b[32m19\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01munstructured_inference\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01minference\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mlayout\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m DocumentLayout\n\u001b[32m 20\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01munstructured_inference\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01minference\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mlayoutelement\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m LayoutElement\n\u001b[32m 22\u001b[39m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[34;01munstructured\u001b[39;00m\u001b[34;01m.\u001b[39;00m\u001b[34;01mchunking\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m add_chunking_strategy\n", + "\u001b[31mModuleNotFoundError\u001b[39m: No module named 'unstructured_inference'" + ] + } + ], + "source": [ + "import pytesseract\n", + "from langchain.document_loaders import UnstructuredPDFLoader\n", + "from ollama import Client\n", + "from langchain_ollama.llms import OllamaLLM\n", + "import os.path\n", + "import os\n", + "os.environ[\"OCR_AGENT\"] =\"unstructured.partition.utils.ocr_models.tesseract_ocr.OCRAgentTesseract\"\n", + "# Configuration de pytesseract\n", + "pytesseract.pytesseract.tesseract_cmd = r'C:\\Program Files\\Tesseract-OCR\\tesseract.exe'\n", + "\n", + "# Chemin vers votre PDF\n", + "path_pdf = r\"F:\\Dev\\Rag\\Rag_Modeling\\document\\11_chapitre3.pdf\"\n", + "\n", + "# Configuration du loader pour extraire images, tableaux et leurs métadonnées\n", + "loader = UnstructuredPDFLoader(\n", + " path_pdf,\n", + " infer_table_structure=True, # Active l'inférence de la structure des tableaux\n", + " extract_images=True, # Extraction des images\n", + " image_output_dir=r\"F:\\Dev\\Rag\\Rag_Modeling\\TEMP\",\n", + " mode=\"elements\",\n", + " strategy=\"hi_res\", # Vous pouvez tester \"fast\" si besoin\n", + " extract_image_block_types=[\"Image\"],\n", + " extract_image_block_to_payload=True,\n", + ")\n", + "documents = loader.load()\n" + ] + }, + { + "cell_type": "code", + "execution_count": 41, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "27\n" + ] + } + ], + "source": [ + "\n", + "# for i, chunk in enumerate(documents):\n", + "# # On vérifie si le chunk correspond à une image\n", + "# if chunk.metadata.get(\"category\") == \"FigureCaption\":\n", + "# print(chunk.page_content.strip())\n", + "def get_images_with_caption(documents):\n", + " images_info = []\n", + " for i, chunk in enumerate(documents):\n", + " # On vérifie si le chunk correspond à une image\n", + " if chunk.metadata.get(\"category\") == \"Image\":\n", + " image_b64 = chunk.metadata.get('image_base64')\n", + " caption = \"\"\n", + " # Si aucune légende n'a été trouvée, on regarde le bloc suivant\n", + " if i < len(documents) - 1:\n", + " next_chunk = documents[i+1]\n", + " # On vérifie si le texte du bloc suivant contient des indices de légende\n", + " if next_chunk.metadata.get(\"category\") == \"FigureCaption\":\n", + " caption = next_chunk.page_content.strip()\n", + " \n", + " images_info.append({\n", + " \"image_base64\": image_b64,\n", + " \"caption\": caption,\n", + " \"source\": os.path.basename(chunk.metadata.get(\"source\", \"\")),\n", + " \"page\": chunk.metadata.get(\"page_number\", \"\"),\n", + " })\n", + " return images_info\n", + "images_with_caption = get_images_with_caption(documents) \n", + "print(len(images_with_caption ))" + ] + }, + { + "cell_type": "code", + "execution_count": 42, + "metadata": {}, + "outputs": [], + "source": [ + "def get_tables_with_caption(documents):\n", + " tables_info = []\n", + " for idx, chunk in enumerate(documents):\n", + "\n", + " if chunk.metadata.get(\"category\") == \"Table\" or \"table\" in chunk.metadata.get(\"category\", \"\").lower():\n", + "\n", + " # Extraction du contenu textuel du tableau et de sa légende\n", + " payload = chunk.metadata.get(\"payload\", {})\n", + " caption = payload.get(\"caption\", \"\").strip()\n", + " # Si aucune légende n'est trouvée, vérifier le bloc suivant\n", + " if not caption and idx + 1 < len(documents):\n", + " next_chunk = documents[idx + 1]\n", + " lower_text = next_chunk.page_content.lower()\n", + " if next_chunk.metadata.get(\"category\") == \"FigureCaption\":\n", + " caption = next_chunk.page_content.strip() \n", + " tables_info.append({\n", + " \"type\": \"table_with_caption\",\n", + " \"table_data\": chunk.page_content, # Le contenu textuel du tableau\n", + " \"caption\": caption,\n", + " \"source\": os.path.basename(chunk.metadata.get(\"source\", \"\")),\n", + " \"page\": chunk.metadata.get(\"page_number\", \"\"),\n", + " })\n", + " return tables_info\n", + " \n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 135, + "metadata": {}, + "outputs": [], + "source": [ + "tables_with_caption=get_tables_with_caption(documents)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 136, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "\n", + "def get_text_elements(documents):\n", + " text_info = []\n", + " text_elements = [doc for doc in documents if doc.metadata.get(\"category\") not in [\"Table\", \"Image\",\"FigureCaption\"]]\n", + "\n", + " for _, chunk in enumerate(text_elements):\n", + " text_info.append({ \n", + " \"page_content\": chunk.page_content, # Le contenu textuel du tableau\n", + " \"source\": os.path.basename(chunk.metadata.get(\"source\", \"\")),\n", + " \"page\": chunk.metadata.get(\"page_number\", \"\"),\n", + " })\n", + " return text_info\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 137, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Nombre de chunks générés: 1078\n" + ] + } + ], + "source": [ + "from langchain.schema import Document\n", + "from langchain.text_splitter import RecursiveCharacterTextSplitter\n", + "import os\n", + "\n", + "# Garde votre fonction get_text_elements telle quelle\n", + "def get_text_elements(documents):\n", + " text_info = []\n", + " text_elements = [doc for doc in documents if doc.metadata.get(\"category\") not in [\"Table\", \"Image\",\"FigureCaption\"]]\n", + "\n", + " for _, chunk in enumerate(text_elements):\n", + " text_info.append({ \n", + " \"page_content\": chunk.page_content, # Le contenu textuel du tableau\n", + " \"source\": os.path.basename(chunk.metadata.get(\"source\", \"\")),\n", + " \"page\": chunk.metadata.get(\"page_number\", \"\"),\n", + " })\n", + " return text_info\n", + "\n", + "# Fonction pour convertir vos dictionnaires en objets Document de LangChain\n", + "def convert_to_langchain_documents(text_info):\n", + " documents = []\n", + " for item in text_info:\n", + " # Créer un dictionnaire de métadonnées complet\n", + " metadata = {\n", + " \"source\": item.get(\"source\", \"\"),\n", + " \"page_number\": item.get(\"page\", \"\"),\n", + " }\n", + " \n", + " # Créer un objet Document\n", + " doc = Document(\n", + " page_content=item[\"page_content\"],\n", + " metadata=metadata\n", + " )\n", + " documents.append(doc)\n", + " return documents\n", + "\n", + "# Application du chunking\n", + "chunk_size = 10000\n", + "chunk_overlap = 2000\n", + "\n", + "# 1. Obtenir les dictionnaires d'éléments textuels\n", + "text_elements_dicts = get_text_elements(documents)\n", + "\n", + "# 2. Convertir en objets Document de LangChain\n", + "text_elements_docs = convert_to_langchain_documents(text_elements_dicts)\n", + "\n", + "# 3. Appliquer le chunking\n", + "text_splitter = RecursiveCharacterTextSplitter(\n", + " chunk_size=chunk_size,\n", + " chunk_overlap=chunk_overlap\n", + ")\n", + "text_chunks = text_splitter.split_documents(text_elements_docs)\n", + "\n", + "print(f\"Nombre de chunks générés: {len(text_chunks)}\")" + ] + }, + { + "cell_type": "code", + "execution_count": 139, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.schema import Document\n", + "from langchain.text_splitter import RecursiveCharacterTextSplitter\n", + "import os\n", + "\n", + "def chunk_by_title(documents, max_chunk_size=10000, chunk_overlap=2000):\n", + " \"\"\"\n", + " Crée des chunks basés sur la structure des titres dans le document.\n", + " Chaque titre commence un nouveau chunk.\n", + " \n", + " Args:\n", + " documents: Liste des documents extraits\n", + " max_chunk_size: Taille maximale d'un chunk\n", + " chunk_overlap: Chevauchement entre les chunks si division supplémentaire est nécessaire\n", + " \n", + " Returns:\n", + " Liste de Documents LangChain\n", + " \"\"\"\n", + " # Identifie les positions des titres dans le document\n", + " title_positions = []\n", + " for i, doc in enumerate(documents):\n", + " if doc.metadata.get(\"category\") == \"Title\":\n", + " title_positions.append(i)\n", + " \n", + " # Ajouter une position finale pour faciliter le traitement\n", + " title_positions.append(len(documents))\n", + " \n", + " # Créer les chunks basés sur les titres\n", + " title_based_chunks = []\n", + " \n", + " # Si aucun titre n'a été trouvé, traiter comme un seul grand chunk\n", + " if len(title_positions) <= 1:\n", + " text_elements = [doc for doc in documents if doc.metadata.get(\"category\") not in [\"Table\", \"Image\", \"FigureCaption\"]]\n", + " combined_text = \" \".join([doc.page_content for doc in text_elements])\n", + " \n", + " title_based_chunks.append(Document(\n", + " page_content=combined_text,\n", + " metadata={\n", + " \"source\": os.path.basename(documents[0].metadata.get(\"source\", \"\")),\n", + " \"title\": \"Document sans titre\",\n", + " \"page_numbers\": list(set(doc.metadata.get(\"page_number\") for doc in text_elements if doc.metadata.get(\"page_number\")))\n", + " }\n", + " ))\n", + " else:\n", + " # Traiter chaque section délimitée par des titres\n", + " for i in range(len(title_positions) - 1):\n", + " start_idx = title_positions[i]\n", + " end_idx = title_positions[i + 1]\n", + " \n", + " # Récupérer le titre de cette section\n", + " title_doc = documents[start_idx]\n", + " title_text = title_doc.page_content\n", + " \n", + " # Extraire les éléments textuels de cette section (en excluant le titre lui-même)\n", + " section_docs = [\n", + " doc for doc in documents[start_idx+1:end_idx]\n", + " if doc.metadata.get(\"category\") not in [\"Table\", \"Image\", \"FigureCaption\"]\n", + " ]\n", + " \n", + " if section_docs:\n", + " # Combiner le contenu textuel de la section\n", + " section_text = \" \".join([doc.page_content for doc in section_docs])\n", + " \n", + " # Récupérer les pages concernées\n", + " page_numbers = list(set(\n", + " doc.metadata.get(\"page_number\") for doc in section_docs \n", + " if doc.metadata.get(\"page_number\")\n", + " ))\n", + " \n", + " source = os.path.basename(section_docs[0].metadata.get(\"source\", \"\"))\n", + " \n", + " # Créer un Document pour cette section\n", + " title_based_chunks.append(Document(\n", + " page_content=section_text,\n", + " metadata={\n", + " \"source\": source,\n", + " \"title\": title_text,\n", + " \"page_numbers\": page_numbers\n", + " }\n", + " ))\n", + " \n", + " # Appliquer un chunking supplémentaire si certaines sections sont trop grandes\n", + " final_chunks = []\n", + " text_splitter = RecursiveCharacterTextSplitter(\n", + " chunk_size=max_chunk_size,\n", + " chunk_overlap=chunk_overlap\n", + " )\n", + " \n", + " for chunk in title_based_chunks:\n", + " if len(chunk.page_content) <= max_chunk_size:\n", + " final_chunks.append(chunk)\n", + " else:\n", + " # Découper davantage cette section car elle est trop grande\n", + " sub_chunks = text_splitter.split_documents([chunk])\n", + " # Préserver l'information du titre dans chaque sous-chunk\n", + " for i, sub_chunk in enumerate(sub_chunks):\n", + " sub_chunk.metadata[\"title\"] = chunk.metadata[\"title\"]\n", + " sub_chunk.metadata[\"sub_chunk\"] = i + 1\n", + " sub_chunk.metadata[\"total_sub_chunks\"] = len(sub_chunks)\n", + " final_chunks.extend(sub_chunks)\n", + " \n", + " return final_chunks\n", + "\n", + "# Utilisation de la fonction\n", + "chunk_size = 10000\n", + "chunk_overlap = 2000\n", + "\n", + "# Créer des chunks basés sur les titres\n", + "title_chunks = chunk_by_title(documents, max_chunk_size=chunk_size, chunk_overlap=chunk_overlap)\n", + "\n", + "# print(f\"Nombre total de chunks basés sur les titres: {len(title_chunks)}\")\n", + "\n", + "# # Afficher quelques exemples\n", + "# for i, chunk in enumerate(title_chunks[:10]): # Limité aux 3 premiers\n", + "# print(f\"\\nChunk #{i+1}\")\n", + "# print(f\"Titre: {chunk.metadata.get('title')}\")\n", + "# print(f\"Pages: {chunk.metadata.get('page_numbers')}\")\n", + "# print(f\"Taille: {len(chunk.page_content)} caractères\")\n", + "# print(f\"Début du texte: {chunk.page_content[:150]}...\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "text_summaries = summarize_chain.batch(title_chunks, {\"max_concurrency\": 3})" + ] + }, + { + "cell_type": "code", + "execution_count": 143, + "metadata": {}, + "outputs": [], + "source": [ + "from ollama import Client\n", + "client = Client(host='http://localhost:11434')\n", + "\n", + "\n", + "# Fonction pour analyser une image en envoyant le fichier image et le prompt au modèle\n", + "def analyze_image(image_data, caption: str, context: str=\"\", prompt_base: str = \"\"):\n", + " prompt = \"\"\n", + " if caption:\n", + " prompt += f\"Caption of image : {caption}. \"\n", + " if context:\n", + " prompt += f\"Contexte : {context}. \"\n", + " if prompt_base:\n", + " prompt = f\"{prompt_base} {prompt}\"\n", + " else:\n", + " prompt += \"Décris cette image en détail.\"\n", + " \n", + " response = client.chat(\n", + " model=\"llama3.2-vision\",\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": prompt, \"images\": [image_data]}\n", + " ]\n", + " )\n", + " return response[\"message\"][\"content\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 149, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Image 1\n", + "Image 2\n", + "Image 3\n", + "Image 4\n", + "Image 5\n", + "Image 6\n", + "Image 7\n", + "Image 8\n", + "Image 9\n", + "Image 10\n", + "Image 11\n", + "Image 12\n", + "Image 13\n", + "Image 14\n", + "Image 15\n", + "Image 16\n", + "Image 17\n", + "Image 18\n", + "Image 19\n", + "Image 20\n", + "Image 21\n", + "Image 22\n", + "Image 23\n", + "Image 24\n", + "Image 25\n", + "Image 26\n", + "Image 27\n" + ] + } + ], + "source": [ + "image_summaries = []\n", + "for i, imge in enumerate(images_with_caption):\n", + " image_summaries.append(analyze_image(image_data=imge.get(\"image_base64\"),caption=imge.get(\"caption\")))\n", + " print(f\"Image {i+1}\")\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 155, + "metadata": {}, + "outputs": [], + "source": [ + "image_summaries1 = [\"Cette image illustre le découpage d'un injecteur (en anglais: injector) en cinq modules pour une analyse numérique globale et complète.\\n\\nUn injecteur est un dispositif utilisé dans les moteurs à combustibles liquides, tel que celui de la figure 3-1. Il s'agit d'une pièce qui permet l'injection du carburant, du mélange air-carburant ou des deux séparément, dans le cylindre du moteur.\\n\\nLes différents modules sont décrits et numérisés comme suit :\\n\\n* **Module 1** : Ce module représente la partie supérieure de l'injecteur. Il contient la vanne d'injection (en anglais: injection valve) qui contrôle le débit d'injection du carburant.\\n* **Module 2** : Ce module représente la partie moyenne de l'injecteur. Il contient les tuyaux d'injection (en anglais: injection tubes) qui transportent le carburant jusqu'à la chambre de combustion.\\n* **Module 3** : Ce module représente la partie inférieure de l'injecteur. Il contient la pompe d'injection (en anglais: injection pump) qui alimente les tuyaux d'injection en carburant.\\n* **Module 4** : Ce module représente la chambre de combustion (en anglais: combustion chamber) où le carburant est brûlé avec l'air pour produire du gaz à haute pression.\\n* **Module 5** : Ce module représente les tuyaux de sortie (en anglais: exhaust tubes) qui transportent le gaz à haute pression hors du moteur.\\n\\nL'image montre comment ces cinq modules sont assemblés pour former l'injecteur complet. Les dimensions et la géométrie des différents éléments sont représentées avec précision, ce qui permettra d'étudier les performances de l'injecteur dans diverses conditions opérationnelles.\\n\\nLes chiffres indiquent le diamètre en millimètres (mm) du module à partir du centre du module. Le numéro 1 est au centre du module et chaque numéro se déplace vers la droite ou la gauche, selon les dimensions de l'élément. Le chiffre 0 correspond aux dimensions relatives.\\n\\nLa figure illustre comment le découpage en modules permet d'analyser séparément chaque partie de l'injecteur, ce qui facilite son étude et son optimisation pour améliorer ses performances.\\n\\nCette image est un outil précieux pour les ingénieurs chargés du développement des moteurs à combustibles liquides. Elle leur permettra de comprendre en détail le fonctionnement de l'injecteur et d'identifier les zones qui nécessitent une attention particulière pour améliorer ses performances.\",\n", + " 'The image presents a graph with two distinct sections: the top section features an inset diagram, while the bottom section displays a line graph.\\n\\n**Top Section**\\n\\n* The top section of the image contains an inset diagram in the upper-left corner.\\n* This diagram is labeled \"P (bar)\" on the y-axis and \"z (mm)\" on the x-axis.\\n* It features three lines with different colors:\\n * Red\\n * Blue\\n * Green\\n\\n**Bottom Section**\\n\\n* The bottom section of the image shows a line graph.\\n* The y-axis is labeled \"P (bar)\", and the x-axis is labeled \"z (mm)\".\\n* The graph displays three lines with different colors:\\n * Red\\n * Blue\\n * Green\\n\\n**Key Takeaways**\\n\\n* Both sections of the image share similar axes labels, indicating that they represent pressure and distance measurements.\\n* The inset diagram appears to be a smaller-scale version of the line graph in the bottom section.\\n\\n**Conclusion**\\n\\nIn conclusion, the image presents two related graphs that display pressure and distance measurements. The top section features an inset diagram with three lines representing different variables, while the bottom section shows a larger line graph with similar axes labels. Overall, the image provides a visual representation of data related to pressure and distance measurements.',\n", + " '**Image Description**\\n\\nThe image presents a graph with a title in French, accompanied by a legend on the right side. The graph features a grid pattern and includes multiple lines representing various data points.\\n\\n* **Title**: The title of the graph is written in French and appears to be related to injection or flow rates.\\n* **Legend**: The legend provides information about the different lines on the graph, including their corresponding labels and colors.\\n* **Grid Pattern**: The grid pattern on the graph allows for easy reading and comparison of data points.\\n* **Lines**: Multiple lines are plotted on the graph, each representing a specific dataset. These lines vary in color and thickness, indicating differences between the datasets.\\n* **Data Points**: Each line represents multiple data points, which are connected by straight or curved segments to form a continuous curve.\\n\\nIn summary, the image presents a detailed graph with a title in French, accompanied by a legend that explains the different lines and colors. The grid pattern makes it easy to read and compare the data points, while the multiple lines provide a comprehensive overview of various datasets.',\n", + " \"Cette image est un diagramme qui illustre le processus de production d'eau potable à partir de l'eau brute.\\n\\nAu premier niveau, on a la source d'eau brute. Ensuite, une unité de traitement primaire traite l'eau brut pour éliminer les particules grossières et les contaminants. Les eaux résiduelles sont ensuite dirigées vers un système de filtration secondaire qui utilise des filtres à sable ou des membranes pour éliminer davantage de contaminants.\\n\\nEnsuite, le produit de la filtration secondaire est envoyé dans une unité de traitement tertiaire qui ajoute du chlore ou d'autres agents chimiques pour supprimer les bactéries et les virus. La eau traitée à ce stade est maintenant appelée eau potable.\\n\\nFinalement, l'eau potable est stockée dans des réservoirs et distribuée aux consommateurs par un réseau de canalisations. Un système de pompage assure le transport continu d'eau potable vers les différents points de distribution.\\n\\nAu total, ce processus assure une production d'eau potable propre et saine pour le consommateur final.\",\n", + " \"Cette image est un diagramme qui illustre les étapes de séparation d'un mélange gazeux dans une colonne de distillation. Cette technique est utilisée pour séparer des composés gazeux ayant des points d'ébullition différents.\\n\\n* **Étape 1 : Mélange gazeux**\\n\\nLa première étape consiste à introduire le mélange gazeux dans la colonne de distillation. Ce mélange contient plusieurs composants gazeux, chacun avec son propre point d'ébullition.\\n* **Étape 2 : Chauffage**\\n\\nLe mélange est ensuite chauffé pour augmenter sa température et atteindre le point d'ébullition du composant le plus volatil. Cette étape permet de séparer les composants gazeux en fonction de leur point d'ébullition.\\n* **Étape 3 : Séparation**\\n\\nLes composants gazeux sont ensuite séparés en fonction de leur point d'ébullition, à l'aide d'un système de condensation ou de réfrigération. Les composants les plus volatils passent dans le haut de la colonne, tandis que ceux qui ont un point d'ébullition plus élevé restent au fond.\\n* **Étape 4 : Condensation**\\n\\nLes composants gazeux sont ensuite condensés en liquide et collectés séparément. Ce processus peut être répété plusieurs fois pour obtenir des résultats de séparation précis.\\n* **Étape 5 : Récupération**\\n\\nEnfin, les composants gazeux sont récupérés sous forme de liquide pur ou gazeux pur, en fonction de la demande.\\n\\nCe diagramme illustre l'importance de la colonne de distillation dans le traitement des mélange gazeux. Cette technique est largement utilisée dans divers domaines industriels, tels que l'industrie chimique, les pétrochimie et les biotechnologies.\",\n", + " \"The image presents a graph illustrating the relationship between temperature and pressure in an injector, with a focus on comparing model predictions to experimental results. The graph features a red line representing the predicted performance of the injector at different temperatures, while pink dots indicate the actual measured data.\\n\\n**Key Features:**\\n\\n* **Temperature Range:** The x-axis spans from 0 to 14 degrees Celsius, providing a clear visual representation of how temperature affects the injector's performance.\\n* **Pressure Trend:** The y-axis shows an upward trend as pressure increases, allowing for easy comparison between predicted and measured values.\\n* **Comparison Points:** Pink dots are scattered along the red line, indicating where experimental data aligns with model predictions. These points provide a visual representation of the accuracy of the model in predicting real-world performance.\\n\\n**Conclusion:**\\n\\nThe graph effectively illustrates how temperature impacts an injector's performance, offering valuable insights for optimizing its operation. By analyzing the relationship between temperature and pressure, engineers can refine their models to better predict real-world behavior, ultimately leading to improved system efficiency and reliability.\",\n", + " \"The image presents a graph illustrating the influence of geometric contraction ratio on the performance of injectors, specifically comparing model predictions with experimental results. The graph features a series of curves representing different values of the geometric contraction ratio, with corresponding points indicating the predicted and actual performance of the injectors.\\n\\n* **Graph Title:** Influence du rapport de contraction géométrique de la chambre de mélange sur les performances des injecteurs INSA/LC/{A1, B1, C1}, comparaison modéle/expérience.\\n* **X-axis:** Pression d'alimentation vapeur (bar)\\n* **Y-axis:** Contrepression maximale (bar)\\n\\nThe graph shows that as the geometric contraction ratio increases, the predicted performance of the injectors also increases. However, there is a significant discrepancy between the model predictions and experimental results for higher values of the geometric contraction ratio.\\n\\n**Key Findings:**\\n\\n* The model predicts an increase in performance with increasing geometric contraction ratio.\\n* Experimental results show a decrease in performance at high geometric contraction ratios.\\n* There is a significant discrepancy between predicted and actual performance at high geometric contraction ratios.\\n\\n**Conclusion:**\\n\\nThe graph suggests that while the model accurately predicts the performance of injectors at lower geometric contraction ratios, it overestimates their performance at higher values. This discrepancy highlights the need for further refinement of the model to better capture the complex interactions between the injector's geometry and its operating conditions.\\n\\n**Answer:** The image presents a graph illustrating the influence of geometric contraction ratio on the performance of injectors, comparing model predictions with experimental results. The graph shows that while the model accurately predicts performance at lower geometric contraction ratios, it overestimates performance at higher values.\",\n", + " 'This image is a detailed diagram of the liquid flow in a chamber, with various zones labeled. The diagram shows the different regions where the liquid flows through the chamber.\\n\\n* **Zone monophasique liquide (6)**: This zone represents the area where the liquid is in its pure form and has not yet mixed with any other substances.\\n* **Onde de condensation (5)**: This zone represents the area where the liquid begins to condense into a solid or semi-solid state, such as ice or water droplets.\\n* **Ecoulement dispersé vapeur/gouttelettes diluées (4)**: This zone represents the area where the vaporized liquid is dispersed throughout the chamber, creating a mixture of gas and liquid particles.\\n* **Noyau liquide (1)**: This zone represents the central core of the liquid flow, which remains in its pure form and does not mix with any other substances.\\n* **Ecoulement stratifié vapeur (2)**: This zone represents the area where the vaporized liquid is stratified or layered, creating a distinct separation between different components.\\n\\nOverall, this diagram provides a detailed understanding of the complex processes involved in liquid flow and mixing within a chamber. It highlights the various zones that exist within the chamber and how they interact with each other to produce a specific outcome.',\n", + " 'The image presents a graph with multiple lines, each representing different curves. The x-axis is labeled \"Titre en vapeur\" and the y-axis is labeled \"Taux de vide.\" There are several colored lines on the graph, including blue, green, red, purple, and teal.\\n\\n**Key Features:**\\n\\n* **X-Axis:** Labeled \"Titre en vapeur\"\\n* **Y-Axis:** Labeled \"Taux de vide\"\\n* **Colored Lines:** Blue, green, red, purple, and teal\\n* **Graph Title:** Not provided\\n\\n**Analysis:**\\n\\nThe graph appears to be showing the relationship between the title in vapor and the void rate for different masses of volume. The colored lines represent different curves, each with its own unique characteristics.\\n\\n**Conclusion:**\\n\\nIn conclusion, the image presents a complex graph with multiple lines representing different curves. While it is difficult to determine the exact meaning of the graph without more context, it appears to be related to the study of fluids and their properties. Further analysis would be required to fully understand the significance of this graph.',\n", + " \"Cette image représente un diagramme de Fresnel, utilisé dans le domaine des ondes électromagnétiques et de l'optique. Il illustre la propagation d'une onde dans une couche de médium différent du vide.\\n\\nLe diagramme est divisé en plusieurs parties\\xa0:\\n\\n1. **Ligne horizontale** : Cette ligne représente la surface entre le vide et le milieu d'intérêt.\\n2. **Zone de propagation** : Cette zone représente l'espace où l'onde se propage dans le milieu d'intérêt. Elle est divisée en plusieurs zones de même taille, séparées par des lignes verticales.\\n3. **Lignes verticales**\\xa0: Ces lignes représentent les points de réflexion de l'onde sur la surface entre le vide et le milieu d'intérêt.\\n\\nLe diagramme montre comment l'onde se propage dans le milieu d'intérêt, en tenant compte des effets de réfraction et de diffraction. Les zones de propagation sont représentées par des lignes verticales, tandis que les lignes horizontales représentent la surface entre le vide et le milieu d'intérêt.\\n\\nCe diagramme est utilisé pour étudier la propagation des ondes électromagnétiques dans divers milieux, tels que l'air, l'eau ou même l'espace. Il permet de comprendre comment les ondes se propagent et interagissent avec leur environnement.\\n\\n**Conclusion**\\n\\nLe diagramme de Fresnel est un outil essentiel pour la compréhension des phénomènes optiques et électromagnétiques. En analysant cet outil, nous pouvons mieux comprendre comment les ondes se propagent dans divers milieux et comment elles interagissent avec leur environnement.\",\n", + " 'This graph presents a comparison between the experimental and calculated vacuum levels, denoted by *alpha (exp)* and *alpha (mod)* respectively.\\n\\nThe x-axis represents the distance measured in millimeters, while the y-axis displays the vacuum level values ranging from 0 to 1. \\n\\nThe experimental results are depicted as a solid green line with diamond-shaped markers, whereas the calculated data is represented by a solid dark green line. The graph reveals that the calculated and experimental values converge at approximately z=80mm and remain in close proximity thereafter.\\n\\nThis chart appears to be part of a larger study examining the relationship between vacuum levels and distance.',\n", + " 'The image depicts a graph with four distinct lines, each representing different variables. The x-axis is labeled \"z(mm)\" and ranges from 0 to 140 mm in increments of 20 mm. The y-axis is unlabeled but appears to represent pressure or some other unit of measurement.\\n\\n**Line Representations:**\\n\\n* **Green Line (Pv(mod)):** This line starts at a high value around 80,000 on the y-axis and decreases steadily as it moves along the x-axis. It reaches its lowest point at approximately 50,000 before increasing slightly towards the end.\\n* **Blue Line (Pl(mod)):** Beginning at a moderate value of around 40,000, this line gradually increases as it progresses along the x-axis. It peaks at about 60,000 and then decreases slightly.\\n* **Green Triangle Points (Pv(exp)):** These points are scattered throughout the graph but generally follow an upward trend from left to right. The values range from approximately 70,000 to over 90,000 on the y-axis.\\n* **Blue Square Points (Pl(exp)):** Similar to the green triangle points, these blue squares exhibit an overall increasing pattern as they move along the x-axis. Their values span from roughly 30,000 to nearly 50,000 on the y-axis.\\n\\n**Key Observations:**\\n\\n* All lines and data points are positioned above the x-axis, indicating positive values for the variables being measured.\\n* The green line (Pv(mod)) shows a more pronounced fluctuation compared to the other lines, while the blue line (Pl(mod)) remains relatively stable throughout its range.\\n* The experimental data points (green triangles and blue squares) tend to cluster around specific regions of the graph, suggesting some level of correlation or pattern in the measured variables.\\n\\n**Conclusion:**\\n\\nThis graph presents a visual representation of various pressure-related measurements across different conditions. While further context would be necessary to fully interpret these results, it is clear that each variable exhibits distinct characteristics and trends throughout its measurement range.',\n", + " 'This graph displays the calculated and experimental temperatures of each phase in a system, as indicated by the title \"Figure 3-12: Températures de chacune des phases calculées et expérimentales\". The x-axis represents the z-coordinate, while the y-axis measures temperature.\\n\\n**Graph Components**\\n\\n* **Lines and Symbols**: Four lines are visible on the graph:\\n * A green line labeled \"Tv(mod)\"\\n * A blue line labeled \"Tl(mod)\"\\n * A dark blue line labeled \"Tl(exp)\"\\n * A light green line labeled \"Tv(exp)\"\\n* Each line is accompanied by a set of symbols, likely indicating experimental data points.\\n* **X-Axis**: The x-axis ranges from 0 to 140 mm, with increments of 20 mm.\\n\\n**Interpretation**\\n\\nThe graph compares calculated and experimental temperatures for each phase in the system. The green lines represent calculated values, while the blue lines represent experimental values. The dark blue line represents the experimental temperature of phase Tl, and the light green line represents the experimental temperature of phase Tv.\\n\\n**Conclusion**\\n\\nThis graph provides a visual representation of the relationship between calculated and experimental temperatures for each phase in the system. By comparing the different lines and symbols, it is possible to identify areas where there may be discrepancies between theory and practice.',\n", + " \"This graph compares the velocity of each phase as predicted by the model and calculated based on experimental measurements. The x-axis measures distance in millimeters, while the y-axis represents velocity in meters per second.\\n\\nThe green line represents the model's prediction for the speed of the first phase (uv). In contrast, the blue line shows the measured speed of this same phase, and the black dashed line indicates the predicted speed of the second phase. The red line corresponds to the measured speed of the latter phase. A similar pattern is observed on the right side of the graph.\\n\\n**Key Observations:**\\n\\n* The model's predictions are generally consistent with experimental measurements.\\n* However, there are some discrepancies between the two sets of data, particularly at higher velocities.\\n* The second phase exhibits a more pronounced difference between the predicted and measured speeds compared to the first phase.\\n\\nOverall, this graph provides valuable insights into the behavior of these phases under different conditions.\",\n", + " 'This graph presents the evolution of entropy in a liquid-vapor mixture within the heterogeneous portion of a mixing chamber. The x-axis represents time, spanning from 0 to 140 seconds, while the y-axis measures entropy values ranging from approximately 5,000 to 7,500.\\n\\nThe data is represented by two lines: a blue line indicating \"sm(mod)\" and a blue dotted line representing \"Sm(exp)\". The graph reveals that the entropy initially increases steadily as time progresses. However, this upward trend abruptly ends at around 40 seconds on the x-axis, followed by a brief decline before stabilizing.\\n\\nThe data indicates that the entropy values for both lines converge towards 6,000 after approximately 60 seconds, with no further changes observed beyond this point. This suggests that there are two distinct phases in the process being studied.',\n", + " \"Cette image représente un graphique à une seule variable indépendante, avec sur l'axe des x, la valeur de la variable indépendante et sur l'axe des y, la valeur de la variable dépendante. \\n\\nL'image montre deux courbes en traits pleins qui sont très proches les unes des autres. Les points de données associés aux courbes sont représentés par des croix vertes. Le graphique contient également une échelle graduée sur l'axe des x et l'axe des y.\\n\\nL'image ne fournit pas d'autres informations, comme le titre du graphique ou les étiquettes des axes. Elle ne mentionne pas non plus la variable indépendante ni la variable dépendante. Cependant, on peut voir que sur l'axe des x, il y a une valeur de 0 et qu'une échelle graduée est utilisée pour représenter les valeurs entre 0 et environ 140. Sur l'axe des y, il n'y a pas de valeur de départ précise mais la courbe se termine à un certain point sur le graphique.\\n\\nEnfin, on peut remarquer que l'image est en noir et blanc avec une grille jaune sur fond blanc.\",\n", + " 'The image depicts a topological representation of the solution space, showcasing the relationships between various regions and their corresponding characteristics.\\n\\n* The image is divided into two main sections: the top section represents the real axis, while the bottom section represents the complex plane.\\n * The real axis is depicted as a horizontal line extending from negative infinity to positive infinity.\\n * This axis represents the set of all real numbers, which are points on this line.\\n * The complex plane is shown as a vertical strip extending upwards and downwards from the real axis.\\n * Each point in the complex plane corresponds to a unique pair of real and imaginary numbers.\\n* Within the complex plane, several regions are identified:\\n * **Domaine supersonique (Supersonic Domain)**: This region is located above the real axis and contains all points where the velocity of the solution exceeds the speed of sound.\\n * The boundary between this domain and others is represented by a wavy line, indicating changes in the nature of solutions within these regions.\\n * **Domaine subsonique (Subsonic Domain)**: Below the real axis lies this region, encompassing points where the velocity of the solution is less than the speed of sound.\\n * Similar to the supersonic domain, its boundary is also depicted by a wavy line.\\n* The image highlights the relationships between these domains and their boundaries:\\n * **Boundary Between Supersonic and Subsonic Domains**: This boundary is represented by a wavy line that separates the two domains.\\n * It indicates where solutions transition from supersonic to subsonic or vice versa.\\n * **Asymptotes**: Several asymptotic lines are shown, which represent the behavior of solutions as they approach certain points in the complex plane.\\n * These lines help visualize how the nature of solutions changes near these critical points.\\n\\nIn summary, the image provides a detailed topological representation of the solution space, illustrating the interplay between supersonic and subsonic domains, boundaries, and asymptotes. This visual aid facilitates understanding complex relationships within the solution space.',\n", + " 'This graph illustrates the relationship between two variables, \"alpha(exp)\" and \"alpha(mod)\", which are plotted against z(mm) on a grid paper background.\\n\\n* The x-axis represents the variable z in millimeters.\\n* The y-axis is not labeled, but it appears to represent the values of alpha(exp) and alpha(mod).\\n* The graph features two lines:\\n * One line represents the calculated values of alpha(exp), denoted by green triangles.\\n * The other line represents the experimental values of alpha(mod), represented by a solid green curve.\\n\\nThe graph shows that as z increases, both alpha(exp) and alpha(mod) decrease. However, there is a noticeable difference between the two lines, with alpha(exp) consistently higher than alpha(mod) across all values of z. This suggests that there may be some discrepancy or error in the experimental measurements compared to the calculated values.\\n\\nOverall, this graph provides a visual representation of the relationship between these two variables and highlights potential differences between theoretical predictions and real-world observations.',\n", + " 'This graph presents a comparative analysis of the pressure in the homogeneous mixing chamber, as depicted by two distinct lines.\\n\\n**Graph Legend:**\\n\\n* **Pm(mod)**: A green line representing the calculated or modeled pressure values.\\n* **Pm(exp)**: An orange line symbolizing the experimental or measured pressure values.\\n\\nThe x-axis represents the distance (z) in millimeters, while the y-axis denotes the pressure in Pascals (Pa). The graph illustrates that as the distance increases, the pressure decreases. Both lines exhibit a similar downward trend but diverge slightly at higher distances, with the orange line indicating slightly lower pressures than the green line.\\n\\n**Key Observations:**\\n\\n* The graph reveals an inverse relationship between the distance and pressure.\\n* A slight discrepancy is observed in the experimental data compared to the calculated values.',\n", + " 'The graph shows the temperature in a combustion chamber, specifically in its homogeneous section. The x-axis represents the distance from the entrance of the combustion chamber to the exit and is marked every 20 mm, starting at 150 mm. The y-axis represents the temperature and ranges from 0°C to 100°C.\\n\\n**Key Features:**\\n\\n* **Experimental Data:** The blue dots represent experimental data points.\\n* **Theoretical Model:** The solid line represents a theoretical model that approximates the behavior of the system.\\n* **Temperature Profile:** The graph indicates that the temperature increases as you move from left to right along the x-axis, reaching its maximum value at the exit of the combustion chamber.\\n\\n**Conclusion:**\\n\\nThe graph provides valuable information about the thermal behavior of the combustion chamber, allowing engineers and researchers to better understand and optimize their designs. By analyzing the data points and comparing them to the theoretical model, they can identify areas for improvement and make informed decisions to enhance the performance of the system.',\n", + " \"Cette image montre deux équations mathématiques qui semblent être liées à la physique ou aux sciences des matériaux.\\n\\nLa première équation est un système de vecteurs et s'accompagne d'un diagramme qui illustre les différents éléments du système : \\n\\n* **Vecteur de vitesse** : $u_m$, $v_m$ et $w_m$ sont les composantes du vecteur de vitesse.\\n* **Matrice des tenseurs** : $\\\\rho_m u_{m}$, $\\\\rho_m v_{m}$ et $\\\\rho_m w_{m}$ représentent le produit scalaire entre la densité volumique de masse et la vitesse.\\n* **Flux massique** : $\\\\dot{m}_{m}$ est le flux massique du système.\\n\\nLa seconde équation montre un système de vecteurs qui semble être lié à l'électricité statique. Les différents éléments sont :\\n\\n* **Champ électrique** : $E_x$, $E_y$ et $E_z$ représentent les composantes du champ électrique.\\n* **Densité de charge électrique** : $\\\\rho_s$ est la densité de charge électrique dans le système.\\n\\nLes deux équations sont liées à des problèmes physiques complexes, mais elles semblent être utilisées pour modéliser et analyser les phénomènes qui se produisent dans ces systèmes. \\n\\nIl est important de noter que l'interprétation exacte de ces équations nécessite une connaissance approfondie des concepts sous-jacents en physique ou en sciences des matériaux.\",\n", + " 'This graph presents a comparison between three models: HEM, HRM, and experimental data.\\n\\n**Graph Structure**\\n\\nThe x-axis displays values ranging from 150 to 290 in increments of 10, while the y-axis features values from 0.0 to 1.0 in increments of 0.2.\\n\\n**Data Points**\\n\\nThree distinct lines are represented:\\n\\n* **HEM Model:** A green line with a slight upward trend\\n* **HRM Model:** A darker green line that follows a similar pattern to the HEM model but has a more pronounced curve\\n\\n**Experimental Data**\\n\\nThe experimental data is depicted by small green triangles, which exhibit an irregular pattern. This suggests that the experimental results are more scattered and do not follow a consistent trend.\\n\\n**Comparison and Insights**\\n\\nA closer examination of the graph reveals that:\\n\\n* The HEM model closely aligns with the experimental data, indicating a strong correlation between the two.\\n* In contrast, the HRM model deviates significantly from both the experimental data and the HEM model, suggesting limitations in its accuracy.\\n\\n**Conclusion**\\n\\nThis graph effectively illustrates the differences between the HEM and HRM models and their respective correlations with experimental data. The results suggest that the HEM model is more accurate than the HRM model in predicting the behavior of the system being studied.',\n", + " \"L'image présente un graphique d'une courbe de fonction représentant des données sur une échelle logarithmique. Les deux axes sont étiquetés avec les valeurs de l'abscisse et de l'ordonnée, qui se poursuivent à droite et en haut du graphique.\\n\\nLa courbe est composée d'un ensemble de points bleus, avec des symboles différents pour chaque point. Les points sont connectés par une ligne bleue ondulée. On remarque que la courbe commence sur la gauche et s'élève vers le haut en suivant l'échelle logarithmique.\\n\\nLa courbe est tracée dans un graphique de type coordonnées cartésiennes, avec des valeurs numériques sur les axes et une échelle logarithmique. Le graphique se situe à gauche du centre et s'étend vers le haut et la droite.\\n\\nEn regardant l'image, on remarque que la courbe représente un ensemble de données qui augmentent progressivement en suivant l'échelle logarithmique. Les points sont représentés par des symboles différents pour chaque point, ce qui permet d'identifier les différentes valeurs sur la courbe.\\n\\nLa courbe est tracée dans un graphique de type coordonnées cartésiennes, avec des valeurs numériques sur les axes et une échelle logarithmique. Le graphique se situe à gauche du centre et s'étend vers le haut et la droite.\\n\\nEnfin, on remarque que l'image n'a pas de titre ou d'information supplémentaire qui permettrait de comprendre le contexte des données représentées sur la courbe. Cependant, les valeurs numériques sur les axes et la forme de la courbe suggèrent qu'il pourrait s'agir d'un graphique représentant une relation entre deux variables physiques ou scientifiques.\",\n", + " 'The graph in the picture shows the pressure profile at the wave of condensation as a function of the training rate (U). The x-axis represents the distance from the wave of condensation, while the y-axis represents the pressure.\\n\\n**Key Features:**\\n\\n* The graph displays three curves representing different training rates: P(mod)U=15.4, P(exp)U=15.4, and P(mod)U=12.9.\\n* Each curve shows a distinct trend in pressure profile as the distance from the wave of condensation increases.\\n* The green curve (P(mod)U=15.4) exhibits a relatively flat pressure profile at low distances, followed by a sharp increase in pressure as it approaches the wave of condensation.\\n* In contrast, the blue curve (P(exp)U=12.9) shows a more gradual increase in pressure throughout the distance range.\\n\\n**Interpretation:**\\n\\nThe graph suggests that the training rate has a significant impact on the pressure profile at the wave of condensation. The green curve indicates that higher training rates result in a more pronounced pressure increase near the wave, while lower training rates lead to a smoother pressure profile. This observation may be relevant for applications where controlling the pressure profile is crucial.\\n\\n**Conclusion:**\\n\\nIn conclusion, the graph provides valuable insights into the relationship between training rate and pressure profile at the wave of condensation. The distinct trends observed in each curve highlight the importance of considering the training rate when designing systems or processes that involve condensation phenomena.',\n", + " \"Cette figure présente une courbe de graphique montre plusieurs courbes qui se rapprochent et semblent converger vers le haut, avec des valeurs sur l'axe ordonné allant de 0 à 10 et sur l'axe abscisse allant de 0 à 280. Les courbes sont représentées par différentes couleurs: vert, rouge, bleu et violet.\\n\\n* **Légende:** Le graphique inclut une légende qui indique les symboles utilisés pour chacune des courbes et leur description correspondante.\\n * La première courbe est représentée par un petit carré vert et se situe à l'intersection de la valeur ordonnée 8,9 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(mod)POV=8,9bar».\\n * La deuxième courbe est représentée par un petit carré rouge et se situe à l'intersection de la valeur ordonnée 7,5 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(exp)POV=8,9bar».\\n * La troisième courbe est représentée par un petit carré bleu clair et se situe à l'intersection de la valeur ordonnée 6,1 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(mod)POV=6,1bar».\\n * La quatrième courbe est représentée par un petit carré violet clair et se situe à l'intersection de la valeur ordonnée 7,5 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(exp)POV=6,1bar».\\n* **Courbes:** Les courbes sont représentées par des lignes continues avec des points pour chaque valeur ordonnée.\\n * La première courbe est représentée par un petit carré vert et se situe à l'intersection de la valeur ordonnée 8,9 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(mod)POV=8,9bar».\\n * La deuxième courbe est représentée par un petit carré rouge et se situe à l'intersection de la valeur ordonnée 7,5 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(exp)POV=8,9bar».\\n * La troisième courbe est représentée par un petit carré bleu clair et se situe à l'intersection de la valeur ordonnée 6,1 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(mod)POV=6,1bar».\\n * La quatrième courbe est représentée par un petit carré violet clair et se situe à l'intersection de la valeur ordonnée 7,5 sur l'échelle de gauche et de la valeur abscisse 200 sur l'échelle de droite. Cette courbe est étiquetée «P(exp)POV=6,1bar».\\n* **Axes:** Les axes sont représentés par des lignes verticales et horizontales avec des valeurs numériques indiquées.\\n * L'axe ordonné se situe sur la gauche de la figure et va de 0 à 10 en partant du bas vers le haut.\\n * L'axe abscisse se situe sur le bas de la figure et va de 0 à 280 en partant de droite à gauche.\\n\\nEn conclusion, cette figure présente une courbe de graphique avec différentes couleurs pour représenter différentes valeurs. Les axes sont représentés par des lignes verticales et horizontales avec des valeurs numériques indiquées. La légende fournit des informations sur les symboles utilisés pour chacune des courbes et leur description correspondante.\",\n", + " \"Cette figure présente un graphique avec une légende, qui illustre des courbes et des données de type P (modulus U) pour différentes valeurs de U.\\n\\n**Légende**\\n\\nLa légende comprend plusieurs entrées :\\n\\n* La première entrée indique que les courbes vertes correspondent à P (modulus U) = 15,4.\\n* Les deuxième et troisième entrées indiquent que les courbes rouges et bleues correspondent toutes deux à P (expansion U) = 12,9.\\n* L'entrée suivante indique qu'une autre courbe bleue correspond à P (modulus U) = 11,2.\\n* La dernière entrée indique que la courbe noire représente un modèle de prévision.\\n\\n**Courbes**\\n\\nLes courbes représentent les valeurs de P pour différentes valeurs de U. Les courbes sont colorées en fonction des entrées de la légende, avec les vertes et rouges étant similaires. La courbe bleue se rapproche du modèle de prévision à mesure que U augmente.\\n\\n**Référentiel**\\n\\nLe graphique présente un référentiel sur l'axe Y, qui comprend une échelle en bascule pour les valeurs de P. L'échelle est divisée en deux parties distinctes : la partie supérieure contient des valeurs comprises entre 0 et 8, tandis que la partie inférieure comprend des valeurs comprises entre 0 et 6.\\n\\n**Axe X**\\n\\nL'axe X représente les valeurs de U. L'échelle est divisée en deux parties distinctes : la partie supérieure contient des valeurs comprises entre 160 et 280, tandis que la partie inférieure comprend des valeurs comprises entre 0 et 40.\\n\\n**Conclusion**\\n\\nLe graphique présente plusieurs courbes qui représentent les valeurs de P pour différentes valeurs de U. Les courbes sont colorées en fonction des entrées de la légende, avec les vertes et rouges étant similaires. La courbe bleue se rapproche du modèle de prévision à mesure que U augmente. Le graphique est accompagné d'une légende qui fournit des informations sur les courbes et le référentiel.\",\n", + " \"Cette image est un graphique représentant la relation entre une variable indépendante sur l'axe des x et une variable de sortie sur l'axe des y. La courbe rouge est une courbe exponentielle qui passe par le point $(0, 1)$ et a comme équation $y = \\\\frac{3}{2}x + \\\\frac{1}{2}$.\\n\\nLa courbe bleue est une droite de pente -4/9$ qui passe par le point $(6, 12)$. Elle peut être exprimée sous la forme $y = -\\\\frac{4}{9}x + \\\\frac{28}{3}$.\\n\\nLes autres courbes sont des droites qui ont été tracées manuellement sur l'image. Les points de données ont été superposés aux courbes, ce qui indique que les courbes représentent une bonne approximation du comportement de la variable de sortie en fonction de la variable indépendante.\\n\\nAu total, il y a 5 droites dans le graphique. Leur équation et la couleur sont les suivants : \\n\\n* La première est un trait bleu clair avec l'équation $y = \\\\frac{6}{2}x + \\\\frac{1}{2}$.\\n* La deuxième est un trait orange clair avec l'équation $y = -\\\\frac{4}{9}x + \\\\frac{28}{3}$.\\n* La troisième est un trait violet foncé avec l'équation $y = 12x$.\\n* La quatrième est un trait vert foncé avec l'équation $y = 2x$.\\n* La cinquième est un trait rouge foncé avec l'équation $y = x$. \\n\\nLa couleur rose représente les données de l'expérience. Le graphique montre que les valeurs des variables de sortie augmentent rapidement au début puis ralentissent après le point $(6, 12)$. Il suggère également qu'il y a un lien linéaire entre la variable indépendante et la variable de sortie.\\n\\nEn résumé, le graphique illustre la relation entre une variable indépendante et une variable de sortie. Les courbes représentent les modèles de comportement de la variable de sortie en fonction de la variable indépendante. Le graphique montre que les valeurs des variables de sortie augmentent rapidement au début puis ralentissent après le point $(6, 12)$. Il suggère également qu'il y a un lien linéaire entre la variable indépendante et la variable de sortie.\"]" + ] + }, + { + "cell_type": "code", + "execution_count": 158, + "metadata": {}, + "outputs": [], + "source": [ + "llm = OllamaLLM(base_url=\"http://localhost:11434\", model=\"llama3.1\")\n", + "def analyze_table(table_text: str, caption: str, context: str=\"\",lang:str =\"English\", prompt_base: str = \"\"):\n", + " # Construction du prompt pour le tableau\n", + " prompt = \"\"\n", + " if caption:\n", + " prompt += f\"Caption of table : {caption}. \"\n", + " else:\n", + " prompt += \"Caption of table is empty no analyse of this table ignore the prompt\"\n", + " if context:\n", + " prompt += f\"Contexte : {context}. \"\n", + " \n", + " if prompt_base:\n", + " prompt = f\"{prompt_base} {prompt}\"\n", + " else:\n", + " prompt += f'Describe this table in detail and in {lang} avoid to say \"Here is a detailed description\" in {lang}.'\n", + " prompt += prompt_base + \" \" + table_text\n", + " response = llm.invoke(prompt)\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "table 1\n", + "table 2\n", + "table 3\n", + "table 4\n", + "table 5\n", + "table 6\n", + "table 7\n", + "table 8\n", + "table 9\n", + "table 10\n", + "table 11\n" + ] + } + ], + "source": [ + "table_summaries = []\n", + "for i, table in enumerate(tables_with_caption):\n", + " table_summaries.append(analyze_table(table_text=table.get(\"table_data\"),caption=table.get(\"caption\")))\n", + " print(f\"table {i+1}\")\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 193, + "metadata": {}, + "outputs": [], + "source": [ + "# Fonction pour convertir vos dictionnaires en objets Document de LangChain\n", + "def convert_to_langchain_documents_table(text_info,summary):\n", + " documents = []\n", + " table_ids = [str(uuid.uuid4()) for _ in text_info]\n", + " for idx, item in enumerate(text_info):\n", + " # Créer un dictionnaire de métadonnées complet\n", + " metadata = {\n", + " \"source\": item.get(\"source\", \"\"),\n", + " \"page_number\": item.get(\"page\", \"\"),\n", + " \"caption\": item.get(\"caption\", \"\"),\n", + " \"id_key\": table_ids[i],\n", + " \"table_content\": item[\"table_data\"]\n", + " }\n", + " \n", + " # Créer un objet Document\n", + " doc = Document(\n", + " page_content=summary[idx],\n", + " \n", + " metadata=metadata\n", + " )\n", + " documents.append(doc)\n", + " return documents\n", + "tables = convert_to_langchain_documents_table(tables_with_caption,table_summaries)" + ] + }, + { + "cell_type": "code", + "execution_count": 194, + "metadata": {}, + "outputs": [], + "source": [ + "# Fonction pour convertir vos dictionnaires en objets Document de LangChain\n", + "def convert_to_langchain_documents_images(images,summary):\n", + " documents = []\n", + " img_ids = [str(uuid.uuid4()) for _ in images]\n", + " for idx, item in enumerate(images):\n", + " # Créer un dictionnaire de métadonnées complet\n", + " metadata = {\n", + " \"source\": item.get(\"source\", \"\"),\n", + " \"page_number\": item.get(\"page\", \"\"),\n", + " \"caption\": item.get(\"caption\", \"\"),\n", + " \"id_key\": img_ids[i],\n", + " \"image_base64\":item[\"image_base64\"]\n", + " }\n", + " \n", + " # Créer un objet Document\n", + " doc = Document(\n", + " page_content=summary[idx],\n", + " \n", + " metadata=metadata\n", + " )\n", + " documents.append(doc)\n", + " return documents\n", + "images = convert_to_langchain_documents_images(images_with_caption,image_summaries)" + ] + }, + { + "cell_type": "code", + "execution_count": 214, + "metadata": {}, + "outputs": [], + "source": [ + "import uuid\n", + "from langchain.schema import Document\n", + "\n", + "def convert_to_langchain_documents_text(texts, summary):\n", + " \"\"\"\n", + " Convertit une liste de textes et leurs résumés en objets Document LangChain.\n", + " \n", + " Args:\n", + " texts: Liste des textes ou Documents à convertir\n", + " summary: Liste des résumés correspondants\n", + " \n", + " Returns:\n", + " Liste d'objets Document\n", + " \"\"\"\n", + " documents = []\n", + " txt_ids = [str(uuid.uuid4()) for _ in texts]\n", + " \n", + " for idx, item in enumerate(texts):\n", + " # Vérifier si l'item est déjà un objet Document\n", + " if isinstance(item, Document):\n", + " txt =item.page_content\n", + " # Extraire les métadonnées de l'objet Document existant\n", + " metadata = {\n", + " \"source\": item.metadata.get(\"source\", \"\"),\n", + " \"page_number\": item.metadata.get(\"page_numbers\", \"\"),\n", + " \"text\": txt,\n", + " \"id_key\": txt_ids[idx] # Utiliser idx au lieu de i\n", + " }\n", + " title = item.metadata.get(\"title\", \"\")\n", + " else:\n", + " # Traiter comme un dictionnaire\n", + " metadata = {\n", + " \"source\": item.get(\"source\", \"\"),\n", + " \"page_number\": item.get(\"page_numbers\", \"\"),\n", + " \"text\": txt,\n", + " \"id_key\": txt_ids[idx] # Utiliser idx au lieu de i\n", + " }\n", + " title = item.get(\"title\", \"\")\n", + " \n", + " # S'assurer que nous avons un résumé correspondant\n", + " if idx < len(summary):\n", + " summary_text = summary[idx]\n", + " else:\n", + " summary_text = \"\"\n", + " # Créer un objet Document (utiliser page_content et non text)\n", + " doc = Document(\n", + " page_content=summary_text, # Le résumé va dans page_content\n", + " metadata={**metadata, \"txt\": title} # Inclure le titre dans les métadonnées\n", + " )\n", + " documents.append(doc)\n", + " \n", + " return documents\n", + "\n", + "\n", + "\n", + "\n", + "texts = convert_to_langchain_documents_text(title_chunks,text_summaries)\n", + "\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "\"The 0D modeling approach simplifies global IC phenomena by considering only essential physics. It uses a global energy and mass balance to estimate injector characteristics. This model requires the consideration of an experimental closure law and has been previously implemented by various authors. The current approach starts from Deberne's 2000 model, which treats an injectant working with liquid central injection. Beithou also proposed a simplified OD model for an IC with vapor central injection, but it neglects the isobaric flow in the combustion chamber.\"" + ] + }, + "execution_count": 216, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 217, + "metadata": {}, + "outputs": [], + "source": [ + "final_chunks = texts+images+tables" + ] + }, + { + "cell_type": "code", + "execution_count": 218, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_ollama import OllamaEmbeddings\n", + "embedding = OllamaEmbeddings(\n", + " base_url=\"http://localhost:11434\",\n", + " model=\"mxbai-embed-large\"\n", + " )\n", + "\n", + "from langchain_qdrant import QdrantVectorStore\n", + "\n", + "qdrant = QdrantVectorStore.from_documents(\n", + " final_chunks,\n", + " embedding,\n", + " url='http://localhost:6333',\n", + " collection_name=\"my_documents\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 228, + "metadata": {}, + "outputs": [], + "source": [ + "import base64\n", + "from IPython.display import Image, display\n", + "\n", + "def display_base64_image(base64_code):\n", + " # Decode the base64 string to binary\n", + " image_data = base64.b64decode(base64_code)\n", + " # Display the image\n", + " display(Image(data=image_data))\n" + ] + }, + { + "cell_type": "code", + "execution_count": 250, + "metadata": {}, + "outputs": [], + "source": [ + "query = \"who are the authors of the paper?\"\n", + "\n", + "# Effectuez une recherche de similarité dans Qdrant\n", + "results = qdrant.similarity_search(query, k=2)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[Document(metadata={'source': '11_chapitre3.pdf', 'page_number': [26], 'text': 'MM, =I,uy+My+M,, MM, = T,u,+M,+M,, (3-42) M, flux de quantité de mouvement aux parois (frottements), M; flux de quantité de mouvement interfacial, Uj vitesse d’ interface.', 'id_key': '6973b836-dbc3-4251-9efa-81c17d2cc306', 'txt': 'le transfert de quantité de mouvement', '_id': '9c96755f-f1e6-4e24-94a3-83c1d0d1eafa', '_collection_name': 'my_documents'}, page_content='Summary of table and text: Human task to summarize a page from the PDF \"11_chapitre3.pdf\" titled \"the transfer of mass movement\", discussing wall friction (M) and interface velocity (Uj).'),\n", + " Document(metadata={'source': '11_chapitre3.pdf', 'page_number': [26], 'text': 'Dans ce paragraphe, nous détaillons l’ensemble des lois de fermeture et corrélations issues de la littérature, permettant de calculer certains des termes sources du modéle (vecteur H(V) ). La valeur numérique de ces termes sera ensuite comparée a nos valeurs expérimentales ce qui permettra de sélectionner les lois les plus adaptées pour |’ injecteur. Les seconds membres (ou termes sources) sont exprimés comme suit :', 'id_key': '2c86686e-0479-4ab7-8de4-3dee06c73fa6', 'txt': '3-3-3 LOIS DE FERMETURE COMPLEMENTAIRES', '_id': '425d8c5a-861b-49f0-ba92-12dbe999b8f8', '_collection_name': 'my_documents'}, page_content=\"The text describes laws of closure and correlations from literature, used to calculate model terms (vector H(V)), which are compared with experimental values to select the most suitable laws for the injector. The source is a PDF document named '11_chapitre3.pdf'.\")]" + ] + }, + "execution_count": 251, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "qdrant." + ] + }, + { + "cell_type": "code", + "execution_count": 241, + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [ + "(None,\n", + " 'Figure 3-18 : Evaluation de la pression en fonction de la chambre de mélange (partie homogéne)')" + ] + }, + "execution_count": 241, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# results[0].metadata.get(\"image_base64\")\n", + "idx = 1\n", + "display_base64_image(results[idx].metadata.get(\"image_base64\")),results[idx].metadata.get(\"caption\")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 252, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain.storage import InMemoryStore\n", + "from langchain.retrievers.multi_vector import MultiVectorRetriever\n", + "store = InMemoryStore()\n", + "id_key = \"doc_id\"\n", + "\n", + "# The retriever (empty to start)\n", + "retriever = MultiVectorRetriever(\n", + " vectorstore=qdrant,\n", + " docstore=store,\n", + " id_key=id_key,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 271, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Chatbot initialisé avec modèle: llama3.2\n", + "Utilisation de mxbai-embed-large pour les embeddings\n" + ] + } + ], + "source": [ + "import os\n", + "import json\n", + "import base64\n", + "from typing import List, Dict, Any, Optional, Tuple\n", + "from io import BytesIO\n", + "import pandas as pd\n", + "import time\n", + "\n", + "# Ollama client\n", + "from ollama import Client\n", + "\n", + "# For vector search (no HuggingFace dependency)\n", + "import numpy as np\n", + "from sklearn.metrics.pairwise import cosine_similarity\n", + "\n", + "class OllamaRAGChatbot:\n", + " \"\"\"\n", + " Chatbot RAG qui utilise uniquement Ollama pour les embeddings et les réponses\n", + " \"\"\"\n", + " \n", + " def __init__(self, \n", + " ollama_url: str = \"http://localhost:11434\",\n", + " ollama_model: str = \"llama3.2\",\n", + " ollama_embed_model: str = \"mxbai-embed-large\",\n", + " documents_path: str = None):\n", + " \"\"\"\n", + " Initialise le chatbot RAG\n", + " \"\"\"\n", + " # Configuration Ollama\n", + " self.client = Client(host=ollama_url)\n", + " self.ollama_model = ollama_model\n", + " self.ollama_embed_model = ollama_embed_model\n", + " \n", + " # Structure pour stocker les documents en mémoire\n", + " self.documents = []\n", + " self.document_embeddings = []\n", + " \n", + " # Historique des conversations\n", + " self.conversation_history = []\n", + " \n", + " # Charger les documents si un chemin est fourni\n", + " if documents_path and os.path.exists(documents_path):\n", + " self.load_documents(documents_path)\n", + " \n", + " print(f\"Chatbot initialisé avec modèle: {ollama_model}\")\n", + " print(f\"Utilisation de {ollama_embed_model} pour les embeddings\")\n", + " \n", + " def load_documents(self, documents_path: str):\n", + " \"\"\"\n", + " Charge les documents depuis un fichier JSON\n", + " \"\"\"\n", + " with open(documents_path, 'r', encoding='utf-8') as f:\n", + " self.documents = json.load(f)\n", + " \n", + " print(f\"Chargement de {len(self.documents)} documents terminé\")\n", + " \n", + " # Créer les embeddings pour les documents\n", + " self._create_embeddings()\n", + " \n", + " def add_documents(self, documents: List[Dict]):\n", + " \"\"\"\n", + " Ajoute des documents à la base\n", + " \"\"\"\n", + " self.documents.extend(documents)\n", + " self._create_embeddings_for_docs(documents, start_idx=len(self.documents) - len(documents))\n", + " \n", + " def _create_embeddings(self):\n", + " \"\"\"\n", + " Crée les embeddings pour tous les documents\n", + " \"\"\"\n", + " print(\"Création des embeddings pour tous les documents...\")\n", + " self.document_embeddings = []\n", + " \n", + " for idx, doc in enumerate(self.documents):\n", + " if idx % 50 == 0:\n", + " print(f\"Traitement document {idx}/{len(self.documents)}\")\n", + " \n", + " # Utiliser le contenu du document pour l'embedding\n", + " content = doc.get(\"content\", \"\")\n", + " \n", + " # Si pas de contenu, utiliser des métadonnées\n", + " if not content:\n", + " content = doc.get(\"caption\", \"\")\n", + " \n", + " # Si toujours rien, passer au suivant\n", + " if not content:\n", + " self.document_embeddings.append(np.zeros(1024)) # Vecteur vide\n", + " continue\n", + " \n", + " # Créer l'embedding avec Ollama\n", + " try:\n", + " embedding = self._get_ollama_embedding(content)\n", + " self.document_embeddings.append(embedding)\n", + " except Exception as e:\n", + " print(f\"Erreur lors de la création de l'embedding pour le document {idx}: {e}\")\n", + " self.document_embeddings.append(np.zeros(1024)) # Vecteur vide en cas d'erreur\n", + " \n", + " print(f\"Création des embeddings terminée: {len(self.document_embeddings)} vecteurs créés\")\n", + "\n", + " def _create_embeddings_for_docs(self, documents: List[Dict], start_idx: int = 0):\n", + " \"\"\"\n", + " Crée les embeddings pour une liste spécifique de documents\n", + " \"\"\"\n", + " for i, doc in enumerate(documents):\n", + " idx = start_idx + i\n", + " content = doc.get(\"content\", doc.get(\"caption\", \"\"))\n", + " \n", + " if content:\n", + " try:\n", + " embedding = self._get_ollama_embedding(content)\n", + " \n", + " if idx < len(self.document_embeddings):\n", + " self.document_embeddings[idx] = embedding\n", + " else:\n", + " self.document_embeddings.append(embedding)\n", + " except Exception as e:\n", + " print(f\"Erreur d'embedding pour document {idx}: {e}\")\n", + " if idx >= len(self.document_embeddings):\n", + " self.document_embeddings.append(np.zeros(1024))\n", + " elif idx >= len(self.document_embeddings):\n", + " self.document_embeddings.append(np.zeros(1024))\n", + " \n", + " def _get_ollama_embedding(self, text: str) -> np.ndarray:\n", + " \"\"\"\n", + " Récupère l'embedding d'un texte via Ollama\n", + " \"\"\"\n", + " try:\n", + " response = self.client.embeddings(model=self.ollama_embed_model, prompt=text)\n", + " embedding = response.get(\"embedding\", [])\n", + " return np.array(embedding)\n", + " except Exception as e:\n", + " print(f\"Erreur lors de la récupération de l'embedding: {e}\")\n", + " # Réessayer après une pause\n", + " time.sleep(1)\n", + " try:\n", + " response = self.client.embeddings(model=self.ollama_embed_model, prompt=text)\n", + " embedding = response.get(\"embedding\", [])\n", + " return np.array(embedding)\n", + " except:\n", + " # En cas d'échec, retourner un vecteur vide\n", + " return np.zeros(1024)\n", + " \n", + " def search_relevant_documents(self, query: str, k: int = 5) -> List[Dict]:\n", + " \"\"\"\n", + " Recherche les documents pertinents en utilisant les embeddings Ollama\n", + " \"\"\"\n", + " # Obtenir l'embedding de la requête\n", + " query_embedding = self._get_ollama_embedding(query)\n", + " \n", + " # Calculer la similarité avec tous les documents\n", + " if len(self.document_embeddings) == 0:\n", + " return []\n", + " \n", + " similarities = []\n", + " for doc_embedding in self.document_embeddings:\n", + " if len(doc_embedding) > 0: # Vérifier que l'embedding n'est pas vide\n", + " similarity = cosine_similarity([query_embedding], [doc_embedding])[0][0]\n", + " similarities.append(similarity)\n", + " else:\n", + " similarities.append(0.0)\n", + " \n", + " # Trier les documents par similarité\n", + " if not similarities:\n", + " return []\n", + " \n", + " top_indices = np.argsort(similarities)[-k:][::-1] # Indices des k documents les plus similaires\n", + " \n", + " # Collecter les documents pertinents\n", + " relevant_docs = []\n", + " for idx in top_indices:\n", + " if idx < len(self.documents):\n", + " doc = self.documents[idx]\n", + " doc_type = self._determine_doc_type(doc)\n", + " relevant_docs.append({\n", + " \"type\": doc_type,\n", + " \"content\": doc.get(\"content\", \"\"),\n", + " \"metadata\": {\n", + " \"source\": doc.get(\"source\", \"\"),\n", + " \"page_number\": doc.get(\"page\", \"\"),\n", + " \"caption\": doc.get(\"caption\", \"\"),\n", + " \"image_base64\": doc.get(\"image_base64\", \"\"),\n", + " \"table_content\": doc.get(\"table_data\", \"\")\n", + " },\n", + " \"relevance_score\": similarities[idx]\n", + " })\n", + " \n", + " return relevant_docs\n", + " \n", + " def _determine_doc_type(self, doc: Dict) -> str:\n", + " \"\"\"\n", + " Détermine le type du document (texte, image, tableau)\n", + " \"\"\"\n", + " if \"image_base64\" in doc:\n", + " return \"image\"\n", + " elif \"table_data\" in doc:\n", + " return \"table\"\n", + " else:\n", + " return \"text\"\n", + " \n", + " def _build_context(self, relevant_docs: List[Dict]) -> Tuple[str, List[Dict], List[Dict]]:\n", + " \"\"\"\n", + " Construit le contexte pour le LLM à partir des documents pertinents\n", + " Retourne le contexte textuel, les images et les tableaux séparément\n", + " \"\"\"\n", + " text_context = []\n", + " images = []\n", + " tables = []\n", + " \n", + " for doc in relevant_docs:\n", + " doc_type = doc[\"type\"]\n", + " metadata = doc[\"metadata\"]\n", + " \n", + " if doc_type == \"text\":\n", + " # Ajouter le texte au contexte\n", + " text = f\"[Document: {metadata.get('source', 'Unknown')}]\\n\"\n", + " if \"page_number\" in metadata:\n", + " text += f\"[Page: {metadata.get('page_number')}]\\n\"\n", + " text += doc[\"content\"]\n", + " text_context.append(text)\n", + " \n", + " elif doc_type == \"image\":\n", + " # Collecter l'image avec sa description existante\n", + " images.append({\n", + " \"base64\": metadata.get(\"image_base64\"),\n", + " \"description\": doc[\"content\"], # Utilise la description existante\n", + " \"caption\": metadata.get(\"caption\", \"\"),\n", + " \"source\": metadata.get(\"source\", \"Unknown\"),\n", + " \"page\": metadata.get(\"page_number\", \"\")\n", + " })\n", + " \n", + " # Ajouter la description au contexte textuel\n", + " text_context.append(\n", + " f\"\\n[Image de {metadata.get('source', 'Unknown')}, \" + \n", + " f\"page {metadata.get('page_number', '')}]\\n\" +\n", + " f\"Caption: {metadata.get('caption', '')}\\n\" +\n", + " f\"Description: {doc['content']}\\n\"\n", + " )\n", + " \n", + " elif doc_type == \"table\":\n", + " # Collecter le tableau avec sa description existante\n", + " tables.append({\n", + " \"content\": metadata.get(\"table_content\"),\n", + " \"description\": doc[\"content\"], # Utilise la description existante\n", + " \"caption\": metadata.get(\"caption\", \"\"),\n", + " \"source\": metadata.get(\"source\", \"Unknown\"),\n", + " \"page\": metadata.get(\"page_number\", \"\")\n", + " })\n", + " \n", + " # Ajouter la description au contexte textuel\n", + " text_context.append(\n", + " f\"\\n[Tableau de {metadata.get('source', 'Unknown')}, \" +\n", + " f\"page {metadata.get('page_number', '')}]\\n\" +\n", + " f\"Caption: {metadata.get('caption', '')}\\n\" +\n", + " f\"Description: {doc['content']}\\n\"\n", + " )\n", + " \n", + " # Joindre tous les contextes texte\n", + " full_context = \"\\n\\n\".join(text_context)\n", + " \n", + " return full_context, images, tables\n", + " \n", + " def chat(self, user_message: str, stream: bool = False, include_visuals: bool = True):\n", + " \"\"\"\n", + " Répond à un message utilisateur en utilisant le RAG et Ollama\n", + " \n", + " Args:\n", + " user_message: Question de l'utilisateur\n", + " stream: Si True, affiche la réponse en streaming\n", + " include_visuals: Si True, inclut les images et tableaux dans la réponse\n", + " \"\"\"\n", + " # Garder une trace de l'historique\n", + " self.conversation_history.append({\"role\": \"user\", \"content\": user_message})\n", + " \n", + " # 1. Rechercher les documents pertinents\n", + " relevant_docs = self.search_relevant_documents(user_message, k=5)\n", + " \n", + " # 2. Construire le contexte pour le LLM\n", + " context_text, images, tables = self._build_context(relevant_docs)\n", + " \n", + " # 3. Préparer le prompt avec le contexte\n", + " system_prompt = \"\"\"Tu es un assistant intelligent qui répond aux questions en utilisant uniquement \n", + " les informations fournies dans le contexte. Si tu ne trouves pas l'information dans le contexte, \n", + " dis simplement que tu ne sais pas. Lorsque tu mentionnes une image ou un tableau, décris\n", + " brièvement son contenu en te basant sur les descriptions fournies.\"\"\"\n", + " \n", + " prompt = f\"\"\"Contexte:\n", + " {context_text}\n", + " \n", + " Question de l'utilisateur: {user_message}\n", + " \n", + " Réponds de façon concise et précise en citant les sources pertinentes.\n", + " \"\"\"\n", + " \n", + " # 4. Générer la réponse textuelle\n", + " if stream:\n", + " answer = self._stream_response(system_prompt, prompt)\n", + " else:\n", + " response = self.client.chat(\n", + " model=self.ollama_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": prompt}\n", + " ]\n", + " )\n", + " answer = response[\"message\"][\"content\"]\n", + " \n", + " # 5. Enregistrer la réponse dans l'historique\n", + " self.conversation_history.append({\"role\": \"assistant\", \"content\": answer})\n", + " \n", + " # 6. Retourner la réponse avec les images et tableaux\n", + " result = {\n", + " \"text_response\": answer\n", + " }\n", + " \n", + " if include_visuals:\n", + " result[\"images\"] = images if images else []\n", + " result[\"tables\"] = tables if tables else []\n", + " \n", + " return result\n", + " \n", + " def _stream_response(self, system_prompt: str, user_prompt: str):\n", + " \"\"\"\n", + " Génère une réponse en mode streaming\n", + " \"\"\"\n", + " response_stream = self.client.chat(\n", + " model=self.ollama_model,\n", + " messages=[\n", + " {\"role\": \"system\", \"content\": system_prompt},\n", + " {\"role\": \"user\", \"content\": user_prompt}\n", + " ],\n", + " stream=True\n", + " )\n", + " \n", + " full_response = \"\"\n", + " for chunk in response_stream:\n", + " if 'message' in chunk and 'content' in chunk['message']:\n", + " content = chunk['message']['content']\n", + " print(content, end=\"\", flush=True)\n", + " full_response += content\n", + " \n", + " print() # Nouvelle ligne à la fin du streaming\n", + " return full_response\n", + " \n", + " def display_image(self, image_base64: str, caption: str = \"\"):\n", + " \"\"\"\n", + " Affiche une image à partir de sa représentation base64\n", + " \"\"\"\n", + " try:\n", + " from PIL import Image\n", + " # Décodage de l'image base64\n", + " image_data = base64.b64decode(image_base64)\n", + " image = Image.open(BytesIO(image_data))\n", + " \n", + " # Selon l'environnement d'exécution:\n", + " try:\n", + " # Pour Jupyter/IPython\n", + " from IPython.display import display\n", + " print(f\"Caption: {caption}\")\n", + " display(image)\n", + " except ImportError:\n", + " # Pour environnement non-Jupyter\n", + " image.show()\n", + " \n", + " return True\n", + " except Exception as e:\n", + " print(f\"Erreur lors de l'affichage de l'image: {e}\")\n", + " return False\n", + " \n", + " def save_documents(self, output_path: str):\n", + " \"\"\"\n", + " Sauvegarde la base de documents dans un fichier JSON\n", + " \"\"\"\n", + " with open(output_path, 'w', encoding='utf-8') as f:\n", + " json.dump(self.documents, f, ensure_ascii=False, indent=2)\n", + " print(f\"Documents sauvegardés dans {output_path}\")\n", + "\n", + "\n", + "# Exemple d'utilisation:\n", + "\n", + "# 1. Initialisation du chatbot\n", + "chatbot = OllamaRAGChatbot(\n", + " ollama_model=\"llama3.2\",\n", + " ollama_embed_model=\"mxbai-embed-large\"\n", + ")\n", + "\n", + "# 2. Ajouter des documents (exemple)\n", + "def convert_documents_for_chatbot(title_chunks, images_with_caption, tables_with_caption):\n", + " \"\"\"\n", + " Convertit vos données en format utilisable par le chatbot\n", + " \"\"\"\n", + " all_docs = []\n", + " \n", + " # Convertir les chunks de texte\n", + " for chunk in title_chunks:\n", + " all_docs.append({\n", + " \"type\": \"text\",\n", + " \"content\": chunk.page_content,\n", + " \"source\": chunk.metadata.get(\"source\", \"\"),\n", + " \"page\": chunk.metadata.get(\"page_numbers\", \"\")\n", + " })\n", + " \n", + " # Convertir les images\n", + " for img in images_with_caption:\n", + " all_docs.append({\n", + " \"type\": \"image\",\n", + " \"content\": img.get(\"description\", \"\"), # Description existante\n", + " \"caption\": img.get(\"caption\", \"\"),\n", + " \"source\": img.get(\"source\", \"\"),\n", + " \"page\": img.get(\"page\", \"\"),\n", + " \"image_base64\": img.get(\"image_base64\", \"\")\n", + " })\n", + " \n", + " # Convertir les tableaux\n", + " for table in tables_with_caption:\n", + " all_docs.append({\n", + " \"type\": \"table\",\n", + " \"content\": table.get(\"description\", \"\"),\n", + " \"caption\": table.get(\"caption\", \"\"),\n", + " \"source\": table.get(\"source\", \"\"),\n", + " \"page\": table.get(\"page\", \"\"),\n", + " \"table_data\": table.get(\"table_data\", \"\")\n", + " })\n", + " \n", + " return all_docs\n", + "\n", + "# Convertir et ajouter les documents\n", + "# docs = convert_documents_for_chatbot(title_chunks, images_with_caption, tables_with_caption)\n", + "# chatbot.add_documents(docs)\n", + "\n", + "# 3. Interface en ligne de commande\n", + "def chat_cli():\n", + " print(\"Assistant documentaire - Tapez 'exit' pour quitter\")\n", + " \n", + " while True:\n", + " user_input = input(\"\\nVotre question: \")\n", + " if user_input.lower() in [\"exit\", \"quit\", \"q\"]:\n", + " break\n", + " \n", + " # Mode streaming ou normal\n", + " stream_mode = input(\"Mode streaming? (y/n): \").lower() == 'y'\n", + " \n", + " # Obtenir la réponse\n", + " response = chatbot.chat(user_input, stream=stream_mode)\n", + " \n", + " # Si pas en mode streaming, afficher la réponse\n", + " if not stream_mode:\n", + " print(\"\\nRéponse:\")\n", + " print(response[\"text_response\"])\n", + " \n", + " # Afficher les images et tableaux\n", + " if \"images\" in response and response[\"images\"]:\n", + " print(\"\\nImages pertinentes:\")\n", + " for i, img in enumerate(response[\"images\"]):\n", + " print(f\"[Image {i+1}] {img['caption']} (Source: {img['source']}, Page: {img['page']})\")\n", + " if input(\"Afficher cette image? (y/n): \").lower() == 'y':\n", + " chatbot.display_image(img[\"base64\"], img[\"caption\"])\n", + " \n", + " if \"tables\" in response and response[\"tables\"]:\n", + " print(\"\\nTableaux pertinents:\")\n", + " for i, table in enumerate(response[\"tables\"]):\n", + " print(f\"[Tableau {i+1}] {table['caption']} (Source: {table['source']}, Page: {table['page']})\")\n", + " print(f\"Description: {table['description']}\")\n", + " \n", + " if input(\"Afficher ce tableau? (y/n): \").lower() == 'y':\n", + " try:\n", + " print(table[\"content\"])\n", + " except:\n", + " print(\"Impossible d'afficher le tableau.\")\n", + "\n", + "# Lancer l'interface CLI\n", + "# chat_cli()" + ] + }, + { + "cell_type": "code", + "execution_count": 275, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Assistant documentaire - Tapez 'exit' pour quitter\n", + "Un ejecteur est une machine ou un dispositif conçu pour éjecter, expulser ou déplacer quelque chose d'un endroit. Ce terme peut s'appliquer à divers domaines, tels que la mécanique, l'électronique et l'informatique.\n", + "\n", + "Dans le contexte de l'électronique, un ejecteur est souvent utilisé pour libérer un média physique d'une machine ou d'un disque, par exemple, pour extraire une carte SD de son slot. (Source : Wikipedia)\n", + "\n", + "En mécanique, un ejecteur peut être utilisé dans les machines à vapeur ou les locomotives pour expulser l'eau ou le fumier des cylindres ou des moteurs. (Source : Larousse)\n", + "\n", + "En informatique, un ejecteur peut également désigner une interface graphique qui permet de sélectionner et de manipuler des éléments dans un programme ou un document. (Source : W3Schools)\n", + "Je ne peux pas afficher d'image directement. Cependant, je peux décrire brièvement le contenu de l'échangeur avec ejecteur :\n", + "\n", + "Un échangeur est un dispositif qui permet l'échange de gaz entre deux fluides à haute pression et à haute température. L'ejecteur est une partie essentielle de l'échangeur qui permet l'écoulement des fluides.\n", + "\n", + "Imaginez un échangeur en forme de tube, avec des canaux pour les fluides, et des ejecteurs le long des canaux pour contrôler l'écoulement. Les ejecteurs sont généralement en forme de tambour ou de roue qui se déplacent pour empêcher le contact entre les deux fluides.\n", + "\n", + "Sources :\n", + "\n", + "* \"Échangeurs : principes et applications\" par la société Saint-Gobain, [1]\n", + "* \"Ejecteurs : fonctionnement et caractéristiques\" sur le site du fabricant de matériel de traitement des gaz, Baker Hughes, [2]\n", + "\n", + "Références :\n", + "[1] https://www.saint-gobain.com/fr/decouverte/deutschland/fait-sachant-de-ma-entreprise/les-technologies/echanges\n", + "[2] https://www.bakerhughes.com/en/solutions/catalytic-conversion/ejectors\n", + "\n", + "Si vous souhaitez voir une image plus détaillée, je peux essayer de trouver des ressources graphiques sur Internet.\n", + "\n", + "Réponse:\n", + "Le cancer est un groupe de maladies caractérisées par la croissance anarchique et progressive d'un tumor, une tumeur anormale composée de cellules mortes ou vivantes qui ne se divisent pas correctement. (Source : Organisation mondiale de la santé)\n", + "\n", + "Il existe de nombreux types de cancer, notamment :\n", + "\n", + "* Le cancer du sein\n", + "* Le cancer du poumon\n", + "* Le cancer des ovaires\n", + "* Le cancer de l'intestin\n", + "* Le cancer de la peau\n", + "* Le cancer du rein\n", + "* Le cancer des os\n", + "* Le cancer de l'hypophyse\n", + "\n", + "Selon le Centre national de contrôle et de prévention des maladies (CDC), les causes principales du cancer incluent :\n", + "\n", + "* Les facteurs génétiques\n", + "* L'exposition à la radiation\n", + "* La pollution environnementale\n", + "* Le tabagisme\n", + "* La consommation excessive d'alcool\n", + "* Un poids corporel élevé\n", + "\n", + "Les traitements pour le cancer peuvent comprendre des opérations, de la chimiothérapie, de la radiothérapie et une greffe de cellules souches. (Source : American Cancer Society)\n", + "\n", + "Il est essentiel d'être conscient des risques de cancer et de prendre des mesures préventives pour réduire les chances de développer ce maladie.\n" + ] + } + ], + "source": [ + "chat_cli()\n", + "\n", + " \n", + " \n" + ] + }, + { + "cell_type": "code", + "execution_count": 263, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Assistant documentaire - Tapez 'exit' pour quitter\n" + ] + } + ], + "source": [ + "chat_cli()" + ] + }, + { + "cell_type": "code", + "execution_count": 253, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.runnables import RunnablePassthrough, RunnableLambda\n", + "from langchain_core.messages import SystemMessage, HumanMessage\n", + "from langchain_ollama import ChatOllama\n", + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "from base64 import b64decode\n", + "\n", + "\n", + "def parse_docs(docs):\n", + " \"\"\"Split base64-encoded images and texts\"\"\"\n", + " b64 = []\n", + " text = []\n", + " for doc in docs:\n", + " try:\n", + " b64decode(doc)\n", + " b64.append(doc)\n", + " except Exception as e:\n", + " text.append(doc)\n", + " return {\"images\": b64, \"texts\": text}\n", + "\n", + "\n", + "def build_prompt(kwargs):\n", + "\n", + " docs_by_type = kwargs[\"context\"]\n", + " user_question = kwargs[\"question\"]\n", + "\n", + " context_text = \"\"\n", + " if len(docs_by_type[\"texts\"]) > 0:\n", + " for text_element in docs_by_type[\"texts\"]:\n", + " context_text += text_element.text\n", + "\n", + " # construct prompt with context (including images)\n", + " prompt_template = f\"\"\"\n", + " Answer the question based only on the following context, which can include text, tables, and the below image.\n", + " Context: {context_text}\n", + " Question: {user_question}\n", + " \"\"\"\n", + "\n", + " prompt_content = [{\"type\": \"text\", \"text\": prompt_template}]\n", + "\n", + " if len(docs_by_type[\"images\"]) > 0:\n", + " for image in docs_by_type[\"images\"]:\n", + " prompt_content.append(\n", + " {\n", + " \"type\": \"image_url\",\n", + " \"image_url\": {\"url\": f\"data:image/jpeg;base64,{image}\"},\n", + " }\n", + " )\n", + "\n", + " return ChatPromptTemplate.from_messages(\n", + " [\n", + " HumanMessage(content=prompt_content),\n", + " ]\n", + " )\n", + "\n", + "\n", + "chain = (\n", + " {\n", + " \"context\": retriever | RunnableLambda(parse_docs),\n", + " \"question\": RunnablePassthrough(),\n", + " }\n", + " | RunnableLambda(build_prompt)\n", + " | ChatOllama(base_url=\"localhost:11434\", model=\"llama3.2\")\n", + " | StrOutputParser()\n", + ")\n", + "\n", + "chain_with_sources = {\n", + " \"context\": retriever | RunnableLambda(parse_docs),\n", + " \"question\": RunnablePassthrough(),\n", + "} | RunnablePassthrough().assign(\n", + " response=(\n", + " RunnableLambda(build_prompt)\n", + " | ChatOllama(base_url=\"localhost:11434\", model=\"llama3.2\")\n", + " | StrOutputParser()\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 255, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "I don't see any context provided. Please share the relevant information, such as text, tables, or an image, and I'll do my best to answer your question about what the \"ejector\" refers to.\n" + ] + } + ], + "source": [ + "response = chain.invoke(\n", + " \"What is the ejector?\"\n", + ")\n", + "\n", + "print(response)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[\"The 0D modeling approach simplifies global IC phenomena by considering only essential physics. It uses a global energy and mass balance to estimate injector characteristics. This model requires the consideration of an experimental closure law and has been previously implemented by various authors. The current approach starts from Deberne's 2000 model, which treats an injectant working with liquid central injection. Beithou also proposed a simplified OD model for an IC with vapor central injection, but it neglects the isobaric flow in the combustion chamber.\",\n", + " 'Steam is supposed to undergo isentropic expansion until the primary pipe throat, then undergo adiabatic expansion in the divergent section, considering irreversibilities such as high velocity and possible oblique shock waves.',\n", + " 'Summary of table: A table containing a single entry with the content \"condition critique de la vapeur\" and metadata including source, title, and page numbers.',\n", + " 'Summary of table/text: Critical relaxation threshold defined as yt + l, source is 11_chapitre3.pdf, page number 3.',\n", + " 'The table describes the parameters of a steam model, including the isentropic coefficient (y = 1.31 for saturated vapor), mass flow rate, and pressure. The system is solved to find the divergent length and continuity equation. A simplification is made by introducing new parameters, resulting in an implicit equation for the convergent length. The solution yields a value for p,, which is then used to solve for other parameters.',\n", + " \"The table doesn't exist. However the text is about a model for liquid fuel injection in an injector condenser. The model assumes equal inlet pressures but contradicts experimental data. It uses Bernoulli's equation to calculate pressure drop and characteristic properties of the fluid entering the mixing chamber.\",\n", + " \"The chamber of mixing is the most critical component of an injector, where most phase transfers between vapor and liquid occur: mass transfer, heat transfer, and momentum transfer. It's a complex section to model due to its creation of essential irreversibilities in the injector. The chamber of mixing modeling considers pressure longitudinal profile variations and separates phases using the vapor velocity rate, with hypotheses assuming steady and one-dimensional flow for equalized dimensions within a given section.\",\n", + " 'Summary of table/text: The page content mentions a coincidence between the bottom merge chamber and the shockwave head, related to section 11_chapitre3.pdf.',\n", + " 'Frottement aux parois negligible, adiabatic system, equilibrium in both kinetic and dynamic phases upon exiting the mixing chamber, and homogeneous mixture at exit.',\n", + " 'Summary of table: Summary statistics for Si Prt variable.',\n", + " 'Summary of table/page content:\\nSummary of fluid dynamics parameters in a mixing chamber, including pressure, velocity, radius, and angle for convergent sections.',\n", + " 'Summary of table or text: Key findings in chapter 3 of the \"Conservation de l\\'énergie\" document, with page numbers 1-12.',\n", + " 'The table provides a system of equations for modeling the LD (Liquid Distribution) of condenser injectors. It includes five inconnues (p27; uz; P2; hz ; Ip) and requires a closure law to calculate the integral pressure term Jp.',\n", + " 'Grolmes (1968) found that pressure profiles are primarily correlated with the calculated vapor condensation rate R, which depends on chamber mixing parameters. The correlation is expressed as L R = Caen (3-16), where Caen is a function of temperature and pressure, and Ly represents the latent heat of water at pressure P.',\n", + " 'Taux de condensation influences la pression dans la chambre de mélange, qui peut varier selon le taux de condensation. Pour R = 1.03, la pression est pratiquement constante dans la première partie de la chambre de mélange.',\n", + " 'Table/Text Summary:\\n\\nInfluence of condensation rate on pressure profiles in the combustion chamber. To determine Ip, seek a correlation for R > 0.69 or calculate it by integrating a linear pressure profile between entry and exit of the chamber for R < 0.69.',\n", + " 'Researchers seek a correlation dependent on the condensation rate R to determine the term Jp. An equivalent pressure is calculated using the formula P(z tan Bz) = Me P= eq 5 (3-17). The pressure is considered as the average pressure in the combustion chamber related to the dynamically active surface of the system. This pressure depends mainly on the condensation rate R.',\n", + " 'The table/text describes considering the pressure profile as constant for this scenario but acknowledges it is an approximation. Instead, a linear relationship between inlet and outlet pressures is used to represent the pressure profile.',\n", + " 'Table/Text Summary:\\n\\nSummary of page content: \\nA mathematical model for the LD (Laminar Discharge) of a condenser injector. The pressure P(z) is related to the discharge parameters by equations (3-21), (3-22). The term Jp depends linearly on the pressure Pz, making the resolution of the system straightforward.',\n", + " 'The injector-condenser pressurizes the water-vapor mixture to a pressure higher than that of the motive steam. The maximum counter-pressure is achieved when the thickness of the condensation wave is minimal and its location is at the throat of the mixing chamber.',\n", + " 'Summary of table: P31U31 refers to a specific location in a document, specifically page 31, unit 31, marked as \"Por-vYrt-v\" with reference number 3-23. \\n\\nDocument metadata: Document source is an 11_chapitre3.pdf file, titled \\'Continuité\\', with page numbers on page 11.',\n", + " 'Summary of table: A mathematical equation relating Pritts and Pavtory with Pav, with a range of 3 to 24. \\n\\nMetadata: Document metadata from a PDF file titled \"Quantité de mouvement\" on page 11.',\n", + " 'Summary of table or text:\\n\\nText: \"hy, eo = hy y + sth (3-25)\"\\nMetadata: Source is a PDF file named \\'11_chapitre3.pdf\\', title is \\'Conservation de l’énergie\\' and it covers page number 11.',\n", + " 'Simplification of system parameters for linearization: \\nKy = Poy-yYor-v, \\nKy = Pry-yYarv + Py = Kory + Pav, \\nKy = hyy + Ber. \\nEquations simplify to:\\nPails = K, Prt + P = K,\\nhy, + aie =K, hy, = AC py, iP',\n", + " \"The table discusses the principles of a diffuser in a liquid dynamics system. It explains how the diffuser slows down the fluid due to its divergent shape and converts its kinetic energy into pressure energy. The flow rate is described by Bernoulli's equation and continuity equation. The coefficients of loss (e, a) are calculated based on the relation provided. The table relates these coefficients to the angle of divergence (B), diameter (D), mean velocity (uo), and surface roughness.\",\n", + " \"The model was programmed on a PC using Borland Pascal 7.0, taking dimensions of an IC and physical/dynamical parameters of liquid water and steam as input to determine optimal performance in an open circuit, with the shockwave located at the neck of the mixing chamber. The code structure is represented in figure 3-4, with PROPEAU module used to calculate water properties within the IC's operation range.\",\n", + " 'Experimental results from INSA/LC injector sets A1, B1, and C1 were evaluated in Chapter 2. The combined test values (Section 2-2) allowed for estimating optimal coefficients for the model (Table 3-1). Figures 3-5 and 3-6 show that modeling provides correct values compared to experimentation. However, the model overestimates the training rate U,,q, and maximum vapor pressure Poymax in general.',\n", + " \"Pressions maximales à la sortie de l'injecteur diminuent avec la pression d'alimentation de la vapeur pour des pressions supérieures à 9 bar. Le modèle sous-estime les irréversibilités et présente limites en termes de corrélation et paramètres empiriques, nécessitant un point d'essai pour calibration.\",\n", + " 'Deberne conducted experiments to visualize the geometric structure of flow in a mixing chamber, using qualitative approaches that helped understand phenomena such as atomization and liquid jet length. He used an experimental setup with a light source, camera, and visualization tube, employing two lighting modes (rear and front) during the experiment. The visualization tube had a central liquid column with a rectangular cross-section and a thickness of 8mm, allowing for clear observation of flow characteristics.',\n", + " 'The study visualizes fluid flow in a chamber of mixture and identifies stratified flow with a central liquid jet and surrounding vapor, as well as dispersed flow of droplets and vapor. The density of droplets is highest at the center of the vein, while the flow seems less dense in the diffuseur and after the col. Condensation waves are observed in the diffuseur and just after the col, and monophasic liquid flow is seen downstream from the diffuser.',\n", + " \"Je ne peux pas trouver l'information que vous recherchez. Puis-je vous aider avec autre chose?\",\n", + " 'Summary of the text:\\n\\nThe article discusses the coalescence of liquid droplets in collisions and confinement geometry. The transition between two fluid flow modes is determined by the rupture point of a liquid jet, which is calculated using the correlation of Monote (1-41). The heat exchange terms are described by convective or thermodynamic laws and drag forces (3-37). A numerical model is developed to simulate this process, which was solved using the CEDRE code.',\n", + " 'Models developed accurately reproduce the flow at the chamber entrance (heterogeneous zone). However, transition between heterogeneous and homogeneous regimes and condensation wave resolution are not accurately modeled. Current goal is to model the entire chamber of mixture: heterogeneous zone, dispersed homogeneous zone, and condensation wave using a simple physically sound model that can be numerically solved.',\n", + " 'The chamber of mixture has two distinct sections with different flow patterns. The first section has a heterogeneous flow (jet + droplets + vapor) and the second section has a homogeneous dispersion flow (vapor + droplets). The length of rupture is characteristic of the primary jet in the first section, as described in paragraph 1-4-2.',\n", + " 'The mixing chamber in a IC engine is characterized by a strong imbalance of thermodynamic and kinetic properties between liquid and vapor phases. This requires calculating separate velocity and temperature fields, as well as considering mass transfer, unequal pressure fields, and intense atomization of the liquid jet. The flow can be considered monodimensional with uniform properties in a cross-sectional area.',\n", + " \"Two coupled eularian systems describe the combustion chamber mixture: one for vapor phase and another for liquid phase, based on Rascle's diphasic equations [Rascle1997].\",\n", + " 'Summary of table: \\nAlapyuyS) = ST, oz aa i” a)p,u,S) = ST, Oz (3-38)\\n\\nSummary of text:\\nDescribes the section on flow rate and mass exchange per unit volume in continuity equations.',\n", + " 'Mapu table: variables for quantity of movement include MM (quantity of movement), P (pressure at the interface) and other parameters.',\n", + " 'Alap equation: Alap = SQ*(1 - at)^p + hu^2, where h is a constant.',\n", + " 'The table does not exist in the provided text. The text only contains a passage about equations of state for real fluids and mentions a table called PROPEAU for water, but no table is actually provided.',\n", + " \"The text describes laws of closure and correlations from literature, used to calculate model terms (vector H(V)), which are compared with experimental values to select the most suitable laws for the injector. The source is a PDF document named '11_chapitre3.pdf'.\",\n", + " 'Summary of table and text: Human task to summarize a page from the PDF \"11_chapitre3.pdf\" titled \"the transfer of mass movement\", discussing wall friction (M) and interface velocity (Uj).',\n", + " 'Table/Text: The table describes thermal transfer concepts with terms such as \"flux de chaleur\" (heat flux), \"enthalpie d\\'interface\" (interfacial enthalpy), and types of heat transfer including \"pariétal\" (boundary) and \"interfacial\" (between surfaces).',\n", + " 'The system of equations is not closed due to seven main unknowns (a, u, U, h, h, P, P) and two secondary unknowns (p, ; 1) derived from the state equations. The system is defined by six balance equations, which assume constant pressure (P = B) and density (ρ = C). An additional relationship links the vapor mass flow rate, temperature, and masses volumiques: g = -Pu(3-45), where py is the gliding between phases, u is the mass flow rate of liquid, x is the molar mass of water.',\n", + " 'The article discusses the modeling of two-phase flow in condenser injectors, focusing on the interface between the liquid and vapor phases. It proposes two modes of interface: stratified and dispersed, with equal velocities at the interface. The pressure at the interface is not physically meaningful but plays a crucial role in hyperbolicity conservation. An expression for pressure is given as BP = Epy - u(T), where T is the saturation temperature. The article also discusses the thermodynamic properties of the interface, including enthalpies, and proposes an expression for them based on the law of saturation.',\n", + " 'The table lists the conservation laws at interfaces: Liouville theorem (LT), X-axis invariant (XL), U-index invariance (Ui), and Mass-time invariance (Mat).',\n", + " 'System description: U = -L, My = M; where T is the total pressure difference, Ov is the outlet pressure, Girv is the valve opening velocity, and h is the distance of the condenser. Page numbers: 30-31.',\n", + " 'The exchange of heat at the interface is mainly caused by the initial thermal imbalance between two phases, leading to condensation. A proposed law for heat exchange is: H = (4sHys + ApH y p \\\\(z, ~ T) or H = (4sH,.5 + ApH» \\\\(Z, ~ qT), where coefficients and densities of surface exchange are defined.',\n", + " \"Table summary: \\nSummary of cte surface d'échange du jet de vapeur. The table describes the surface for the exchange of steam jet, considered as a cylindrical shape with constant diameter D.\\n\\nText summary:\\nCalculs d'un coefficient d'échange selon la corrélation St = 6,5 Re* (3-59)\",\n", + " \"Table des constantes utilisées dans le modélisation LD des injecteurs condenseurs :\\n\\n- u; = vitesse d'interface en m/s\\n- TD = taux de détection de vitesse en m^3/m^2s\\n- A IAL = surface de l'interface liquide/vapeur en m^2\\n- Evy, py = vitesse de la vapeur et du liquide dans l'interface\\n- Eo = énergie spécifique de la vapeur\\n- PL = pression de la vapeur\\n- Re : nombre de Reynolds pour les flux de masse échangées à l'interface\\n- fi, fv = coefficients de frottement à l'interface\\n- m = flux de masse lié à la condensation\\n- Ty, Eq, ui, u' = variables dans la loi de Darcy pour déterminer les quantités de mouvement échangées à l'interface\",\n", + " 'Summary of the text: The article discusses the calculation of heat transfer coefficients in liquid-vapor condensation. Various authors have proposed different formulas based on molecular theory and experimental data. Iwaki et al. suggest a formula using temperature profiles measured in an injector, resulting in an average coefficient of 6.10* Win?.K with pressure below 1.5 bar. The choice of correlation depends on the relation by Miyazaki.',\n", + " 'Table: \\n| Longueur de rupture du jet liquide | Prolongement temporelle de la condensation |\\n| --- | --- |\\n| 104 < Rey < 1.2.10° | 0.7 < Pry < 100 |\\n\\nText:\\nResearchers Nariai and Aya studied the direct condensation of vapor on liquid water, for stratified flow. They estimated a coefficient of heat transfer between vapor and liquid in the range (3-70) W/mK. In the case of coexistence of liquid water and vapor, the heat transfer is primarily controlled by the liquid phase. The calculation of heat exchange coefficients in the dispersed Hiy,p and Hit,p phases involves the exchange between sub-cooled droplets and the vapor phase, a less studied mode of condensation.',\n", + " 'Moresco (1980) studied heat transfer in a two-phase spray consisting of a continuous phase and a dispersed phase. The study covered a range of flow rates (0.17-0.31 kg/s), temperatures (300-370 K), and droplet sizes (0.007-0.01 m). Moresco proposed the correlation Nu = 0.0178Re^0.4Pr^0.33 for the dispersed phase, while Srinivas (1996) studied a spray with vapor-saturated water droplets in air and used a 2D model to calculate the Nusselt number.',\n", + " 'The outside medium of the fuel injector is generally colder than the internal flow, causing external heat losses. The only contact with the wall in this heterogeneous part of the flow is with the vapor, leading to consideration of convective transfer on the vapor side.',\n", + " 'The forces of dragging and friction are related to the difference in velocity between phases. The coefficient of drag (Cd) is proportional to the square of the relative velocity: Cd = f(u) with f being a function of velocity u, where Cp is the coefficient of drag for the dispersed phase and Cs is the coefficient of friction for the stratified phase.',\n", + " 'The table provides equations related to the heat transfer and friction coefficients in a two-phase flow system. The Darcy-Weisbach equation is used for the heat exchange between phases, while the Blasius equation is applied for the coefficient of friction on the wall in the vapor phase, assuming turbulent flow.',\n", + " 'Transfer of mass under adiabatic conditions only follows the laws of interface, expressed as l = -I = Ov + Qu.',\n", + " 'The chamber of the IC has a conical shape with a heterogeneous section that is also conical. The cross-sectional area of the flow varies linearly with depth (z), resulting in a surface area S = ar(z) where r(z) and r(inlet) and r(outlet) are related by H(z).',\n", + " 'The table describes the surface interfacial representation between vapor and liquid jet for stratified flow mode. The volume of the cylinder and cone are related to Az (3-93) and (3-94), where r = 4AztanB and tan B = ae, with N being the number of mesh. The volume removed from the cylinder by the liquid is calculated as V(cylindre) - V(cone) according to equation (3-96).',\n", + " 'Table content: Describes the calculation of surface-to-volume ratio in each pore space and its relation to particle density.\\n\\nText content: Explains the concept of surface-to-volume ratio and its application to liquid particle counting in a stratified flow.',\n", + " 'The study presented here allowed us to choose the correlations that provide the best estimation of friction transfer coefficients for our case. The necessary values are compiled in Table 3-1, derived from measurements taken at the entrance of the mixing chamber (rectangular section). Values of different coefficients are illustrated on Table 3-2.',\n", + " 'There is a significant disparity among different authors in terms of heat exchange and friction coefficients. Results are compared to experimental and numerical data, with numerical results based on a reference experiment shown in Table 3-1. Equations for interface sizes and terms are listed in Tables 3-3 and 3-4.',\n", + " \"The system of 7 equations is transformed into a non-conservative form to facilitate a matrix-based solution. The resulting system is an ordinary differential equation with 7 first-order equations, which can be integrated explicitly and numerically using the Runge-Kutta method of order 4 (RK 4), supplemented by the Newton-Raphson method for calculating the inverse H''(V).\",\n", + " \"Conception de la veine axysimétrique n'a pas permis des mesures locales dans la chambre de mélange; modèle sera validé sur une section rectangulaire. Calcul validé aux conditions expérimentales avec une géométrie de 2D plane. Mesures locales réalisées sur une veine en Plexiglas de section rectangulaire, respectant les lois de similitude géométrique d'un IC.\",\n", + " \"Chapitre 3 : Modélisation LD des injecteurs condenseurs. Le taux de vide augmente à l'entrée de la chambre de mélange, mais la pression vapeur calculée ne correspond pas aux mesures locales de pression. La hypothèse de pression liquide constante et égale à la pression vapeur est plus adéquate pour rendre compte de la pression dans le liquide à l'entrée, mais elle ne prend pas en compte l'effet piston de la phase vapeur sur la phase liquide. La température de la vapeur calculée décroit à l'entrée, tandis que la température calculée de la phase liquide augmente plus fortement que la température mesurée.\",\n", + " 'The chapter discusses the modeling of liquid droplet (LD) injectors in condensers. The temperature measurement of the heart liquid is equal to that of the vapor and liquid phases, but the calculated temperature differs due to non-separation of the two structures. An analysis of experimental results revealed variables such as vapor velocity and liquid velocity. A model was developed using the experiment and based on heat transfer between liquids and vapors. The system of equations describes the conservation of mass in a stationary regime, including thermodynamic properties of water and steam.',\n", + " 'The table shows a comparison of calculated and measured velocity fields, with slight differences between model-calculated and experimental values due to measurement uncertainties and modeling assumptions.',\n", + " 'The table discusses the relationship between entropy and exergy in a combustion chamber. It highlights the importance of accounting for thermohydraulic phenomena during mixing in the chamber. The study aims to compare experimental and modeled entropies to determine global entropy created by internal irreversibilities. An equation is given for calculating the overall entropy, and its values are compared using data from experiments and models.',\n", + " \"The table presents a concordance between model and experimental results for entropy increase in the mixing chamber, with maximum energy losses occurring at the entrance of the chamber. The exergies corresponding to the system's energy are calculated and plotted against the liquid temperature, showing an increase in energy losses as the flow rate increases.\",\n", + " 'Summary of the table:\\n\\nPage content: Chapter 3 discussion on Lumped Discretization (LD) modeling of condenser injectors. \\n\\nMetadata: Source document is \"11_chapitre3.pdf\", title contains units \"mm\", and page numbers are 52-53.',\n", + " 'This 1D modelling of the heterogeneous part shows globally coherent results, correctly reproducing physical phenomena and variable flow evolution. The model accurately captures kinetic and thermal imbalance, leading to direct condensation between phases and separation of liquid and vapor pressure fields.',\n", + " 'This text discusses the modeling of a two-phase flow in a mixing chamber, specifically focusing on the behavior of droplets and vapor. The author reviews existing models, such as that by Deberne, which treats the flow as a diphasic dispersed system. However, due to large droplet sizes, the model is adapted for better accuracy. The text also explores the phenomenon of phase separation, including thermodynamic and mechanical instabilities, and presents an analysis of the factors influencing these instabilities, such as germ presence in the vapor and velocity of flow.',\n", + " 'The equation to calculate the imbalance is given by: y, ate = Au (3-112) dz Ty 146. The time of mechanical relaxation is compared with the local velocity gradient.',\n", + " 'The table provides information on the sensitivity of mechanical instability in a system, with studies by Young (1982) indicating that for droplet diameters below 0.5 μm, mechanical instability is negligible and relaxation times differ significantly between thermal and mechanical processes. In most cases, mechanical instability is not considered.',\n", + " 'The simplest model is the homogeneous equilibrium model (MHE), assuming negligible discrepancies. This model considers the average properties of a mixture, with 3 equations describing fluid flow and 5 assumptions: thermodynamic equilibrium, unit phase transition, and adiabatic conditions. The model approximates a monophasic fluid with given properties, neglecting gradients and non-stationary flow.',\n", + " 'System of equations describing fluid flow: dL/dt = (P - P_m) * L + F / a * v, where L is volumetric flow rate, P and Pm are pressures, F is fuel, a is cross-sectional area, v is velocity. After rewriting the system as a homogeneous one, it becomes: d(aL)/dt = R * V, with R being the Riemann matrix and V being the vector of principal unknowns.',\n", + " 'Table/PDF content: Speed of sound in a homogeneous equilibrium medium, equation: ω_cy = ω_p (3-117), where ω is the angular frequency.',\n", + " 'Summary: The chapter discusses the LD modeling of condenser injectors, assuming a balanced medium and applying Clausius-Clapeyron equation for pressure dependence on temperature. It also uses Maxwell equations to calculate sound velocity and introduces a friction closure law for wall friction, represented by the Chézy formula with a coefficient dependent on Reynolds number and wall roughness, related to Nikuradse coefficients.',\n", + " 'A system has a solution if its Riemann matrix is invertible, with determinant Det(R) = u² + C (u² Cy lly + C). The case where u² = cy represents a singular point that annihilates the determinant, characteristic of a transonic passage between two solutions.',\n", + " 'This table discusses the modeling of condenser injectors in a system, specifically focusing on the 1D model and its solutions. It describes two cases: supersonic flow and transsonic flow, where the latter leads to a critical point (section critique) that determines the uniqueness of the solution. The section critique is related to the col or chamber de mélange.',\n", + " \"Deberne [Deberne2000] developed a 2D (rectangular) visualization vein concept to measure local parameters in the entire chamber of mixing. This approach will be validated using experimental results on axisymmetric geometry by comparing with rectangular geometry. The input conditions for the model match the numerical output of the heterogeneous part's exit (Table 3-6).\",\n", + " 'The tables (3-17, 3-18, and 3-19) show the evolution of parameters in the heterogeneous mixing chamber section along the axial position. The figure 3-17 shows the reduction of void fraction after the heterogeneous section, due to condensation affecting the surface area of exchange. The pressure calculated matches the experimental data with a delay at the end of the heterogeneous section. Temperature variation is minimal, with good agreement between measured and calculated values, mainly due to temperature being an unknown auxiliary variable in the system.',\n", + " 'The table/chunk discusses a model for liquid droplet (LD) injection in condenser injectors. The temperature of the mixture is considered a weighted average with a calculated void fraction, resulting in less precise predictions for the dispersed phase (z > 150 mm). Error sensitivity analysis shows significant variations in results due to measurement errors, especially beyond z = 150 mm, affecting credibility and numerical model accuracy.',\n", + " 'We use a second model that considers the existing thermodynamic imbalance and highlighted in the tests (HRM: homogeneous relaxation model). The thermodynamic imbalance is interpreted as a delay in condensation, with a vapor title that does not follow pressure evolution (constant entropy) if the system were in an equilibrium state. A law of type (rappel to equilibrium) governs this delay: Dx, Ox, Ox, x, —X.',\n", + " 'A system of equations describing fluid flow in the model is given as uy Lm gy Hm iB = ae Pm a Prt Sa Uy, with similar terms and an equality operator linking them.',\n", + " 'The system admits a solution if the Riemann matrix is invertible. The solution is determined by analyzing the figure 3-14 and checking the equation derived from the resolution of the subsytem (3-129). This equation defines the x-coordinate of the critical section Ze. \\n\\nIn the homogenous model with relaxation, the second term in the equation (3-130) moves the critical section towards the nozzle exit as thermal imbalance increases. In supersonic flow, a point of bifurcation occurs at the critical section, and a new condition must be defined to determine the branch taken by the solution.\\n\\nThe system is solved numerically using Runge-Kutta method with an adaptive step size, replacing real values with their duals. The results have been improved slightly but still do not capture the effects of condensation in this homogenous part of the combustion chamber.',\n", + " \"The mixing chamber structure varies with a cut-off at the liquid jet's complete disintegration length. The homogeneous section consists of dispersed droplets in the vapor, characterized by weighted flow values and high surface exchange area. Two models (HEM and HRM) show similar numerical results to experimental data up to the condensation wave front.\",\n", + " 'Summary of Chapitre 3 : Modélisation LD des injecteurs condenseurs: Model for Liquid Distribution (LD) in Condenser Injectors.',\n", + " \"Il semble que le texte fourni est un extrait de travail académique qui présente divers travaux antérieurs sur le sujet du choc thermique dans les écoulements diphasiques (écoulements comportant à la fois une phase liquide et une phase gazeuse). Voici quelques-uns des principaux résultats présentés :\\n\\n1. **Travaux de Guha** : L'auteur Guha a étudié le choc thermique dans les flux diphasiques en présence ou non d'un gaz porteur. Il constate que ces écoulements sont caractérisés par deux genres de flux : \\n - Flux bloqué (ou flux figé), qui est caractérisé par des gouttelettes liquides non participantes au processus mécanique du fluide.\\n - Flux équilibré, qui est caractérisé par des gouttelettes liquides qui sont toujours dans un équilibre complet avec leur propre vapeur.\\n\\n2. **Expression de flux critique** : L'auteur Guha a présenté une formule pour calculer le flux critique en tenant compte de la variation de la surface d'échange et de la variation du flux massique de la vapeur, qui est donnée par l'équation :\\n - Gs) 1) (3-141)\\n - P*o 5) Ma? 142= D ta? r+ $ | 7 2\\n\\n3. **Travaux de Chen** : L'auteur Chen propose une formule pour calculer la vitesse du son dans les écoulements diphasiques, qui est donnée par l'équation :\\n - c= (3-140)\\n - 0,5 5 2 I (1 of) e.| I+ d C p Be PL aT Pi) Siv\\n\\n4. **Travaux de Young** : L'auteur Young a étudié le choc thermique dans les écoulements diphasiques en présence ou non d'un gaz porteur. Il constate que la vitesse du son dépend de la dispersion de la phase liquide et aussi de la fréquence de l'onde. Il propose des valeurs pour les coefficients ky et ke en fonction de la pression.\\n\\nIl est important de noter que ces résultats sont basés sur des équations et des formules qui peuvent nécessiter des conditions spécifiques d'équilibre thermodynamique et mécanique pour être applicables à différents écoulements.\",\n", + " 'The model HEM and HRM were unable to capture the condensation wave. A new method is proposed to calculate the conditions of jump using an equation with four unknowns (py, Uy, P2, T). The equation includes parameters such as specific heat capacity, latent heat, and viscosity. The pressure at point 2 (P2) is calculated by solving a non-linear, implicit equation in the range [Pamin, P2max].',\n", + " \"The text describes the fluid flow in a diffuser, using equations such as Bernoulli's equation, continuity equation, and state equation to calculate enthalpy at the outlet of an IC (Intermediate Cooling Channel). The calculation also involves pressure terms and a singular loss coefficient for conical diffusers.\",\n", + " \"Simulations confirm that the shock wave is defined by the conditions of impact adopted. Profiles of pressure obtained are compared to experimental results. Local measurements ([Deberne2000]) were taken on an IC with a rectangular section, which only represents the qualitative functioning of the IC. The IC's ability to function with a compression ratio above 1 unit is limited. Experimental results show that the 2D effect is present but less influential in axisymmetric configuration. Results will be compared to performance tests on IC INSA/LC, which better represent the actual IC functioning (figures 3-22 and 3-23). The influence of the training rate on the condensation pressure profile and the effect of the vapor inlet pressure on the outlet pressure are also studied.\",\n", + " 'The model with relaxation in HRM did not produce the condensation wave (real thermal shock in IC function), but a simple physically model can be adopted by changing boundary conditions to reflect real IC functioning. New boundary conditions are applied to impose a totally liquid flow at the outlet of the diffuser and calculate numerically within the diffuser by going back to the flow.',\n", + " 'Validation of results was based solely on pressure profiles, P(bar).',\n", + " \"Summary of Table: \\nTable contains data related to modelling LD of injectors, including pressure (Pbar), with page numbers 77 and 78.\\n\\nMetadata:\\nPage content from chapter 3 of a PDF document titled 'z(mm)'.\",\n", + " \"The main disadvantage is that numerical values of velocities are far off from the IC's real functioning, with excessive increases in speed to compensate for pressure drops. Resolving this problem and joining heterogeneous parameters can close the condensation wave issue, allowing for numerical simulation of the entire IC without relying on jump conditions across the condensation wave.\"]" + ] + }, + "execution_count": 122, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "import uuid\n", + "from qdrant_client import QdrantClient\n", + "from langchain_qdrant import QdrantVectorStore\n", + "from langchain.storage import InMemoryStore\n", + "from langchain.schema.document import Document\n", + "from langchain_ollama import OllamaEmbeddings # Vous pouvez remplacer par OpenAIEmbeddings si besoin\n", + "from langchain.retrievers.multi_vector import MultiVectorRetriever\n", + "from langchain.embeddings import OpenAIEmbeddings\n", + "\n", + "# Initialiser le client Qdrant (ici, on suppose un serveur local sur le port 6333)\n", + "qdrant_client = QdrantClient(host=\"localhost\", port=6333)\n", + "\n", + "# Définir le nom de la collection\n", + "collection_name = \"multi_modal_rag_07032025\"\n", + "vector_size =1536\n", + "# Créer (ou recréer) la collection dans Qdrant\n", + "\n", + "qdrant_client.create_collection(\n", + " collection_name=collection_name,\n", + " vectors_config={\"size\": vector_size, \"distance\": \"Cosine\"},\n", + ")\n", + "\n", + "# Choix de la fonction d'embedding :\n", + "# Pour utiliser OllamaEmbeddings :\n", + "embedding_function = OpenAIEmbeddings()\n", + "# Pour utiliser OpenAIEmbeddings, décommentez la ligne suivante et commentez la précédente :\n", + "# embedding_function = OpenAIEmbeddings()\n", + "\n", + "# Créer la vectorstore avec QdrantVectorStore\n", + "vectorstore = QdrantVectorStore(\n", + " client=qdrant_client,\n", + " collection_name=collection_name,\n", + " embedding=embedding_function\n", + ")\n", + "\n", + "# Couche de stockage en mémoire pour les documents parents\n", + "store = InMemoryStore()\n", + "id_key = \"doc_id\"\n", + "\n", + "# Créer le retriever multi-vecteur\n", + "retriever = MultiVectorRetriever(\n", + " vectorstore=vectorstore,\n", + " docstore=store,\n", + " id_key=id_key,\n", + ")\n", + "\n", + "# --- Ajout des textes ---\n", + "# (les variables texts et text_summaries doivent être définies au préalable)\n", + "doc_ids = [str(uuid.uuid4()) for _ in title_chunks]\n", + "summary_texts = [\n", + " Document(page_content=summary, metadata={id_key: doc_ids[i]})\n", + " for i, summary in enumerate(text_summaries)\n", + "]\n", + "retriever.vectorstore.add_documents(summary_texts)\n", + "retriever.docstore.mset(list(zip(doc_ids, title_chunks)))\n", + "+ images_with_caption\n", + "# --- Ajout des tableaux ---\n", + "# (les variables tables et table_summaries doivent être définies au préalable)\n", + "table_ids = [str(uuid.uuid4()) for _ in tables]\n", + "summary_tables = [\n", + " Document(page_content=summary, metadata={id_key: table_ids[i]})\n", + " for i, summary in enumerate(table_summaries)\n", + "]\n", + "retriever.vectorstore.add_documents(summary_tables)\n", + "retriever.docstore.mset(list(zip(table_ids, tables)))\n", + "\n", + "# --- Ajout des résumés d'images ---\n", + "# (les variables images et image_summaries doivent être définies au préalable)\n", + "img_ids = [str(uuid.uuid4()) for _ in images]\n", + "summary_img = [\n", + " Document(page_content=summary, metadata={id_key: img_ids[i]})\n", + " for i, summary in enumerate(image_summaries)\n", + "]\n", + "retriever.vectorstore.add_documents(summary_img)\n", + "retriever.docstore.mset(list(zip(img_ids, images)))" + ] + }, + { + "cell_type": "code", + "execution_count": 114, + "metadata": {}, + "outputs": [ + { + "ename": "AttributeError", + "evalue": "'dict' object has no attribute 'page_content'", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mAttributeError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[114], line 9\u001b[0m\n\u001b[0;32m 2\u001b[0m embedding \u001b[38;5;241m=\u001b[39m OllamaEmbeddings(\n\u001b[0;32m 3\u001b[0m base_url\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mhttp://localhost:11434\u001b[39m\u001b[38;5;124m\"\u001b[39m,\n\u001b[0;32m 4\u001b[0m model\u001b[38;5;241m=\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmxbai-embed-large\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[0;32m 5\u001b[0m )\n\u001b[0;32m 7\u001b[0m \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21;01mlangchain_qdrant\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mimport\u001b[39;00m QdrantVectorStore\n\u001b[1;32m----> 9\u001b[0m qdrant \u001b[38;5;241m=\u001b[39m \u001b[43mQdrantVectorStore\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfrom_documents\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 10\u001b[0m \u001b[43m \u001b[49m\u001b[43mfinal_chunks\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 11\u001b[0m \u001b[43m \u001b[49m\u001b[43membedding\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 12\u001b[0m \u001b[43m \u001b[49m\u001b[43murl\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mhttp://localhost:6333\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 13\u001b[0m \u001b[43m \u001b[49m\u001b[43mcollection_name\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mmy_documents\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 14\u001b[0m \u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\ramez\\miniconda3\\envs\\rag\\lib\\site-packages\\langchain_core\\vectorstores\\base.py:832\u001b[0m, in \u001b[0;36mVectorStore.from_documents\u001b[1;34m(cls, documents, embedding, **kwargs)\u001b[0m\n\u001b[0;32m 815\u001b[0m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[0;32m 816\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mfrom_documents\u001b[39m(\n\u001b[0;32m 817\u001b[0m \u001b[38;5;28mcls\u001b[39m: \u001b[38;5;28mtype\u001b[39m[VST],\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 820\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m 821\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m VST:\n\u001b[0;32m 822\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return VectorStore initialized from documents and embeddings.\u001b[39;00m\n\u001b[0;32m 823\u001b[0m \n\u001b[0;32m 824\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 830\u001b[0m \u001b[38;5;124;03m VectorStore: VectorStore initialized from documents and embeddings.\u001b[39;00m\n\u001b[0;32m 831\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 832\u001b[0m texts \u001b[38;5;241m=\u001b[39m [d\u001b[38;5;241m.\u001b[39mpage_content \u001b[38;5;28;01mfor\u001b[39;00m d \u001b[38;5;129;01min\u001b[39;00m documents]\n\u001b[0;32m 833\u001b[0m metadatas \u001b[38;5;241m=\u001b[39m [d\u001b[38;5;241m.\u001b[39mmetadata \u001b[38;5;28;01mfor\u001b[39;00m d \u001b[38;5;129;01min\u001b[39;00m documents]\n\u001b[0;32m 835\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mids\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n", + "File \u001b[1;32mc:\\Users\\ramez\\miniconda3\\envs\\rag\\lib\\site-packages\\langchain_core\\vectorstores\\base.py:832\u001b[0m, in \u001b[0;36m\u001b[1;34m(.0)\u001b[0m\n\u001b[0;32m 815\u001b[0m \u001b[38;5;129m@classmethod\u001b[39m\n\u001b[0;32m 816\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mfrom_documents\u001b[39m(\n\u001b[0;32m 817\u001b[0m \u001b[38;5;28mcls\u001b[39m: \u001b[38;5;28mtype\u001b[39m[VST],\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 820\u001b[0m \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs: Any,\n\u001b[0;32m 821\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m VST:\n\u001b[0;32m 822\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"Return VectorStore initialized from documents and embeddings.\u001b[39;00m\n\u001b[0;32m 823\u001b[0m \n\u001b[0;32m 824\u001b[0m \u001b[38;5;124;03m Args:\u001b[39;00m\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 830\u001b[0m \u001b[38;5;124;03m VectorStore: VectorStore initialized from documents and embeddings.\u001b[39;00m\n\u001b[0;32m 831\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 832\u001b[0m texts \u001b[38;5;241m=\u001b[39m [\u001b[43md\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mpage_content\u001b[49m \u001b[38;5;28;01mfor\u001b[39;00m d \u001b[38;5;129;01min\u001b[39;00m documents]\n\u001b[0;32m 833\u001b[0m metadatas \u001b[38;5;241m=\u001b[39m [d\u001b[38;5;241m.\u001b[39mmetadata \u001b[38;5;28;01mfor\u001b[39;00m d \u001b[38;5;129;01min\u001b[39;00m documents]\n\u001b[0;32m 835\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mids\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n", + "\u001b[1;31mAttributeError\u001b[0m: 'dict' object has no attribute 'page_content'" + ] + } + ], + "source": [ + "from langchain_ollama import OllamaEmbeddings\n", + "embedding = OllamaEmbeddings(\n", + " base_url=\"http://localhost:11434\",\n", + " model=\"mxbai-embed-large\"\n", + " )\n", + "\n", + "from langchain_qdrant import QdrantVectorStore\n", + "\n", + "qdrant = QdrantVectorStore.from_documents(\n", + " final_chunks,\n", + " embedding,\n", + " url='http://localhost:6333',\n", + " collection_name=\"my_documents\",\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "11\n" + ] + } + ], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ + "# def get_tables_with_caption(documents):\n", + "# tables_info = []\n", + "# for idx, chunk in enumerate(documents):\n", + "\n", + "# if chunk.metadata.get(\"category\") == \"Table\" or \"table\" in chunk.metadata.get(\"category\", \"\").lower():\n", + "\n", + "# # Extraction du contenu textuel du tableau et de sa légende\n", + "# payload = chunk.metadata.get(\"payload\", {})\n", + "# caption = payload.get(\"caption\", \"\").strip()\n", + "# print(chunk.metadata)\n", + "# # Si aucune légende n'est trouvée, vérifier le bloc suivant\n", + "# if not caption and idx + 1 < len(documents):\n", + "# next_chunk = documents[idx + 1]\n", + "# lower_text = next_chunk.page_content.lower()\n", + "# if any(keyword in lower_text for keyword in [\"table\", \"tab.\", \"légende\",\"tableau\"]):\n", + "# caption = next_chunk.page_content.strip()\n", + "\n", + "\n", + " \n", + "# tables_info.append({\n", + "# \"type\": \"table_with_caption\",\n", + "# \"table_data\": chunk.page_content, # Le contenu textuel du tableau\n", + "# \"caption\": caption\n", + "# })\n", + "# return tables_info\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "metadata": {}, + "outputs": [], + "source": [ + "# get_tables_with_caption(documents)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "ename": "ConnectionError", + "evalue": "Failed to connect to Ollama. Please check that Ollama is downloaded, running and accessible. https://ollama.com/download", + "output_type": "error", + "traceback": [ + "\u001b[1;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[1;31mConnectionError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[1;32mIn[10], line 2\u001b[0m\n\u001b[0;32m 1\u001b[0m idx\u001b[38;5;241m=\u001b[39m \u001b[38;5;241m7\u001b[39m \n\u001b[1;32m----> 2\u001b[0m \u001b[43manalyze_image\u001b[49m\u001b[43m(\u001b[49m\u001b[43mimages_with_caption\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mimage_base64\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\u001b[43mimages_with_caption\u001b[49m\u001b[43m[\u001b[49m\u001b[43midx\u001b[49m\u001b[43m]\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcaption\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m)\u001b[49m \n", + "Cell \u001b[1;32mIn[9], line 17\u001b[0m, in \u001b[0;36manalyze_image\u001b[1;34m(image_data, caption, context, prompt_base)\u001b[0m\n\u001b[0;32m 14\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[0;32m 15\u001b[0m prompt \u001b[38;5;241m+\u001b[39m\u001b[38;5;241m=\u001b[39m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mDécris cette image en détail.\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m---> 17\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mclient\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mchat\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 18\u001b[0m \u001b[43m \u001b[49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mllama3.2-vision\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 19\u001b[0m \u001b[43m \u001b[49m\u001b[43mmessages\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\n\u001b[0;32m 20\u001b[0m \u001b[43m \u001b[49m\u001b[43m{\u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mrole\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43muser\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mcontent\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[38;5;124;43mimages\u001b[39;49m\u001b[38;5;124;43m\"\u001b[39;49m\u001b[43m:\u001b[49m\u001b[43m \u001b[49m\u001b[43m[\u001b[49m\u001b[43mimage_data\u001b[49m\u001b[43m]\u001b[49m\u001b[43m}\u001b[49m\n\u001b[0;32m 21\u001b[0m \u001b[43m \u001b[49m\u001b[43m]\u001b[49m\n\u001b[0;32m 22\u001b[0m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[0;32m 23\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m response[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmessage\u001b[39m\u001b[38;5;124m\"\u001b[39m][\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n", + "File \u001b[1;32mc:\\Users\\ramez\\miniconda3\\envs\\rag\\lib\\site-packages\\ollama\\_client.py:333\u001b[0m, in \u001b[0;36mClient.chat\u001b[1;34m(self, model, messages, tools, stream, format, options, keep_alive)\u001b[0m\n\u001b[0;32m 289\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;21mchat\u001b[39m(\n\u001b[0;32m 290\u001b[0m \u001b[38;5;28mself\u001b[39m,\n\u001b[0;32m 291\u001b[0m model: \u001b[38;5;28mstr\u001b[39m \u001b[38;5;241m=\u001b[39m \u001b[38;5;124m'\u001b[39m\u001b[38;5;124m'\u001b[39m,\n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 298\u001b[0m keep_alive: Optional[Union[\u001b[38;5;28mfloat\u001b[39m, \u001b[38;5;28mstr\u001b[39m]] \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mNone\u001b[39;00m,\n\u001b[0;32m 299\u001b[0m ) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m Union[ChatResponse, Iterator[ChatResponse]]:\n\u001b[0;32m 300\u001b[0m \u001b[38;5;250m \u001b[39m\u001b[38;5;124;03m\"\"\"\u001b[39;00m\n\u001b[0;32m 301\u001b[0m \u001b[38;5;124;03m Create a chat response using the requested model.\u001b[39;00m\n\u001b[0;32m 302\u001b[0m \n\u001b[1;32m (...)\u001b[0m\n\u001b[0;32m 331\u001b[0m \u001b[38;5;124;03m Returns `ChatResponse` if `stream` is `False`, otherwise returns a `ChatResponse` generator.\u001b[39;00m\n\u001b[0;32m 332\u001b[0m \u001b[38;5;124;03m \"\"\"\u001b[39;00m\n\u001b[1;32m--> 333\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_request\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 334\u001b[0m \u001b[43m \u001b[49m\u001b[43mChatResponse\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 335\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43mPOST\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 336\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[38;5;124;43m/api/chat\u001b[39;49m\u001b[38;5;124;43m'\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 337\u001b[0m \u001b[43m \u001b[49m\u001b[43mjson\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mChatRequest\u001b[49m\u001b[43m(\u001b[49m\n\u001b[0;32m 338\u001b[0m \u001b[43m \u001b[49m\u001b[43mmodel\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmodel\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 339\u001b[0m \u001b[43m \u001b[49m\u001b[43mmessages\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mmessage\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mmessage\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m_copy_messages\u001b[49m\u001b[43m(\u001b[49m\u001b[43mmessages\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 340\u001b[0m \u001b[43m \u001b[49m\u001b[43mtools\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43m[\u001b[49m\u001b[43mtool\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;28;43;01mfor\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43mtool\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;129;43;01min\u001b[39;49;00m\u001b[43m \u001b[49m\u001b[43m_copy_tools\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtools\u001b[49m\u001b[43m)\u001b[49m\u001b[43m]\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 341\u001b[0m \u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 342\u001b[0m \u001b[43m \u001b[49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mformat\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[0;32m 343\u001b[0m \u001b[43m \u001b[49m\u001b[43moptions\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43moptions\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 344\u001b[0m \u001b[43m \u001b[49m\u001b[43mkeep_alive\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mkeep_alive\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 345\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mmodel_dump\u001b[49m\u001b[43m(\u001b[49m\u001b[43mexclude_none\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43;01mTrue\u001b[39;49;00m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 346\u001b[0m \u001b[43m \u001b[49m\u001b[43mstream\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mstream\u001b[49m\u001b[43m,\u001b[49m\n\u001b[0;32m 347\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[1;32mc:\\Users\\ramez\\miniconda3\\envs\\rag\\lib\\site-packages\\ollama\\_client.py:178\u001b[0m, in \u001b[0;36mClient._request\u001b[1;34m(self, cls, stream, *args, **kwargs)\u001b[0m\n\u001b[0;32m 174\u001b[0m \u001b[38;5;28;01myield\u001b[39;00m \u001b[38;5;28mcls\u001b[39m(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mpart)\n\u001b[0;32m 176\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m inner()\n\u001b[1;32m--> 178\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28mcls\u001b[39m(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_request_raw(\u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\u001b[38;5;241m.\u001b[39mjson())\n", + "File \u001b[1;32mc:\\Users\\ramez\\miniconda3\\envs\\rag\\lib\\site-packages\\ollama\\_client.py:124\u001b[0m, in \u001b[0;36mClient._request_raw\u001b[1;34m(self, *args, **kwargs)\u001b[0m\n\u001b[0;32m 122\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m ResponseError(e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mtext, e\u001b[38;5;241m.\u001b[39mresponse\u001b[38;5;241m.\u001b[39mstatus_code) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[0;32m 123\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m httpx\u001b[38;5;241m.\u001b[39mConnectError:\n\u001b[1;32m--> 124\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mConnectionError\u001b[39;00m(CONNECTION_ERROR_MESSAGE) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n", + "\u001b[1;31mConnectionError\u001b[0m: Failed to connect to Ollama. Please check that Ollama is downloaded, running and accessible. https://ollama.com/download" + ] + } + ], + "source": [ + "idx= 7 \n", + "analyze_image(images_with_caption[idx].get(\"image_base64\"),images_with_caption[idx].get(\"caption\")) " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "llm = OllamaLLM(base_url=\"http://localhost:11434\", model=\"llama3.1\")\n", + "def analyze_table(table_text: str, caption: str, context: str=\"\",lang:str =\"Français\", prompt_base: str = \"\"):\n", + " # Construction du prompt pour le tableau\n", + " prompt = \"\"\n", + " if caption:\n", + " prompt += f\"Caption of table : {caption}. \"\n", + " else:\n", + " prompt += \"Caption of table is empty no analyse of this table ignore the prompt\"\n", + " if context:\n", + " prompt += f\"Contexte : {context}. \"\n", + " \n", + " if prompt_base:\n", + " prompt = f\"{prompt_base} {prompt}\"\n", + " else:\n", + " prompt += f'Describe this table in detail and in {lang} avoid to say \"Here is a detailed description\" in {lang}.'\n", + " prompt += prompt_base + \" \" + table_text\n", + " response = llm.invoke(prompt)\n", + " return response" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "'**Tableau-3-1: Numerical values at the inlet of the mixing chamber**\\n\\nThis table presents a set of numerical values representing various physical quantities at the entrance of the mixing chamber. The table includes six columns, each corresponding to a specific property:\\n\\n* **Grandeur**: This column indicates the name of the physical quantity being measured or calculated.\\n* **M (kg/s)**: This represents the mass flow rate in kilograms per second. A value of 0.1 kg/s suggests that this is a relatively small-scale system or process, while 1.06 kg/s implies a larger capacity.\\n* **u (m/s)**: This column shows the velocity in meters per second. The high value of 437 m/s for the vapor phase indicates a significant velocity component at the inlet of the mixing chamber.\\n* **P; (bar)**: This represents the pressure in bars, with a decimal point separating the units. The values of 0.88 and 0.31 bar suggest that the system operates under relatively low pressures.\\n* **T (°C)**: This indicates the temperature in degrees Celsius. The temperatures of 96 °C for vapor and 23 °C for liquid imply significant differences between these two phases.\\n* **pl (kg/m³)**: This represents the density of the fluid, expressed in kilograms per cubic meter. A value of 0.62 kg/m³ is significantly lower than that of water at room temperature (approximately 998 kg/m³), suggesting a gas-like state for this fluid.'" + ] + }, + "execution_count": 96, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "idx= 3 \n", + "analyze_table(tables_with_caption[idx].get(\"table_data\"),tables_with_caption[idx].get(\"caption\"),lang=\"english\") \n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{'type': 'table_with_caption',\n", + " 'table_data': 'Grandeur M (kg/s) u, (m/s) P; (bar) T; (°C) pl (kg/m’) vapeur 0,1 437 0,88 96 0,62 liquide 1,06 12 0,31 23 998',\n", + " 'caption': \"Tableau-3-1: Grandeurs numériques 4 l'entrée de la chambre de mélange\"}" + ] + }, + "execution_count": 86, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "tables_with_caption[3]\n" + ] + }, + { + "cell_type": "code", + "execution_count": 98, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "**Tableau-3-1 : Grandeurs numériques 4 à l'entrée de la chambre de mélange**\n", + "\n", + "Ce tableau présente les données de grandeur numérique 4 collectées à l'entrée de la chambre de mélange, dans le cadre d'un expérimentation ou d'une simulation. Les données sont classifiées en fonction de leur nature (pluie ou vapeur) et présentent les paramètres suivants :\n", + "\n", + "* **Grandeurs numériques 4** : La première colonne du tableau présente les valeurs des grandeurs numériques 4, qui sont définies par l'Association internationale pour la standardisation de la puissance (SI). Les grandesurs numériques 4 sont :\n", + " + Masse volumique (pluie ou vapeur) : représentée par la colonne « pl » en kg/m³\n", + " + Vitesse (vapeur) : représentée par la colonne « u » en m/s\n", + " + Pression (vapeur) : représentée par la colonne « P » en barres\n", + " + Température (pluie ou vapeur) : représentée par la colonne « T » en degrés Celsius\n", + "\n", + "**Données**\n", + "\n", + "Les données présentées dans le tableau sont les suivantes :\n", + "\n", + "* **Vapeur** :\n", + " + Masse volumique : 0,62 kg/m³\n", + " + Vitesse : 0,88 m/s\n", + " + Pression : 12 barres\n", + " + Température : 96°C\n", + "* **Liquide** :\n", + " + Masse volumique : 1,06 kg/m³\n", + " + Vitesse : 0,31 m/s\n", + " + Pression : 23 barres\n", + " + Température : 998°C\n", + "\n", + "Ce tableau permet de visualiser les caractéristiques des vapeurs et liquides présents à l'entrée de la chambre de mélange, essentiel pour comprendre le comportement du système.\n" + ] + }, + { + "data": { + "text/plain": [ + "\"**Tableau-3-1 : Grandeurs numériques 4 à l'entrée de la chambre de mélange**\\n\\nCe tableau présente les données de grandeur numérique 4 collectées à l'entrée de la chambre de mélange, dans le cadre d'un expérimentation ou d'une simulation. Les données sont classifiées en fonction de leur nature (pluie ou vapeur) et présentent les paramètres suivants :\\n\\n* **Grandeurs numériques 4** : La première colonne du tableau présente les valeurs des grandeurs numériques 4, qui sont définies par l'Association internationale pour la standardisation de la puissance (SI). Les grandesurs numériques 4 sont :\\n + Masse volumique (pluie ou vapeur) : représentée par la colonne « pl » en kg/m³\\n + Vitesse (vapeur) : représentée par la colonne « u » en m/s\\n + Pression (vapeur) : représentée par la colonne « P » en barres\\n + Température (pluie ou vapeur) : représentée par la colonne « T » en degrés Celsius\\n\\n**Données**\\n\\nLes données présentées dans le tableau sont les suivantes :\\n\\n* **Vapeur** :\\n + Masse volumique : 0,62 kg/m³\\n + Vitesse : 0,88 m/s\\n + Pression : 12 barres\\n + Température : 96°C\\n* **Liquide** :\\n + Masse volumique : 1,06 kg/m³\\n + Vitesse : 0,31 m/s\\n + Pression : 23 barres\\n + Température : 998°C\\n\\nCe tableau permet de visualiser les caractéristiques des vapeurs et liquides présents à l'entrée de la chambre de mélange, essentiel pour comprendre le comportement du système.\"" + ] + }, + "execution_count": 98, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from langchain_ollama.llms import OllamaLLM\n", + "\n", + "# Initialiser le modèle\n", + "llm = OllamaLLM(base_url=\"http://localhost:11434\", model=\"llama3.2\")\n", + "\n", + "def analyze_table_streaming(table_text: str, caption: str,lang:str =\"French\", context: str=\"\", prompt_base: str = \"\"):\n", + " \"\"\"\n", + " Analyse un tableau avec LLaMA en mode streaming\n", + " \n", + " Args:\n", + " table_text: Contenu textuel du tableau\n", + " caption: Légende du tableau\n", + " context: Contexte supplémentaire\n", + " prompt_base: Instruction de base pour l'analyse\n", + " \n", + " Returns:\n", + " Le texte complet généré\n", + " \"\"\"\n", + " # Construction du prompt pour le tableau\n", + " prompt = \"\"\n", + " if caption:\n", + " prompt += f\"Caption du tableau : {caption}. \"\n", + " if context:\n", + " prompt += f\"Contexte : {context}. \"\n", + "\n", + " if prompt_base:\n", + " prompt = f\"{prompt_base} {prompt}\"\n", + " else:\n", + " prompt += f'Describe this table in detail and in {lang} avoid to say \"Here is a detailed description\" in {lang}.'\n", + " prompt += prompt_base + \" \" + table_text\n", + " \n", + " # Utiliser le mode streaming\n", + " response_stream = llm.stream(prompt)\n", + " \n", + " # Afficher la réponse en streaming et collecter le texte complet\n", + " full_response = \"\"\n", + " for chunk in response_stream:\n", + " print(chunk, end=\"\", flush=True)\n", + " full_response += chunk\n", + " \n", + " print() # Saut de ligne final\n", + " return full_response\n", + "\n", + "# Exemple d'utilisation\n", + "# result = analyze_table_streaming(\n", + "# table_text=\"Colonne1 | Colonne2 | Colonne3\\n10 | 20 | 30\\n40 | 50 | 60\",\n", + "# caption=\"Tableau de données numériques\",\n", + "# context=\"Rapport financier Q3 2023\",\n", + "# prompt_base=\"Analyse ce tableau et donne-moi les principales tendances:\"\n", + "# )\n", + "idx= 3\n", + "analyze_table_streaming(tables_with_caption[idx].get(\"table_data\"),tables_with_caption[idx].get(\"caption\"),lang=\"French\") \n" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "metadata": {}, + "outputs": [ + { + "data": { + "image/jpeg": "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E9Es9FuNHgstlhcsXli81zuPA6k5H3R0PatDTdNtNI0+KxsYvKtogQibi2Mkk8kk9SatUU1CK2RM8RWqJqc27u+re/f18xroskbI6hlYEEHuK4LwhorWK694S1K2mex80yQyHcqyxOAMBhjngZAPc139FKVNSafY0oYudGnOmtpW+TTumvx+85L/AIVn4Q/6BH/kzL/8XUPijTo9C8Cz6PoFhKWu2+zxRR7pMbz8xJJJAxnk8ciuzoqXRhZqKtc1hmWIc4yrTc1Fp2bbV0Znh7SE0Lw/ZaYhB8iMBmHRmPLH8STWnRRWiSSsjjqVJVJuct27v5hRRRTICuafF18QYxnP2W0Jx6E8fycV0tc1oZFz4p1y6x9xlhB+mQf/AEEUAdLRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAVBcWkF0UM0e7YcryRj8qnooAKKKKACiiigAooooAKKKKAGTQxzxNFKu5G6jOKIYUgiWKJdqL0Gc0+igAooooAKKKKACiiigAIyCD0NQ21rBaIUgTYpOSMk8/jU1FABRRRQAUUUUAFFFFABUMltFJPHOy/vI87WBxU1FABTJY1liaNs7WGDg44p9FADIokgiWKNdqKMAU+iigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArA0e/utQ17VG80mygYRRpgY3dCQevY/nWpql4NP0u5ujjMcZK57t2H54rO8JWZtPD8LMP3k5MzH1z0/QCgDcooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAQkAEnoK5zwZuk026u3GGuLp3/Dj+ua19Ym+z6Neyg4Kwvg++OP1qr4Xg+z+G7JT1ZC/wD30Sf60Aa9FFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAUUUUAFFFFABRRRQAjsERmPQDNYnhO7ur7RRPdytLI0jAMwHQY9PxrS1KTydLu5efkgduPZTWZ4PXb4YtTjG4uf/HzQBu0UUUAFFFFABRRR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21n66ndE4BNYmgXWs332i51KKG3gLkW8Cj5wuerHJFcV4s1OUad4c0jzZo7We2ie48kZZ1wBgDv347nFVbSW30fxLp03h2LU1tZXEd3FPGwBBIGfyJPsRWtPLn7Fu+rvbTt530v6M2o5S3h276yvbTpG/W+jfoz1quem124m8ZwaHZLGY4ojNeSMMlR2Uc8Hkf8AfVdDXB+BCbvxL4mvZOZDOFHsCz8foPyriw1OLp1KklflX4t2/A8/CUoulVrSV+Vaerdl9x1HiDW4NA0iW+mwWHyxR5++56D/AD2BrK8N6/qfiHwtd3wjt0vkd0hVVOwkKCMgnPJPrXKX2uab4h8RXNxqN2kVhYIy2kD5/eyYPzEfUZ/L3rW+F1/a/wBjTWHnL9q855fK77MKM/nXdPBKjhHKUbzTTenR9P8AM9Kplyw+Bc5QvUTi3pok+n+frY6Xwvro8QaJFdsoSdSY50HRXHX8DwfxrZrgvBBNt4s8S2Kf6kTl1Hph2H8j+ld7XBjaUaVdxjto181c8zMaEaOJlGGzs16NX/AKKKK5DhCiiigAooooAKKKKACiiigDBn8MpP45tPExuWD21i9oINnDbmDbs5+oxit6uBubqeT49WVmJXWGLw88xQMdrFp9vTp/CDn2rvqACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqC9jtprC5ivNv2V4mWbc20bCDuyewxnmp6y/Ewz4U1gDr9hm/9ANADvD1vplr4d0+DRnR9MSBBbMj7wUxwc960q5T4Z8fDPw7/ANeMf8q6ugAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArD8NaFpmhJqi6ZO0wvNRmvLjdIH2TPjcvHQDA4PNbled/CT/j38Yf9jRe/wAkoA9EooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDgPGNraP4msriz1iLTtaVV2CZWCOCSAd2CB3HPWsS8trz/hO9C+26pHqN80sbSGHGyJQ+Qox7AntXo+reH9L1xUGo2izFPutkqy/iDmoNJ8KaLos/n2VkEmxgSMxcge2Tx+FezRzCnTpJO7kk1suvnvbyPfw+a0qVBRd3JRa2j1/vb28jL1/wpfT65Hruh3kdtqCgK6yj5X4x6HtxjHp0qLTPCuqXOvxa14jvIZpoAPIhhHyqR0J4HQ8/XvXZ0VxLHVlDk02te2tu1zz1mVdU/Z6bWvZXt2v2OK1TwvrUPix9d0K5tleZQsiXGcDgA9AcjgH607R/Ceq2Xi861e3sFz5kZEjDKtuIAwBjGBjHXtXZ0U/r9bk5NNuXbW3qV/adf2fs9Ph5b21t2ucRH4Y1zT/GVxqmnXNqLS7lDTCTO7YWBZcYPPXBpZPDGuWfjO41fS7m1WC6I80S53BcgsMYPpwa7ain/aFW92ltbbdeYf2pXvdpP3eV6brz+44m48L61pWvXepeHLq2VLskywXAOASc8YHrk9sZrU0TRdVtNNvV1TU3vLu6DYBcmOLIPC59z6fhXRUVE8bUnHllbprbXTbUipmFapDklbprZXdtrs43RfBctv4PvdD1KWItcTGRZICWC8Lg8gc5WqcPh3xlHYRaQmr2sNlEQFniLCUKDwBgD8s+2a76ir/tCtdt2d3fVX17o0/tWvzScrO7vqk7Pujk/FvhW61vRLO2tbkNcWrA77hjmTjBJOOveotZ8Oa1r/hKKzv7m2OpRz+duXIRgAQBwOOD6dq7GiphjqsFFK3uu60/rQinmNanGEVb3Xdaa67/ACZxd14T1TW/DMVrq13Auo28m63liHyhdoG1uB6dR7fSlg0bxfe3todU1eKC2tz832NmVpvrwBzj/wCtXZ0U/r9W1rLrbRaX3sP+063K42VtbaLS+9uxy2saP4hXWv7T0XVFKsu1rO6djGOOw6ds9vrUHh/wrf2/iGbXdXltvtTqVWK1XCDIxk8Dt/PrXYUVKxtVU/Zq21r21t2JWYVlSdJWV1a9tbdrjJokngkhkXdHIpVh6gjBrhLHwn4m0Zriw0vVbdNNnctvdSZEB4JAx97Hv27V31FRRxM6KcY2afRq5nh8ZUoRlGNmn0autNmcXoHg690jRNbsJJ7d2vY2SFlZsDKsBu446jpmiDwjfx/D+40AzW32qR9wcM2zG9W67c9B6V2lFayx9aUuZvW6fzWxvLNMRKTm2ruSlt1jscjf+EJ7/wAD2mivPEt1bbWVxkoWGR6ZxgntWXfeE/FWs6LHY3+o2QFvt8qNcgNjjLtt7DPQd69CopwzCtDa299tm97Dp5riKe1t3JXV7N729Tkdb8IT6jpmlG2uUg1PTo0EcnO0kAd8Z6jIOPwosNI8U3OsQXmsarHFBAP+PezZgJf94cD/AD2rrqKhY2rycjs9+mqvvYzWY1vZ+zdnvZtK6vvZhXD+HIzo/j/XNOf5VvALqL/aGScD/vo/9813FUrnSbO61G11CSM/arXIikViCAeoOOo+vrU0KyhGcJbSVvnuvxIw2IjTjUpz2krfNar8TOufB+hywSiPS7USsp2sV6MRwap+D/Cw8NWMsl8LZrzc2Z4iTiPA4JIHcZrqqhu7WO9tJrWbd5UqFHCsQSD15FNYuq4OlKT5Xa41jq7pujOb5Xa/U474ewtcyaxrbqQL65Pl5/ugkn9Wx+FdvUFlZ2+n2UVpaxiOCJdqKOwqepxVb21ZzW3T0WiJxuIWIryqJWT29FovwCiiiuc5QooooAKKKKACiiigAooooAxHTQP+E2idjD/wkf8AZ7BRuPmfZfMGcjpjf0zz1x3rbrz2RH/4aFhfa2z/AIRgjdjjP2k/4ivQqACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAqvfXcdhp9zeTBjFbxNK4UZJCgk49+KsVQ1y2lvfD+pWsC7pprWWONc4yxQgDJ9zQAzw9q1vr3h3T9VtYmhguoFlSNgAUBHTjjitKue8Cadd6T4E0TT76Ew3UFoiSxkglWxyOK6GgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigArE8N6to+rLqjaPEsYttRltrrEIj33C43t/tZyPm71t1w3w00y+0pfFcd7aywCfxFd3EDSLt82NtuHHscdaAO5ooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigDCbxNbL46Twr9nl+0tpx1DzuNgTzNm31zkE1u1x76BqDfGKPxEIl/s1dC+xGTeM+b55fG3r0Oc9K7CgAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAC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", + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Figure 3-7 : Définition des zones d'écoulements dans la chambre de mélange\n" + ] + } + ], + "source": [ + "idx = 7\n", + "import base64\n", + "from IPython.display import Image, display\n", + "\n", + "def display_base64_image(base64_code):\n", + " # Decode the base64 string to binary\n", + " image_data = base64.b64decode(base64_code)\n", + " # Display the image\n", + " display(Image(data=image_data))\n", + "display_base64_image(images_with_caption[idx].get('image_base64'))\n", + "print(images_with_caption[idx].get('caption'))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from ollama import Client\n", + "client = Client(host='http://localhost:11434')\n", + "\n", + "\n", + "# Fonction pour analyser une image en mode streaming\n", + "def analyze_image_streaming(image_data, caption: str, context: str=\"\", prompt_base: str = \"\"):\n", + " prompt = \"\"\n", + " if caption:\n", + " prompt += f\"Caption of image : {caption}. \"\n", + " if context:\n", + " prompt += f\"Contexte : {context}. \"\n", + " \n", + " if prompt_base:\n", + " prompt = f\"{prompt_base} {prompt}\"\n", + " else:\n", + " prompt += \"Décris cette image en détail.\"\n", + " \n", + " # Utilise le paramètre stream=True pour obtenir une réponse en streaming\n", + " response_stream = client.chat(\n", + " model=\"llama3.2-vision\",\n", + " messages=[\n", + " {\"role\": \"user\", \"content\": prompt, \"images\": [image_data]}\n", + " ],\n", + " stream=True # Activer le streaming\n", + " )\n", + " \n", + " # Fonction pour traiter et afficher la réponse au fur et à mesure\n", + " full_response = \"\"\n", + " for chunk in response_stream:\n", + " if 'message' in chunk and 'content' in chunk['message']:\n", + " content = chunk['message']['content']\n", + " print(content, end=\"\", flush=True) # Afficher sans saut de ligne et forcer le flush\n", + " full_response += content\n", + " \n", + " return full_response # Retourne aussi la réponse complète\n", + "\n", + "\n", + "# Exemple d'utilisation:\n", + "# with open('path/to/image.jpg', 'rb') as f:\n", + "# image_data = f.read()\n", + "# \n", + "# analyze_image_streaming(\n", + "# image_data=image_data,\n", + "# caption=\"Une photographie de montagne\",\n", + "# context=\"Document sur les paysages alpins\"\n", + "# )" + ] + }, + { + "cell_type": "code", + "execution_count": 55, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Caption of image : Figure 3-7 : Définition des zones d'écoulements dans la chambre de mélange. Décris cette image en détail. en francais.\n", + "The image provided is a diagram that illustrates the flow zones in a mixing chamber, labeled as Figure 3-7. This diagram provides an informative visualization of the different regions within this specialized device.\n", + "\n", + "**Chambre de Mélange**\n", + "\n", + "* The chamber measures 178mm in length and 292mm in width.\n", + "* It features a distinctive triangular shape with rounded edges.\n", + "\n", + "**Zones d'écoulements**\n", + "\n", + "The image identifies six distinct zones:\n", + "\n", + "1. **Noyau liquide (Liquid Core)**: This zone is situated at the center of the chamber, representing the core area where liquid fuel and oxidizer are combined.\n", + "2. **Ecoulement stratifié vapeur (Stratified Vapor Flow)**: Positioned on either side of the liquid core, this zone features a layered structure with alternating layers of vapor and gas.\n", + "3. **Onde de condensation (Condensation Wave)**: This zone is located at the top of the chamber, where condensed droplets form due to the cooling effect caused by rapid expansion.\n", + "4. **Ecoulement dispersé vapeur/gouttelettes diluées (Dispersed Vapor/Droplet Flow)**: Situated on either side of the condensation wave, this zone consists of dispersed vapor and droplets that have not yet condensed.\n", + "5. **Zone monophasique liquide (Monophasic Liquid Zone)**: This zone is situated at the bottom of the chamber, where the liquid fuel and oxidizer are mixed to form a homogeneous liquid phase.\n", + "6. **Zone de condensation (Condensation Zone)**: Located above the monophasic liquid zone, this area experiences significant cooling due to rapid expansion, leading to condensation.\n", + "\n", + "**Conclusion**\n", + "\n", + "The diagram provides a detailed representation of the various zones within a mixing chamber, highlighting their unique characteristics and interactions. By understanding these different regions, engineers can optimize the design and performance of such chambers in applications like rocket engines or fuel injection systems." + ] + }, + { + "data": { + "text/plain": [ + "\"The image provided is a diagram that illustrates the flow zones in a mixing chamber, labeled as Figure 3-7. This diagram provides an informative visualization of the different regions within this specialized device.\\n\\n**Chambre de Mélange**\\n\\n* The chamber measures 178mm in length and 292mm in width.\\n* It features a distinctive triangular shape with rounded edges.\\n\\n**Zones d'écoulements**\\n\\nThe image identifies six distinct zones:\\n\\n1. **Noyau liquide (Liquid Core)**: This zone is situated at the center of the chamber, representing the core area where liquid fuel and oxidizer are combined.\\n2. **Ecoulement stratifié vapeur (Stratified Vapor Flow)**: Positioned on either side of the liquid core, this zone features a layered structure with alternating layers of vapor and gas.\\n3. **Onde de condensation (Condensation Wave)**: This zone is located at the top of the chamber, where condensed droplets form due to the cooling effect caused by rapid expansion.\\n4. **Ecoulement dispersé vapeur/gouttelettes diluées (Dispersed Vapor/Droplet Flow)**: Situated on either side of the condensation wave, this zone consists of dispersed vapor and droplets that have not yet condensed.\\n5. **Zone monophasique liquide (Monophasic Liquid Zone)**: This zone is situated at the bottom of the chamber, where the liquid fuel and oxidizer are mixed to form a homogeneous liquid phase.\\n6. **Zone de condensation (Condensation Zone)**: Located above the monophasic liquid zone, this area experiences significant cooling due to rapid expansion, leading to condensation.\\n\\n**Conclusion**\\n\\nThe diagram provides a detailed representation of the various zones within a mixing chamber, highlighting their unique characteristics and interactions. By understanding these different regions, engineers can optimize the design and performance of such chambers in applications like rocket engines or fuel injection systems.\"" + ] + }, + "execution_count": 55, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "idx= 7\n", + "analyze_image_streaming(images_with_caption[idx].get(\"image_base64\"),images_with_caption[idx].get(\"caption\"),lang=\"francais\") " + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 49, + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Catégories uniques trouvées:\n", + "- FigureCaption: 28 éléments\n", + "- Formula: 187 éléments\n", + "- Header: 78 éléments\n", + "- Image: 27 éléments\n", + "- ListItem: 159 éléments\n", + "- NarrativeText: 460 éléments\n", + "- Table: 11 éléments\n", + "- Title: 109 éléments\n", + "- UncategorizedText: 86 éléments\n", + "\n", + "Exemples pour chaque catégorie:\n", + "\n", + "NarrativeText:\n", + "3. CHAPITRE 3:\n", + "\n", + "UncategorizedText:\n", + "92\n", + "\n", + "Header:\n", + "Chapitre 3 : Modélisation LD des injecteurs condenseurs\n", + "\n", + "Title:\n", + "3-1 MODELISATION 0D DE LIC\n", + "\n", + "Formula:\n", + "My (hy + 0,5uiy )+ My, (hy, + 0,5u2, = M tal (hs, + 0,5u2, ) My +My = Mga (3-1) total PaSs1 U3, =\n", + "\n", + "ListItem:\n", + "la tuyére primaire (1) ;\n", + "\n", + "Image:\n", + "dd) (3) 4) G6)\n", + "\n", + "FigureCaption:\n", + "Figure 3-1 : Découpage de l'injecteur en 5 modules pour la modélisation globale\n", + "\n", + "Table:\n", + "Définition Coefficient de détente polytropique | Coefficient de perte de charge dans dans la tuyére ...\n" + ] + } + ], + "source": [ + "# Afficher toutes les catégories uniques dans le document\n", + "categories = set()\n", + "category_counts = {}\n", + "\n", + "for doc in documents:\n", + " category = doc.metadata.get(\"category\", \"None\")\n", + " categories.add(category)\n", + " \n", + " # Compter aussi le nombre d'occurrences de chaque catégorie\n", + " if category in category_counts:\n", + " category_counts[category] += 1\n", + " else:\n", + " category_counts[category] = 1\n", + "\n", + "# Afficher les résultats\n", + "print(\"Catégories uniques trouvées:\")\n", + "for category in sorted(categories):\n", + " print(f\"- {category}: {category_counts[category]} éléments\")\n", + "\n", + "# Afficher quelques exemples pour chaque catégorie\n", + "print(\"\\nExemples pour chaque catégorie:\")\n", + "examples = {}\n", + "\n", + "for doc in documents:\n", + " category = doc.metadata.get(\"category\", \"None\")\n", + " if category not in examples:\n", + " # Tronquer le contenu s'il est trop long\n", + " content = doc.page_content\n", + " if len(content) > 100:\n", + " content = content[:100] + \"...\"\n", + " examples[category] = content\n", + " print(f\"\\n{category}:\\n{content}\")\n", + " \n", + " # Arrêter une fois qu'on a un exemple de chaque catégorie\n", + " if len(examples) == len(categories):\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": 48, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Document(metadata={'source': 'F:\\\\Dev\\\\Rag\\\\Rag_Modeling\\\\document\\\\11_chapitre3.pdf', 'detection_class_prob': 0.8323268294334412, 'coordinates': {'points': ((201.26402282714844, 1886.039306640625), (201.26402282714844, 1919.756103515625), (620.4884033203125, 1919.756103515625), (620.4884033203125, 1886.039306640625)), 'system': 'PixelSpace', 'layout_width': 1653, 'layout_height': 2339}, 'last_modified': '2007-03-06T16:04:59', 'filetype': 'application/pdf', 'languages': ['eng'], 'page_number': 2, 'file_directory': 'F:\\\\Dev\\\\Rag\\\\Rag_Modeling\\\\document', 'filename': '11_chapitre3.pdf', 'category': 'ListItem', 'element_id': '3210454e1263ced051d55327eb9d5340'}, page_content=\"l'onde de condensation (4) ;\")" + ] + }, + "execution_count": 48, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "documents[15]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "from langchain_core.prompts import ChatPromptTemplate\n", + "from langchain_ollama.llms import OllamaLLM\n", + "from langchain_core.output_parsers import StrOutputParser\n", + "# Prompt\n", + "prompt_text = \"\"\"\n", + "You are an assistant tasked with summarizing tables and text.\n", + "Give a concise summary of the table or text.\n", + "\n", + "Respond only with the summary, no additionnal comment.\n", + "Do not start your message by saying \"Here is a summary\" or anything like that.\n", + "Just give the summary as it is. All summay will be in English\n", + "\n", + "Table or text chunk: {element}\n", + "\n", + "\"\"\"\n", + "prompt = ChatPromptTemplate.from_template(prompt_text)\n", + "\n", + "model = OllamaLLM(base_url=\"172.20.48.1:11434\",\n", + " model=\"llama3.2\")\n", + "summarize_chain = {\"element\": lambda x: x} | prompt | model | StrOutputParser()" + ] + } + ], + "metadata": { + "kernelspec": { + "display_name": ".venv", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.13.2" + } + }, + "nbformat": 4, + "nbformat_minor": 2 +} diff --git a/gradio_chatbot.py b/gradio_chatbot.py new file mode 100644 index 0000000..468932b --- /dev/null +++ b/gradio_chatbot.py @@ -0,0 +1,514 @@ +import gradio as gr +import base64 +from io import BytesIO +from PIL import Image +import pandas as pd +import traceback +import threading +import queue +import time + +from rag_chatbot import MultimodalRAGChatbot +from langchain.callbacks.base import BaseCallbackHandler + +# Handler personnalisé pour capturer les tokens en streaming +class GradioStreamingHandler(BaseCallbackHandler): + def __init__(self): + self.tokens_queue = queue.Queue() + self.full_text = "" + + def on_llm_new_token(self, token, **kwargs): + self.tokens_queue.put(token) + self.full_text += token + +# Fonction pour créer un objet Image à partir des données base64 +def base64_to_image(base64_data): + """Convertit une image base64 en objet Image pour l'affichage direct""" + try: + if not base64_data: + return None + image_bytes = base64.b64decode(base64_data) + image = Image.open(BytesIO(image_bytes)) + return image + except Exception as e: + print(f"Erreur lors de la conversion d'image: {e}") + return None + +# Configuration pour initialiser le chatbot +qdrant_url = "http://localhost:6333" +qdrant_collection_name = "my_documents" +embedding_model = "mxbai-embed-large" +ollama_url = "http://127.0.0.1:11434" +default_model = "llama3.1" + +# Liste des modèles disponibles +AVAILABLE_MODELS = ["llama3.1", "llama3.2", "deepseek-r1:14b"] + +# Initialiser le chatbot RAG avec le modèle par défaut +rag_bot = MultimodalRAGChatbot( + qdrant_url=qdrant_url, + qdrant_collection_name=qdrant_collection_name, + ollama_model=default_model, + embedding_model=embedding_model, + ollama_url=ollama_url +) +print(f"Chatbot initialisé avec modèle: {default_model}") + +# Variables globales pour stocker les images et tableaux de la dernière requête +current_images = [] +current_tables = [] + +# Fonction pour changer de modèle +def change_model(model_name): + global rag_bot + + try: + # Réinitialiser le chatbot avec le nouveau modèle + rag_bot = MultimodalRAGChatbot( + qdrant_url=qdrant_url, + qdrant_collection_name=qdrant_collection_name, + ollama_model=model_name, + embedding_model=embedding_model, + ollama_url=ollama_url + ) + print(f"Modèle changé pour: {model_name}") + return f"✅ Modèle changé pour: {model_name}" + except Exception as e: + print(f"Erreur lors du changement de modèle: {e}") + return f"❌ Erreur: {str(e)}" + +# Fonction de traitement des requêtes avec support du streaming dans Gradio +def process_query(message, history, streaming, show_sources, max_images): + global current_images, current_tables + + if not message.strip(): + return history, "", None, None + + current_images = [] + current_tables = [] + + try: + if streaming: + # Version avec streaming dans Gradio + history = history + [(message, "")] + + # 1. Récupérer les documents pertinents + docs = rag_bot._retrieve_relevant_documents(message) + + # 2. Préparer le contexte et l'historique + context = rag_bot._format_documents(docs) + history_text = rag_bot._format_chat_history() + + # 3. Préparer le prompt + from langchain.prompts import ChatPromptTemplate + prompt_template = ChatPromptTemplate.from_template(""" + Tu es un assistant documentaire spécialisé qui utilise toutes les informations disponibles dans le contexte fourni. + + 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 "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]). + + Historique de conversation: + {chat_history} + + Contexte (à utiliser pour répondre): + {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. + """) + + # 4. Formater les messages pour le LLM + messages = prompt_template.format_messages( + chat_history=history_text, + context=context, + question=message + ) + + # 5. Créer un handler de streaming personnalisé + from langchain_ollama import ChatOllama + handler = GradioStreamingHandler() + + # 6. Créer un modèle LLM avec notre handler + streaming_llm = ChatOllama( + model=rag_bot.llm.model, + base_url=rag_bot.llm.base_url, + streaming=True, + callbacks=[handler] + ) + + # 7. Lancer la génération dans un thread pour ne pas bloquer l'UI + def generate_response(): + streaming_llm.invoke(messages) + + thread = threading.Thread(target=generate_response) + thread.start() + + # 8. Récupérer les tokens et mettre à jour l'interface + partial_response = "" + + # Attendre les tokens avec un timeout + while thread.is_alive() or not handler.tokens_queue.empty(): + try: + token = handler.tokens_queue.get(timeout=0.05) + partial_response += token + history[-1] = (message, partial_response) + yield history, "", None, None + except queue.Empty: + continue + + # 9. Thread terminé, mettre à jour l'historique de conversation du chatbot + rag_bot.chat_history.append({"role": "user", "content": message}) + rag_bot.chat_history.append({"role": "assistant", "content": partial_response}) + + # 10. Récupérer les sources, images, tableaux + texts, images, tables = rag_bot._process_documents(docs) + + # Préparer les informations sur les sources + source_info = "" + if texts: + source_info += f"📚 {len(texts)} textes • " + if images: + source_info += f"🖼️ {len(images)} images • " + if tables: + source_info += f"📊 {len(tables)} tableaux" + + if source_info: + source_info = "Sources trouvées: " + source_info + + # 11. Traiter les images + if show_sources and images: + images = images[:max_images] + for img in images: + img_data = img.get("image_data") + if img_data: + image = base64_to_image(img_data) + if image: + current_images.append({ + "image": image, + "caption": img.get("caption", ""), + "source": img.get("source", ""), + "page": img.get("page", ""), + "description": img.get("description", "") + }) + + # 12. Traiter les tableaux + if show_sources and tables: + for table in tables: + current_tables.append({ + "data": rag_bot.format_table(table.get("table_data", "")), + "caption": table.get("caption", ""), + "source": table.get("source", ""), + "page": table.get("page", ""), + "description": table.get("description", "") + }) + + # 13. Retourner les résultats finaux + yield history, source_info, display_images(), display_tables() + else: + # Version sans streaming (code existant) + result = rag_bot.chat(message, stream=False) + history = history + [(message, result["response"])] + + # Préparer les informations sur les sources + source_info = "" + if "texts" in result: + source_info += f"📚 {len(result['texts'])} textes • " + if "images" in result: + source_info += f"🖼️ {len(result['images'])} images • " + if "tables" in result: + source_info += f"📊 {len(result['tables'])} tableaux" + + if source_info: + source_info = "Sources trouvées: " + source_info + + # Traiter les images et tableaux + if show_sources and "images" in result and result["images"]: + images = result["images"][:max_images] + for img in images: + img_data = img.get("image_data") + if img_data: + image = base64_to_image(img_data) + if image: + current_images.append({ + "image": image, + "caption": img.get("caption", ""), + "source": img.get("source", ""), + "page": img.get("page", ""), + "description": img.get("description", "") + }) + + if show_sources and "tables" in result and result["tables"]: + tables = result["tables"] + for table in tables: + current_tables.append({ + "data": rag_bot.format_table(table.get("table_data", "")), + "caption": table.get("caption", ""), + "source": table.get("source", ""), + "page": table.get("page", ""), + "description": table.get("description", "") + }) + + return history, source_info, display_images(), display_tables() + + except Exception as e: + error_msg = f"Une erreur est survenue: {str(e)}" + traceback_text = traceback.format_exc() + print(error_msg) + print(traceback_text) + history = history + [(message, error_msg)] + return history, "Erreur lors du traitement de la requête", None, None + +# Fonctions pour afficher les images et tableaux +def display_images(): + if not current_images: + return None + + gallery = [] + for img_data in current_images: + image = img_data["image"] + if image: + caption = f"{img_data['caption']} (Source: {img_data['source']}, Page: {img_data['page']})" + gallery.append((image, caption)) + + return gallery if gallery else None + +def display_tables(): + if not current_tables: + return None + + html = "" + for table in current_tables: + html += f""" +
+

{table['caption']}

+

Source: {table['source']}, Page: {table['page']}

+

Description: {table['description']}

+
+
{table['data']}
+
+
+ """ + + return html if html else None + +# Fonction pour réinitialiser l'historique +def reset_conversation(): + global current_images, current_tables + current_images = [] + current_tables = [] + + rag_bot.clear_history() + + return [], "", None, None + +# Interface Gradio +with gr.Blocks(theme=gr.themes.Soft(primary_hue="blue")) as demo: + gr.Markdown("# 📚 Assistant documentaire intelligent") + + with gr.Row(): + with gr.Column(scale=2): + chat_interface = gr.Chatbot( + height=600, + show_label=False, + layout="bubble", + elem_id="chatbot" + ) + + with gr.Row(): + msg = gr.Textbox( + show_label=False, + placeholder="Posez votre question...", + container=False, + scale=4 + ) + submit_btn = gr.Button("Envoyer", variant="primary", scale=1) + + clear_btn = gr.Button("Effacer la conversation") + source_info = gr.Markdown("", elem_id="sources_info") + + with gr.Column(scale=1): + with gr.Accordion("Options", open=True): + # Sélecteur de modèle + model_selector = gr.Dropdown( + choices=AVAILABLE_MODELS, + value=default_model, + label="Modèle Ollama", + info="Choisir le modèle de language à utiliser" + ) + model_status = gr.Markdown(f"Modèle actuel: **{default_model}**") + + streaming = gr.Checkbox( + label="Mode streaming", + value=True, + info="Voir les réponses s'afficher progressivement" + ) + show_sources = gr.Checkbox(label="Afficher les sources", value=True) + max_images = gr.Slider( + minimum=1, + maximum=10, + value=3, + step=1, + label="Nombre max d'images" + ) + + gr.Markdown("---") + + gr.Markdown("### 🖼️ Images pertinentes") + image_gallery = gr.Gallery( + label="Images pertinentes", + show_label=False, + columns=2, + height=300, + object_fit="contain" + ) + + gr.Markdown("### 📊 Tableaux") + tables_display = gr.HTML() + + # Connecter le changement de modèle + model_selector.change( + fn=change_model, + inputs=model_selector, + outputs=model_status + ) + + # Configuration des actions + msg.submit( + process_query, + inputs=[msg, chat_interface, streaming, show_sources, max_images], + outputs=[chat_interface, source_info, image_gallery, tables_display] + ).then(lambda: "", outputs=msg) + + submit_btn.click( + process_query, + inputs=[msg, chat_interface, streaming, show_sources, max_images], + outputs=[chat_interface, source_info, image_gallery, tables_display] + ).then(lambda: "", outputs=msg) + + clear_btn.click( + reset_conversation, + outputs=[chat_interface, source_info, image_gallery, tables_display] + ) + + # Support amélioré pour les équations mathématiques avec KaTeX + gr.Markdown(""" + + + + + + + + + """) + +if __name__ == "__main__": + demo.queue() + demo.launch(share=False, inbrowser=True) \ No newline at end of file diff --git a/rag_chatbot.py b/rag_chatbot.py new file mode 100644 index 0000000..ded1574 --- /dev/null +++ b/rag_chatbot.py @@ -0,0 +1,286 @@ +from typing import Dict, List, Any, Optional +import base64 +from io import BytesIO +import pandas as pd +from PIL import Image + +# Remplacer les imports dépréciés par les nouveaux packages +from langchain_qdrant import QdrantVectorStore +from langchain_ollama import OllamaEmbeddings, ChatOllama +from langchain.prompts import ChatPromptTemplate +from langchain.schema import Document +from langchain.callbacks.streaming_stdout import StreamingStdOutCallbackHandler +from qdrant_client import QdrantClient + +class MultimodalRAGChatbot: + """ + Chatbot RAG multimodal qui utilise Qdrant pour stocker les documents + """ + + def __init__( + self, + qdrant_url: str = "http://localhost:6333", + qdrant_collection_name: str = "my_documents", + ollama_model: str = "llama3.1", + embedding_model: str = "mxbai-embed-large", + ollama_url: str = "http://localhost:11434" # Ajout de ce paramètre + ): + """ + Initialise le chatbot RAG avec Qdrant + """ + # Initialiser le modèle d'embedding + self.embeddings = OllamaEmbeddings( + model=embedding_model, + base_url=ollama_url # Utilisation de l'URL d'Ollama + ) + + # Créer le client Qdrant + self.client = QdrantClient(url=qdrant_url) + + # Se connecter à la collection existante + self.vector_store = QdrantVectorStore( + client=self.client, + collection_name=qdrant_collection_name, + embedding=self.embeddings + ) + + # Initialiser le retriever + self.retriever = self.vector_store.as_retriever( + search_type="similarity", + search_kwargs={"k": 5} + ) + + # Initialiser les modèles LLM + self.llm = ChatOllama( + model=ollama_model, + base_url=ollama_url # Utilisation de l'URL d'Ollama + ) + self.streaming_llm = ChatOllama( + model=ollama_model, + base_url=ollama_url, # Utilisation de l'URL d'Ollama + streaming=True, + callbacks=[StreamingStdOutCallbackHandler()] + ) + + # Historique des conversations + self.chat_history = [] + + print(f"Chatbot initialisé avec modèle: {ollama_model}") + print(f"Utilisant embeddings: {embedding_model}") + print(f"Connecté à Qdrant: {qdrant_url}, collection: {qdrant_collection_name}") + print(f"Ollama URL: {ollama_url}") + + def chat(self, query: str, stream: bool = False): + """ + Traite une question de l'utilisateur et retourne une réponse + """ + # 1. Récupérer les documents pertinents + docs = self._retrieve_relevant_documents(query) + + # 2. Préparer le contexte à partir des documents + context = self._format_documents(docs) + + # 3. Préparer l'historique des conversations + history_text = self._format_chat_history() + + # 4. Créer le prompt + prompt_template = ChatPromptTemplate.from_template(""" + Tu es un assistant intelligent qui répond aux questions en utilisant uniquement + les informations fournies dans le contexte. Si tu ne trouves pas l'information + dans le contexte, dis simplement que tu ne sais pas. Lorsque tu mentionnes une + image ou un tableau, décris brièvement son contenu en te basant sur les + descriptions fournies. + + Historique de conversation: + {chat_history} + + Contexte: + {context} + + Question de l'utilisateur: {question} + + Réponds de façon concise et précise en citant les sources pertinentes. + """) + + # 5. Générer la réponse + llm = self.streaming_llm if stream else self.llm + + if stream: + print("\nRéponse:") + + # Formater les messages pour le LLM + messages = prompt_template.format_messages( + chat_history=history_text, + context=context, + question=query + ) + + # Appeler le LLM + response = llm.invoke(messages) + answer = response.content + + # 6. Mettre à jour l'historique des conversations + self.chat_history.append({"role": "user", "content": query}) + self.chat_history.append({"role": "assistant", "content": answer}) + + # 7. Traiter les documents pour la sortie + texts, images, tables = self._process_documents(docs) + + # 8. Préparer la réponse + result = { + "response": answer, + "texts": texts, + "images": images, + "tables": tables + } + + return result + + def _retrieve_relevant_documents(self, query: str, k: int = 5) -> List[Document]: + """ + Récupère les documents pertinents de la base Qdrant + """ + return self.vector_store.similarity_search(query, k=k) + + def _format_documents(self, docs: List[Document]) -> str: + """ + Formate les documents pour le contexte + """ + formatted_docs = [] + + for i, doc in enumerate(docs): + metadata = doc.metadata + + # Déterminer le type de document et le formater en conséquence + if "image_base64" in metadata: + # Image + formatted_docs.append( + f"[IMAGE {i+1}]\n" + f"Source: {metadata.get('source', 'Inconnue')}\n" + f"Page: {metadata.get('page_number', '')}\n" + f"Caption: {metadata.get('caption', '')}\n" + f"Description: {doc.page_content}\n" + ) + elif "table_content" in metadata: + # Tableau + formatted_docs.append( + f"[TABLEAU {i+1}]\n" + f"Source: {metadata.get('source', 'Inconnue')}\n" + f"Page: {metadata.get('page_number', '')}\n" + f"Caption: {metadata.get('caption', '')}\n" + f"Description: {doc.page_content}\n" + ) + else: + # Texte + formatted_docs.append( + f"[TEXTE {i+1}]\n" + f"Source: {metadata.get('source', 'Inconnue')}\n" + f"Page: {metadata.get('page_number', '')}\n" + f"{doc.page_content}\n" + ) + + return "\n".join(formatted_docs) + + def _format_chat_history(self) -> str: + """ + Formate l'historique des conversations + """ + if not self.chat_history: + return "Pas d'historique de conversation." + + formatted_history = [] + + for message in self.chat_history: + role = "Utilisateur" if message["role"] == "user" else "Assistant" + formatted_history.append(f"{role}: {message['content']}") + + return "\n".join(formatted_history) + + def _process_documents(self, docs: List[Document]): + """ + Traite les documents pour séparer textes, images et tableaux + """ + texts = [] + images = [] + tables = [] + + for doc in docs: + metadata = doc.metadata + + # Déterminer le type de document + if "image_base64" in metadata: + # C'est une image + images.append({ + "image_data": metadata.get("image_base64", ""), + "description": doc.page_content, + "caption": metadata.get("caption", ""), + "source": metadata.get("source", ""), + "page": metadata.get("page_number", "") + }) + elif "table_content" in metadata: + # C'est un tableau + tables.append({ + "table_data": metadata.get("table_content", ""), + "description": doc.page_content, + "caption": metadata.get("caption", ""), + "source": metadata.get("source", ""), + "page": metadata.get("page_number", "") + }) + else: + # C'est du texte + texts.append({ + "content": doc.page_content, + "source": metadata.get("source", ""), + "page": metadata.get("page_number", "") + }) + + return texts, images, tables + + def clear_history(self): + """ + Efface l'historique de conversation + """ + self.chat_history = [] + + def display_image(self, image_data: str, caption: str = ""): + """ + Affiche une image à partir de sa représentation base64 + """ + try: + # Décodage de l'image base64 + image_bytes = base64.b64decode(image_data) + image = Image.open(BytesIO(image_bytes)) + + # Affichage selon l'environnement + try: + from IPython.display import display + print(f"Caption: {caption}") + display(image) + except ImportError: + image.show() + + return True + except Exception as e: + print(f"Erreur lors de l'affichage de l'image: {e}") + return False + + def format_table(self, table_data: str) -> str: + """ + Formate les données d'un tableau pour l'affichage + """ + try: + # Si format markdown + if isinstance(table_data, str) and table_data.strip().startswith("|"): + return table_data + + # Essayer de parser comme JSON + import json + try: + data = json.loads(table_data) + df = pd.DataFrame(data) + return df.to_string(index=False) + except: + # Si échec, retourner les données brutes + return str(table_data) + except Exception as e: + return f"Erreur lors du formatage du tableau: {e}\n{table_data}" \ No newline at end of file diff --git a/requirement.txt b/requirement.txt new file mode 100644 index 0000000..3622111 --- /dev/null +++ b/requirement.txt @@ -0,0 +1,45 @@ +# Core LangChain packages +langchain>=0.1.0 +langchain-community>=0.0.1 +langchain-ollama>=0.0.1 +langchain-qdrant>=0.0.1 + +# Vector database +qdrant-client>=1.6.0 + +# LLM interface +ollama>=0.1.0 + +# Document processing with specific versions +pytesseract>=0.3.10 +unstructured==0.10.30 +pdfminer.six==20221105 +pdf2image>=1.16.0 +pypdf>=3.15.0 + +# OCR and image processing +pillow_heif>=0.13.0 +Pillow>=10.0.0 + +# Data processing and visualization +pandas>=2.0.0 + +# UI and interface +gradio>=4.0.0 + +# Other utilities +ipython>=8.0.0 +uuid>=1.30 + +onnx +pdf2image +pdfminer.six +pikepdf +pi_heif +pypdf +google-cloud-vision +effdet +# Do not move to constraints.in, otherwise unstructured-inference will not be upgraded +# when unstructured library is. +unstructured-inference>=0.8.7 +unstructured.pytesseract>=0.3.12 \ No newline at end of file