diff --git a/.env_example b/.env_example index d20bbf73..a4a7aed0 100644 --- a/.env_example +++ b/.env_example @@ -1,2 +1,6 @@ OPENAI_API_KEY=YOUR_API_KEY_IF_YOU_USE_OPENAI GROQ_API_KEY=YOUR_API_KEY_IF_YOU_USE_GROQ +ANTHROPIC_API_KEY=YOUR_API_KEY_IF_YOU_USE_ANTHROPIC +GOOGLE_API_KEY=YOUR_API_KEY_IF_YOU_USE_GOOGLE +COHERE_API_KEY=YOUR_API_KEY_IF_YOU_USE_COHERE +HF_TOKEN=YOUR_API_KEY_IF_YOU_USE_HF diff --git a/.github/workflows/documentation.yml b/.github/workflows/documentation.yml new file mode 100644 index 00000000..6d251f96 --- /dev/null +++ b/.github/workflows/documentation.yml @@ -0,0 +1,68 @@ +name: Documentation + +on: + push: + branches: + - xiaoyi_doc # Ensure this is the branch where you commit documentation updates + +permissions: + contents: write + actions: read + +jobs: + build-and-deploy: + runs-on: ubuntu-latest + + steps: + - name: Checkout code + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5 + with: + python-version: '3.11' + + - name: Install Poetry + run: | + curl -sSL https://install.python-poetry.org | python3 - + echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Install dependencies using Poetry + run: | + poetry config virtualenvs.create false + poetry install + + - name: Build documentation using Makefile + run: | + echo "Building documentation from: $(pwd)" + ls -l # Debug: List current directory contents + poetry run make -C docs html + working-directory: ${{ github.workspace }} + + - name: List built documentation + run: | + find ./build/ -type f + working-directory: ${{ github.workspace }}/docs + + - name: Create .nojekyll file + run: | + touch .nojekyll + working-directory: ${{ github.workspace }}/docs/build + + - name: Deploy to GitHub Pages + uses: peaceiris/actions-gh-pages@v3 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + publish_branch: gh-pages + publish_dir: ./docs/build/ + user_name: github-actions[bot] + user_email: github-actions[bot]@users.noreply.github.com + + # - name: Debug Output + # run: | + # pwd # Print the current working directory + # ls -l # List files in the build directory + # cat ./source/conf.py # Show Sphinx config file for debugging + # working-directory: ${{ github.workspace }}/docs/build diff --git a/README.md b/README.md new file mode 100644 index 00000000..396534b5 --- /dev/null +++ b/README.md @@ -0,0 +1,102 @@ +# Introduction + +LightRAG is the `PyTorch` library for building large language model (LLM) applications. We help developers with both building and optimizing `Retriever`-`Agent`-`Generator` (RAG) pipelines. +It is light, modular, and robust. + +**PyTorch** + +```python +import torch +import torch.nn as nn + +class Net(nn.Module): + def __init__(self): + super(Net, self).__init__() + self.conv1 = nn.Conv2d(1, 32, 3, 1) + self.conv2 = nn.Conv2d(32, 64, 3, 1) + self.dropout1 = nn.Dropout2d(0.25) + self.dropout2 = nn.Dropout2d(0.5) + self.fc1 = nn.Linear(9216, 128) + self.fc2 = nn.Linear(128, 10) + + def forward(self, x): + x = self.conv1(x) + x = self.conv2(x) + x = self.dropout1(x) + x = self.dropout2(x) + x = self.fc1(x) + return self.fc2(x) + +**LightRAG** + +```python + +from lightrag.core import Component, Generator +from lightrag.components.model_client import GroqAPIClient +from lightrag.utils import setup_env #noqa + +class SimpleQA(Component): + def __init__(self): + super().__init__() + template = r""" + You are a helpful assistant. + + User: {{input_str}} + You: + """ + self.generator = Generator( + model_client=GroqAPIClient(), + model_kwargs={"model": "llama3-8b-8192"}, + template=template, + ) + + def call(self, query): + return self.generator({"input_str": query}) + + async def acall(self, query): + return await self.generator.acall({"input_str": query}) +``` + +## Simplicity + +Developers who are building real-world Large Language Model (LLM) applications are the real heroes. +As a library, we provide them with the fundamental building blocks with 100% clarity and simplicity. + +* Two fundamental and powerful base classes: Component for the pipeline and DataClass for data interaction with LLMs. +* We end up with less than two levels of subclasses. Class Hierarchy Visualization. +* The result is a library with bare minimum abstraction, providing developers with maximum customizability. + +Similar to the PyTorch module, our Component provides excellent visualization of the pipeline structure. + +``` +SimpleQA( + (generator): Generator( + model_kwargs={'model': 'llama3-8b-8192'}, + (prompt): Prompt( + template: + You are a helpful assistant. + + User: {{input_str}} + You: + , prompt_variables: ['input_str'] + ) + (model_client): GroqAPIClient() + ) +) +``` + +## Controllability + +Our simplicity did not come from doing 'less'. +On the contrary, we have to do 'more' and go 'deeper' and 'wider' on any topic to offer developers maximum control and robustness. + +* LLMs are sensitive to the prompt. We allow developers full control over their prompts without relying on API features such as tools and JSON format with components like Prompt, OutputParser, FunctionTool, and ToolManager. +* Our goal is not to optimize for integration, but to provide a robust abstraction with representative examples. See this in ModelClient and Retriever. +* All integrations, such as different API SDKs, are formed as optional packages but all within the same library. You can easily switch to any models from different providers that we officially support. + +## Future of LLM Applications + +On top of the easiness to use, we in particular optimize the configurability of components for researchers to build their solutions and to benchmark existing solutions. +Like how PyTorch has united both researchers and production teams, it enables smooth transition from research to production. +With researchers building on LightRAG, production engineers can easily take over the method and test and iterate on their production data. +Researchers will want their code to be adapted into more products too. diff --git a/class_hierarchy_edges.csv b/class_hierarchy_edges.csv new file mode 100644 index 00000000..a9348645 --- /dev/null +++ b/class_hierarchy_edges.csv @@ -0,0 +1,68 @@ +Component,ListParser +Component,JsonParser +Component,YamlParser +Component,ToolManager +Component,Prompt +Component,ModelClient +Component,Retriever +Component,FunctionTool +Component,Tokenizer +Component,Generator +Component,Embedder +Component,BatchEmbedder +Component,Sequential +Component,FunComponent +Component,ReActAgent +Component,OutputParser +Component,TextSplitter +Component,DocumentSplitter +Component,ToEmbeddings +Component,RetrieverOutputToContextStr +Component,DefaultLLMJudge +Component,LLMAugmenter +Generic,LocalDB +Generic,Retriever +Generic,GeneratorOutput +Generic,Parameter +Generic,Sample +Generic,Sampler +Generic,RandomSampler +Generic,ClassSampler +ModelClient,CohereAPIClient +ModelClient,TransformersClient +ModelClient,GroqAPIClient +ModelClient,GoogleGenAIClient +ModelClient,OpenAIClient +ModelClient,AnthropicAPIClient +Retriever,BM25Retriever +Retriever,PostgresRetriever +Retriever,RerankerRetriever +Retriever,LLMRetriever +Retriever,FAISSRetriever +Enum,DataClassFormatType +Enum,ModelType +Enum,DistanceToOperator +Enum,OptionalPackages +DataClass,EmbedderOutput +DataClass,GeneratorOutput +DataClass,RetrieverOutput +DataClass,FunctionDefinition +DataClass,Function +DataClass,FunctionExpression +DataClass,FunctionOutput +DataClass,StepOutput +DataClass,Document +DataClass,DialogTurn +DataClass,Instruction +DataClass,GeneratorStatesRecord +DataClass,GeneratorCallRecord +Generator,CoTGenerator +Generator,CoTGeneratorWithJsonOutput +OutputParser,YamlOutputParser +OutputParser,JsonOutputParser +OutputParser,ListOutputParser +OutputParser,BooleanOutputParser +Optimizer,BootstrapFewShot +Optimizer,LLMOptimizer +Sampler,RandomSampler +Sampler,ClassSampler diff --git a/developer_notes/generator.ipynb b/developer_notes/generator.ipynb index 67eb62a6..548ca532 100644 --- a/developer_notes/generator.ipynb +++ b/developer_notes/generator.ipynb @@ -74,10 +74,48 @@ }, { "cell_type": "code", - "execution_count": null, + "execution_count": 3, "metadata": {}, - "outputs": [], - "source": [] + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "GeneratorOutput(data='LightRAG is a light-based Real-time Anomaly Generator, which is a special type of anomaly detection system. It uses a combination of visual and statistical techniques to detect unusual patterns or outliers in a dataset in real-time, often for purposes such as identifying security threats, detecting fraud, or monitoring system performance. Would you like to know more about its applications or how it works?', error=None, usage=None, raw_response='LightRAG is a light-based Real-time Anomaly Generator, which is a special type of anomaly detection system. It uses a combination of visual and statistical techniques to detect unusual patterns or outliers in a dataset in real-time, often for purposes such as identifying security threats, detecting fraud, or monitoring system performance. Would you like to know more about its applications or how it works?')\n" + ] + } + ], + "source": [ + "from lightrag.core import Component, Generator, Prompt\n", + "from lightrag.components.model_client import GroqAPIClient\n", + "from lightrag.utils import setup_env\n", + "\n", + "\n", + "class SimpleQA(Component):\n", + " def __init__(self):\n", + " super().__init__()\n", + " template = r\"\"\"\n", + " You are a helpful assistant.\n", + " \n", + " User: {{input_str}}\n", + " You:\n", + " \"\"\"\n", + " self.generator = Generator(\n", + " model_client=GroqAPIClient(), model_kwargs={\"model\": \"llama3-8b-8192\"}, template=template\n", + " )\n", + "\n", + " def call(self, query):\n", + " return self.generator({\"input_str\": query})\n", + "\n", + " async def acall(self, query):\n", + " return await self.generator.acall({\"input_str\": query})\n", + "\n", + "\n", + "qa = SimpleQA()\n", + "answer = qa(\"What is LightRAG?\")\n", + "\n", + "print(answer)" + ] } ], "metadata": { diff --git a/developer_notes/generator_note.py b/developer_notes/generator_note.py new file mode 100644 index 00000000..5d05f31a --- /dev/null +++ b/developer_notes/generator_note.py @@ -0,0 +1,30 @@ +from lightrag.core import Component, Generator +from lightrag.components.model_client import GroqAPIClient +from lightrag.utils import setup_env # noqa + + +class SimpleQA(Component): + def __init__(self): + super().__init__() + template = r""" + You are a helpful assistant. + + User: {{input_str}} + You: + """ + self.generator = Generator( + model_client=GroqAPIClient(), + model_kwargs={"model": "llama3-8b-8192"}, + template=template, + ) + + def call(self, query): + return self.generator({"input_str": query}) + + async def acall(self, query): + return await self.generator.acall({"input_str": query}) + + +qa = SimpleQA() +answer = qa("What is LightRAG?") +print(qa) diff --git a/docs/requirements.txt b/docs/requirements.txt index 428413ff..e59cca03 100644 --- a/docs/requirements.txt +++ b/docs/requirements.txt @@ -1,4 +1,11 @@ -pydata-sphinx-theme==0.15.2 -Sphinx==7.3.7 -sphinx_design==0.6.0 -sphinx-copybutton==0.5.2 \ No newline at end of file +pydata-sphinx-theme==0.15.3 +sphinx-design==0.6.0 +sphinx-copybutton==0.5.2 +sphinx==7.3.7 +nbsphinx==0.9.4 +nbconvert==7.16.4 +PyYAML +readthedocs-sphinx-search==0.3.2 +numpy +tqdm +tiktoken \ No newline at end of file diff --git a/docs/source/_static/class_hierarchy.html b/docs/source/_static/class_hierarchy.html new file mode 100644 index 00000000..f6f6256f --- /dev/null +++ b/docs/source/_static/class_hierarchy.html @@ -0,0 +1,155 @@ + + + + + + + + + +
+

+
+ + + + + + +
+

+
+ + + + + +
+ + +
+
+ + + + + + + diff --git a/docs/source/_static/css/custom.css b/docs/source/_static/css/custom.css index 8f4f9369..be7a7db0 100644 --- a/docs/source/_static/css/custom.css +++ b/docs/source/_static/css/custom.css @@ -5,12 +5,30 @@ --pst-color-logo: #2EB5EB; --bs-gray-500:#adb5bd; + +} +.theme-version { + display: none; +} +.bd-sidebar-primary { + width: 100%; /* Full width by default */ +} + +/* Adjust width for larger screens */ +@media (min-width: 768px) { /* Example breakpoint for tablets and larger */ + .bd-sidebar-primary { + width: 270px; /* Adjust the width for larger screens */ } +} + +/* .copyright { + text-align: center; +} */ p { font-size: 0.9em; margin-bottom: 1.15rem; } - + html[data-theme=light] { --pst-color-secondary: #3d3d3d; /*change the secondary color, header link to gray */ --pst-color-link-hover: #25262; /*change the side bar link color to black */ @@ -27,7 +45,7 @@ h1{ font-size: 2rem; /* make the h1 in the code smaller */ } /* .bd-page-width { - max-width: 100%; + max-width: 100%; } */ .sig-name { diff --git a/docs/source/apis/components/index.rst b/docs/source/apis/components/index.rst index 0fef9a70..3a311617 100644 --- a/docs/source/apis/components/index.rst +++ b/docs/source/apis/components/index.rst @@ -9,9 +9,10 @@ Overview components.agent components.model_client + components.data_process .. components.reasoning - + components.retriever components.output_parsers @@ -37,6 +38,13 @@ Model Clients components.model_client +Data Process +---------------- +.. toctree:: + :maxdepth: 1 + + components.data_process + .. Embedders .. --------- .. .. toctree:: diff --git a/docs/source/apis/core/index.rst b/docs/source/apis/core/index.rst index c87b38b8..dc5dc194 100644 --- a/docs/source/apis/core/index.rst +++ b/docs/source/apis/core/index.rst @@ -7,22 +7,19 @@ Overview ---------- .. autosummary:: - core.base_data_class - core.model_client + core.base_data_class core.component - core.data_components core.db core.default_prompt_template - core.document_splitter core.embedder core.functional core.generator core.memory + core.model_client core.parameter core.prompt_builder core.retriever core.string_parser - core.text_splitter core.tokenizer core.func_tool core.tool_manager @@ -51,8 +48,6 @@ Data Handling core.base_data_class core.types - - core.data_components core.db Prompts and Templates @@ -63,10 +58,10 @@ Prompts and Templates core.default_prompt_template core.prompt_builder -Document Processing -------------------- -.. toctree:: - :maxdepth: 1 +.. Document Processing +.. ------------------- +.. .. toctree:: +.. :maxdepth: 1 .. core.document_splitter core.text_splitter diff --git a/docs/source/apis/index.rst b/docs/source/apis/index.rst index 1e52b879..6b4af1d2 100644 --- a/docs/source/apis/index.rst +++ b/docs/source/apis/index.rst @@ -17,7 +17,6 @@ The core section of the LightRAG API documentation provides detailed information core.data_components core.db core.default_prompt_template - core.document_splitter core.embedder core.functional core.generator @@ -26,7 +25,6 @@ The core section of the LightRAG API documentation provides detailed information core.prompt_builder core.retriever core.string_parser - core.text_splitter core.tokenizer core.func_tool core.tool_manager @@ -42,9 +40,9 @@ The components section of the LightRAG API documentation outlines the detailed s components.agent components.model_client - + componnets.data_process .. components.reasoning - + components.retriever components.output_parsers diff --git a/docs/source/conf.py b/docs/source/conf.py index 986d5c25..59eb52ba 100644 --- a/docs/source/conf.py +++ b/docs/source/conf.py @@ -21,21 +21,12 @@ # sys.path.insert(0, dir[0]) # # print(dir[0]) -import lightrag - -import lightrag.components -import lightrag.core -import lightrag.eval -import lightrag.utils -import lightrag.tracing -import lightrag.optim # -- Project information ----------------------------------------------------- project = "LightRAG" -copyright = "2024, SylphAI" -author = "SylphAI" - +copyright = "2024, SylphAI, Inc" +author = "SylphAI, Inc" # -- General configuration --------------------------------------------------- @@ -56,13 +47,15 @@ "sphinx_design", "sphinx_copybutton", "nbsphinx", - "sphinx_search.extension" + "sphinx_search.extension", # "myst_nb", # "sphinx.builders.changes", # 'recommonmark', # 'myst_parser' ] +html_show_sphinx = False + # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] @@ -135,4 +128,6 @@ def setup(app): - app.add_css_file("css/custom.css") # Add custom CSS file to the Sphinx configuration + app.add_css_file( + "css/custom.css" + ) # Add custom CSS file to the Sphinx configuration diff --git a/docs/source/developer_notes/base_data_class.rst b/docs/source/developer_notes/base_data_class.rst index 1ece815b..966d155e 100644 --- a/docs/source/developer_notes/base_data_class.rst +++ b/docs/source/developer_notes/base_data_class.rst @@ -495,11 +495,11 @@ The output will be: } } question: - question: What is the capital of France? - metadata: {} + question: What is the capital of France? + metadata: {} label: 1 metadata: - key: value + key: value TrecData2(question=Question(question='What is the capital of France?', metadata={}), label=1, metadata={'key': 'value'}) True @@ -569,6 +569,7 @@ You can simply do a bit customization to map the dataset's key to the field name .. code-block:: python + @dataclass class OutputFormat(DataClass): thought: str = field( metadata={ diff --git a/docs/source/developer_notes/class_hierarchy.rst b/docs/source/developer_notes/class_hierarchy.rst new file mode 100644 index 00000000..80a32bb1 --- /dev/null +++ b/docs/source/developer_notes/class_hierarchy.rst @@ -0,0 +1,6 @@ +LightRAG Class Hierarchy +============================= + +.. raw:: html + + diff --git a/docs/source/developer_notes/component.rst b/docs/source/developer_notes/component.rst index f06706af..365e970d 100644 --- a/docs/source/developer_notes/component.rst +++ b/docs/source/developer_notes/component.rst @@ -1,5 +1,10 @@ Component ============ +.. admonition:: Author + :class: highlight + + `Li Yin `_ + What you will learn? 1. What is ``Component`` and why is it designed this way? diff --git a/docs/source/developer_notes/db.rst b/docs/source/developer_notes/db.rst index a1a754bd..8b20e555 100644 --- a/docs/source/developer_notes/db.rst +++ b/docs/source/developer_notes/db.rst @@ -1,7 +1,13 @@ Data & RAG ==================== - The purpose of this note is to provide an overview on data, data modeling, and data storage in LLM applications along with how LightRAG works with data. +.. admonition:: Author + :class: highlight + + `Li Yin `_ + + +The purpose of this note is to provide an overview on data, data modeling, and data storage in LLM applications along with how LightRAG works with data. We will conver: * Data models on how to represent important data. diff --git a/docs/source/developer_notes/embedder.rst b/docs/source/developer_notes/embedder.rst index 4e71c74b..a9d040b1 100644 --- a/docs/source/developer_notes/embedder.rst +++ b/docs/source/developer_notes/embedder.rst @@ -1,5 +1,10 @@ Embedder ============ +.. admonition:: Author + :class: highlight + + `Li Yin `_ + What you will learn? 1. What is ``Embedder`` and why is it designed this way? @@ -62,10 +67,10 @@ We find the ``model_kwargs`` from the OpenAI API documentation. We setup `query` **Visualize structure**: we use ``print(embedder)``. The output will be: -.. code-block:: +.. code-block:: Embedder( - model_kwargs={'model': 'text-embedding-3-small', 'dimensions': 256, 'encoding_format': 'float'}, + model_kwargs={'model': 'text-embedding-3-small', 'dimensions': 256, 'encoding_format': 'float'}, (model_client): OpenAIClient() ) @@ -140,7 +145,7 @@ If we want to decreate the embedding dimension to only 256 to save memory, we ca new_embedding = normalize_vector(new_embedding) embedding.embedding = new_embedding return output - + def _extra_repr(self) -> str: repr_str = f"old_dim={self.old_dim}, new_dim={self.new_dim}, normalize={self.normalize}" return repr_str @@ -159,10 +164,10 @@ Putting it all together, we can create a new embedder with the output processor. The structure looks like: -.. code-block:: +.. code-block:: Embedder( - model_kwargs={'model': 'thenlper/gte-base'}, + model_kwargs={'model': 'thenlper/gte-base'}, (model_client): TransformersClient() (output_processors): DecreaseEmbeddingDim(old_dim=768, new_dim=256, normalize=True) ) @@ -188,7 +193,7 @@ The BatchEmbedder orchestrates the ``Embedder`` and handles the batching process .. code-block:: python from lightrag.core.embedder import BatchEmbedder - + batch_embedder = BatchEmbedder(embedder=local_embedder, batch_size=100) queries = [query] * 1000 @@ -216,4 +221,4 @@ The BatchEmbedder orchestrates the ``Embedder`` and handles the batching process - :class:`core.types.Embedding` - :class:`components.model_client.openai_client.OpenAIClient` - :class:`components.model_client.transformers_client.TransformersClient` - - :class:`core.functional.normalize_vector` \ No newline at end of file + - :class:`core.functional.normalize_vector` diff --git a/docs/source/developer_notes/evaluation.rst b/docs/source/developer_notes/evaluation.rst index a5f563ea..9b9315eb 100644 --- a/docs/source/developer_notes/evaluation.rst +++ b/docs/source/developer_notes/evaluation.rst @@ -1,7 +1,12 @@ -A Guideline on LLM Evaluation +LLM Evaluation ==================================== -As the saying goes, "You cannot improve what you cannot measure". This is especially true in the context of LLMs, which have become increasingly popular due to their impressive performance on a wide range of tasks. Evaluating LLMs and their applications is crucial in both research and production to understand their capabilities and limitations. +.. admonition:: Author + :class: highlight + + `Meng Liu `_ + +"You cannot improve what you cannot measure". This is especially true in the context of LLMs, which have become increasingly popular due to their impressive performance on a wide range of tasks. Evaluating LLMs and their applications is crucial in both research and production to understand their capabilities and limitations. Overall, such evaluation is a complex and multifaceted process. Below, we provide a guideline for evaluating LLMs and their applications, incorporating aspects outlined by *Chang et al.* [1]_: * **What to evaluate**: the tasks and capabilities that LLMs are evaluated on. diff --git a/docs/source/developer_notes/generator.rst b/docs/source/developer_notes/generator.rst index 00625a47..ee7beaab 100644 --- a/docs/source/developer_notes/generator.rst +++ b/docs/source/developer_notes/generator.rst @@ -1,10 +1,16 @@ .. _generator: -Generator +Generator ========= + +.. admonition:: Author + :class: highlight + + `Li Yin `_ + *The Center of it All* -Generator is the most essential functional component in LightRAG. +Generator is the most essential functional component in LightRAG. It is a user-facing orchestration component with a simple and unified interface for LLM prediction. It orchestrates the following components along with their required arguments: @@ -20,7 +26,7 @@ GeneratorOutput ^^^^^^^^^^^^^^^ Different from all other components, we can not alway enforce LLM to output the right format. We in particular created a :class:`core.types.GeneratorOutput` (a subclass of ``DataClass``) to store `data` (parsed response), `error` (error message if either the model inference SDKs fail or the output parsing fail) and `raw_response` (raw string response for reference) for any LLM predictions. -It is in developers' hands to process the output accordingly. +It is in developers' hands to process the output accordingly. GeneratorInAction ^^^^^^^^^^^^^^^^^ @@ -38,7 +44,7 @@ In particular, we provide two tracing methods to help you develop and improve th to lose track of the prompt changes when your current change actually makes the performance much worse. We created a `GeneratorStateLogger` to handle the logging and saving into json files. To further simplify developers's process, -we provides a class decorator `trace_generator_states` where a single line of code can be added to any of your task component. +we provides a class decorator `trace_generator_states` where a single line of code can be added to any of your task component. It will automatically track any attributes of type `Generator`. .. code-block:: python @@ -54,7 +60,7 @@ It will automatically track any attributes of type `Generator`. self.generator_2 = Generator(...) def call(...): -In default, a dir from the current working directory will be created to store the log files. +In default, a dir from the current working directory will be created to store the log files. The project name in defaul is `SimpleQA` and the log file will be named as `generator_state_trace.json` where both the `generator` and `generator_2` will be logged. The structure of log directory is as follows: @@ -147,7 +153,7 @@ Here is an example log file: } ] } - + 2. Trace all failed LLM predictions for further improvement. Similarly, :class:`tracing.generator_call_logger.GeneratorCallLogger` is created to log generator call input arguments and output results. diff --git a/docs/source/developer_notes/index.rst b/docs/source/developer_notes/index.rst index 28cb8c41..0029d1da 100644 --- a/docs/source/developer_notes/index.rst +++ b/docs/source/developer_notes/index.rst @@ -9,9 +9,11 @@ Developer Notes Learn LightRAG design phisolophy and the `why` and `how-to` (customize and integrate) behind each core part within the LightRAG library. This is our tutorials before you move ahead to build use cases (LLM applications) end to end. -.. note:: +.. raw:: - You can read interchangably between :ref:`Use Cases `. + .. note:: + + You can read interchangably between :ref:`Use Cases `. @@ -26,26 +28,26 @@ This is our tutorials before you move ahead to build use cases (LLM application .. :width: 200px LightRAG library focus on providing building blocks for developers to **build** and **optimize** the `task pipeline`. -We have clear design phisolophy: +We have clear design phisolophy: :doc:`lightrag_design_philosophy`. -.. toctree:: - :maxdepth: 1 - :caption: Introduction +.. :maxdepth: 1 +.. :hidden: - lightrag_design_philosophy +.. lightrag_design_philosophy - llm_intro +.. llm_intro -Building -============================= + +Building +------------------- Base classes ---------------- +~~~~~~~~~~~~~~~~~~~~~~ Code path: ``lightrag.core``. .. list-table:: @@ -73,9 +75,10 @@ Code path: ``lightrag.core``. base_data_class RAG Essentials -------------------- +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RAG components -~~~~~~~~~~~~~~~~~~~~~~ +^^^^^^^^^^^^^^^^^^^ + Code path: ``lightrag.core``. For abstract classes: @@ -100,8 +103,8 @@ Code path: ``lightrag.core``. For abstract classes: * - :doc:`retriever` - The base class for all retrievers who in particular retrieve relevant documents from a given database to add **context** to the generator. -Data, Processing, and storage -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Data Pipeline and Storage +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Data Processing: including transformer, pipeline, and storage. Code path: ``lightrag.components.data_process``, ``lightrag.core.db``, and ``lightrag.database``. Components work on a sequence of ``Document`` and return a sequence of ``Document``. @@ -139,7 +142,7 @@ Components work on a sequence of ``Document`` and return a sequence of ``Documen Agent Essentials ------------------------------ +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Agent in ``components.agent`` is LLM great with reasoning, planning, and using tools to interact and accomplish tasks. .. list-table:: @@ -186,7 +189,7 @@ Agent in ``components.agent`` is LLM great with reasoning, planning, and using t Optimizing -============================= +------------------- Datasets and Evaulation @@ -213,7 +216,7 @@ Optimizer & Trainer Logging & Tracing & Configurations -============================= +------------------------------------ Code path: ``lightrag.utils``. .. list-table:: diff --git a/docs/source/developer_notes/model_client.rst b/docs/source/developer_notes/model_client.rst index 98b21bea..abad8f02 100644 --- a/docs/source/developer_notes/model_client.rst +++ b/docs/source/developer_notes/model_client.rst @@ -1,5 +1,11 @@ ModelClient ============ + +.. admonition:: Author + :class: highlight + + `Li Yin `_ + What you will learn? 1. What is ``ModelClient`` and why is it designed this way? @@ -23,7 +29,7 @@ Because so, by switching off ``ModelClient`` in a ``Generator`` or ``Embedder`` Model Inference SDKs ------------------------ -With cloud API providers like OpenAI, Groq, Anthropic, it often comes with a `sync` and an `async` client via their SDKs. +With cloud API providers like OpenAI, Groq, Anthropic, it often comes with a `sync` and an `async` client via their SDKs. For example: .. code-block:: python @@ -33,7 +39,7 @@ For example: sync_client = OpenAI() async_client = AsyncOpenAI() - # sync call using APIs + # sync call using APIs response = sync_client.chat.completions.create(...) For local models, such as using `huggingface transformers`, you need to create this model inference SDKs yourself. @@ -141,7 +147,7 @@ This is how `OpenAIClient` implements these methods along with ``__init__`` meth class OpenAIClient(ModelClient): def __init__(self, api_key: Optional[str] = None): - + super().__init__() self._api_key = api_key self.sync_client = self.init_sync_client() @@ -175,7 +181,7 @@ This is how ``TransformerClient`` does the same thing: } def init_sync_client(self): - return TransformerEmbedder() + return TransformerEmbedder() Second. we use `convert_inputs_to_api_kwargs` for subclass to convert LightRAG inputs into the `api_kwargs` (SDKs arguments). @@ -202,7 +208,7 @@ This is how `OpenAIClient` implements this method: model_kwargs: Dict = {}, model_type: ModelType = ModelType.UNDEFINED, ) -> Dict: - + final_model_kwargs = model_kwargs.copy() if model_type == ModelType.EMBEDDER: if isinstance(input, str): @@ -314,8 +320,8 @@ Here is an example to use ``OpenAIClient`` directly, first on LLM model: prompt = f"User: {query}\n" model_kwargs = {"model": "gpt-3.5-turbo", "temperature": 0.5, "max_tokens": 100} - api_kwargs = openai_client.convert_inputs_to_api_kwargs(input=prompt, - model_kwargs=model_kwargs, + api_kwargs = openai_client.convert_inputs_to_api_kwargs(input=prompt, + model_kwargs=model_kwargs, model_type=model_type) print(f"api_kwargs: {api_kwargs}") @@ -325,10 +331,10 @@ Here is an example to use ``OpenAIClient`` directly, first on LLM model: The output will be: -.. code-block:: +.. code-block:: api_kwargs: {'model': 'gpt-3.5-turbo', 'temperature': 0.5, 'max_tokens': 100, 'messages': [{'role': 'system', 'content': 'User: What is the capital of France?\n'}]} - response_text: The capital of France is Paris. + response_text: The capital of France is Paris. Then on Embedder model: diff --git a/docs/source/developer_notes/optimizer.rst b/docs/source/developer_notes/optimizer.rst index e6201a16..d26f6ad0 100644 --- a/docs/source/developer_notes/optimizer.rst +++ b/docs/source/developer_notes/optimizer.rst @@ -1,2 +1,2 @@ -Optimizer - The Future of LLM applications -========================================================== \ No newline at end of file +Optimizer +========================================================== diff --git a/docs/source/developer_notes/prompt.rst b/docs/source/developer_notes/prompt.rst index d5624f4e..2c73bc85 100644 --- a/docs/source/developer_notes/prompt.rst +++ b/docs/source/developer_notes/prompt.rst @@ -1,9 +1,14 @@ Prompt ============ +.. admonition:: Author + :class: highlight + + `Li Yin `_ + We strick to maximize developers' control towards the final experience and performance, simplify the development process, and minimize the token consumption. For the major chat models, we eventually will only send two messages to the model: the system message and the user message. The user message is simple, -often you have a message `{'role': 'user', 'content': 'Hello, how are you?'}`. The system message is more complex, it contains the task description, tools, examples, chat history, context, and +often you have a message `{'role': 'user', 'content': 'Hello, how are you?'}`. The system message is more complex, it contains the task description, tools, examples, chat history, context, and intermediate step history from agents. Prompt template @@ -11,7 +16,7 @@ Prompt template Our `DEFAULT_LIGHTRAG_SYSTEM_PROMPT` templates the system prompt with 7 important sections. We leverage `jinjia2` template for **programmable prompt** right along with string. -The default template comes with 7 variables: `task_desc_str`, `output_format_str`, `tools_str`, `examples_str`, `chat_history_str`, `context_str`, and `steps_str`. +The default template comes with 7 variables: `task_desc_str`, `output_format_str`, `tools_str`, `examples_str`, `chat_history_str`, `context_str`, and `steps_str`. A jinjia2 template will rendered with :ref:`Prompt` class. If some fields being empty, that section will be empty in the final prompt string. @@ -54,7 +59,7 @@ A jinjia2 template will rendered with :ref:`Prompt` class. {% endif %} """ -Across our library, here our advanced features: +Across our library, here our advanced features: - Various output formats where the `output_format_str` variable is used to pass the output format to the model. @@ -108,19 +113,19 @@ Prompt and Special Tokens context ---------------------------------- -Each section other than `task_desc_str` is encapulated in a special token. Different model can have different special tokens. +Each section other than `task_desc_str` is encapulated in a special token. Different model can have different special tokens. Here is one example of `Llama3 Documentation `_ prompts formatted with special tokens: -input string to the LLM model and minimize the token consumption. +input string to the LLM model and minimize the token consumption. We enable advanced features without relying on API provider's prompt manipulation such as `OpenAI`'s tools or assistant APIs. -.. code-block:: +.. code-block:: :linenos: <|begin_of_text|><|start_header_id|>system<|end_header_id|> You are a helpful AI assistant for travel tips and recommendations<|eot_id|> - + <|start_header_id|>user<|end_header_id|> What can you help me with?<|eot_id|> @@ -164,6 +169,3 @@ Output yaml or json format can lead to different performance. We have better luc Resources: 1. `Jinja2`: - - - diff --git a/docs/source/developer_notes/retriever.rst b/docs/source/developer_notes/retriever.rst index 5ef08560..d99201f5 100644 --- a/docs/source/developer_notes/retriever.rst +++ b/docs/source/developer_notes/retriever.rst @@ -1,6 +1,11 @@ Retriever ============ +.. admonition:: Author + :class: highlight + + `Li Yin `_ + Context ------------------ diff --git a/docs/source/developer_notes/text_splitter.rst b/docs/source/developer_notes/text_splitter.rst index ff7afc9d..b6904110 100644 --- a/docs/source/developer_notes/text_splitter.rst +++ b/docs/source/developer_notes/text_splitter.rst @@ -7,13 +7,13 @@ Text Splitter In this tutorial, we will learn: -#. Why do we need the ``TextSplitter`` +#. TextSplitter Overview -#. How does ``LightRAG's TextSplitter`` work +#. How does it work -#. How to implement ``LightRAG's TextSplitter`` +#. How to use it -Why do we need the ``TextSplitter`` +TextSplitter Overview ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LLMs’s context window is limited and the performance often drops with very long and nonsense input. Shorter content is more manageable and fits memory constraint. @@ -22,195 +22,97 @@ The goal of the text splitter is to chunk large data into smaller ones, potentia The ``TextSplitter`` is designed to efficiently process and chunk **plain text**. It leverages configurable separators to facilitate the splitting of :obj:`document object ` into smaller manageable document chunks. -How does ``LightRAG's TextSplitter`` work +How does it work ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -``TextSplitter`` supports 2 types of splitting. - -* Type 1: Specify the exact text splitting point such as space<" "> and periods<".">. It is intuitive: -"Hello, world!" -> ["Hello, " ,"world!"] - -* Type 2: Use :class:`tokenizer `. It works as: -"Hello, world!" -> ['Hello', ',', ' world', '!'] -This aligns with how models see text in the form of tokens. (`Reference `_) - -Simple text splitting can underestimate the number of tokens. Tokenizer reflects the real token numbers the models take in. -But the Tokenizer here only works on world level. - -* **Overview**: ``TextSplitter`` first utilizes ``split_by`` to specify the text-splitting criterion and breaks the long text into smaller texts. Then we create a sliding window with length= ``chunk_size``. It moves at step= ``chunk_size`` - ``chunk_overlap``. -The texts inside each window will get concatenated to a smaller chunk. The generated chunks from the splitted text will be returned. +The texts inside each window will get merged to a smaller chunk. The generated chunks from the splitted text will be returned. -Here are some Definitions: +**Splitting Types** -* **Definitions** +``TextSplitter`` supports 2 types of splitting. -``split_by``: Specifies the text-splitting criterion using predefined keys like "word", "sentence", "page", "passage", and "token". The splitter utilizes the corresponding separator from the ``SEPARATORS`` dictionary. - -``SEPARATORS``: Maps ``split_by`` criterions to their exact text separators, e.g., spaces<" "> for "word" or periods<"."> for "sentence". +* **Type 1:** Specify the exact text splitting point such as space<" "> and periods<".">. It is intuitive, for example, split_by "word": -Usage: **SEPARATORS[``split_by``]=separator** +:: -.. note:: - For option ``token``, its separator is "" because we directly split by a tokenizer, instead of text point. - -* ``split_by`` specifies the separator by which the document should be split, i.e. the smallest unit during splitting. -For Type 1 splitting, we apply ``Python str.split()`` to break the text. -Check the following table for ``split_by`` options: - -.. list-table:: Text Splitting Options - :widths: 10 15 75 - :header-rows: 1 + "Hello, world!" -> ["Hello, " ,"world!"] - * - ``split_by`` Option - - Actual Separator - - Example - * - **page** - - ``\f`` - - ``Hello, world!\fNew page starts here.`` to ``['Hello, world!\x0c', 'New page starts here.']`` - * - **passage** - - ``\n\n`` - - ``Hello, world!\n\nNew paragraph starts here`` to ``['Hello, world!\n\n', 'New paragraph starts here.']`` - * - **sentence** - - ``.`` - - ``Hello, world. This is LightRAG.`` to ``['Hello, world.', ' This is LightRAG.', '']`` - * - **word** - - ```` - - ``Hello, world. This is LightRAG.`` to ``['Hello, ', 'world. ', 'This ', 'is ', 'LightRAG.']`` +* **Type 2:** Use :class:`tokenizer `. It works as: -* ``chunk_size`` is the the maximum number of units in each chunk. +:: -* ``chunk_overlap`` is the number of units that each chunk should overlap. Including context at the borders prevents sudden meaning shift in text between sentences/context, especially in sentiment analysis. + "Hello, world!" -> ['Hello', ',', ' world', '!'] -Here is an example of how ``chunk_size`` works with ``chunk_overlap``: +This aligns with how models see text in the form of tokens (`Reference `_), +Tokenizer reflects the real token numbers the models take in and helps the developers control budgets. -.. code-block:: python - from lightrag.core.text_splitter import TextSplitter - from lightrag.core.types import Document +**Definitions** + +* **split_by** specifies the split rule, i.e. the smallest unit during splitting. We support ``"word"``, ``"sentence"``, ``"page"``, ``"passage"``, and ``"token"``. The splitter utilizes the corresponding separator from the ``SEPARATORS`` dictionary. +For Type 1 splitting, we apply ``Python str.split()`` to break the text. - # configure the splitter setting - text_splitter_settings = { - "split_by": "word", - "chunk_size": 5, - "chunk_overlap": 2, - } +* **SEPARATORS**: Maps ``split_by`` criterions to their exact text separators, e.g., spaces <" "> for "word" or periods <"."> for "sentence". - # set up the document splitter - text_splitter = TextSplitter( - split_by=text_splitter_settings["split_by"], - chunk_size=text_splitter_settings["chunk_size"], - chunk_overlap=text_splitter_settings["chunk_overlap"], - ) - doc1 = Document( - text="Hello, this is lightrag. Please implement your splitter here.", - id="doc1", - ) +.. note:: + For option ``token``, its separator is "" because we directly split by a tokenizer, instead of text point. - documents = [doc1] +* **chunk_size** is the the maximum number of units in each chunk. - splitted_docs = (text_splitter.call(documents=documents)) +* **chunk_overlap** is the number of units that each chunk should overlap. Including context at the borders prevents sudden meaning shift in text between sentences/context, especially in sentiment analysis. - for doc in splitted_docs: - print(doc.text) - # Output: - # Hello, this is lightrag. Please - # lightrag. Please implement your splitter - # your splitter here. -In this case, when splitting by ``word`` with ``chunk_size``=5 and ``chunk_overlap``=2, -each chunk will repeat 2 words from the previous chunk. These 2 words are set by ``chunk_overlap``. -This means each chunk has ``5-2=3`` word(split unit) difference compared with its previous. +Here are examples of how ``split_by``, ``chunk_size`` works with ``chunk_overlap``. +Document Text: -.. note:: - ``chunk_overlap`` should always be smaller than ``chunk_size``, otherwise the window won't move and the splitting stucks. - - -One more example on ``split_by=token``: +:: + + Hello, this is lightrag. Please implement your splitter here. -.. code-block:: python - # configure the splitter setting - text_splitter_settings = { - "split_by": "token", - "chunk_size": 5, - "chunk_overlap": 2, - } - - # set up the document splitter - text_splitter = TextSplitter( - ... - ) - doc1 = Document( - text="Hello, this is lightrag. Please implement your splitter here.", - id="doc1", - ) - documents = [doc1] - splitted_docs = (text_splitter.call(documents=documents)) +.. list-table:: Chunking Example Detailed + :widths: 15 15 15 55 + :header-rows: 1 - for doc in splitted_docs: - print(doc.text) - # Output: - # Hello, this is lightrag. Please - # lightrag. Please implement your splitter - # your splitter here. -In this case, when splitting by ``word`` with ``chunk_size``=5 and ``chunk_overlap``=2, + * - Split By + - Chunk Size + - Chunk Overlap + - Resulting Chunks + * - word + - 5 + - 2 + - "Hello, this is lightrag. Please", "lightrag. Please implement your splitter", "your splitter here." + * - sentence + - 1 + - 0 + - "Hello, this is lightrag.", "Please implement your splitter here." + * - token + - 5 + - 2 + - "Hello, this is l", "is lightrag.", "trag. Please implement your", "implement your splitter here." + +When splitting by ``word`` with ``chunk_size`` = 5 and ``chunk_overlap`` = 2, each chunk will repeat 2 words from the previous chunk. These 2 words are set by ``chunk_overlap``. This means each chunk has ``5-2=3`` word(split unit) difference compared with its previous. -.. note:: - ``chunk_overlap`` should always be smaller than ``chunk_size``, otherwise the window won't move and the splitting stucks. - - -One more example on ``split_by=token``: - -.. code-block:: python - # configure the splitter setting - text_splitter_settings = { - "split_by": "token", - "chunk_size": 5, - "chunk_overlap": 2, - } - - # set up the document splitter - text_splitter = TextSplitter( - ... - ) - - doc1 = Document( - text="Hello, this is lightrag. Please implement your splitter here.", - id="doc1", - ) - documents = [doc1] - splitted_docs = (text_splitter.call(documents=documents)) - for doc in splitted_docs: - print(doc.text) - # Output: - # Hello, this is l - # is lightrag. - # trag. Please implement your - # implement your splitter here. When splitting using tokenizer, each chunk still keeps 5 tokens. -Since ``lightrag`` -> ['l', 'igh', 'trag'], the second chunk is actually ``is`` + ``l`` + ``igh`` + ``trag`` + ``.``. +For example, the tokenizer transforms ``lightrag`` to ['l', 'igh', 'trag']. So the second chunk is actually ``is`` + ``l`` + ``igh`` + ``trag`` + ``.``. .. note:: - The punctuation is considered as a token. - -This splitting aligns with how models see text in the form of tokens. (`Reference `_) - -Simple text splitting(Type 1) can underestimate the number of tokens. Tokenizer reflects the real token numbers the models take in. -But the Tokenizer here only works at world level. + ``chunk_overlap`` should always be smaller than ``chunk_size``, otherwise the window won't move and the splitting stucks. + When ``split_by`` = ``token``, the punctuation is considered as a token. -How to implement ``LightRAG's TextSplitter`` +How to use it ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ What you need is to specify the arguments and input your documents this way: .. code-block:: python - from lightrag.core.text_splitter import TextSplitter + from lightrag.components.data_process.text_splitter import TextSplitter from lightrag.core.types import Document # Configure the splitter settings text_splitter = TextSplitter( - split_by="sentence", + split_by="word", chunk_size=5, chunk_overlap=1 ) @@ -227,6 +129,11 @@ What you need is to specify the arguments and input your documents this way: for doc in splitted_docs: print(doc) + # Output: + # Document(id=44a8aa37-0d16-40f0-9ca4-2e25ae5336c8, text='Example text. More example text. ', meta_data=None, vector=[], parent_doc_id=doc1, order=0, score=None) + # Document(id=ca0af45b-4f88-49b5-97db-163da9868ea4, text='text. Even more text to ', meta_data=None, vector=[], parent_doc_id=doc1, order=1, score=None) + # Document(id=e7b617b2-3927-4248-afce-ec0fc247ac8b, text='to illustrate.', meta_data=None, vector=[], parent_doc_id=doc1, order=2, score=None) + Integration with Other Document Types ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ This functionality is ideal for segmenting texts into sentences, words, pages, or passages, which can then be processed further for NLP applications. diff --git a/docs/source/developer_notes/tool_helper.rst b/docs/source/developer_notes/tool_helper.rst index b1dff8b5..07cc1c3b 100644 --- a/docs/source/developer_notes/tool_helper.rst +++ b/docs/source/developer_notes/tool_helper.rst @@ -1,5 +1,10 @@ Function calls =========================== +.. admonition:: Author + :class: highlight + + `Li Yin `_ + Tools are means LLM can use to interact with the world beyond of its internal knowledge. Technically speaking, retrievers are tools to help LLM to get more relevant context, and memory is a tool for LLM to carry out a conversation. Deciding when, which, and how to use a tool, and even to creating a tool is an agentic behavior: Function calls is a process of showing LLM a list of funciton definitions and prompt it to choose one or few of them. diff --git a/docs/source/get_started/installation.rst b/docs/source/get_started/installation.rst index 5f35ccef..b213d0c1 100644 --- a/docs/source/get_started/installation.rst +++ b/docs/source/get_started/installation.rst @@ -1,16 +1,111 @@ Installation ============ -[Xiaoyi] +LightRAG is available in Python. -To start with LightRAG, please follow the steps: +1. Install LightRAG +~~~~~~~~~~~~~~~~~~~~ -1. Clone the repository. +To install the package, run: -2. Setup API keys by make a copy of ``.env.example`` to ``.env`` and fill in the necessary API keys. +.. code-block:: bash -3. Setup the Python environment using ``poetry install``. And activate the environment using ``poetry shell``. + pip install lightrag -4. (For contributors only) Install pre-commit into your git hooks using ``pre-commit install``, which will automatically check the code standard on every commit. -5. Now you should be able to run any file in the repo. + +2. Set up API keys +~~~~~~~~~~~~~~~~~~~ + +``.env`` file is recommended. +You can have it at your project root directory. +Here are an example: + +.. code-block:: bash + + OPENAI_API_KEY=YOUR_API_KEY_IF_YOU_USE_OPENAI + GROQ_API_KEY=YOUR_API_KEY_IF_YOU_USE_GROQ + ANTHROPIC_API_KEY=YOUR_API_KEY_IF_YOU_USE_ANTHROPIC + GOOGLE_API_KEY=YOUR_API_KEY_IF_YOU_USE_GOOGLE + COHERE_API_KEY=YOUR_API_KEY_IF_YOU_USE_COHERE + HF_TOKEN=YOUR_API_KEY_IF_YOU_USE_HF + + +3. Load environment variables +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can add the following import: + +.. code-block:: python + + from lightrag.utils import setup_env #noqa + +Or, you can load it yourself: + +.. code-block:: python + + from dotenv import load_dotenv + load_dotenv() # This loads the environment variables from `.env`. + +This setup ensures that LightRAG can access all necessary configurations during runtime. + +4. Install Optional Packages +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + +LightRAG currently has built-in support for (1) OpenAI, Groq, Anthropic, Google, and Cohere, (2) FAISS and Transformers. +You can find all optional packages at :class:`utils.lazy_import.OptionalPackages`. +Make sure to install the necessary SDKs for the components you plan to use. +Here is the list of our tested versions: + +.. code-block:: + + openai = "^1.12.0" + groq = "^0.5.0" + faiss-cpu = "^1.8.0" + sqlalchemy = "^2.0.30" + cohere = "^5.5.8" + pgvector = "^0.2.5" + anthropic = "^0.26.0" + google-generativeai = "^0.5.4" + + + + + + +.. Poetry Installation +.. -------------------------- + +.. Developers and contributors who need access to the source code or wish to contribute to the project should set up their environment as follows: + +.. 1. **Clone the Repository:** + +.. Start by cloning the LightRAG repository to your local machine: + +.. .. code-block:: bash + +.. git clone https://github.com/SylphAI-Inc/LightRAG +.. cd LightRAG + +.. 2. **Configure API Keys:** + +.. Copy the example environment file and add your API keys: + +.. .. code-block:: bash + +.. cp .env.example .env +.. # Open .env and fill in your API keys + +.. 3. **Install Dependencies:** + +.. Use Poetry to install the dependencies and set up the virtual environment: + +.. .. code-block:: bash + +.. poetry install +.. poetry shell + +.. 4. **Verification:** + +.. Now, you should be able to run any file within the repository or execute tests to confirm everything is set up correctly. diff --git a/docs/source/index.rst b/docs/source/index.rst index b23ce133..234e2c5d 100644 --- a/docs/source/index.rst +++ b/docs/source/index.rst @@ -1,17 +1,13 @@ -.. LightRAG documentation master file, created by - sphinx-quickstart on Thu May 9 15:45:29 2024. - You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. ======================= -LightRAG Home +Introduction ======================= +LightRAG is the `PyTorch` library for building large language model (LLM) applications. We help developers with both building and optimizing `Retriever`-`Agent`-`Generator` (RAG) pipelines. +It is light, modular, and robust. -LightRAG is the "PyTorch" library for building large langage model(LLM) applications. It is super light, modular and robust like "PyTorch", and offers essential components for `Retriever`-`Agent`-`Generator` (RAG). -You have a similar coding experience as PyTorch. Here is a side to side comparison of writing a PyTorch module and a LightRAG component: -.. grid:: 2 +.. grid:: 1 :gutter: 1 .. grid-item-card:: PyTorch @@ -43,84 +39,107 @@ You have a similar coding experience as PyTorch. Here is a side to side comparis .. code-block:: python - from core.component import Component, Generator - from components.model_client import OpenAIClient + from lightrag.core import Component, Generator + from lightrag.components.model_client import GroqAPIClient + from lightrag.utils import setup_env #noqa + class SimpleQA(Component): def __init__(self): super().__init__() + template = r""" + You are a helpful assistant. + + User: {{input_str}} + You: + """ self.generator = Generator( - model_client=OpenAIClient(), - model_kwargs={'model': 'gpt-3.5-turbo'} + model_client=GroqAPIClient(), + model_kwargs={"model": "llama3-8b-8192"}, + template=template, ) def call(self, query): - return self.generator.call({'input_str': query}) + return self.generator({"input_str": query}) async def acall(self, query): - return await self.generator.acall({'input_str': query}) - - qa = SimpleQA() - print(qa) - + return await self.generator.acall({"input_str": query}) -**Why LightRAG?** -1. **Clarity and Simplicity** +.. and Customizability - We understand that developers building real-world Large Language Model (LLM) applications are the real heroes. Just like AI researchers and engineers who build models on top of PyTorch, developers require **Maximum Flexibility and Customizability**: Each developer has unique data needs to build their own models/components, experiment with In-context Learning (ICL) or model finetuning, and deploy the LLM applications to production. This means the library must provide fundamental lower-level building blocks and strive for clarity and simplicity: - - We maintain no more than two levels of subclasses. - - Each core abstract class is designed to be robust and flexible. - - We use 10X less code than other libraries to achieve 10X more robustness and flexibility. +Simplicity +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Developers who are building real-world Large Language Model (LLM) applications are the real heroes. +As a library, we provide them with the fundamental building blocks with 100% clarity and simplicity. -2. **Control and Transparency** +- Two fundamental and powerful base classes: `Component` for the pipeline and `DataClass` for data interaction with LLMs. +- We end up with less than two levels of subclasses. :doc:`developer_notes/class_hierarchy`. +- The result is a library with bare minimum abstraction, providing developers with maximum customizability. - Coming from a deep AI research background, we understand that the more control and transparency developers have over their prompts, the better. In default: +.. - We use 10X less code than other libraries to achieve 10X more robustness and flexibility. - - LightRAG simplifies what developers need to send to LLM proprietary APIs to just two messages each time: a `system message` and a `user message`. This minimizes reliance on and manipulation by API providers. - - LightRAG provides advanced tooling for developers to build `agents`, `tools/function calls`, etc., without relying on any proprietary API provider's 'advanced' features such as `OpenAI` assistant, tools, and JSON format. +.. - `Class Hierarchy Visualization `_ +.. We support them with require **Maximum Flexibility and Customizability**: -3. **Suitted for Both Researchers and Production Engineers** +.. Each developer has unique data needs to build their own models/components, experiment with In-context Learning (ICL) or model finetuning, and deploy the LLM applications to production. This means the library must provide fundamental lower-level building blocks and strive for clarity and simplicity: - On top of the easiness to use, we in particular optimize the configurability of components for researchers to build their solutions and to benchmark existing solutions. - Like how PyTorch has united both researchers and production teams, it enables smooth transition from research to production. - With researchers building on LightRAG, production engineers can easily take over the method and test and iterate on their production data. - Researchers will want their code to be adapted into more products too. +Similar to the `PyTorch` module, our ``Component`` provides excellent visualization of the pipeline structure. +.. code-block:: + SimpleQA( + (generator): Generator( + model_kwargs={'model': 'llama3-8b-8192'}, + (prompt): Prompt( + template: + You are a helpful assistant. + + User: {{input_str}} + You: + , prompt_variables: ['input_str'] + ) + (model_client): GroqAPIClient() + ) + ) -**LightRAG vs other LLM libraries:** +.. and Robustness +Controllability +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Our simplicity did not come from doing 'less'. +On the contrary, we have to do 'more' and go 'deeper' and 'wider' on any topic to offer developers maximum control and robustness. -**LightRAG library structures as follows:** +- LLMs are sensitive to the prompt. We allow developers full control over their prompts without relying on API features such as tools and JSON format with components like ``Prompt``, ``OutputParser``, ``FunctionTool``, and ``ToolManager``. +- Our goal is not to optimize for integration, but to provide a robust abstraction with representative examples. See this in ``ModelClient`` and ``Retriever``. +- All integrations, such as different API SDKs, are formed as optional packages but all within the same library. You can easily switch to any models from different providers that we officially support. -#TODO: One diagram to make people understand lightrag faster -* `core` - Base abstractions, core functions, and core components like `Generator` and `Embedder` to support more advanced components. -* `components` - Components that are built on top of the core directive. Users will install relevant depencides on their own for some components. +.. Coming from a deep AI research background, we understand that the more control and transparency developers have over their prompts, the better. In default: -**LightRAG documentation is divided into two parts:** +.. - LightRAG simplifies what developers need to send to LLM proprietary APIs to just two messages each time: a `system message` and a `user message`. This minimizes reliance on and manipulation by API providers. -* **Developer Documentation**: This documentation explains how LightRAG is designed in more depth and is especially useful for developers who want to contribute to LightRAG. +.. - LightRAG provides advanced tooling for developers to build `agents`, `tools/function calls`, etc., without relying on any proprietary API provider's 'advanced' features such as `OpenAI` assistant, tools, and JSON format -* **User Documentation**: This documentation is for users who want to use LightRAG to build their applications. - -We encourage all users to at least skim through the developer documentation. Different from "PyTorch" where a normal user does not have to customize a building module for neural network, -LLM applications have much bigger scope and varies even more to different product environments, so developers customizing components on their own is much more common. +It is the future of LLM applications +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +On top of the easiness to use, we in particular optimize the configurability of components for researchers to build their solutions and to benchmark existing solutions. +Like how PyTorch has united both researchers and production teams, it enables smooth transition from research to production. +With researchers building on LightRAG, production engineers can easily take over the method and test and iterate on their production data. +Researchers will want their code to be adapted into more products too. .. toctree:: :glob: :maxdepth: 1 - :caption: New Users - + :hidden: get_started/index @@ -130,35 +149,32 @@ LLM applications have much bigger scope and varies even more to different produc .. toctree:: :glob: :maxdepth: 1 - :caption: Tutorials - How each part works + :hidden: developer_notes/index - - - - + .. :caption: Tutorials - How each part works + .. :hidden: .. toctree:: :maxdepth: 1 :caption: Use Cases - How different parts are used to build various LLM applications + :hidden: tutorials/index .. toctree:: + :glob: :maxdepth: 1 - :caption: API Reference + :hidden: apis/index -.. todo:: - .. toctree:: - :maxdepth: 1 - :caption: Benchmarks + .. :caption: Benchmarks - Manually add documents for the code in benchmarks + .. Manually add documents for the code in benchmarks .. :glob: @@ -172,5 +188,6 @@ LLM applications have much bigger scope and varies even more to different produc :glob: :maxdepth: 1 :caption: For Contributors + :hidden: contributor/index diff --git a/lightrag/components/data_process/__init__.py b/lightrag/components/data_process/__init__.py index c88b3389..b50494d5 100644 --- a/lightrag/components/data_process/__init__.py +++ b/lightrag/components/data_process/__init__.py @@ -1,11 +1,11 @@ """Components here are used for data processing/transformation.""" -from .document_splitter import DocumentSplitter +from .text_splitter import TextSplitter from .data_components import ToEmbeddings, RetrieverOutputToContextStr from lightrag.utils.registry import EntityMapping -__all__ = ["DocumentSplitter", "ToEmbeddings", "RetrieverOutputToContextStr"] +__all__ = ["TextSplitter", "ToEmbeddings", "RetrieverOutputToContextStr"] for name in __all__: EntityMapping.register(name, globals()[name]) diff --git a/lightrag/components/data_process/document_splitter.py b/lightrag/components/data_process/document_splitter.py deleted file mode 100644 index 1a2d4598..00000000 --- a/lightrag/components/data_process/document_splitter.py +++ /dev/null @@ -1,167 +0,0 @@ -"""Text splitter to split long text into smaller chunks to fit into the token limits of embedding and LLM models.""" - -# TODO: JSON/HTML Splitter -from copy import deepcopy -from typing import List, Literal -from tqdm import tqdm - -from more_itertools import windowed - -from lightrag.core.component import Component -from lightrag.core.types import Document -from lightrag.core.tokenizer import Tokenizer - - -DocumentSplitterInputType = List[Document] -DocumentSplitterOutputType = List[Document] - - -def split_text_by_token_fn(x: str, tokenizer: Tokenizer = Tokenizer()) -> List[str]: - x = x.lower() - return tokenizer.get_string_tokens(x) - - -DocumentSplitterInputType = List[Document] -DocumentSplitterOutputType = List[Document] - - -class DocumentSplitter(Component): - __doc__ = r""" - Splits a list of text documents into a list of text documents with shorter texts. - - Output: List[Document] - - Splitting documents with long texts is a common preprocessing step for LLM applications. - The splitted documents are easier to fit into the token limits of language models, both Embedders and Generators, - and to ensure the retrieved context can be more relevant than the large text itself. - - Args: - split_by (str): The unit by which the document should be split. Choose from "word" for splitting by " ", - "sentence" for splitting by ".", "page" for splitting by "\\f" or "passage" for splitting by "\\n\\n". - split_length (int): The maximum number of units in each split. It can be number of works, sentences, pages or passages. - split_overlap (int): The number of units that each split should overlap. - - Example: - - .. code-block:: python - - from lightrag.core.document_splitter import DocumentSplitter - from lightrag.core.types import Document - - doc1 = Document(text="This is a test document. It is a long document.") - doc2 = Document(text="This is another test document. It is also a long document.") - splitter = DocumentSplitter(split_by="token", split_length=4, split_overlap=1) - print(splitter) - splitted_docs = splitter([doc1, doc2]) - print(splitted_docs) - """ - - def __init__( - self, - split_by: Literal["word", "token", "sentence", "page", "passage"] = "word", - split_length: int = 200, - split_overlap: int = 0, - ): - super().__init__( - split_by=split_by, split_length=split_length, split_overlap=split_overlap - ) - - self.split_by = split_by - if split_by not in ["word", "sentence", "page", "passage", "token"]: - raise ValueError( - "split_by must be one of 'word', 'sentence', 'page' or 'passage'." - ) - if split_length <= 0: - raise ValueError("split_length must be greater than 0.") - self.split_length = split_length - if split_overlap < 0: - raise ValueError("split_overlap must be greater than or equal to 0.") - self.split_overlap = split_overlap - - def split_text(self, text: str) -> List[str]: - r"""Splits a text into a list of shorter texts.""" - units = self._split_into_units(text, self.split_by) - return self._concatenate_units(units, self.split_length, self.split_overlap) - - def call(self, documents: List[Document]) -> List[Document]: - if not isinstance(documents, list) or ( - documents and not isinstance(documents[0], Document) - ): - raise TypeError("DocumentSplitter expects a List of Documents as input.") - - split_docs: List[Document] = [] - for doc in tqdm(documents, desc="Splitting documents"): - if doc.text is None: - raise ValueError( - f"DocumentSplitter only works with text documents but document.content for document ID {doc.id} is None." - ) - text_splits = self.split_text(doc.text) - meta_data = deepcopy(doc.meta_data) - split_docs += [ - Document( - text=txt, - meta_data=meta_data, - parent_doc_id=f"{doc.id}", - order=i, - vector=[], - ) - for i, txt in enumerate(text_splits) - ] - return split_docs - - def _split_into_units( - self, - text: str, - split_by: Literal["word", "sentence", "passage", "page", "token"], - ) -> List[str]: - if split_by == "token": - units = split_text_by_token_fn(x=text) - print(units) - else: # text splitter - if split_by == "page": - split_at = "\f" - elif split_by == "passage": - split_at = "\n\n" - elif split_by == "sentence": - split_at = "." - elif split_by == "word": - split_at = " " - else: - raise NotImplementedError( - "DocumentSplitter only supports 'word', 'sentence', 'page' or 'passage' split_by options." - ) - units = text.split(split_at) - # Add the delimiter back to all units except the last one - for i in range(len(units) - 1): - units[i] += split_at - return units - - def _concatenate_units( - self, elements: List[str], split_length: int, split_overlap: int - ) -> List[str]: - """Concatenates the elements into parts of split_length units.""" - text_splits = [] - segments = windowed(elements, n=split_length, step=split_length - split_overlap) - for seg in segments: - current_units = [unit for unit in seg if unit is not None] - txt = "".join(current_units) - if len(txt) > 0: - text_splits.append(txt) - return text_splits - - def _extra_repr(self) -> str: - s = f"split_by={self.split_by}, split_length={self.split_length}, split_overlap={self.split_overlap}" - return s - -if __name__ == "__main__": - from lightrag.core.document_splitter import DocumentSplitter - from lightrag.core.types import Document - - doc1 = Document(text="This is a simple test to check splitting.") - # doc2 = Document(text="This is another test document. It is also a long document.") - splitter = DocumentSplitter(split_by="word", split_length=5, split_overlap=2) - # print(splitter) - splitted_docs = splitter([doc1]) - # print(splitted_docs) - for doc in splitted_docs: - print(doc.text) \ No newline at end of file diff --git a/lightrag/components/data_process/text_splitter.py b/lightrag/components/data_process/text_splitter.py index ad7bd7a6..2f632c1b 100644 --- a/lightrag/components/data_process/text_splitter.py +++ b/lightrag/components/data_process/text_splitter.py @@ -21,7 +21,7 @@ from lightrag.core.component import Component from lightrag.core.types import Document -from lightrag.components.retriever.bm25_retriever import split_text_tokenized +from lightrag.core.tokenizer import Tokenizer # TODO: # More splitters such as PDF/JSON/HTML Splitter can be built on TextSplitter. @@ -34,45 +34,52 @@ # customizable seperators map SEPARATORS = {"page": "\f", "passage": "\n\n", "word": " ", "sentence": ".", "token": ""} -DEFAULT_CHUNK_SIZE = 1024 -DEFAULT_CHUNK_OVERLAP = 20 +DEFAULT_CHUNK_SIZE = 800 +DEFAULT_CHUNK_OVERLAP = 200 + +tokenizer = Tokenizer() class TextSplitter(Component): """ - Text Splitter for Chunking Documents in Batch + Text Splitter for Chunking Documents - The ``TextSplitter`` is designed for splitting plain text into manageable chunks. - It supports 2 types of splitting. - - * Type 1: Specify the exact text splitting point such as space<" "> and periods<".">. It is intuitive: - "Hello, world!" -> ["Hello, " ,"world!"] - - * Type 2: Use :class:`tokenizer `. It works as: - "Hello, world!" -> ['Hello', ',', ' world', '!'] - - .. note:: - The punctuation is considered as a token. + ``TextSplitter`` first utilizes ``split_by`` to specify the text-splitting criterion and breaks the long text into smaller texts. + Then we create a sliding window with length= ``chunk_size``. It moves at step= ``chunk_size`` - ``chunk_overlap``. + The texts inside each window will get merged to a smaller chunk. The generated chunks from the splitted text will be returned. + + **Splitting Types** + + ``TextSplitter`` supports 2 types of splitting. - This aligns with how models see text in the form of tokens. (`Reference `_) - - Simple text splitting(Type 1) can underestimate the number of tokens. Tokenizer reflects the real token numbers the models take in. - But the Tokenizer here only works at world level. - - * **Definitions** - - ``split_by``: Specifies the text-splitting criterion using predefined keys like "word", "sentence", "page", "passage", and "token". The splitter utilizes the corresponding separator from the ``SEPARATORS`` dictionary. - - ``SEPARATORS``: Maps ``split_by`` criterions to their exact text separators, e.g., spaces<" "> for "word" or periods<"."> for "sentence". - - Usage: **SEPARATORS[``split_by``]=separator** - + * **Type 1:** Specify the exact text splitting point such as space<" "> and periods<".">. It is intuitive, for example, split_by "word": + + :: + + "Hello, world!" -> ["Hello, " ,"world!"] + + * **Type 2:** Use :class:`tokenizer `. It works as: + + :: + + "Hello, world!" -> ['Hello', ',', ' world', '!'] + + This aligns with how models see text in the form of tokens (`Reference `_), + Tokenizer reflects the real token numbers the models take in and helps the developers control budgets. + + **Definitions** + + * **split_by** specifies the split rule, i.e. the smallest unit during splitting. We support ``"word"``, ``"sentence"``, ``"page"``, ``"passage"``, and ``"token"``. The splitter utilizes the corresponding separator from the ``SEPARATORS`` dictionary. + For Type 1 splitting, we apply ``Python str.split()`` to break the text. + + * **SEPARATORS**: Maps ``split_by`` criterions to their exact text separators, e.g., spaces <" "> for "word" or periods <"."> for "sentence". + .. note:: For option ``token``, its separator is "" because we directly split by a tokenizer, instead of text point. - - * **Overview**: - ``TextSplitter`` first utilizes ``split_by`` to specify the text-splitting criterion and breaks the long text into smaller texts. - Then we create a sliding window with length= ``chunk_size``. It moves at step= ``chunk_size`` - ``chunk_overlap``. - The texts inside each window will get concatenated to a smaller chunk. The generated chunks from the splitted text will be returned. + + * **chunk_size** is the the maximum number of units in each chunk. + + * **chunk_overlap** is the number of units that each chunk should overlap. Including context at the borders prevents sudden meaning shift in text between sentences/context, especially in sentiment analysis. + * **Splitting Details** Type 1: @@ -91,80 +98,55 @@ class TextSplitter(Component): .. note:: Developers need to determine how to assign text to each data chunk for the embedding and retrieval tasks. - The ``TextSplitter`` ``split_by`` cases: - - - "word": Splits the text at every space (" "), treating spaces as the boundaries between words. - - - "sentence": Splits the text at every period ("."), treating these as the ends of sentences. - - - "page": Splits the text at form feed characters ("\\f"), which are often used to represent page breaks in documents. - - - "passage": Splits the text at double newline characters ("\\n\\n"), useful for distinguishing between paragraphs or sections. Type 2: We implement a tokenizer using ``cl100k_base`` encoding that aligns with how models see text in the form of tokens. E.g. "tiktoken is great!" -> ["t", "ik", "token", " is", " great", "!"] This helps developers control the token usage and budget better. + * **Merge Details** + Type 1/Type 2 create a list of split texts. ``TextSplitter`` then reattaches the specified separator to each piece of the split text, except for the last segment. + This approach maintains the original spacing and punctuation, which is critical in contexts like natural language processing where text formatting can impact interpretations and outcomes. + E.g. "hello world!" split by "word" will be kept as "hello " and "world!" * **Customization** You can also customize the ``SEPARATORS``. For example, by defining ``SEPARATORS`` = {"question": "?"} and setting ``split_by`` = "question", the document will be split at each ``?``, ideal for processing text structured as a series of questions. If you need to customize :class:`tokenizer `, please check `Reference `_. - * **Concatenating Details** - Type 1/Type 2 create a list of split texts. ``TextSplitter`` then reattaches the specified separator to each piece of the split text, except for the last segment. - This approach maintains the original spacing and punctuation, which is critical in contexts like natural language processing where text formatting can impact interpretations and outcomes. - E.g. "hello world!" split by "word" will be kept as "hello " and "world!" - - * **Use Cases** + * **Integration with Other Document Types** This functionality is ideal for segmenting texts into sentences, words, pages, or passages, which can then be processed further for NLP applications. - - To handle PDF content, developers need to first extract the text using tools like ``PyPDF2`` or ``PDFMiner`` before splitting. - - Example: - .. code-block:: python + For **PDFs**, developers will need to extract the text before using the splitter. Libraries like ``PyPDF2`` or ``PDFMiner`` can be utilized for this purpose. + ``LightRAG``'s future implementations will introduce splitters for ``JSON``, ``HTML``, ``markdown``, and ``code``. - from lightrag.core.text_splitter import TextSplitter - from lightrag.core.types import Document - - # configure the splitter setting - text_splitter_settings = { - "split_by": "word", - "chunk_size": 20, - "chunk_overlap": 2, - } - - # set up the document splitter - text_splitter = TextSplitter( - split_by=text_splitter_settings["split_by"], - chunk_size=text_splitter_settings["chunk_size"], - chunk_overlap=text_splitter_settings["chunk_overlap"], - ) - - doc1 = Document( - meta_data={"title": "Luna's Profile"}, - text="lots of more nonsense text." * 2 - + "Luna is a domestic shorthair." - + "lots of nonsense text." * 3, - id="doc1", - ) - doc2 = Document( - meta_data={"title": "Luna's Hobbies"}, - text="lots of more nonsense text." * 2 - + "Luna loves to eat lickable treats." - + "lots of more nonsense text." * 2 - + "Luna loves to play cat wand." - + "lots of more nonsense text." * 2 - + "Luna likes to sleep all the afternoon", - id="doc2", - ) - documents = [doc1, doc2] - - splitted_docs = (text_splitter.call(documents=documents)) - - for doc in splitted_docs: - print("*" * 50) - print(doc) - print("*" * 50) + Example: + + .. code-block:: python + + from lightrag.components.data_process.text_splitter import TextSplitter + from lightrag.core.types import Document + + # Configure the splitter settings + text_splitter = TextSplitter( + split_by="word", + chunk_size=5, + chunk_overlap=1 + ) + + # Example document + doc = Document( + text="Example text. More example text. Even more text to illustrate.", + id="doc1" + ) + + # Execute the splitting + splitted_docs = text_splitter.call(documents=[doc]) + + for doc in splitted_docs: + print(doc) + + # Output: + # Document(id=44a8aa37-0d16-40f0-9ca4-2e25ae5336c8, text='Example text. More example text. ', meta_data=None, vector=[], parent_doc_id=doc1, order=0, score=None) + # Document(id=ca0af45b-4f88-49b5-97db-163da9868ea4, text='text. Even more text to ', meta_data=None, vector=[], parent_doc_id=doc1, order=1, score=None) + # Document(id=e7b617b2-3927-4248-afce-ec0fc247ac8b, text='to illustrate.', meta_data=None, vector=[], parent_doc_id=doc1, order=2, score=None) """ def __init__( self, @@ -190,30 +172,20 @@ def __init__( """ super().__init__() - # variable value checks self.split_by = split_by - if split_by not in SEPARATORS: - options = ", ".join(f"'{key}'" for key in SEPARATORS.keys()) - log.error(f"Invalid options for split_by. You must select from {options}.") - raise ValueError(f"Invalid options for split_by. You must select from {options}.") - - if chunk_overlap >= chunk_size: - log.error(f"chunk_overlap can't be larger than or equal to chunk_size. Received chunk_size: {chunk_size}, chunk_overlap: {chunk_overlap}") - raise ValueError( - f"chunk_overlap can't be larger than or equal to chunk_size. Received chunk_size: {chunk_size}, chunk_overlap: {chunk_overlap}" - ) - - if chunk_size <= 0: - log.error(f"chunk_size must be greater than 0. Received value: {chunk_size}") - raise ValueError(f"chunk_size must be greater than 0. Received value: {chunk_size}") - self.chunk_size = chunk_size + assert split_by in SEPARATORS, f"Invalid options for split_by. You must select from {list(SEPARATORS.keys())}." - if chunk_overlap < 0: - log.error(f"chunk_overlap must be non-negative. Received value: {chunk_overlap}") - raise ValueError(f"chunk_overlap must be non-negative. Received value: {chunk_overlap}") - self.chunk_overlap = chunk_overlap + assert chunk_overlap < chunk_size, f"chunk_overlap can't be larger than or equal to chunk_size. Received chunk_size: {chunk_size}, chunk_overlap: {chunk_overlap}" + assert chunk_size > 0, f"chunk_size must be greater than 0. Received value: {chunk_size}" + self.chunk_size = chunk_size + + assert chunk_overlap >= 0, f"chunk_overlap must be non-negative. Received value: {chunk_overlap}" + self.chunk_overlap = chunk_overlap + self.batch_size = batch_size + + log.info(f"Initialized TextSplitter with split_by={self.split_by}, chunk_size={self.chunk_size}, chunk_overlap={self.chunk_overlap}, batch_size={self.batch_size}") def split_text(self, text: str) -> List[str]: """ @@ -229,10 +201,10 @@ def split_text(self, text: str) -> List[str]: """ log.info(f"Splitting text with split_by: {self.split_by}, chunk_size: {self.chunk_size}, chunk_overlap: {self.chunk_overlap}") separator = SEPARATORS[self.split_by] - splits = self._split_text(text, separator) + splits = self._split_text_into_units(text, separator) log.info(f"Text split into {len(splits)} parts.") - chunks = self._concatenate_splits(splits, self.chunk_size, self.chunk_overlap, separator) - log.info(f"Text concatenated into {len(chunks)} chunks.") + chunks = self._merge_units_to_chunks(splits, self.chunk_size, self.chunk_overlap, separator) + log.info(f"Text merged into {len(chunks)} chunks.") return chunks def call(self, documents: DocumentSplitterInputType) -> DocumentSplitterOutputType: @@ -287,21 +259,21 @@ def call(self, documents: DocumentSplitterInputType) -> DocumentSplitterOutputTy log.info(f"Processed {len(documents)} documents into {len(split_docs)} split documents.") return split_docs - def _split_text( + def _split_text_into_units( self, text: str, separator: str) -> List[str]: """Split text based on the specified separator.""" if self.split_by == "token": - splits = split_text_tokenized(text) + splits = tokenizer.encode(text) else: splits = text.split(separator) - log.info(f"Text split by '{separator}' into {len(splits)} parts.") + log.info(f"Text split by '{separator}' into {len(splits)} parts.") return splits - def _concatenate_splits( + def _merge_units_to_chunks( self, splits: List[str], chunk_size: int, chunk_overlap: int, separator: str ) -> List[str]: """ - Concatenates split text chunks based on the specified chunk size and overlap. + Merge split text chunks based on the specified chunk size and overlap. """ chunks = [] # we use a window to get the text for each trunk, the window size is chunk_size, step is chunk_size - chunk_overlap @@ -314,16 +286,27 @@ def _concatenate_splits( if idx+chunk_size >= len(splits): break current_splits = splits[idx:idx+chunk_size] - # add the separator between each unit and concatenate the string + # add the separator between each unit and merge the string # this won't be the last chunk, so we need to add the separator at the end - chunk = separator.join(current_splits) + separator + if self.split_by == "token": + chunk = current_splits # if token, then keep the original form + else: + chunk = separator.join(current_splits) + separator chunks.append(chunk) if idx < len(splits): - last_chunk = separator.join(splits[idx:]) + if self.split_by == "token": + last_chunk = splits[idx:] # if token, then keep the original form + else: + last_chunk = separator.join(splits[idx:]) # if not token, then join into string if len(last_chunk) > 0: chunks.append(last_chunk) - log.info(f"Concatenated into {len(chunks)} chunks.") + + if self.split_by=="token": + # decode each chunk here + chunks = [tokenizer.decode(chunk) for chunk in chunks] + + log.info(f"Merged into {len(chunks)} chunks.") return chunks def _extra_repr(self) -> str: diff --git a/lightrag/components/model_client/__init__.py b/lightrag/components/model_client/__init__.py index 6667e159..5d8c4413 100644 --- a/lightrag/components/model_client/__init__.py +++ b/lightrag/components/model_client/__init__.py @@ -15,6 +15,10 @@ "lightrag.components.model_client.transformers_client.TransformerEmbedder", OptionalPackages.TRANSFORMERS, ) +TransformerLLM = LazyImport( + "lightrag.components.model_client.transformers_client.TransformerLLM", + OptionalPackages.TRANSFORMERS, +) TransformersClient = LazyImport( "lightrag.components.model_client.transformers_client.TransformersClient", OptionalPackages.TRANSFORMERS, @@ -49,6 +53,7 @@ "CohereAPIClient", "TransformerReranker", "TransformerEmbedder", + "TransformerLLM", "TransformersClient", "AnthropicAPIClient", "GroqAPIClient", diff --git a/lightrag/components/model_client/transformers_client.py b/lightrag/components/model_client/transformers_client.py index cf9aeba5..a40e651e 100644 --- a/lightrag/components/model_client/transformers_client.py +++ b/lightrag/components/model_client/transformers_client.py @@ -13,6 +13,7 @@ AutoTokenizer, AutoModel, AutoModelForSequenceClassification, + AutoModelForCausalLM ) from lightrag.core.model_client import ModelClient @@ -222,7 +223,78 @@ def __call__(self, **kwargs): else: raise ValueError(f"model {model_name} is not supported") +class TransformerLLM: + models: Dict[str, type] = {} + + def __init__(self, model_name: Optional[str] = "HuggingFaceH4/zephyr-7b-beta"): + super().__init__() + if model_name is not None: + self.init_model(model_name=model_name) + + def init_model(self, model_name: str): + try: + self.tokenizer = AutoTokenizer.from_pretrained(model_name) + self.model = AutoModelForCausalLM.from_pretrained(model_name) + # register the model + self.models[model_name] = self.model + self.device = 'cuda' if torch.cuda.is_available() else 'cpu' + log.info(f"Done loading model {model_name}") + # Set pad token if it's not already set + if self.tokenizer.pad_token is None: + self.tokenizer.pad_token = self.tokenizer.eos_token # common fallback + self.model.config.pad_token_id = self.tokenizer.eos_token_id # ensure consistency in the model config + except Exception as e: + log.error(f"Error loading model {model_name}: {e}") + raise e + + def parse_chat_completion(self, input_text: str, response: str): + parsed_response = response.replace(input_text, "").strip() # Safely handle cases where input_text might not be in response + + return parsed_response if parsed_response else response + + def call(self, input_text: str, skip_special_tokens: bool = True, clean_up_tokenization_spaces: bool = False, max_length: int = 150): + if not self.model: + log.error("Model is not initialized.") + raise ValueError("Model is not initialized.") + + # Ensure tokenizer has pad token; set it if not + if self.tokenizer.pad_token is None: + self.tokenizer.pad_token = self.tokenizer.eos_token + self.model.config.pad_token_id = self.tokenizer.eos_token_id # Sync model config pad token id + + # Process inputs with attention mask and padding + inputs = self.tokenizer(input_text, return_tensors="pt", padding=True).to(self.device) + # inputs = self.tokenizer(input_text, return_tensors="pt", padding="longest", truncation=True).to(self.device) + + with torch.no_grad(): # Ensures no gradients are calculated to save memory and computations + generate_ids = self.model.generate( + inputs['input_ids'], + attention_mask=inputs['attention_mask'], + max_length=max_length # Control the output length more precisely + ) + response = self.tokenizer.decode(generate_ids[0], skip_special_tokens=skip_special_tokens, clean_up_tokenization_spaces=clean_up_tokenization_spaces) + parsed_response = self.parse_chat_completion(input_text, response) + return parsed_response + + def __call__(self, input_text: str, skip_special_tokens: bool = True, clean_up_tokenization_spaces: bool = False, max_length: int = 150): + return self.call(input_text, skip_special_tokens=skip_special_tokens, clean_up_tokenization_spaces=clean_up_tokenization_spaces, max_length=max_length) + + + # def call(self, input_text: str, skip_special_tokens: bool = True, clean_up_tokenization_spaces: bool = False): + # if not self.model: + # log.error("Model is not initialized.") + # raise ValueError("Model is not initialized.") + + # inputs = self.tokenizer(input_text, return_tensors="pt") + # generate_ids = self.model.generate(inputs.input_ids, max_length=30) + # response = self.tokenizer.batch_decode(generate_ids, skip_special_tokens=skip_special_tokens, clean_up_tokenization_spaces=clean_up_tokenization_spaces)[0] + # return response + + # def __call__(self, input_text: str, skip_special_tokens: bool = True, clean_up_tokenization_spaces: bool = False): + # return self.call(input_text, skip_special_tokens=skip_special_tokens, clean_up_tokenization_spaces=clean_up_tokenization_spaces) + + class TransformersClient(ModelClient): __doc__ = r"""LightRAG API client for transformers. @@ -236,6 +308,9 @@ class TransformersClient(ModelClient): "BAAI/bge-reranker-base": { "type": ModelType.RERANKER, }, + "HuggingFaceH4/zephyr-7b-beta": { + "type": ModelType.LLM + } } def __init__(self, model_name: Optional[str] = None) -> None: @@ -249,6 +324,8 @@ def __init__(self, model_name: Optional[str] = None) -> None: self.sync_client = self.init_sync_client() elif self._model_name == "BAAI/bge-reranker-base": self.reranker_client = self.init_reranker_client() + elif self._model_name == "HuggingFaceH4/zephyr-7b-beta": + self.llm_client = self.init_llm_client() self.async_client = None def init_sync_client(self): @@ -256,6 +333,9 @@ def init_sync_client(self): def init_reranker_client(self): return TransformerReranker() + + def init_llm_client(self): + return TransformerLLM() def parse_embedding_response(self, response: Any) -> EmbedderOutput: embeddings: List[Embedding] = [] @@ -289,6 +369,15 @@ def call(self, api_kwargs: Dict = {}, model_type: ModelType = ModelType.UNDEFINE scores, api_kwargs["top_k"] ) return top_k_indices, top_k_scores + elif ( # LLM + model_type == ModelType.LLM + and "model" in api_kwargs + and api_kwargs["model"] == "HuggingFaceH4/zephyr-7b-beta" + ): + if not hasattr(self, "llm_client") or self.llm_client is None: + self.llm_client = self.init_llm_client() + response = self.llm_client(**api_kwargs) + return response def convert_inputs_to_api_kwargs( self, @@ -306,5 +395,9 @@ def convert_inputs_to_api_kwargs( assert "top_k" in final_model_kwargs, "top_k must be specified" final_model_kwargs["query"] = input return final_model_kwargs + elif model_type == ModelType.LLM: + assert "model" in final_model_kwargs, "model must be specified" + final_model_kwargs["input"] = input + return final_model_kwargs else: raise ValueError(f"model_type {model_type} is not supported") \ No newline at end of file diff --git a/lightrag/core/base_data_class.py b/lightrag/core/base_data_class.py index 4d84059b..e434097d 100644 --- a/lightrag/core/base_data_class.py +++ b/lightrag/core/base_data_class.py @@ -179,7 +179,7 @@ class MyOutputs(DataClass): def __post_init__(self): for f in fields(self): - if "desc" not in f.metadata or "desription" not in f.metadata: + if "desc" not in f.metadata and "description" not in f.metadata: warnings.warn( f"Class { self.__class__.__name__} Field {f.name} is missing 'desc' in metadata", UserWarning, diff --git a/lightrag/tests/test_gt_text_splitter.py b/lightrag/tests/test_gt_text_splitter.py deleted file mode 100644 index 8c3aa4d2..00000000 --- a/lightrag/tests/test_gt_text_splitter.py +++ /dev/null @@ -1,143 +0,0 @@ -import unittest -from lightrag.core.types import Document -from lightrag.components.data_process.text_splitter import TextSplitter # Import your TextSplitter -from lightrag.components.data_process.document_splitter import DocumentSplitter # Import the ground truth splitter - - -class TestTextSplitterComparison(unittest.TestCase): - - def setUp(self): - self.text_splitter = TextSplitter(split_by="word", chunk_size=5, chunk_overlap=2) - self.ground_truth_splitter = DocumentSplitter(split_by="word", split_length=5, split_overlap=2) - - def compare_splits(self, text): - expected = self.ground_truth_splitter.split_text(text) - result = self.text_splitter.split_text(text) - - print(f"expected: {expected}") - print(f"result: {result}") - self.assertEqual(result, expected) - - def test_exact_chunk_size(self): - text = "one two three four five" - self.compare_splits(text) - - def test_less_than_chunk_size(self): - text = "one two" - self.compare_splits(text) - - def test_single_word(self): - text = "word" - self.compare_splits(text) - - def test_overlap_handling(self): - text = "one two three four five six seven" - self.compare_splits(text) - - def test_multiple_chunks_with_overlap(self): - text = "one two three four five six seven eight nine ten eleven" - self.compare_splits(text) - - def test_end_index_matches_length(self): - text = "one two three four five six" - self.compare_splits(text) - - def test_long_text(self): - text = " ".join(["word"] * 50) - self.compare_splits(text) - - def test_split_by_sentence(self): - self.text_splitter = TextSplitter(split_by="sentence", chunk_size=1, chunk_overlap=0) - self.ground_truth_splitter = DocumentSplitter(split_by="sentence", split_length=1, split_overlap=0) - text = "This is a test. It should work well." - - self.compare_splits(text) - - def test_split_by_page(self): - self.text_splitter = TextSplitter(split_by="page", chunk_size=1, chunk_overlap=0) - self.ground_truth_splitter = DocumentSplitter(split_by="page", split_length=1, split_overlap=0) - text = "This is a test\fThis is another page" - self.compare_splits(text) - - def test_split_by_passage(self): - self.text_splitter = TextSplitter(split_by="passage", chunk_size=1, chunk_overlap=0) - self.ground_truth_splitter = DocumentSplitter(split_by="passage", split_length=1, split_overlap=0) - text = "This is a test\n\nThis is another passage" - self.compare_splits(text) - - def test_empty_text(self): - text = "" - self.compare_splits(text) - - def test_special_characters(self): - text = "one! two@ three# four$ five% six^ seven& eight* nine( ten)" - self.compare_splits(text) - - def test_multiple_spaces(self): - text = "one two three four five" - self.compare_splits(text) - - def test_newlines(self): - text = "one\ntwo\nthree\nfour\nfive\nsix" - self.compare_splits(text) - - def test_tabs(self): - text = "one\ttwo\tthree\tfour\tfive\tsix" - self.compare_splits(text) - - def test_varied_delimiters(self): - text = "one. two, three; four: five! six? seven" - self.compare_splits(text) - - def test_text_with_punctuation(self): - text = "Hello, world! This is a test. Let's see how it works." - self.compare_splits(text) - - def test_long_paragraph(self): - text = ( - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. " - "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. " - "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. " - "Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - ) - self.compare_splits(text) - - def test_trailing_whitespace(self): - text = "one two three four five " - self.compare_splits(text) - - def test_leading_whitespace(self): - text = " one two three four five" - self.compare_splits(text) - - def test_mixed_whitespace(self): - text = " one two three four five " - self.compare_splits(text) - - def test_chunk_size_greater_than_overlap(self): - self.text_splitter = TextSplitter(split_by="word", chunk_size=4, chunk_overlap=2) - self.ground_truth_splitter = DocumentSplitter(split_by="word", split_length=4, split_overlap=2) - text = "one two three four five six seven eight nine ten" - self.compare_splits(text) - - def test_overlap_zero(self): - self.text_splitter = TextSplitter(split_by="word", chunk_size=4, chunk_overlap=0) - self.ground_truth_splitter = DocumentSplitter(split_by="word", split_length=4, split_overlap=0) - text = "one two three four five six seven eight nine ten" - self.compare_splits(text) - - def test_overlap_zero_end(self): - self.text_splitter = TextSplitter(split_by="word", chunk_size=5, chunk_overlap=0) - self.ground_truth_splitter = DocumentSplitter(split_by="word", split_length=5, split_overlap=0) - text = "one two three four five six seven eight nine ten" - self.compare_splits(text) - - def test_invalid_parameters(self): - with self.assertRaises(ValueError): - TextSplitter(split_by="word", chunk_size=-1, chunk_overlap=2) - with self.assertRaises(ValueError): - TextSplitter(split_by="word", chunk_size=5, chunk_overlap=6) - - -if __name__ == '__main__': - unittest.main() diff --git a/lightrag/tests/test_text_splitter.py b/lightrag/tests/test_text_splitter.py new file mode 100644 index 00000000..98fbc530 --- /dev/null +++ b/lightrag/tests/test_text_splitter.py @@ -0,0 +1,62 @@ +import unittest +from lightrag.core.types import Document +from lightrag.components.data_process.text_splitter import TextSplitter + +class TestTextSplitter(unittest.TestCase): + + def setUp(self): + # Set up a TextSplitter instance before each test + self.splitter = TextSplitter(split_by="word", chunk_size=5, chunk_overlap=2) + + # def test_invalid_split_by(self): + # # Test initialization with invalid split_by value + # with self.assertRaises(ValueError): + # TextSplitter(split_by="invalid", chunk_size=5, chunk_overlap=0) + + # def test_negative_chunk_size(self): + # # Test initialization with negative chunk_size + # with self.assertRaises(ValueError): + # TextSplitter(split_by="word", chunk_size=-1, chunk_overlap=0) + + # def test_negative_chunk_overlap(self): + # # Test initialization with negative chunk_overlap + # with self.assertRaises(ValueError): + # TextSplitter(split_by="word", chunk_size=5, chunk_overlap=-1) + + def test_split_by_word(self): + # Test the basic functionality of splitting by word + text = "This is a simple test" + expected = ["This is a simple test"] + result = self.splitter.split_text(text) + self.assertEqual(result, expected) + + def test_split_by_sentence(self): + # Test splitting by sentence + splitter = TextSplitter(split_by="sentence", chunk_size=1, chunk_overlap=0) + text = "This is a test. It should work well." + expected = ["This is a test.", " It should work well."] + result = splitter.split_text(text) + self.assertEqual(result, expected) + + def test_overlap_handling(self): + # Test proper handling of overlap + text = "one two three four five six seven" + expected = ["one two three four five ", "four five six seven"] + result = self.splitter.split_text(text) + self.assertEqual(result, expected) + + def test_document_splitting(self): + # Test splitting a list of documents + docs = [Document(text="This is a simple test to check splitting.", id="1")] + expected_texts = ["This is a simple test ", "simple test to check splitting."] + result = self.splitter.call(docs) + result_texts = [doc.text for doc in result] + self.assertEqual(result_texts, expected_texts) + + # def test_empty_text_handling(self): + # # Test handling of empty text + # with self.assertRaises(ValueError): + # self.splitter.call([Document(text=None, id="1")]) + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/lightrag/tests/test_transformer_client.py b/lightrag/tests/test_transformer_client.py index 33e498d4..cdbc1931 100644 --- a/lightrag/tests/test_transformer_client.py +++ b/lightrag/tests/test_transformer_client.py @@ -4,6 +4,7 @@ from lightrag.components.model_client import ( TransformersClient, TransformerReranker, + TransformerLLM, TransformerEmbedder, ) from lightrag.core.types import ModelType @@ -22,81 +23,106 @@ def setUp(self) -> None: "The red panda (Ailurus fulgens), also called the lesser panda, the red bear-cat, and the red cat-bear, is a mammal native to the eastern Himalayas and southwestern China.", ] - def test_transformer_embedder(self): - transformer_embedder_model = "thenlper/gte-base" - transformer_embedder_model_component = TransformerEmbedder( - model_name=transformer_embedder_model - ) - print( - f"Testing transformer embedder with model {transformer_embedder_model_component}" - ) - print("Testing transformer embedder") - output = transformer_embedder_model_component( - model=transformer_embedder_model, input="Hello world" - ) - print(output) - - def test_transformer_client(self): - transformer_client = TransformersClient() - print("Testing transformer client") - # run the model - kwargs = { - "model": "thenlper/gte-base", - # "mock": False, - } - api_kwargs = transformer_client.convert_inputs_to_api_kwargs( - input="Hello world", - model_kwargs=kwargs, - model_type=ModelType.EMBEDDER, - ) - # print(api_kwargs) - output = transformer_client.call( - api_kwargs=api_kwargs, model_type=ModelType.EMBEDDER - ) - - # print(transformer_client) - # print(output) - - def test_transformer_reranker(self): - transformer_reranker_model = "BAAI/bge-reranker-base" - transformer_reranker_model_component = TransformerReranker() - # print( - # f"Testing transformer reranker with model {transformer_reranker_model_component}" - # ) - - model_kwargs = { - "model": transformer_reranker_model, - "documents": self.documents, - "query": self.query, - "top_k": 2, - } - - output = transformer_reranker_model_component( - **model_kwargs, - ) - # assert output is a list of float with length 2 - self.assertEqual(len(output), 2) - self.assertEqual(type(output[0]), float) - - def test_transformer_reranker_client(self): - transformer_reranker_client = TransformersClient( - model_name="BAAI/bge-reranker-base" - ) - print("Testing transformer reranker client") - # run the model - kwargs = { - "model": "BAAI/bge-reranker-base", - "documents": self.documents, - "top_k": 2, - } - api_kwargs = transformer_reranker_client.convert_inputs_to_api_kwargs( - input=self.query, - model_kwargs=kwargs, - model_type=ModelType.RERANKER, - ) - print(api_kwargs) - self.assertEqual(api_kwargs["model"], "BAAI/bge-reranker-base") - output = transformer_reranker_client.call( - api_kwargs=api_kwargs, model_type=ModelType.RERANKER - ) - self.assertEqual(type(output), tuple) + # def test_transformer_embedder(self): + # transformer_embedder_model = "thenlper/gte-base" + # transformer_embedder_model_component = TransformerEmbedder( + # model_name=transformer_embedder_model + # ) + # print( + # f"Testing transformer embedder with model {transformer_embedder_model_component}" + # ) + # print("Testing transformer embedder") + # output = transformer_embedder_model_component( + # model=transformer_embedder_model, input="Hello world" + # ) + # print(output) + + # def test_transformer_client(self): + # transformer_client = TransformersClient() + # print("Testing transformer client") + # # run the model + # kwargs = { + # "model": "thenlper/gte-base", + # # "mock": False, + # } + # api_kwargs = transformer_client.convert_inputs_to_api_kwargs( + # input="Hello world", + # model_kwargs=kwargs, + # model_type=ModelType.EMBEDDER, + # ) + # # print(api_kwargs) + # output = transformer_client.call( + # api_kwargs=api_kwargs, model_type=ModelType.EMBEDDER + # ) + + # # print(transformer_client) + # # print(output) + + # def test_transformer_reranker(self): + # transformer_reranker_model = "BAAI/bge-reranker-base" + # transformer_reranker_model_component = TransformerReranker() + # # print( + # # f"Testing transformer reranker with model {transformer_reranker_model_component}" + # # ) + + # model_kwargs = { + # "model": transformer_reranker_model, + # "documents": self.documents, + # "query": self.query, + # "top_k": 2, + # } + + # output = transformer_reranker_model_component( + # **model_kwargs, + # ) + # # assert output is a list of float with length 2 + # self.assertEqual(len(output), 2) + # self.assertEqual(type(output[0]), float) + + # def test_transformer_reranker_client(self): + # transformer_reranker_client = TransformersClient( + # model_name="BAAI/bge-reranker-base" + # ) + # print("Testing transformer reranker client") + # # run the model + # kwargs = { + # "model": "BAAI/bge-reranker-base", + # "documents": self.documents, + # "top_k": 2, + # } + # api_kwargs = transformer_reranker_client.convert_inputs_to_api_kwargs( + # input=self.query, + # model_kwargs=kwargs, + # model_type=ModelType.RERANKER, + # ) + # print(api_kwargs) + # self.assertEqual(api_kwargs["model"], "BAAI/bge-reranker-base") + # output = transformer_reranker_client.call( + # api_kwargs=api_kwargs, model_type=ModelType.RERANKER + # ) + # self.assertEqual(type(output), tuple) + + + # def test_transformer_llm_response(self): + # """Test the TransformerLLM model with zephyr-7b-beta for generating a response.""" + # transformer_llm_model = "HuggingFaceH4/zephyr-7b-beta" + # transformer_llm_model_component = TransformerLLM(model_name=transformer_llm_model) + + # # Define a sample input + # input_text = "Hello, what's the weather today?" + + # # Test generating a response, providing the 'model' keyword + # # response = transformer_llm_model_component(input=input_text, model=transformer_llm_model) + # response = transformer_llm_model_component(input_text=input_text) + + + # # Check if the response is valid + # self.assertIsInstance(response, str, "The response should be a string.") + # self.assertTrue(len(response) > 0, "The response should not be empty.") + + # # Optionally, print the response for visual verification during testing + # print(f"Generated response: {response}") + + +if __name__ == '__main__': + unittest.main() \ No newline at end of file diff --git a/poetry.lock b/poetry.lock index c021f7d1..db792665 100644 --- a/poetry.lock +++ b/poetry.lock @@ -494,17 +494,17 @@ css = ["tinycss2 (>=1.1.0,<1.3)"] [[package]] name = "boto3" -version = "1.34.131" +version = "1.34.136" description = "The AWS SDK for Python" optional = false python-versions = ">=3.8" files = [ - {file = "boto3-1.34.131-py3-none-any.whl", hash = "sha256:05e388cb937e82be70bfd7eb0c84cf8011ff35cf582a593873ac21675268683b"}, - {file = "boto3-1.34.131.tar.gz", hash = "sha256:dab8f72a6c4e62b4fd70da09e08a6b2a65ea2115b27dd63737142005776ef216"}, + {file = "boto3-1.34.136-py3-none-any.whl", hash = "sha256:d41037e2c680ab8d6c61a0a4ee6bf1fdd9e857f43996672830a95d62d6f6fa79"}, + {file = "boto3-1.34.136.tar.gz", hash = "sha256:0314e6598f59ee0f34eb4e6d1a0f69fa65c146d2b88a6e837a527a9956ec2731"}, ] [package.dependencies] -botocore = ">=1.34.131,<1.35.0" +botocore = ">=1.34.136,<1.35.0" jmespath = ">=0.7.1,<2.0.0" s3transfer = ">=0.10.0,<0.11.0" @@ -513,13 +513,13 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] [[package]] name = "botocore" -version = "1.34.131" +version = "1.34.136" description = "Low-level, data-driven core of boto 3." optional = false python-versions = ">=3.8" files = [ - {file = "botocore-1.34.131-py3-none-any.whl", hash = "sha256:13b011d7b206ce00727dcee26548fa3b550db9046d5a0e90ac25a6e6c8fde6ef"}, - {file = "botocore-1.34.131.tar.gz", hash = "sha256:502ddafe1d627fcf1e4c007c86454e5dd011dba7c58bd8e8a5368a79f3e387dc"}, + {file = "botocore-1.34.136-py3-none-any.whl", hash = "sha256:c63fe9032091fb9e9477706a3ebfa4d0c109b807907051d892ed574f9b573e61"}, + {file = "botocore-1.34.136.tar.gz", hash = "sha256:7f7135178692b39143c8f152a618d2a3b71065a317569a7102d2306d4946f42f"}, ] [package.dependencies] @@ -791,6 +791,84 @@ traitlets = ">=4" [package.extras] test = ["pytest"] +[[package]] +name = "contourpy" +version = "1.2.1" +description = "Python library for calculating contours of 2D quadrilateral grids" +optional = false +python-versions = ">=3.9" +files = [ + {file = "contourpy-1.2.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bd7c23df857d488f418439686d3b10ae2fbf9bc256cd045b37a8c16575ea1040"}, + {file = "contourpy-1.2.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:5b9eb0ca724a241683c9685a484da9d35c872fd42756574a7cfbf58af26677fd"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:4c75507d0a55378240f781599c30e7776674dbaf883a46d1c90f37e563453480"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:11959f0ce4a6f7b76ec578576a0b61a28bdc0696194b6347ba3f1c53827178b9"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:eb3315a8a236ee19b6df481fc5f997436e8ade24a9f03dfdc6bd490fea20c6da"}, + {file = "contourpy-1.2.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39f3ecaf76cd98e802f094e0d4fbc6dc9c45a8d0c4d185f0f6c2234e14e5f75b"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:94b34f32646ca0414237168d68a9157cb3889f06b096612afdd296003fdd32fd"}, + {file = "contourpy-1.2.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:457499c79fa84593f22454bbd27670227874cd2ff5d6c84e60575c8b50a69619"}, + {file = "contourpy-1.2.1-cp310-cp310-win32.whl", hash = "sha256:ac58bdee53cbeba2ecad824fa8159493f0bf3b8ea4e93feb06c9a465d6c87da8"}, + {file = "contourpy-1.2.1-cp310-cp310-win_amd64.whl", hash = "sha256:9cffe0f850e89d7c0012a1fb8730f75edd4320a0a731ed0c183904fe6ecfc3a9"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6022cecf8f44e36af10bd9118ca71f371078b4c168b6e0fab43d4a889985dbb5"}, + {file = "contourpy-1.2.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:ef5adb9a3b1d0c645ff694f9bca7702ec2c70f4d734f9922ea34de02294fdf72"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6150ffa5c767bc6332df27157d95442c379b7dce3a38dff89c0f39b63275696f"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:4c863140fafc615c14a4bf4efd0f4425c02230eb8ef02784c9a156461e62c965"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:00e5388f71c1a0610e6fe56b5c44ab7ba14165cdd6d695429c5cd94021e390b2"}, + {file = "contourpy-1.2.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d4492d82b3bc7fbb7e3610747b159869468079fe149ec5c4d771fa1f614a14df"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:49e70d111fee47284d9dd867c9bb9a7058a3c617274900780c43e38d90fe1205"}, + {file = "contourpy-1.2.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:b59c0ffceff8d4d3996a45f2bb6f4c207f94684a96bf3d9728dbb77428dd8cb8"}, + {file = "contourpy-1.2.1-cp311-cp311-win32.whl", hash = "sha256:7b4182299f251060996af5249c286bae9361fa8c6a9cda5efc29fe8bfd6062ec"}, + {file = "contourpy-1.2.1-cp311-cp311-win_amd64.whl", hash = "sha256:2855c8b0b55958265e8b5888d6a615ba02883b225f2227461aa9127c578a4922"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:62828cada4a2b850dbef89c81f5a33741898b305db244904de418cc957ff05dc"}, + {file = "contourpy-1.2.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:309be79c0a354afff9ff7da4aaed7c3257e77edf6c1b448a779329431ee79d7e"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2e785e0f2ef0d567099b9ff92cbfb958d71c2d5b9259981cd9bee81bd194c9a4"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1cac0a8f71a041aa587410424ad46dfa6a11f6149ceb219ce7dd48f6b02b87a7"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:af3f4485884750dddd9c25cb7e3915d83c2db92488b38ccb77dd594eac84c4a0"}, + {file = "contourpy-1.2.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9ce6889abac9a42afd07a562c2d6d4b2b7134f83f18571d859b25624a331c90b"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:a1eea9aecf761c661d096d39ed9026574de8adb2ae1c5bd7b33558af884fb2ce"}, + {file = "contourpy-1.2.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:187fa1d4c6acc06adb0fae5544c59898ad781409e61a926ac7e84b8f276dcef4"}, + {file = "contourpy-1.2.1-cp312-cp312-win32.whl", hash = "sha256:c2528d60e398c7c4c799d56f907664673a807635b857df18f7ae64d3e6ce2d9f"}, + {file = "contourpy-1.2.1-cp312-cp312-win_amd64.whl", hash = "sha256:1a07fc092a4088ee952ddae19a2b2a85757b923217b7eed584fdf25f53a6e7ce"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:bb6834cbd983b19f06908b45bfc2dad6ac9479ae04abe923a275b5f48f1a186b"}, + {file = "contourpy-1.2.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:1d59e739ab0e3520e62a26c60707cc3ab0365d2f8fecea74bfe4de72dc56388f"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bd3db01f59fdcbce5b22afad19e390260d6d0222f35a1023d9adc5690a889364"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:a12a813949e5066148712a0626895c26b2578874e4cc63160bb007e6df3436fe"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:fe0ccca550bb8e5abc22f530ec0466136379c01321fd94f30a22231e8a48d985"}, + {file = "contourpy-1.2.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e1d59258c3c67c865435d8fbeb35f8c59b8bef3d6f46c1f29f6123556af28445"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:f32c38afb74bd98ce26de7cc74a67b40afb7b05aae7b42924ea990d51e4dac02"}, + {file = "contourpy-1.2.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:d31a63bc6e6d87f77d71e1abbd7387ab817a66733734883d1fc0021ed9bfa083"}, + {file = "contourpy-1.2.1-cp39-cp39-win32.whl", hash = "sha256:ddcb8581510311e13421b1f544403c16e901c4e8f09083c881fab2be80ee31ba"}, + {file = "contourpy-1.2.1-cp39-cp39-win_amd64.whl", hash = "sha256:10a37ae557aabf2509c79715cd20b62e4c7c28b8cd62dd7d99e5ed3ce28c3fd9"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:a31f94983fecbac95e58388210427d68cd30fe8a36927980fab9c20062645609"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ef2b055471c0eb466033760a521efb9d8a32b99ab907fc8358481a1dd29e3bd3"}, + {file = "contourpy-1.2.1-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:b33d2bc4f69caedcd0a275329eb2198f560b325605810895627be5d4b876bf7f"}, + {file = "contourpy-1.2.1.tar.gz", hash = "sha256:4d8908b3bee1c889e547867ca4cdc54e5ab6be6d3e078556814a22457f49423c"}, +] + +[package.dependencies] +numpy = ">=1.20" + +[package.extras] +bokeh = ["bokeh", "selenium"] +docs = ["furo", "sphinx (>=7.2)", "sphinx-copybutton"] +mypy = ["contourpy[bokeh,docs]", "docutils-stubs", "mypy (==1.8.0)", "types-Pillow"] +test = ["Pillow", "contourpy[test-no-images]", "matplotlib"] +test-no-images = ["pytest", "pytest-cov", "pytest-xdist", "wurlitzer"] + +[[package]] +name = "cycler" +version = "0.12.1" +description = "Composable style cycles" +optional = false +python-versions = ">=3.8" +files = [ + {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, + {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, +] + +[package.extras] +docs = ["ipython", "matplotlib", "numpydoc", "sphinx"] +tests = ["pytest", "pytest-cov", "pytest-xdist"] + [[package]] name = "dataclasses-json" version = "0.6.7" @@ -874,33 +952,33 @@ vision = ["Pillow (>=9.4.0)"] [[package]] name = "debugpy" -version = "1.8.1" +version = "1.8.2" description = "An implementation of the Debug Adapter Protocol for Python" optional = false python-versions = ">=3.8" files = [ - {file = "debugpy-1.8.1-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:3bda0f1e943d386cc7a0e71bfa59f4137909e2ed947fb3946c506e113000f741"}, - {file = "debugpy-1.8.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dda73bf69ea479c8577a0448f8c707691152e6c4de7f0c4dec5a4bc11dee516e"}, - {file = "debugpy-1.8.1-cp310-cp310-win32.whl", hash = "sha256:3a79c6f62adef994b2dbe9fc2cc9cc3864a23575b6e387339ab739873bea53d0"}, - {file = "debugpy-1.8.1-cp310-cp310-win_amd64.whl", hash = "sha256:7eb7bd2b56ea3bedb009616d9e2f64aab8fc7000d481faec3cd26c98a964bcdd"}, - {file = "debugpy-1.8.1-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:016a9fcfc2c6b57f939673c874310d8581d51a0fe0858e7fac4e240c5eb743cb"}, - {file = "debugpy-1.8.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fd97ed11a4c7f6d042d320ce03d83b20c3fb40da892f994bc041bbc415d7a099"}, - {file = "debugpy-1.8.1-cp311-cp311-win32.whl", hash = "sha256:0de56aba8249c28a300bdb0672a9b94785074eb82eb672db66c8144fff673146"}, - {file = "debugpy-1.8.1-cp311-cp311-win_amd64.whl", hash = "sha256:1a9fe0829c2b854757b4fd0a338d93bc17249a3bf69ecf765c61d4c522bb92a8"}, - {file = "debugpy-1.8.1-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:3ebb70ba1a6524d19fa7bb122f44b74170c447d5746a503e36adc244a20ac539"}, - {file = "debugpy-1.8.1-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a2e658a9630f27534e63922ebf655a6ab60c370f4d2fc5c02a5b19baf4410ace"}, - {file = "debugpy-1.8.1-cp312-cp312-win32.whl", hash = "sha256:caad2846e21188797a1f17fc09c31b84c7c3c23baf2516fed5b40b378515bbf0"}, - {file = "debugpy-1.8.1-cp312-cp312-win_amd64.whl", hash = "sha256:edcc9f58ec0fd121a25bc950d4578df47428d72e1a0d66c07403b04eb93bcf98"}, - {file = "debugpy-1.8.1-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:7a3afa222f6fd3d9dfecd52729bc2e12c93e22a7491405a0ecbf9e1d32d45b39"}, - {file = "debugpy-1.8.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d915a18f0597ef685e88bb35e5d7ab968964b7befefe1aaea1eb5b2640b586c7"}, - {file = "debugpy-1.8.1-cp38-cp38-win32.whl", hash = "sha256:92116039b5500633cc8d44ecc187abe2dfa9b90f7a82bbf81d079fcdd506bae9"}, - {file = "debugpy-1.8.1-cp38-cp38-win_amd64.whl", hash = "sha256:e38beb7992b5afd9d5244e96ad5fa9135e94993b0c551ceebf3fe1a5d9beb234"}, - {file = "debugpy-1.8.1-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:bfb20cb57486c8e4793d41996652e5a6a885b4d9175dd369045dad59eaacea42"}, - {file = "debugpy-1.8.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:efd3fdd3f67a7e576dd869c184c5dd71d9aaa36ded271939da352880c012e703"}, - {file = "debugpy-1.8.1-cp39-cp39-win32.whl", hash = "sha256:58911e8521ca0c785ac7a0539f1e77e0ce2df753f786188f382229278b4cdf23"}, - {file = "debugpy-1.8.1-cp39-cp39-win_amd64.whl", hash = "sha256:6df9aa9599eb05ca179fb0b810282255202a66835c6efb1d112d21ecb830ddd3"}, - {file = "debugpy-1.8.1-py2.py3-none-any.whl", hash = "sha256:28acbe2241222b87e255260c76741e1fbf04fdc3b6d094fcf57b6c6f75ce1242"}, - {file = "debugpy-1.8.1.zip", hash = "sha256:f696d6be15be87aef621917585f9bb94b1dc9e8aced570db1b8a6fc14e8f9b42"}, + {file = "debugpy-1.8.2-cp310-cp310-macosx_11_0_x86_64.whl", hash = "sha256:7ee2e1afbf44b138c005e4380097d92532e1001580853a7cb40ed84e0ef1c3d2"}, + {file = "debugpy-1.8.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3f8c3f7c53130a070f0fc845a0f2cee8ed88d220d6b04595897b66605df1edd6"}, + {file = "debugpy-1.8.2-cp310-cp310-win32.whl", hash = "sha256:f179af1e1bd4c88b0b9f0fa153569b24f6b6f3de33f94703336363ae62f4bf47"}, + {file = "debugpy-1.8.2-cp310-cp310-win_amd64.whl", hash = "sha256:0600faef1d0b8d0e85c816b8bb0cb90ed94fc611f308d5fde28cb8b3d2ff0fe3"}, + {file = "debugpy-1.8.2-cp311-cp311-macosx_11_0_universal2.whl", hash = "sha256:8a13417ccd5978a642e91fb79b871baded925d4fadd4dfafec1928196292aa0a"}, + {file = "debugpy-1.8.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:acdf39855f65c48ac9667b2801234fc64d46778021efac2de7e50907ab90c634"}, + {file = "debugpy-1.8.2-cp311-cp311-win32.whl", hash = "sha256:2cbd4d9a2fc5e7f583ff9bf11f3b7d78dfda8401e8bb6856ad1ed190be4281ad"}, + {file = "debugpy-1.8.2-cp311-cp311-win_amd64.whl", hash = "sha256:d3408fddd76414034c02880e891ea434e9a9cf3a69842098ef92f6e809d09afa"}, + {file = "debugpy-1.8.2-cp312-cp312-macosx_11_0_universal2.whl", hash = "sha256:5d3ccd39e4021f2eb86b8d748a96c766058b39443c1f18b2dc52c10ac2757835"}, + {file = "debugpy-1.8.2-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:62658aefe289598680193ff655ff3940e2a601765259b123dc7f89c0239b8cd3"}, + {file = "debugpy-1.8.2-cp312-cp312-win32.whl", hash = "sha256:bd11fe35d6fd3431f1546d94121322c0ac572e1bfb1f6be0e9b8655fb4ea941e"}, + {file = "debugpy-1.8.2-cp312-cp312-win_amd64.whl", hash = "sha256:15bc2f4b0f5e99bf86c162c91a74c0631dbd9cef3c6a1d1329c946586255e859"}, + {file = "debugpy-1.8.2-cp38-cp38-macosx_11_0_x86_64.whl", hash = "sha256:5a019d4574afedc6ead1daa22736c530712465c0c4cd44f820d803d937531b2d"}, + {file = "debugpy-1.8.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:40f062d6877d2e45b112c0bbade9a17aac507445fd638922b1a5434df34aed02"}, + {file = "debugpy-1.8.2-cp38-cp38-win32.whl", hash = "sha256:c78ba1680f1015c0ca7115671fe347b28b446081dada3fedf54138f44e4ba031"}, + {file = "debugpy-1.8.2-cp38-cp38-win_amd64.whl", hash = "sha256:cf327316ae0c0e7dd81eb92d24ba8b5e88bb4d1b585b5c0d32929274a66a5210"}, + {file = "debugpy-1.8.2-cp39-cp39-macosx_11_0_x86_64.whl", hash = "sha256:1523bc551e28e15147815d1397afc150ac99dbd3a8e64641d53425dba57b0ff9"}, + {file = "debugpy-1.8.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:e24ccb0cd6f8bfaec68d577cb49e9c680621c336f347479b3fce060ba7c09ec1"}, + {file = "debugpy-1.8.2-cp39-cp39-win32.whl", hash = "sha256:7f8d57a98c5a486c5c7824bc0b9f2f11189d08d73635c326abef268f83950326"}, + {file = "debugpy-1.8.2-cp39-cp39-win_amd64.whl", hash = "sha256:16c8dcab02617b75697a0a925a62943e26a0330da076e2a10437edd9f0bf3755"}, + {file = "debugpy-1.8.2-py2.py3-none-any.whl", hash = "sha256:16e16df3a98a35c63c3ab1e4d19be4cbc7fdda92d9ddc059294f18910928e0ca"}, + {file = "debugpy-1.8.2.zip", hash = "sha256:95378ed08ed2089221896b9b3a8d021e642c24edc8fef20e5d4342ca8be65c00"}, ] [[package]] @@ -1108,6 +1186,71 @@ sentence_transformers = "*" torch = ">=1.6.0" transformers = ">=4.33.0" +[[package]] +name = "fonttools" +version = "4.53.0" +description = "Tools to manipulate font files" +optional = false +python-versions = ">=3.8" +files = [ + {file = "fonttools-4.53.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:52a6e0a7a0bf611c19bc8ec8f7592bdae79c8296c70eb05917fd831354699b20"}, + {file = "fonttools-4.53.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:099634631b9dd271d4a835d2b2a9e042ccc94ecdf7e2dd9f7f34f7daf333358d"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e40013572bfb843d6794a3ce076c29ef4efd15937ab833f520117f8eccc84fd6"}, + {file = "fonttools-4.53.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:715b41c3e231f7334cbe79dfc698213dcb7211520ec7a3bc2ba20c8515e8a3b5"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:74ae2441731a05b44d5988d3ac2cf784d3ee0a535dbed257cbfff4be8bb49eb9"}, + {file = "fonttools-4.53.0-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:95db0c6581a54b47c30860d013977b8a14febc206c8b5ff562f9fe32738a8aca"}, + {file = "fonttools-4.53.0-cp310-cp310-win32.whl", hash = "sha256:9cd7a6beec6495d1dffb1033d50a3f82dfece23e9eb3c20cd3c2444d27514068"}, + {file = "fonttools-4.53.0-cp310-cp310-win_amd64.whl", hash = "sha256:daaef7390e632283051e3cf3e16aff2b68b247e99aea916f64e578c0449c9c68"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:a209d2e624ba492df4f3bfad5996d1f76f03069c6133c60cd04f9a9e715595ec"}, + {file = "fonttools-4.53.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:4f520d9ac5b938e6494f58a25c77564beca7d0199ecf726e1bd3d56872c59749"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:eceef49f457253000e6a2d0f7bd08ff4e9fe96ec4ffce2dbcb32e34d9c1b8161"}, + {file = "fonttools-4.53.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:fa1f3e34373aa16045484b4d9d352d4c6b5f9f77ac77a178252ccbc851e8b2ee"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:28d072169fe8275fb1a0d35e3233f6df36a7e8474e56cb790a7258ad822b6fd6"}, + {file = "fonttools-4.53.0-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:4a2a6ba400d386e904fd05db81f73bee0008af37799a7586deaa4aef8cd5971e"}, + {file = "fonttools-4.53.0-cp311-cp311-win32.whl", hash = "sha256:bb7273789f69b565d88e97e9e1da602b4ee7ba733caf35a6c2affd4334d4f005"}, + {file = "fonttools-4.53.0-cp311-cp311-win_amd64.whl", hash = "sha256:9fe9096a60113e1d755e9e6bda15ef7e03391ee0554d22829aa506cdf946f796"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:d8f191a17369bd53a5557a5ee4bab91d5330ca3aefcdf17fab9a497b0e7cff7a"}, + {file = "fonttools-4.53.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:93156dd7f90ae0a1b0e8871032a07ef3178f553f0c70c386025a808f3a63b1f4"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:bff98816cb144fb7b85e4b5ba3888a33b56ecef075b0e95b95bcd0a5fbf20f06"}, + {file = "fonttools-4.53.0-cp312-cp312-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:973d030180eca8255b1bce6ffc09ef38a05dcec0e8320cc9b7bcaa65346f341d"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:c4ee5a24e281fbd8261c6ab29faa7fd9a87a12e8c0eed485b705236c65999109"}, + {file = "fonttools-4.53.0-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:bd5bc124fae781a4422f61b98d1d7faa47985f663a64770b78f13d2c072410c2"}, + {file = "fonttools-4.53.0-cp312-cp312-win32.whl", hash = "sha256:a239afa1126b6a619130909c8404070e2b473dd2b7fc4aacacd2e763f8597fea"}, + {file = "fonttools-4.53.0-cp312-cp312-win_amd64.whl", hash = "sha256:45b4afb069039f0366a43a5d454bc54eea942bfb66b3fc3e9a2c07ef4d617380"}, + {file = "fonttools-4.53.0-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:93bc9e5aaa06ff928d751dc6be889ff3e7d2aa393ab873bc7f6396a99f6fbb12"}, + {file = "fonttools-4.53.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2367d47816cc9783a28645bc1dac07f8ffc93e0f015e8c9fc674a5b76a6da6e4"}, + {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:907fa0b662dd8fc1d7c661b90782ce81afb510fc4b7aa6ae7304d6c094b27bce"}, + {file = "fonttools-4.53.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3e0ad3c6ea4bd6a289d958a1eb922767233f00982cf0fe42b177657c86c80a8f"}, + {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_aarch64.whl", hash = "sha256:73121a9b7ff93ada888aaee3985a88495489cc027894458cb1a736660bdfb206"}, + {file = "fonttools-4.53.0-cp38-cp38-musllinux_1_2_x86_64.whl", hash = "sha256:ee595d7ba9bba130b2bec555a40aafa60c26ce68ed0cf509983e0f12d88674fd"}, + {file = "fonttools-4.53.0-cp38-cp38-win32.whl", hash = "sha256:fca66d9ff2ac89b03f5aa17e0b21a97c21f3491c46b583bb131eb32c7bab33af"}, + {file = "fonttools-4.53.0-cp38-cp38-win_amd64.whl", hash = "sha256:31f0e3147375002aae30696dd1dc596636abbd22fca09d2e730ecde0baad1d6b"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:7d6166192dcd925c78a91d599b48960e0a46fe565391c79fe6de481ac44d20ac"}, + {file = "fonttools-4.53.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:ef50ec31649fbc3acf6afd261ed89d09eb909b97cc289d80476166df8438524d"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7f193f060391a455920d61684a70017ef5284ccbe6023bb056e15e5ac3de11d1"}, + {file = "fonttools-4.53.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba9f09ff17f947392a855e3455a846f9855f6cf6bec33e9a427d3c1d254c712f"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_aarch64.whl", hash = "sha256:0c555e039d268445172b909b1b6bdcba42ada1cf4a60e367d68702e3f87e5f64"}, + {file = "fonttools-4.53.0-cp39-cp39-musllinux_1_2_x86_64.whl", hash = "sha256:5a4788036201c908079e89ae3f5399b33bf45b9ea4514913f4dbbe4fac08efe0"}, + {file = "fonttools-4.53.0-cp39-cp39-win32.whl", hash = "sha256:d1a24f51a3305362b94681120c508758a88f207fa0a681c16b5a4172e9e6c7a9"}, + {file = "fonttools-4.53.0-cp39-cp39-win_amd64.whl", hash = "sha256:1e677bfb2b4bd0e5e99e0f7283e65e47a9814b0486cb64a41adf9ef110e078f2"}, + {file = "fonttools-4.53.0-py3-none-any.whl", hash = "sha256:6b4f04b1fbc01a3569d63359f2227c89ab294550de277fd09d8fca6185669fa4"}, + {file = "fonttools-4.53.0.tar.gz", hash = "sha256:c93ed66d32de1559b6fc348838c7572d5c0ac1e4a258e76763a5caddd8944002"}, +] + +[package.extras] +all = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "fs (>=2.2.0,<3)", "lxml (>=4.0)", "lz4 (>=1.7.4.2)", "matplotlib", "munkres", "pycairo", "scipy", "skia-pathops (>=0.5.0)", "sympy", "uharfbuzz (>=0.23.0)", "unicodedata2 (>=15.1.0)", "xattr", "zopfli (>=0.1.4)"] +graphite = ["lz4 (>=1.7.4.2)"] +interpolatable = ["munkres", "pycairo", "scipy"] +lxml = ["lxml (>=4.0)"] +pathops = ["skia-pathops (>=0.5.0)"] +plot = ["matplotlib"] +repacker = ["uharfbuzz (>=0.23.0)"] +symfont = ["sympy"] +type1 = ["xattr"] +ufo = ["fs (>=2.2.0,<3)"] +unicode = ["unicodedata2 (>=15.1.0)"] +woff = ["brotli (>=1.0.1)", "brotlicffi (>=0.8.0)", "zopfli (>=0.1.4)"] + [[package]] name = "fqdn" version = "1.5.1" @@ -1265,13 +1408,13 @@ protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4 [[package]] name = "google-api-core" -version = "2.19.0" +version = "2.19.1" description = "Google API client core library" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-core-2.19.0.tar.gz", hash = "sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10"}, - {file = "google_api_core-2.19.0-py3-none-any.whl", hash = "sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251"}, + {file = "google-api-core-2.19.1.tar.gz", hash = "sha256:f4695f1e3650b316a795108a76a1c416e6afb036199d1c1f1f110916df479ffd"}, + {file = "google_api_core-2.19.1-py3-none-any.whl", hash = "sha256:f12a9b8309b5e21d92483bbd47ce2c445861ec7d269ef6784ecc0ea8c1fa6125"}, ] [package.dependencies] @@ -1280,7 +1423,7 @@ googleapis-common-protos = ">=1.56.2,<2.0.dev0" grpcio = {version = ">=1.49.1,<2.0dev", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} grpcio-status = {version = ">=1.49.1,<2.0.dev0", optional = true, markers = "python_version >= \"3.11\" and extra == \"grpc\""} proto-plus = ">=1.22.3,<2.0.0dev" -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<5.0.0.dev0" +protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.0 || >4.21.0,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" requests = ">=2.18.0,<3.0.0.dev0" [package.extras] @@ -1290,13 +1433,13 @@ grpcio-gcp = ["grpcio-gcp (>=0.2.2,<1.0.dev0)"] [[package]] name = "google-api-python-client" -version = "2.134.0" +version = "2.135.0" description = "Google API Client Library for Python" optional = false python-versions = ">=3.7" files = [ - {file = "google-api-python-client-2.134.0.tar.gz", hash = "sha256:4a8f0bea651a212997cc83c0f271fc86f80ef93d1cee9d84de7dfaeef2a858b6"}, - {file = "google_api_python_client-2.134.0-py2.py3-none-any.whl", hash = "sha256:ba05d60f6239990b7994f6328f17bb154c602d31860fb553016dc9f8ce886945"}, + {file = "google-api-python-client-2.135.0.tar.gz", hash = "sha256:b552a28123ed95493035698db80e8ed78c9106a8b422e63a175150b9b55b704e"}, + {file = "google_api_python_client-2.135.0-py2.py3-none-any.whl", hash = "sha256:91742fa4c779d48456c0256ef346fa1cc185ba427176d3277e35141fa3268026"}, ] [package.dependencies] @@ -1369,17 +1512,17 @@ dev = ["Pillow", "absl-py", "black", "ipython", "nose2", "pandas", "pytype", "py [[package]] name = "googleapis-common-protos" -version = "1.63.1" +version = "1.63.2" description = "Common protobufs used in Google APIs" optional = false python-versions = ">=3.7" files = [ - {file = "googleapis-common-protos-1.63.1.tar.gz", hash = "sha256:c6442f7a0a6b2a80369457d79e6672bb7dcbaab88e0848302497e3ec80780a6a"}, - {file = "googleapis_common_protos-1.63.1-py2.py3-none-any.whl", hash = "sha256:0e1c2cdfcbc354b76e4a211a35ea35d6926a835cba1377073c4861db904a1877"}, + {file = "googleapis-common-protos-1.63.2.tar.gz", hash = "sha256:27c5abdffc4911f28101e635de1533fb4cfd2c37fbaa9174587c799fac90aa87"}, + {file = "googleapis_common_protos-1.63.2-py2.py3-none-any.whl", hash = "sha256:27a2499c7e8aff199665b22741997e485eccc8645aa9176c7c988e6fae507945"}, ] [package.dependencies] -protobuf = ">=3.19.5,<3.20.0 || >3.20.0,<3.20.1 || >3.20.1,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" +protobuf = ">=3.20.2,<4.21.1 || >4.21.1,<4.21.2 || >4.21.2,<4.21.3 || >4.21.3,<4.21.4 || >4.21.4,<4.21.5 || >4.21.5,<6.0.0.dev0" [package.extras] grpc = ["grpcio (>=1.44.0,<2.0.0.dev0)"] @@ -1748,13 +1891,13 @@ test = ["flaky", "ipyparallel", "pre-commit", "pytest (>=7.0)", "pytest-asyncio [[package]] name = "ipython" -version = "8.25.0" +version = "8.26.0" description = "IPython: Productive Interactive Computing" optional = false python-versions = ">=3.10" files = [ - {file = "ipython-8.25.0-py3-none-any.whl", hash = "sha256:53eee7ad44df903a06655871cbab66d156a051fd86f3ec6750470ac9604ac1ab"}, - {file = "ipython-8.25.0.tar.gz", hash = "sha256:c6ed726a140b6e725b911528f80439c534fac915246af3efc39440a6b0f9d716"}, + {file = "ipython-8.26.0-py3-none-any.whl", hash = "sha256:e6b347c27bdf9c32ee9d31ae85defc525755a1869f14057e900675b9e8d6e6ff"}, + {file = "ipython-8.26.0.tar.gz", hash = "sha256:1cec0fbba8404af13facebe83d04436a7434c7400e59f47acf467c64abd0956c"}, ] [package.dependencies] @@ -1780,7 +1923,7 @@ nbformat = ["nbformat"] notebook = ["ipywidgets", "notebook"] parallel = ["ipyparallel"] qtconsole = ["qtconsole"] -test = ["pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] +test = ["packaging", "pickleshare", "pytest", "pytest-asyncio (<0.22)", "testpath"] test-extra = ["curio", "ipython[test]", "matplotlib (!=3.2.0)", "nbformat", "numpy (>=1.23)", "pandas", "trio"] [[package]] @@ -1856,72 +1999,72 @@ i18n = ["Babel (>=2.7)"] [[package]] name = "jiter" -version = "0.4.2" +version = "0.5.0" description = "Fast iterable JSON parser." optional = false python-versions = ">=3.8" files = [ - {file = "jiter-0.4.2-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:c2b003ff58d14f5e182b875acd5177b2367245c19a03be9a2230535d296f7550"}, - {file = "jiter-0.4.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:b48c77c25f094707731cd5bad6b776046846b60a27ee20efc8fadfb10a89415f"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9f50ad6b172bde4d45f4d4ea10c49282a337b8bb735afc99763dfa55ea84a743"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:95f6001e86f525fbbc9706db2078dc22be078b0950de55b92d37041930f5f940"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:16646ef23b62b007de80460d303ebb2d81e355dac9389c787cec87cdd7ffef2f"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4b4e847c13b0bf1255c711a92330e7a8cb8b5cdd1e37d7db309627bcdd3367ff"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3c536589be60e4c5f2b20fadc4db7e9f55d4c9df3551f29ddf1c4a18dcc9dd54"}, - {file = "jiter-0.4.2-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:b3b2763996167830889a854b4ded30bb90897f9b76be78069c50c3ec4540950e"}, - {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:675e8ab98c99495091af6b6e9bf2b6353bcf81f25ab6ce27d36127e315b4505d"}, - {file = "jiter-0.4.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:e48e43d9d999aaf55f53406b8846ff8cbe3e47ee4b9dc37e5a10a65ce760809f"}, - {file = "jiter-0.4.2-cp310-none-win32.whl", hash = "sha256:881b6e67c50bc36acb3570eda693763c8cd77d590940e06fa6d325d0da52ec1b"}, - {file = "jiter-0.4.2-cp310-none-win_amd64.whl", hash = "sha256:bb8f7b43259efc6add0d721ade2953e064b24e2026d26d979bc09ec080844cef"}, - {file = "jiter-0.4.2-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:24ad336ac47f274fa83f6fbedcabff9d3387c80f67c66b992688e6a8ba2c47e9"}, - {file = "jiter-0.4.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fc392a220095730afe365ce1516f2f88bb085a2fd29ea191be9c6e3c71713d9a"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c1fdc408de36c81460896de0176f2f7b9f3574dcd35693a0b2c00f4ca34c98e4"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c10ad76722ee6a8c820b0db06a793c08b7d679e5201b9563015bd1e06c959a09"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:dbb46d1e9c82bba87f0cbda38413e49448a7df35b1e55917124bff9f38974a23"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:194e28ef4b5f3b61408cb2ee6b6dcbcdb0c9063d01b92b01345b7605692849f5"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1f0a447533eccd62748a727e058efa10a8d7cf1de8ffe1a4d705ecb41dad9090"}, - {file = "jiter-0.4.2-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:5f7704d7260bbb88cca3453951af739589132b26e896a3144fa2dae2263716d7"}, - {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:01427458bc9550f2eda09d425755330e7d0eb09adce099577433bebf05d28d59"}, - {file = "jiter-0.4.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:159b8416879c0053b17c352f70b67b749ef5b2924c6154318ecf71918aab0905"}, - {file = "jiter-0.4.2-cp311-none-win32.whl", hash = "sha256:f2445234acfb79048ce1a0d5d0e181abb9afd9e4a29d8d9988fe26cc5773a81a"}, - {file = "jiter-0.4.2-cp311-none-win_amd64.whl", hash = "sha256:e15a65f233b6b0e5ac10ddf3b97ceb18aa9ffba096259961641d78b4ee321bd5"}, - {file = "jiter-0.4.2-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:d61d59521aea9745447ce50f74d39a16ef74ec9d6477d9350d77e75a3d774ad2"}, - {file = "jiter-0.4.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:8eef607dc0acc251923427808dbd017f1998ae3c1a0430a261527aa5cbb3a942"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:af6bf39954646e374fc47429c656372ac731a6a26b644158a5a84bcdbed33a47"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8f509d23606e476852ee46a2b65b5c4ad3905f17424d9cc19c1dffa1c94ba3c6"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59672774daa44ee140aada0c781c82bee4d9ac5e522966186cfb6b3c217d8a51"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:24a0458efac5afeca254cf557b8a654e17013075a69905c78f88d557f129d871"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d8860766d1c293e75c1bb4e25b74fa987e3adf199cac3f5f9e6e49c2bebf092f"}, - {file = "jiter-0.4.2-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:a109f3281b72bbf4921fe43db1005c004a38559ca0b6c4985add81777dfe0a44"}, - {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:faa7e667454b77ad2f0ef87db39f4944de759617aadf210ea2b73f26bb24755f"}, - {file = "jiter-0.4.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:3512f8b00cafb6780b427cb6282800d2bf8277161d9c917830661bd4ed1d3528"}, - {file = "jiter-0.4.2-cp312-none-win32.whl", hash = "sha256:853b35d508ee5b66d06630473c1c0b7bb5e29bf4785c9d2202437116c94f7e21"}, - {file = "jiter-0.4.2-cp312-none-win_amd64.whl", hash = "sha256:4a3a8197784278eb8b24cb02c45e1cad67c2ce5b5b758adfb19b87f74bbdff9c"}, - {file = "jiter-0.4.2-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:ca2a4d750aed3154b89f2efb148609fc985fad8db739460797aaf9b478acedda"}, - {file = "jiter-0.4.2-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:0e6c304b3cc6896256727e1fb8991c7179a345eca8224e201795e9cacf4683b0"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:7cc34ac708ae1750d077e490321761ec4b9a055b994cbdd1d6fbd37099e4aa7b"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:8c93383875ab8d2e4f760aaff335b4a12ff32d4f9cf49c4498d657734f611466"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:ce197ee044add576afca0955b42142dd0312639adb6ebadbdbe4277f2855614f"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a427716813ff65480ca5b5117cfa099f49b49cd38051f8609bd0d5493013ca0"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:479990218353356234669e70fac53e5eb6f739a10db25316171aede2c97d9364"}, - {file = "jiter-0.4.2-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:d35a91ec5ac74cf33234c431505299fa91c0a197c2dbafd47400aca7c69489d4"}, - {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:b27189847193708c94ad10ca0d891309342ae882725d2187cf5d2db02bde8d1b"}, - {file = "jiter-0.4.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:76c255308cd1093fb411a03756b7bb220e48d4a98c30cbc79ed448bf3978e27d"}, - {file = "jiter-0.4.2-cp38-none-win32.whl", hash = "sha256:bb77438060bad49cc251941e6701b31138365c8a0ddaf10cdded2fcc6dd30701"}, - {file = "jiter-0.4.2-cp38-none-win_amd64.whl", hash = "sha256:ce858af19f7ce0d4b51c9f6c0c9d08f1e9dcef1986c5875efd0674a7054292ca"}, - {file = "jiter-0.4.2-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:6128838a2f357b3921b2a3242d5dc002ae4255ecc8f9f05c20d56d7d2d79c5ad"}, - {file = "jiter-0.4.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f2420cebb9ba856cb57dcab1d2d8def949b464b0db09c22a4e4dbd52fff7b200"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c5d13d8128e853b320e00bb18bd4bb8b136cc0936091dc87633648fc688eb705"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:eba5d6e54f149c508ba88677f97d3dc7dd75e9980d234bbac8027ac6db0763a3"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0fad5d64af0bc0545237419bf4150d8de56f0bd217434bdd1a59730327252bef"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:8d179e7bca89cf5719bd761dd37a341ff0f98199ecaa9c14af09792e47e977cc"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:36353caee9f103d8ee7bda077f6400505b0f370e27eabcab33a33d21de12a2a6"}, - {file = "jiter-0.4.2-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:dd146c25bce576ca5db64fc7eccb8862af00f1f0e30108796953f12a53660e4c"}, - {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:14b7c08cadbcd703041c66dc30e24e17de2f340281cac0e69374223ecf153aa4"}, - {file = "jiter-0.4.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a90f1a8b3d29aea198f8ea2b01148276ced8056e5103f32525266b3d880e65c9"}, - {file = "jiter-0.4.2-cp39-none-win32.whl", hash = "sha256:25b174997c780337b61ae57b1723455eecae9a17a9659044fd3c3b369190063f"}, - {file = "jiter-0.4.2-cp39-none-win_amd64.whl", hash = "sha256:bef62cea18521c5b99368147040c7e560c55098a35c93456f110678a2d34189a"}, - {file = "jiter-0.4.2.tar.gz", hash = "sha256:29b9d44f23f0c05f46d482f4ebf03213ee290d77999525d0975a17f875bf1eea"}, + {file = "jiter-0.5.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:b599f4e89b3def9a94091e6ee52e1d7ad7bc33e238ebb9c4c63f211d74822c3f"}, + {file = "jiter-0.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:2a063f71c4b06225543dddadbe09d203dc0c95ba352d8b85f1221173480a71d5"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:acc0d5b8b3dd12e91dd184b87273f864b363dfabc90ef29a1092d269f18c7e28"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:c22541f0b672f4d741382a97c65609332a783501551445ab2df137ada01e019e"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:63314832e302cc10d8dfbda0333a384bf4bcfce80d65fe99b0f3c0da8945a91a"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a25fbd8a5a58061e433d6fae6d5298777c0814a8bcefa1e5ecfff20c594bd749"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:503b2c27d87dfff5ab717a8200fbbcf4714516c9d85558048b1fc14d2de7d8dc"}, + {file = "jiter-0.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:6d1f3d27cce923713933a844872d213d244e09b53ec99b7a7fdf73d543529d6d"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c95980207b3998f2c3b3098f357994d3fd7661121f30669ca7cb945f09510a87"}, + {file = "jiter-0.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:afa66939d834b0ce063f57d9895e8036ffc41c4bd90e4a99631e5f261d9b518e"}, + {file = "jiter-0.5.0-cp310-none-win32.whl", hash = "sha256:f16ca8f10e62f25fd81d5310e852df6649af17824146ca74647a018424ddeccf"}, + {file = "jiter-0.5.0-cp310-none-win_amd64.whl", hash = "sha256:b2950e4798e82dd9176935ef6a55cf6a448b5c71515a556da3f6b811a7844f1e"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:d4c8e1ed0ef31ad29cae5ea16b9e41529eb50a7fba70600008e9f8de6376d553"}, + {file = "jiter-0.5.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:c6f16e21276074a12d8421692515b3fd6d2ea9c94fd0734c39a12960a20e85f3"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5280e68e7740c8c128d3ae5ab63335ce6d1fb6603d3b809637b11713487af9e6"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:583c57fc30cc1fec360e66323aadd7fc3edeec01289bfafc35d3b9dcb29495e4"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:26351cc14507bdf466b5f99aba3df3143a59da75799bf64a53a3ad3155ecded9"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4829df14d656b3fb87e50ae8b48253a8851c707da9f30d45aacab2aa2ba2d614"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a42a4bdcf7307b86cb863b2fb9bb55029b422d8f86276a50487982d99eed7c6e"}, + {file = "jiter-0.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:04d461ad0aebf696f8da13c99bc1b3e06f66ecf6cfd56254cc402f6385231c06"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:e6375923c5f19888c9226582a124b77b622f8fd0018b843c45eeb19d9701c403"}, + {file = "jiter-0.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:2cec323a853c24fd0472517113768c92ae0be8f8c384ef4441d3632da8baa646"}, + {file = "jiter-0.5.0-cp311-none-win32.whl", hash = "sha256:aa1db0967130b5cab63dfe4d6ff547c88b2a394c3410db64744d491df7f069bb"}, + {file = "jiter-0.5.0-cp311-none-win_amd64.whl", hash = "sha256:aa9d2b85b2ed7dc7697597dcfaac66e63c1b3028652f751c81c65a9f220899ae"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:9f664e7351604f91dcdd557603c57fc0d551bc65cc0a732fdacbf73ad335049a"}, + {file = "jiter-0.5.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:044f2f1148b5248ad2c8c3afb43430dccf676c5a5834d2f5089a4e6c5bbd64df"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:702e3520384c88b6e270c55c772d4bd6d7b150608dcc94dea87ceba1b6391248"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:528d742dcde73fad9d63e8242c036ab4a84389a56e04efd854062b660f559544"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8cf80e5fe6ab582c82f0c3331df27a7e1565e2dcf06265afd5173d809cdbf9ba"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:44dfc9ddfb9b51a5626568ef4e55ada462b7328996294fe4d36de02fce42721f"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c451f7922992751a936b96c5f5b9bb9312243d9b754c34b33d0cb72c84669f4e"}, + {file = "jiter-0.5.0-cp312-cp312-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:308fce789a2f093dca1ff91ac391f11a9f99c35369117ad5a5c6c4903e1b3e3a"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:7f5ad4a7c6b0d90776fdefa294f662e8a86871e601309643de30bf94bb93a64e"}, + {file = "jiter-0.5.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:ea189db75f8eca08807d02ae27929e890c7d47599ce3d0a6a5d41f2419ecf338"}, + {file = "jiter-0.5.0-cp312-none-win32.whl", hash = "sha256:e3bbe3910c724b877846186c25fe3c802e105a2c1fc2b57d6688b9f8772026e4"}, + {file = "jiter-0.5.0-cp312-none-win_amd64.whl", hash = "sha256:a586832f70c3f1481732919215f36d41c59ca080fa27a65cf23d9490e75b2ef5"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:f04bc2fc50dc77be9d10f73fcc4e39346402ffe21726ff41028f36e179b587e6"}, + {file = "jiter-0.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:6f433a4169ad22fcb550b11179bb2b4fd405de9b982601914ef448390b2954f3"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ad4a6398c85d3a20067e6c69890ca01f68659da94d74c800298581724e426c7e"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:6baa88334e7af3f4d7a5c66c3a63808e5efbc3698a1c57626541ddd22f8e4fbf"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1ece0a115c05efca597c6d938f88c9357c843f8c245dbbb53361a1c01afd7148"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:335942557162ad372cc367ffaf93217117401bf930483b4b3ebdb1223dbddfa7"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:649b0ee97a6e6da174bffcb3c8c051a5935d7d4f2f52ea1583b5b3e7822fbf14"}, + {file = "jiter-0.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:f4be354c5de82157886ca7f5925dbda369b77344b4b4adf2723079715f823989"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:5206144578831a6de278a38896864ded4ed96af66e1e63ec5dd7f4a1fce38a3a"}, + {file = "jiter-0.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:8120c60f8121ac3d6f072b97ef0e71770cc72b3c23084c72c4189428b1b1d3b6"}, + {file = "jiter-0.5.0-cp38-none-win32.whl", hash = "sha256:6f1223f88b6d76b519cb033a4d3687ca157c272ec5d6015c322fc5b3074d8a5e"}, + {file = "jiter-0.5.0-cp38-none-win_amd64.whl", hash = "sha256:c59614b225d9f434ea8fc0d0bec51ef5fa8c83679afedc0433905994fb36d631"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:0af3838cfb7e6afee3f00dc66fa24695199e20ba87df26e942820345b0afc566"}, + {file = "jiter-0.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:550b11d669600dbc342364fd4adbe987f14d0bbedaf06feb1b983383dcc4b961"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:489875bf1a0ffb3cb38a727b01e6673f0f2e395b2aad3c9387f94187cb214bbf"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:b250ca2594f5599ca82ba7e68785a669b352156260c5362ea1b4e04a0f3e2389"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8ea18e01f785c6667ca15407cd6dabbe029d77474d53595a189bdc813347218e"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:462a52be85b53cd9bffd94e2d788a09984274fe6cebb893d6287e1c296d50653"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:92cc68b48d50fa472c79c93965e19bd48f40f207cb557a8346daa020d6ba973b"}, + {file = "jiter-0.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:1c834133e59a8521bc87ebcad773608c6fa6ab5c7a022df24a45030826cf10bc"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:ab3a71ff31cf2d45cb216dc37af522d335211f3a972d2fe14ea99073de6cb104"}, + {file = "jiter-0.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:cccd3af9c48ac500c95e1bcbc498020c87e1781ff0345dd371462d67b76643eb"}, + {file = "jiter-0.5.0-cp39-none-win32.whl", hash = "sha256:368084d8d5c4fc40ff7c3cc513c4f73e02c85f6009217922d0823a48ee7adf61"}, + {file = "jiter-0.5.0-cp39-none-win_amd64.whl", hash = "sha256:ce03f7b4129eb72f1687fa11300fbf677b02990618428934662406d2a76742a1"}, + {file = "jiter-0.5.0.tar.gz", hash = "sha256:1d916ba875bcab5c5f7d927df998c4cb694d27dceddf3392e58beaf10563368a"}, ] [[package]] @@ -1985,6 +2128,22 @@ files = [ [package.dependencies] jsonpointer = ">=1.9" +[[package]] +name = "jsonpickle" +version = "3.2.2" +description = "Python library for serializing arbitrary object graphs into JSON" +optional = false +python-versions = ">=3.7" +files = [ + {file = "jsonpickle-3.2.2-py3-none-any.whl", hash = "sha256:87cd82d237fd72c5a34970e7222dddc0accc13fddf49af84111887ed9a9445aa"}, + {file = "jsonpickle-3.2.2.tar.gz", hash = "sha256:d425fd2b8afe9f5d7d57205153403fbf897782204437882a477e8eed60930f8c"}, +] + +[package.extras] +docs = ["furo", "rst.linker (>=1.9)", "sphinx"] +packaging = ["build", "twine"] +testing = ["bson", "ecdsa", "feedparser", "gmpy2", "numpy", "pandas", "pymongo", "pytest (>=3.5,!=3.7.3)", "pytest-benchmark", "pytest-benchmark[histogram]", "pytest-checkdocs (>=1.2.3)", "pytest-cov", "pytest-enabler (>=1.0.1)", "pytest-ruff (>=0.2.1)", "scikit-learn", "scipy", "scipy (>=1.9.3)", "simplejson", "sqlalchemy", "ujson"] + [[package]] name = "jsonpointer" version = "3.0.0" @@ -2221,13 +2380,13 @@ test = ["jupyter-server (>=2.0.0)", "pytest (>=7.0)", "pytest-jupyter[server] (> [[package]] name = "jupyterlab" -version = "4.2.2" +version = "4.2.3" description = "JupyterLab computational environment" optional = false python-versions = ">=3.8" files = [ - {file = "jupyterlab-4.2.2-py3-none-any.whl", hash = "sha256:59ee9b839f43308c3dfd55d72d1f1a299ed42a7f91f2d1afe9c12a783f9e525f"}, - {file = "jupyterlab-4.2.2.tar.gz", hash = "sha256:a534b6a25719a92a40d514fb133a9fe8f0d9981b0bbce5d8a5fcaa33344a3038"}, + {file = "jupyterlab-4.2.3-py3-none-any.whl", hash = "sha256:0b59d11808e84bb84105c73364edfa867dd475492429ab34ea388a52f2e2e596"}, + {file = "jupyterlab-4.2.3.tar.gz", hash = "sha256:df6e46969ea51d66815167f23d92f105423b7f1f06fa604d4f44aeb018c82c7b"}, ] [package.dependencies] @@ -2299,20 +2458,133 @@ files = [ {file = "jupyterlab_widgets-3.0.11.tar.gz", hash = "sha256:dd5ac679593c969af29c9bed054c24f26842baa51352114736756bc035deee27"}, ] +[[package]] +name = "kiwisolver" +version = "1.4.5" +description = "A fast implementation of the Cassowary constraint solver" +optional = false +python-versions = ">=3.7" +files = [ + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:05703cf211d585109fcd72207a31bb170a0f22144d68298dc5e61b3c946518af"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:146d14bebb7f1dc4d5fbf74f8a6cb15ac42baadee8912eb84ac0b3b2a3dc6ac3"}, + {file = "kiwisolver-1.4.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:6ef7afcd2d281494c0a9101d5c571970708ad911d028137cd558f02b851c08b4"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:9eaa8b117dc8337728e834b9c6e2611f10c79e38f65157c4c38e9400286f5cb1"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:ec20916e7b4cbfb1f12380e46486ec4bcbaa91a9c448b97023fde0d5bbf9e4ff"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:39b42c68602539407884cf70d6a480a469b93b81b7701378ba5e2328660c847a"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:aa12042de0171fad672b6c59df69106d20d5596e4f87b5e8f76df757a7c399aa"}, + {file = "kiwisolver-1.4.5-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2a40773c71d7ccdd3798f6489aaac9eee213d566850a9533f8d26332d626b82c"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:19df6e621f6d8b4b9c4d45f40a66839294ff2bb235e64d2178f7522d9170ac5b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:83d78376d0d4fd884e2c114d0621624b73d2aba4e2788182d286309ebdeed770"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:e391b1f0a8a5a10ab3b9bb6afcfd74f2175f24f8975fb87ecae700d1503cdee0"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_s390x.whl", hash = "sha256:852542f9481f4a62dbb5dd99e8ab7aedfeb8fb6342349a181d4036877410f525"}, + {file = "kiwisolver-1.4.5-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59edc41b24031bc25108e210c0def6f6c2191210492a972d585a06ff246bb79b"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win32.whl", hash = "sha256:a6aa6315319a052b4ee378aa171959c898a6183f15c1e541821c5c59beaa0238"}, + {file = "kiwisolver-1.4.5-cp310-cp310-win_amd64.whl", hash = "sha256:d0ef46024e6a3d79c01ff13801cb19d0cad7fd859b15037aec74315540acc276"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_universal2.whl", hash = "sha256:11863aa14a51fd6ec28688d76f1735f8f69ab1fabf388851a595d0721af042f5"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:8ab3919a9997ab7ef2fbbed0cc99bb28d3c13e6d4b1ad36e97e482558a91be90"}, + {file = "kiwisolver-1.4.5-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:fcc700eadbbccbf6bc1bcb9dbe0786b4b1cb91ca0dcda336eef5c2beed37b797"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dfdd7c0b105af050eb3d64997809dc21da247cf44e63dc73ff0fd20b96be55a9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:76c6a5964640638cdeaa0c359382e5703e9293030fe730018ca06bc2010c4437"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:bbea0db94288e29afcc4c28afbf3a7ccaf2d7e027489c449cf7e8f83c6346eb9"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:ceec1a6bc6cab1d6ff5d06592a91a692f90ec7505d6463a88a52cc0eb58545da"}, + {file = "kiwisolver-1.4.5-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:040c1aebeda72197ef477a906782b5ab0d387642e93bda547336b8957c61022e"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:f91de7223d4c7b793867797bacd1ee53bfe7359bd70d27b7b58a04efbb9436c8"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:faae4860798c31530dd184046a900e652c95513796ef51a12bc086710c2eec4d"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:b0157420efcb803e71d1b28e2c287518b8808b7cf1ab8af36718fd0a2c453eb0"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_s390x.whl", hash = "sha256:06f54715b7737c2fecdbf140d1afb11a33d59508a47bf11bb38ecf21dc9ab79f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:fdb7adb641a0d13bdcd4ef48e062363d8a9ad4a182ac7647ec88f695e719ae9f"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win32.whl", hash = "sha256:bb86433b1cfe686da83ce32a9d3a8dd308e85c76b60896d58f082136f10bffac"}, + {file = "kiwisolver-1.4.5-cp311-cp311-win_amd64.whl", hash = "sha256:6c08e1312a9cf1074d17b17728d3dfce2a5125b2d791527f33ffbe805200a355"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_universal2.whl", hash = "sha256:32d5cf40c4f7c7b3ca500f8985eb3fb3a7dfc023215e876f207956b5ea26632a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:f846c260f483d1fd217fe5ed7c173fb109efa6b1fc8381c8b7552c5781756192"}, + {file = "kiwisolver-1.4.5-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:5ff5cf3571589b6d13bfbfd6bcd7a3f659e42f96b5fd1c4830c4cf21d4f5ef45"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7269d9e5f1084a653d575c7ec012ff57f0c042258bf5db0954bf551c158466e7"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:da802a19d6e15dffe4b0c24b38b3af68e6c1a68e6e1d8f30148c83864f3881db"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3aba7311af82e335dd1e36ffff68aaca609ca6290c2cb6d821a39aa075d8e3ff"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:763773d53f07244148ccac5b084da5adb90bfaee39c197554f01b286cf869228"}, + {file = "kiwisolver-1.4.5-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:2270953c0d8cdab5d422bee7d2007f043473f9d2999631c86a223c9db56cbd16"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:d099e745a512f7e3bbe7249ca835f4d357c586d78d79ae8f1dcd4d8adeb9bda9"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:74db36e14a7d1ce0986fa104f7d5637aea5c82ca6326ed0ec5694280942d1162"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:7e5bab140c309cb3a6ce373a9e71eb7e4873c70c2dda01df6820474f9889d6d4"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_s390x.whl", hash = "sha256:0f114aa76dc1b8f636d077979c0ac22e7cd8f3493abbab152f20eb8d3cda71f3"}, + {file = "kiwisolver-1.4.5-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:88a2df29d4724b9237fc0c6eaf2a1adae0cdc0b3e9f4d8e7dc54b16812d2d81a"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win32.whl", hash = "sha256:72d40b33e834371fd330fb1472ca19d9b8327acb79a5821d4008391db8e29f20"}, + {file = "kiwisolver-1.4.5-cp312-cp312-win_amd64.whl", hash = "sha256:2c5674c4e74d939b9d91dda0fae10597ac7521768fec9e399c70a1f27e2ea2d9"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:3a2b053a0ab7a3960c98725cfb0bf5b48ba82f64ec95fe06f1d06c99b552e130"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3cd32d6c13807e5c66a7cbb79f90b553642f296ae4518a60d8d76243b0ad2898"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:59ec7b7c7e1a61061850d53aaf8e93db63dce0c936db1fda2658b70e4a1be709"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:da4cfb373035def307905d05041c1d06d8936452fe89d464743ae7fb8371078b"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:2400873bccc260b6ae184b2b8a4fec0e4082d30648eadb7c3d9a13405d861e89"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:1b04139c4236a0f3aff534479b58f6f849a8b351e1314826c2d230849ed48985"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:4e66e81a5779b65ac21764c295087de82235597a2293d18d943f8e9e32746265"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:7931d8f1f67c4be9ba1dd9c451fb0eeca1a25b89e4d3f89e828fe12a519b782a"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:b3f7e75f3015df442238cca659f8baa5f42ce2a8582727981cbfa15fee0ee205"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_s390x.whl", hash = "sha256:bbf1d63eef84b2e8c89011b7f2235b1e0bf7dacc11cac9431fc6468e99ac77fb"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:4c380469bd3f970ef677bf2bcba2b6b0b4d5c75e7a020fb863ef75084efad66f"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win32.whl", hash = "sha256:9408acf3270c4b6baad483865191e3e582b638b1654a007c62e3efe96f09a9a3"}, + {file = "kiwisolver-1.4.5-cp37-cp37m-win_amd64.whl", hash = "sha256:5b94529f9b2591b7af5f3e0e730a4e0a41ea174af35a4fd067775f9bdfeee01a"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:11c7de8f692fc99816e8ac50d1d1aef4f75126eefc33ac79aac02c099fd3db71"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:53abb58632235cd154176ced1ae8f0d29a6657aa1aa9decf50b899b755bc2b93"}, + {file = "kiwisolver-1.4.5-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:88b9f257ca61b838b6f8094a62418421f87ac2a1069f7e896c36a7d86b5d4c29"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3195782b26fc03aa9c6913d5bad5aeb864bdc372924c093b0f1cebad603dd712"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:fc579bf0f502e54926519451b920e875f433aceb4624a3646b3252b5caa9e0b6"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5a580c91d686376f0f7c295357595c5a026e6cbc3d77b7c36e290201e7c11ecb"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:cfe6ab8da05c01ba6fbea630377b5da2cd9bcbc6338510116b01c1bc939a2c18"}, + {file = "kiwisolver-1.4.5-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:d2e5a98f0ec99beb3c10e13b387f8db39106d53993f498b295f0c914328b1333"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:a51a263952b1429e429ff236d2f5a21c5125437861baeed77f5e1cc2d2c7c6da"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:3edd2fa14e68c9be82c5b16689e8d63d89fe927e56debd6e1dbce7a26a17f81b"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:74d1b44c6cfc897df648cc9fdaa09bc3e7679926e6f96df05775d4fb3946571c"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_s390x.whl", hash = "sha256:76d9289ed3f7501012e05abb8358bbb129149dbd173f1f57a1bf1c22d19ab7cc"}, + {file = "kiwisolver-1.4.5-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:92dea1ffe3714fa8eb6a314d2b3c773208d865a0e0d35e713ec54eea08a66250"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win32.whl", hash = "sha256:5c90ae8c8d32e472be041e76f9d2f2dbff4d0b0be8bd4041770eddb18cf49a4e"}, + {file = "kiwisolver-1.4.5-cp38-cp38-win_amd64.whl", hash = "sha256:c7940c1dc63eb37a67721b10d703247552416f719c4188c54e04334321351ced"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:9407b6a5f0d675e8a827ad8742e1d6b49d9c1a1da5d952a67d50ef5f4170b18d"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:15568384086b6df3c65353820a4473575dbad192e35010f622c6ce3eebd57af9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:0dc9db8e79f0036e8173c466d21ef18e1befc02de8bf8aa8dc0813a6dc8a7046"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:cdc8a402aaee9a798b50d8b827d7ecf75edc5fb35ea0f91f213ff927c15f4ff0"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:6c3bd3cde54cafb87d74d8db50b909705c62b17c2099b8f2e25b461882e544ff"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:955e8513d07a283056b1396e9a57ceddbd272d9252c14f154d450d227606eb54"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:346f5343b9e3f00b8db8ba359350eb124b98c99efd0b408728ac6ebf38173958"}, + {file = "kiwisolver-1.4.5-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b9098e0049e88c6a24ff64545cdfc50807818ba6c1b739cae221bbbcbc58aad3"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:00bd361b903dc4bbf4eb165f24d1acbee754fce22ded24c3d56eec268658a5cf"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:7b8b454bac16428b22560d0a1cf0a09875339cab69df61d7805bf48919415901"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:f1d072c2eb0ad60d4c183f3fb44ac6f73fb7a8f16a2694a91f988275cbf352f9"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_s390x.whl", hash = "sha256:31a82d498054cac9f6d0b53d02bb85811185bcb477d4b60144f915f3b3126342"}, + {file = "kiwisolver-1.4.5-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:6512cb89e334e4700febbffaaa52761b65b4f5a3cf33f960213d5656cea36a77"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win32.whl", hash = "sha256:9db8ea4c388fdb0f780fe91346fd438657ea602d58348753d9fb265ce1bca67f"}, + {file = "kiwisolver-1.4.5-cp39-cp39-win_amd64.whl", hash = "sha256:59415f46a37f7f2efeec758353dd2eae1b07640d8ca0f0c42548ec4125492635"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-macosx_10_9_x86_64.whl", hash = "sha256:5c7b3b3a728dc6faf3fc372ef24f21d1e3cee2ac3e9596691d746e5a536de920"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:620ced262a86244e2be10a676b646f29c34537d0d9cc8eb26c08f53d98013390"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:378a214a1e3bbf5ac4a8708304318b4f890da88c9e6a07699c4ae7174c09a68d"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:aaf7be1207676ac608a50cd08f102f6742dbfc70e8d60c4db1c6897f62f71523"}, + {file = "kiwisolver-1.4.5-pp37-pypy37_pp73-win_amd64.whl", hash = "sha256:ba55dce0a9b8ff59495ddd050a0225d58bd0983d09f87cfe2b6aec4f2c1234e4"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-macosx_10_9_x86_64.whl", hash = "sha256:fd32ea360bcbb92d28933fc05ed09bffcb1704ba3fc7942e81db0fd4f81a7892"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_i686.manylinux2010_i686.whl", hash = "sha256:5e7139af55d1688f8b960ee9ad5adafc4ac17c1c473fe07133ac092310d76544"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_12_x86_64.manylinux2010_x86_64.whl", hash = "sha256:dced8146011d2bc2e883f9bd68618b8247387f4bbec46d7392b3c3b032640126"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c9bf3325c47b11b2e51bca0824ea217c7cd84491d8ac4eefd1e409705ef092bd"}, + {file = "kiwisolver-1.4.5-pp38-pypy38_pp73-win_amd64.whl", hash = "sha256:5794cf59533bc3f1b1c821f7206a3617999db9fbefc345360aafe2e067514929"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-macosx_10_9_x86_64.whl", hash = "sha256:e368f200bbc2e4f905b8e71eb38b3c04333bddaa6a2464a6355487b02bb7fb09"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:e5d706eba36b4c4d5bc6c6377bb6568098765e990cfc21ee16d13963fab7b3e7"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:85267bd1aa8880a9c88a8cb71e18d3d64d2751a790e6ca6c27b8ccc724bcd5ad"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:210ef2c3a1f03272649aff1ef992df2e724748918c4bc2d5a90352849eb40bea"}, + {file = "kiwisolver-1.4.5-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:11d011a7574eb3b82bcc9c1a1d35c1d7075677fdd15de527d91b46bd35e935ee"}, + {file = "kiwisolver-1.4.5.tar.gz", hash = "sha256:e57e563a57fb22a142da34f38acc2fc1a5c864bc29ca1517a88abc963e60d6ec"}, +] + [[package]] name = "langchain" -version = "0.2.5" +version = "0.2.6" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain-0.2.5-py3-none-any.whl", hash = "sha256:9aded9a65348254e1c93dcdaacffe4d1b6a5e7f74ef80c160c88ff78ad299228"}, - {file = "langchain-0.2.5.tar.gz", hash = "sha256:ffdbf4fcea46a10d461bcbda2402220fcfd72a0c70e9f4161ae0510067b9b3bd"}, + {file = "langchain-0.2.6-py3-none-any.whl", hash = "sha256:f86e8a7afd3e56f8eb5ba47f01dd00144fb9fc2f1db9873bd197347be2857aa4"}, + {file = "langchain-0.2.6.tar.gz", hash = "sha256:867f6add370c1e3911b0e87d3dd0e36aec1e8f513bf06131340fe8f151d89dc5"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langchain-text-splitters = ">=0.2.0,<0.3.0" langsmith = ">=0.1.17,<0.2.0" numpy = [ @@ -2323,24 +2595,24 @@ pydantic = ">=1,<3" PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-community" -version = "0.2.5" +version = "0.2.6" description = "Community contributed LangChain integrations." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_community-0.2.5-py3-none-any.whl", hash = "sha256:bf37a334952e42c7676d083cf2d2c4cbfbb7de1949c4149fe19913e2b06c485f"}, - {file = "langchain_community-0.2.5.tar.gz", hash = "sha256:476787b8c8c213b67e7b0eceb53346e787f00fbae12d8e680985bd4f93b0bf64"}, + {file = "langchain_community-0.2.6-py3-none-any.whl", hash = "sha256:758cc800acfe5dd396bf8ba1b57c4792639ead0eab48ed0367f0732ec6ee1f68"}, + {file = "langchain_community-0.2.6.tar.gz", hash = "sha256:40ce09a50ed798aa651ddb34c8978200fa8589b9813c7a28ce8af027bbf249f0"}, ] [package.dependencies] aiohttp = ">=3.8.3,<4.0.0" dataclasses-json = ">=0.5.7,<0.7" -langchain = ">=0.2.5,<0.3.0" -langchain-core = ">=0.2.7,<0.3.0" +langchain = ">=0.2.6,<0.3.0" +langchain-core = ">=0.2.10,<0.3.0" langsmith = ">=0.1.0,<0.2.0" numpy = [ {version = ">=1,<2", markers = "python_version < \"3.12\""}, @@ -2349,17 +2621,17 @@ numpy = [ PyYAML = ">=5.3" requests = ">=2,<3" SQLAlchemy = ">=1.4,<3" -tenacity = ">=8.1.0,<9.0.0" +tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-core" -version = "0.2.9" +version = "0.2.10" description = "Building applications with LLMs through composability" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_core-0.2.9-py3-none-any.whl", hash = "sha256:426a5a4fea95a5db995ba5ab560b76edd4998fb6fe52ccc28ac987092a4cbfcd"}, - {file = "langchain_core-0.2.9.tar.gz", hash = "sha256:f1c59082642921727844e1cd0eb36d451edd1872c20e193aa3142aac03495986"}, + {file = "langchain_core-0.2.10-py3-none-any.whl", hash = "sha256:6eb72086b6bc86db9812da98f79e507c2209a15c0112aefd214a04182ada8586"}, + {file = "langchain_core-0.2.10.tar.gz", hash = "sha256:33d1fc234ab58c80476eb5bbde2107ef522a2ce8f46bdf47d9e1bd21e054208f"}, ] [package.dependencies] @@ -2375,62 +2647,62 @@ tenacity = ">=8.1.0,<8.4.0 || >8.4.0,<9.0.0" [[package]] name = "langchain-openai" -version = "0.1.9" +version = "0.1.13" description = "An integration package connecting OpenAI and LangChain" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_openai-0.1.9-py3-none-any.whl", hash = "sha256:afae71ef315c967685e53fe061470438000946739a9492d5f2d53bd4ae9d495a"}, - {file = "langchain_openai-0.1.9.tar.gz", hash = "sha256:730a94d68208678b9b9f64e4959a87057e021d6600754ea8b954e7765c7a62f1"}, + {file = "langchain_openai-0.1.13-py3-none-any.whl", hash = "sha256:4344b6c5c67088a28eed80ba763157fdd1d690cee679966a021b42f305dbf7b5"}, + {file = "langchain_openai-0.1.13.tar.gz", hash = "sha256:03318669bcb3238f7d1bb043329f91d150ca09246f1faf569ef299f535405c71"}, ] [package.dependencies] langchain-core = ">=0.2.2,<0.3" -openai = ">=1.26.0,<2.0.0" +openai = ">=1.32.0,<2.0.0" tiktoken = ">=0.7,<1" [[package]] name = "langchain-text-splitters" -version = "0.2.1" +version = "0.2.2" description = "LangChain text splitting utilities" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langchain_text_splitters-0.2.1-py3-none-any.whl", hash = "sha256:c2774a85f17189eaca50339629d2316d13130d4a8d9f1a1a96f3a03670c4a138"}, - {file = "langchain_text_splitters-0.2.1.tar.gz", hash = "sha256:06853d17d7241ecf5c97c7b6ef01f600f9b0fb953dd997838142a527a4f32ea4"}, + {file = "langchain_text_splitters-0.2.2-py3-none-any.whl", hash = "sha256:1c80d4b11b55e2995f02d2a326c0323ee1eeff24507329bb22924e420c782dff"}, + {file = "langchain_text_splitters-0.2.2.tar.gz", hash = "sha256:a1e45de10919fa6fb080ef0525deab56557e9552083600455cb9fa4238076140"}, ] [package.dependencies] -langchain-core = ">=0.2.0,<0.3.0" - -[package.extras] -extended-testing = ["beautifulsoup4 (>=4.12.3,<5.0.0)", "lxml (>=4.9.3,<6.0)"] +langchain-core = ">=0.2.10,<0.3.0" [[package]] name = "langsmith" -version = "0.1.81" +version = "0.1.82" description = "Client library to connect to the LangSmith LLM Tracing and Evaluation Platform." optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "langsmith-0.1.81-py3-none-any.whl", hash = "sha256:3251d823225eef23ee541980b9d9e506367eabbb7f985a086b5d09e8f78ba7e9"}, - {file = "langsmith-0.1.81.tar.gz", hash = "sha256:585ef3a2251380bd2843a664c9a28da4a7d28432e3ee8bcebf291ffb8e1f0af0"}, + {file = "langsmith-0.1.82-py3-none-any.whl", hash = "sha256:9b3653e7d316036b0c60bf0bc3e280662d660f485a4ebd8e5c9d84f9831ae79c"}, + {file = "langsmith-0.1.82.tar.gz", hash = "sha256:c02e2bbc488c10c13b52c69d271eb40bd38da078d37b6ae7ae04a18bd48140be"}, ] [package.dependencies] orjson = ">=3.9.14,<4.0.0" -pydantic = ">=1,<3" +pydantic = [ + {version = ">=1,<3", markers = "python_full_version < \"3.12.4\""}, + {version = ">=2.7.4,<3.0.0", markers = "python_full_version >= \"3.12.4\""}, +] requests = ">=2,<3" [[package]] name = "lightning-utilities" -version = "0.11.2" +version = "0.11.3.post0" description = "Lightning toolbox for across the our ecosystem." optional = false python-versions = ">=3.8" files = [ - {file = "lightning-utilities-0.11.2.tar.gz", hash = "sha256:adf4cf9c5d912fe505db4729e51d1369c6927f3a8ac55a9dff895ce5c0da08d9"}, - {file = "lightning_utilities-0.11.2-py3-none-any.whl", hash = "sha256:541f471ed94e18a28d72879338c8c52e873bb46f4c47644d89228faeb6751159"}, + {file = "lightning_utilities-0.11.3.post0-py3-none-any.whl", hash = "sha256:2aec1d067e5ab61a8978f879998850a97f9a3764ee54aade329552706b0d189b"}, + {file = "lightning_utilities-0.11.3.post0.tar.gz", hash = "sha256:7485fad0e3c5607a6bde4507935689c553a2c91325de2127b4bb8171a601e236"}, ] [package.dependencies] @@ -2464,23 +2736,38 @@ tiktoken = "^0.7.0" type = "directory" url = "lightrag" +[[package]] +name = "llama-cloud" +version = "0.0.6" +description = "" +optional = false +python-versions = "<4,>=3.8" +files = [ + {file = "llama_cloud-0.0.6-py3-none-any.whl", hash = "sha256:0f07c8a865be632b543dec2bcad350a68a61f13413a7421b4b03de32c36f0194"}, + {file = "llama_cloud-0.0.6.tar.gz", hash = "sha256:33b94cd119133dcb2899c9b69e8e1c36aec7bc7e80062c55c65f15618722e091"}, +] + +[package.dependencies] +httpx = ">=0.20.0" +pydantic = ">=1.10" + [[package]] name = "llama-index" -version = "0.10.48.post1" +version = "0.10.51" description = "Interface between LLMs and your data" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index-0.10.48.post1-py3-none-any.whl", hash = "sha256:4fefceb769624ea680ddd6bad810f35eeaaee26d0ef9263b7ad10d3006d8934e"}, - {file = "llama_index-0.10.48.post1.tar.gz", hash = "sha256:4790110c19ee072097e660ec290211aac3ad7d83c06838278855371c7f098416"}, + {file = "llama_index-0.10.51-py3-none-any.whl", hash = "sha256:dd7c01fdeb103ee177681bb240c9a0c1d3f9ce34cb797f4f6cb991b2d1bd4f4e"}, + {file = "llama_index-0.10.51.tar.gz", hash = "sha256:4b23e946e7fd80c7e6f8c6323c44b2e413301a485ca1294caf50145c2629c05d"}, ] [package.dependencies] llama-index-agent-openai = ">=0.1.4,<0.3.0" llama-index-cli = ">=0.1.2,<0.2.0" -llama-index-core = "0.10.48" +llama-index-core = "0.10.51" llama-index-embeddings-openai = ">=0.1.5,<0.2.0" -llama-index-indices-managed-llama-cloud = ">=0.1.2,<0.2.0" +llama-index-indices-managed-llama-cloud = ">=0.2.0" llama-index-legacy = ">=0.9.48,<0.10.0" llama-index-llms-openai = ">=0.1.13,<0.2.0" llama-index-multi-modal-llms-openai = ">=0.1.3,<0.2.0" @@ -2523,13 +2810,13 @@ llama-index-llms-openai = ">=0.1.1,<0.2.0" [[package]] name = "llama-index-core" -version = "0.10.48" +version = "0.10.51" description = "Interface between LLMs and your data" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index_core-0.10.48-py3-none-any.whl", hash = "sha256:320ede0a4a33e7582a6c600c53f9aa2ee8290abfa6e315c4c6fab65bd1d1116b"}, - {file = "llama_index_core-0.10.48.tar.gz", hash = "sha256:160140adc085a23d346c562cf9089a6f69fb78d0cc9443bfa8a94381a3296bd9"}, + {file = "llama_index_core-0.10.51-py3-none-any.whl", hash = "sha256:34051f188258bfb71335e018dcdf54291ef4feda15cadebb9be0402e98bd1d27"}, + {file = "llama_index_core-0.10.51.tar.gz", hash = "sha256:40b7052a6127810032b2d0b6abd72dd1767d8dd589c0f13747c4307942e81dd5"}, ] [package.dependencies] @@ -2539,7 +2826,7 @@ deprecated = ">=1.2.9.3" dirtyjson = ">=1.0.8,<2.0.0" fsspec = ">=2023.5.0" httpx = "*" -llamaindex-py-client = ">=0.1.18,<0.2.0" +llama-cloud = ">=0.0.6,<0.0.7" nest-asyncio = ">=1.5.8,<2.0.0" networkx = ">=3.0" nltk = ">=3.8.1,<4.0.0" @@ -2573,18 +2860,18 @@ llama-index-core = ">=0.10.1,<0.11.0" [[package]] name = "llama-index-indices-managed-llama-cloud" -version = "0.1.6" +version = "0.2.1" description = "llama-index indices llama-cloud integration" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index_indices_managed_llama_cloud-0.1.6-py3-none-any.whl", hash = "sha256:cba33e1a3677b2a2ae7f239119acbf6dc3818f105edc92315729842b56fbc949"}, - {file = "llama_index_indices_managed_llama_cloud-0.1.6.tar.gz", hash = "sha256:74b3b0e9ebf9d348d3054f9fc0c657031acceb9351c31116ad8d5a7ae4729f5c"}, + {file = "llama_index_indices_managed_llama_cloud-0.2.1-py3-none-any.whl", hash = "sha256:69abd37bc7b57abcea841eea2a89cb0adee29bce3fd05c61e3082ae50f047b87"}, + {file = "llama_index_indices_managed_llama_cloud-0.2.1.tar.gz", hash = "sha256:b07fa606f1085e22918d2d45e00ab86f3430f36057e115322bd360b695eef565"}, ] [package.dependencies] -llama-index-core = ">=0.10.0,<0.11.0" -llamaindex-py-client = ">=0.1.19,<0.2.0" +llama-cloud = ">=0.0.6,<0.0.7" +llama-index-core = ">=0.10.48.post1,<0.11.0" [[package]] name = "llama-index-legacy" @@ -2627,13 +2914,13 @@ query-tools = ["guidance (>=0.0.64,<0.0.65)", "jsonpath-ng (>=1.6.0,<2.0.0)", "l [[package]] name = "llama-index-llms-openai" -version = "0.1.22" +version = "0.1.24" description = "llama-index llms openai integration" optional = false python-versions = "<4.0,>=3.8.1" files = [ - {file = "llama_index_llms_openai-0.1.22-py3-none-any.whl", hash = "sha256:84a8c910671460ad724ed818192f209f7481e71bcc6528553ba7e66db2e14bcd"}, - {file = "llama_index_llms_openai-0.1.22.tar.gz", hash = "sha256:729bf2ea7043517465e1d585089512b77d8b3ce92233a67c138d5d621061ed56"}, + {file = "llama_index_llms_openai-0.1.24-py3-none-any.whl", hash = "sha256:c7b71cd34765e2d080d5eaf23c602877cc74fea162b59d53965273b2d4c4a56a"}, + {file = "llama_index_llms_openai-0.1.24.tar.gz", hash = "sha256:9031bd155c303f89cc51cfcc75d7d6f12fffa4274f2f9c7f67d4140350d13d56"}, ] [package.dependencies] @@ -2753,21 +3040,6 @@ files = [ [package.dependencies] llama-index-core = ">=0.10.29" -[[package]] -name = "llamaindex-py-client" -version = "0.1.19" -description = "" -optional = false -python-versions = "<4,>=3.8" -files = [ - {file = "llamaindex_py_client-0.1.19-py3-none-any.whl", hash = "sha256:fd9416fd78b97209bf323bc3c7fab314499778563e7274f10853ad560563d10e"}, - {file = "llamaindex_py_client-0.1.19.tar.gz", hash = "sha256:73f74792bb8c092bae6dc626627a09ac13a099fa8d10f8fcc83e17a2b332cca7"}, -] - -[package.dependencies] -httpx = ">=0.20.0" -pydantic = ">=1.10" - [[package]] name = "markupsafe" version = "2.1.5" @@ -2856,6 +3128,58 @@ dev = ["marshmallow[tests]", "pre-commit (>=3.5,<4.0)", "tox"] docs = ["alabaster (==0.7.16)", "autodocsumm (==0.2.12)", "sphinx (==7.3.7)", "sphinx-issues (==4.1.0)", "sphinx-version-warning (==1.1.2)"] tests = ["pytest", "pytz", "simplejson"] +[[package]] +name = "matplotlib" +version = "3.9.0" +description = "Python plotting package" +optional = false +python-versions = ">=3.9" +files = [ + {file = "matplotlib-3.9.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:2bcee1dffaf60fe7656183ac2190bd630842ff87b3153afb3e384d966b57fe56"}, + {file = "matplotlib-3.9.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:3f988bafb0fa39d1074ddd5bacd958c853e11def40800c5824556eb630f94d3b"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:fe428e191ea016bb278758c8ee82a8129c51d81d8c4bc0846c09e7e8e9057241"}, + {file = "matplotlib-3.9.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:eaf3978060a106fab40c328778b148f590e27f6fa3cd15a19d6892575bce387d"}, + {file = "matplotlib-3.9.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:2e7f03e5cbbfacdd48c8ea394d365d91ee8f3cae7e6ec611409927b5ed997ee4"}, + {file = "matplotlib-3.9.0-cp310-cp310-win_amd64.whl", hash = "sha256:13beb4840317d45ffd4183a778685e215939be7b08616f431c7795276e067463"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_10_12_x86_64.whl", hash = "sha256:063af8587fceeac13b0936c42a2b6c732c2ab1c98d38abc3337e430e1ff75e38"}, + {file = "matplotlib-3.9.0-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:9a2fa6d899e17ddca6d6526cf6e7ba677738bf2a6a9590d702c277204a7c6152"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:550cdda3adbd596078cca7d13ed50b77879104e2e46392dcd7c75259d8f00e85"}, + {file = "matplotlib-3.9.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:76cce0f31b351e3551d1f3779420cf8f6ec0d4a8cf9c0237a3b549fd28eb4abb"}, + {file = "matplotlib-3.9.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c53aeb514ccbbcbab55a27f912d79ea30ab21ee0531ee2c09f13800efb272674"}, + {file = "matplotlib-3.9.0-cp311-cp311-win_amd64.whl", hash = "sha256:a5be985db2596d761cdf0c2eaf52396f26e6a64ab46bd8cd810c48972349d1be"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_10_12_x86_64.whl", hash = "sha256:c79f3a585f1368da6049318bdf1f85568d8d04b2e89fc24b7e02cc9b62017382"}, + {file = "matplotlib-3.9.0-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:bdd1ecbe268eb3e7653e04f451635f0fb0f77f07fd070242b44c076c9106da84"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d38e85a1a6d732f645f1403ce5e6727fd9418cd4574521d5803d3d94911038e5"}, + {file = "matplotlib-3.9.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0a490715b3b9984fa609116481b22178348c1a220a4499cda79132000a79b4db"}, + {file = "matplotlib-3.9.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8146ce83cbc5dc71c223a74a1996d446cd35cfb6a04b683e1446b7e6c73603b7"}, + {file = "matplotlib-3.9.0-cp312-cp312-win_amd64.whl", hash = "sha256:d91a4ffc587bacf5c4ce4ecfe4bcd23a4b675e76315f2866e588686cc97fccdf"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_10_12_x86_64.whl", hash = "sha256:616fabf4981a3b3c5a15cd95eba359c8489c4e20e03717aea42866d8d0465956"}, + {file = "matplotlib-3.9.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:cd53c79fd02f1c1808d2cfc87dd3cf4dbc63c5244a58ee7944497107469c8d8a"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:06a478f0d67636554fa78558cfbcd7b9dba85b51f5c3b5a0c9be49010cf5f321"}, + {file = "matplotlib-3.9.0-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:81c40af649d19c85f8073e25e5806926986806fa6d54be506fbf02aef47d5a89"}, + {file = "matplotlib-3.9.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:52146fc3bd7813cc784562cb93a15788be0b2875c4655e2cc6ea646bfa30344b"}, + {file = "matplotlib-3.9.0-cp39-cp39-win_amd64.whl", hash = "sha256:0fc51eaa5262553868461c083d9adadb11a6017315f3a757fc45ec6ec5f02888"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_10_12_x86_64.whl", hash = "sha256:bd4f2831168afac55b881db82a7730992aa41c4f007f1913465fb182d6fb20c0"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-macosx_11_0_arm64.whl", hash = "sha256:290d304e59be2b33ef5c2d768d0237f5bd132986bdcc66f80bc9bcc300066a03"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7ff2e239c26be4f24bfa45860c20ffccd118d270c5b5d081fa4ea409b5469fcd"}, + {file = "matplotlib-3.9.0-pp39-pypy39_pp73-win_amd64.whl", hash = "sha256:af4001b7cae70f7eaacfb063db605280058246de590fa7874f00f62259f2df7e"}, + {file = "matplotlib-3.9.0.tar.gz", hash = "sha256:e6d29ea6c19e34b30fb7d88b7081f869a03014f66fe06d62cc77d5a6ea88ed7a"}, +] + +[package.dependencies] +contourpy = ">=1.0.1" +cycler = ">=0.10" +fonttools = ">=4.22.0" +kiwisolver = ">=1.3.1" +numpy = ">=1.23" +packaging = ">=20.0" +pillow = ">=8" +pyparsing = ">=2.3.1" +python-dateutil = ">=2.7" + +[package.extras] +dev = ["meson-python (>=0.13.1)", "numpy (>=1.25)", "pybind11 (>=2.6)", "setuptools (>=64)", "setuptools_scm (>=7)"] + [[package]] name = "matplotlib-inline" version = "0.1.7" @@ -3443,13 +3767,13 @@ files = [ [[package]] name = "openai" -version = "1.35.3" +version = "1.35.7" description = "The official Python library for the openai API" optional = false python-versions = ">=3.7.1" files = [ - {file = "openai-1.35.3-py3-none-any.whl", hash = "sha256:7b26544cef80f125431c073ffab3811d2421fbb9e30d3bd5c2436aba00b042d5"}, - {file = "openai-1.35.3.tar.gz", hash = "sha256:d6177087f150b381d49499be782d764213fdf638d391b29ca692b84dd675a389"}, + {file = "openai-1.35.7-py3-none-any.whl", hash = "sha256:3d1e0b0aac9b0db69a972d36dc7efa7563f8e8d65550b27a48f2a0c2ec207e80"}, + {file = "openai-1.35.7.tar.gz", hash = "sha256:009bfa1504c9c7ef64d87be55936d142325656bbc6d98c68b669d6472e4beb09"}, ] [package.dependencies] @@ -4251,13 +4575,13 @@ typing-extensions = ">=4.6.0,<4.7.0 || >4.7.0" [[package]] name = "pydata-sphinx-theme" -version = "0.15.3" +version = "0.15.4" description = "Bootstrap-based Sphinx theme from the PyData community" optional = false python-versions = ">=3.9" files = [ - {file = "pydata_sphinx_theme-0.15.3-py3-none-any.whl", hash = "sha256:a48ee049dc9b0f7064dbb8f7064b1cf3ae48aa193faafe14abd403a1b7102810"}, - {file = "pydata_sphinx_theme-0.15.3.tar.gz", hash = "sha256:f26ed9b676f61d1b2ae9289f3d7e496e8678dd56f2568b27a66fa4ad1f164efd"}, + {file = "pydata_sphinx_theme-0.15.4-py3-none-any.whl", hash = "sha256:2136ad0e9500d0949f96167e63f3e298620040aea8f9c74621959eda5d4cf8e6"}, + {file = "pydata_sphinx_theme-0.15.4.tar.gz", hash = "sha256:7762ec0ac59df3acecf49fd2f889e1b4565dbce8b88b2e29ee06fdd90645a06d"}, ] [package.dependencies] @@ -4273,7 +4597,7 @@ typing-extensions = "*" [package.extras] a11y = ["pytest-playwright"] dev = ["pandoc", "pre-commit", "pydata-sphinx-theme[doc,test]", "pyyaml", "sphinx-theme-builder[cli]", "tox"] -doc = ["ablog (>=0.11.8)", "colorama", "ipykernel", "ipyleaflet", "ipywidgets", "jupyter_sphinx", "jupyterlite-sphinx", "linkify-it-py", "matplotlib", "myst-parser", "nbsphinx", "numpy", "numpydoc", "pandas", "plotly", "rich", "sphinx-autoapi (>=3.0.0)", "sphinx-copybutton", "sphinx-design", "sphinx-favicon (>=1.0.1)", "sphinx-sitemap", "sphinx-togglebutton", "sphinxcontrib-youtube (<1.4)", "sphinxext-rediraffe", "xarray"] +doc = ["ablog (>=0.11.8)", "colorama", "graphviz", "ipykernel", "ipyleaflet", "ipywidgets", "jupyter_sphinx", "jupyterlite-sphinx", "linkify-it-py", "matplotlib", "myst-parser", "nbsphinx", "numpy", "numpydoc", "pandas", "plotly", "rich", "sphinx-autoapi (>=3.0.0)", "sphinx-copybutton", "sphinx-design", "sphinx-favicon (>=1.0.1)", "sphinx-sitemap", "sphinx-togglebutton", "sphinxcontrib-youtube (>=1.4.1)", "sphinxext-rediraffe", "xarray"] i18n = ["Babel", "jinja2"] test = ["pytest", "pytest-cov", "pytest-regressions", "sphinx[test]"] @@ -4392,6 +4716,22 @@ files = [ {file = "pytz-2024.1.tar.gz", hash = "sha256:2a29735ea9c18baf14b448846bde5a48030ed267578472d8955cd0e7443a9812"}, ] +[[package]] +name = "pyvis" +version = "0.3.2" +description = "A Python network graph visualization library" +optional = false +python-versions = ">3.6" +files = [ + {file = "pyvis-0.3.2-py3-none-any.whl", hash = "sha256:5720c4ca8161dc5d9ab352015723abb7a8bb8fb443edeb07f7a322db34a97555"}, +] + +[package.dependencies] +ipython = ">=5.3.0" +jinja2 = ">=2.9.6" +jsonpickle = ">=1.4.1" +networkx = ">=1.11" + [[package]] name = "pywin32" version = "306" @@ -4933,13 +5273,13 @@ pyasn1 = ">=0.1.3" [[package]] name = "s3transfer" -version = "0.10.1" +version = "0.10.2" description = "An Amazon S3 Transfer Manager" optional = false -python-versions = ">= 3.8" +python-versions = ">=3.8" files = [ - {file = "s3transfer-0.10.1-py3-none-any.whl", hash = "sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d"}, - {file = "s3transfer-0.10.1.tar.gz", hash = "sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19"}, + {file = "s3transfer-0.10.2-py3-none-any.whl", hash = "sha256:eca1c20de70a39daee580aef4986996620f365c4e0fda6a86100231d62f1bf69"}, + {file = "s3transfer-0.10.2.tar.gz", hash = "sha256:0711534e9356d3cc692fdde846b4a1e4b0cb6519971860796e6bc4c7aea00ef6"}, ] [package.dependencies] @@ -5117,45 +5457,45 @@ tests = ["black (>=24.3.0)", "matplotlib (>=3.3.4)", "mypy (>=1.9)", "numpydoc ( [[package]] name = "scipy" -version = "1.13.1" +version = "1.14.0" description = "Fundamental algorithms for scientific computing in Python" optional = false -python-versions = ">=3.9" +python-versions = ">=3.10" files = [ - {file = "scipy-1.13.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:20335853b85e9a49ff7572ab453794298bcf0354d8068c5f6775a0eabf350aca"}, - {file = "scipy-1.13.1-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:d605e9c23906d1994f55ace80e0125c587f96c020037ea6aa98d01b4bd2e222f"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:cfa31f1def5c819b19ecc3a8b52d28ffdcc7ed52bb20c9a7589669dd3c250989"}, - {file = "scipy-1.13.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f26264b282b9da0952a024ae34710c2aff7d27480ee91a2e82b7b7073c24722f"}, - {file = "scipy-1.13.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:eccfa1906eacc02de42d70ef4aecea45415f5be17e72b61bafcfd329bdc52e94"}, - {file = "scipy-1.13.1-cp310-cp310-win_amd64.whl", hash = "sha256:2831f0dc9c5ea9edd6e51e6e769b655f08ec6db6e2e10f86ef39bd32eb11da54"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:27e52b09c0d3a1d5b63e1105f24177e544a222b43611aaf5bc44d4a0979e32f9"}, - {file = "scipy-1.13.1-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:54f430b00f0133e2224c3ba42b805bfd0086fe488835effa33fa291561932326"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e89369d27f9e7b0884ae559a3a956e77c02114cc60a6058b4e5011572eea9299"}, - {file = "scipy-1.13.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a78b4b3345f1b6f68a763c6e25c0c9a23a9fd0f39f5f3d200efe8feda560a5fa"}, - {file = "scipy-1.13.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:45484bee6d65633752c490404513b9ef02475b4284c4cfab0ef946def50b3f59"}, - {file = "scipy-1.13.1-cp311-cp311-win_amd64.whl", hash = "sha256:5713f62f781eebd8d597eb3f88b8bf9274e79eeabf63afb4a737abc6c84ad37b"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:5d72782f39716b2b3509cd7c33cdc08c96f2f4d2b06d51e52fb45a19ca0c86a1"}, - {file = "scipy-1.13.1-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:017367484ce5498445aade74b1d5ab377acdc65e27095155e448c88497755a5d"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:949ae67db5fa78a86e8fa644b9a6b07252f449dcf74247108c50e1d20d2b4627"}, - {file = "scipy-1.13.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:de3ade0e53bc1f21358aa74ff4830235d716211d7d077e340c7349bc3542e884"}, - {file = "scipy-1.13.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:2ac65fb503dad64218c228e2dc2d0a0193f7904747db43014645ae139c8fad16"}, - {file = "scipy-1.13.1-cp312-cp312-win_amd64.whl", hash = "sha256:cdd7dacfb95fea358916410ec61bbc20440f7860333aee6d882bb8046264e949"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:436bbb42a94a8aeef855d755ce5a465479c721e9d684de76bf61a62e7c2b81d5"}, - {file = "scipy-1.13.1-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:8335549ebbca860c52bf3d02f80784e91a004b71b059e3eea9678ba994796a24"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d533654b7d221a6a97304ab63c41c96473ff04459e404b83275b60aa8f4b7004"}, - {file = "scipy-1.13.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:637e98dcf185ba7f8e663e122ebf908c4702420477ae52a04f9908707456ba4d"}, - {file = "scipy-1.13.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a014c2b3697bde71724244f63de2476925596c24285c7a637364761f8710891c"}, - {file = "scipy-1.13.1-cp39-cp39-win_amd64.whl", hash = "sha256:392e4ec766654852c25ebad4f64e4e584cf19820b980bc04960bca0b0cd6eaa2"}, - {file = "scipy-1.13.1.tar.gz", hash = "sha256:095a87a0312b08dfd6a6155cbbd310a8c51800fc931b8c0b84003014b874ed3c"}, -] - -[package.dependencies] -numpy = ">=1.22.4,<2.3" + {file = "scipy-1.14.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:7e911933d54ead4d557c02402710c2396529540b81dd554fc1ba270eb7308484"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:687af0a35462402dd851726295c1a5ae5f987bd6e9026f52e9505994e2f84ef6"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:07e179dc0205a50721022344fb85074f772eadbda1e1b3eecdc483f8033709b7"}, + {file = "scipy-1.14.0-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:6a9c9a9b226d9a21e0a208bdb024c3982932e43811b62d202aaf1bb59af264b1"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:076c27284c768b84a45dcf2e914d4000aac537da74236a0d45d82c6fa4b7b3c0"}, + {file = "scipy-1.14.0-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:42470ea0195336df319741e230626b6225a740fd9dce9642ca13e98f667047c0"}, + {file = "scipy-1.14.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:176c6f0d0470a32f1b2efaf40c3d37a24876cebf447498a4cefb947a79c21e9d"}, + {file = "scipy-1.14.0-cp310-cp310-win_amd64.whl", hash = "sha256:ad36af9626d27a4326c8e884917b7ec321d8a1841cd6dacc67d2a9e90c2f0359"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6d056a8709ccda6cf36cdd2eac597d13bc03dba38360f418560a93050c76a16e"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:f0a50da861a7ec4573b7c716b2ebdcdf142b66b756a0d392c236ae568b3a93fb"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:94c164a9e2498e68308e6e148646e486d979f7fcdb8b4cf34b5441894bdb9caf"}, + {file = "scipy-1.14.0-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:a7d46c3e0aea5c064e734c3eac5cf9eb1f8c4ceee756262f2c7327c4c2691c86"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9eee2989868e274aae26125345584254d97c56194c072ed96cb433f32f692ed8"}, + {file = "scipy-1.14.0-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e3154691b9f7ed73778d746da2df67a19d046a6c8087c8b385bc4cdb2cfca74"}, + {file = "scipy-1.14.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:c40003d880f39c11c1edbae8144e3813904b10514cd3d3d00c277ae996488cdb"}, + {file = "scipy-1.14.0-cp311-cp311-win_amd64.whl", hash = "sha256:5b083c8940028bb7e0b4172acafda6df762da1927b9091f9611b0bcd8676f2bc"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:bff2438ea1330e06e53c424893ec0072640dac00f29c6a43a575cbae4c99b2b9"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:bbc0471b5f22c11c389075d091d3885693fd3f5e9a54ce051b46308bc787e5d4"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:64b2ff514a98cf2bb734a9f90d32dc89dc6ad4a4a36a312cd0d6327170339eb0"}, + {file = "scipy-1.14.0-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:7d3da42fbbbb860211a811782504f38ae7aaec9de8764a9bef6b262de7a2b50f"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d91db2c41dd6c20646af280355d41dfa1ec7eead235642178bd57635a3f82209"}, + {file = "scipy-1.14.0-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a01cc03bcdc777c9da3cfdcc74b5a75caffb48a6c39c8450a9a05f82c4250a14"}, + {file = "scipy-1.14.0-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:65df4da3c12a2bb9ad52b86b4dcf46813e869afb006e58be0f516bc370165159"}, + {file = "scipy-1.14.0-cp312-cp312-win_amd64.whl", hash = "sha256:4c4161597c75043f7154238ef419c29a64ac4a7c889d588ea77690ac4d0d9b20"}, + {file = "scipy-1.14.0.tar.gz", hash = "sha256:b5923f48cb840380f9854339176ef21763118a7300a88203ccd0bdd26e58527b"}, +] + +[package.dependencies] +numpy = ">=1.23.5,<2.3" [package.extras] -dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy", "pycodestyle", "pydevtool", "rich-click", "ruff", "types-psutil", "typing_extensions"] -doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.12.0)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] -test = ["array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "mpmath", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] +dev = ["cython-lint (>=0.12.2)", "doit (>=0.36.0)", "mypy (==1.10.0)", "pycodestyle", "pydevtool", "rich-click", "ruff (>=0.0.292)", "types-psutil", "typing_extensions"] +doc = ["jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.13.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0)", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] [[package]] name = "send2trash" @@ -5200,13 +5540,13 @@ train = ["accelerate (>=0.20.3)", "datasets"] [[package]] name = "setuptools" -version = "70.1.0" +version = "70.1.1" description = "Easily download, build, install, upgrade, and uninstall Python packages" optional = false python-versions = ">=3.8" files = [ - {file = "setuptools-70.1.0-py3-none-any.whl", hash = "sha256:d9b8b771455a97c8a9f3ab3448ebe0b29b5e105f1228bba41028be116985a267"}, - {file = "setuptools-70.1.0.tar.gz", hash = "sha256:01a1e793faa5bd89abc851fa15d0a0db26f160890c7102cd8dce643e886b47f5"}, + {file = "setuptools-70.1.1-py3-none-any.whl", hash = "sha256:a58a8fde0541dab0419750bcc521fbdf8585f6e5cb41909df3a472ef7b81ca95"}, + {file = "setuptools-70.1.1.tar.gz", hash = "sha256:937a48c7cdb7a21eb53cd7f9b59e525503aa8abaf3584c730dc5f7a5bec3a650"}, ] [package.extras] @@ -5573,13 +5913,13 @@ files = [ [[package]] name = "tenacity" -version = "8.4.1" +version = "8.4.2" description = "Retry code until it succeeds" optional = false python-versions = ">=3.8" files = [ - {file = "tenacity-8.4.1-py3-none-any.whl", hash = "sha256:28522e692eda3e1b8f5e99c51464efcc0b9fc86933da92415168bc1c4e2308fa"}, - {file = "tenacity-8.4.1.tar.gz", hash = "sha256:54b1412b878ddf7e1f1577cd49527bad8cdef32421bd599beac0c6c3f10582fd"}, + {file = "tenacity-8.4.2-py3-none-any.whl", hash = "sha256:9e6f7cf7da729125c7437222f8a522279751cdfbe6b67bfe64f75d3a348661b2"}, + {file = "tenacity-8.4.2.tar.gz", hash = "sha256:cd80a53a79336edba8489e767f729e4f391c896956b57140b5d7511a64bbd3ef"}, ] [package.extras] @@ -5945,19 +6285,19 @@ test = ["argcomplete (>=3.0.3)", "mypy (>=1.7.0)", "pre-commit", "pytest (>=7.0, [[package]] name = "transformers" -version = "4.41.2" +version = "4.42.3" description = "State-of-the-art Machine Learning for JAX, PyTorch and TensorFlow" optional = false python-versions = ">=3.8.0" files = [ - {file = "transformers-4.41.2-py3-none-any.whl", hash = "sha256:05555d20e43f808de1ef211ab64803cdb513170cef70d29a888b589caebefc67"}, - {file = "transformers-4.41.2.tar.gz", hash = "sha256:80a4db216533d573e9cc7388646c31ed9480918feb7c55eb211249cb23567f87"}, + {file = "transformers-4.42.3-py3-none-any.whl", hash = "sha256:a61a0df9609b7d69229d941b2fd857c841ba3043d6da503d0da1a4b133f65b92"}, + {file = "transformers-4.42.3.tar.gz", hash = "sha256:7539873ff45809145265cbc94ea4619d2713c41ceaa277b692d8b0be3430f7eb"}, ] [package.dependencies] filelock = "*" -huggingface-hub = ">=0.23.0,<1.0" -numpy = ">=1.17" +huggingface-hub = ">=0.23.2,<1.0" +numpy = ">=1.17,<2.0" packaging = ">=20.0" pyyaml = ">=5.1" regex = "!=2019.12.17" @@ -5969,14 +6309,15 @@ tqdm = ">=4.27" [package.extras] accelerate = ["accelerate (>=0.21.0)"] agents = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "datasets (!=2.5.0)", "diffusers", "opencv-python", "sentencepiece (>=0.1.91,!=0.1.92)", "torch"] -all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision"] +all = ["Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "codecarbon (==1.2.0)", "decord (==0.6.0)", "flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "phonemizer", "protobuf", "pyctcdecode (>=0.4.0)", "ray[tune] (>=2.7.0)", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timm (<=0.9.16)", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision"] audio = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] +benchmark = ["optimum-benchmark (>=0.2.0)"] codecarbon = ["codecarbon (==1.2.0)"] deepspeed = ["accelerate (>=0.21.0)", "deepspeed (>=0.9.3)"] -deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.21.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] -dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] -dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.19,<0.20)", "urllib3 (<2.0.0)"] -dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +deepspeed-testing = ["GitPython (<3.1.19)", "accelerate (>=0.21.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "deepspeed (>=0.9.3)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk", "optuna", "parameterized", "protobuf", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.4.4)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +dev = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "av (==9.2.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "decord (==0.6.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "flax (>=0.4.1,<=0.7.0)", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "optax (>=0.0.8,<=0.1.4)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.4.4)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "scipy (<1.13.0)", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] +dev-tensorflow = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "isort (>=5.5.4)", "kenlm", "keras-nlp (>=0.3.1)", "librosa", "nltk", "onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.4.4)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx", "timeout-decorator", "tokenizers (>=0.19,<0.20)", "urllib3 (<2.0.0)"] +dev-torch = ["GitPython (<3.1.19)", "Pillow (>=10.0.1,<=15.0)", "accelerate (>=0.21.0)", "beautifulsoup4", "codecarbon (==1.2.0)", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "fugashi (>=1.0)", "ipadic (>=1.0.0,<2.0)", "isort (>=5.5.4)", "kenlm", "librosa", "nltk", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "optuna", "parameterized", "phonemizer", "protobuf", "psutil", "pyctcdecode (>=0.4.0)", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "ray[tune] (>=2.7.0)", "rhoknp (>=1.1.0,<1.3.1)", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.4.4)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "scikit-learn", "sentencepiece (>=0.1.91,!=0.1.92)", "sigopt", "sudachidict-core (>=20220729)", "sudachipy (>=0.6.6)", "tensorboard", "timeout-decorator", "timm (<=0.9.16)", "tokenizers (>=0.19,<0.20)", "torch", "torchaudio", "torchvision", "unidic (>=1.0.2)", "unidic-lite (>=1.0.7)", "urllib3 (<2.0.0)"] flax = ["flax (>=0.4.1,<=0.7.0)", "jax (>=0.4.1,<=0.4.13)", "jaxlib (>=0.4.1,<=0.4.13)", "optax (>=0.0.8,<=0.1.4)", "scipy (<1.13.0)"] flax-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] ftfy = ["ftfy"] @@ -5987,25 +6328,26 @@ natten = ["natten (>=0.14.6,<0.15.0)"] onnx = ["onnxconverter-common", "onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)", "tf2onnx"] onnxruntime = ["onnxruntime (>=1.4.0)", "onnxruntime-tools (>=1.4.2)"] optuna = ["optuna"] -quality = ["GitPython (<3.1.19)", "datasets (!=2.5.0)", "isort (>=5.5.4)", "ruff (==0.1.5)", "urllib3 (<2.0.0)"] +quality = ["GitPython (<3.1.19)", "datasets (!=2.5.0)", "isort (>=5.5.4)", "ruff (==0.4.4)", "urllib3 (<2.0.0)"] ray = ["ray[tune] (>=2.7.0)"] retrieval = ["datasets (!=2.5.0)", "faiss-cpu"] +ruff = ["ruff (==0.4.4)"] sagemaker = ["sagemaker (>=2.31.0)"] sentencepiece = ["protobuf", "sentencepiece (>=0.1.91,!=0.1.92)"] serving = ["fastapi", "pydantic", "starlette", "uvicorn"] sigopt = ["sigopt"] sklearn = ["scikit-learn"] speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] -testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk", "parameterized", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.1.5)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] +testing = ["GitPython (<3.1.19)", "beautifulsoup4", "cookiecutter (==1.7.3)", "datasets (!=2.5.0)", "dill (<0.3.5)", "evaluate (>=0.2.0)", "faiss-cpu", "nltk", "parameterized", "psutil", "pydantic", "pytest (>=7.2.0,<8.0.0)", "pytest-rich", "pytest-timeout", "pytest-xdist", "rjieba", "rouge-score (!=0.0.7,!=0.0.8,!=0.1,!=0.1.1)", "ruff (==0.4.4)", "sacrebleu (>=1.4.12,<2.0.0)", "sacremoses", "sentencepiece (>=0.1.91,!=0.1.92)", "tensorboard", "timeout-decorator"] tf = ["keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow (>2.9,<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] -tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<2.16)", "tensorflow-text (<2.16)", "tf2onnx"] +tf-cpu = ["keras (>2.9,<2.16)", "keras-nlp (>=0.3.1)", "onnxconverter-common", "tensorflow-cpu (>2.9,<2.16)", "tensorflow-probability (<0.24)", "tensorflow-text (<2.16)", "tf2onnx"] tf-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)"] -timm = ["timm"] +timm = ["timm (<=0.9.16)"] tokenizers = ["tokenizers (>=0.19,<0.20)"] torch = ["accelerate (>=0.21.0)", "torch"] torch-speech = ["kenlm", "librosa", "phonemizer", "pyctcdecode (>=0.4.0)", "torchaudio"] torch-vision = ["Pillow (>=10.0.1,<=15.0)", "torchvision"] -torchhub = ["filelock", "huggingface-hub (>=0.23.0,<1.0)", "importlib-metadata", "numpy (>=1.17)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.19,<0.20)", "torch", "tqdm (>=4.27)"] +torchhub = ["filelock", "huggingface-hub (>=0.23.2,<1.0)", "importlib-metadata", "numpy (>=1.17,<2.0)", "packaging (>=20.0)", "protobuf", "regex (!=2019.12.17)", "requests", "sentencepiece (>=0.1.91,!=0.1.92)", "tokenizers (>=0.19,<0.20)", "torch", "tqdm (>=4.27)"] video = ["av (==9.2.0)", "decord (==0.6.0)"] vision = ["Pillow (>=10.0.1,<=15.0)"] @@ -6522,4 +6864,4 @@ multidict = ">=4.0" [metadata] lock-version = "2.0" python-versions = ">=3.11, <4.0" -content-hash = "4129281871725e73ccb571ca9a71a96c2c575b583bd6eb3eea649c1a96c8d9f2" +content-hash = "0be4e6e956c9ecb269263f17c19dfa5506ae361a3a999c8e11fdae1ad46b3bcf" diff --git a/pyproject.toml b/pyproject.toml index 894932bd..e2b148d0 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -17,6 +17,8 @@ torch = "^2.3.1" flagembedding = "^1.2.10" # cohere = "^5.5.7" openai = "^1.34.0" +networkx = "^3.3" +pyvis = "^0.3.2" [tool.poetry.group.dev.dependencies] @@ -50,6 +52,8 @@ langchain = "^0.2.5" langchain-community = "^0.2.5" langchain-openai = "^0.1.8" pydot = "^2.0.0" +matplotlib = "^3.9.0" +pyvis = "^0.3.2" [tool.poetry.group.doc.dependencies] diff --git a/test_pyvis.py b/test_pyvis.py new file mode 100644 index 00000000..39f72639 --- /dev/null +++ b/test_pyvis.py @@ -0,0 +1,15 @@ +from pyvis.network import Network +import networkx as nx + +# Create a simple NetworkX graph +G = nx.DiGraph() +G.add_edges_from([(1, 2), (2, 3), (3, 4)]) + +# Create a Pyvis Network +net = Network(notebook=False, width="100%", height="100%", directed=True) + +# Add nodes and edges from NetworkX to Pyvis +net.from_nx(G) + +# Save the network to an HTML file +net.show("test_network.html") diff --git a/visualize.py b/visualize.py index c3aca3f8..971d6e65 100644 --- a/visualize.py +++ b/visualize.py @@ -1,6 +1,8 @@ import os import ast import pydot +import networkx as nx +from pyvis.network import Network def get_class_name(node): @@ -28,6 +30,56 @@ def get_classes_from_file(file_path): return classes +def get_class_hierarchy_nx(classes): + graph = nx.DiGraph() + excluded_bases = { + "ComponentWithSuperInit", + "ComponentMissSuperInit", + "Memory", + "ObjectTypes", + } + + for cls in classes: + for base in cls.bases: + try: + base_name = get_class_name(base) + if base_name not in excluded_bases and cls.name not in excluded_bases: + print(f"Adding edge from {base_name} to {cls.name}") + graph.add_edge(base_name, cls.name) + except AttributeError as e: + print(f"Error processing {cls.name}: {base}, {e}") + pass + + return graph + + +def visualize_class_hierarchy_2(graph, filename="class_hierarchy.html"): + # Create a Pyvis Network + # Create a Pyvis Network + filename = filename.replace(".png", ".html") + print(filename) + net = Network(notebook=False, width="100%", height="100%", directed=True) + + # Add nodes and edges to the Pyvis network from the NetworkX graph + for node1, node2 in graph.edges(): + net.add_node(node1) + net.add_node(node2) + net.add_edge(node1, node2) + print("Nodes and edges added to the Pyvis network") + print(net) + + # Show graph + net.show(filename, local=True) + print(f"Class hierarchy saved as {filename}") + + +def save_edges_to_file(graph, filename="class_hierarchy_edges.csv"): + with open(filename, "w") as file: + for node1, node2 in graph.edges(): + file.write(f"{node1},{node2}\n") + print(f"Edges saved to {filename}") + + def get_class_hierarchy(classes): graph = pydot.Dot(graph_type="digraph") excluded_bases = { @@ -52,6 +104,41 @@ def get_class_hierarchy(classes): return graph +# def visualize_class_hierarchy_nx(graph, filename="class_hierarchy.png"): + +# filename = filename.replace(".png", ".html") + +# pos = nx.spring_layout(graph) # You can choose other layouts as needed + +# plt.figure(figsize=(10, 8)) +# nx.draw( +# graph, +# pos, +# with_labels=True, +# node_size=1500, +# node_color="skyblue", +# font_size=10, +# font_color="black", +# font_weight="bold", +# edge_color="#666666", +# linewidths=2, +# arrows=True, +# arrowstyle="->", +# arrowsize=10, +# ) + +# plt.title("LightRAG Class Hierarchy") +# plt.tight_layout() + +# # Convert to HTML using mpld3 +# html_str = mpld3.fig_to_html(plt.gcf()) + +# with open(filename, "w") as file: +# file.write(html_str) + +# print(f"Class hierarchy saved as {filename}") + + def visualize_class_hierarchy(graph, filename="class_hierarchy.png"): dpi = 800 graph.set_graph_defaults(dpi=str(dpi)) @@ -119,7 +206,13 @@ def lang_chain_paths(): all_classes.extend(process_directory(path)) # Generate the class hierarchy graph - graph = get_class_hierarchy(all_classes) + # graph = get_class_hierarchy(all_classes) + + # use nx + graph = get_class_hierarchy_nx(all_classes) # Visualize the class hierarchy - visualize_class_hierarchy(graph, filename=graph_name) + # visualize_class_hierarchy(graph, filename=graph_name) + + # visualize_class_hierarchy_2(graph, filename=graph_name) + save_edges_to_file(graph, filename="class_hierarchy_edges.csv")