From d3dda482aca309439361c6709370a271f452acad Mon Sep 17 00:00:00 2001 From: diansensun Date: Tue, 21 Jan 2025 17:07:01 +0800 Subject: [PATCH 1/2] add configurations --- .gitignore | 60 +-------- .vscode/launch.json | 49 +++---- .vscode/settings.json | 2 +- graphrag/config/models/graph_rag_config.py | 2 +- graphrag/requirements.txt | 149 +++++++++++++++++++++ graphrag/requirements1.txt | 149 +++++++++++++++++++++ 6 files changed, 321 insertions(+), 90 deletions(-) create mode 100644 graphrag/requirements.txt create mode 100644 graphrag/requirements1.txt diff --git a/.gitignore b/.gitignore index 707bc44711..7664732944 100644 --- a/.gitignore +++ b/.gitignore @@ -1,58 +1,2 @@ -# Python Artifacts -python/*/lib/ -dist/ - -# Test Output -.coverage -coverage/ -licenses.txt -examples_notebooks/*/data -tests/fixtures/cache -tests/fixtures/*/cache -tests/fixtures/*/output -output/lancedb - - -# Random -.DS_Store -*.log* -.venv -venv/ -.conda -.tmp - -.env -build.zip - -.turbo - -__pycache__ - -.pipeline - -# Azurite -temp_azurite/ -__azurite*.json -__blobstorage*.json -__blobstorage__/ - -# Getting started example -ragtest/ -.ragtest/ -.pipelines -.pipeline - - -# mkdocs -site/ - -# Docs migration -docsite/ -.yarn/ -.pnp* - -# PyCharm -.idea/ - -# Jupyter notebook -.ipynb_checkpoints/ +**/__pycache__/ +workdir/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 2167063966..73d104e509 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,37 +3,26 @@ "version": "0.2.0", "configurations": [ { - "name": "Indexer", - "type": "debugpy", - "request": "launch", - "module": "poetry", - "args": [ - "poe", "index", - "--root", "" + "name": "Graphrag init", + "type": "python", + "request": "launch", + "module": "graphrag", + "args": [ + "init", + "--root", "${workspaceFolder}/workdir" ], - }, + "console": "integratedTerminal" + }, { - "name": "Query", - "type": "debugpy", - "request": "launch", - "module": "poetry", - "args": [ - "poe", "query", - "--root", "", - "--method", "global", - "--query", "What are the top themes in this story", - ] - }, - { - "name": "Prompt Tuning", - "type": "debugpy", - "request": "launch", - "module": "poetry", - "args": [ - "poe", "prompt-tune", - "--config", - "/settings.yaml", - ] - } + "name": "Graphrag index", + "type": "python", + "request": "launch", + "module": "graphrag", + "args": [ + "index", + "--root", "${workspaceFolder}/workdir" + ], + "console": "integratedTerminal" + } ] } \ No newline at end of file diff --git a/.vscode/settings.json b/.vscode/settings.json index 0b678d5d95..edc1b4294a 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -37,7 +37,7 @@ "node_modules{,/**}", ".vscode{,/**}" ], - "python.defaultInterpreterPath": "python/services/.venv/bin/python", + "python.defaultInterpreterPath": ".venv/bin/python", "python.languageServer": "Pylance", "cSpell.customDictionaries": { "project-words": { diff --git a/graphrag/config/models/graph_rag_config.py b/graphrag/config/models/graph_rag_config.py index 77ad944053..8c03074658 100644 --- a/graphrag/config/models/graph_rag_config.py +++ b/graphrag/config/models/graph_rag_config.py @@ -3,7 +3,7 @@ """Parameterization settings for the default configuration.""" -from devtools import pformat +from pprint import pformat from pydantic import Field import graphrag.config.defaults as defs diff --git a/graphrag/requirements.txt b/graphrag/requirements.txt new file mode 100644 index 0000000000..8ab3579977 --- /dev/null +++ b/graphrag/requirements.txt @@ -0,0 +1,149 @@ +aiofiles==24.1.0 +aiolimiter==1.2.1 +annotated-types==0.7.0 +anyio==4.8.0 +anytree==2.12.1 +asttokens==2.4.1 +attrs==24.3.0 +autograd==1.7.0 +azure-common==1.1.28 +azure-core==1.32.0 +azure-cosmos==4.9.0 +azure-identity==1.19.0 +azure-search-documents==11.5.2 +azure-storage-blob==12.24.0 +backcall==0.2.0 +backlash==0.3.2 +beartype==0.18.5 +beautifulsoup4==4.12.3 +bleach==6.2.0 +certifi==2024.12.14 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +contourpy==1.3.1 +crank==0.8.1 +cryptography==44.0.0 +cycler==0.12.1 +decorator==5.1.1 +defusedxml==0.7.1 +deprecation==2.1.0 +devtools==0.12.2 +distro==1.9.0 +docopt==0.6.2 +environs==11.2.1 +executing==2.1.0 +fastjsonschema==2.21.1 +fnllm==0.0.10 +fonttools==4.55.3 +future==1.0.0 +gearbox==0.2.2 +gensim==4.3.3 +graspologic==3.4.1 +graspologic-native==1.2.1 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hupper==1.12.1 +hyppo==0.4.0 +idna==3.10 +ipython==8.12.3 +isodate==0.7.2 +jedi==0.19.2 +Jinja2==3.1.5 +jiter==0.8.2 +joblib==1.4.2 +json_repair==0.30.3 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +jupyterlab_pygments==0.3.0 +kiwisolver==1.4.8 +lancedb==0.17.0 +llvmlite==0.44.0 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +marshmallow==3.25.1 +matplotlib==3.10.0 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mistune==3.1.0 +msal==1.31.1 +msal-extensions==1.2.0 +nbclient==0.10.2 +nbconvert==7.16.5 +nbformat==5.10.4 +networkx==3.4.2 +nltk==3.9.1 +numba==0.61.0 +numpy==1.26.4 +openai==1.59.9 +overrides==7.7.0 +packaging==24.2 +pandas==2.2.3 +pandocfilters==1.5.1 +parso==0.8.4 +PasteDeploy==3.1.0 +patsy==1.0.1 +pexpect==4.9.0 +pickleshare==0.7.5 +pillow==11.1.0 +pipreqs==0.5.0 +platformdirs==4.3.6 +portalocker==2.10.1 +POT==0.9.5 +prompt_toolkit==3.0.50 +ptyprocess==0.7.0 +pure_eval==0.2.3 +pyarrow==15.0.2 +pycparser==2.22 +pydantic==2.10.5 +pydantic_core==2.27.2 +Pygments==2.19.1 +PyJWT==2.10.1 +pylance==0.20.0 +pynndescent==0.5.13 +pyparsing==3.2.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pytz==2024.2 +PyYAML==6.0.2 +pyzmq==26.2.0 +referencing==0.36.1 +regex==2024.11.6 +repoze.lru==0.7 +requests==2.32.3 +rich==13.9.4 +rpds-py==0.22.3 +scikit-learn==1.6.1 +scipy==1.12.0 +seaborn==0.13.2 +shellingham==1.5.4 +six==1.17.0 +smart-open==7.1.0 +sniffio==1.3.1 +soupsieve==2.6 +stack-data==0.6.3 +statsmodels==0.14.4 +Tempita==0.6.0 +tenacity==9.0.0 +tg.devtools==2.4.3 +tgext.debugbar==0.5.0 +threadpoolctl==3.5.0 +tiktoken==0.8.0 +tinycss2==1.4.0 +tornado==6.4.2 +tqdm==4.67.1 +traitlets==5.14.3 +TurboGears2==2.4.3 +typer==0.15.1 +typing_extensions==4.12.2 +tzdata==2024.2 +umap-learn==0.5.7 +urllib3==2.3.0 +wcwidth==0.2.13 +webencodings==0.5.1 +WebOb==1.8.9 +wrapt==1.17.2 +yarg==0.1.9 diff --git a/graphrag/requirements1.txt b/graphrag/requirements1.txt new file mode 100644 index 0000000000..8ab3579977 --- /dev/null +++ b/graphrag/requirements1.txt @@ -0,0 +1,149 @@ +aiofiles==24.1.0 +aiolimiter==1.2.1 +annotated-types==0.7.0 +anyio==4.8.0 +anytree==2.12.1 +asttokens==2.4.1 +attrs==24.3.0 +autograd==1.7.0 +azure-common==1.1.28 +azure-core==1.32.0 +azure-cosmos==4.9.0 +azure-identity==1.19.0 +azure-search-documents==11.5.2 +azure-storage-blob==12.24.0 +backcall==0.2.0 +backlash==0.3.2 +beartype==0.18.5 +beautifulsoup4==4.12.3 +bleach==6.2.0 +certifi==2024.12.14 +cffi==1.17.1 +charset-normalizer==3.4.1 +click==8.1.8 +contourpy==1.3.1 +crank==0.8.1 +cryptography==44.0.0 +cycler==0.12.1 +decorator==5.1.1 +defusedxml==0.7.1 +deprecation==2.1.0 +devtools==0.12.2 +distro==1.9.0 +docopt==0.6.2 +environs==11.2.1 +executing==2.1.0 +fastjsonschema==2.21.1 +fnllm==0.0.10 +fonttools==4.55.3 +future==1.0.0 +gearbox==0.2.2 +gensim==4.3.3 +graspologic==3.4.1 +graspologic-native==1.2.1 +h11==0.14.0 +httpcore==1.0.7 +httpx==0.28.1 +hupper==1.12.1 +hyppo==0.4.0 +idna==3.10 +ipython==8.12.3 +isodate==0.7.2 +jedi==0.19.2 +Jinja2==3.1.5 +jiter==0.8.2 +joblib==1.4.2 +json_repair==0.30.3 +jsonschema==4.23.0 +jsonschema-specifications==2024.10.1 +jupyter_client==8.6.3 +jupyter_core==5.7.2 +jupyterlab_pygments==0.3.0 +kiwisolver==1.4.8 +lancedb==0.17.0 +llvmlite==0.44.0 +markdown-it-py==3.0.0 +MarkupSafe==3.0.2 +marshmallow==3.25.1 +matplotlib==3.10.0 +matplotlib-inline==0.1.7 +mdurl==0.1.2 +mistune==3.1.0 +msal==1.31.1 +msal-extensions==1.2.0 +nbclient==0.10.2 +nbconvert==7.16.5 +nbformat==5.10.4 +networkx==3.4.2 +nltk==3.9.1 +numba==0.61.0 +numpy==1.26.4 +openai==1.59.9 +overrides==7.7.0 +packaging==24.2 +pandas==2.2.3 +pandocfilters==1.5.1 +parso==0.8.4 +PasteDeploy==3.1.0 +patsy==1.0.1 +pexpect==4.9.0 +pickleshare==0.7.5 +pillow==11.1.0 +pipreqs==0.5.0 +platformdirs==4.3.6 +portalocker==2.10.1 +POT==0.9.5 +prompt_toolkit==3.0.50 +ptyprocess==0.7.0 +pure_eval==0.2.3 +pyarrow==15.0.2 +pycparser==2.22 +pydantic==2.10.5 +pydantic_core==2.27.2 +Pygments==2.19.1 +PyJWT==2.10.1 +pylance==0.20.0 +pynndescent==0.5.13 +pyparsing==3.2.1 +python-dateutil==2.9.0.post0 +python-dotenv==1.0.1 +pytz==2024.2 +PyYAML==6.0.2 +pyzmq==26.2.0 +referencing==0.36.1 +regex==2024.11.6 +repoze.lru==0.7 +requests==2.32.3 +rich==13.9.4 +rpds-py==0.22.3 +scikit-learn==1.6.1 +scipy==1.12.0 +seaborn==0.13.2 +shellingham==1.5.4 +six==1.17.0 +smart-open==7.1.0 +sniffio==1.3.1 +soupsieve==2.6 +stack-data==0.6.3 +statsmodels==0.14.4 +Tempita==0.6.0 +tenacity==9.0.0 +tg.devtools==2.4.3 +tgext.debugbar==0.5.0 +threadpoolctl==3.5.0 +tiktoken==0.8.0 +tinycss2==1.4.0 +tornado==6.4.2 +tqdm==4.67.1 +traitlets==5.14.3 +TurboGears2==2.4.3 +typer==0.15.1 +typing_extensions==4.12.2 +tzdata==2024.2 +umap-learn==0.5.7 +urllib3==2.3.0 +wcwidth==0.2.13 +webencodings==0.5.1 +WebOb==1.8.9 +wrapt==1.17.2 +yarg==0.1.9 From d77be3bce9db1dc662acf2b8c8baf2aac8fa08bb Mon Sep 17 00:00:00 2001 From: diansensun Date: Thu, 23 Jan 2025 11:17:53 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E4=BC=98=E5=8C=96=E4=BA=86=E5=AF=B9entity?= =?UTF-8?q?=5Fextraction=20prompt=E7=9A=84=E5=A4=84=E7=90=86=E7=BB=86?= =?UTF-8?q?=E8=8A=82=EF=BC=8C=E6=B7=BB=E5=8A=A0=E4=BA=86=E5=AF=B9prompt?= =?UTF-8?q?=E6=A8=A1=E6=9D=BF=E6=A0=BC=E5=BC=8F=E5=8C=96=E8=BF=87=E7=A8=8B?= =?UTF-8?q?=E4=B8=AD=E5=AF=B9=E5=B5=8C=E5=A5=97=E7=BB=93=E6=9E=84=E5=8D=A0?= =?UTF-8?q?=E4=BD=8D=E7=AC=A6=E4=B8=8E=E6=9C=AA=E6=88=90=E5=AF=B9=E8=8A=B1?= =?UTF-8?q?=E6=8B=AC=E5=8F=B7=E5=A4=84=E7=90=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 详细描述 新增功能: 支持嵌套结构占位符(如 {data[key]} 和 {obj.attr}),这些占位符将被保留原样,不被 str.format() 解析。 引入未成对花括号的处理逻辑: 未闭合的 { 转换为普通字符 {{。 单独的 } 转换为普通字符 }}。 确保未成对的花括号不会触发解析错误。 修复问题: 修复嵌套结构占位符在模板中被错误解析的问题。 修复未成对花括号导致 str.format() 抛出异常的问题。 具体修改: 新增 _replace_unpaired_braces 方法,使用正则表达式检测未成对的 { 或 },并将其替换为普通字符,确保模板完整性。 修改 SafeFormatter.format 方法,调用 _replace_unpaired_braces 预处理模板,避免未成对花括号干扰格式化流程。 优化嵌套结构的正则匹配逻辑,将匹配到的嵌套占位符(如 {data[key]})转义为普通文本 {{data[key]}},避免解析。 测试覆盖: 测试未成对的 { 和 }: {abc -> {abc(被保留为普通字符)。 abc} -> abc}(被保留为普通字符)。 测试嵌套占位符: {data[key]} -> 被保留原样。 测试合法占位符的正常解析: {name} -> 被替换为传入的数据值。 测试混合场景: {abc}def} -> {abc}def}。 Hello {name}, Welcome {place}! -> Hello Alice, Welcome Wonderland!(假设传入数据)。 --- .gitignore | 4 +- .vscode/launch.json | 45 +++++- .../extract_entities/graph_extractor.py | 65 +++++++- graphrag/requirements1.txt | 149 ------------------ 4 files changed, 106 insertions(+), 157 deletions(-) delete mode 100644 graphrag/requirements1.txt diff --git a/.gitignore b/.gitignore index 7664732944..00a9938165 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,4 @@ **/__pycache__/ -workdir/ \ No newline at end of file +workdir/ +sac/ +prompts/ \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json index 73d104e509..12505a6bed 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -3,7 +3,7 @@ "version": "0.2.0", "configurations": [ { - "name": "Graphrag init", + "name": "Debug Graphrag init", "type": "python", "request": "launch", "module": "graphrag", @@ -14,7 +14,7 @@ "console": "integratedTerminal" }, { - "name": "Graphrag index", + "name": "Debug Graphrag index", "type": "python", "request": "launch", "module": "graphrag", @@ -22,7 +22,48 @@ "index", "--root", "${workspaceFolder}/workdir" ], + "justMyCode": false, // 设置为 false 以调试第三方库 "console": "integratedTerminal" + }, + { + "name": "Run Graphrag index", + "type": "python", + "request": "launch", + "module": "graphrag", + "args": [ + "index", + "--root", "${workspaceFolder}/workdir" + ], + "justMyCode": false, // 设置为 false 以调试第三方库 + "console": "integratedTerminal", + "noDebug": true + }, + { + "name": "Debug Graphrag prompt-tune", + "type": "python", + "request": "launch", + "module": "graphrag", + "args": [ + "prompt-tune", + "--root", "${workspaceFolder}/workdir", + "--config", "${workspaceFolder}/workdir/settings.yaml", + "--discover-entity-types" + ], + "console": "integratedTerminal" + }, + { + "name": "Run Graphrag prompt-tune", + "type": "python", + "request": "launch", + "module": "graphrag", + "args": [ + "prompt-tune", + "--root", "${workspaceFolder}/workdir", + "--config", "${workspaceFolder}/workdir/settings.yaml", + "--discover-entity-types" + ], + "console": "integratedTerminal", + "noDebug": true } ] } \ No newline at end of file diff --git a/graphrag/index/operations/extract_entities/graph_extractor.py b/graphrag/index/operations/extract_entities/graph_extractor.py index f10b2c83e5..bf5bcce782 100644 --- a/graphrag/index/operations/extract_entities/graph_extractor.py +++ b/graphrag/index/operations/extract_entities/graph_extractor.py @@ -8,6 +8,7 @@ import traceback from collections.abc import Mapping from dataclasses import dataclass +from string import Formatter from typing import Any import networkx as nx @@ -30,7 +31,58 @@ log = logging.getLogger(__name__) - +class SafeFormatter(Formatter): + def __init__(self): + # 匹配嵌套结构占位符的正则表达式 + self.nested_pattern = re.compile(r"{([^{}]+)}") + # 匹配未成对的单独花括号 + self.unpaired_pattern = re.compile(r"(?:{[^{}]*$|^[^{}]*}|{[^{}]*}|})") + + + def format(self, format_string, *args, **kwargs): + # 替换未成对的花括号 + format_string = self._replace_unpaired_braces(format_string) + # 替换嵌套结构占位符 + format_string = self._replace_nested(format_string) + # 使用父类的 format 方法处理非嵌套占位符 + return super().format(format_string, *args, **kwargs) + + def get_value(self, key, args, kwargs) -> Any: + # 仅处理字符串键,如果 key 不存在于 kwargs,则保留原样占位符 + if isinstance(key, str) and key in kwargs: + return kwargs[key] + return f"{{{key}}}" + + def _replace_unpaired_braces(self, format_string): + """ + 替换未成对的花括号为普通字符 '{' 或 '}'。 + """ + # 替换未成对的 `{` 或 `}` 为普通字符 + def replace_unpaired(match): + unmatched = match.group(0) + # 如果是未闭合的 `{` 或单独的 `}`, 替换为普通字符 + if unmatched.startswith("{") and unmatched.endswith("}"): + return unmatched # 保留合法的占位符 + elif unmatched.startswith("{"): + return "{{" # 替换未闭合的 `{` 为普通字符 + elif unmatched.endswith("}"): + return "}}" # 替换单独的 `}` 为普通字符 + return unmatched + return self.unpaired_pattern.sub(replace_unpaired, format_string) + + def _replace_nested(self, format_string): + """ + 替换嵌套结构为普通文本{{}} + """ + def replace_nested(match): + key = match.group(1) + # # 如果是嵌套结构(检测到 "[" 或 "."),转义为 {{...}} + if "[" in key or "." in key: + return f"{{{{{key}}}}}" # 双括号转义,避免解析 + return match.group(0) # 保留原始内容 + return self.nested_pattern.sub(replace_nested, format_string) + + @dataclass class GraphExtractionResult: """Unipartite graph extraction result class definition.""" @@ -152,11 +204,14 @@ async def __call__( async def _process_document( self, text: str, prompt_variables: dict[str, str] ) -> str: + formatter = SafeFormatter() + kwargs = { + **prompt_variables, + self._input_text_key: text + } + formated_prompt = formatter.format(self._extraction_prompt, **kwargs) response = await self._llm( - self._extraction_prompt.format(**{ - **prompt_variables, - self._input_text_key: text, - }), + formated_prompt ) results = response.output.content or "" diff --git a/graphrag/requirements1.txt b/graphrag/requirements1.txt deleted file mode 100644 index 8ab3579977..0000000000 --- a/graphrag/requirements1.txt +++ /dev/null @@ -1,149 +0,0 @@ -aiofiles==24.1.0 -aiolimiter==1.2.1 -annotated-types==0.7.0 -anyio==4.8.0 -anytree==2.12.1 -asttokens==2.4.1 -attrs==24.3.0 -autograd==1.7.0 -azure-common==1.1.28 -azure-core==1.32.0 -azure-cosmos==4.9.0 -azure-identity==1.19.0 -azure-search-documents==11.5.2 -azure-storage-blob==12.24.0 -backcall==0.2.0 -backlash==0.3.2 -beartype==0.18.5 -beautifulsoup4==4.12.3 -bleach==6.2.0 -certifi==2024.12.14 -cffi==1.17.1 -charset-normalizer==3.4.1 -click==8.1.8 -contourpy==1.3.1 -crank==0.8.1 -cryptography==44.0.0 -cycler==0.12.1 -decorator==5.1.1 -defusedxml==0.7.1 -deprecation==2.1.0 -devtools==0.12.2 -distro==1.9.0 -docopt==0.6.2 -environs==11.2.1 -executing==2.1.0 -fastjsonschema==2.21.1 -fnllm==0.0.10 -fonttools==4.55.3 -future==1.0.0 -gearbox==0.2.2 -gensim==4.3.3 -graspologic==3.4.1 -graspologic-native==1.2.1 -h11==0.14.0 -httpcore==1.0.7 -httpx==0.28.1 -hupper==1.12.1 -hyppo==0.4.0 -idna==3.10 -ipython==8.12.3 -isodate==0.7.2 -jedi==0.19.2 -Jinja2==3.1.5 -jiter==0.8.2 -joblib==1.4.2 -json_repair==0.30.3 -jsonschema==4.23.0 -jsonschema-specifications==2024.10.1 -jupyter_client==8.6.3 -jupyter_core==5.7.2 -jupyterlab_pygments==0.3.0 -kiwisolver==1.4.8 -lancedb==0.17.0 -llvmlite==0.44.0 -markdown-it-py==3.0.0 -MarkupSafe==3.0.2 -marshmallow==3.25.1 -matplotlib==3.10.0 -matplotlib-inline==0.1.7 -mdurl==0.1.2 -mistune==3.1.0 -msal==1.31.1 -msal-extensions==1.2.0 -nbclient==0.10.2 -nbconvert==7.16.5 -nbformat==5.10.4 -networkx==3.4.2 -nltk==3.9.1 -numba==0.61.0 -numpy==1.26.4 -openai==1.59.9 -overrides==7.7.0 -packaging==24.2 -pandas==2.2.3 -pandocfilters==1.5.1 -parso==0.8.4 -PasteDeploy==3.1.0 -patsy==1.0.1 -pexpect==4.9.0 -pickleshare==0.7.5 -pillow==11.1.0 -pipreqs==0.5.0 -platformdirs==4.3.6 -portalocker==2.10.1 -POT==0.9.5 -prompt_toolkit==3.0.50 -ptyprocess==0.7.0 -pure_eval==0.2.3 -pyarrow==15.0.2 -pycparser==2.22 -pydantic==2.10.5 -pydantic_core==2.27.2 -Pygments==2.19.1 -PyJWT==2.10.1 -pylance==0.20.0 -pynndescent==0.5.13 -pyparsing==3.2.1 -python-dateutil==2.9.0.post0 -python-dotenv==1.0.1 -pytz==2024.2 -PyYAML==6.0.2 -pyzmq==26.2.0 -referencing==0.36.1 -regex==2024.11.6 -repoze.lru==0.7 -requests==2.32.3 -rich==13.9.4 -rpds-py==0.22.3 -scikit-learn==1.6.1 -scipy==1.12.0 -seaborn==0.13.2 -shellingham==1.5.4 -six==1.17.0 -smart-open==7.1.0 -sniffio==1.3.1 -soupsieve==2.6 -stack-data==0.6.3 -statsmodels==0.14.4 -Tempita==0.6.0 -tenacity==9.0.0 -tg.devtools==2.4.3 -tgext.debugbar==0.5.0 -threadpoolctl==3.5.0 -tiktoken==0.8.0 -tinycss2==1.4.0 -tornado==6.4.2 -tqdm==4.67.1 -traitlets==5.14.3 -TurboGears2==2.4.3 -typer==0.15.1 -typing_extensions==4.12.2 -tzdata==2024.2 -umap-learn==0.5.7 -urllib3==2.3.0 -wcwidth==0.2.13 -webencodings==0.5.1 -WebOb==1.8.9 -wrapt==1.17.2 -yarg==0.1.9