Update chatbot configuration and enhance PDF processing documentation

This commit is contained in:
sepehr 2025-03-07 23:28:06 +01:00
parent 229ba53246
commit e9a273d844
6 changed files with 606 additions and 135 deletions

View File

@ -44,10 +44,44 @@ 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.
The repository includes two methods for processing PDF documents as knowledge sources:
### PDF Processing Class
A highly configurable `PdfProcessor` class is available for extracting text, images, and tables from PDF documents and storing them in a Qdrant vector database.
Key features:
- Support for both Ollama and OpenAI models
- Configurable embedding, text summarization, and image analysis models
- Automatic text chunking based on document structure
- Image and table extraction with descriptions
- Customizable Qdrant collection configuration
Example usage:
```python
from pdf_processor import PdfProcessor
# Basic usage with default settings
processor = PdfProcessor()
result = processor.process_pdf("path/to/document.pdf")
# Custom configuration
config = {
"embedding_provider": "openai",
"image_provider": "openai",
"collection_name": "my_documents",
"openai_api_key": "your-api-key",
"summary_language": "French"
}
processor = PdfProcessor(config)
processor.process_pdf("path/to/document.pdf")
```
### Jupyter Notebook
For interactive PDF processing, you can also use the Jupyter notebook [`final_pdf.ipynb`](final_pdf.ipynb).
## 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
- [`pdf_processor.py`](pdf_processor.py): PDF processing and vectorization
- [`final_pdf.ipynb`](final_pdf.ipynb): Jupyter notebook for PDF processing

BIN
T4 Machines thermiques.pdf Normal file

Binary file not shown.

Binary file not shown.

View File

@ -2,25 +2,9 @@
"cells": [
{
"cell_type": "code",
"execution_count": 2,
"execution_count": 3,
"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'"
]
}
],
"outputs": [],
"source": [
"import pytesseract\n",
"from langchain.document_loaders import UnstructuredPDFLoader\n",
@ -28,7 +12,7 @@
"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",
"# 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",
@ -51,7 +35,7 @@
},
{
"cell_type": "code",
"execution_count": 41,
"execution_count": 4,
"metadata": {},
"outputs": [
{
@ -95,7 +79,7 @@
},
{
"cell_type": "code",
"execution_count": 42,
"execution_count": 5,
"metadata": {},
"outputs": [],
"source": [
@ -128,7 +112,7 @@
},
{
"cell_type": "code",
"execution_count": 135,
"execution_count": 6,
"metadata": {},
"outputs": [],
"source": [
@ -137,7 +121,7 @@
},
{
"cell_type": "code",
"execution_count": 136,
"execution_count": 7,
"metadata": {},
"outputs": [],
"source": [
@ -159,7 +143,7 @@
},
{
"cell_type": "code",
"execution_count": 137,
"execution_count": 8,
"metadata": {},
"outputs": [
{
@ -228,7 +212,7 @@
},
{
"cell_type": "code",
"execution_count": 139,
"execution_count": 9,
"metadata": {},
"outputs": [],
"source": [
@ -354,7 +338,35 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 11,
"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()\n"
]
},
{
"cell_type": "code",
"execution_count": 12,
"metadata": {},
"outputs": [],
"source": [
@ -441,46 +453,45 @@
},
{
"cell_type": "code",
"execution_count": 155,
"execution_count": 17,
"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.\"]"
"import os\n",
"os.environ[\"OPENAI_API_KEY\"] = \"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\"\n",
"from langchain_openai import ChatOpenAI\n",
"\n",
"prompt_template = \"\"\"Describe the image in detail. For context,\n",
" the image is part of a research paper explaining the transformers\n",
" architecture. Be specific about graphs, such as bar plots.\"\"\"\n",
"messages = [\n",
" (\n",
" \"user\",\n",
" [\n",
" {\"type\": \"text\", \"text\": prompt_template},\n",
" {\n",
" \"type\": \"image_url\",\n",
" \"image_url\": {\"url\": \"data:image/jpeg;base64,{image_base64}\"},\n",
" },\n",
" ],\n",
" )\n",
"]\n",
"\n",
"prompt = ChatPromptTemplate.from_messages(messages)\n",
"\n",
"chain = prompt | ChatOpenAI(model=\"gpt-4o-mini\") | StrOutputParser()\n",
"\n",
"\n",
"image_summaries = chain.batch(images_with_caption)"
]
},
{
"cell_type": "code",
"execution_count": 158,
"execution_count": 22,
"metadata": {},
"outputs": [],
"source": [
"llm = OllamaLLM(base_url=\"http://localhost:11434\", model=\"llama3.1\")\n",
"llm = OllamaLLM(base_url=\"http://localhost:11434\", model=\"llama3.2\")\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",
@ -502,7 +513,7 @@
},
{
"cell_type": "code",
"execution_count": null,
"execution_count": 23,
"metadata": {},
"outputs": [
{
@ -533,10 +544,11 @@
},
{
"cell_type": "code",
"execution_count": 193,
"execution_count": 24,
"metadata": {},
"outputs": [],
"source": [
"import uuid\n",
"# Fonction pour convertir vos dictionnaires en objets Document de LangChain\n",
"def convert_to_langchain_documents_table(text_info,summary):\n",
" documents = []\n",
@ -564,7 +576,7 @@
},
{
"cell_type": "code",
"execution_count": 194,
"execution_count": 27,
"metadata": {},
"outputs": [],
"source": [
@ -595,68 +607,13 @@
},
{
"cell_type": "code",
"execution_count": 214,
"execution_count": null,
"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"
]
},
@ -664,23 +621,12 @@
"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"
}
],
"outputs": [],
"source": []
},
{
"cell_type": "code",
"execution_count": 217,
"execution_count": 29,
"metadata": {},
"outputs": [],
"source": [
@ -689,7 +635,7 @@
},
{
"cell_type": "code",
"execution_count": 218,
"execution_count": 30,
"metadata": {},
"outputs": [],
"source": [
@ -705,7 +651,7 @@
" final_chunks,\n",
" embedding,\n",
" url='http://localhost:6333',\n",
" collection_name=\"my_documents\",\n",
" collection_name=\"essai\",\n",
")"
]
},
@ -2287,7 +2233,7 @@
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.13.2"
"version": "3.11.11"
}
},
"nbformat": 4,

View File

@ -36,13 +36,13 @@ def base64_to_image(base64_data):
# Configuration pour initialiser le chatbot
qdrant_url = "http://localhost:6333"
qdrant_collection_name = "my_documents"
qdrant_collection_name = "my_custom_collection"
embedding_model = "mxbai-embed-large"
ollama_url = "http://127.0.0.1:11434"
default_model = "llama3.1"
default_model = "llama3.2"
# Liste des modèles disponibles
AVAILABLE_MODELS = ["llama3.1", "llama3.2", "deepseek-r1:14b"]
AVAILABLE_MODELS = ["llama3.1", "llama3.2","deepseek-r1:7b", "deepseek-r1:14b"]
# Initialiser le chatbot RAG avec le modèle par défaut
rag_bot = MultimodalRAGChatbot(

491
pdfProcessing.py Normal file
View File

@ -0,0 +1,491 @@
import os
import uuid
import pytesseract
from typing import Dict, List, Any, Optional, Union
from langchain_community.document_loaders import UnstructuredPDFLoader
from langchain.schema import Document
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.output_parsers import StrOutputParser
class PdfProcessor:
"""
A configurable PDF processor that extracts text, images, and tables from PDFs,
summarizes them using LLMs, and stores them in a Qdrant vector database.
"""
def __init__(self, config: Optional[Dict[str, Any]] = None):
"""
Initialize the PDF processor with the given configuration.
Args:
config: Dictionary of configuration options
"""
# Default configuration
self.config = {
# Embeddings
"embedding_provider": "ollama", # "ollama" or "openai"
"ollama_embedding_url": "http://localhost:11434",
"ollama_embedding_model": "mxbai-embed-large",
"openai_embedding_model": "text-embedding-3-small",
# LLM for text/table summarization
"summary_provider": "ollama", # "ollama" or "openai"
"ollama_summary_url": "http://localhost:11434",
"ollama_summary_model": "llama3.2",
"openai_summary_model": "gpt-3.5-turbo",
# Image processing
"image_provider": "ollama", # "ollama" or "openai"
"ollama_image_url": "http://localhost:11434",
"ollama_image_model": "llama3.2-vision",
"openai_image_model": "gpt-4o-mini",
# Vector store
"qdrant_url": "http://localhost:6333",
"collection_name": "pdf_documents",
# PDF processing
"extract_images": True,
"extract_tables": True,
"chunk_size": 10000,
"chunk_overlap": 2000,
"tesseract_path": r'C:\Program Files\Tesseract-OCR\tesseract.exe',
"image_output_dir": "./temp_images",
"summary_language": "English",
# API keys
"openai_api_key": None,
}
# Update with user-provided configuration
if config:
self.config.update(config)
# Set up components
self._setup_components()
self._setup_models()
def _setup_components(self):
"""Set up necessary components based on configuration."""
# Set up Tesseract for OCR
if self.config["tesseract_path"]:
pytesseract.pytesseract.tesseract_cmd = self.config["tesseract_path"]
# Set up OpenAI key if using OpenAI services
if (self.config["embedding_provider"] == "openai" or
self.config["summary_provider"] == "openai" or
self.config["image_provider"] == "openai"):
if not self.config["openai_api_key"]:
raise ValueError("OpenAI API key is required when using OpenAI models")
os.environ["OPENAI_API_KEY"] = self.config["openai_api_key"]
def _setup_models(self):
"""Initialize models based on configuration."""
# Set up embedding model
if self.config["embedding_provider"] == "ollama":
from langchain_ollama import OllamaEmbeddings
self.embedding_model = OllamaEmbeddings(
base_url=self.config["ollama_embedding_url"],
model=self.config["ollama_embedding_model"]
)
else: # openai
from langchain_openai import OpenAIEmbeddings
self.embedding_model = OpenAIEmbeddings(
model=self.config["openai_embedding_model"]
)
# Set up text summarization model
if self.config["summary_provider"] == "ollama":
from langchain_ollama import OllamaLLM
self.summary_model = OllamaLLM(
base_url=self.config["ollama_summary_url"],
model=self.config["ollama_summary_model"]
)
else: # openai
from langchain_openai import ChatOpenAI
self.summary_model = ChatOpenAI(
model=self.config["openai_summary_model"]
)
# Create summarization chain
prompt_text = """
You are an assistant tasked with summarizing tables and text.
Give a concise summary of the table or text.
Respond only with the summary, no additional comment.
Do not start your message by saying "Here is a summary" or anything like that.
Just give the summary as it is. All summaries will be in {language}
Text or table to summarize: {element}
"""
self.summarize_prompt = ChatPromptTemplate.from_template(prompt_text)
self.summarize_chain = {"element": lambda x: x, "language": lambda _: self.config["summary_language"]} | self.summarize_prompt | self.summary_model | StrOutputParser()
def process_pdf(self, pdf_path: str) -> Dict[str, Any]:
"""
Process a PDF file and store its contents in Qdrant.
Args:
pdf_path: Path to the PDF file
Returns:
Dictionary with processing statistics
"""
# Load and extract content from PDF
print("Loading PDF and extracting elements...")
documents = self._load_pdf(pdf_path)
# Process text chunks
print("Processing text chunks...")
title_chunks = self._process_text(documents)
text_summaries = self._summarize_text(title_chunks)
processed_text = self._convert_text_to_documents(title_chunks, text_summaries)
# Process images if configured
print("Processing images...")
processed_images = []
if self.config["extract_images"]:
images = self._extract_images(documents)
image_summaries = self._process_images(images)
processed_images = self._convert_images_to_documents(images, image_summaries)
# Process tables if configured
print("Processing tables...")
processed_tables = []
if self.config["extract_tables"]:
tables = self._extract_tables(documents)
table_summaries = self._process_tables(tables)
processed_tables = self._convert_tables_to_documents(tables, table_summaries)
print("Storing processed elements in Qdrant...")
# Combine all processed elements
final_documents = processed_text + processed_images + processed_tables
# Store in Qdrant
self._store_documents(final_documents)
return {
"text_chunks": len(processed_text),
"image_chunks": len(processed_images),
"table_chunks": len(processed_tables),
"total_chunks": len(final_documents),
"collection_name": self.config["collection_name"]
}
def _load_pdf(self, pdf_path: str) -> List[Document]:
"""Load PDF and extract elements."""
loader = UnstructuredPDFLoader(
pdf_path,
infer_table_structure=True,
extract_images=self.config["extract_images"],
image_output_dir=self.config["image_output_dir"],
mode="elements",
strategy="hi_res",
extract_image_block_types=["Image"],
extract_image_block_to_payload=True,
)
return loader.load()
def _process_text(self, documents: List[Document]) -> List[Document]:
"""Process text and create title-based chunks."""
return self._chunk_by_title(
documents,
max_chunk_size=self.config["chunk_size"],
chunk_overlap=self.config["chunk_overlap"]
)
def _summarize_text(self, chunks: List[Document]) -> List[str]:
"""Generate summaries for text chunks."""
return self.summarize_chain.batch([chunk.page_content for chunk in chunks], {"max_concurrency": 3})
def _extract_images(self, documents: List[Document]) -> List[Dict[str, Any]]:
"""Extract images with captions from documents."""
images_info = []
for i, chunk in enumerate(documents):
if chunk.metadata.get("category") == "Image":
image_b64 = chunk.metadata.get('image_base64')
caption = ""
# Look for caption in next chunk
if i < len(documents) - 1:
next_chunk = documents[i+1]
if next_chunk.metadata.get("category") == "FigureCaption":
caption = next_chunk.page_content.strip()
images_info.append({
"image_base64": image_b64,
"caption": caption,
"source": os.path.basename(chunk.metadata.get("source", "")),
"page": chunk.metadata.get("page_number", ""),
})
return images_info
def _process_images(self, images: List[Dict[str, Any]]) -> List[str]:
"""Generate descriptions for images using configured model."""
if self.config["image_provider"] == "ollama":
from ollama import Client
client = Client(host=self.config["ollama_image_url"])
image_summaries = []
for img in images:
prompt = f"Caption of image: {img.get('caption', '')}. Describe this image in detail in {self.config['summary_language']}."
response = client.chat(
model=self.config["ollama_image_model"],
messages=[
{"role": "user", "content": prompt, "images": [img.get("image_base64")]}
]
)
image_summaries.append(response["message"]["content"])
return image_summaries
else: # openai
from langchain_openai import ChatOpenAI
prompt_template = f"""Describe the image in detail in {self.config['summary_language']}.
If there's a caption, use it for context: {{caption}}"""
messages = [
(
"user",
[
{"type": "text", "text": prompt_template},
{
"type": "image_url",
"image_url": {"url": "data:image/jpeg;base64,{image_base64}"},
},
],
)
]
prompt = ChatPromptTemplate.from_messages(messages)
chain = prompt | ChatOpenAI(model=self.config["openai_image_model"]) | StrOutputParser()
return chain.batch([{"image_base64": img["image_base64"], "caption": img.get("caption", "")} for img in images])
def _extract_tables(self, documents: List[Document]) -> List[Dict[str, Any]]:
"""Extract tables with captions from documents."""
tables_info = []
for idx, chunk in enumerate(documents):
if chunk.metadata.get("category") == "Table" or "table" in chunk.metadata.get("category", "").lower():
# Extract table content and caption
payload = chunk.metadata.get("payload", {})
caption = payload.get("caption", "").strip()
# Look for caption in next chunk
if not caption and idx + 1 < len(documents):
next_chunk = documents[idx + 1]
if next_chunk.metadata.get("category") == "FigureCaption":
caption = next_chunk.page_content.strip()
tables_info.append({
"table_data": chunk.page_content,
"caption": caption,
"source": os.path.basename(chunk.metadata.get("source", "")),
"page": chunk.metadata.get("page_number", ""),
})
return tables_info
def _process_tables(self, tables: List[Dict[str, Any]]) -> List[str]:
"""Generate summaries for tables."""
table_summaries = []
for table in tables:
prompt = f"""Caption of table: {table.get('caption', '')}.
Describe this table in detail in {self.config['summary_language']}.
Table content: {table.get('table_data', '')}"""
if self.config["summary_provider"] == "ollama":
summary = self.summary_model.invoke(prompt)
else: # openai
summary = self.summary_model.invoke(prompt).content
table_summaries.append(summary)
return table_summaries
def _convert_text_to_documents(self, texts: List[Document], summaries: List[str]) -> List[Document]:
"""Convert text chunks and summaries into Document objects."""
documents = []
txt_ids = [str(uuid.uuid4()) for _ in texts]
for idx, item in enumerate(texts):
if idx < len(summaries):
summary_text = summaries[idx]
else:
summary_text = ""
metadata = {
"source": item.metadata.get("source", ""),
"page_number": item.metadata.get("page_numbers", []),
"text": item.page_content,
"id_key": txt_ids[idx],
"txt": item.metadata.get("title", "")
}
doc = Document(page_content=summary_text, metadata=metadata)
documents.append(doc)
return documents
def _convert_images_to_documents(self, images: List[Dict[str, Any]], summaries: List[str]) -> List[Document]:
"""Convert image data and summaries into Document objects."""
documents = []
img_ids = [str(uuid.uuid4()) for _ in images]
for idx, item in enumerate(images):
if idx < len(summaries):
summary_text = summaries[idx]
else:
summary_text = ""
metadata = {
"source": item.get("source", ""),
"page_number": item.get("page", ""),
"caption": item.get("caption", ""),
"id_key": img_ids[idx],
"image_base64": item.get("image_base64")
}
doc = Document(page_content=summary_text, metadata=metadata)
documents.append(doc)
return documents
def _convert_tables_to_documents(self, tables: List[Dict[str, Any]], summaries: List[str]) -> List[Document]:
"""Convert table data and summaries into Document objects."""
documents = []
table_ids = [str(uuid.uuid4()) for _ in tables]
for idx, item in enumerate(tables):
if idx < len(summaries):
summary_text = summaries[idx]
else:
summary_text = ""
metadata = {
"source": item.get("source", ""),
"page_number": item.get("page", ""),
"caption": item.get("caption", ""),
"id_key": table_ids[idx],
"table_content": item.get("table_data")
}
doc = Document(page_content=summary_text, metadata=metadata)
documents.append(doc)
return documents
def _store_documents(self, documents: List[Document]) -> None:
"""Store documents in Qdrant vector database."""
from langchain_qdrant import QdrantVectorStore
qdrant = QdrantVectorStore.from_documents(
documents,
self.embedding_model,
url=self.config["qdrant_url"],
collection_name=self.config["collection_name"],
)
def _chunk_by_title(self, documents: List[Document], max_chunk_size: int = 10000,
chunk_overlap: int = 2000) -> List[Document]:
"""
Create chunks based on document title structure.
Each title starts a new chunk.
"""
# Identify title positions
title_positions = []
for i, doc in enumerate(documents):
if doc.metadata.get("category") == "Title":
title_positions.append(i)
# Add final position
title_positions.append(len(documents))
# Create chunks based on titles
title_based_chunks = []
# If no titles found, process as single chunk
if len(title_positions) <= 1:
text_elements = [doc for doc in documents
if doc.metadata.get("category") not in ["Table", "Image", "FigureCaption"]]
combined_text = " ".join([doc.page_content for doc in text_elements])
title_based_chunks.append(Document(
page_content=combined_text,
metadata={
"source": os.path.basename(documents[0].metadata.get("source", "")),
"title": "Document without title",
"page_numbers": list(set(doc.metadata.get("page_number")
for doc in text_elements if doc.metadata.get("page_number")))
}
))
else:
# Process each title-delimited section
for i in range(len(title_positions) - 1):
start_idx = title_positions[i]
end_idx = title_positions[i + 1]
# Get section title
title_doc = documents[start_idx]
title_text = title_doc.page_content
# Get section text elements
section_docs = [
doc for doc in documents[start_idx+1:end_idx]
if doc.metadata.get("category") not in ["Table", "Image", "FigureCaption"]
]
if section_docs:
# Combine section text
section_text = " ".join([doc.page_content for doc in section_docs])
# Get page numbers
page_numbers = list(set(
doc.metadata.get("page_number") for doc in section_docs
if doc.metadata.get("page_number")
))
source = os.path.basename(section_docs[0].metadata.get("source", ""))
# Create Document for section
title_based_chunks.append(Document(
page_content=section_text,
metadata={
"source": source,
"title": title_text,
"page_numbers": page_numbers
}
))
# Further chunk if sections are too large
final_chunks = []
text_splitter = RecursiveCharacterTextSplitter(
chunk_size=max_chunk_size,
chunk_overlap=chunk_overlap
)
for chunk in title_based_chunks:
if len(chunk.page_content) <= max_chunk_size:
final_chunks.append(chunk)
else:
# Split large sections
sub_chunks = text_splitter.split_documents([chunk])
# Preserve title info in sub-chunks
for i, sub_chunk in enumerate(sub_chunks):
sub_chunk.metadata["title"] = chunk.metadata["title"]
sub_chunk.metadata["sub_chunk"] = i + 1
sub_chunk.metadata["total_sub_chunks"] = len(sub_chunks)
final_chunks.extend(sub_chunks)
return final_chunks
processor = PdfProcessor({
"image_provider": "openai",
"openai_api_key": "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",
"collection_name": "my_custom_collection",
"summary_language": "English"
})
result = processor.process_pdf(r"F:\Dev\Rag\chat_bot_rag\T4 Machines thermiques.pdf")