diff --git a/M2/Natural Language Process/TP5 RAG.ipynb b/M2/Natural Language Process/TP5 RAG.ipynb index 6efff60..efcd054 100644 --- a/M2/Natural Language Process/TP5 RAG.ipynb +++ b/M2/Natural Language Process/TP5 RAG.ipynb @@ -1,14 +1,5 @@ { "cells": [ - { - "cell_type": "code", - "execution_count": null, - "metadata": {}, - "outputs": [], - "source": [ - "%pip install langchain-core langchain-mistralai langchain-qdrant qdrant-client python-dotenv gradio\n" - ] - }, { "cell_type": "markdown", "metadata": {}, @@ -123,18 +114,27 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 9, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Loaded 952 FAQ entries!\n", + "\n" + ] + } + ], "source": [ "# Load the FAQ data\n", - "from pathlib import Path\n", "import json\n", + "from pathlib import Path\n", "\n", "# Get the notebook's directory\n", "notebook_dir = Path.cwd()\n", - "data_path = \"paris-2024-faq.json\"\n", - "with open(data_path, \"r\") as f:\n", + "data_path = notebook_dir / \"data\" / \"paris-2024-faq.json\"\n", + "with Path(data_path).open() as f:\n", " faq_data = json.load(f)\n", "\n", "print(f\"✅ Loaded {len(faq_data)} FAQ entries!\\n\")\n" @@ -142,9 +142,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 10, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'id': '-Bgz0H-g-fr',\n", + " 'lang': 'fr',\n", + " 'label': 'Existe-t-il des places spécifiques pour les personnes avec un handicap mental/neurologique/psychique ?',\n", + " 'body': \"Les personnes avec un handicap mental, neurologique ou psychologique peuvent bénéficier des places réservées pour les personnes en situation de handicap qui sont faciles d'accès sur présentation d'une carte d'invalidité ou d'un équivalent.\\n\\nTous les volontaires seront sensibilisés au handicap mental, neurologique et psychique afin de garantir la meilleure expérience et le meilleur accueil possible.\",\n", + " 'topics': 'Spectateurs ;Accessibilité;Accès / services sur site',\n", + " 'url': 'https://help.paris2024.org/contents/Existe-t-il-des-places-specifiques-pour-les-personnes-avec-un-handicap-mental-neurologique-psychique--Bgz0H-g'}" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Display first entry\n", "faq_data[0]\n" @@ -152,7 +168,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 11, "metadata": {}, "outputs": [], "source": [ @@ -162,9 +178,36 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 12, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "📋 Sample FAQ Entries:\n", + "\n", + "1. Q: How often will the toilets at the competition venues be cleaned?\n", + " A: The toilets will be cleaned regularly during each session....\n", + "\n", + "2. Q: How do you apply to carry the Flame?\n", + " A: The public campaigns for torchbearers have all concluded.\n", + "\n", + "\n", + "\n", + "For more information, please visit:\n", + "\n", + "ht...\n", + "\n", + "3. Q: Combien y a-t-il de volontaires ?\n", + " A: The deadline for applying to the Paris 2024 volunteering programme has already passed.\n", + "\n", + "However, the...\n", + "\n", + "💡 Total entries: 478\n" + ] + } + ], "source": [ "# Display sample entries\n", "print(\"📋 Sample FAQ Entries:\\n\")\n", @@ -195,9 +238,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 13, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "page_content='Hello, world!' metadata={'source': 'https://example.com'}\n" + ] + } + ], "source": [ "from langchain_core.documents import Document\n", "\n", @@ -217,18 +268,40 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 14, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "'Hello, world!'" + ] + }, + "execution_count": 14, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "document.page_content\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 15, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "{'source': 'https://example.com'}" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "document.metadata\n" ] @@ -249,9 +322,30 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 16, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🔄 Creating LangChain Document objects...\n", + "\n", + "✅ Created 478 Document objects!\n", + "\n", + "📄 Example Document Structure:\n", + "\n", + "Content (first 200 chars):\n", + "Question: How often will the toilets at the competition venues be cleaned?\n", + "Answer: The toilets will be cleaned regularly during each session....\n", + "\n", + "Metadata:\n", + "{'source': 'Olympics FAQ', 'faq_id': 'OnlBYpRa-en', 'question': 'How often will the toilets at the competition venues be cleaned?', 'answer': 'The toilets will be cleaned regularly during each session.', 'topics': 'Other;Environmental commitments;Waste management', 'url': 'https://help.paris2024.org/en-gb/contents/How-often-will-the-toilets-at-the-competition-venues-be-cleaned-OnlBYpRa'}\n", + "\n", + "💡 These documents are now ready for embedding!\n" + ] + } + ], "source": [ "print(\"🔄 Creating LangChain Document objects...\\n\")\n", "\n", @@ -330,9 +424,17 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 17, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Warning: You are sending unauthenticated requests to the HF Hub. Please set a HF_TOKEN to enable higher rate limits and faster downloads.\n" + ] + } + ], "source": [ "import os\n", "\n", @@ -349,7 +451,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 18, "metadata": {}, "outputs": [], "source": [ @@ -357,7 +459,6 @@ "from qdrant_client import QdrantClient\n", "from qdrant_client.http.models import Distance, VectorParams\n", "\n", - "\n", "# client = QdrantClient(path=local_output)\n", "# In memory client:\n", "COLLECTION_NAME = \"olympics-2024\"\n", @@ -382,9 +483,22 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 19, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "\n", + "============================================================\n", + "💡 What just happened:\n", + " 1. Each document was converted to a 1024D vector\n", + " 2. Vectors were indexed in Qdrant for fast search\n", + " 3. Now we can find similar documents!\n" + ] + } + ], "source": [ "from uuid import uuid4\n", "\n", @@ -420,9 +534,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 20, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🔍 Testing the Retrieval System\n", + "\n", + "============================================================\n", + "❓ User Query: 'How do I get disabled parking spaces?'\n", + "\n" + ] + } + ], "source": [ "print(\"🔍 Testing the Retrieval System\\n\")\n", "print(\"=\" * 60)\n", @@ -435,13 +561,61 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 21, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ Found 3 relevant documents!\n", + "\n", + "📄 Retrieved Documents:\n", + "\n", + "============================================================\n", + "Document 1:\n", + "============================================================\n", + "Content:\n", + "Question: Are parking spaces reserved for individuals with disabilities available on-site?\n", + "Answer: Each site will have a limited number of parking spaces reserved for wheelchair users.\n", + "\n", + "Holders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\n", + "\n", + "\n", + "\n", + "For countries not issuing either of these two cards, any other official document justifying a disability will be accepted.\n", + "\n", + "============================================================\n", + "Document 2:\n", + "============================================================\n", + "Content:\n", + "Question: What documentary evidence do visitors with disabilities from abroad need?\n", + "Answer: Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\n", + "\n", + "This documentation can be a European parking card or a mobility inclusion card.\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n", + "\n", + "\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n", + "\n", + "============================================================\n", + "Document 3:\n", + "============================================================\n", + "Content:\n", + "Question: Are there any specific spaces for individuals with mental/neurological/psychological disabilities?\n", + "Answer: Individuals with mental, neurological, or psychological disabilities can access reserved spots for people with disabilities that are easily accessible upon presentation of a disability card or equivalent.\n", + "\n", + "All volunteers will receive training on mental, neurological, and psychological disabilities to ensure the best possible experience and welcome.\n", + "\n" + ] + } + ], "source": [ "# Retrieve top 3 most relevant documents\n", "retrieved_docs = vector_store.similarity_search(\n", - " query=test_query, k=3 # Return top 3 matches\n", + " query=test_query, k=3, # Return top 3 matches\n", ")\n", "\n", "print(f\"✅ Found {len(retrieved_docs)} relevant documents!\\n\")\n", @@ -456,14 +630,34 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 27, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[(Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'OnlmLzuE-en', 'question': 'Are parking spaces reserved for individuals with disabilities available on-site?', 'answer': 'Each site will have a limited number of parking spaces reserved for wheelchair users.\\n\\nHolders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\\n\\n\\n\\nFor countries not issuing either of these two cards, any other official document justifying a disability will be accepted.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/Are-parking-spaces-reserved-for-individuals-with-disabilities-available-on-site-OnlmLzuE', '_id': 'be6db04a-2902-4ccd-bc29-d2f0d010fff4', '_collection_name': 'olympics-2024'}, page_content='Question: Are parking spaces reserved for individuals with disabilities available on-site?\\nAnswer: Each site will have a limited number of parking spaces reserved for wheelchair users.\\n\\nHolders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\\n\\n\\n\\nFor countries not issuing either of these two cards, any other official document justifying a disability will be accepted.'),\n", + " 0.8989433697194552),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'OnllTAmy-en', 'question': 'What documentary evidence do visitors with disabilities from abroad need?', 'answer': 'Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\\n\\nThis documentation can be a European parking card or a mobility inclusion card.\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\\n\\n\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/What-documentary-evidence-do-visitors-with-disabilities-from-abroad-need-OnllTAmy', '_id': 'af36d08e-9cc3-49d2-81e3-d0e15a6825f9', '_collection_name': 'olympics-2024'}, page_content='Question: What documentary evidence do visitors with disabilities from abroad need?\\nAnswer: Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\\n\\nThis documentation can be a European parking card or a mobility inclusion card.\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\\n\\n\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.'),\n", + " 0.8880006763829658),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': '-Bgz0H-g-en', 'question': 'Are there any specific spaces for individuals with mental/neurological/psychological disabilities?', 'answer': 'Individuals with mental, neurological, or psychological disabilities can access reserved spots for people with disabilities that are easily accessible upon presentation of a disability card or equivalent.\\n\\nAll volunteers will receive training on mental, neurological, and psychological disabilities to ensure the best possible experience and welcome.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/Are-there-any-specific-spaces-for-individuals-with-mental-neurological-psychological-disabilities--Bgz0H-g', '_id': 'd0248842-155d-4875-a1a2-baaac8e30a27', '_collection_name': 'olympics-2024'}, page_content='Question: Are there any specific spaces for individuals with mental/neurological/psychological disabilities?\\nAnswer: Individuals with mental, neurological, or psychological disabilities can access reserved spots for people with disabilities that are easily accessible upon presentation of a disability card or equivalent.\\n\\nAll volunteers will receive training on mental, neurological, and psychological disabilities to ensure the best possible experience and welcome.'),\n", + " 0.8761557912533754)]" + ] + }, + "execution_count": 27, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# TODO: Try to Enhance retrieval quality\n", "# - Find a way to Retrieve cosine similarity scores [hint: there is a method called \"similarity_search_with_relevance_scores]\n", "# - Experiment with higher k values to return more candidate documents. But remember the more k is high the more\n", - "# - you'll have a big system prompt on the next step (generation)\n" + "# - you'll have a big system prompt on the next step (generation)\n", + "similarity_scores = vector_store.similarity_search_with_relevance_scores(\n", + " query=test_query, k=3, # Return top 3 matches\n", + ")\n", + "similarity_scores\n" ] }, { @@ -481,13 +675,33 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 26, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[(Document(metadata={'source': 'Olympics FAQ', 'faq_id': '3KjcmsfM-en', 'question': 'What are the planned works for the area around the Grand Palais, Pont Alexandre III, and Les Invalides in preparation for the Paris 2024 Olympic and Paralympic Games?', 'answer': 'The schedule for the temporary installations of Paris 2024 in the area of the Grand Palais, Pont Alexandre III, and Les Invalides runs from April to October 2024.\\n\\n\\n\\n * Mid-April: Start of assembly on the southeast lawns of Les Invalides.\\n\\n * From mid-April to mid-June: Progressive expansion of the construction site across all the lawns of Les Invalides and on Avenue du Maréchal Gallieni; closure of Cours la Reine between Pont Alexandre III and Les Invalides from April 26 onwards and occupation of Pont Alexandre III and the nearby lower quays from May 17 onwards.\\n\\n * From September to late October: Gradual release of the Champ-de-Mars.\\n\\n\\n\\nFor more information on the assembly and dismantling of the sites:\\n\\nhttps://www.paris2024.org/fr/Montage-Demontage-Sites/%EF%BF%BC', 'topics': 'Spectators;Competition venues', 'url': 'https://help.paris2024.org/en-gb/contents/What-are-the-planned-works-for-the-area-around-the-Grand-Palais-Pont-Alexandre-III-and-Les-Invalides-in-preparation-for-the-Paris-2024-Olympic-and-Paralympic-Games-3KjcmsfM', '_id': '6c3feb47-3d53-4fcb-b9aa-463367fb5e8c', '_collection_name': 'olympics-2024'}, page_content='Question: What are the planned works for the area around the Grand Palais, Pont Alexandre III, and Les Invalides in preparation for the Paris 2024 Olympic and Paralympic Games?\\nAnswer: The schedule for the temporary installations of Paris 2024 in the area of the Grand Palais, Pont Alexandre III, and Les Invalides runs from April to October 2024.\\n\\n\\n\\n * Mid-April: Start of assembly on the southeast lawns of Les Invalides.\\n\\n * From mid-April to mid-June: Progressive expansion of the construction site across all the lawns of Les Invalides and on Avenue du Maréchal Gallieni; closure of Cours la Reine between Pont Alexandre III and Les Invalides from April 26 onwards and occupation of Pont Alexandre III and the nearby lower quays from May 17 onwards.\\n\\n * From September to late October: Gradual release of the Champ-de-Mars.\\n\\n\\n\\nFor more information on the assembly and dismantling of the sites:\\n\\nhttps://www.paris2024.org/fr/Montage-Demontage-Sites/%EF%BF%BC'),\n", + " 0.8400907480550941),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'v-ZwbOWG-en', 'question': 'What are the objectives of the endowment Fund?', 'answer': 'The Paris 2024 endowment Fund is a platform for social innovation through sports with three main objectives:\\n\\n * Inspire and identify projects with high potential for social innovation through sports\\n\\n * Support project leaders (sports organizations, communities, associations) in the design, implementation, and impact evaluation of these projects\\n\\n * Promote and publicize these projects to encourage their replication', 'topics': 'Other;Impact 2024', 'url': 'https://help.paris2024.org/en-gb/contents/What-are-the-objectives-of-the-endowment-Fund-v-ZwbOWG', '_id': '706433f3-76a8-4252-88a7-26b3c64eeb1f', '_collection_name': 'olympics-2024'}, page_content='Question: What are the objectives of the endowment Fund?\\nAnswer: The Paris 2024 endowment Fund is a platform for social innovation through sports with three main objectives:\\n\\n * Inspire and identify projects with high potential for social innovation through sports\\n\\n * Support project leaders (sports organizations, communities, associations) in the design, implementation, and impact evaluation of these projects\\n\\n * Promote and publicize these projects to encourage their replication'),\n", + " 0.8396205061244493),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'OngwUizS-en', 'question': 'Why create an account on the Génération 2024 platform?', 'answer': 'Once you have created an account on the Génération 2024 platform:\\n\\n\\n\\n * You will receive all the latest news via the quarterly newsletter\\n\\n * You will have exclusive access to educational resources such as Escape Games, films, colouring books, etc.\\n\\n\\n\\nFor more information, please visit:\\n\\nhttps://generation.paris2024.org/', 'topics': 'Education;Platform Generation 2024', 'url': 'https://help.paris2024.org/en-gb/contents/Why-create-an-account-on-the-Generation-2024-platform-OngwUizS', '_id': '9e124dde-3f7d-4419-b18d-b85ede16099c', '_collection_name': 'olympics-2024'}, page_content='Question: Why create an account on the Génération 2024 platform?\\nAnswer: Once you have created an account on the Génération 2024 platform:\\n\\n\\n\\n * You will receive all the latest news via the quarterly newsletter\\n\\n * You will have exclusive access to educational resources such as Escape Games, films, colouring books, etc.\\n\\n\\n\\nFor more information, please visit:\\n\\nhttps://generation.paris2024.org/'),\n", + " 0.8395605827531454)]" + ] + }, + "execution_count": 26, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# TODO: - Implement something to filter low-relevance results\n", "# Use the following query:\n", - "query = \"Why did Napoleon Bonaparte invade Egypt ?\"\n" + "query = \"Why did Napoleon Bonaparte invade Egypt ?\"\n", + "similarity_scores = vector_store.similarity_search_with_relevance_scores(\n", + " query=query, k=3, # Return top 3 matches\n", + ")\n", + "similarity_scores\n" ] }, { @@ -502,13 +716,32 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 29, "metadata": {}, - "outputs": [], + "outputs": [ + { + "data": { + "text/plain": [ + "[(Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'OnlmLzuE-en', 'question': 'Are parking spaces reserved for individuals with disabilities available on-site?', 'answer': 'Each site will have a limited number of parking spaces reserved for wheelchair users.\\n\\nHolders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\\n\\n\\n\\nFor countries not issuing either of these two cards, any other official document justifying a disability will be accepted.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/Are-parking-spaces-reserved-for-individuals-with-disabilities-available-on-site-OnlmLzuE', '_id': 'be6db04a-2902-4ccd-bc29-d2f0d010fff4', '_collection_name': 'olympics-2024'}, page_content='Question: Are parking spaces reserved for individuals with disabilities available on-site?\\nAnswer: Each site will have a limited number of parking spaces reserved for wheelchair users.\\n\\nHolders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\\n\\n\\n\\nFor countries not issuing either of these two cards, any other official document justifying a disability will be accepted.'),\n", + " 0.8989433697194552),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': 'OnllTAmy-en', 'question': 'What documentary evidence do visitors with disabilities from abroad need?', 'answer': 'Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\\n\\nThis documentation can be a European parking card or a mobility inclusion card.\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\\n\\n\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/What-documentary-evidence-do-visitors-with-disabilities-from-abroad-need-OnllTAmy', '_id': 'af36d08e-9cc3-49d2-81e3-d0e15a6825f9', '_collection_name': 'olympics-2024'}, page_content='Question: What documentary evidence do visitors with disabilities from abroad need?\\nAnswer: Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\\n\\nThis documentation can be a European parking card or a mobility inclusion card.\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\\n\\n\\n\\nFor countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.'),\n", + " 0.8880006763829658),\n", + " (Document(metadata={'source': 'Olympics FAQ', 'faq_id': '-Bgz0H-g-en', 'question': 'Are there any specific spaces for individuals with mental/neurological/psychological disabilities?', 'answer': 'Individuals with mental, neurological, or psychological disabilities can access reserved spots for people with disabilities that are easily accessible upon presentation of a disability card or equivalent.\\n\\nAll volunteers will receive training on mental, neurological, and psychological disabilities to ensure the best possible experience and welcome.', 'topics': 'Spectators;Accessibility;On-site access / services', 'url': 'https://help.paris2024.org/en-gb/contents/Are-there-any-specific-spaces-for-individuals-with-mental-neurological-psychological-disabilities--Bgz0H-g', '_id': 'd0248842-155d-4875-a1a2-baaac8e30a27', '_collection_name': 'olympics-2024'}, page_content='Question: Are there any specific spaces for individuals with mental/neurological/psychological disabilities?\\nAnswer: Individuals with mental, neurological, or psychological disabilities can access reserved spots for people with disabilities that are easily accessible upon presentation of a disability card or equivalent.\\n\\nAll volunteers will receive training on mental, neurological, and psychological disabilities to ensure the best possible experience and welcome.'),\n", + " 0.8761557912533754)]" + ] + }, + "execution_count": 29, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "# Retrieve top 3 most relevant documents\n", "test_query = \"How do I get disabled parking spaces?\"\n", - "retrieved_docs =\n" + "retrieved_docs = vector_store.similarity_search_with_relevance_scores(\n", + " query=test_query, k=3, # Return top 3 matches\n", + ")\n", + "retrieved_docs\n" ] }, { @@ -543,19 +776,50 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 32, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🎨 Document Formatting Example:\n", + "\n", + "============================================================\n", + "Document 1:\n", + "Question: Are parking spaces reserved for individuals with disabilities available on-site?\n", + "Answer: Each site will have a limited number of parking spaces reserved for wheelchair users.\n", + "\n", + "Holders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\n", + "\n", + "\n", + "\n", + "For countries not issuing either of these two cards, any other official document justifying a disability will be accepted.\n", + "\n", + "Document 2:\n", + "Question: What documentary evidence do visitors with disabilities from abroad need?\n", + "Answer: Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\n", + "\n", + "This documentation can be a European parking card or a mobility inclusion card.\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n", + "\n", + "\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n" + ] + } + ], "source": [ "def format_docs(docs: list[Document]) -> str:\n", - " \"\"\"\n", - " Format retrieved documents for inclusion in prompt\n", + " \"\"\"Format retrieved documents for inclusion in prompt.\n", "\n", " Args:\n", " docs: List of Document objects\n", "\n", " Returns:\n", " Formatted string with numbered documents\n", + "\n", " \"\"\"\n", " formatted = []\n", "\n", @@ -569,25 +833,59 @@ "print(\"🎨 Document Formatting Example:\\n\")\n", "print(\"=\" * 60)\n", "\n", - "formatted_context = format_docs(retrieved_docs[:2]) # Show first 2\n", + "docs_to_format = [\n", + " item[0] if isinstance(item, tuple) else item for item in retrieved_docs[:2]\n", + "]\n", + "formatted_context = format_docs(docs_to_format) # Show first 2\n", "print(formatted_context)\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 34, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🎨 Document Formatting Example:\n", + "\n", + "============================================================\n", + "Document 1 (Source: https://help.paris2024.org/en-gb/contents/Are-parking-spaces-reserved-for-individuals-with-disabilities-available-on-site-OnlmLzuE):\n", + "Question: Are parking spaces reserved for individuals with disabilities available on-site?\n", + "Answer: Each site will have a limited number of parking spaces reserved for wheelchair users.\n", + "\n", + "Holders of a PFR ticket will be able to access them without reservation and subject to availability, upon presentation of a European parking card, a mobility inclusion card, and a PFR ticket.\n", + "\n", + "\n", + "\n", + "For countries not issuing either of these two cards, any other official document justifying a disability will be accepted.\n", + "\n", + "Document 2 (Source: https://help.paris2024.org/en-gb/contents/What-documentary-evidence-do-visitors-with-disabilities-from-abroad-need-OnllTAmy):\n", + "Question: What documentary evidence do visitors with disabilities from abroad need?\n", + "Answer: Visitors will need to provide documentation to book PFR (wheelchair spaces) or PSH (easy access seating in the stands).\n", + "\n", + "This documentation can be a European parking card or a mobility inclusion card.\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n", + "\n", + "\n", + "\n", + "For countries that do not issue either of these cards, any other official documentation justifying a disability will be accepted.\n" + ] + } + ], "source": [ - "def format_docs_alternative(docs):\n", - " \"\"\"\n", - " Format retrieved documents for inclusion in prompt\n", + "def format_docs_alternative(docs: list[Document]) -> str:\n", + " \"\"\"Format retrieved documents for inclusion in prompt.\n", "\n", " Args:\n", " docs: List of Document objects\n", "\n", " Returns:\n", " Formatted string with numbered documents\n", + "\n", " \"\"\"\n", " formatted = []\n", "\n", @@ -596,6 +894,9 @@ " # Rationale: While questions improve retrieval quality, including both FAQ\n", " # questions and user queries in the prompt may confuse the LLM and increase hallucinations\n", " # - Include source URLs from metadata to enable citation and improve transparency\n", + " for i, doc in enumerate(docs, 1):\n", + " source_url = doc.metadata.get(\"url\", \"No URL\")\n", + " formatted.append(f\"Document {i} (Source: {source_url}):\\n{doc.page_content}\")\n", " return \"\\n\\n\".join(formatted)\n", "\n", "\n", @@ -603,7 +904,10 @@ "print(\"🎨 Document Formatting Example:\\n\")\n", "print(\"=\" * 60)\n", "\n", - "formatted_context = format_docs_alternative(retrieved_docs[:2]) # Show first 2\n", + "docs_to_format = [\n", + " item[0] if isinstance(item, tuple) else item for item in retrieved_docs[:2]\n", + "]\n", + "formatted_context = format_docs_alternative(docs_to_format) # Show first 2\n", "print(formatted_context)\n" ] }, @@ -642,9 +946,19 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 35, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "📝 Creating the RAG Prompt Template\n", + "\n", + "============================================================\n" + ] + } + ], "source": [ "print(\"📝 Creating the RAG Prompt Template\\n\")\n", "print(\"=\" * 60)\n", @@ -691,7 +1005,7 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 36, "metadata": {}, "outputs": [], "source": [ @@ -701,9 +1015,20 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 37, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🤖 Initializing the Language Model\n", + "\n", + "============================================================\n", + "response to hello: Hello! 😊 How can I assist you today? Whether you have a question, need help with something, or just want to chat, I'm here for you!\n" + ] + } + ], "source": [ "print(\"🤖 Initializing the Language Model\\n\")\n", "print(\"=\" * 60)\n", @@ -711,7 +1036,7 @@ "from langchain_mistralai import ChatMistralAI\n", "\n", "llm = ChatMistralAI(\n", - " model=MODEL_NAME, temperature=TEMPERATURE\n", + " model=MODEL_NAME, temperature=TEMPERATURE,\n", ")\n", "\n", "# try an invoke\n", @@ -738,40 +1063,122 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 38, "metadata": {}, "outputs": [], "source": [ - "def make_rag_prompt(question, k=3, score_threshold=0.4):\n", - " \"\"\"\n", - " Create a RAG prompt by retrieving relevant documents\n", + "def make_rag_prompt(question: str, k: int = 3, score_threshold: float = 0.4) -> str:\n", + " \"\"\"Create a RAG prompt by retrieving relevant documents.\n", "\n", " Args:\n", " question: User's question\n", " k: Number of documents to retrieve\n", + " score_threshold: Minimum similarity score for retrieved documents\n", "\n", " Returns:\n", " Formatted prompt string with context and question\n", + "\n", " \"\"\"\n", " # Step 1: Retrieve relevant documents\n", " retrieved_docs = vector_store.similarity_search(\n", - " query=question, k=k, score_threshold=score_threshold\n", + " query=question, k=k, score_threshold=score_threshold,\n", " )\n", "\n", " # Step 2: Format documents\n", " context = format_docs(retrieved_docs)\n", "\n", " # Step 3: Fill in the prompt template\n", - " full_prompt = prompt_template.format(context=context, question=question)\n", - "\n", - " return full_prompt\n" + " return prompt_template.format(context=context, question=question)\n" ] }, { "cell_type": "code", - "execution_count": null, + "execution_count": 39, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "You are a helpful assistant answering questions about the Olympic Games.\n", + "\n", + "Use the following context documents to answer the user's question. If the answer is not in the provided documents, say \"I don't have that information in the provided documents.\"\n", + "\n", + "Context Documents:\n", + "Document 1:\n", + "Question: I am a traveler with a disability, how can I travel by plane?\n", + "Answer: Air France offers specific services to facilitate the travel of people with reduced mobility through the SAPHIR programme (Service dedicated to Assistance for Persons with Handicaps for Information and Reservations).\n", + "\n", + "This free service is available in France as well as in 20 countries worldwide.\n", + "\n", + "To be considered, your request must reach us at least 48 hours before the departure of your first flight.\n", + "\n", + "Air France acknowledges the Sunflower symbol from the \"Hidden disabilities Sunflower®\" programme as an emblem to facilitate the identification and travel experience of its customers with invisible disabilities.\n", + "\n", + "\n", + "\n", + "To learn more, please visit: https://wwws.airfrance.fr/information/passagers/acheter-billet-avion-pmr-autres-handicaps\n", + "\n", + "Document 2:\n", + "Question: I have a disability, can I receive assistance at the train station?\n", + "Answer: People with disabilities and reduced mobility can benefit from free assistance at the departure and/or arrival station, from a reception point to their seat on the train.\n", + "\n", + "This service is called Assist'enGare and is available in over 1,000 stations in France. Assist'enGare can be reached:\n", + "\n", + " * Online via the reservation form 24/7:\n", + " \n", + " https://www.garesetconnexions.sncf/en/assistances-psh-pmr\n", + "\n", + " * By phone every day between 8 a.m. and 8 p.m. at 3212 and at +33 (0)9 72 72 00 92 from abroad (free service + call price).\n", + "\n", + " * Via Rogervoice, our relay center allowing deaf and hard of hearing people to communicate with our Assist'enGare teleadvisors through a translator operator. This service is available Monday to Friday from 8:30 a.m. to 9 p.m. (excluding holidays) in French Sign Language (LSF), French Spoken Complemented (LfPC), and Real-Time Speech Transcription (TTRP), and 24/7 in Text Transcription (TT).\n", + "\n", + "During peak periods, it is advisable to book this service as soon as you purchase your train ticket to ensure assistance. Without a reservation, assistance is provided subject to availability.\n", + "\n", + "Before purchasing the train ticket, it is advisable to check that assistance is available at the desired station and time.\n", + "\n", + "\n", + "\n", + "For more information, please visit:\n", + "\n", + "https://www.paris2024.org/en/practical-information-accessibility/\n", + "\n", + "Document 3:\n", + "Question: How will individuals with disabilities be accommodated at the competition venues?\n", + "Answer: Paris 2024 is committed to ensuring accessibility for people with disabilities at every competition venue by implementing the following measures:\n", + "\n", + " * A drop-off zone near the site entrances for PWD (People With Disabilities).\n", + "\n", + " * A parking area for PFR (People with Reduced Mobility) and a drop-off zone for IDFM shuttles for PFR.\n", + "\n", + " * Dedicated assistance available from the drop-off and parking zone.\n", + "\n", + " * A priority queue for PWD at the site entrances.\n", + "\n", + " * Dedicated reception staff for people with disabilities.\n", + "\n", + " * Mobility assistance within the site, with the option to use a wheelchair to reach the seating area.\n", + "\n", + " * A ticketing offer specifically dedicated to people with disabilities and their companions.\n", + "\n", + " * A dog relief area at each site.\n", + "\n", + "\n", + "\n", + "Find all the services available to PWD and PFR spectators on our dedicated page: https://www.paris2024.org/fr/infos-pratiques-accessibilite/\n", + "\n", + "User Question: what can I do if I'm disabled ?\n", + "\n", + "Instructions:\n", + "1. Answer based ONLY on the provided documents\n", + "2. Be specific and cite which document(s) you used\n", + "3. If information is unclear or missing, say so\n", + "4. Keep answers concise but complete\n", + "5. Use a friendly, informative tone\n", + "Answer:\n" + ] + } + ], "source": [ "question = \"what can I do if I'm disabled ?\"\n", "print(make_rag_prompt(question, k=3, score_threshold=0.4))\n" @@ -779,13 +1186,21 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 41, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "✅ RAG Pipeline Functions Created!\n", + "\n" + ] + } + ], "source": [ - "def rag_assistant(user_question, k=3, verbose=False):\n", - " \"\"\"\n", - " Complete RAG pipeline: question → retrieval → generation\n", + "def rag_assistant(user_question: str, k: int = 3, verbose: bool = False) -> str:\n", + " \"\"\"Complete RAG pipeline: question → retrieval → generation.\n", "\n", " Args:\n", " user_question: The question to answer\n", @@ -794,6 +1209,7 @@ "\n", " Returns:\n", " LLM's answer string\n", + "\n", " \"\"\"\n", " if verbose:\n", " print(\"🔄 RAG Pipeline Steps:\\n\")\n", @@ -805,12 +1221,19 @@ "\n", " if verbose:\n", " print(f\"3️⃣ Prompt created ({len(full_prompt)} characters)\")\n", - " print(f\"4️⃣ Generating answer with LLM...\\n\")\n", + " print(\"4️⃣ Generating answer with LLM...\\n\")\n", "\n", " # Get answer from LLM\n", " response = llm.invoke(full_prompt)\n", + " content = response.content\n", "\n", - " return response.content\n", + " if isinstance(content, str):\n", + " return content\n", + "\n", + " return \"\\n\".join(\n", + " item if isinstance(item, str) else str(item)\n", + " for item in content\n", + " )\n", "\n", "\n", "print(\"✅ RAG Pipeline Functions Created!\\n\")\n" @@ -833,9 +1256,68 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 42, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🎮 Testing the RAG System\n", + "\n", + "======================================================================\n", + "\n", + "❓ Question 1: What can I do if i'm disabled?\n", + "\n", + "🤖 RAG Assistant's Answer:\n", + "\n", + "Here’s what you can do if you’re a person with a disability (PWD) or have reduced mobility (PFR) for the Paris 2024 Olympic and Paralympic Games, based on the provided documents:\n", + "\n", + "### **At Competition Venues (Document 1)**\n", + "You’ll have access to:\n", + "- **Drop-off zones** near entrances for PWD.\n", + "- **Dedicated parking** for PFR and shuttle drop-off zones.\n", + "- **Priority queues** at entrances.\n", + "- **Assistance staff** to help from arrival to seating.\n", + "- **Wheelchair mobility support** within venues.\n", + "- **Special ticketing offers** for PWD and companions.\n", + "- **Dog relief areas** at each site.\n", + "\n", + "🔗 More details: [Paris 2024 Accessibility Page](https://www.paris2024.org/fr/infos-pratiques-accessibilite/)\n", + "\n", + "---\n", + "\n", + "### **Train Travel (Document 2)**\n", + "- **Free assistance** (Assist’enGare) at over 1,000 stations in France, from arrival to your train seat.\n", + "- **Booking options**:\n", + " - Online form (24/7): [SNCF Assistance](https://www.garesetconnexions.sncf/en/assistances-psh-pmr)\n", + " - Phone: 3212 (France) or +33 (0)9 72 72 00 92 (abroad).\n", + " - **For deaf/hard of hearing**: Rogervoice relay service (LSF, LfPC, TTRP, or text).\n", + "- **Book early** during peak periods to guarantee assistance.\n", + "\n", + "🔗 More info: [Paris 2024 Accessibility](https://www.paris2024.org/en/practical-information-accessibility/)\n", + "\n", + "---\n", + "\n", + "### **Air Travel (Document 3)**\n", + "- **Air France’s SAPHIR program** offers free assistance for PWD/PFR.\n", + " - Request at least **48 hours before departure**.\n", + " - Recognizes the **Sunflower symbol** for invisible disabilities.\n", + "🔗 Details: [Air France Accessibility](https://wwws.airfrance.fr/information/passagers/acheter-billet-avion-pmr-autres-handicaps)\n", + "\n", + "---\n", + "\n", + "### **Tickets (Document 5)**\n", + "- **Special seating** for PWD, including wheelchair-accessible spots.\n", + "- Purchase through the [official ticketing site](https://tickets.paris2024.org).\n", + "🔗 FAQ: [Accessible Ticket Categories](https://tickets.paris2024.org/faq/en_en/category/accessibility/what-categories-are-available-for-people-with-disabilities)\n", + "\n", + "---\n", + "\n", + "======================================================================\n" + ] + } + ], "source": [ "print(\"🎮 Testing the RAG System\\n\")\n", "print(\"=\" * 70)\n", @@ -862,16 +1344,46 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 43, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "* Running on local URL: http://127.0.0.1:7860\n", + "* To create a public link, set `share=True` in `launch()`.\n" + ] + }, + { + "data": { + "text/html": [ + "
" + ], + "text/plain": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "text/plain": [] + }, + "execution_count": 43, + "metadata": {}, + "output_type": "execute_result" + } + ], "source": [ "import gradio as gr\n", "\n", "K = 5\n", "\n", "\n", - "def rag_assistant_response(message, history):\n", + "def rag_assistant_response(message: str, _history: list) -> str:\n", + " \"\"\"Gradio response function for RAG assistant.\"\"\"\n", " return rag_assistant(message, k=K, verbose=False)\n", "\n", "\n", @@ -1007,13 +1519,24 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 44, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Query: 'How do I get tickets for the swimming finals?'\n", + "Results: 5 document(s) found\n", + "\n", + "Query: 'Who invented the telephone?'\n", + "⚠️ 5 document(s) returned (lower your threshold?)\n" + ] + } + ], "source": [ "def filtered_retrieval(query: str, k: int = 5, score_threshold: float = 0.6) -> list[Document]:\n", - " \"\"\"\n", - " Retrieve documents only if their similarity score exceeds the threshold.\n", + " \"\"\"Retrieve documents only if their similarity score exceeds the threshold.\n", "\n", " Args:\n", " query: The user question\n", @@ -1022,16 +1545,19 @@ "\n", " Returns:\n", " List of relevant Document objects (empty if nothing passes the threshold)\n", + "\n", " \"\"\"\n", " # TODO: use vector_store.similarity_search_with_relevance_scores()\n", " # to get (Document, score) tuples, then filter by score_threshold\n", "\n", - " results_with_scores = ... # your code here\n", + " results_with_scores = vector_store.similarity_search_with_relevance_scores(\n", + " query=query, k=k,\n", + " )\n", "\n", " # Filter and extract only the documents that pass the threshold\n", - " filtered_docs = ... # your code here\n", - "\n", - " return filtered_docs\n", + " return [\n", + " doc for doc, score in results_with_scores if score >= score_threshold\n", + " ]\n", "\n", "\n", "# Test 1: Relevant query — should return results\n", @@ -1078,31 +1604,135 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 45, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "=== Original format_docs ===\n", + "Document 1:\n", + "Question: I have a disability, can I receive assistance at the train station?\n", + "Answer: People with disabilities and reduced mobility can benefit from free assistance at the departure and/or arrival station, from a reception point to their seat on the train.\n", + "\n", + "This service is called Assist'enGare and is available in over 1,000 stations in France. Assist'enGare can be reached:\n", + "\n", + " * Online via the reservation form 24/7:\n", + " \n", + " https://www.garesetconnexions.sncf/en/assistances-psh-pmr\n", + "\n", + " * By phone every day between 8 a.m. and 8 p.m. at 3212 and at +33 (0)9 72 72 00 92 from abroad (free service + call price).\n", + "\n", + " * Via Rogervoice, our relay center allowing deaf and hard of hearing people to communicate with our Assist'enGare teleadvisors through a translator operator. This service is available Monday to Friday from 8:30 a.m. to 9 p.m. (excluding holidays) in French Sign Language (LSF), French Spoken Complemented (LfPC), and Real-Time Speech Transcription (TTRP), and 24/7 in Text Transcription (TT).\n", + "\n", + "During peak periods, it is advisable to book this service as soon as you purchase your train ticket to ensure assistance. Without a reservation, assistance is provided subject to availability.\n", + "\n", + "Before purchasing the train ticket, it is advisable to check that assistance is available at the desired station and time.\n", + "\n", + "\n", + "\n", + "For more information, please visit:\n", + "\n", + "https://www.paris2024.org/en/practical-information-accessibility/\n", + "\n", + "Document 2:\n", + "Question: How will individuals with disabilities be accommodated at the competition venues?\n", + "Answer: Paris 2024 is committed to ensuring accessibility for people with disabilities at every competition venue by implementing the following measures:\n", + "\n", + " * A drop-off zone near the site entrances for PWD (People With Disabilities).\n", + "\n", + " * A parking area for PFR (People with Reduced Mobility) and a drop-off zone for IDFM shuttles for PFR.\n", + "\n", + " * Dedicated assistance available from the drop-off and parking zone.\n", + "\n", + " * A priority queue for PWD at the site entrances.\n", + "\n", + " * Dedicated reception staff for people with disabilities.\n", + "\n", + " * Mobility assistance within the site, with the option to use a wheelchair to reach the seating area.\n", + "\n", + " * A ticketing offer specifically dedicated to people with disabilities and their companions.\n", + "\n", + " * A dog relief area at each site.\n", + "\n", + "\n", + "\n", + "Find all the services available to PWD and PFR spectators on our dedicated page: https://www.paris2024.org/fr/infos-pratiques-accessibilite/\n", + "\n", + "=== New format_docs_with_citations ===\n", + "Document 1:\n", + "People with disabilities and reduced mobility can benefit from free assistance at the departure and/or arrival station, from a reception point to their seat on the train.\n", + "\n", + "This service is called Assist'enGare and is available in over 1,000 stations in France. Assist'enGare can be reached:\n", + "\n", + " * Online via the reservation form 24/7:\n", + " \n", + " https://www.garesetconnexions.sncf/en/assistances-psh-pmr\n", + "\n", + " * By phone every day between 8 a.m. and 8 p.m. at 3212 and at +33 (0)9 72 72 00 92 from abroad (free service + call price).\n", + "\n", + " * Via Rogervoice, our relay center allowing deaf and hard of hearing people to communicate with our Assist'enGare teleadvisors through a translator operator. This service is available Monday to Friday from 8:30 a.m. to 9 p.m. (excluding holidays) in French Sign Language (LSF), French Spoken Complemented (LfPC), and Real-Time Speech Transcription (TTRP), and 24/7 in Text Transcription (TT).\n", + "\n", + "During peak periods, it is advisable to book this service as soon as you purchase your train ticket to ensure assistance. Without a reservation, assistance is provided subject to availability.\n", + "\n", + "Before purchasing the train ticket, it is advisable to check that assistance is available at the desired station and time.\n", + "\n", + "\n", + "\n", + "For more information, please visit:\n", + "\n", + "https://www.paris2024.org/en/practical-information-accessibility/\n", + "Source: https://help.paris2024.org/en-gb/contents/I-have-a-disability-can-I-receive-assistance-at-the-train-station-8_44nFrI\n", + "\n", + "Document 2:\n", + "Paris 2024 is committed to ensuring accessibility for people with disabilities at every competition venue by implementing the following measures:\n", + "\n", + " * A drop-off zone near the site entrances for PWD (People With Disabilities).\n", + "\n", + " * A parking area for PFR (People with Reduced Mobility) and a drop-off zone for IDFM shuttles for PFR.\n", + "\n", + " * Dedicated assistance available from the drop-off and parking zone.\n", + "\n", + " * A priority queue for PWD at the site entrances.\n", + "\n", + " * Dedicated reception staff for people with disabilities.\n", + "\n", + " * Mobility assistance within the site, with the option to use a wheelchair to reach the seating area.\n", + "\n", + " * A ticketing offer specifically dedicated to people with disabilities and their companions.\n", + "\n", + " * A dog relief area at each site.\n", + "\n", + "\n", + "\n", + "Find all the services available to PWD and PFR spectators on our dedicated page: https://www.paris2024.org/fr/infos-pratiques-accessibilite/\n", + "Source: https://help.paris2024.org/en-gb/contents/How-will-individuals-with-disabilities-be-accommodated-at-the-competition-venues-OnjlYofa\n" + ] + } + ], "source": [ "def format_docs_with_citations(docs: list[Document]) -> str:\n", - " \"\"\"\n", - " Format retrieved documents using answers only + source URLs.\n", + " \"\"\"Format retrieved documents using answers only + source URLs.\n", "\n", " Args:\n", " docs: List of Document objects (each has metadata[\"answer\"] and metadata[\"url\"])\n", "\n", " Returns:\n", " Formatted string ready for the prompt\n", + "\n", " \"\"\"\n", " formatted = []\n", "\n", " for i, doc in enumerate(docs, 1):\n", " # TODO: Extract only the answer from metadata (not the full page_content)\n", - " answer = ... # hint: doc.metadata[\"answer\"]\n", + " answer = doc.metadata[\"answer\"]\n", "\n", " # TODO: Extract the source URL from metadata\n", - " url = ... # hint: doc.metadata[\"url\"]\n", + " url = doc.metadata[\"url\"]\n", "\n", " # TODO: Build the formatted block\n", - " block = ... # \"Document {i}:\\n{answer}\\nSource: {url}\"\n", + " block = f\"Document {i}:\\n{answer}\\nSource: {url}\"\n", "\n", " formatted.append(block)\n", "\n", @@ -1140,13 +1770,25 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 47, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Original query: 'accessibility services for people with mobility issues'\n", + "\n", + "Standard retrieval: 3 docs\n", + "Multi-query retrieval: 0 unique docs\n", + "\n", + "📄 Unique documents found:\n" + ] + } + ], "source": [ "def generate_query_variants(question: str, n_variants: int = 3) -> list[str]:\n", - " \"\"\"\n", - " Use the LLM to generate alternative phrasings of the question.\n", + " \"\"\"Use the LLM to generate alternative phrasings of the question.\n", "\n", " Args:\n", " question: Original user question\n", @@ -1154,6 +1796,7 @@ "\n", " Returns:\n", " List of alternative query strings (NOT including the original)\n", + "\n", " \"\"\"\n", " prompt = f\"\"\"Generate {n_variants} different ways to ask the following question.\n", "Return ONLY the questions, one per line, with no numbering or extra text.\n", @@ -1161,14 +1804,12 @@ "Original question: {question}\"\"\"\n", "\n", " # TODO: call llm.invoke(prompt) and parse the response into a list of strings\n", - " response = ...\n", - " variants = ... # hint: response.content.strip().split(\"\\n\")\n", - " return variants\n", + " response = llm.invoke(prompt)\n", + " return response.content.strip().split(\"\\n\")\n", "\n", "\n", "def multi_query_retrieval(question: str, k: int = 3, n_variants: int = 3) -> list[Document]:\n", - " \"\"\"\n", - " Retrieve documents using multiple query variants and deduplicate results.\n", + " \"\"\"Retrieve documents using multiple query variants and deduplicate results.\n", "\n", " Args:\n", " question: Original user question\n", @@ -1177,8 +1818,9 @@ "\n", " Returns:\n", " Deduplicated list of relevant Document objects\n", + "\n", " \"\"\"\n", - " all_queries = [question] + generate_query_variants(question, n_variants)\n", + " all_queries = [question, *generate_query_variants(question, n_variants)]\n", "\n", " seen_ids = set()\n", " unique_docs = []\n", @@ -1235,26 +1877,56 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 48, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "🎯 Conversational RAG Demo\n", + "============================================================\n", + "\n", + "👤 What kind of transport options are available to get to the venues?\n", + "🤖 Based on the provided context documents, here are the transport options available to get to the Paris 2024 Olympic and Paralympic competition venues:\n", + "\n", + "1. **Public Transport** – All venues are accessible via the **Île-de-France Mobilités network**, which includes:\n", + " - Metro\n", + " - RER (regional expres...\n", + "\n", + "👤 Is it free?\n", + "🔄 Rewritten: 'Will public transportation to the Paris 2024 Olympic and Paralympic venues be free for attendees?'\n", + "🤖 Based on the provided context documents, **public transportation to the Paris 2024 Olympic and Paralympic venues will not be free for attendees**. However, there will be an **adapted fare package** available for spectators during the Games.\n", + "\n", + "Here’s what we know:\n", + "- The **Île-de-France Mobilités netwo...\n", + "\n", + "👤 What about for disabled people?\n", + "🔄 Rewritten: 'What specific transport accommodations and accessibility options will be available for disabled attendees traveling to the Paris 2024 Olympic and Paralympic venues?'\n", + "🤖 Based on the provided context documents, here are the **specific transport accommodations and accessibility options** available for disabled attendees (PWD – People With Disabilities and PFR – People with Reduced Mobility) traveling to the **Paris 2024 Olympic and Paralympic venues**:\n", + "\n", + "---\n", + "\n", + "### **1....\n" + ] + } + ], "source": [ "class ConversationalRAG:\n", - " \"\"\"\n", - " A stateful RAG assistant that remembers previous conversation turns.\n", - " \"\"\"\n", + " \"\"\"A stateful RAG assistant that remembers previous conversation turns.\"\"\"\n", "\n", - " def __init__(self, k: int = 3):\n", + " def __init__(self, k: int = 3) -> None:\n", + " \"\"\"Initialize the assistant with an optional k for retrieval.\"\"\"\n", " self.k = k\n", " self.history: list[tuple[str, str]] = [] # list of (question, answer) pairs\n", "\n", - " def reset(self):\n", + " def reset(self) -> None:\n", " \"\"\"Clear the conversation history.\"\"\"\n", " self.history = []\n", "\n", " def _make_standalone_question(self, question: str) -> str:\n", - " \"\"\"\n", - " Rewrite the question to be self-contained, resolving any references\n", + " \"\"\"Rewrite the question to be self-contained, resolving any references.\n", + "\n", " to previous turns (e.g. pronouns, 'there', 'them', 'those').\n", " If no history exists, return the question unchanged.\n", " \"\"\"\n", @@ -1264,7 +1936,7 @@ " # TODO: Build a prompt that includes the conversation history\n", " # and asks the LLM to rewrite the question to be standalone\n", " history_text = \"\\n\".join(\n", - " [f\"User: {q}\\nAssistant: {a}\" for q, a in self.history[-3:]]\n", + " [f\"User: {q}\\nAssistant: {a}\" for q, a in self.history[-3:]],\n", " )\n", " rewrite_prompt = f\"\"\"Given the conversation below, rewrite the follow-up question to be a fully standalone question that can be understood without the conversation context. Return ONLY the rewritten question, nothing else.\n", "\n", @@ -1275,8 +1947,8 @@ "Standalone question:\"\"\"\n", "\n", " # TODO: invoke the llm and return the rewritten question\n", - " response = ...\n", - " return ...\n", + " response = llm.invoke(rewrite_prompt)\n", + " return response.content.strip()\n", "\n", " def _build_prompt(self, standalone_question: str, context: str) -> str:\n", " \"\"\"Build the full prompt including conversation history.\"\"\"\n", @@ -1301,9 +1973,7 @@ "Assistant:\"\"\"\n", "\n", " def chat(self, question: str, verbose: bool = False) -> str:\n", - " \"\"\"\n", - " Answer a question, using conversation history for context.\n", - " \"\"\"\n", + " \"\"\"Answer a question, using conversation history for context.\"\"\"\n", " # Step 1: Rewrite the question to be standalone\n", " standalone_q = self._make_standalone_question(question)\n", " if verbose and standalone_q != question:\n", @@ -1311,21 +1981,22 @@ "\n", " # TODO:\n", " # Step 2: Retrieve relevant documents using the standalone question\n", - " docs = ...\n", + " docs = vector_store.similarity_search(standalone_q, k=self.k)\n", "\n", " # Step 3: Format documents into context\n", - " context = ...\n", + " context = \"\\n\\n\".join([doc.page_content for doc in docs])\n", "\n", " # Step 4: Build the prompt\n", - " full_prompt = ...\n", + " full_prompt = self._build_prompt(standalone_q, context)\n", "\n", " # Step 5: Invoke the LLM\n", - " response = ...\n", + " response = llm.invoke(full_prompt)\n", "\n", " # Step 6: Store the turn in history\n", - " self.history.append((question, response.content))\n", + " answer = response.content if isinstance(response.content, str) else str(response.content)\n", + " self.history.append((question, answer))\n", "\n", - " return response.content\n", + " return answer\n", "\n", "\n", "# Test it!\n", @@ -1365,15 +2036,39 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 50, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "📊 RAG Evaluation Results\n", + "============================================================\n", + "\n", + "✅ Good case: \"What can I do if I'm disabled?\"\n", + " Faithfulness : 5/5\n", + " Relevance : 5/5\n", + " Feedback : The answer accurately and comprehensively summarizes all key points from the retrieved context, providing clear, actionable information for disabled individuals across train stations, Olympic venues, and air travel. No inaccuracies or omissions were detected.\n", + "\n", + "❌ Hallucination case: \"What is the price of a gold medal?\"\n", + " Faithfulness : 0/5\n", + " Relevance : 1/5\n", + " Feedback : The generated answer is entirely fabricated—the retrieved context contains no information about the price or material composition of a gold medal. The question is relevant to the Olympics, but the answer is unsupported by the provided context.\n", + "\n", + "⚠️ Off-topic retrieval: \"How do I become an Olympic athlete?\"\n", + " Faithfulness : 4/5\n", + " Relevance : 3/5\n", + " Feedback : The answer is mostly faithful to the retrieved context, particularly Document 2, which explains the qualification process. However, it does not provide a direct or comprehensive step-by-step guide on becoming an Olympic athlete, as the context lacks specific details. The relevance is moderate because while the answer addresses the question, it relies on external suggestions rather than concrete information from the provided documents.\n" + ] + } + ], "source": [ "import json\n", "\n", + "\n", "def evaluate_rag_answer(question: str, context: str, answer: str) -> dict:\n", - " \"\"\"\n", - " Use the LLM as a judge to evaluate the quality of a RAG answer.\n", + " \"\"\"Use the LLM as a judge to evaluate the quality of a RAG answer.\n", "\n", " Args:\n", " question: The original user question\n", @@ -1382,6 +2077,7 @@ "\n", " Returns:\n", " dict with keys: \"faithfulness\" (0-5), \"relevance\" (0-5), \"feedback\" (str)\n", + "\n", " \"\"\"\n", " eval_prompt = f\"\"\"You are an expert evaluator for RAG (Retrieval-Augmented Generation) systems.\n", "\n", @@ -1404,12 +2100,11 @@ "{{\"faithfulness\": , \"relevance\": , \"feedback\": \"\"}}\"\"\"\n", "\n", " # TODO: invoke the LLM with the eval_prompt\n", - " response = ...\n", + " response = llm.invoke(eval_prompt)\n", "\n", " # TODO: parse the JSON response and return the dict\n", - " # hint: json.loads(response.content.strip())\n", - " scores = ...\n", - " return scores\n", + " response_text = response.content if isinstance(response.content, str) else str(response.content)\n", + " return json.loads(response_text.strip())\n", "\n", "\n", "# Build a test harness\n", @@ -1437,21 +2132,54 @@ "for case in test_cases:\n", " question = case[\"question\"]\n", "\n", + " # Retrieve and validate question\n", + " question_raw = case.get(\"question\", \"\")\n", + " if not isinstance(question_raw, str):\n", + " raise TypeError(\"case['question'] must be a string\")\n", + " question = question_raw\n", + "\n", " # Retrieve context\n", " docs = vector_store.similarity_search(question, k=3)\n", " context = format_docs(docs)\n", "\n", " # Get or fake the answer\n", - " if case[\"use_rag\"]:\n", - " answer = rag_assistant(question, k=3)\n", - " else:\n", - " answer = case[\"fake_answer\"]\n", + " use_rag = case.get(\"use_rag\", False) is True\n", + " fake_answer = case.get(\"fake_answer\", \"\")\n", + " fake_answer_str = fake_answer if isinstance(fake_answer, str) else str(fake_answer)\n", + " answer = rag_assistant(question, k=3) if use_rag else fake_answer_str\n", "\n", " # Evaluate\n", - " # TODO: call evaluate_rag_answer and print the results\n", - " scores = evaluate_rag_answer(question, context, answer)\n", + " try:\n", + " scores = evaluate_rag_answer(question, context, answer)\n", + " except (json.JSONDecodeError, TypeError, ValueError):\n", + " raw_eval = llm.invoke(\n", + " f\"\"\"Evaluate this RAG answer and return ONLY valid JSON.\n", "\n", - " print(f\"\\n{case['label']}: \\\"{question}\\\"\")\n", + "QUESTION: {question}\n", + "\n", + "RETRIEVED CONTEXT:\n", + "{context}\n", + "\n", + "GENERATED ANSWER:\n", + "{answer}\n", + "\n", + "Return exactly:\n", + "{{\"faithfulness\": , \"relevance\": , \"feedback\": \"\"}}\"\"\",\n", + " )\n", + " raw_text = raw_eval.content if isinstance(raw_eval.content, str) else str(raw_eval.content)\n", + " start = raw_text.find(\"{\")\n", + " end = raw_text.rfind(\"}\") + 1\n", + "\n", + " if start != -1 and end > start:\n", + " scores = json.loads(raw_text[start:end])\n", + " else:\n", + " scores = {\n", + " \"faithfulness\": 0,\n", + " \"relevance\": 0,\n", + " \"feedback\": \"Could not parse evaluator response as JSON.\",\n", + " }\n", + "\n", + " print(f'\\n{case['label']}: \"{question}\"')\n", " print(f\" Faithfulness : {scores.get('faithfulness', '?')}/5\")\n", " print(f\" Relevance : {scores.get('relevance', '?')}/5\")\n", " print(f\" Feedback : {scores.get('feedback', '?')}\")\n" @@ -1516,7 +2244,7 @@ ], "metadata": { "kernelspec": { - "display_name": ".venv (3.12.8)", + "display_name": "studies (3.13.9)", "language": "python", "name": "python3" }, @@ -1530,7 +2258,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.12.8" + "version": "3.13.9" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 9a73df9..41f4504 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,18 +7,22 @@ requires-python = ">= 3.12,<3.14" dependencies = [ "catboost>=1.2.10", "flask>=3.1.3", + "gradio>=6.9.0", "ipykernel>=7.2.0", "ipywidgets>=8.1.8", "langchain>=1.2.10", "langchain-core>=1.2.18", "langchain-huggingface>=1.2.1", "langchain-mistralai>=1.1.1", + "langchain-qdrant>=1.1.0", "matplotlib>=3.10.8", "numpy>=2.4.3", "opencv-python>=4.13.0.92", "pandas>=3.0.1", "pandas-stubs>=3.0.0.260204", "plotly>=6.6.0", + "python-dotenv>=1.2.2", + "qdrant-client>=1.17.0", "scikit-learn>=1.8.0", "scipy>=1.17.1", "seaborn>=0.13.2", diff --git a/uv.lock b/uv.lock index a7fdb85..da5849c 100644 --- a/uv.lock +++ b/uv.lock @@ -21,6 +21,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/18/a6/907a406bb7d359e6a63f99c313846d9eec4f7e6f7437809e03aa00fa3074/absl_py-2.4.0-py3-none-any.whl", hash = "sha256:88476fd881ca8aab94ffa78b7b6c632a782ab3ba1cd19c9bd423abc4fb4cd28d", size = 135750, upload-time = "2026-01-28T10:17:04.19Z" }, ] +[[package]] +name = "aiofiles" +version = "24.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/0b/03/a88171e277e8caa88a4c77808c20ebb04ba74cc4681bf1e9416c862de237/aiofiles-24.1.0.tar.gz", hash = "sha256:22a075c9e5a3810f0c2e48f3008c94d68c65d763b9b03857924c99e57355166c", size = 30247, upload-time = "2024-06-24T11:02:03.584Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a5/45/30bb92d442636f570cb5651bc661f52b610e2eec3f891a5dc3a4c3667db0/aiofiles-24.1.0-py3-none-any.whl", hash = "sha256:b4ec55f4195e3eb5d7abd1bf7e061763e864dd4954231fb8539a0ef8bb8260e5", size = 15896, upload-time = "2024-06-24T11:02:01.529Z" }, +] + [[package]] name = "annotated-doc" version = "0.0.4" @@ -83,6 +92,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2b/03/13dde6512ad7b4557eb792fbcf0c653af6076b81e5941d36ec61f7ce6028/astunparse-1.6.3-py2.py3-none-any.whl", hash = "sha256:c2652417f2c8b5bb325c885ae329bdf3f86424075c4fd1a128674bc6fba4b8e8", size = 12732, upload-time = "2019-12-22T18:12:11.297Z" }, ] +[[package]] +name = "audioop-lts" +version = "0.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/38/53/946db57842a50b2da2e0c1e34bd37f36f5aadba1a929a3971c5d7841dbca/audioop_lts-0.2.2.tar.gz", hash = "sha256:64d0c62d88e67b98a1a5e71987b7aa7b5bcffc7dcee65b635823dbdd0a8dbbd0", size = 30686, upload-time = "2025-08-05T16:43:17.409Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/de/d4/94d277ca941de5a507b07f0b592f199c22454eeaec8f008a286b3fbbacd6/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_universal2.whl", hash = "sha256:fd3d4602dc64914d462924a08c1a9816435a2155d74f325853c1f1ac3b2d9800", size = 46523, upload-time = "2025-08-05T16:42:20.836Z" }, + { url = "https://files.pythonhosted.org/packages/f8/5a/656d1c2da4b555920ce4177167bfeb8623d98765594af59702c8873f60ec/audioop_lts-0.2.2-cp313-abi3-macosx_10_13_x86_64.whl", hash = "sha256:550c114a8df0aafe9a05442a1162dfc8fec37e9af1d625ae6060fed6e756f303", size = 27455, upload-time = "2025-08-05T16:42:22.283Z" }, + { url = "https://files.pythonhosted.org/packages/1b/83/ea581e364ce7b0d41456fb79d6ee0ad482beda61faf0cab20cbd4c63a541/audioop_lts-0.2.2-cp313-abi3-macosx_11_0_arm64.whl", hash = "sha256:9a13dc409f2564de15dd68be65b462ba0dde01b19663720c68c1140c782d1d75", size = 26997, upload-time = "2025-08-05T16:42:23.849Z" }, + { url = "https://files.pythonhosted.org/packages/b8/3b/e8964210b5e216e5041593b7d33e97ee65967f17c282e8510d19c666dab4/audioop_lts-0.2.2-cp313-abi3-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:51c916108c56aa6e426ce611946f901badac950ee2ddaf302b7ed35d9958970d", size = 85844, upload-time = "2025-08-05T16:42:25.208Z" }, + { url = "https://files.pythonhosted.org/packages/c7/2e/0a1c52faf10d51def20531a59ce4c706cb7952323b11709e10de324d6493/audioop_lts-0.2.2-cp313-abi3-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:47eba38322370347b1c47024defbd36374a211e8dd5b0dcbce7b34fdb6f8847b", size = 85056, upload-time = "2025-08-05T16:42:26.559Z" }, + { url = "https://files.pythonhosted.org/packages/75/e8/cd95eef479656cb75ab05dfece8c1f8c395d17a7c651d88f8e6e291a63ab/audioop_lts-0.2.2-cp313-abi3-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:ba7c3a7e5f23e215cb271516197030c32aef2e754252c4c70a50aaff7031a2c8", size = 93892, upload-time = "2025-08-05T16:42:27.902Z" }, + { url = "https://files.pythonhosted.org/packages/5c/1e/a0c42570b74f83efa5cca34905b3eef03f7ab09fe5637015df538a7f3345/audioop_lts-0.2.2-cp313-abi3-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:def246fe9e180626731b26e89816e79aae2276f825420a07b4a647abaa84becc", size = 96660, upload-time = "2025-08-05T16:42:28.9Z" }, + { url = "https://files.pythonhosted.org/packages/50/d5/8a0ae607ca07dbb34027bac8db805498ee7bfecc05fd2c148cc1ed7646e7/audioop_lts-0.2.2-cp313-abi3-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:e160bf9df356d841bb6c180eeeea1834085464626dc1b68fa4e1d59070affdc3", size = 79143, upload-time = "2025-08-05T16:42:29.929Z" }, + { url = "https://files.pythonhosted.org/packages/12/17/0d28c46179e7910bfb0bb62760ccb33edb5de973052cb2230b662c14ca2e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_aarch64.whl", hash = "sha256:4b4cd51a57b698b2d06cb9993b7ac8dfe89a3b2878e96bc7948e9f19ff51dba6", size = 84313, upload-time = "2025-08-05T16:42:30.949Z" }, + { url = "https://files.pythonhosted.org/packages/84/ba/bd5d3806641564f2024e97ca98ea8f8811d4e01d9b9f9831474bc9e14f9e/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_ppc64le.whl", hash = "sha256:4a53aa7c16a60a6857e6b0b165261436396ef7293f8b5c9c828a3a203147ed4a", size = 93044, upload-time = "2025-08-05T16:42:31.959Z" }, + { url = "https://files.pythonhosted.org/packages/f9/5e/435ce8d5642f1f7679540d1e73c1c42d933331c0976eb397d1717d7f01a3/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_riscv64.whl", hash = "sha256:3fc38008969796f0f689f1453722a0f463da1b8a6fbee11987830bfbb664f623", size = 78766, upload-time = "2025-08-05T16:42:33.302Z" }, + { url = "https://files.pythonhosted.org/packages/ae/3b/b909e76b606cbfd53875693ec8c156e93e15a1366a012f0b7e4fb52d3c34/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_s390x.whl", hash = "sha256:15ab25dd3e620790f40e9ead897f91e79c0d3ce65fe193c8ed6c26cffdd24be7", size = 87640, upload-time = "2025-08-05T16:42:34.854Z" }, + { url = "https://files.pythonhosted.org/packages/30/e7/8f1603b4572d79b775f2140d7952f200f5e6c62904585d08a01f0a70393a/audioop_lts-0.2.2-cp313-abi3-musllinux_1_2_x86_64.whl", hash = "sha256:03f061a1915538fd96272bac9551841859dbb2e3bf73ebe4a23ef043766f5449", size = 86052, upload-time = "2025-08-05T16:42:35.839Z" }, + { url = "https://files.pythonhosted.org/packages/b5/96/c37846df657ccdda62ba1ae2b6534fa90e2e1b1742ca8dcf8ebd38c53801/audioop_lts-0.2.2-cp313-abi3-win32.whl", hash = "sha256:3bcddaaf6cc5935a300a8387c99f7a7fbbe212a11568ec6cf6e4bc458c048636", size = 26185, upload-time = "2025-08-05T16:42:37.04Z" }, + { url = "https://files.pythonhosted.org/packages/34/a5/9d78fdb5b844a83da8a71226c7bdae7cc638861085fff7a1d707cb4823fa/audioop_lts-0.2.2-cp313-abi3-win_amd64.whl", hash = "sha256:a2c2a947fae7d1062ef08c4e369e0ba2086049a5e598fda41122535557012e9e", size = 30503, upload-time = "2025-08-05T16:42:38.427Z" }, + { url = "https://files.pythonhosted.org/packages/34/25/20d8fde083123e90c61b51afb547bb0ea7e77bab50d98c0ab243d02a0e43/audioop_lts-0.2.2-cp313-abi3-win_arm64.whl", hash = "sha256:5f93a5db13927a37d2d09637ccca4b2b6b48c19cd9eda7b17a2e9f77edee6a6f", size = 24173, upload-time = "2025-08-05T16:42:39.704Z" }, + { url = "https://files.pythonhosted.org/packages/58/a7/0a764f77b5c4ac58dc13c01a580f5d32ae8c74c92020b961556a43e26d02/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_universal2.whl", hash = "sha256:73f80bf4cd5d2ca7814da30a120de1f9408ee0619cc75da87d0641273d202a09", size = 47096, upload-time = "2025-08-05T16:42:40.684Z" }, + { url = "https://files.pythonhosted.org/packages/aa/ed/ebebedde1a18848b085ad0fa54b66ceb95f1f94a3fc04f1cd1b5ccb0ed42/audioop_lts-0.2.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:106753a83a25ee4d6f473f2be6b0966fc1c9af7e0017192f5531a3e7463dce58", size = 27748, upload-time = "2025-08-05T16:42:41.992Z" }, + { url = "https://files.pythonhosted.org/packages/cb/6e/11ca8c21af79f15dbb1c7f8017952ee8c810c438ce4e2b25638dfef2b02c/audioop_lts-0.2.2-cp313-cp313t-macosx_11_0_arm64.whl", hash = "sha256:fbdd522624141e40948ab3e8cdae6e04c748d78710e9f0f8d4dae2750831de19", size = 27329, upload-time = "2025-08-05T16:42:42.987Z" }, + { url = "https://files.pythonhosted.org/packages/84/52/0022f93d56d85eec5da6b9da6a958a1ef09e80c39f2cc0a590c6af81dcbb/audioop_lts-0.2.2-cp313-cp313t-manylinux1_x86_64.manylinux_2_28_x86_64.manylinux_2_5_x86_64.whl", hash = "sha256:143fad0311e8209ece30a8dbddab3b65ab419cbe8c0dde6e8828da25999be911", size = 92407, upload-time = "2025-08-05T16:42:44.336Z" }, + { url = "https://files.pythonhosted.org/packages/87/1d/48a889855e67be8718adbc7a01f3c01d5743c325453a5e81cf3717664aad/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:dfbbc74ec68a0fd08cfec1f4b5e8cca3d3cd7de5501b01c4b5d209995033cde9", size = 91811, upload-time = "2025-08-05T16:42:45.325Z" }, + { url = "https://files.pythonhosted.org/packages/98/a6/94b7213190e8077547ffae75e13ed05edc488653c85aa5c41472c297d295/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:cfcac6aa6f42397471e4943e0feb2244549db5c5d01efcd02725b96af417f3fe", size = 100470, upload-time = "2025-08-05T16:42:46.468Z" }, + { url = "https://files.pythonhosted.org/packages/e9/e9/78450d7cb921ede0cfc33426d3a8023a3bda755883c95c868ee36db8d48d/audioop_lts-0.2.2-cp313-cp313t-manylinux2014_s390x.manylinux_2_17_s390x.manylinux_2_28_s390x.whl", hash = "sha256:752d76472d9804ac60f0078c79cdae8b956f293177acd2316cd1e15149aee132", size = 103878, upload-time = "2025-08-05T16:42:47.576Z" }, + { url = "https://files.pythonhosted.org/packages/4f/e2/cd5439aad4f3e34ae1ee852025dc6aa8f67a82b97641e390bf7bd9891d3e/audioop_lts-0.2.2-cp313-cp313t-manylinux_2_31_riscv64.manylinux_2_39_riscv64.whl", hash = "sha256:83c381767e2cc10e93e40281a04852facc4cd9334550e0f392f72d1c0a9c5753", size = 84867, upload-time = "2025-08-05T16:42:49.003Z" }, + { url = "https://files.pythonhosted.org/packages/68/4b/9d853e9076c43ebba0d411e8d2aa19061083349ac695a7d082540bad64d0/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:c0022283e9556e0f3643b7c3c03f05063ca72b3063291834cca43234f20c60bb", size = 90001, upload-time = "2025-08-05T16:42:50.038Z" }, + { url = "https://files.pythonhosted.org/packages/58/26/4bae7f9d2f116ed5593989d0e521d679b0d583973d203384679323d8fa85/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_ppc64le.whl", hash = "sha256:a2d4f1513d63c795e82948e1305f31a6d530626e5f9f2605408b300ae6095093", size = 99046, upload-time = "2025-08-05T16:42:51.111Z" }, + { url = "https://files.pythonhosted.org/packages/b2/67/a9f4fb3e250dda9e9046f8866e9fa7d52664f8985e445c6b4ad6dfb55641/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_riscv64.whl", hash = "sha256:c9c8e68d8b4a56fda8c025e538e639f8c5953f5073886b596c93ec9b620055e7", size = 84788, upload-time = "2025-08-05T16:42:52.198Z" }, + { url = "https://files.pythonhosted.org/packages/70/f7/3de86562db0121956148bcb0fe5b506615e3bcf6e63c4357a612b910765a/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_s390x.whl", hash = "sha256:96f19de485a2925314f5020e85911fb447ff5fbef56e8c7c6927851b95533a1c", size = 94472, upload-time = "2025-08-05T16:42:53.59Z" }, + { url = "https://files.pythonhosted.org/packages/f1/32/fd772bf9078ae1001207d2df1eef3da05bea611a87dd0e8217989b2848fa/audioop_lts-0.2.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:e541c3ef484852ef36545f66209444c48b28661e864ccadb29daddb6a4b8e5f5", size = 92279, upload-time = "2025-08-05T16:42:54.632Z" }, + { url = "https://files.pythonhosted.org/packages/4f/41/affea7181592ab0ab560044632571a38edaf9130b84928177823fbf3176a/audioop_lts-0.2.2-cp313-cp313t-win32.whl", hash = "sha256:d5e73fa573e273e4f2e5ff96f9043858a5e9311e94ffefd88a3186a910c70917", size = 26568, upload-time = "2025-08-05T16:42:55.627Z" }, + { url = "https://files.pythonhosted.org/packages/28/2b/0372842877016641db8fc54d5c88596b542eec2f8f6c20a36fb6612bf9ee/audioop_lts-0.2.2-cp313-cp313t-win_amd64.whl", hash = "sha256:9191d68659eda01e448188f60364c7763a7ca6653ed3f87ebb165822153a8547", size = 30942, upload-time = "2025-08-05T16:42:56.674Z" }, + { url = "https://files.pythonhosted.org/packages/ee/ca/baf2b9cc7e96c179bb4a54f30fcd83e6ecb340031bde68f486403f943768/audioop_lts-0.2.2-cp313-cp313t-win_arm64.whl", hash = "sha256:c174e322bb5783c099aaf87faeb240c8d210686b04bd61dfd05a8e5a83d88969", size = 24603, upload-time = "2025-08-05T16:42:57.571Z" }, +] + [[package]] name = "blinker" version = "1.9.0" @@ -117,6 +166,34 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/31/07/4cdc81a47bf862c0b06d91f1bc6782064e8b69ac9b5d4ff51d97e4ff03da/blis-1.3.3-cp313-cp313-win_amd64.whl", hash = "sha256:7a0fc4b237a3a453bdc3c7ab48d91439fcd2d013b665c46948d9eaf9c3e45a97", size = 6192624, upload-time = "2025-11-17T12:28:14.197Z" }, ] +[[package]] +name = "brotli" +version = "1.2.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/f7/16/c92ca344d646e71a43b8bb353f0a6490d7f6e06210f8554c8f874e454285/brotli-1.2.0.tar.gz", hash = "sha256:e310f77e41941c13340a95976fe66a8a95b01e783d430eeaf7a2f87e0a57dd0a", size = 7388632, upload-time = "2025-11-05T18:39:42.86Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/11/ee/b0a11ab2315c69bb9b45a2aaed022499c9c24a205c3a49c3513b541a7967/brotli-1.2.0-cp312-cp312-macosx_10_13_universal2.whl", hash = "sha256:35d382625778834a7f3061b15423919aa03e4f5da34ac8e02c074e4b75ab4f84", size = 861543, upload-time = "2025-11-05T18:38:24.183Z" }, + { url = "https://files.pythonhosted.org/packages/e1/2f/29c1459513cd35828e25531ebfcbf3e92a5e49f560b1777a9af7203eb46e/brotli-1.2.0-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:7a61c06b334bd99bc5ae84f1eeb36bfe01400264b3c352f968c6e30a10f9d08b", size = 444288, upload-time = "2025-11-05T18:38:25.139Z" }, + { url = "https://files.pythonhosted.org/packages/3d/6f/feba03130d5fceadfa3a1bb102cb14650798c848b1df2a808356f939bb16/brotli-1.2.0-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:acec55bb7c90f1dfc476126f9711a8e81c9af7fb617409a9ee2953115343f08d", size = 1528071, upload-time = "2025-11-05T18:38:26.081Z" }, + { url = "https://files.pythonhosted.org/packages/2b/38/f3abb554eee089bd15471057ba85f47e53a44a462cfce265d9bf7088eb09/brotli-1.2.0-cp312-cp312-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:260d3692396e1895c5034f204f0db022c056f9e2ac841593a4cf9426e2a3faca", size = 1626913, upload-time = "2025-11-05T18:38:27.284Z" }, + { url = "https://files.pythonhosted.org/packages/03/a7/03aa61fbc3c5cbf99b44d158665f9b0dd3d8059be16c460208d9e385c837/brotli-1.2.0-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:072e7624b1fc4d601036ab3f4f27942ef772887e876beff0301d261210bca97f", size = 1419762, upload-time = "2025-11-05T18:38:28.295Z" }, + { url = "https://files.pythonhosted.org/packages/21/1b/0374a89ee27d152a5069c356c96b93afd1b94eae83f1e004b57eb6ce2f10/brotli-1.2.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:adedc4a67e15327dfdd04884873c6d5a01d3e3b6f61406f99b1ed4865a2f6d28", size = 1484494, upload-time = "2025-11-05T18:38:29.29Z" }, + { url = "https://files.pythonhosted.org/packages/cf/57/69d4fe84a67aef4f524dcd075c6eee868d7850e85bf01d778a857d8dbe0a/brotli-1.2.0-cp312-cp312-musllinux_1_2_ppc64le.whl", hash = "sha256:7a47ce5c2288702e09dc22a44d0ee6152f2c7eda97b3c8482d826a1f3cfc7da7", size = 1593302, upload-time = "2025-11-05T18:38:30.639Z" }, + { url = "https://files.pythonhosted.org/packages/d5/3b/39e13ce78a8e9a621c5df3aeb5fd181fcc8caba8c48a194cd629771f6828/brotli-1.2.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:af43b8711a8264bb4e7d6d9a6d004c3a2019c04c01127a868709ec29962b6036", size = 1487913, upload-time = "2025-11-05T18:38:31.618Z" }, + { url = "https://files.pythonhosted.org/packages/62/28/4d00cb9bd76a6357a66fcd54b4b6d70288385584063f4b07884c1e7286ac/brotli-1.2.0-cp312-cp312-win32.whl", hash = "sha256:e99befa0b48f3cd293dafeacdd0d191804d105d279e0b387a32054c1180f3161", size = 334362, upload-time = "2025-11-05T18:38:32.939Z" }, + { url = "https://files.pythonhosted.org/packages/1c/4e/bc1dcac9498859d5e353c9b153627a3752868a9d5f05ce8dedd81a2354ab/brotli-1.2.0-cp312-cp312-win_amd64.whl", hash = "sha256:b35c13ce241abdd44cb8ca70683f20c0c079728a36a996297adb5334adfc1c44", size = 369115, upload-time = "2025-11-05T18:38:33.765Z" }, + { url = "https://files.pythonhosted.org/packages/6c/d4/4ad5432ac98c73096159d9ce7ffeb82d151c2ac84adcc6168e476bb54674/brotli-1.2.0-cp313-cp313-macosx_10_13_universal2.whl", hash = "sha256:9e5825ba2c9998375530504578fd4d5d1059d09621a02065d1b6bfc41a8e05ab", size = 861523, upload-time = "2025-11-05T18:38:34.67Z" }, + { url = "https://files.pythonhosted.org/packages/91/9f/9cc5bd03ee68a85dc4bc89114f7067c056a3c14b3d95f171918c088bf88d/brotli-1.2.0-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0cf8c3b8ba93d496b2fae778039e2f5ecc7cff99df84df337ca31d8f2252896c", size = 444289, upload-time = "2025-11-05T18:38:35.6Z" }, + { url = "https://files.pythonhosted.org/packages/2e/b6/fe84227c56a865d16a6614e2c4722864b380cb14b13f3e6bef441e73a85a/brotli-1.2.0-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:c8565e3cdc1808b1a34714b553b262c5de5fbda202285782173ec137fd13709f", size = 1528076, upload-time = "2025-11-05T18:38:36.639Z" }, + { url = "https://files.pythonhosted.org/packages/55/de/de4ae0aaca06c790371cf6e7ee93a024f6b4bb0568727da8c3de112e726c/brotli-1.2.0-cp313-cp313-manylinux2014_ppc64le.manylinux_2_17_ppc64le.manylinux_2_28_ppc64le.whl", hash = "sha256:26e8d3ecb0ee458a9804f47f21b74845cc823fd1bb19f02272be70774f56e2a6", size = 1626880, upload-time = "2025-11-05T18:38:37.623Z" }, + { url = "https://files.pythonhosted.org/packages/5f/16/a1b22cbea436642e071adcaf8d4b350a2ad02f5e0ad0da879a1be16188a0/brotli-1.2.0-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:67a91c5187e1eec76a61625c77a6c8c785650f5b576ca732bd33ef58b0dff49c", size = 1419737, upload-time = "2025-11-05T18:38:38.729Z" }, + { url = "https://files.pythonhosted.org/packages/46/63/c968a97cbb3bdbf7f974ef5a6ab467a2879b82afbc5ffb65b8acbb744f95/brotli-1.2.0-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:4ecdb3b6dc36e6d6e14d3a1bdc6c1057c8cbf80db04031d566eb6080ce283a48", size = 1484440, upload-time = "2025-11-05T18:38:39.916Z" }, + { url = "https://files.pythonhosted.org/packages/06/9d/102c67ea5c9fc171f423e8399e585dabea29b5bc79b05572891e70013cdd/brotli-1.2.0-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:3e1b35d56856f3ed326b140d3c6d9db91740f22e14b06e840fe4bb1923439a18", size = 1593313, upload-time = "2025-11-05T18:38:41.24Z" }, + { url = "https://files.pythonhosted.org/packages/9e/4a/9526d14fa6b87bc827ba1755a8440e214ff90de03095cacd78a64abe2b7d/brotli-1.2.0-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:54a50a9dad16b32136b2241ddea9e4df159b41247b2ce6aac0b3276a66a8f1e5", size = 1487945, upload-time = "2025-11-05T18:38:42.277Z" }, + { url = "https://files.pythonhosted.org/packages/5b/e8/3fe1ffed70cbef83c5236166acaed7bb9c766509b157854c80e2f766b38c/brotli-1.2.0-cp313-cp313-win32.whl", hash = "sha256:1b1d6a4efedd53671c793be6dd760fcf2107da3a52331ad9ea429edf0902f27a", size = 334368, upload-time = "2025-11-05T18:38:43.345Z" }, + { url = "https://files.pythonhosted.org/packages/ff/91/e739587be970a113b37b821eae8097aac5a48e5f0eca438c22e4c7dd8648/brotli-1.2.0-cp313-cp313-win_amd64.whl", hash = "sha256:b63daa43d82f0cdabf98dee215b375b4058cce72871fd07934f179885aad16e8", size = 369116, upload-time = "2025-11-05T18:38:44.609Z" }, +] + [[package]] name = "catalogue" version = "2.0.10" @@ -438,6 +515,31 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/c1/ea/53f2148663b321f21b5a606bd5f191517cf40b7072c0497d3c92c4a13b1e/executing-2.2.1-py2.py3-none-any.whl", hash = "sha256:760643d3452b4d777d295bb167ccc74c64a81df23fb5e08eff250c425a4b2017", size = 28317, upload-time = "2025-09-01T09:48:08.5Z" }, ] +[[package]] +name = "fastapi" +version = "0.135.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "annotated-doc" }, + { name = "pydantic" }, + { name = "starlette" }, + { name = "typing-extensions" }, + { name = "typing-inspection" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/e7/7b/f8e0211e9380f7195ba3f3d40c292594fd81ba8ec4629e3854c353aaca45/fastapi-0.135.1.tar.gz", hash = "sha256:d04115b508d936d254cea545b7312ecaa58a7b3a0f84952535b4c9afae7668cd", size = 394962, upload-time = "2026-03-01T18:18:29.369Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e4/72/42e900510195b23a56bde950d26a51f8b723846bfcaa0286e90287f0422b/fastapi-0.135.1-py3-none-any.whl", hash = "sha256:46e2fc5745924b7c840f71ddd277382af29ce1cdb7d5eab5bf697e3fb9999c9e", size = 116999, upload-time = "2026-03-01T18:18:30.831Z" }, +] + +[[package]] +name = "ffmpy" +version = "1.0.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/d2/1c4c582d71bcc65c76fa69fab85de6257d50fdf6fd4a2317c53917e9a581/ffmpy-1.0.0.tar.gz", hash = "sha256:b12932e95435c8820f1cd041024402765f821971e4bae753b327fc02a6e12f8b", size = 5101, upload-time = "2025-11-11T06:24:23.856Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/55/56/dd3669eccebb6d8ac81e624542ebd53fe6f08e1b8f2f8d50aeb7e3b83f99/ffmpy-1.0.0-py3-none-any.whl", hash = "sha256:5640e5f0fd03fb6236d0e119b16ccf6522db1c826fdf35dcb87087b60fd7504f", size = 5614, upload-time = "2025-11-11T06:24:22.818Z" }, +] + [[package]] name = "filelock" version = "3.25.1" @@ -527,6 +629,62 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/a3/de/c648ef6835192e6e2cc03f40b19eeda4382c49b5bafb43d88b931c4c74ac/google_pasta-0.2.0-py3-none-any.whl", hash = "sha256:b32482794a366b5366a32c92a9a9201b107821889935a02b3e51f6b432ea84ed", size = 57471, upload-time = "2020-03-13T18:57:48.872Z" }, ] +[[package]] +name = "gradio" +version = "6.9.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "aiofiles" }, + { name = "anyio" }, + { name = "audioop-lts", marker = "python_full_version >= '3.13'" }, + { name = "brotli" }, + { name = "fastapi" }, + { name = "ffmpy" }, + { name = "gradio-client" }, + { name = "groovy" }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "jinja2" }, + { name = "markupsafe" }, + { name = "numpy" }, + { name = "orjson" }, + { name = "packaging" }, + { name = "pandas" }, + { name = "pillow" }, + { name = "pydantic" }, + { name = "pydub" }, + { name = "python-multipart" }, + { name = "pytz" }, + { name = "pyyaml" }, + { name = "safehttpx" }, + { name = "semantic-version" }, + { name = "starlette" }, + { name = "tomlkit" }, + { name = "typer" }, + { name = "typing-extensions" }, + { name = "uvicorn" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/bd/83/29bdbf94b212512e3c775482d390f5b699a72d71a2c431dea367a6e45a37/gradio-6.9.0.tar.gz", hash = "sha256:593e60e33233f3586452ebfa9f741817c5ae849a98cc70945f3ccb8dc895eb22", size = 57904480, upload-time = "2026-03-06T17:44:26.025Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/b3/8b/dc357ab966544e4dc898a2fee326d755c5f54da82af71a1a802e3476e78e/gradio-6.9.0-py3-none-any.whl", hash = "sha256:c173dd330c9247002a42222c85d76c0ecee65437eff808084e360862e7bbd24f", size = 42940853, upload-time = "2026-03-06T17:44:22.009Z" }, +] + +[[package]] +name = "gradio-client" +version = "2.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "fsspec" }, + { name = "httpx" }, + { name = "huggingface-hub" }, + { name = "packaging" }, + { name = "typing-extensions" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/97/d2/de2037f5eff13a5145cdf6982fd34c9735f0806e8a2ee5d4bfe9a7d25a54/gradio_client-2.3.0.tar.gz", hash = "sha256:1c700dc60e65bae4386ba7cf3732b9f9d5bcf5fb8eb451df3944fe092d7d9a29", size = 57552, upload-time = "2026-03-06T17:44:38.247Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/99/6a/41752781399811afbf8ac858f63c20eff354ed35169daa39604aefced4e8/gradio_client-2.3.0-py3-none-any.whl", hash = "sha256:9ec51a927888fc188e123a0ac5ad341d9265b325539a399554d1fc2604942e74", size = 58531, upload-time = "2026-03-06T17:44:36.961Z" }, +] + [[package]] name = "graphviz" version = "0.21" @@ -536,6 +694,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/91/4c/e0ce1ef95d4000ebc1c11801f9b944fa5910ecc15b5e351865763d8657f8/graphviz-0.21-py3-none-any.whl", hash = "sha256:54f33de9f4f911d7e84e4191749cac8cc5653f815b06738c54db9a15ab8b1e42", size = 47300, upload-time = "2025-06-15T09:35:04.433Z" }, ] +[[package]] +name = "groovy" +version = "0.1.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/52/36/bbdede67400277bef33d3ec0e6a31750da972c469f75966b4930c753218f/groovy-0.1.2.tar.gz", hash = "sha256:25c1dc09b3f9d7e292458aa762c6beb96ea037071bf5e917fc81fb78d2231083", size = 17325, upload-time = "2025-02-28T20:24:56.068Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/28/27/3d6dcadc8a3214d8522c1e7f6a19554e33659be44546d44a2f7572ac7d2a/groovy-0.1.2-py3-none-any.whl", hash = "sha256:7f7975bab18c729a257a8b1ae9dcd70b7cafb1720481beae47719af57c35fa64", size = 14090, upload-time = "2025-02-28T20:24:55.152Z" }, +] + [[package]] name = "grpcio" version = "1.78.0" @@ -576,6 +743,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/04/4b/29cac41a4d98d144bf5f6d33995617b185d14b22401f75ca86f384e87ff1/h11-0.16.0-py3-none-any.whl", hash = "sha256:63cf8bbe7522de3bf65932fda1d9c2772064ffb3dae62d55932da54b31cb6c86", size = 37515, upload-time = "2025-04-24T03:35:24.344Z" }, ] +[[package]] +name = "h2" +version = "4.3.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "hpack" }, + { name = "hyperframe" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/1d/17/afa56379f94ad0fe8defd37d6eb3f89a25404ffc71d4d848893d270325fc/h2-4.3.0.tar.gz", hash = "sha256:6c59efe4323fa18b47a632221a1888bd7fde6249819beda254aeca909f221bf1", size = 2152026, upload-time = "2025-08-23T18:12:19.778Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/69/b2/119f6e6dcbd96f9069ce9a2665e0146588dc9f88f29549711853645e736a/h2-4.3.0-py3-none-any.whl", hash = "sha256:c438f029a25f7945c69e0ccf0fb951dc3f73a5f6412981daee861431b70e2bdd", size = 61779, upload-time = "2025-08-23T18:12:17.779Z" }, +] + [[package]] name = "h5py" version = "3.14.0" @@ -621,6 +801,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/cc/02/9a6e4ca1f3f73a164c0cd48e41b3cc56585dcc37e809250de443d673266f/hf_xet-1.3.2-cp37-abi3-win_arm64.whl", hash = "sha256:83d8ec273136171431833a6957e8f3af496bee227a0fe47c7b8b39c106d1749a", size = 3503976, upload-time = "2026-02-27T17:26:12.123Z" }, ] +[[package]] +name = "hpack" +version = "4.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/2c/48/71de9ed269fdae9c8057e5a4c0aa7402e8bb16f2c6e90b3aa53327b113f8/hpack-4.1.0.tar.gz", hash = "sha256:ec5eca154f7056aa06f196a557655c5b009b382873ac8d1e66e79e87535f1dca", size = 51276, upload-time = "2025-01-22T21:44:58.347Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/07/c6/80c95b1b2b94682a72cbdbfb85b81ae2daffa4291fbfa1b1464502ede10d/hpack-4.1.0-py3-none-any.whl", hash = "sha256:157ac792668d995c657d93111f46b4535ed114f0c9c8d672271bbec7eae1b496", size = 34357, upload-time = "2025-01-22T21:44:56.92Z" }, +] + [[package]] name = "httpcore" version = "1.0.9" @@ -649,6 +838,11 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2a/39/e50c7c3a983047577ee07d2a9e53faf5a69493943ec3f6a384bdc792deb2/httpx-0.28.1-py3-none-any.whl", hash = "sha256:d909fcccc110f8c7faf814ca82a9a4d816bc5a6dbfea25d6591d6985b8ba59ad", size = 73517, upload-time = "2024-12-06T15:37:21.509Z" }, ] +[package.optional-dependencies] +http2 = [ + { name = "h2" }, +] + [[package]] name = "httpx-sse" version = "0.4.3" @@ -678,6 +872,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/92/e3/e3a44f54c8e2f28983fcf07f13d4260b37bd6a0d3a081041bc60b91d230e/huggingface_hub-1.6.0-py3-none-any.whl", hash = "sha256:ef40e2d5cb85e48b2c067020fa5142168342d5108a1b267478ed384ecbf18961", size = 612874, upload-time = "2026-03-06T14:19:16.844Z" }, ] +[[package]] +name = "hyperframe" +version = "6.1.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/02/e7/94f8232d4a74cc99514c13a9f995811485a6903d48e5d952771ef6322e30/hyperframe-6.1.0.tar.gz", hash = "sha256:f630908a00854a7adeabd6382b43923a4c4cd4b821fcb527e6ab9e15382a3b08", size = 26566, upload-time = "2025-01-22T21:41:49.302Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/48/30/47d0bf6072f7252e6521f3447ccfa40b421b6824517f82854703d0f5a98b/hyperframe-6.1.0-py3-none-any.whl", hash = "sha256:b03380493a519fce58ea5af42e4a42317bf9bd425596f7a0835ffce80f1a42e5", size = 13007, upload-time = "2025-01-22T21:41:47.295Z" }, +] + [[package]] name = "idna" version = "3.11" @@ -999,6 +1202,20 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2f/96/67e029665e9c348a2f17d1a681dc139631a6d8241b7a8d8e6ee69ff70a4b/langchain_mistralai-1.1.1-py3-none-any.whl", hash = "sha256:47839fc69c879bad4ff60133f238c15574416c2dcd850121621a7e9de45800c1", size = 19439, upload-time = "2025-12-12T22:11:53.546Z" }, ] +[[package]] +name = "langchain-qdrant" +version = "1.1.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "langchain-core" }, + { name = "pydantic" }, + { name = "qdrant-client" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/77/66/fb1c4e2801e55d92dea71d9a7f948574a322a1f5adc7913231023827f79f/langchain_qdrant-1.1.0.tar.gz", hash = "sha256:433236845736f973543ac6b7137f9d7fa511b7539373fbc6565c581d3ba59373", size = 195565, upload-time = "2025-10-22T17:27:15.157Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/62/7e/d951082cb13e923508ba1eee4f48e7d511efc991c6506af567334654a3f3/langchain_qdrant-1.1.0-py3-none-any.whl", hash = "sha256:546c5c9aa57f543dbcee07343f730c331e4ec2af2ec55b541010af08d872bf35", size = 24254, upload-time = "2025-10-22T17:27:14.065Z" }, +] + [[package]] name = "langgraph" version = "1.0.10" @@ -1843,6 +2060,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/52/d2/c6e44dba74f17c6216ce1b56044a9b93a929f1c2d5bdaff892512b260f5e/plotly-6.6.0-py3-none-any.whl", hash = "sha256:8d6daf0f87412e0c0bfe72e809d615217ab57cc715899a1e5145135a7800d1d0", size = 9910315, upload-time = "2026-03-02T21:10:18.131Z" }, ] +[[package]] +name = "portalocker" +version = "3.2.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "pywin32", marker = "sys_platform == 'win32'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/5e/77/65b857a69ed876e1951e88aaba60f5ce6120c33703f7cb61a3c894b8c1b6/portalocker-3.2.0.tar.gz", hash = "sha256:1f3002956a54a8c3730586c5c77bf18fae4149e07eaf1c29fc3faf4d5a3f89ac", size = 95644, upload-time = "2025-06-14T13:20:40.03Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/4b/a6/38c8e2f318bf67d338f4d629e93b0b4b9af331f455f0390ea8ce4a099b26/portalocker-3.2.0-py3-none-any.whl", hash = "sha256:3cdc5f565312224bc570c49337bd21428bba0ef363bbcf58b9ef4a9f11779968", size = 22424, upload-time = "2025-06-14T13:20:38.083Z" }, +] + [[package]] name = "preshed" version = "3.0.12" @@ -2005,6 +2234,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f7/07/34573da085946b6a313d7c42f82f16e8920bfd730665de2d11c0c37a74b5/pydantic_core-2.41.5-graalpy312-graalpy250_312_native-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76d0819de158cd855d1cbb8fcafdf6f5cf1eb8e470abe056d5d161106e38062b", size = 2139017, upload-time = "2025-11-04T13:42:59.471Z" }, ] +[[package]] +name = "pydub" +version = "0.25.1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/fe/9a/e6bca0eed82db26562c73b5076539a4a08d3cffd19c3cc5913a3e61145fd/pydub-0.25.1.tar.gz", hash = "sha256:980a33ce9949cab2a569606b65674d748ecbca4f0796887fd6f46173a7b0d30f", size = 38326, upload-time = "2021-03-10T02:09:54.659Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/a6/53/d78dc063216e62fc55f6b2eebb447f6a4b0a59f55c8406376f76bf959b08/pydub-0.25.1-py2.py3-none-any.whl", hash = "sha256:65617e33033874b59d87db603aa1ed450633288aefead953b30bded59cb599a6", size = 32327, upload-time = "2021-03-10T02:09:53.503Z" }, +] + [[package]] name = "pygments" version = "2.19.2" @@ -2079,6 +2317,46 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/ec/57/56b9bcc3c9c6a792fcbaf139543cee77261f3651ca9da0c93f5c1221264b/python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427", size = 229892, upload-time = "2024-03-01T18:36:18.57Z" }, ] +[[package]] +name = "python-dotenv" +version = "1.2.2" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/82/ed/0301aeeac3e5353ef3d94b6ec08bbcabd04a72018415dcb29e588514bba8/python_dotenv-1.2.2.tar.gz", hash = "sha256:2c371a91fbd7ba082c2c1dc1f8bf89ca22564a087c2c287cd9b662adde799cf3", size = 50135, upload-time = "2026-03-01T16:00:26.196Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/d7/1959b9648791274998a9c3526f6d0ec8fd2233e4d4acce81bbae76b44b2a/python_dotenv-1.2.2-py3-none-any.whl", hash = "sha256:1d8214789a24de455a8b8bd8ae6fe3c6b69a5e3d64aa8a8e5d68e694bbcb285a", size = 22101, upload-time = "2026-03-01T16:00:25.09Z" }, +] + +[[package]] +name = "python-multipart" +version = "0.0.22" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/94/01/979e98d542a70714b0cb2b6728ed0b7c46792b695e3eaec3e20711271ca3/python_multipart-0.0.22.tar.gz", hash = "sha256:7340bef99a7e0032613f56dc36027b959fd3b30a787ed62d310e951f7c3a3a58", size = 37612, upload-time = "2026-01-25T10:15:56.219Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/1b/d0/397f9626e711ff749a95d96b7af99b9c566a9bb5129b8e4c10fc4d100304/python_multipart-0.0.22-py3-none-any.whl", hash = "sha256:2b2cd894c83d21bf49d702499531c7bafd057d730c201782048f7945d82de155", size = 24579, upload-time = "2026-01-25T10:15:54.811Z" }, +] + +[[package]] +name = "pytz" +version = "2026.1.post1" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/56/db/b8721d71d945e6a8ac63c0fc900b2067181dbb50805958d4d4661cf7d277/pytz-2026.1.post1.tar.gz", hash = "sha256:3378dde6a0c3d26719182142c56e60c7f9af7e968076f31aae569d72a0358ee1", size = 321088, upload-time = "2026-03-03T07:47:50.683Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/10/99/781fe0c827be2742bcc775efefccb3b048a3a9c6ce9aec0cbf4a101677e5/pytz-2026.1.post1-py2.py3-none-any.whl", hash = "sha256:f2fd16142fda348286a75e1a524be810bb05d444e5a081f37f7affc635035f7a", size = 510489, upload-time = "2026-03-03T07:47:49.167Z" }, +] + +[[package]] +name = "pywin32" +version = "311" +source = { registry = "https://pypi.org/simple" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/e7/ab/01ea1943d4eba0f850c3c61e78e8dd59757ff815ff3ccd0a84de5f541f42/pywin32-311-cp312-cp312-win32.whl", hash = "sha256:750ec6e621af2b948540032557b10a2d43b0cee2ae9758c54154d711cc852d31", size = 8706543, upload-time = "2025-07-14T20:13:20.765Z" }, + { url = "https://files.pythonhosted.org/packages/d1/a8/a0e8d07d4d051ec7502cd58b291ec98dcc0c3fff027caad0470b72cfcc2f/pywin32-311-cp312-cp312-win_amd64.whl", hash = "sha256:b8c095edad5c211ff31c05223658e71bf7116daa0ecf3ad85f3201ea3190d067", size = 9495040, upload-time = "2025-07-14T20:13:22.543Z" }, + { url = "https://files.pythonhosted.org/packages/ba/3a/2ae996277b4b50f17d61f0603efd8253cb2d79cc7ae159468007b586396d/pywin32-311-cp312-cp312-win_arm64.whl", hash = "sha256:e286f46a9a39c4a18b319c28f59b61de793654af2f395c102b4f819e584b5852", size = 8710102, upload-time = "2025-07-14T20:13:24.682Z" }, + { url = "https://files.pythonhosted.org/packages/a5/be/3fd5de0979fcb3994bfee0d65ed8ca9506a8a1260651b86174f6a86f52b3/pywin32-311-cp313-cp313-win32.whl", hash = "sha256:f95ba5a847cba10dd8c4d8fefa9f2a6cf283b8b88ed6178fa8a6c1ab16054d0d", size = 8705700, upload-time = "2025-07-14T20:13:26.471Z" }, + { url = "https://files.pythonhosted.org/packages/e3/28/e0a1909523c6890208295a29e05c2adb2126364e289826c0a8bc7297bd5c/pywin32-311-cp313-cp313-win_amd64.whl", hash = "sha256:718a38f7e5b058e76aee1c56ddd06908116d35147e133427e59a3983f703a20d", size = 9494700, upload-time = "2025-07-14T20:13:28.243Z" }, + { url = "https://files.pythonhosted.org/packages/04/bf/90339ac0f55726dce7d794e6d79a18a91265bdf3aa70b6b9ca52f35e022a/pywin32-311-cp313-cp313-win_arm64.whl", hash = "sha256:7b4075d959648406202d92a2310cb990fea19b535c7f4a78d3f5e10b926eeb8a", size = 8709318, upload-time = "2025-07-14T20:13:30.348Z" }, +] + [[package]] name = "pyyaml" version = "6.0.3" @@ -2140,6 +2418,24 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f6/fa/f8aea7a28b0641f31d40dea42d7ef003fded31e184ef47db696bc74cd610/pyzmq-27.1.0-cp313-cp313t-win_arm64.whl", hash = "sha256:6bb54ca21bcfe361e445256c15eedf083f153811c37be87e0514934d6913061e", size = 561541, upload-time = "2025-09-08T23:08:42.668Z" }, ] +[[package]] +name = "qdrant-client" +version = "1.17.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "grpcio" }, + { name = "httpx", extra = ["http2"] }, + { name = "numpy" }, + { name = "portalocker" }, + { name = "protobuf" }, + { name = "pydantic" }, + { name = "urllib3" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/20/fb/c9c4cecf6e7fdff2dbaeee0de40e93fe495379eb5fe2775b184ea45315da/qdrant_client-1.17.0.tar.gz", hash = "sha256:47eb033edb9be33a4babb4d87b0d8d5eaf03d52112dca0218db7f2030bf41ba9", size = 344839, upload-time = "2026-02-19T16:03:17.069Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/c1/15/dfadbc9d8c9872e8ac45fa96f5099bb2855f23426bfea1bbcdc85e64ef6e/qdrant_client-1.17.0-py3-none-any.whl", hash = "sha256:f5b452c68c42b3580d3d266446fb00d3c6e3aae89c916e16585b3c704e108438", size = 390381, upload-time = "2026-02-19T16:03:15.486Z" }, +] + [[package]] name = "regex" version = "2026.2.28" @@ -2236,6 +2532,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/14/25/b208c5683343959b670dc001595f2f3737e051da617f66c31f7c4fa93abc/rich-14.3.3-py3-none-any.whl", hash = "sha256:793431c1f8619afa7d3b52b2cdec859562b950ea0d4b6b505397612db8d5362d", size = 310458, upload-time = "2026-02-19T17:23:13.732Z" }, ] +[[package]] +name = "safehttpx" +version = "0.1.7" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "httpx" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/89/d1/4282284d9cf1ee873607a46442da977fc3c985059315ab23610be31d5885/safehttpx-0.1.7.tar.gz", hash = "sha256:db201c0978c41eddb8bb480f3eee59dd67304fdd91646035e9d9a720049a9d23", size = 10385, upload-time = "2025-10-24T18:30:09.783Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/2e/a3/0f0b7d78e2f1eb9e8e1afbff1d2bff8d60144aee17aca51c065b516743dd/safehttpx-0.1.7-py3-none-any.whl", hash = "sha256:c4f4a162db6993464d7ca3d7cc4af0ffc6515a606dfd220b9f82c6945d869cde", size = 8959, upload-time = "2025-10-24T18:30:08.733Z" }, +] + [[package]] name = "scikit-learn" version = "1.8.0" @@ -2323,6 +2631,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/83/11/00d3c3dfc25ad54e731d91449895a79e4bf2384dc3ac01809010ba88f6d5/seaborn-0.13.2-py3-none-any.whl", hash = "sha256:636f8336facf092165e27924f223d3c62ca560b1f2bb5dff7ab7fad265361987", size = 294914, upload-time = "2024-01-25T13:21:49.598Z" }, ] +[[package]] +name = "semantic-version" +version = "2.10.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/7d/31/f2289ce78b9b473d582568c234e104d2a342fd658cc288a7553d83bb8595/semantic_version-2.10.0.tar.gz", hash = "sha256:bdabb6d336998cbb378d4b9db3a4b56a1e3235701dc05ea2690d9a997ed5041c", size = 52289, upload-time = "2022-05-26T13:35:23.454Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/6a/23/8146aad7d88f4fcb3a6218f41a60f6c2d4e3a72de72da1825dc7c8f7877c/semantic_version-2.10.0-py2.py3-none-any.whl", hash = "sha256:de78a3b8e0feda74cabc54aab2da702113e33ac9d9eb9d2389bcf1f58b7d9177", size = 15552, upload-time = "2022-05-26T13:35:21.206Z" }, +] + [[package]] name = "setuptools" version = "82.0.1" @@ -2509,6 +2826,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/f1/7b/ce1eafaf1a76852e2ec9b22edecf1daa58175c090266e9f6c64afcd81d91/stack_data-0.6.3-py3-none-any.whl", hash = "sha256:d5558e0c25a4cb0853cddad3d77da9891a08cb85dd9f9f91b9f8cd66e511e695", size = 24521, upload-time = "2023-09-30T13:58:03.53Z" }, ] +[[package]] +name = "starlette" +version = "0.52.1" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "anyio" }, + { name = "typing-extensions", marker = "python_full_version < '3.13'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/c4/68/79977123bb7be889ad680d79a40f339082c1978b5cfcf62c2d8d196873ac/starlette-0.52.1.tar.gz", hash = "sha256:834edd1b0a23167694292e94f597773bc3f89f362be6effee198165a35d62933", size = 2653702, upload-time = "2026-01-18T13:34:11.062Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/81/0d/13d1d239a25cbfb19e740db83143e95c772a1fe10202dda4b76792b114dd/starlette-0.52.1-py3-none-any.whl", hash = "sha256:0029d43eb3d273bc4f83a08720b4912ea4b071087a3b48db01b7c839f7954d74", size = 74272, upload-time = "2026-01-18T13:34:09.188Z" }, +] + [[package]] name = "studies" version = "0.1.0" @@ -2516,18 +2846,22 @@ source = { virtual = "." } dependencies = [ { name = "catboost" }, { name = "flask" }, + { name = "gradio" }, { name = "ipykernel" }, { name = "ipywidgets" }, { name = "langchain" }, { name = "langchain-core" }, { name = "langchain-huggingface" }, { name = "langchain-mistralai" }, + { name = "langchain-qdrant" }, { name = "matplotlib" }, { name = "numpy" }, { name = "opencv-python" }, { name = "pandas" }, { name = "pandas-stubs" }, { name = "plotly" }, + { name = "python-dotenv" }, + { name = "qdrant-client" }, { name = "scikit-learn" }, { name = "scipy" }, { name = "seaborn" }, @@ -2552,18 +2886,22 @@ dev = [ requires-dist = [ { name = "catboost", specifier = ">=1.2.10" }, { name = "flask", specifier = ">=3.1.3" }, + { name = "gradio", specifier = ">=6.9.0" }, { name = "ipykernel", specifier = ">=7.2.0" }, { name = "ipywidgets", specifier = ">=8.1.8" }, { name = "langchain", specifier = ">=1.2.10" }, { name = "langchain-core", specifier = ">=1.2.18" }, { name = "langchain-huggingface", specifier = ">=1.2.1" }, { name = "langchain-mistralai", specifier = ">=1.1.1" }, + { name = "langchain-qdrant", specifier = ">=1.1.0" }, { name = "matplotlib", specifier = ">=3.10.8" }, { name = "numpy", specifier = ">=2.4.3" }, { name = "opencv-python", specifier = ">=4.13.0.92" }, { name = "pandas", specifier = ">=3.0.1" }, { name = "pandas-stubs", specifier = ">=3.0.0.260204" }, { name = "plotly", specifier = ">=6.6.0" }, + { name = "python-dotenv", specifier = ">=1.2.2" }, + { name = "qdrant-client", specifier = ">=1.17.0" }, { name = "scikit-learn", specifier = ">=1.8.0" }, { name = "scipy", specifier = ">=1.17.1" }, { name = "seaborn", specifier = ">=0.13.2" }, @@ -2769,6 +3107,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/72/f4/0de46cfa12cdcbcd464cc59fde36912af405696f687e53a091fb432f694c/tokenizers-0.22.2-cp39-abi3-win_arm64.whl", hash = "sha256:9ce725d22864a1e965217204946f830c37876eee3b2ba6fc6255e8e903d5fcbc", size = 2612133, upload-time = "2026-01-05T10:45:17.232Z" }, ] +[[package]] +name = "tomlkit" +version = "0.13.3" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/cc/18/0bbf3884e9eaa38819ebe46a7bd25dcd56b67434402b66a58c4b8e552575/tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1", size = 185207, upload-time = "2025-06-05T07:13:44.947Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/bd/75/8539d011f6be8e29f339c42e633aae3cb73bffa95dd0f9adec09b9c58e85/tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0", size = 38901, upload-time = "2025-06-05T07:13:43.546Z" }, +] + [[package]] name = "torch" version = "2.10.0" @@ -2802,6 +3149,9 @@ dependencies = [ wheels = [ { url = "https://files.pythonhosted.org/packages/d3/54/a2ba279afcca44bbd320d4e73675b282fcee3d81400ea1b53934efca6462/torch-2.10.0-2-cp312-none-macosx_11_0_arm64.whl", hash = "sha256:13ec4add8c3faaed8d13e0574f5cd4a323c11655546f91fbe6afa77b57423574", size = 79498202, upload-time = "2026-02-10T21:44:52.603Z" }, { url = "https://files.pythonhosted.org/packages/ec/23/2c9fe0c9c27f7f6cb865abcea8a4568f29f00acaeadfc6a37f6801f84cb4/torch-2.10.0-2-cp313-none-macosx_11_0_arm64.whl", hash = "sha256:e521c9f030a3774ed770a9c011751fb47c4d12029a3d6522116e48431f2ff89e", size = 79498254, upload-time = "2026-02-10T21:44:44.095Z" }, + { url = "https://files.pythonhosted.org/packages/b3/7a/abada41517ce0011775f0f4eacc79659bc9bc6c361e6bfe6f7052a6b9363/torch-2.10.0-3-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:98c01b8bb5e3240426dcde1446eed6f40c778091c8544767ef1168fc663a05a6", size = 915622781, upload-time = "2026-03-11T14:17:11.354Z" }, + { url = "https://files.pythonhosted.org/packages/ab/c6/4dfe238342ffdcec5aef1c96c457548762d33c40b45a1ab7033bb26d2ff2/torch-2.10.0-3-cp313-cp313-manylinux_2_28_x86_64.whl", hash = "sha256:80b1b5bfe38eb0e9f5ff09f206dcac0a87aadd084230d4a36eea5ec5232c115b", size = 915627275, upload-time = "2026-03-11T14:16:11.325Z" }, + { url = "https://files.pythonhosted.org/packages/d8/f0/72bf18847f58f877a6a8acf60614b14935e2f156d942483af1ffc081aea0/torch-2.10.0-3-cp313-cp313t-manylinux_2_28_x86_64.whl", hash = "sha256:46b3574d93a2a8134b3f5475cfb98e2eb46771794c57015f6ad1fb795ec25e49", size = 915523474, upload-time = "2026-03-11T14:17:44.422Z" }, { url = "https://files.pythonhosted.org/packages/cc/af/758e242e9102e9988969b5e621d41f36b8f258bb4a099109b7a4b4b50ea4/torch-2.10.0-cp312-cp312-manylinux_2_28_aarch64.whl", hash = "sha256:5fd4117d89ffd47e3dcc71e71a22efac24828ad781c7e46aaaf56bf7f2796acf", size = 145996088, upload-time = "2026-01-21T16:24:44.171Z" }, { url = "https://files.pythonhosted.org/packages/23/8e/3c74db5e53bff7ed9e34c8123e6a8bfef718b2450c35eefab85bb4a7e270/torch-2.10.0-cp312-cp312-manylinux_2_28_x86_64.whl", hash = "sha256:787124e7db3b379d4f1ed54dd12ae7c741c16a4d29b49c0226a89bea50923ffb", size = 915711952, upload-time = "2026-01-21T16:23:53.503Z" }, { url = "https://files.pythonhosted.org/packages/6e/01/624c4324ca01f66ae4c7cd1b74eb16fb52596dce66dbe51eff95ef9e7a4c/torch-2.10.0-cp312-cp312-win_amd64.whl", hash = "sha256:2c66c61f44c5f903046cc696d088e21062644cbe541c7f1c4eaae88b2ad23547", size = 113757972, upload-time = "2026-01-21T16:24:39.516Z" }, @@ -2998,6 +3348,19 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/5e/49/4971affd9c62d26b3ff4a84dc6432275be72d9615d95f7bb9e027beeeed8/uv-0.10.9-py3-none-win_arm64.whl", hash = "sha256:47e18a0521d76293d4f60d129f520b18bddf1976b4a47b50f0fcb04fb6a9d40f", size = 22454171, upload-time = "2026-03-06T21:21:24.596Z" }, ] +[[package]] +name = "uvicorn" +version = "0.41.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "click" }, + { name = "h11" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/32/ce/eeb58ae4ac36fe09e3842eb02e0eb676bf2c53ae062b98f1b2531673efdd/uvicorn-0.41.0.tar.gz", hash = "sha256:09d11cf7008da33113824ee5a1c6422d89fbc2ff476540d69a34c87fab8b571a", size = 82633, upload-time = "2026-02-16T23:07:24.1Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/83/e4/d04a086285c20886c0daad0e026f250869201013d18f81d9ff5eada73a88/uvicorn-0.41.0-py3-none-any.whl", hash = "sha256:29e35b1d2c36a04b9e180d4007ede3bcb32a85fbdfd6c6aeb3f26839de088187", size = 68783, upload-time = "2026-02-16T23:07:22.357Z" }, +] + [[package]] name = "wasabi" version = "1.1.3"