From 10ece0638f564d6ca92dd9f84daf0f0041822733 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 17:33:59 +0200 Subject: [PATCH 01/71] clean up poetry --- cognee/infrastructure/llm/config.py | 35 +++++++++++-------- .../baml_src/extraction/extract_summary.py | 6 ++++ .../knowledge_graph/extract_content_graph.py | 3 ++ pyproject.toml | 15 ++++---- 4 files changed, 35 insertions(+), 24 deletions(-) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index de2e2168e..1ff8f6433 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -3,7 +3,10 @@ from typing import Optional, ClassVar from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import model_validator -from baml_py import ClientRegistry +try: + from baml_py import ClientRegistry +except ImportError: + ClientRegistry = None class LLMConfig(BaseSettings): @@ -63,25 +66,27 @@ class LLMConfig(BaseSettings): fallback_endpoint: str = "" fallback_model: str = "" - baml_registry: ClassVar[ClientRegistry] = ClientRegistry() + baml_registry: ClassVar = None model_config = SettingsConfigDict(env_file=".env", extra="allow") def model_post_init(self, __context) -> None: """Initialize the BAML registry after the model is created.""" - self.baml_registry.add_llm_client( - name=self.baml_llm_provider, - provider=self.baml_llm_provider, - options={ - "model": self.baml_llm_model, - "temperature": self.baml_llm_temperature, - "api_key": self.baml_llm_api_key, - "base_url": self.baml_llm_endpoint, - "api_version": self.baml_llm_api_version, - }, - ) - # Sets the primary client - self.baml_registry.set_primary(self.baml_llm_provider) + if ClientRegistry is not None: + self.baml_registry = ClientRegistry() + self.baml_registry.add_llm_client( + name=self.baml_llm_provider, + provider=self.baml_llm_provider, + options={ + "model": self.baml_llm_model, + "temperature": self.baml_llm_temperature, + "api_key": self.baml_llm_api_key, + "base_url": self.baml_llm_endpoint, + "api_version": self.baml_llm_api_version, + }, + ) + # Sets the primary client + self.baml_registry.set_primary(self.baml_llm_provider) @model_validator(mode="after") def ensure_env_vars_for_ollama(self) -> "LLMConfig": diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py index 697a52a45..8caabd937 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py @@ -37,6 +37,9 @@ async def extract_summary(content: str, response_model: Type[BaseModel]): """ config = get_llm_config() + if config.baml_registry is None: + raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + # Use BAML's SummarizeContent function summary_result = await b.SummarizeContent( content, baml_options={"client_registry": config.baml_registry} @@ -77,6 +80,9 @@ async def extract_code_summary(content: str): try: config = get_llm_config() + if config.baml_registry is None: + raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + result = await b.SummarizeCode( content, baml_options={"client_registry": config.baml_registry} ) diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py index abff07e09..aa4fce637 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py @@ -16,6 +16,9 @@ async def extract_content_graph( get_logger(level="INFO") + if config.baml_registry is None: + raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + # if response_model: # # tb = TypeBuilder() # # country = tb.union \ diff --git a/pyproject.toml b/pyproject.toml index 272c8e929..d4ffedf5a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,9 +28,7 @@ dependencies = [ "nltk>=3.9.1,<4.0.0", "numpy>=1.26.4, <=4.0.0", "pandas>=2.2.2,<3.0.0", - # Note: New s3fs and boto3 versions don't work well together - # Always use comaptible fixed versions of these two dependencies - "s3fs[boto3]==2025.3.2", + "sqlalchemy>=2.0.39,<3.0.0", "aiosqlite>=0.20.0,<1.0.0", "tiktoken>=0.8.0,<1.0.0", @@ -53,10 +51,10 @@ dependencies = [ "fastapi>=0.115.7,<1.0.0", "python-multipart>=0.0.20,<1.0.0", "fastapi-users[sqlalchemy]>=14.0.1,<15.0.0", - "dlt[sqlalchemy]>=1.9.0,<2", + "sentry-sdk[fastapi]>=2.9.0,<3", "structlog>=25.2.0,<26", - "baml-py (>=0.201.0,<0.202.0)", + "pympler>=1.1,<2.0.0", "onnxruntime>=1.0.0,<2.0.0", "pylance>=0.22.0,<1.0.0", @@ -116,14 +114,13 @@ evals = [ "plotly>=6.0.0,<7", "gdown>=5.2.0,<6", ] -gui = [ - "pyside6>=6.8.3,<7", - "qasync>=0.27.1,<0.28", -] + graphiti = ["graphiti-core>=0.7.0,<0.8"] # Note: New s3fs and boto3 versions don't work well together # Always use comaptible fixed versions of these two dependencies aws = ["s3fs[boto3]==2025.3.2"] +dlt = ["dlt[sqlalchemy]>=1.9.0,<2"] +baml = ["baml-py (>=0.201.0,<0.202.0)"] dev = [ "pytest>=7.4.0,<8", "pytest-cov>=6.1.1,<7.0.0", From 2413b7272b172121e679fd2e6dc47739006f1c10 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 17:34:55 +0200 Subject: [PATCH 02/71] clean up poetry --- cognee/infrastructure/llm/config.py | 1 + .../baml/baml_src/extraction/extract_summary.py | 8 ++++++-- .../extraction/knowledge_graph/extract_content_graph.py | 4 +++- 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index 1ff8f6433..b2a058ca6 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -3,6 +3,7 @@ from typing import Optional, ClassVar from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import model_validator + try: from baml_py import ClientRegistry except ImportError: diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py index 8caabd937..89889d294 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py @@ -38,7 +38,9 @@ async def extract_summary(content: str, response_model: Type[BaseModel]): config = get_llm_config() if config.baml_registry is None: - raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + raise ImportError( + "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." + ) # Use BAML's SummarizeContent function summary_result = await b.SummarizeContent( @@ -81,7 +83,9 @@ async def extract_code_summary(content: str): config = get_llm_config() if config.baml_registry is None: - raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + raise ImportError( + "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." + ) result = await b.SummarizeCode( content, baml_options={"client_registry": config.baml_registry} diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py index aa4fce637..f87d87d1b 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py @@ -17,7 +17,9 @@ async def extract_content_graph( get_logger(level="INFO") if config.baml_registry is None: - raise ImportError("BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features.") + raise ImportError( + "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." + ) # if response_model: # # tb = TypeBuilder() From 2e07c6cbc10f09147fc2cfdd705b8e38cb3ae070 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 17:47:51 +0200 Subject: [PATCH 03/71] fixes to postgres issue --- .../relational/create_relational_engine.py | 13 +++++++++--- .../vector/pgvector/PGVectorAdapter.py | 21 +++++++++++++++---- pyproject.toml | 9 +++++--- 3 files changed, 33 insertions(+), 10 deletions(-) diff --git a/cognee/infrastructure/databases/relational/create_relational_engine.py b/cognee/infrastructure/databases/relational/create_relational_engine.py index a889e1758..d38c506ad 100644 --- a/cognee/infrastructure/databases/relational/create_relational_engine.py +++ b/cognee/infrastructure/databases/relational/create_relational_engine.py @@ -39,8 +39,15 @@ def create_relational_engine( connection_string = f"sqlite+aiosqlite:///{db_path}/{db_name}" if db_provider == "postgres": - connection_string = ( - f"postgresql+asyncpg://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}" - ) + try: + # Test if asyncpg is available + import asyncpg + connection_string = ( + f"postgresql+asyncpg://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}" + ) + except ImportError: + raise ImportError( + "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PostgreSQL functionality." + ) return SQLAlchemyAdapter(connection_string) diff --git a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py index 4dfd9792f..5d8fd3ae3 100644 --- a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +++ b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py @@ -7,7 +7,16 @@ from sqlalchemy import JSON, Column, Table, select, delete, MetaData from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.exc import ProgrammingError from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential -from asyncpg import DeadlockDetectedError, DuplicateTableError, UniqueViolationError +try: + from asyncpg import DeadlockDetectedError, DuplicateTableError, UniqueViolationError +except ImportError: + # PostgreSQL dependencies not installed, define dummy exceptions + class DeadlockDetectedError(Exception): + pass + class DuplicateTableError(Exception): + pass + class UniqueViolationError(Exception): + pass from cognee.shared.logging_utils import get_logger @@ -70,9 +79,13 @@ class PGVectorAdapter(SQLAlchemyAdapter, VectorDBInterface): # Has to be imported at class level # Functions reading tables from database need to know what a Vector column type is - from pgvector.sqlalchemy import Vector - - self.Vector = Vector + try: + from pgvector.sqlalchemy import Vector + self.Vector = Vector + except ImportError: + raise ImportError( + "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PGVector functionality." + ) async def embed_data(self, data: list[str]) -> list[list[float]]: """ diff --git a/pyproject.toml b/pyproject.toml index d4ffedf5a..0d076e2e5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -72,15 +72,18 @@ distributed = [ "modal>=1.0.5,<2.0.0", ] +# Database backends neo4j = ["neo4j>=5.28.0,<6"] neptune = ["langchain_aws>=0.2.22"] +# PostgreSQL support (binary - no compilation required) postgres = [ - "psycopg2>=2.9.10,<3", + "psycopg2-binary>=2.9.10,<3.0.0", # Pre-compiled binary, no PostgreSQL headers needed "pgvector>=0.3.5,<0.4", "asyncpg>=0.30.0,<1.0.0", ] -postgres-binary = [ - "psycopg2-binary>=2.9.10,<3.0.0", +# PostgreSQL support (source - requires PostgreSQL development headers) +postgres-source = [ + "psycopg2>=2.9.10,<3 ; platform_system != 'Windows'", # Requires libpq-dev, build tools "pgvector>=0.3.5,<0.4", "asyncpg>=0.30.0,<1.0.0", ] From 5bc4a6cc0286bf5263f6d0f9174b4bab96e1d6ae Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 17:57:39 +0200 Subject: [PATCH 04/71] fixes to postgres issue --- .../relational/create_relational_engine.py | 1 + .../vector/pgvector/PGVectorAdapter.py | 4 ++++ .../files/utils/open_data_file.py | 21 +++++++------------ 3 files changed, 12 insertions(+), 14 deletions(-) diff --git a/cognee/infrastructure/databases/relational/create_relational_engine.py b/cognee/infrastructure/databases/relational/create_relational_engine.py index d38c506ad..4f117bf4c 100644 --- a/cognee/infrastructure/databases/relational/create_relational_engine.py +++ b/cognee/infrastructure/databases/relational/create_relational_engine.py @@ -42,6 +42,7 @@ def create_relational_engine( try: # Test if asyncpg is available import asyncpg + connection_string = ( f"postgresql+asyncpg://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}" ) diff --git a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py index 5d8fd3ae3..b2e2bf8c7 100644 --- a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +++ b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py @@ -7,14 +7,17 @@ from sqlalchemy import JSON, Column, Table, select, delete, MetaData from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.exc import ProgrammingError from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential + try: from asyncpg import DeadlockDetectedError, DuplicateTableError, UniqueViolationError except ImportError: # PostgreSQL dependencies not installed, define dummy exceptions class DeadlockDetectedError(Exception): pass + class DuplicateTableError(Exception): pass + class UniqueViolationError(Exception): pass @@ -81,6 +84,7 @@ class PGVectorAdapter(SQLAlchemyAdapter, VectorDBInterface): # Functions reading tables from database need to know what a Vector column type is try: from pgvector.sqlalchemy import Vector + self.Vector = Vector except ImportError: raise ImportError( diff --git a/cognee/infrastructure/files/utils/open_data_file.py b/cognee/infrastructure/files/utils/open_data_file.py index 171f5deb7..fcfca4161 100644 --- a/cognee/infrastructure/files/utils/open_data_file.py +++ b/cognee/infrastructure/files/utils/open_data_file.py @@ -4,7 +4,6 @@ from urllib.parse import urlparse from contextlib import asynccontextmanager from cognee.infrastructure.files.utils.get_data_file_path import get_data_file_path -from cognee.infrastructure.files.storage.S3FileStorage import S3FileStorage from cognee.infrastructure.files.storage.LocalFileStorage import LocalFileStorage @@ -23,23 +22,17 @@ async def open_data_file(file_path: str, mode: str = "rb", encoding: str = None, yield file elif file_path.startswith("s3://"): + try: + from cognee.infrastructure.files.storage.S3FileStorage import S3FileStorage + except ImportError: + raise ImportError( + "S3 dependencies are not installed. Please install with 'pip install cognee[aws]' to use S3 functionality." + ) + normalized_url = get_data_file_path(file_path) s3_dir_path = os.path.dirname(normalized_url) s3_filename = os.path.basename(normalized_url) - # if "/" in s3_path: - # s3_dir = "/".join(s3_path.split("/")[:-1]) - # s3_filename = s3_path.split("/")[-1] - # else: - # s3_dir = "" - # s3_filename = s3_path - - # Extract filesystem path from S3 URL structure - # file_dir_path = ( - # f"s3://{parsed_url.netloc}/{s3_dir}" if s3_dir else f"s3://{parsed_url.netloc}" - # ) - # file_name = s3_filename - file_storage = S3FileStorage(s3_dir_path) async with file_storage.open(s3_filename, mode=mode, **kwargs) as file: From 64d6d6ede26e28e19e69696a57600f00e4ee8a93 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 18:18:17 +0200 Subject: [PATCH 05/71] added new optionals --- cognee/api/client.py | 18 ++++++++++++------ cognee/modules/observability/get_observe.py | 13 +++++++++++-- .../cognee_network_visualization.py | 8 +++++++- cognee/shared/utils.py | 1 - pyproject.toml | 8 ++------ 5 files changed, 32 insertions(+), 16 deletions(-) diff --git a/cognee/api/client.py b/cognee/api/client.py index 215e4a17e..d72614e14 100644 --- a/cognee/api/client.py +++ b/cognee/api/client.py @@ -3,7 +3,6 @@ import os import uvicorn -import sentry_sdk from traceback import format_exc from contextlib import asynccontextmanager from fastapi import Request @@ -37,11 +36,18 @@ from cognee.api.v1.users.routers import ( logger = get_logger() if os.getenv("ENV", "prod") == "prod": - sentry_sdk.init( - dsn=os.getenv("SENTRY_REPORTING_URL"), - traces_sample_rate=1.0, - profiles_sample_rate=1.0, - ) + try: + import sentry_sdk + + sentry_sdk.init( + dsn=os.getenv("SENTRY_REPORTING_URL"), + traces_sample_rate=1.0, + profiles_sample_rate=1.0, + ) + except ImportError: + logger.info( + "Sentry SDK not available. Install with 'pip install cognee[monitoring]' to enable error monitoring." + ) app_environment = os.getenv("ENV", "prod") diff --git a/cognee/modules/observability/get_observe.py b/cognee/modules/observability/get_observe.py index db3655482..cbd55f072 100644 --- a/cognee/modules/observability/get_observe.py +++ b/cognee/modules/observability/get_observe.py @@ -6,6 +6,15 @@ def get_observe(): monitoring = get_base_config().monitoring_tool if monitoring == Observer.LANGFUSE: - from langfuse.decorators import observe + try: + from langfuse.decorators import observe - return observe + return observe + except ImportError: + # Return a no-op decorator if Langfuse is not available + def noop_observe(func=None, **kwargs): + if func is None: + return lambda f: f + return func + + return noop_observe diff --git a/cognee/modules/visualization/cognee_network_visualization.py b/cognee/modules/visualization/cognee_network_visualization.py index dde2fe98d..ef9b2f126 100644 --- a/cognee/modules/visualization/cognee_network_visualization.py +++ b/cognee/modules/visualization/cognee_network_visualization.py @@ -1,6 +1,5 @@ import os import json -import networkx from cognee.shared.logging_utils import get_logger from cognee.infrastructure.files.storage.LocalFileStorage import LocalFileStorage @@ -9,6 +8,13 @@ logger = get_logger() async def cognee_network_visualization(graph_data, destination_file_path: str = None): + try: + import networkx + except ImportError: + raise ImportError( + "NetworkX is not installed. Please install with 'pip install cognee[visualization]' to use graph visualization features." + ) + nodes_data, edges_data = graph_data G = networkx.DiGraph() diff --git a/cognee/shared/utils.py b/cognee/shared/utils.py index fb4193a8c..22557d2ac 100644 --- a/cognee/shared/utils.py +++ b/cognee/shared/utils.py @@ -3,7 +3,6 @@ import os import requests from datetime import datetime, timezone -import matplotlib.pyplot as plt import http.server import socketserver from threading import Thread diff --git a/pyproject.toml b/pyproject.toml index 0d076e2e5..5cb378a0c 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -34,15 +34,12 @@ dependencies = [ "tiktoken>=0.8.0,<1.0.0", "litellm>=1.71.0, <2.0.0", "instructor>=1.9.1,<2.0.0", - "langfuse>=2.32.0,<3", "filetype>=1.2.0,<2.0.0", "aiohttp>=3.11.14,<4.0.0", "aiofiles>=23.2.1,<24.0.0", "rdflib>=7.1.4,<7.2.0", "pypdf>=4.1.0,<6.0.0", "jinja2>=3.1.3,<4", - "matplotlib>=3.8.3,<4", - "networkx>=3.4.2,<4", "lancedb>=0.24.0,<1.0.0", "alembic>=1.13.3,<2", "pre-commit>=4.0.1,<5", @@ -51,10 +48,7 @@ dependencies = [ "fastapi>=0.115.7,<1.0.0", "python-multipart>=0.0.20,<1.0.0", "fastapi-users[sqlalchemy]>=14.0.1,<15.0.0", - - "sentry-sdk[fastapi]>=2.9.0,<3", "structlog>=25.2.0,<26", - "pympler>=1.1,<2.0.0", "onnxruntime>=1.0.0,<2.0.0", "pylance>=0.22.0,<1.0.0", @@ -141,6 +135,8 @@ dev = [ "mkdocstrings[python]>=0.26.2,<0.27", ] debug = ["debugpy>=1.8.9,<2.0.0"] +visualization = ["networkx>=3.4.2,<4", "matplotlib>=3.8.3,<4"] +monitoring = ["sentry-sdk[fastapi]>=2.9.0,<3", "langfuse>=2.32.0,<3"] [project.urls] Homepage = "https://www.cognee.ai" From 38bbfd42cf66c16708a87e95eff047583c2c210e Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 19:14:16 +0200 Subject: [PATCH 06/71] added lancedb pandas removal --- cognee/eval_framework/modal_eval_dashboard.py | 14 +- .../vector/lancedb/LanceDBAdapter.py | 13 +- cognee/tasks/graph/infer_data_ontology.py | 309 ------------------ pyproject.toml | 3 +- 4 files changed, 21 insertions(+), 318 deletions(-) delete mode 100644 cognee/tasks/graph/infer_data_ontology.py diff --git a/cognee/eval_framework/modal_eval_dashboard.py b/cognee/eval_framework/modal_eval_dashboard.py index acc0c3aa9..9ff6f543c 100644 --- a/cognee/eval_framework/modal_eval_dashboard.py +++ b/cognee/eval_framework/modal_eval_dashboard.py @@ -1,6 +1,10 @@ import os import json -import pandas as pd + +try: + import pandas as pd +except ImportError: + pd = None import subprocess import modal import streamlit as st @@ -12,7 +16,7 @@ metrics_volume = modal.Volume.from_name("evaluation_dashboard_results", create_i image = ( modal.Image.debian_slim(python_version="3.11") - .pip_install("streamlit", "pandas", "plotly") + .pip_install("streamlit", "plotly") .add_local_file(__file__, "/root/serve_dashboard.py") ) @@ -78,6 +82,12 @@ def main(): } ) + if pd is None: + st.error( + "Pandas is required for the evaluation dashboard. Install with 'pip install cognee[evals]' to use this feature." + ) + return + df = pd.DataFrame(records) if df.empty: st.warning("No JSON files found in the volume.") diff --git a/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py b/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py index 0184ec3ee..7bc3385b9 100644 --- a/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +++ b/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py @@ -205,9 +205,12 @@ class LanceDBAdapter(VectorDBInterface): collection = await self.get_collection(collection_name) if len(data_point_ids) == 1: - results = await collection.query().where(f"id = '{data_point_ids[0]}'").to_pandas() + results = await collection.query().where(f"id = '{data_point_ids[0]}'") else: - results = await collection.query().where(f"id IN {tuple(data_point_ids)}").to_pandas() + results = await collection.query().where(f"id IN {tuple(data_point_ids)}") + + # Convert query results to list format + results_list = results.to_list() if hasattr(results, "to_list") else list(results) return [ ScoredResult( @@ -215,7 +218,7 @@ class LanceDBAdapter(VectorDBInterface): payload=result["payload"], score=0, ) - for result in results.to_dict("index").values() + for result in results_list ] async def search( @@ -242,9 +245,9 @@ class LanceDBAdapter(VectorDBInterface): if limit == 0: return [] - results = await collection.vector_search(query_vector).limit(limit).to_pandas() + result_values = await collection.vector_search(query_vector).limit(limit).to_list() - result_values = list(results.to_dict("index").values()) + # result_values = list(results.to_dict("index").values()) if not result_values: return [] diff --git a/cognee/tasks/graph/infer_data_ontology.py b/cognee/tasks/graph/infer_data_ontology.py deleted file mode 100644 index 93b02db9f..000000000 --- a/cognee/tasks/graph/infer_data_ontology.py +++ /dev/null @@ -1,309 +0,0 @@ -# PROPOSED TO BE DEPRECATED - -"""This module contains the OntologyEngine class which is responsible for adding graph ontology from a JSON or CSV file.""" - -import csv -import json -from cognee.shared.logging_utils import get_logger -from datetime import datetime, timezone -from fastapi import status -from typing import Any, Dict, List, Optional, Union, Type - -import aiofiles -import pandas as pd -from pydantic import BaseModel - -from cognee.modules.graph.exceptions import EntityNotFoundError -from cognee.modules.ingestion.exceptions import IngestionError - -from cognee.infrastructure.data.chunking.config import get_chunk_config -from cognee.infrastructure.data.chunking.get_chunking_engine import get_chunk_engine -from cognee.infrastructure.databases.graph.get_graph_engine import get_graph_engine -from cognee.infrastructure.files.utils.extract_text_from_file import extract_text_from_file -from cognee.infrastructure.files.utils.guess_file_type import guess_file_type, FileTypeException -from cognee.modules.data.methods.add_model_class_to_graph import ( - add_model_class_to_graph, -) -from cognee.tasks.graph.models import NodeModel, GraphOntology -from cognee.shared.data_models import KnowledgeGraph -from cognee.modules.engine.utils import generate_node_id, generate_node_name -from cognee.infrastructure.llm.LLMGateway import LLMGateway - -logger = get_logger("task:infer_data_ontology") - - -async def extract_ontology(content: str, response_model: Type[BaseModel]): - """ - Extracts structured ontology from the provided content using a pre-defined LLM client. - - This asynchronous function retrieves a system prompt from a file and utilizes an LLM - client to create a structured output based on the input content and specified response - model. - - Parameters: - ----------- - - - content (str): The content from which to extract the ontology. - - response_model (Type[BaseModel]): The model that defines the structure of the - output ontology. - - Returns: - -------- - - The structured ontology extracted from the content. - """ - - system_prompt = LLMGateway.read_query_prompt("extract_ontology.txt") - - ontology = await LLMGateway.acreate_structured_output(content, system_prompt, response_model) - - return ontology - - -class OntologyEngine: - """ - Manage ontology data and operations for graph structures, providing methods for data - loading, flattening models, and adding ontological relationships to a graph database. - - Public methods: - - - flatten_model - - recursive_flatten - - load_data - - add_graph_ontology - """ - - async def flatten_model( - self, model: NodeModel, parent_id: Optional[str] = None - ) -> Dict[str, Any]: - """ - Flatten the model to a dictionary including optional parent ID and relationship details - if available. - - Parameters: - ----------- - - - model (NodeModel): The NodeModel instance to flatten. - - parent_id (Optional[str]): An optional ID of the parent node for hierarchical - purposes. (default None) - - Returns: - -------- - - - Dict[str, Any]: A dictionary representation of the model with flattened - attributes. - """ - result = model.dict() - result["parent_id"] = parent_id - if model.default_relationship: - result.update( - { - "relationship_type": model.default_relationship.type, - "relationship_source": model.default_relationship.source, - "relationship_target": model.default_relationship.target, - } - ) - return result - - async def recursive_flatten( - self, items: Union[List[Dict[str, Any]], Dict[str, Any]], parent_id: Optional[str] = None - ) -> List[Dict[str, Any]]: - """ - Recursively flatten a hierarchical structure of models into a flat list of dictionaries. - - Parameters: - ----------- - - - items (Union[List[Dict[str, Any]], Dict[str, Any]]): A list or dictionary - containing models to flatten. - - parent_id (Optional[str]): An optional ID of the parent node to maintain hierarchy - during flattening. (default None) - - Returns: - -------- - - - List[Dict[str, Any]]: A flat list of dictionaries representing the hierarchical - model structure. - """ - flat_list = [] - - if isinstance(items, list): - for item in items: - flat_list.extend(await self.recursive_flatten(item, parent_id)) - elif isinstance(items, dict): - model = NodeModel.model_validate(items) - flat_list.append(await self.flatten_model(model, parent_id)) - for child in model.children: - flat_list.extend(await self.recursive_flatten(child, model.node_id)) - return flat_list - - async def load_data(self, file_path: str) -> Union[List[Dict[str, Any]], Dict[str, Any]]: - """ - Load data from a specified JSON or CSV file and return it in a structured format. - - Parameters: - ----------- - - - file_path (str): The path to the file to load data from. - - Returns: - -------- - - - Union[List[Dict[str, Any]], Dict[str, Any]]: Parsed data from the file as either a - list of dictionaries or a single dictionary depending on content type. - """ - try: - if file_path.endswith(".json"): - async with aiofiles.open(file_path, mode="r") as f: - data = await f.read() - return json.loads(data) - elif file_path.endswith(".csv"): - async with aiofiles.open(file_path, mode="r") as f: - content = await f.read() - reader = csv.DictReader(content.splitlines()) - return list(reader) - else: - raise IngestionError(message="Unsupported file format") - except Exception as e: - raise IngestionError( - message=f"Failed to load data from {file_path}: {e}", - status_code=status.HTTP_422_UNPROCESSABLE_ENTITY, - ) - - async def add_graph_ontology(self, file_path: str = None, documents: list = None): - """ - Add graph ontology from a JSON or CSV file, or infer relationships from provided - document content. Raise exceptions for invalid file types or missing entities. - - Parameters: - ----------- - - - file_path (str): Optional path to a file containing data to be loaded. (default - None) - - documents (list): Optional list of document objects for content extraction if no - file path is provided. (default None) - """ - if file_path is None: - initial_chunks_and_ids = [] - - chunk_config = get_chunk_config() - chunk_engine = get_chunk_engine() - chunk_strategy = chunk_config.chunk_strategy - - for base_file in documents: - with open(base_file.raw_data_location, "rb") as file: - try: - file_type = guess_file_type(file) - text = extract_text_from_file(file, file_type) - - subchunks, chunks_with_ids = chunk_engine.chunk_data( - chunk_strategy, - text, - chunk_config.chunk_size, - chunk_config.chunk_overlap, - ) - - if chunks_with_ids[0][0] == 1: - initial_chunks_and_ids.append({base_file.id: chunks_with_ids}) - - except FileTypeException: - logger.warning( - "File (%s) has an unknown file type. We are skipping it.", file["id"] - ) - - ontology = await extract_ontology(str(initial_chunks_and_ids), GraphOntology) - graph_client = await get_graph_engine() - - await graph_client.add_nodes( - [ - ( - node.id, - dict( - uuid=generate_node_id(node.id), - name=generate_node_name(node.name), - type=generate_node_id(node.id), - description=node.description, - updated_at=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - ), - ) - for node in ontology.nodes - ] - ) - - await graph_client.add_edges( - ( - generate_node_id(edge.source_id), - generate_node_id(edge.target_id), - edge.relationship_type, - dict( - source_node_id=generate_node_id(edge.source_id), - target_node_id=generate_node_id(edge.target_id), - relationship_name=edge.relationship_type, - updated_at=datetime.now(timezone.utc).strftime("%Y-%m-%d %H:%M:%S"), - ), - ) - for edge in ontology.edges - ) - - else: - dataset_level_information = documents[0][1] - - # Extract the list of valid IDs from the explanations - valid_ids = {item["id"] for item in dataset_level_information} - try: - data = await self.load_data(file_path) - flt_ontology = await self.recursive_flatten(data) - df = pd.DataFrame(flt_ontology) - graph_client = await get_graph_engine() - - for _, row in df.iterrows(): - node_data = row.to_dict() - node_id = node_data.pop("node_id", None) - if node_id in valid_ids: - await graph_client.add_node(node_id, node_data) - if node_id not in valid_ids: - raise EntityNotFoundError( - message=f"Node ID {node_id} not found in the dataset" - ) - if pd.notna(row.get("relationship_source")) and pd.notna( - row.get("relationship_target") - ): - await graph_client.add_edge( - row["relationship_source"], - row["relationship_target"], - relationship_name=row["relationship_type"], - edge_properties={ - "source_node_id": row["relationship_source"], - "target_node_id": row["relationship_target"], - "relationship_name": row["relationship_type"], - "updated_at": datetime.now(timezone.utc).strftime( - "%Y-%m-%d %H:%M:%S" - ), - }, - ) - - return - except Exception as e: - raise RuntimeError(f"Failed to add graph ontology from {file_path}: {e}") from e - - -async def infer_data_ontology(documents, ontology_model=KnowledgeGraph, root_node_id=None): - """ - Infer data ontology from provided documents and optionally add it to a graph. - - Parameters: - ----------- - - - documents: The documents from which to infer the ontology. - - ontology_model: The ontology model to use for the inference, defaults to - KnowledgeGraph. (default KnowledgeGraph) - - root_node_id: An optional root node identifier for the ontology. (default None) - """ - if ontology_model == KnowledgeGraph: - ontology_engine = OntologyEngine() - root_node_id = await ontology_engine.add_graph_ontology(documents=documents) - else: - graph_engine = await get_graph_engine() - await add_model_class_to_graph(ontology_model, graph_engine) - - yield (documents, root_node_id) diff --git a/pyproject.toml b/pyproject.toml index 5cb378a0c..b17b4893a 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,8 +27,6 @@ dependencies = [ "typing_extensions>=4.12.2,<5.0.0", "nltk>=3.9.1,<4.0.0", "numpy>=1.26.4, <=4.0.0", - "pandas>=2.2.2,<3.0.0", - "sqlalchemy>=2.0.39,<3.0.0", "aiosqlite>=0.20.0,<1.0.0", "tiktoken>=0.8.0,<1.0.0", @@ -110,6 +108,7 @@ codegraph = [ evals = [ "plotly>=6.0.0,<7", "gdown>=5.2.0,<6", + "pandas>=2.2.2,<3.0.0", ] graphiti = ["graphiti-core>=0.7.0,<0.8"] From c85302f467be683e2edc52d34439063859ae1d84 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 19:42:30 +0200 Subject: [PATCH 07/71] added lancedb pandas removal --- poetry.lock | 261 ++++++++++++++++++++++------------------------------ 1 file changed, 109 insertions(+), 152 deletions(-) diff --git a/poetry.lock b/poetry.lock index 109e5d917..5ef1c5783 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,12 +1,13 @@ -# This file is automatically @generated by Poetry 2.1.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 2.1.2 and should not be changed by hand. [[package]] name = "aiobotocore" version = "2.24.1" description = "Async client for aws services using botocore and aiohttp" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"aws\"" files = [ {file = "aiobotocore-2.24.1-py3-none-any.whl", hash = "sha256:557922823455ca65bbd065b363b54846f16b9c4b6bd0b61ecdfa01ca13a04531"}, {file = "aiobotocore-2.24.1.tar.gz", hash = "sha256:59237f1b2d4ff619f9a9e78360b691d59b92fdd4d03d054dbd2eeff8ada5667e"}, @@ -164,9 +165,10 @@ speedups = ["Brotli ; platform_python_implementation == \"CPython\"", "aiodns (> name = "aioitertools" version = "0.12.0" description = "itertools and builtins for AsyncIO and mixed iterables" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"aws\"" files = [ {file = "aioitertools-0.12.0-py3-none-any.whl", hash = "sha256:fc1f5fac3d737354de8831cbba3eb04f79dd649d8f3afb4c5b114925e662a796"}, {file = "aioitertools-0.12.0.tar.gz", hash = "sha256:c2a9055b4fbb7705f561b9d86053e8af5d10cc845d22c32008c43490b2d8dd6b"}, @@ -455,7 +457,7 @@ description = "An asyncio PostgreSQL driver" optional = true python-versions = ">=3.8.0" groups = ["main"] -markers = "extra == \"postgres\" or extra == \"postgres-binary\"" +markers = "extra == \"postgres\" or extra == \"postgres-source\"" files = [ {file = "asyncpg-0.30.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:bfb4dd5ae0699bad2b233672c8fc5ccbd9ad24b89afded02341786887e37927e"}, {file = "asyncpg-0.30.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc1f62c792752a49f88b7e6f774c26077091b44caceb1983509edc18a2222ec0"}, @@ -556,9 +558,10 @@ dev = ["backports.zoneinfo ; python_version < \"3.9\"", "freezegun (>=1.0,<2.0)" name = "backoff" version = "2.2.1" description = "Function decoration for backoff and retry" -optional = false +optional = true python-versions = ">=3.7,<4.0" groups = ["main"] +markers = "extra == \"deepeval\" or extra == \"posthog\" or extra == \"chromadb\" or extra == \"docs\" or extra == \"monitoring\"" files = [ {file = "backoff-2.2.1-py3-none-any.whl", hash = "sha256:63579f9a0628e06278f7e47b7d7d5b6ce20dc65c5e96a6f3ca99a6adca0396e8"}, {file = "backoff-2.2.1.tar.gz", hash = "sha256:03f829f5bb1923180821643f8753b0502c3b682293992485b0eef2807afa5cba"}, @@ -589,9 +592,10 @@ extras = ["regex"] name = "baml-py" version = "0.201.0" description = "BAML python bindings (pyproject.toml)" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"baml\"" files = [ {file = "baml_py-0.201.0-cp38-abi3-macosx_10_12_x86_64.whl", hash = "sha256:83228d2af2b0e845bbbb4e14f7cbd3376cec385aee01210ac522ab6076e07bec"}, {file = "baml_py-0.201.0-cp38-abi3-macosx_11_0_arm64.whl", hash = "sha256:2a9d016139e3ae5b5ce98c7b05b5fbd53d5d38f04dc810ec4d70fb17dd6c10e4"}, @@ -739,9 +743,10 @@ css = ["tinycss2 (>=1.1.0,<1.5)"] name = "boto3" version = "1.39.11" description = "The AWS SDK for Python" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\"" files = [ {file = "boto3-1.39.11-py3-none-any.whl", hash = "sha256:af8f1dad35eceff7658fab43b39b0f55892b6e3dd12308733521cc24dd2c9a02"}, {file = "boto3-1.39.11.tar.gz", hash = "sha256:3027edf20642fe1d5f9dc50a420d0fe2733073ed6a9f0f047b60fe08c3682132"}, @@ -759,9 +764,10 @@ crt = ["botocore[crt] (>=1.21.0,<2.0a0)"] name = "botocore" version = "1.39.11" description = "Low-level, data-driven core of boto 3." -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\"" files = [ {file = "botocore-1.39.11-py3-none-any.whl", hash = "sha256:1545352931a8a186f3e977b1e1a4542d7d434796e274c3c62efd0210b5ea76dc"}, {file = "botocore-1.39.11.tar.gz", hash = "sha256:953b12909d6799350e346ab038e55b6efe622c616f80aef74d7a6683ffdd972c"}, @@ -1176,10 +1182,10 @@ test = ["pytest"] name = "contourpy" version = "1.3.2" description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version == \"3.10\"" +markers = "python_version == \"3.10\" and extra == \"visualization\"" files = [ {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, @@ -1254,10 +1260,10 @@ test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist" name = "contourpy" version = "1.3.3" description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false +optional = true python-versions = ">=3.11" groups = ["main"] -markers = "python_version >= \"3.11\"" +markers = "python_version >= \"3.11\" and extra == \"visualization\"" files = [ {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"}, {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"}, @@ -1524,9 +1530,10 @@ files = [ name = "cycler" version = "0.12.1" description = "Composable style cycles" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"visualization\"" files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, @@ -1815,9 +1822,10 @@ files = [ name = "dlt" version = "1.15.0" description = "dlt is an open-source python-first scalable data loading library that does not require any backend to run." -optional = false +optional = true python-versions = "<3.15,>=3.9.2" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "dlt-1.15.0-py3-none-any.whl", hash = "sha256:fdc1e8a47b6daae9d7f235de1146427a40518960f46089c3ae2b3c7ce5f66cd9"}, {file = "dlt-1.15.0.tar.gz", hash = "sha256:3dff1419649c984c183ba2ae53bfa60f4d0d7cf3590c1388997886dbe7bfee97"}, @@ -2236,9 +2244,10 @@ files = [ name = "fonttools" version = "4.59.1" description = "Tools to manipulate font files" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"visualization\"" files = [ {file = "fonttools-4.59.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:e90a89e52deb56b928e761bb5b5f65f13f669bfd96ed5962975debea09776a23"}, {file = "fonttools-4.59.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:5d29ab70658d2ec19422b25e6ace00a0b0ae4181ee31e03335eaef53907d2d83"}, @@ -2525,9 +2534,10 @@ dev = ["flake8", "markdown", "twine", "wheel"] name = "gitdb" version = "4.0.12" description = "Git Object Database" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"dlt\" or extra == \"dev\"" files = [ {file = "gitdb-4.0.12-py3-none-any.whl", hash = "sha256:67073e15955400952c6565cc3e707c554a4eea2e428946f7a4c162fab9bd9bcf"}, {file = "gitdb-4.0.12.tar.gz", hash = "sha256:5ef71f855d191a3326fcfbc0d5da835f26b13fbcba60c32c21091c349ffdb571"}, @@ -2540,9 +2550,10 @@ smmap = ">=3.0.1,<6" name = "gitpython" version = "3.1.45" description = "GitPython is a Python library used to interact with Git repositories" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"dlt\" or extra == \"dev\"" files = [ {file = "gitpython-3.1.45-py3-none-any.whl", hash = "sha256:8908cb2e02fb3b93b7eb0f2827125cb699869470432cc885f019b8fd0fccff77"}, {file = "gitpython-3.1.45.tar.gz", hash = "sha256:85b0ee964ceddf211c41b9f27a49086010a190fd8132a24e21f362a4b36a791c"}, @@ -2559,9 +2570,10 @@ test = ["coverage[toml]", "ddt (>=1.1.1,!=1.4.3)", "mock ; python_version < \"3. name = "giturlparse" version = "0.12.0" description = "A Git URL parsing module (supports parsing and rewriting)" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "giturlparse-0.12.0-py2.py3-none-any.whl", hash = "sha256:412b74f2855f1da2fefa89fd8dde62df48476077a72fc19b62039554d27360eb"}, {file = "giturlparse-0.12.0.tar.gz", hash = "sha256:c0fff7c21acc435491b1779566e038757a205c1ffdcb47e4f81ea52ad8c3859a"}, @@ -3051,9 +3063,10 @@ hyperframe = ">=6.1,<7" name = "hexbytes" version = "1.3.1" description = "hexbytes: Python `bytes` subclass that decodes hex, with a readable console output" -optional = false +optional = true python-versions = "<4,>=3.8" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "hexbytes-1.3.1-py3-none-any.whl", hash = "sha256:da01ff24a1a9a2b1881c4b85f0e9f9b0f51b526b379ffa23832ae7899d29c2c7"}, {file = "hexbytes-1.3.1.tar.gz", hash = "sha256:a657eebebdfe27254336f98d8af6e2236f3f83aed164b87466b6cf6c5f5a4765"}, @@ -3327,9 +3340,10 @@ pyreadline3 = {version = "*", markers = "sys_platform == \"win32\" and python_ve name = "humanize" version = "4.13.0" description = "Python humanize utilities" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "humanize-4.13.0-py3-none-any.whl", hash = "sha256:b810820b31891813b1673e8fec7f1ed3312061eab2f26e3fa192c393d11ed25f"}, {file = "humanize-4.13.0.tar.gz", hash = "sha256:78f79e68f76f0b04d711c4e55d32bebef5be387148862cb1ef83d2b58e7935a0"}, @@ -3769,9 +3783,10 @@ files = [ name = "jmespath" version = "1.0.1" description = "JSON Matching Expressions" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\"" files = [ {file = "jmespath-1.0.1-py3-none-any.whl", hash = "sha256:02e2e4cc71b5bcab88332eebf907519190dd9e6e82107fa7f83b1003a6252980"}, {file = "jmespath-1.0.1.tar.gz", hash = "sha256:90261b206d6defd58fdd5e85f478bf633a2901798906be2ad389150c5c60edbe"}, @@ -3837,11 +3852,14 @@ jsonpointer = ">=1.9" name = "jsonpath-ng" version = "1.7.0" description = "A final implementation of JSONPath for Python that aims to be standard compliant, including arithmetic and binary comparison operators and providing clear AST for metaprogramming." -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "jsonpath-ng-1.7.0.tar.gz", hash = "sha256:f6f5f7fd4e5ff79c785f1573b394043b39849fb2bb47bcead935d12b00beab3c"}, + {file = "jsonpath_ng-1.7.0-py2-none-any.whl", hash = "sha256:898c93fc173f0c336784a3fa63d7434297544b7198124a68f9a3ef9597b0ae6e"}, + {file = "jsonpath_ng-1.7.0-py3-none-any.whl", hash = "sha256:f3d7f9e848cba1b6da28c55b1c26ff915dc9e0b1ba7e752a53d6da8d5cbd00b6"}, ] [package.dependencies] @@ -4148,9 +4166,10 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v name = "kiwisolver" version = "1.4.9" description = "A fast implementation of the Cassowary constraint solver" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] +markers = "extra == \"visualization\"" files = [ {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b"}, {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f"}, @@ -4421,9 +4440,10 @@ six = "*" name = "langfuse" version = "2.60.9" description = "A client library for accessing langfuse" -optional = false +optional = true python-versions = "<4.0,>=3.9" groups = ["main"] +markers = "extra == \"monitoring\"" files = [ {file = "langfuse-2.60.9-py3-none-any.whl", hash = "sha256:e4291a66bc579c66d7652da5603ca7f0409536700d7b812e396780b5d9a0685d"}, {file = "langfuse-2.60.9.tar.gz", hash = "sha256:040753346d7df4a0be6967dfc7efe3de313fee362524fe2f801867fcbbca3c98"}, @@ -5015,9 +5035,10 @@ tests = ["pytest", "simplejson"] name = "matplotlib" version = "3.10.5" description = "Python plotting package" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] +markers = "extra == \"visualization\"" files = [ {file = "matplotlib-3.10.5-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:5d4773a6d1c106ca05cb5a5515d277a6bb96ed09e5c8fab6b7741b8fcaa62c8f"}, {file = "matplotlib-3.10.5-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc88af74e7ba27de6cbe6faee916024ea35d895ed3d61ef6f58c4ce97da7185a"}, @@ -5935,10 +5956,10 @@ files = [ name = "networkx" version = "3.4.2" description = "Python package for creating and manipulating graphs and networks" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version == \"3.10\"" +markers = "python_version == \"3.10\" and (extra == \"llama-index\" or extra == \"docs\" or extra == \"visualization\")" files = [ {file = "networkx-3.4.2-py3-none-any.whl", hash = "sha256:df5d4365b724cf81b8c6a7312509d0c22386097011ad1abe274afd5e9d3bbc5f"}, {file = "networkx-3.4.2.tar.gz", hash = "sha256:307c3669428c5362aab27c8a1260aa8f47c4e91d3891f48be0141738d8d053e1"}, @@ -5956,10 +5977,10 @@ test = ["pytest (>=7.2)", "pytest-cov (>=4.0)"] name = "networkx" version = "3.5" description = "Python package for creating and manipulating graphs and networks" -optional = false +optional = true python-versions = ">=3.11" groups = ["main"] -markers = "python_version >= \"3.11\"" +markers = "python_version >= \"3.11\" and (extra == \"llama-index\" or extra == \"docs\" or extra == \"visualization\")" files = [ {file = "networkx-3.5-py3-none-any.whl", hash = "sha256:0030d386a9a06dee3565298b4a734b68589749a544acbb6c412dc9e2489ec6ec"}, {file = "networkx-3.5.tar.gz", hash = "sha256:d4c6f9cf81f52d69230866796b82afbccdec3db7ae4fbd1b65ea750feed50037"}, @@ -6452,10 +6473,10 @@ test = ["pytest (>=8.3.0,<8.4.0)", "pytest-benchmark (>=5.1.0,<5.2.0)", "pytest- name = "orjson" version = "3.11.3" description = "Fast, correct Python JSON library supporting dataclasses, datetimes, and numpy" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] -markers = "(sys_platform != \"emscripten\" or extra == \"neptune\" or extra == \"langchain\") and (sys_platform != \"emscripten\" or platform_python_implementation != \"PyPy\")" +markers = "(sys_platform != \"emscripten\" or platform_python_implementation != \"PyPy\") and (sys_platform != \"emscripten\" or extra == \"neptune\" or extra == \"langchain\") and (platform_python_implementation != \"PyPy\" or extra == \"dlt\") and (extra == \"neptune\" or extra == \"langchain\" or extra == \"dlt\")" files = [ {file = "orjson-3.11.3-cp310-cp310-macosx_10_15_x86_64.macosx_11_0_arm64.macosx_10_15_universal2.whl", hash = "sha256:29cb1f1b008d936803e2da3d7cba726fc47232c45df531b29edf0b232dd737e7"}, {file = "orjson-3.11.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:97dceed87ed9139884a55db8722428e27bd8452817fbf1869c58b49fecab1120"}, @@ -6587,9 +6608,10 @@ lint = ["black"] name = "pandas" version = "2.3.2" description = "Powerful data structures for data analysis, time series, and statistics" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"chromadb\" or extra == \"docs\" or extra == \"evals\"" files = [ {file = "pandas-2.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:52bc29a946304c360561974c6542d1dd628ddafa69134a7131fdfd6a5d7a1a35"}, {file = "pandas-2.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:220cc5c35ffaa764dd5bb17cf42df283b5cb7fdf49e10a7b053a06c9cb48ee2b"}, @@ -6717,9 +6739,10 @@ files = [ name = "pathvalidate" version = "3.3.1" description = "pathvalidate is a Python library to sanitize/validate a string such as filenames/file-paths/etc." -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "pathvalidate-3.3.1-py3-none-any.whl", hash = "sha256:5263baab691f8e1af96092fa5137ee17df5bdfbd6cff1fcac4d6ef4bc2e1735f"}, {file = "pathvalidate-3.3.1.tar.gz", hash = "sha256:b18c07212bfead624345bb8e1d6141cdcf15a39736994ea0b94035ad2b1ba177"}, @@ -6734,9 +6757,10 @@ test = ["Faker (>=1.0.8)", "allpairspy (>=2)", "click (>=6.2)", "pytest (>=6.0.1 name = "pendulum" version = "3.1.0" description = "Python datetimes made easy" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "pendulum-3.1.0-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:aa545a59e6517cf43597455a6fb44daa4a6e08473d67a7ad34e4fa951efb9620"}, {file = "pendulum-3.1.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:299df2da6c490ede86bb8d58c65e33d7a2a42479d21475a54b467b03ccb88531"}, @@ -6834,7 +6858,7 @@ description = "pgvector support for Python" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"postgres\" or extra == \"postgres-binary\"" +markers = "extra == \"postgres\" or extra == \"postgres-source\"" files = [ {file = "pgvector-0.3.6-py3-none-any.whl", hash = "sha256:f6c269b3c110ccb7496bac87202148ed18f34b390a0189c783e351062400a75a"}, {file = "pgvector-0.3.6.tar.gz", hash = "sha256:31d01690e6ea26cea8a633cde5f0f55f5b246d9c8292d68efdef8c22ec994ade"}, @@ -6847,9 +6871,10 @@ numpy = "*" name = "pillow" version = "11.3.0" description = "Python Imaging Library (Fork)" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "(extra == \"codegraph\" or extra == \"llama-index\" or extra == \"mistral\" or extra == \"docs\" or extra == \"visualization\") and (python_version <= \"3.12\" or extra == \"llama-index\" or extra == \"mistral\" or extra == \"docs\" or extra == \"visualization\")" files = [ {file = "pillow-11.3.0-cp310-cp310-macosx_10_10_x86_64.whl", hash = "sha256:1b9c17fd4ace828b3003dfd1e30bff24863e0eb59b535e8f80194d9cc7ecf860"}, {file = "pillow-11.3.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:65dc69160114cdd0ca0f35cb434633c75e8e7fad4cf855177a05bf38678f73ad"}, @@ -7014,9 +7039,10 @@ kaleido = ["kaleido (>=1.0.0)"] name = "pluggy" version = "1.6.0" description = "plugin and hook calling mechanisms for python" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"deepeval\" or extra == \"dev\" or extra == \"dlt\"" files = [ {file = "pluggy-1.6.0-py3-none-any.whl", hash = "sha256:e920276dd6813095e9377c0bc5566d94c932c33b27a3e3945d8389c374dd4746"}, {file = "pluggy-1.6.0.tar.gz", hash = "sha256:7dcc130b76258d33b90f61b658791dede3486c3e6bfb003ee5c9bfb396dd22f3"}, @@ -7030,9 +7056,10 @@ testing = ["coverage", "pytest", "pytest-benchmark"] name = "ply" version = "3.11" description = "Python Lex & Yacc" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "ply-3.11-py2.py3-none-any.whl", hash = "sha256:096f9b8350b65ebd2fd1346b12452efe5b9607f7482813ffca50c22722a807ce"}, {file = "ply-3.11.tar.gz", hash = "sha256:00c7c1aaa88358b9c765b6d3000c6eec0ba42abca5351b095321aef446081da3"}, @@ -7317,7 +7344,7 @@ description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"postgres\"" +markers = "extra == \"postgres-source\" and platform_system != \"Windows\"" files = [ {file = "psycopg2-2.9.10-cp310-cp310-win32.whl", hash = "sha256:5df2b672140f95adb453af93a7d669d7a7bf0a56bcd26f1502329166f4a61716"}, {file = "psycopg2-2.9.10-cp310-cp310-win_amd64.whl", hash = "sha256:c6f7b8561225f9e711a9c47087388a97fdc948211c10a4bccbf0ba68ab7b3b5a"}, @@ -7337,7 +7364,7 @@ description = "psycopg2 - Python-PostgreSQL Database Adapter" optional = true python-versions = ">=3.8" groups = ["main"] -markers = "extra == \"postgres-binary\"" +markers = "extra == \"postgres\"" files = [ {file = "psycopg2-binary-2.9.10.tar.gz", hash = "sha256:4b3df0e6990aa98acda57d983942eff13d824135fe2250e6522edaa782a06de2"}, {file = "psycopg2_binary-2.9.10-cp310-cp310-macosx_12_0_x86_64.whl", hash = "sha256:0ea8e3d0ae83564f2fc554955d327fa081d065c8ca5cc6d2abb643e2c9c1200f"}, @@ -7386,6 +7413,7 @@ files = [ {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_i686.whl", hash = "sha256:bb89f0a835bcfc1d42ccd5f41f04870c1b936d8507c6df12b7737febc40f0909"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_ppc64le.whl", hash = "sha256:f0c2d907a1e102526dd2986df638343388b94c33860ff3bbe1384130828714b1"}, {file = "psycopg2_binary-2.9.10-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f8157bed2f51db683f31306aa497311b560f2265998122abe1dce6428bd86567"}, + {file = "psycopg2_binary-2.9.10-cp313-cp313-win_amd64.whl", hash = "sha256:27422aa5f11fbcd9b18da48373eb67081243662f9b46e6fd07c3eb46e4535142"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-macosx_12_0_x86_64.whl", hash = "sha256:eb09aa7f9cecb45027683bb55aebaaf45a0df8bf6de68801a6afdc7947bb09d4"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b73d6d7f0ccdad7bc43e6d34273f70d587ef62f824d7261c4ae9b8b1b6af90e8"}, {file = "psycopg2_binary-2.9.10-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ce5ab4bf46a211a8e924d307c1b1fcda82368586a19d0a24f8ae166f5c784864"}, @@ -8097,66 +8125,6 @@ files = [ [package.extras] dev = ["build", "flake8", "mypy", "pytest", "twine"] -[[package]] -name = "pyside6" -version = "6.9.2" -description = "Python bindings for the Qt cross-platform application and UI framework" -optional = true -python-versions = "<3.14,>=3.9" -groups = ["main"] -markers = "extra == \"gui\"" -files = [ - {file = "pyside6-6.9.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:71245c76bfbe5c41794ffd8546730ec7cc869d4bbe68535639e026e4ef8a7714"}, - {file = "pyside6-6.9.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:64a9e2146e207d858e00226f68d7c1b4ab332954742a00dcabb721bb9e4aa0cd"}, - {file = "pyside6-6.9.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:a78fad16241a1f2ed0fa0098cf3d621f591fc75b4badb7f3fa3959c9d861c806"}, - {file = "pyside6-6.9.2-cp39-abi3-win_amd64.whl", hash = "sha256:d1afbf48f9a5612b9ee2dc7c384c1a65c08b5830ba5e7d01f66d82678e5459df"}, - {file = "pyside6-6.9.2-cp39-abi3-win_arm64.whl", hash = "sha256:1499b1d7629ab92119118e2636b4ace836b25e457ddf01003fdca560560b8c0a"}, -] - -[package.dependencies] -PySide6_Addons = "6.9.2" -PySide6_Essentials = "6.9.2" -shiboken6 = "6.9.2" - -[[package]] -name = "pyside6-addons" -version = "6.9.2" -description = "Python bindings for the Qt cross-platform application and UI framework (Addons)" -optional = true -python-versions = "<3.14,>=3.9" -groups = ["main"] -markers = "extra == \"gui\"" -files = [ - {file = "pyside6_addons-6.9.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:7019fdcc0059626eb1608b361371f4dc8cb7f2d02f066908fd460739ff5a07cd"}, - {file = "pyside6_addons-6.9.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:24350e5415317f269e743d1f7b4933fe5f59d90894aa067676c9ce6bfe9e7988"}, - {file = "pyside6_addons-6.9.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:af8dee517de8d336735a6543f7dd496eb580e852c14b4d2304b890e2a29de499"}, - {file = "pyside6_addons-6.9.2-cp39-abi3-win_amd64.whl", hash = "sha256:98d2413904ee4b2b754b077af7875fa6ec08468c01a6628a2c9c3d2cece4874f"}, - {file = "pyside6_addons-6.9.2-cp39-abi3-win_arm64.whl", hash = "sha256:b430cae782ff1a99fb95868043557f22c31b30c94afb9cf73278584e220a2ab6"}, -] - -[package.dependencies] -PySide6_Essentials = "6.9.2" -shiboken6 = "6.9.2" - -[[package]] -name = "pyside6-essentials" -version = "6.9.2" -description = "Python bindings for the Qt cross-platform application and UI framework (Essentials)" -optional = true -python-versions = "<3.14,>=3.9" -groups = ["main"] -markers = "extra == \"gui\"" -files = [ - {file = "pyside6_essentials-6.9.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:713eb8dcbb016ff10e6fca129c1bf2a0fd8cfac979e689264e0be3b332f9398e"}, - {file = "pyside6_essentials-6.9.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:84b8ca4fa56506e2848bdb4c7a0851a5e7adcb916bef9bce25ce2eeb6c7002cc"}, - {file = "pyside6_essentials-6.9.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:d0f701503974bd51b408966539aa6956f3d8536e547ea8002fbfb3d77796bbc3"}, - {file = "pyside6_essentials-6.9.2-cp39-abi3-win_amd64.whl", hash = "sha256:b2f746f795138ac63eb173f9850a6db293461a1b6ce22cf6dafac7d194a38951"}, - {file = "pyside6_essentials-6.9.2-cp39-abi3-win_arm64.whl", hash = "sha256:ecd7b5cd9e271f397fb89a6357f4ec301d8163e50869c6c557f9ccc6bed42789"}, -] - -[package.dependencies] -shiboken6 = "6.9.2" - [[package]] name = "pysocks" version = "1.7.1" @@ -8295,9 +8263,10 @@ testing = ["filelock"] name = "python-dateutil" version = "2.9.0.post0" description = "Extensions to the standard Python datetime module" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\" or extra == \"notebook\" or extra == \"dev\" or extra == \"deepeval\" or extra == \"posthog\" or extra == \"chromadb\" or extra == \"falkordb\" or extra == \"docs\" or extra == \"evals\" or extra == \"dlt\" or extra == \"visualization\"" files = [ {file = "python-dateutil-2.9.0.post0.tar.gz", hash = "sha256:37dd54208da7e1cd875388217d5e00ebd4179249f90fb72437e91a35459a0ad3"}, {file = "python_dateutil-2.9.0.post0-py2.py3-none-any.whl", hash = "sha256:a8b2bc7bffae282281c8140a97d3aa9c14da0b136dfe83f850eea9a5f7470427"}, @@ -8450,9 +8419,10 @@ XlsxWriter = ">=0.5.7" name = "pytz" version = "2025.2" description = "World timezone definitions, modern and historical" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"neo4j\" or extra == \"graphiti\" or extra == \"chromadb\" or extra == \"docs\" or extra == \"evals\" or extra == \"dlt\"" files = [ {file = "pytz-2025.2-py2.py3-none-any.whl", hash = "sha256:5ddf76296dd8c44c26eb8f4b6f35488f3ccbf6fbbd7adee0b7262d43f0ec2f00"}, {file = "pytz-2025.2.tar.gz", hash = "sha256:360b9e3dbb49a209c21ad61809c7fb453643e048b38924c765813546746e81c3"}, @@ -8465,7 +8435,7 @@ description = "Python for Window Extensions" optional = false python-versions = "*" groups = ["main"] -markers = "sys_platform == \"win32\" or platform_system == \"Windows\"" +markers = "(platform_system == \"Windows\" or platform_python_implementation != \"PyPy\" or extra == \"dlt\") and (platform_system == \"Windows\" or extra == \"notebook\" or extra == \"dev\" or extra == \"dlt\") and (platform_system == \"Windows\" or sys_platform == \"win32\")" files = [ {file = "pywin32-311-cp310-cp310-win32.whl", hash = "sha256:d03ff496d2a0cd4a5893504789d4a15399133fe82517455e78bad62efbb7f0a3"}, {file = "pywin32-311-cp310-cp310-win_amd64.whl", hash = "sha256:797c2772017851984b97180b0bebe4b620bb86328e8a884bb626156295a63b3b"}, @@ -8692,19 +8662,6 @@ files = [ [package.dependencies] cffi = {version = "*", markers = "implementation_name == \"pypy\""} -[[package]] -name = "qasync" -version = "0.27.1" -description = "Python library for using asyncio in Qt-based applications" -optional = true -python-versions = ">=3.8,<4.0" -groups = ["main"] -markers = "extra == \"gui\"" -files = [ - {file = "qasync-0.27.1-py3-none-any.whl", hash = "sha256:5d57335723bc7d9b328dadd8cb2ed7978640e4bf2da184889ce50ee3ad2602c7"}, - {file = "qasync-0.27.1.tar.gz", hash = "sha256:8dc768fd1ee5de1044c7c305eccf2d39d24d87803ea71189d4024fb475f4985f"}, -] - [[package]] name = "rapidfuzz" version = "3.13.0" @@ -9034,9 +8991,10 @@ requests = ">=2.0.1,<3.0.0" name = "requirements-parser" version = "0.13.0" description = "This is a small Python module for parsing Pip requirement files." -optional = false +optional = true python-versions = "<4.0,>=3.8" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "requirements_parser-0.13.0-py3-none-any.whl", hash = "sha256:2b3173faecf19ec5501971b7222d38f04cb45bb9d87d0ad629ca71e2e62ded14"}, {file = "requirements_parser-0.13.0.tar.gz", hash = "sha256:0843119ca2cb2331de4eb31b10d70462e39ace698fd660a915c247d2301a4418"}, @@ -9116,9 +9074,10 @@ jupyter = ["ipywidgets (>=7.5.1,<9)"] name = "rich-argparse" version = "1.7.1" description = "Rich help formatters for argparse and optparse" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "rich_argparse-1.7.1-py3-none-any.whl", hash = "sha256:a8650b42e4a4ff72127837632fba6b7da40784842f08d7395eb67a9cbd7b4bf9"}, {file = "rich_argparse-1.7.1.tar.gz", hash = "sha256:d7a493cde94043e41ea68fb43a74405fa178de981bf7b800f7a3bd02ac5c27be"}, @@ -9342,9 +9301,10 @@ files = [ name = "s3fs" version = "2025.3.2" description = "Convenient Filesystem interface over S3" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"aws\"" files = [ {file = "s3fs-2025.3.2-py3-none-any.whl", hash = "sha256:81eae3f37b4b04bcc08845d7bcc607c6ca45878813ef7e6a28d77b2688417130"}, {file = "s3fs-2025.3.2.tar.gz", hash = "sha256:6798f896ec76dd3bfd8beb89f0bb7c5263cb2760e038bae0978505cd172a307c"}, @@ -9366,9 +9326,10 @@ boto3 = ["aiobotocore[boto3] (>=2.5.4,<3.0.0)"] name = "s3transfer" version = "0.13.1" description = "An Amazon S3 Transfer Manager" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\"" files = [ {file = "s3transfer-0.13.1-py3-none-any.whl", hash = "sha256:a981aa7429be23fe6dfc13e80e4020057cbab622b08c0315288758d67cabc724"}, {file = "s3transfer-0.13.1.tar.gz", hash = "sha256:c3fdba22ba1bd367922f27ec8032d6a1cf5f10c934fb5d68cf60fd5a23d936cf"}, @@ -9614,9 +9575,10 @@ test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6 name = "semver" version = "3.0.4" description = "Python helper for Semantic Versioning (https://semver.org)" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "semver-3.0.4-py3-none-any.whl", hash = "sha256:9c824d87ba7f7ab4a1890799cec8596f15c1241cb473404ea1cb0c55e4b04746"}, {file = "semver-3.0.4.tar.gz", hash = "sha256:afc7d8c584a5ed0a11033af086e8af226a9c0b206f313e0301f8dd7b6b589602"}, @@ -9644,9 +9606,10 @@ win32 = ["pywin32 ; sys_platform == \"win32\""] name = "sentry-sdk" version = "2.35.1" description = "Python client for Sentry (https://sentry.io)" -optional = false +optional = true python-versions = ">=3.6" groups = ["main"] +markers = "extra == \"deepeval\" or extra == \"monitoring\"" files = [ {file = "sentry_sdk-2.35.1-py2.py3-none-any.whl", hash = "sha256:13b6d6cfdae65d61fe1396a061cf9113b20f0ec1bcb257f3826b88f01bb55720"}, {file = "sentry_sdk-2.35.1.tar.gz", hash = "sha256:241b41e059632fe1f7c54ae6e1b93af9456aebdfc297be9cf7ecfd6da5167e8e"}, @@ -9702,9 +9665,10 @@ unleash = ["UnleashClient (>=6.0.1)"] name = "setuptools" version = "80.9.0" description = "Easily download, build, install, upgrade, and uninstall Python packages" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"notebook\" or extra == \"dev\" or extra == \"llama-index\" or extra == \"deepeval\" or extra == \"dlt\"" files = [ {file = "setuptools-80.9.0-py3-none-any.whl", hash = "sha256:062d34222ad13e0cc312a4c02d73f059e86a4acbfbdea8f8f76b28c99f306922"}, {file = "setuptools-80.9.0.tar.gz", hash = "sha256:f36b47402ecde768dbfafc46e8e4207b4360c654f1f3bb84475f0a28628fb19c"}, @@ -9731,22 +9695,6 @@ files = [ {file = "shellingham-1.5.4.tar.gz", hash = "sha256:8dbca0739d487e5bd35ab3ca4b36e11c4078f3a234bfce294b0a0291363404de"}, ] -[[package]] -name = "shiboken6" -version = "6.9.2" -description = "Python/C++ bindings helper module" -optional = true -python-versions = "<3.14,>=3.9" -groups = ["main"] -markers = "extra == \"gui\"" -files = [ - {file = "shiboken6-6.9.2-cp39-abi3-macosx_12_0_universal2.whl", hash = "sha256:8bb1c4326330e53adeac98bfd9dcf57f5173a50318a180938dcc4825d9ca38da"}, - {file = "shiboken6-6.9.2-cp39-abi3-manylinux_2_28_x86_64.whl", hash = "sha256:3b54c0a12ea1b03b9dc5dcfb603c366e957dc75341bf7cb1cc436d0d848308ee"}, - {file = "shiboken6-6.9.2-cp39-abi3-manylinux_2_39_aarch64.whl", hash = "sha256:a5f5985938f5acb604c23536a0ff2efb3cccb77d23da91fbaff8fd8ded3dceb4"}, - {file = "shiboken6-6.9.2-cp39-abi3-win_amd64.whl", hash = "sha256:68c33d565cd4732be762d19ff67dfc53763256bac413d392aa8598b524980bc4"}, - {file = "shiboken6-6.9.2-cp39-abi3-win_arm64.whl", hash = "sha256:c5b827797b3d89d9b9a3753371ff533fcd4afc4531ca51a7c696952132098054"}, -] - [[package]] name = "sigtools" version = "4.0.1" @@ -9771,9 +9719,10 @@ tests = ["coverage", "mock", "repeated-test (>=2.2.1)", "sphinx"] name = "simplejson" version = "3.20.1" description = "Simple, fast, extensible JSON encoder/decoder for Python" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.5" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:f5272b5866b259fe6c33c4a8c5073bf8b359c3c97b70c298a2f09a69b52c7c41"}, {file = "simplejson-3.20.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:5c0de368f3052a59a1acf21f8b2dd28686a9e4eba2da7efae7ed9554cb31e7bc"}, @@ -9891,9 +9840,10 @@ files = [ name = "six" version = "1.17.0" description = "Python 2 and 3 compatibility utilities" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,>=2.7" groups = ["main"] +markers = "extra == \"neptune\" or extra == \"aws\" or extra == \"notebook\" or extra == \"dev\" or extra == \"deepeval\" or extra == \"posthog\" or extra == \"chromadb\" or extra == \"falkordb\" or extra == \"docs\" or extra == \"evals\" or extra == \"dlt\" or extra == \"visualization\"" files = [ {file = "six-1.17.0-py2.py3-none-any.whl", hash = "sha256:4721f391ed90541fddacab5acf947aa0d3dc7d27b2e1e8eda2be8970586c3274"}, {file = "six-1.17.0.tar.gz", hash = "sha256:ff70335d468e7eb6ec65b95b99d3a2836546063f63acc5171de367e834932a81"}, @@ -9903,9 +9853,10 @@ files = [ name = "smmap" version = "5.0.2" description = "A pure Python implementation of a sliding window memory map manager" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] +markers = "extra == \"dlt\" or extra == \"dev\"" files = [ {file = "smmap-5.0.2-py3-none-any.whl", hash = "sha256:b30115f0def7d7531d22a0fb6502488d879e75b260a9db4d0819cfb25403af5e"}, {file = "smmap-5.0.2.tar.gz", hash = "sha256:26ea65a03958fa0c8a1c7e8c7a58fdc77221b8910f6be2131affade476898ad5"}, @@ -10036,9 +9987,10 @@ sqlcipher = ["sqlcipher3_binary"] name = "sqlglot" version = "27.8.0" description = "An easily customizable SQL parser and transpiler" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dlt\"" files = [ {file = "sqlglot-27.8.0-py3-none-any.whl", hash = "sha256:3961277277bc5bae459762294e160b6b7ce998e7d016f5adf8311a1d50b7a1a7"}, {file = "sqlglot-27.8.0.tar.gz", hash = "sha256:026ca21be0106d23f67519d583a24131d27131ceb80b595efa2a59a2746f351f"}, @@ -10366,9 +10318,10 @@ files = [ name = "tomlkit" version = "0.13.3" description = "Style preserving TOML library" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"dlt\" or extra == \"dev\"" files = [ {file = "tomlkit-0.13.3-py3-none-any.whl", hash = "sha256:c89c649d79ee40629a9fda55f8ace8c6a1b42deb912b2a8fd8d942ddadb606b0"}, {file = "tomlkit-0.13.3.tar.gz", hash = "sha256:430cf247ee57df2b94ee3fbe588e71d362a941ebb545dec29b53961d61add2a1"}, @@ -10705,9 +10658,10 @@ typing-extensions = ">=4.12.0" name = "tzdata" version = "2025.2" description = "Provider of IANA time zone data" -optional = false +optional = true python-versions = ">=2" groups = ["main"] +markers = "extra == \"chromadb\" or extra == \"docs\" or extra == \"evals\" or extra == \"dlt\"" files = [ {file = "tzdata-2025.2-py2.py3-none-any.whl", hash = "sha256:1a403fada01ff9221ca8044d701868fa132215d84beb92242d9acd2147f667a8"}, {file = "tzdata-2025.2.tar.gz", hash = "sha256:b60a638fcc0daffadf82fe0f57e53d06bdec2f36c4df66280ae79bce6bd6f2b9"}, @@ -11288,10 +11242,10 @@ test = ["pytest (>=6.0.0)", "setuptools (>=65)"] name = "win-precise-time" version = "1.4.2" description = "" -optional = false +optional = true python-versions = ">=3.7" groups = ["main"] -markers = "os_name == \"nt\" and python_version <= \"3.12\"" +markers = "extra == \"dlt\" and os_name == \"nt\" and python_version <= \"3.12\"" files = [ {file = "win-precise-time-1.4.2.tar.gz", hash = "sha256:89274785cbc5f2997e01675206da3203835a442c60fd97798415c6b3c179c0b9"}, {file = "win_precise_time-1.4.2-cp310-cp310-win32.whl", hash = "sha256:7fa13a2247c2ef41cd5e9b930f40716eacc7fc1f079ea72853bd5613fe087a1a"}, @@ -11702,32 +11656,35 @@ cffi = ["cffi (>=1.17) ; python_version >= \"3.13\" and platform_python_implemen anthropic = ["anthropic"] api = ["gunicorn", "uvicorn", "websockets"] aws = ["s3fs"] +baml = ["baml-py"] chromadb = ["chromadb", "pypika"] codegraph = ["fastembed", "transformers", "tree-sitter", "tree-sitter-python"] debug = ["debugpy"] deepeval = ["deepeval"] dev = ["coverage", "deptry", "gitpython", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings", "mypy", "notebook", "pylint", "pytest", "pytest-asyncio", "pytest-cov", "ruff", "tweepy"] distributed = ["modal"] +dlt = ["dlt"] docs = ["unstructured"] -evals = ["gdown", "plotly"] +evals = ["gdown", "pandas", "plotly"] falkordb = ["falkordb"] gemini = ["google-generativeai"] graphiti = ["graphiti-core"] groq = ["groq"] -gui = ["pyside6", "qasync"] huggingface = ["transformers"] langchain = ["langchain_text_splitters", "langsmith"] llama-index = ["llama-index-core"] mistral = ["mistral-common"] +monitoring = ["langfuse", "sentry-sdk"] neo4j = ["neo4j"] neptune = ["langchain_aws"] notebook = ["notebook"] ollama = ["transformers"] -postgres = ["asyncpg", "pgvector", "psycopg2"] -postgres-binary = ["asyncpg", "pgvector", "psycopg2-binary"] +postgres = ["asyncpg", "pgvector", "psycopg2-binary"] +postgres-source = ["asyncpg", "pgvector", "psycopg2"] posthog = ["posthog"] +visualization = ["matplotlib", "networkx"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "7743005314483d6cc76febb7970c8af9a3d2a63e76247505e33b20fdc974aca1" +content-hash = "5468b51a59af0c5530d4f8c5a0180d5161a034538f3a9707a46a82b4abde2754" From 00c7dfae492509549b1c26cbf530736e30b776c4 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 19:43:34 +0200 Subject: [PATCH 08/71] added lancedb pandas removal --- pyproject.toml | 1 - 1 file changed, 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index b17b4893a..4c165a325 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ dependencies = [ "fastapi-users[sqlalchemy]>=14.0.1,<15.0.0", "structlog>=25.2.0,<26", "pympler>=1.1,<2.0.0", - "onnxruntime>=1.0.0,<2.0.0", "pylance>=0.22.0,<1.0.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows From 76b8e16bcb1abc424cd699453c2e8832d9825376 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 19:59:38 +0200 Subject: [PATCH 09/71] removed extra things --- .../data/utils/extract_keywords.py | 64 +++++++++---------- cognee/shared/utils.py | 45 +++++++------ pyproject.toml | 5 +- 3 files changed, 58 insertions(+), 56 deletions(-) diff --git a/cognee/infrastructure/data/utils/extract_keywords.py b/cognee/infrastructure/data/utils/extract_keywords.py index 8085459c9..811999618 100644 --- a/cognee/infrastructure/data/utils/extract_keywords.py +++ b/cognee/infrastructure/data/utils/extract_keywords.py @@ -1,48 +1,46 @@ -from sklearn.feature_extraction.text import TfidfVectorizer from cognee.infrastructure.data.exceptions.exceptions import KeywordExtractionError -from cognee.shared.utils import extract_pos_tags -def extract_keywords(text: str) -> list[str]: - """ - Extract keywords from the provided text string. +# def extract_keywords(text: str) -> list[str]: +# """ +# Extract keywords from the provided text string. - This function raises an KeyWordExtractionError if the input text is empty. It processes the - text to extract parts of speech, focusing on nouns, and uses TF-IDF to identify the most - relevant keywords based on their frequency. The function returns a list of up to 15 - keywords, each having more than 3 characters. +# This function raises an KeyWordExtractionError if the input text is empty. It processes the +# text to extract parts of speech, focusing on nouns, and uses TF-IDF to identify the most +# relevant keywords based on their frequency. The function returns a list of up to 15 +# keywords, each having more than 3 characters. - Parameters: - ----------- +# Parameters: +# ----------- - - text (str): The input text from which to extract keywords. +# - text (str): The input text from which to extract keywords. - Returns: - -------- +# Returns: +# -------- - - list[str]: A list of keywords extracted from the text, containing up to 15 nouns - with more than 3 characters. - """ - if len(text) == 0: - raise KeywordExtractionError() +# - list[str]: A list of keywords extracted from the text, containing up to 15 nouns +# with more than 3 characters. +# """ +# if len(text) == 0: +# raise KeywordExtractionError() - tags = extract_pos_tags(text) - nouns = [word for (word, tag) in tags if tag == "NN"] +# tags = extract_pos_tags(text) +# nouns = [word for (word, tag) in tags if tag == "NN"] - vectorizer = TfidfVectorizer() - tfidf = vectorizer.fit_transform(nouns) +# vectorizer = TfidfVectorizer() +# tfidf = vectorizer.fit_transform(nouns) - top_nouns = sorted( - vectorizer.vocabulary_, key=lambda x: tfidf[0, vectorizer.vocabulary_[x]], reverse=True - ) +# top_nouns = sorted( +# vectorizer.vocabulary_, key=lambda x: tfidf[0, vectorizer.vocabulary_[x]], reverse=True +# ) - keywords = [] +# keywords = [] - for word in top_nouns: - if len(word) > 3: - keywords.append(word) - if len(keywords) >= 15: - break +# for word in top_nouns: +# if len(word) > 3: +# keywords.append(word) +# if len(keywords) >= 15: +# break - return keywords +# return keywords diff --git a/cognee/shared/utils.py b/cognee/shared/utils.py index 22557d2ac..df141f2de 100644 --- a/cognee/shared/utils.py +++ b/cognee/shared/utils.py @@ -18,34 +18,41 @@ proxy_url = "https://test.prometh.ai" def get_entities(tagged_tokens): - import nltk - - nltk.download("maxent_ne_chunker", quiet=True) - - from nltk.chunk import ne_chunk - - return ne_chunk(tagged_tokens) + try: + import nltk + nltk.download("maxent_ne_chunker", quiet=True) + from nltk.chunk import ne_chunk + return ne_chunk(tagged_tokens) + except ImportError: + raise ImportError( + "NLTK is required for entity extraction. Install with 'pip install cognee[nlp]' to use this feature." + ) def extract_pos_tags(sentence): """Extract Part-of-Speech (POS) tags for words in a sentence.""" - import nltk + try: + import nltk - # Ensure that the necessary NLTK resources are downloaded - nltk.download("words", quiet=True) - nltk.download("punkt", quiet=True) - nltk.download("averaged_perceptron_tagger", quiet=True) + # Ensure that the necessary NLTK resources are downloaded + nltk.download("words", quiet=True) + nltk.download("punkt", quiet=True) + nltk.download("averaged_perceptron_tagger", quiet=True) - from nltk.tag import pos_tag - from nltk.tokenize import word_tokenize + from nltk.tag import pos_tag + from nltk.tokenize import word_tokenize - # Tokenize the sentence into words - tokens = word_tokenize(sentence) + # Tokenize the sentence into words + tokens = word_tokenize(sentence) - # Tag each word with its corresponding POS tag - pos_tags = pos_tag(tokens) + # Tag each word with its corresponding POS tag + pos_tags = pos_tag(tokens) - return pos_tags + return pos_tags + except ImportError: + raise ImportError( + "NLTK is required for POS tagging. Install with 'pip install cognee[nlp]' to use this feature." + ) def get_anonymous_id(): diff --git a/pyproject.toml b/pyproject.toml index 4c165a325..e71393b21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -25,7 +25,6 @@ dependencies = [ "pydantic>=2.10.5,<3.0.0", "pydantic-settings>=2.2.1,<3", "typing_extensions>=4.12.2,<5.0.0", - "nltk>=3.9.1,<4.0.0", "numpy>=1.26.4, <=4.0.0", "sqlalchemy>=2.0.39,<3.0.0", "aiosqlite>=0.20.0,<1.0.0", @@ -40,14 +39,11 @@ dependencies = [ "jinja2>=3.1.3,<4", "lancedb>=0.24.0,<1.0.0", "alembic>=1.13.3,<2", - "pre-commit>=4.0.1,<5", - "scikit-learn>=1.6.1,<2", "limits>=4.4.1,<5", "fastapi>=0.115.7,<1.0.0", "python-multipart>=0.0.20,<1.0.0", "fastapi-users[sqlalchemy]>=14.0.1,<15.0.0", "structlog>=25.2.0,<26", - "pympler>=1.1,<2.0.0", "pylance>=0.22.0,<1.0.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows @@ -135,6 +131,7 @@ dev = [ debug = ["debugpy>=1.8.9,<2.0.0"] visualization = ["networkx>=3.4.2,<4", "matplotlib>=3.8.3,<4"] monitoring = ["sentry-sdk[fastapi]>=2.9.0,<3", "langfuse>=2.32.0,<3"] +nlp = ["nltk>=3.9.1,<4.0.0"] [project.urls] Homepage = "https://www.cognee.ai" From 861ae205d23d5332de2c440920205c4ab0ab6de7 Mon Sep 17 00:00:00 2001 From: vasilije Date: Wed, 27 Aug 2025 21:12:45 +0200 Subject: [PATCH 10/71] removed extra things --- cognee/modules/ingestion/data_types/TextData.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cognee/modules/ingestion/data_types/TextData.py b/cognee/modules/ingestion/data_types/TextData.py index 7c2364a5a..90d5335b5 100644 --- a/cognee/modules/ingestion/data_types/TextData.py +++ b/cognee/modules/ingestion/data_types/TextData.py @@ -1,7 +1,6 @@ from typing import BinaryIO from contextlib import asynccontextmanager import hashlib -from cognee.infrastructure.data.utils.extract_keywords import extract_keywords from .IngestionData import IngestionData From 8f9e289a83c15e2969aed0919ebb1fb83ed6e3b4 Mon Sep 17 00:00:00 2001 From: vasilije Date: Thu, 28 Aug 2025 08:10:25 +0200 Subject: [PATCH 11/71] added baml test fix and format --- .github/workflows/basic_tests.yml | 3 +++ cognee/infrastructure/data/utils/extract_keywords.py | 1 - cognee/shared/utils.py | 2 ++ 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/.github/workflows/basic_tests.yml b/.github/workflows/basic_tests.yml index e2264da3d..b6da0d295 100644 --- a/.github/workflows/basic_tests.yml +++ b/.github/workflows/basic_tests.yml @@ -189,6 +189,9 @@ jobs: with: python-version: ${{ inputs.python-version }} + - name: Install BAML Dependencies + run: uv add "cognee[baml]" + - name: Run Simple Examples run: uv run python ./examples/python/simple_example.py diff --git a/cognee/infrastructure/data/utils/extract_keywords.py b/cognee/infrastructure/data/utils/extract_keywords.py index 811999618..c3e47c4c8 100644 --- a/cognee/infrastructure/data/utils/extract_keywords.py +++ b/cognee/infrastructure/data/utils/extract_keywords.py @@ -1,4 +1,3 @@ - from cognee.infrastructure.data.exceptions.exceptions import KeywordExtractionError diff --git a/cognee/shared/utils.py b/cognee/shared/utils.py index df141f2de..16d0961cc 100644 --- a/cognee/shared/utils.py +++ b/cognee/shared/utils.py @@ -20,8 +20,10 @@ proxy_url = "https://test.prometh.ai" def get_entities(tagged_tokens): try: import nltk + nltk.download("maxent_ne_chunker", quiet=True) from nltk.chunk import ne_chunk + return ne_chunk(tagged_tokens) except ImportError: raise ImportError( From 0fd1dae448a29f7e777229963d6e31d4a3e4a92b Mon Sep 17 00:00:00 2001 From: vasilije Date: Tue, 2 Sep 2025 09:31:28 +0200 Subject: [PATCH 12/71] reverted some changes and remove some upper bounds --- pyproject.toml | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index e71393b21..6667819c8 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -20,7 +20,7 @@ classifiers = [ "Operating System :: Microsoft :: Windows", ] dependencies = [ - "openai>=1.80.1,<1.99.9", + "openai>=1.80.1", "python-dotenv>=1.0.1,<2.0.0", "pydantic>=2.10.5,<3.0.0", "pydantic-settings>=2.2.1,<3", @@ -29,7 +29,7 @@ dependencies = [ "sqlalchemy>=2.0.39,<3.0.0", "aiosqlite>=0.20.0,<1.0.0", "tiktoken>=0.8.0,<1.0.0", - "litellm>=1.71.0, <2.0.0", + "litellm>=1.76.0", "instructor>=1.9.1,<2.0.0", "filetype>=1.2.0,<2.0.0", "aiohttp>=3.11.14,<4.0.0", @@ -47,6 +47,10 @@ dependencies = [ "pylance>=0.22.0,<1.0.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows + "fastembed<=0.6.0 ", + "networkx>=3.4.2,<4", + "matplotlib>=3.8.3,<4" + ] [project.optional-dependencies] From aa445cfaa7828863d35287c99f7bd2178a2bea70 Mon Sep 17 00:00:00 2001 From: vasilije Date: Sun, 7 Sep 2025 15:56:11 -0700 Subject: [PATCH 13/71] addressed issues --- cognee/eval_framework/modal_eval_dashboard.py | 2 +- .../data/utils/extract_keywords.py | 45 ------------------- cognee/infrastructure/llm/config.py | 7 +++ .../baml_src/extraction/extract_summary.py | 10 ----- .../knowledge_graph/extract_content_graph.py | 5 --- cognee/shared/utils.py | 40 ----------------- pyproject.toml | 11 ++--- 7 files changed, 11 insertions(+), 109 deletions(-) delete mode 100644 cognee/infrastructure/data/utils/extract_keywords.py diff --git a/cognee/eval_framework/modal_eval_dashboard.py b/cognee/eval_framework/modal_eval_dashboard.py index 9ff6f543c..e2ed8e453 100644 --- a/cognee/eval_framework/modal_eval_dashboard.py +++ b/cognee/eval_framework/modal_eval_dashboard.py @@ -16,7 +16,7 @@ metrics_volume = modal.Volume.from_name("evaluation_dashboard_results", create_i image = ( modal.Image.debian_slim(python_version="3.11") - .pip_install("streamlit", "plotly") + .pip_install("streamlit", "pandas", "plotly") .add_local_file(__file__, "/root/serve_dashboard.py") ) diff --git a/cognee/infrastructure/data/utils/extract_keywords.py b/cognee/infrastructure/data/utils/extract_keywords.py deleted file mode 100644 index c3e47c4c8..000000000 --- a/cognee/infrastructure/data/utils/extract_keywords.py +++ /dev/null @@ -1,45 +0,0 @@ -from cognee.infrastructure.data.exceptions.exceptions import KeywordExtractionError - - -# def extract_keywords(text: str) -> list[str]: -# """ -# Extract keywords from the provided text string. - -# This function raises an KeyWordExtractionError if the input text is empty. It processes the -# text to extract parts of speech, focusing on nouns, and uses TF-IDF to identify the most -# relevant keywords based on their frequency. The function returns a list of up to 15 -# keywords, each having more than 3 characters. - -# Parameters: -# ----------- - -# - text (str): The input text from which to extract keywords. - -# Returns: -# -------- - -# - list[str]: A list of keywords extracted from the text, containing up to 15 nouns -# with more than 3 characters. -# """ -# if len(text) == 0: -# raise KeywordExtractionError() - -# tags = extract_pos_tags(text) -# nouns = [word for (word, tag) in tags if tag == "NN"] - -# vectorizer = TfidfVectorizer() -# tfidf = vectorizer.fit_transform(nouns) - -# top_nouns = sorted( -# vectorizer.vocabulary_, key=lambda x: tfidf[0, vectorizer.vocabulary_[x]], reverse=True -# ) - -# keywords = [] - -# for word in top_nouns: -# if len(word) > 3: -# keywords.append(word) -# if len(keywords) >= 15: -# break - -# return keywords diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index c5240935c..9e5120456 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -75,6 +75,13 @@ class LLMConfig(BaseSettings): def model_post_init(self, __context) -> None: """Initialize the BAML registry after the model is created.""" + # Check if BAML is selected as structured output framework but not available + if self.structured_output_framework == "baml" and ClientRegistry is None: + raise ImportError( + "BAML is selected as structured output framework but not available. " + "Please install with 'pip install cognee[baml]' to use BAML extraction features." + ) + if ClientRegistry is not None: self.baml_registry = ClientRegistry() self.baml_registry.add_llm_client( diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py index 89889d294..697a52a45 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/extract_summary.py @@ -37,11 +37,6 @@ async def extract_summary(content: str, response_model: Type[BaseModel]): """ config = get_llm_config() - if config.baml_registry is None: - raise ImportError( - "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." - ) - # Use BAML's SummarizeContent function summary_result = await b.SummarizeContent( content, baml_options={"client_registry": config.baml_registry} @@ -82,11 +77,6 @@ async def extract_code_summary(content: str): try: config = get_llm_config() - if config.baml_registry is None: - raise ImportError( - "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." - ) - result = await b.SummarizeCode( content, baml_options={"client_registry": config.baml_registry} ) diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py index f87d87d1b..abff07e09 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/knowledge_graph/extract_content_graph.py @@ -16,11 +16,6 @@ async def extract_content_graph( get_logger(level="INFO") - if config.baml_registry is None: - raise ImportError( - "BAML is not available. Please install with 'pip install cognee[baml]' to use BAML extraction features." - ) - # if response_model: # # tb = TypeBuilder() # # country = tb.union \ diff --git a/cognee/shared/utils.py b/cognee/shared/utils.py index 16d0961cc..3071a82cb 100644 --- a/cognee/shared/utils.py +++ b/cognee/shared/utils.py @@ -17,46 +17,6 @@ from cognee.infrastructure.databases.graph import get_graph_engine proxy_url = "https://test.prometh.ai" -def get_entities(tagged_tokens): - try: - import nltk - - nltk.download("maxent_ne_chunker", quiet=True) - from nltk.chunk import ne_chunk - - return ne_chunk(tagged_tokens) - except ImportError: - raise ImportError( - "NLTK is required for entity extraction. Install with 'pip install cognee[nlp]' to use this feature." - ) - - -def extract_pos_tags(sentence): - """Extract Part-of-Speech (POS) tags for words in a sentence.""" - try: - import nltk - - # Ensure that the necessary NLTK resources are downloaded - nltk.download("words", quiet=True) - nltk.download("punkt", quiet=True) - nltk.download("averaged_perceptron_tagger", quiet=True) - - from nltk.tag import pos_tag - from nltk.tokenize import word_tokenize - - # Tokenize the sentence into words - tokens = word_tokenize(sentence) - - # Tag each word with its corresponding POS tag - pos_tags = pos_tag(tokens) - - return pos_tags - except ImportError: - raise ImportError( - "NLTK is required for POS tagging. Install with 'pip install cognee[nlp]' to use this feature." - ) - - def get_anonymous_id(): """Creates or reads a anonymous user id""" tracking_id = os.getenv("TRACKING_ID", None) diff --git a/pyproject.toml b/pyproject.toml index 6667819c8..2a4c36132 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,8 @@ dependencies = [ "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows "fastembed<=0.6.0 ", "networkx>=3.4.2,<4", - "matplotlib>=3.8.3,<4" + "matplotlib>=3.8.3,<4", + "baml-py>=0.201.0" ] @@ -66,18 +67,12 @@ distributed = [ # Database backends neo4j = ["neo4j>=5.28.0,<6"] neptune = ["langchain_aws>=0.2.22"] -# PostgreSQL support (binary - no compilation required) postgres = [ + "psycopg2>=2.9.10,<3", "psycopg2-binary>=2.9.10,<3.0.0", # Pre-compiled binary, no PostgreSQL headers needed "pgvector>=0.3.5,<0.4", "asyncpg>=0.30.0,<1.0.0", ] -# PostgreSQL support (source - requires PostgreSQL development headers) -postgres-source = [ - "psycopg2>=2.9.10,<3 ; platform_system != 'Windows'", # Requires libpq-dev, build tools - "pgvector>=0.3.5,<0.4", - "asyncpg>=0.30.0,<1.0.0", -] notebook = ["notebook>=7.1.0,<8"] langchain = [ "langsmith>=0.2.3,<1.0.0", From 356e685563001bdd90aca9529deb36c0d13f70a6 Mon Sep 17 00:00:00 2001 From: vasilije Date: Sun, 7 Sep 2025 16:03:39 -0700 Subject: [PATCH 14/71] adding info --- cognee/infrastructure/llm/config.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index 9e5120456..4281921f7 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -1,5 +1,5 @@ import os -from typing import Optional, ClassVar +from typing import Optional, ClassVar, Any from functools import lru_cache from pydantic_settings import BaseSettings, SettingsConfigDict from pydantic import model_validator @@ -69,7 +69,7 @@ class LLMConfig(BaseSettings): fallback_endpoint: str = "" fallback_model: str = "" - baml_registry: ClassVar = None + baml_registry: Optional[Any] = None model_config = SettingsConfigDict(env_file=".env", extra="allow") From bb8b47bf344ff65b8e3f7e67010d05f3f3ba4841 Mon Sep 17 00:00:00 2001 From: vasilije Date: Sun, 7 Sep 2025 16:37:39 -0700 Subject: [PATCH 15/71] add fix --- .github/workflows/basic_tests.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/basic_tests.yml b/.github/workflows/basic_tests.yml index b6da0d295..bfe15a6cf 100644 --- a/.github/workflows/basic_tests.yml +++ b/.github/workflows/basic_tests.yml @@ -190,7 +190,7 @@ jobs: python-version: ${{ inputs.python-version }} - name: Install BAML Dependencies - run: uv add "cognee[baml]" + run: uv add "baml-py>=0.201.0,<0.202.0" - name: Run Simple Examples run: uv run python ./examples/python/simple_example.py From b230247c25ceb9812d9a0f1b694109158ab6e697 Mon Sep 17 00:00:00 2001 From: vasilije Date: Sun, 7 Sep 2025 16:50:39 -0700 Subject: [PATCH 16/71] added s3 as optional --- .../files/storage/S3FileStorage.py | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/cognee/infrastructure/files/storage/S3FileStorage.py b/cognee/infrastructure/files/storage/S3FileStorage.py index 6218d6240..0b95ca0cf 100644 --- a/cognee/infrastructure/files/storage/S3FileStorage.py +++ b/cognee/infrastructure/files/storage/S3FileStorage.py @@ -1,6 +1,5 @@ import os -import s3fs -from typing import BinaryIO, Union +from typing import BinaryIO, Union, TYPE_CHECKING from contextlib import asynccontextmanager from cognee.infrastructure.files.storage.s3_config import get_s3_config @@ -8,17 +7,27 @@ from cognee.infrastructure.utils.run_async import run_async from cognee.infrastructure.files.storage.FileBufferedReader import FileBufferedReader from .storage import Storage +if TYPE_CHECKING: + import s3fs + class S3FileStorage(Storage): """ - Manage local file storage operations such as storing, retrieving, and managing files on - the filesystem. + Manage S3 file storage operations such as storing, retrieving, and managing files on + S3-compatible storage. """ storage_path: str - s3: s3fs.S3FileSystem + s3: "s3fs.S3FileSystem" def __init__(self, storage_path: str): + try: + import s3fs + except ImportError: + raise ImportError( + "s3fs is required for S3FileStorage. Install it with: pip install cognee[aws]" + ) + self.storage_path = storage_path s3_config = get_s3_config() if s3_config.aws_access_key_id is not None and s3_config.aws_secret_access_key is not None: From 5fa5bfa68211f645bef20de54e9e73e5408a9c19 Mon Sep 17 00:00:00 2001 From: Mohammad Date: Wed, 10 Sep 2025 14:11:00 +0200 Subject: [PATCH 17/71] feat: add support for AWS session token in S3 configuration --- cognee/infrastructure/files/storage/S3FileStorage.py | 8 +++++++- cognee/infrastructure/files/storage/s3_config.py | 2 +- cognee/tasks/ingestion/resolve_data_directories.py | 2 +- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/cognee/infrastructure/files/storage/S3FileStorage.py b/cognee/infrastructure/files/storage/S3FileStorage.py index 7c5a1033c..a0d611241 100644 --- a/cognee/infrastructure/files/storage/S3FileStorage.py +++ b/cognee/infrastructure/files/storage/S3FileStorage.py @@ -21,10 +21,11 @@ class S3FileStorage(Storage): def __init__(self, storage_path: str): self.storage_path = storage_path s3_config = get_s3_config() - if s3_config.aws_access_key_id is not None and s3_config.aws_secret_access_key is not None: + if s3_config.aws_access_key_id is not None and s3_config.aws_secret_access_key is not None and s3_config.aws_session_token is not None: self.s3 = s3fs.S3FileSystem( key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key, + token=s3_config.aws_session_token, anon=False, endpoint_url=s3_config.aws_endpoint_url, client_kwargs={"region_name": s3_config.aws_region}, @@ -146,6 +147,11 @@ class S3FileStorage(Storage): self.s3.isfile, os.path.join(self.storage_path.replace("s3://", ""), file_path) ) + async def get_size(self, file_path: str) -> int: + return await run_async( + self.s3.size, os.path.join(self.storage_path.replace("s3://", ""), file_path) + ) + async def ensure_directory_exists(self, directory_path: str = ""): """ Ensure that the specified directory exists, creating it if necessary. diff --git a/cognee/infrastructure/files/storage/s3_config.py b/cognee/infrastructure/files/storage/s3_config.py index 0b9372b7e..3b59bcd57 100644 --- a/cognee/infrastructure/files/storage/s3_config.py +++ b/cognee/infrastructure/files/storage/s3_config.py @@ -8,9 +8,9 @@ class S3Config(BaseSettings): aws_endpoint_url: Optional[str] = None aws_access_key_id: Optional[str] = None aws_secret_access_key: Optional[str] = None + aws_session_token: Optional[str] = None model_config = SettingsConfigDict(env_file=".env", extra="allow") - @lru_cache def get_s3_config(): return S3Config() diff --git a/cognee/tasks/ingestion/resolve_data_directories.py b/cognee/tasks/ingestion/resolve_data_directories.py index 1d3124a0c..cbd979e16 100644 --- a/cognee/tasks/ingestion/resolve_data_directories.py +++ b/cognee/tasks/ingestion/resolve_data_directories.py @@ -32,7 +32,7 @@ async def resolve_data_directories( import s3fs fs = s3fs.S3FileSystem( - key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key, anon=False + key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key,token=s3_config.aws_session_token, anon=False ) for item in data: From e2ed2793140a6993d500f823bf656f5ba93af6cd Mon Sep 17 00:00:00 2001 From: Mohammad Date: Wed, 10 Sep 2025 14:14:22 +0200 Subject: [PATCH 18/71] feat: add support for AWS session token in S3 configuration --- cognee/infrastructure/files/storage/s3_config.py | 1 + 1 file changed, 1 insertion(+) diff --git a/cognee/infrastructure/files/storage/s3_config.py b/cognee/infrastructure/files/storage/s3_config.py index 3b59bcd57..cefe5cd2f 100644 --- a/cognee/infrastructure/files/storage/s3_config.py +++ b/cognee/infrastructure/files/storage/s3_config.py @@ -11,6 +11,7 @@ class S3Config(BaseSettings): aws_session_token: Optional[str] = None model_config = SettingsConfigDict(env_file=".env", extra="allow") + @lru_cache def get_s3_config(): return S3Config() From a0c951336e22a6ee14036c3e51527e2b1723f9ed Mon Sep 17 00:00:00 2001 From: Mohammad Date: Wed, 10 Sep 2025 14:20:42 +0200 Subject: [PATCH 19/71] feat: add support for AWS session token in S3 configuration --- cognee/infrastructure/files/storage/S3FileStorage.py | 6 +++++- cognee/tasks/ingestion/resolve_data_directories.py | 5 ++++- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/cognee/infrastructure/files/storage/S3FileStorage.py b/cognee/infrastructure/files/storage/S3FileStorage.py index a0d611241..078d5fe2a 100644 --- a/cognee/infrastructure/files/storage/S3FileStorage.py +++ b/cognee/infrastructure/files/storage/S3FileStorage.py @@ -21,7 +21,11 @@ class S3FileStorage(Storage): def __init__(self, storage_path: str): self.storage_path = storage_path s3_config = get_s3_config() - if s3_config.aws_access_key_id is not None and s3_config.aws_secret_access_key is not None and s3_config.aws_session_token is not None: + if ( + s3_config.aws_access_key_id is not None + and s3_config.aws_secret_access_key is not None + and s3_config.aws_session_token is not None + ): self.s3 = s3fs.S3FileSystem( key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key, diff --git a/cognee/tasks/ingestion/resolve_data_directories.py b/cognee/tasks/ingestion/resolve_data_directories.py index cbd979e16..aa2f95303 100644 --- a/cognee/tasks/ingestion/resolve_data_directories.py +++ b/cognee/tasks/ingestion/resolve_data_directories.py @@ -32,7 +32,10 @@ async def resolve_data_directories( import s3fs fs = s3fs.S3FileSystem( - key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key,token=s3_config.aws_session_token, anon=False + key=s3_config.aws_access_key_id, + secret=s3_config.aws_secret_access_key, + token=s3_config.aws_session_token, + anon=False, ) for item in data: From 8ad3ab23285a2865a0e1455081a5ece5e8104c7a Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Wed, 10 Sep 2025 15:06:37 +0200 Subject: [PATCH 20/71] fix: Allow S3 usage without token --- .env.template | 10 ++++++++++ cognee/infrastructure/files/storage/S3FileStorage.py | 6 +----- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/.env.template b/.env.template index 28980de74..b90ad7525 100644 --- a/.env.template +++ b/.env.template @@ -155,6 +155,16 @@ LITELLM_LOG="ERROR" # DEFAULT_USER_EMAIL="" # DEFAULT_USER_PASSWORD="" +################################################################################ +# 📂 AWS Settings +################################################################################ + +#AWS_REGION="" +#AWS_ENDPOINT_URL="" +#AWS_ACCESS_KEY_ID="" +#AWS_SECRET_ACCESS_KEY="" +#AWS_SESSION_TOKEN="" + ------------------------------- END OF POSSIBLE SETTINGS ------------------------------- diff --git a/cognee/infrastructure/files/storage/S3FileStorage.py b/cognee/infrastructure/files/storage/S3FileStorage.py index 078d5fe2a..4284dcac2 100644 --- a/cognee/infrastructure/files/storage/S3FileStorage.py +++ b/cognee/infrastructure/files/storage/S3FileStorage.py @@ -21,11 +21,7 @@ class S3FileStorage(Storage): def __init__(self, storage_path: str): self.storage_path = storage_path s3_config = get_s3_config() - if ( - s3_config.aws_access_key_id is not None - and s3_config.aws_secret_access_key is not None - and s3_config.aws_session_token is not None - ): + if s3_config.aws_access_key_id is not None and s3_config.aws_secret_access_key is not None: self.s3 = s3fs.S3FileSystem( key=s3_config.aws_access_key_id, secret=s3_config.aws_secret_access_key, From afa47c28b02286a834301f73e0a9873ae037de01 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Tue, 23 Sep 2025 13:41:12 +0200 Subject: [PATCH 21/71] fix: Resolve issue with only_context --- .../methods/no_access_control_search.py | 2 +- cognee/modules/search/methods/search.py | 37 +++++++++++++------ 2 files changed, 27 insertions(+), 12 deletions(-) diff --git a/cognee/modules/search/methods/no_access_control_search.py b/cognee/modules/search/methods/no_access_control_search.py index bb3eaba42..a93fce067 100644 --- a/cognee/modules/search/methods/no_access_control_search.py +++ b/cognee/modules/search/methods/no_access_control_search.py @@ -35,7 +35,7 @@ async def no_access_control_search( [get_completion, get_context] = search_tools if only_context: - return await get_context(query_text) + return None, await get_context(query_text), [] context = await get_context(query_text) result = await get_completion(query_text, context) diff --git a/cognee/modules/search/methods/search.py b/cognee/modules/search/methods/search.py index 65efafb4c..8bcef815f 100644 --- a/cognee/modules/search/methods/search.py +++ b/cognee/modules/search/methods/search.py @@ -143,20 +143,35 @@ async def search( context = prepared_search_results["context"] datasets = prepared_search_results["datasets"] - return_value.append( - { - "search_result": [result] if result else None, - "dataset_id": datasets[0].id, - "dataset_name": datasets[0].name, - "graphs": graphs, - } - ) + if only_context: + return_value.append( + { + "search_result": [context] if context else None, + "dataset_id": datasets[0].id, + "dataset_name": datasets[0].name, + "graphs": graphs, + } + ) + else: + return_value.append( + { + "search_result": [result] if result else None, + "dataset_id": datasets[0].id, + "dataset_name": datasets[0].name, + "graphs": graphs, + } + ) return return_value else: return_value = [] - for search_result in search_results: - result, context, datasets = search_result - return_value.append(result) + if only_context: + for search_result in search_results: + prepared_search_results = await prepare_search_result(search_result) + return_value.append(prepared_search_results["context"]) + else: + for search_result in search_results: + result, context, datasets = search_result + return_value.append(result) # For maintaining backwards compatibility if len(return_value) == 1 and isinstance(return_value[0], list): return return_value[0] From a9c507b36eca10903359c2f8659f83304739f0d0 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Tue, 23 Sep 2025 18:43:05 +0200 Subject: [PATCH 22/71] fix: Remove creation of default user during search --- .../TripletSearchContextProvider.py | 5 +---- .../modules/retrieval/graph_completion_retriever.py | 3 --- .../retrieval/utils/brute_force_triplet_search.py | 13 ++----------- examples/python/graphiti_example.py | 1 - 4 files changed, 3 insertions(+), 19 deletions(-) diff --git a/cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py b/cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py index b539055fa..6cdd57eec 100644 --- a/cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py +++ b/cognee/modules/retrieval/context_providers/TripletSearchContextProvider.py @@ -42,14 +42,12 @@ class TripletSearchContextProvider(BaseContextProvider): self, entities: List[DataPoint], query: str, - user: User, memory_fragment: CogneeGraph, ) -> List: """Creates search tasks for valid entities.""" tasks = [ brute_force_triplet_search( query=f"{entity_text} {query}", - user=user, top_k=self.top_k, collections=self.collections, properties_to_project=self.properties_to_project, @@ -84,9 +82,8 @@ class TripletSearchContextProvider(BaseContextProvider): if not entities: return "No entities provided for context search." - user = await get_default_user() memory_fragment = await get_memory_fragment(self.properties_to_project) - search_tasks = self._get_search_tasks(entities, query, user, memory_fragment) + search_tasks = self._get_search_tasks(entities, query, memory_fragment) if not search_tasks: return "No valid entities found for context search." diff --git a/cognee/modules/retrieval/graph_completion_retriever.py b/cognee/modules/retrieval/graph_completion_retriever.py index cd4944ca9..1772c6300 100644 --- a/cognee/modules/retrieval/graph_completion_retriever.py +++ b/cognee/modules/retrieval/graph_completion_retriever.py @@ -93,11 +93,8 @@ class GraphCompletionRetriever(BaseGraphRetriever): for field_name in index_fields: vector_index_collections.append(f"{subclass.__name__}_{field_name}") - user = await get_default_user() - found_triplets = await brute_force_triplet_search( query, - user=user, top_k=self.top_k, collections=vector_index_collections or None, node_type=self.node_type, diff --git a/cognee/modules/retrieval/utils/brute_force_triplet_search.py b/cognee/modules/retrieval/utils/brute_force_triplet_search.py index aa3233776..172c45d6d 100644 --- a/cognee/modules/retrieval/utils/brute_force_triplet_search.py +++ b/cognee/modules/retrieval/utils/brute_force_triplet_search.py @@ -89,7 +89,6 @@ async def get_memory_fragment( async def brute_force_triplet_search( query: str, - user: User, top_k: int = 5, collections: Optional[List[str]] = None, properties_to_project: Optional[List[str]] = None, @@ -102,7 +101,6 @@ async def brute_force_triplet_search( Args: query (str): The search query. - user (User): The user performing the search. top_k (int): The number of top results to retrieve. collections (Optional[List[str]]): List of collections to query. properties_to_project (Optional[List[str]]): List of properties to project. @@ -139,8 +137,6 @@ async def brute_force_triplet_search( query_vector = (await vector_engine.embedding_engine.embed_text([query]))[0] - send_telemetry("cognee.brute_force_triplet_search EXECUTION STARTED", user.id) - async def search_in_collection(collection_name: str): try: return await vector_engine.search( @@ -176,20 +172,15 @@ async def brute_force_triplet_search( results = await memory_fragment.calculate_top_triplet_importances(k=top_k) - send_telemetry("cognee.brute_force_triplet_search EXECUTION COMPLETED", user.id) - return results except CollectionNotFoundError: return [] except Exception as error: logger.error( - "Error during brute force search for user: %s, query: %s. Error: %s", - user.id, + "Error during brute force search for query: %s. Error: %s", query, error, ) - send_telemetry( - "cognee.brute_force_triplet_search EXECUTION FAILED", user.id, {"error": str(error)} - ) + send_telemetry("cognee.brute_force_triplet_search EXECUTION FAILED", {"error": str(error)}) raise error diff --git a/examples/python/graphiti_example.py b/examples/python/graphiti_example.py index f3bd86847..ece9c452b 100644 --- a/examples/python/graphiti_example.py +++ b/examples/python/graphiti_example.py @@ -48,7 +48,6 @@ async def main(): query = "When was Kamala Harris in office?" triplets = await brute_force_triplet_search( query=query, - user=user, top_k=3, collections=["graphitinode_content", "graphitinode_name", "graphitinode_summary"], ) From 9715c0106eda5c9082aa6f5d56087ea3ef94a10f Mon Sep 17 00:00:00 2001 From: Boris Arzentar Date: Wed, 24 Sep 2025 10:49:40 +0200 Subject: [PATCH 23/71] fix: add env variable for changing frontend app url --- .env.template | 9 ++++++++- cognee/api/client.py | 2 +- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.env.template b/.env.template index ddcd41a6c..f3168e6e2 100644 --- a/.env.template +++ b/.env.template @@ -176,7 +176,14 @@ ENABLE_BACKEND_ACCESS_CONTROL=False # Cognee Cloud API settings for syncing data to/from cloud infrastructure COGNEE_CLOUD_API_URL="http://localhost:8001" -COGNEE_CLOUD_AUTH_TOKEN="your-auth-token" +COGNEE_CLOUD_AUTH_TOKEN="your-api-key" + +################################################################################ +# UI Settings +################################################################################ + +# URL where the frontend is served, defaults to http://localhost:3000 +UI_APP_URL=http://localhost:3000 ################################################################################ # 🛠️ DEV Settings diff --git a/cognee/api/client.py b/cognee/api/client.py index 7d5f48672..5fec00c85 100644 --- a/cognee/api/client.py +++ b/cognee/api/client.py @@ -81,7 +81,7 @@ if CORS_ALLOWED_ORIGINS: ] else: allowed_origins = [ - "http://localhost:3000", + os.getenv("UI_APP_URL", "http://localhost:3000"), ] # Block all except explicitly set origins app.add_middleware( From d2d0d0de4ed65f671f11d999396b4f9f093e622c Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 13:32:09 +0200 Subject: [PATCH 24/71] refactor: install cognee defined baml version for CI/CD --- .github/actions/cognee_setup/action.yml | 4 ++-- .github/workflows/basic_tests.yml | 3 --- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.github/actions/cognee_setup/action.yml b/.github/actions/cognee_setup/action.yml index 9ae669b53..77c5b3b1f 100644 --- a/.github/actions/cognee_setup/action.yml +++ b/.github/actions/cognee_setup/action.yml @@ -24,7 +24,7 @@ runs: uses: astral-sh/setup-uv@v4 with: enable-cache: true - + - name: Rebuild uv lockfile shell: bash run: | @@ -41,4 +41,4 @@ runs: EXTRA_ARGS="$EXTRA_ARGS --extra $extra" done fi - uv sync --extra api --extra docs --extra evals --extra gemini --extra codegraph --extra ollama --extra dev --extra neo4j $EXTRA_ARGS + uv sync --extra api --extra docs --extra evals --extra gemini --extra codegraph --extra ollama --extra dev --extra baml --extra neo4j $EXTRA_ARGS diff --git a/.github/workflows/basic_tests.yml b/.github/workflows/basic_tests.yml index bfe15a6cf..e2264da3d 100644 --- a/.github/workflows/basic_tests.yml +++ b/.github/workflows/basic_tests.yml @@ -189,9 +189,6 @@ jobs: with: python-version: ${{ inputs.python-version }} - - name: Install BAML Dependencies - run: uv add "baml-py>=0.201.0,<0.202.0" - - name: Run Simple Examples run: uv run python ./examples/python/simple_example.py From ca2e63bd84ed9c6acb1234f45785a78385ced467 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 13:49:04 +0200 Subject: [PATCH 25/71] refactor: Move postgres handling to database creation time --- .../databases/vector/create_vector_engine.py | 7 +++++- .../vector/pgvector/PGVectorAdapter.py | 24 +++---------------- cognee/infrastructure/llm/config.py | 6 ++--- .../extraction/acreate_structured_output.py | 3 ++- 4 files changed, 14 insertions(+), 26 deletions(-) diff --git a/cognee/infrastructure/databases/vector/create_vector_engine.py b/cognee/infrastructure/databases/vector/create_vector_engine.py index 77bf7d83f..9432cb296 100644 --- a/cognee/infrastructure/databases/vector/create_vector_engine.py +++ b/cognee/infrastructure/databases/vector/create_vector_engine.py @@ -66,7 +66,12 @@ def create_vector_engine( f"postgresql+asyncpg://{db_username}:{db_password}@{db_host}:{db_port}/{db_name}" ) - from .pgvector.PGVectorAdapter import PGVectorAdapter + try: + from .pgvector.PGVectorAdapter import PGVectorAdapter + except ImportError: + raise ImportError( + "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PGVector functionality." + ) return PGVectorAdapter( connection_string, diff --git a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py index b2e2bf8c7..d20d7d519 100644 --- a/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py +++ b/cognee/infrastructure/databases/vector/pgvector/PGVectorAdapter.py @@ -7,20 +7,7 @@ from sqlalchemy import JSON, Column, Table, select, delete, MetaData from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker from sqlalchemy.exc import ProgrammingError from tenacity import retry, retry_if_exception_type, stop_after_attempt, wait_exponential - -try: - from asyncpg import DeadlockDetectedError, DuplicateTableError, UniqueViolationError -except ImportError: - # PostgreSQL dependencies not installed, define dummy exceptions - class DeadlockDetectedError(Exception): - pass - - class DuplicateTableError(Exception): - pass - - class UniqueViolationError(Exception): - pass - +from asyncpg import DeadlockDetectedError, DuplicateTableError, UniqueViolationError from cognee.shared.logging_utils import get_logger from cognee.infrastructure.engine import DataPoint @@ -82,14 +69,9 @@ class PGVectorAdapter(SQLAlchemyAdapter, VectorDBInterface): # Has to be imported at class level # Functions reading tables from database need to know what a Vector column type is - try: - from pgvector.sqlalchemy import Vector + from pgvector.sqlalchemy import Vector - self.Vector = Vector - except ImportError: - raise ImportError( - "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PGVector functionality." - ) + self.Vector = Vector async def embed_data(self, data: list[str]) -> list[list[float]]: """ diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index 6c4047847..3c3ff00b0 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -76,14 +76,14 @@ class LLMConfig(BaseSettings): def model_post_init(self, __context) -> None: """Initialize the BAML registry after the model is created.""" # Check if BAML is selected as structured output framework but not available - if self.structured_output_framework == "baml" and ClientRegistry is None: + if self.structured_output_framework.lower() == "baml" and ClientRegistry is None: raise ImportError( "BAML is selected as structured output framework but not available. " "Please install with 'pip install cognee[baml]' to use BAML extraction features." ) + elif self.structured_output_framework.lower() == "baml" and ClientRegistry is not None: + self.baml_registry = ClientRegistry() - if ClientRegistry is not None: - LLMConfig.baml_registry = ClientRegistry() raw_options = { "model": self.baml_llm_model, "temperature": self.baml_llm_temperature, diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py index 8efcce23d..55632be8e 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py @@ -53,7 +53,8 @@ async def acreate_structured_output( # Transform BAML response to proper pydantic reponse model if response_model is str: - return str(result) + # Note: when a response model is set to string in python result is stored in text property in the BAML response model + return str(result.text) return response_model.model_validate(result.dict()) From d1724c710b84ee90bf20ac03218b739662dd39d7 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 13:55:01 +0200 Subject: [PATCH 26/71] refactor: Add proper pip install command for optional extras --- cognee/api/client.py | 2 +- cognee/eval_framework/modal_eval_dashboard.py | 2 +- .../databases/vector/create_vector_engine.py | 2 +- .../files/storage/S3FileStorage.py | 2 +- .../files/utils/open_data_file.py | 2 +- .../cognee_network_visualization.py | 23 ++++++++----------- 6 files changed, 14 insertions(+), 19 deletions(-) diff --git a/cognee/api/client.py b/cognee/api/client.py index 978bc1929..f129ff2ec 100644 --- a/cognee/api/client.py +++ b/cognee/api/client.py @@ -51,7 +51,7 @@ if os.getenv("ENV", "prod") == "prod": ) except ImportError: logger.info( - "Sentry SDK not available. Install with 'pip install cognee[monitoring]' to enable error monitoring." + "Sentry SDK not available. Install with 'pip install cognee\"[monitoring]\"' to enable error monitoring." ) diff --git a/cognee/eval_framework/modal_eval_dashboard.py b/cognee/eval_framework/modal_eval_dashboard.py index 6fbe45f8a..9b1147528 100644 --- a/cognee/eval_framework/modal_eval_dashboard.py +++ b/cognee/eval_framework/modal_eval_dashboard.py @@ -82,7 +82,7 @@ def main(): import pandas as pd except ImportError: st.error( - "Pandas is required for the evaluation dashboard. Install with 'pip install cognee[evals]' to use this feature." + "Pandas is required for the evaluation dashboard. Install with 'pip install cognee\"[evals]\"' to use this feature." ) return diff --git a/cognee/infrastructure/databases/vector/create_vector_engine.py b/cognee/infrastructure/databases/vector/create_vector_engine.py index 9432cb296..5c4e93359 100644 --- a/cognee/infrastructure/databases/vector/create_vector_engine.py +++ b/cognee/infrastructure/databases/vector/create_vector_engine.py @@ -70,7 +70,7 @@ def create_vector_engine( from .pgvector.PGVectorAdapter import PGVectorAdapter except ImportError: raise ImportError( - "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PGVector functionality." + "PostgreSQL dependencies are not installed. Please install with 'pip install cognee\"[postgres]\"' or 'pip install cognee\"[postgres-binary]\"' to use PGVector functionality." ) return PGVectorAdapter( diff --git a/cognee/infrastructure/files/storage/S3FileStorage.py b/cognee/infrastructure/files/storage/S3FileStorage.py index 789018d46..4c986bbe9 100644 --- a/cognee/infrastructure/files/storage/S3FileStorage.py +++ b/cognee/infrastructure/files/storage/S3FileStorage.py @@ -25,7 +25,7 @@ class S3FileStorage(Storage): import s3fs except ImportError: raise ImportError( - "s3fs is required for S3FileStorage. Install it with: pip install cognee[aws]" + 's3fs is required for S3FileStorage. Install it with: pip install cognee"[aws]"' ) self.storage_path = storage_path diff --git a/cognee/infrastructure/files/utils/open_data_file.py b/cognee/infrastructure/files/utils/open_data_file.py index fcfca4161..ad8a6b63e 100644 --- a/cognee/infrastructure/files/utils/open_data_file.py +++ b/cognee/infrastructure/files/utils/open_data_file.py @@ -26,7 +26,7 @@ async def open_data_file(file_path: str, mode: str = "rb", encoding: str = None, from cognee.infrastructure.files.storage.S3FileStorage import S3FileStorage except ImportError: raise ImportError( - "S3 dependencies are not installed. Please install with 'pip install cognee[aws]' to use S3 functionality." + "S3 dependencies are not installed. Please install with 'pip install cognee\"[aws]\"' to use S3 functionality." ) normalized_url = get_data_file_path(file_path) diff --git a/cognee/modules/visualization/cognee_network_visualization.py b/cognee/modules/visualization/cognee_network_visualization.py index ef9b2f126..bbdbc0019 100644 --- a/cognee/modules/visualization/cognee_network_visualization.py +++ b/cognee/modules/visualization/cognee_network_visualization.py @@ -8,12 +8,7 @@ logger = get_logger() async def cognee_network_visualization(graph_data, destination_file_path: str = None): - try: - import networkx - except ImportError: - raise ImportError( - "NetworkX is not installed. Please install with 'pip install cognee[visualization]' to use graph visualization features." - ) + import networkx nodes_data, edges_data = graph_data @@ -110,7 +105,7 @@ async def cognee_network_visualization(graph_data, destination_file_path: str = .nodes circle { stroke: white; stroke-width: 0.5px; filter: drop-shadow(0 0 5px rgba(255,255,255,0.3)); } .node-label { font-size: 5px; font-weight: bold; fill: white; text-anchor: middle; dominant-baseline: middle; font-family: 'Inter', sans-serif; pointer-events: none; } .edge-label { font-size: 3px; fill: rgba(255, 255, 255, 0.7); text-anchor: middle; dominant-baseline: middle; font-family: 'Inter', sans-serif; pointer-events: none; } - + .tooltip { position: absolute; text-align: left; @@ -172,7 +167,7 @@ async def cognee_network_visualization(graph_data, destination_file_path: str = // Create tooltip content for edge var content = "Edge Information
"; content += "Relationship: " + d.relation + "
"; - + // Show all weights if (d.all_weights && Object.keys(d.all_weights).length > 0) { content += "Weights:
"; @@ -182,23 +177,23 @@ async def cognee_network_visualization(graph_data, destination_file_path: str = } else if (d.weight !== null && d.weight !== undefined) { content += "Weight: " + d.weight + "
"; } - + if (d.relationship_type) { content += "Type: " + d.relationship_type + "
"; } - + // Add other edge properties if (d.edge_info) { Object.keys(d.edge_info).forEach(function(key) { - if (key !== 'weight' && key !== 'weights' && key !== 'relationship_type' && - key !== 'source_node_id' && key !== 'target_node_id' && - key !== 'relationship_name' && key !== 'updated_at' && + if (key !== 'weight' && key !== 'weights' && key !== 'relationship_type' && + key !== 'source_node_id' && key !== 'target_node_id' && + key !== 'relationship_name' && key !== 'updated_at' && !key.startsWith('weight_')) { content += key + ": " + d.edge_info[key] + "
"; } }); } - + tooltip.html(content) .style("left", (d3.event.pageX + 10) + "px") .style("top", (d3.event.pageY - 10) + "px") From 8265ec03341cad520232c87ba1f99f9fd2cabe28 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 13:57:14 +0200 Subject: [PATCH 27/71] refactor: Add missing install info --- .../databases/relational/create_relational_engine.py | 2 +- cognee/infrastructure/llm/config.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cognee/infrastructure/databases/relational/create_relational_engine.py b/cognee/infrastructure/databases/relational/create_relational_engine.py index 4f117bf4c..deaeaa2da 100644 --- a/cognee/infrastructure/databases/relational/create_relational_engine.py +++ b/cognee/infrastructure/databases/relational/create_relational_engine.py @@ -48,7 +48,7 @@ def create_relational_engine( ) except ImportError: raise ImportError( - "PostgreSQL dependencies are not installed. Please install with 'pip install cognee[postgres]' or 'pip install cognee[postgres-binary]' to use PostgreSQL functionality." + "PostgreSQL dependencies are not installed. Please install with 'pip install cognee\"[postgres]\"' or 'pip install cognee\"[postgres-binary]\"' to use PostgreSQL functionality." ) return SQLAlchemyAdapter(connection_string) diff --git a/cognee/infrastructure/llm/config.py b/cognee/infrastructure/llm/config.py index 3c3ff00b0..6658a6251 100644 --- a/cognee/infrastructure/llm/config.py +++ b/cognee/infrastructure/llm/config.py @@ -79,7 +79,7 @@ class LLMConfig(BaseSettings): if self.structured_output_framework.lower() == "baml" and ClientRegistry is None: raise ImportError( "BAML is selected as structured output framework but not available. " - "Please install with 'pip install cognee[baml]' to use BAML extraction features." + "Please install with 'pip install cognee\"[baml]\"' to use BAML extraction features." ) elif self.structured_output_framework.lower() == "baml" and ClientRegistry is not None: self.baml_registry = ClientRegistry() From 6f8f9bf7de3b3b16d57d3aff1c5a67bc0aa2e78b Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 13:58:52 +0200 Subject: [PATCH 28/71] refactor: make comment more understandable --- .../baml/baml_src/extraction/acreate_structured_output.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py index 55632be8e..6ef27e51d 100644 --- a/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +++ b/cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py @@ -53,7 +53,7 @@ async def acreate_structured_output( # Transform BAML response to proper pydantic reponse model if response_model is str: - # Note: when a response model is set to string in python result is stored in text property in the BAML response model + # Note: when a response model is set to string in python, result is stored in text property in the BAML response model return str(result.text) return response_model.model_validate(result.dict()) From 61ef6fa444328ef9f749013333a383908c0c41a7 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 15:26:10 +0200 Subject: [PATCH 29/71] chore: Update pyproject --- poetry.lock | 52 ++++++++++++++++++++++++++++++++++++-------------- pyproject.toml | 6 ++++-- uv.lock | 24 +++++++++++++++++++---- 3 files changed, 62 insertions(+), 20 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1e42dc88d..f0f0c4ee4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1200,10 +1200,10 @@ test = ["pytest"] name = "contourpy" version = "1.3.2" description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] -markers = "python_version == \"3.10\"" +markers = "python_version == \"3.10\" and extra == \"evals\"" files = [ {file = "contourpy-1.3.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ba38e3f9f330af820c4b27ceb4b9c7feee5fe0493ea53a8720f4792667465934"}, {file = "contourpy-1.3.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:dc41ba0714aa2968d1f8674ec97504a8f7e334f48eeacebcaa6256213acb0989"}, @@ -1278,10 +1278,10 @@ test-no-images = ["pytest", "pytest-cov", "pytest-rerunfailures", "pytest-xdist" name = "contourpy" version = "1.3.3" description = "Python library for calculating contours of 2D quadrilateral grids" -optional = false +optional = true python-versions = ">=3.11" groups = ["main"] -markers = "python_version >= \"3.11\"" +markers = "python_version >= \"3.11\" and extra == \"evals\"" files = [ {file = "contourpy-1.3.3-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:709a48ef9a690e1343202916450bc48b9e51c049b089c7f79a267b46cffcdaa1"}, {file = "contourpy-1.3.3-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:23416f38bfd74d5d28ab8429cc4d63fa67d5068bd711a85edb1c3fb0c3e2f381"}, @@ -1582,9 +1582,10 @@ files = [ name = "cycler" version = "0.12.1" description = "Composable style cycles" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"evals\"" files = [ {file = "cycler-0.12.1-py3-none-any.whl", hash = "sha256:85cef7cff222d8644161529808465972e51340599459b8ac3ccbac5a854e0d30"}, {file = "cycler-0.12.1.tar.gz", hash = "sha256:88bb128f02ba341da8ef447245a9e138fae777f6a23943da4540077d3601eb1c"}, @@ -2303,9 +2304,10 @@ files = [ name = "fonttools" version = "4.60.0" description = "Tools to manipulate font files" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"evals\"" files = [ {file = "fonttools-4.60.0-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:151282a235c36024168c21c02193e939e8b28c73d5fa0b36ae1072671d8fa134"}, {file = "fonttools-4.60.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:3f32cc42d485d9b1546463b9a7a92bdbde8aef90bac3602503e04c2ddb27e164"}, @@ -3069,6 +3071,28 @@ multidict = "*" [package.extras] protobuf = ["protobuf (>=3.20.0)"] +[[package]] +name = "gunicorn" +version = "23.0.0" +description = "WSGI HTTP Server for UNIX" +optional = false +python-versions = ">=3.7" +groups = ["main"] +files = [ + {file = "gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d"}, + {file = "gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec"}, +] + +[package.dependencies] +packaging = "*" + +[package.extras] +eventlet = ["eventlet (>=0.24.1,!=0.36.0)"] +gevent = ["gevent (>=1.4.0)"] +setproctitle = ["setproctitle"] +testing = ["coverage", "eventlet", "gevent", "pytest", "pytest-cov"] +tornado = ["tornado (>=0.2)"] + [[package]] name = "h11" version = "0.16.0" @@ -4209,9 +4233,10 @@ test = ["hatch", "ipykernel", "openapi-core (>=0.18.0,<0.19.0)", "openapi-spec-v name = "kiwisolver" version = "1.4.9" description = "A fast implementation of the Cassowary constraint solver" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] +markers = "extra == \"evals\"" files = [ {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:b4b4d74bda2b8ebf4da5bd42af11d02d04428b2c32846e4c2c93219df8a7987b"}, {file = "kiwisolver-1.4.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:fb3b8132019ea572f4611d770991000d7f58127560c4889729248eb5852a102f"}, @@ -5127,9 +5152,10 @@ tests = ["pytest", "simplejson"] name = "matplotlib" version = "3.10.6" description = "Python plotting package" -optional = false +optional = true python-versions = ">=3.10" groups = ["main"] +markers = "extra == \"evals\"" files = [ {file = "matplotlib-3.10.6-cp310-cp310-macosx_10_12_x86_64.whl", hash = "sha256:bc7316c306d97463a9866b89d5cc217824e799fa0de346c8f68f4f3d27c8693d"}, {file = "matplotlib-3.10.6-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:d00932b0d160ef03f59f9c0e16d1e3ac89646f7785165ce6ad40c842db16cc2e"}, @@ -10788,10 +10814,9 @@ zstd = ["zstandard (>=0.18.0)"] name = "uvicorn" version = "0.37.0" description = "The lightning-fast ASGI server." -optional = true +optional = false python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"chromadb\"" files = [ {file = "uvicorn-0.37.0-py3-none-any.whl", hash = "sha256:913b2b88672343739927ce381ff9e2ad62541f9f8289664fa1d1d3803fa2ce6c"}, {file = "uvicorn-0.37.0.tar.gz", hash = "sha256:4115c8add6d3fd536c8ee77f0e14a7fd2ebba939fed9b02583a97f80648f9e13"}, @@ -11112,10 +11137,9 @@ test = ["websockets"] name = "websockets" version = "15.0.1" description = "An implementation of the WebSocket Protocol (RFC 6455 & 7692)" -optional = true +optional = false python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"deepeval\" or extra == \"chromadb\"" files = [ {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:d63efaa0cd96cf0c5fe4d581521d9fa87744540d4bc999ae6e08595a1014b45b"}, {file = "websockets-15.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ac60e3b188ec7574cb761b08d50fcedf9d77f1530352db4eef1707fe9dee7205"}, @@ -11631,7 +11655,7 @@ dev = ["coverage", "deptry", "gitpython", "mkdocs-material", "mkdocs-minify-plug distributed = ["modal"] dlt = ["dlt"] docs = ["unstructured"] -evals = ["gdown", "pandas", "plotly"] +evals = ["gdown", "matplotlib", "pandas", "plotly"] falkordb = ["falkordb"] gemini = ["google-generativeai"] graphiti = ["graphiti-core"] @@ -11652,4 +11676,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "320addf9d82b65c74ee256b7a50be3832473661cedfe9d3f1459b125ee8f799c" +content-hash = "e31994b59356d0bbb7c40dcd5e8ea19cc453c3f1303a7e8f82eeadd4595dbfb4" diff --git a/pyproject.toml b/pyproject.toml index 18b481db5..9bcbc8b5d 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,12 +48,13 @@ dependencies = [ "structlog>=25.2.0,<26", "pympler>=1.1,<2.0.0", "onnxruntime>=1.0.0,<2.0.0", - "pylance>=0.22.0,<1.0.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows "fastembed<=0.6.0 ", "networkx>=3.4.2,<4", - "matplotlib>=3.8.3,<4", + "uvicorn>=0.34.0,<1.0.0", + "gunicorn>=20.1.0,<24", + "websockets>=15.0.1,<16.0.0" ] @@ -106,6 +107,7 @@ evals = [ "plotly>=6.0.0,<7", "gdown>=5.2.0,<6", "pandas>=2.2.2,<3.0.0", + "matplotlib>=3.8.3,<4", ] graphiti = ["graphiti-core>=0.7.0,<0.8"] diff --git a/uv.lock b/uv.lock index 559dea22d..32d93f815 100644 --- a/uv.lock +++ b/uv.lock @@ -826,13 +826,13 @@ dependencies = [ { name = "fastapi-users", extra = ["sqlalchemy"] }, { name = "fastembed" }, { name = "filetype" }, + { name = "gunicorn" }, { name = "instructor" }, { name = "jinja2" }, { name = "kuzu" }, { name = "lancedb" }, { name = "limits" }, { name = "litellm" }, - { name = "matplotlib" }, { name = "nbformat" }, { name = "networkx", version = "3.4.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, { name = "networkx", version = "3.5", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, @@ -843,7 +843,6 @@ dependencies = [ { name = "pre-commit" }, { name = "pydantic" }, { name = "pydantic-settings" }, - { name = "pylance" }, { name = "pympler" }, { name = "pypdf" }, { name = "python-dotenv" }, @@ -854,6 +853,8 @@ dependencies = [ { name = "structlog" }, { name = "tiktoken" }, { name = "typing-extensions" }, + { name = "uvicorn" }, + { name = "websockets" }, ] [package.optional-dependencies] @@ -909,6 +910,7 @@ docs = [ ] evals = [ { name = "gdown" }, + { name = "matplotlib" }, { name = "pandas" }, { name = "plotly" }, ] @@ -994,6 +996,7 @@ requires-dist = [ { name = "google-generativeai", marker = "extra == 'gemini'", specifier = ">=0.8.4,<0.9" }, { name = "graphiti-core", marker = "extra == 'graphiti'", specifier = ">=0.7.0,<0.8" }, { name = "groq", marker = "extra == 'groq'", specifier = ">=0.8.0,<1.0.0" }, + { name = "gunicorn", specifier = ">=20.1.0,<24" }, { name = "instructor", specifier = ">=1.9.1,<2.0.0" }, { name = "jinja2", specifier = ">=3.1.3,<4" }, { name = "kuzu", specifier = "==0.11.0" }, @@ -1005,7 +1008,7 @@ requires-dist = [ { name = "limits", specifier = ">=4.4.1,<5" }, { name = "litellm", specifier = ">=1.76.0" }, { name = "llama-index-core", marker = "extra == 'llama-index'", specifier = ">=0.12.11,<0.13" }, - { name = "matplotlib", specifier = ">=3.8.3,<4" }, + { name = "matplotlib", marker = "extra == 'evals'", specifier = ">=3.8.3,<4" }, { name = "mistral-common", marker = "extra == 'mistral'", specifier = ">=1.5.2,<2" }, { name = "mkdocs-material", marker = "extra == 'dev'", specifier = ">=9.5.42,<10" }, { name = "mkdocs-minify-plugin", marker = "extra == 'dev'", specifier = ">=0.8.0,<0.9" }, @@ -1030,7 +1033,6 @@ requires-dist = [ { name = "psycopg2-binary", marker = "extra == 'postgres-binary'", specifier = ">=2.9.10,<3.0.0" }, { name = "pydantic", specifier = ">=2.10.5,<3.0.0" }, { name = "pydantic-settings", specifier = ">=2.2.1,<3" }, - { name = "pylance", specifier = ">=0.22.0,<1.0.0" }, { name = "pylint", marker = "extra == 'dev'", specifier = ">=3.0.3,<4" }, { name = "pympler", specifier = ">=1.1,<2.0.0" }, { name = "pypdf", specifier = ">=4.1.0,<7.0.0" }, @@ -1056,6 +1058,8 @@ requires-dist = [ { name = "tweepy", marker = "extra == 'dev'", specifier = ">=4.14.0,<5.0.0" }, { name = "typing-extensions", specifier = ">=4.12.2,<5.0.0" }, { name = "unstructured", extras = ["csv", "doc", "docx", "epub", "md", "odt", "org", "ppt", "pptx", "rst", "rtf", "tsv", "xlsx"], marker = "extra == 'docs'", specifier = ">=0.18.1,<19" }, + { name = "uvicorn", specifier = ">=0.34.0,<1.0.0" }, + { name = "websockets", specifier = ">=15.0.1,<16.0.0" }, ] provides-extras = ["api", "distributed", "neo4j", "neptune", "postgres", "postgres-binary", "notebook", "langchain", "llama-index", "gemini", "huggingface", "ollama", "mistral", "anthropic", "deepeval", "posthog", "falkordb", "groq", "chromadb", "docs", "codegraph", "evals", "graphiti", "aws", "dlt", "baml", "dev", "debug", "monitoring"] @@ -2364,6 +2368,18 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/03/8b/ad381ec1b8195fa4a9a693cb8087e031b99530c0d6b8ad036dcb99e144c4/grpclib-0.4.8-py3-none-any.whl", hash = "sha256:a5047733a7acc1c1cee6abf3c841c7c6fab67d2844a45a853b113fa2e6cd2654", size = 76311, upload-time = "2025-05-04T16:27:22.818Z" }, ] +[[package]] +name = "gunicorn" +version = "23.0.0" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "packaging" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/34/72/9614c465dc206155d93eff0ca20d42e1e35afc533971379482de953521a4/gunicorn-23.0.0.tar.gz", hash = "sha256:f014447a0101dc57e294f6c18ca6b40227a4c90e9bdb586042628030cba004ec", size = 375031, upload-time = "2024-08-10T20:25:27.378Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/cb/7d/6dac2a6e1eba33ee43f318edbed4ff29151a49b5d37f080aad1e6469bca4/gunicorn-23.0.0-py3-none-any.whl", hash = "sha256:ec400d38950de4dfd418cff8328b2c8faed0edb0d517d3394e457c317908ca4d", size = 85029, upload-time = "2024-08-10T20:25:24.996Z" }, +] + [[package]] name = "h11" version = "0.16.0" From 664459e23978538d411fd45096f3245c373facf6 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 15:30:27 +0200 Subject: [PATCH 30/71] refactor: Install baml only for BAML test --- .github/actions/cognee_setup/action.yml | 2 +- .github/workflows/basic_tests.yml | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/actions/cognee_setup/action.yml b/.github/actions/cognee_setup/action.yml index 77c5b3b1f..e46a42edb 100644 --- a/.github/actions/cognee_setup/action.yml +++ b/.github/actions/cognee_setup/action.yml @@ -41,4 +41,4 @@ runs: EXTRA_ARGS="$EXTRA_ARGS --extra $extra" done fi - uv sync --extra api --extra docs --extra evals --extra gemini --extra codegraph --extra ollama --extra dev --extra baml --extra neo4j $EXTRA_ARGS + uv sync --extra api --extra docs --extra evals --extra gemini --extra codegraph --extra ollama --extra dev --extra neo4j $EXTRA_ARGS diff --git a/.github/workflows/basic_tests.yml b/.github/workflows/basic_tests.yml index e2264da3d..3f3e644a2 100644 --- a/.github/workflows/basic_tests.yml +++ b/.github/workflows/basic_tests.yml @@ -188,6 +188,7 @@ jobs: uses: ./.github/actions/cognee_setup with: python-version: ${{ inputs.python-version }} + extra-dependencies: "baml" - name: Run Simple Examples run: uv run python ./examples/python/simple_example.py From 50032dd13322ebfb0d3f312fbb9f784e80295350 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 16:02:30 +0200 Subject: [PATCH 31/71] fix: install aws for gh action --- .github/workflows/e2e_tests.yml | 3 --- .github/workflows/test_s3_file_storage.yml | 1 + 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/.github/workflows/e2e_tests.yml b/.github/workflows/e2e_tests.yml index af3a3ff44..3fe7a7992 100644 --- a/.github/workflows/e2e_tests.yml +++ b/.github/workflows/e2e_tests.yml @@ -166,9 +166,6 @@ jobs: python-version: '3.11.x' extra-dependencies: "aws" - - name: Dependencies already installed - run: echo "Dependencies already installed in setup" - - name: Run S3 Bucket Test env: ENV: 'dev' diff --git a/.github/workflows/test_s3_file_storage.yml b/.github/workflows/test_s3_file_storage.yml index c4866ec2d..a477d8933 100644 --- a/.github/workflows/test_s3_file_storage.yml +++ b/.github/workflows/test_s3_file_storage.yml @@ -18,6 +18,7 @@ jobs: uses: ./.github/actions/cognee_setup with: python-version: '3.11.x' + extra-dependencies: "aws" - name: Run S3 File Storage Test env: From 4054307b15a13decb728b76544f15648b2b66b2e Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 16:03:11 +0200 Subject: [PATCH 32/71] refactor: Remove comment --- .../infrastructure/databases/vector/lancedb/LanceDBAdapter.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py b/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py index 7bc3385b9..0c93f81e7 100644 --- a/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +++ b/cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py @@ -247,8 +247,6 @@ class LanceDBAdapter(VectorDBInterface): result_values = await collection.vector_search(query_vector).limit(limit).to_list() - # result_values = list(results.to_dict("index").values()) - if not result_values: return [] From cf3f5945e71678fb4ba371996e1dde5121c9e4e2 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 16:44:55 +0200 Subject: [PATCH 33/71] chore: Limit pylance to 0.36 for MacOS13 --- poetry.lock | 2 +- pyproject.toml | 2 +- uv.lock | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/poetry.lock b/poetry.lock index b8cbdc95d..03b4130b4 100644 --- a/poetry.lock +++ b/poetry.lock @@ -11937,4 +11937,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "fc32c4e05914cf364d4feb0c3baec9771d149eb65626e5337fa2eb55e7130499" +content-hash = "a3e4b759a594833ee435a0ece818896eedcaa5b6cd20f9098a46ad4422f62ef1" diff --git a/pyproject.toml b/pyproject.toml index d465f772e..5770d1b1f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ dependencies = [ "baml-py (==0.206.0)", "pympler>=1.1,<2.0.0", "onnxruntime>=1.0.0,<2.0.0", - "pylance>=0.22.0,<1.0.0", + "pylance>=0.22.0,<=0.36.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows "uvicorn>=0.34.0,<1.0.0", diff --git a/uv.lock b/uv.lock index 08a474be6..caa3e1bf5 100644 --- a/uv.lock +++ b/uv.lock @@ -1034,7 +1034,7 @@ requires-dist = [ { name = "psycopg2-binary", marker = "extra == 'postgres-binary'", specifier = ">=2.9.10,<3.0.0" }, { name = "pydantic", specifier = ">=2.10.5,<3.0.0" }, { name = "pydantic-settings", specifier = ">=2.2.1,<3" }, - { name = "pylance", specifier = ">=0.22.0,<1.0.0" }, + { name = "pylance", specifier = ">=0.22.0,<=0.36.0" }, { name = "pylint", marker = "extra == 'dev'", specifier = ">=3.0.3,<4" }, { name = "pympler", specifier = ">=1.1,<2.0.0" }, { name = "pypdf", specifier = ">=4.1.0,<7.0.0" }, @@ -1785,17 +1785,17 @@ name = "fastembed" version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "huggingface-hub" }, - { name = "loguru" }, - { name = "mmh3" }, + { name = "huggingface-hub", marker = "python_full_version < '3.13'" }, + { name = "loguru", marker = "python_full_version < '3.13'" }, + { name = "mmh3", marker = "python_full_version < '3.13'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "onnxruntime" }, - { name = "pillow" }, - { name = "py-rust-stemmers" }, - { name = "requests" }, - { name = "tokenizers" }, - { name = "tqdm" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.12.*'" }, + { name = "onnxruntime", marker = "python_full_version < '3.13'" }, + { name = "pillow", marker = "python_full_version < '3.13'" }, + { name = "py-rust-stemmers", marker = "python_full_version < '3.13'" }, + { name = "requests", marker = "python_full_version < '3.13'" }, + { name = "tokenizers", marker = "python_full_version < '3.13'" }, + { name = "tqdm", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/f4/036a656c605f63dc25f11284f60f69900a54a19c513e1ae60d21d6977e75/fastembed-0.6.0.tar.gz", hash = "sha256:5c9ead25f23449535b07243bbe1f370b820dcc77ec2931e61674e3fe7ff24733", size = 50731, upload-time = "2025-02-26T13:50:33.031Z" } wheels = [ @@ -3539,8 +3539,8 @@ name = "loguru" version = "0.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version < '3.13' and sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "python_full_version < '3.13' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } wheels = [ From bcc1747ab85f20423475847f6b350ef33cad4006 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 17:02:58 +0200 Subject: [PATCH 34/71] chore: resolve ruff v0.13.2 support issue --- poetry.lock | 62 ++++++++++++++++++++++++-------------------- pyproject.toml | 4 +-- uv.lock | 70 +++++++++++++++++++++++++------------------------- 3 files changed, 71 insertions(+), 65 deletions(-) diff --git a/poetry.lock b/poetry.lock index b8cbdc95d..346c1929e 100644 --- a/poetry.lock +++ b/poetry.lock @@ -945,9 +945,10 @@ pycparser = {version = "*", markers = "implementation_name != \"PyPy\""} name = "cfgv" version = "3.4.0" description = "Validate configuration and produce human readable error messages." -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "cfgv-3.4.0-py2.py3-none-any.whl", hash = "sha256:b7265b1f29fd3316bfcd2b330d63d024f2bfd8bcb8b0272f8e19a504856c48f9"}, {file = "cfgv-3.4.0.tar.gz", hash = "sha256:e52591d4c5f5dead8e0f673fb16db7949d2cfb3f7da4582893288f0ded8fe560"}, @@ -1847,9 +1848,10 @@ files = [ name = "distlib" version = "0.4.0" description = "Distribution utilities" -optional = false +optional = true python-versions = "*" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "distlib-0.4.0-py2.py3-none-any.whl", hash = "sha256:9659f7d87e46584a30b5780e43ac7a2143098441670ff0a49d5f9034c54a6c16"}, {file = "distlib-0.4.0.tar.gz", hash = "sha256:feec40075be03a04501a973d81f633735b4b69f98b05450592310c0f401a4e0d"}, @@ -3399,9 +3401,10 @@ files = [ name = "identify" version = "2.6.14" description = "File identification library for Python" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "identify-2.6.14-py2.py3-none-any.whl", hash = "sha256:11a073da82212c6646b1f39bb20d4483bfb9543bd5566fec60053c4bb309bf2e"}, {file = "identify-2.6.14.tar.gz", hash = "sha256:663494103b4f717cb26921c52f8751363dc89db64364cd836a9bf1535f53cd6a"}, @@ -6118,9 +6121,10 @@ twitter = ["twython"] name = "nodeenv" version = "1.9.1" description = "Node.js virtual environment builder" -optional = false +optional = true python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, @@ -7297,9 +7301,10 @@ test = ["anthropic", "coverage", "django", "flake8", "freezegun (==1.5.1)", "lan name = "pre-commit" version = "4.3.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "pre_commit-4.3.0-py2.py3-none-any.whl", hash = "sha256:2b0747ad7e6e967169136edffee14c16e148a778a54e4f967921aa1ebf2308d8"}, {file = "pre_commit-4.3.0.tar.gz", hash = "sha256:499fe450cc9d42e9d58e606262795ecb64dd05438943c62b66f6a8673da30b16"}, @@ -9507,32 +9512,32 @@ pyasn1 = ">=0.1.3" [[package]] name = "ruff" -version = "0.13.1" +version = "0.13.0" description = "An extremely fast Python linter and code formatter, written in Rust." optional = true python-versions = ">=3.7" groups = ["main"] markers = "extra == \"dev\"" files = [ - {file = "ruff-0.13.1-py3-none-linux_armv6l.whl", hash = "sha256:b2abff595cc3cbfa55e509d89439b5a09a6ee3c252d92020bd2de240836cf45b"}, - {file = "ruff-0.13.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4ee9f4249bf7f8bb3984c41bfaf6a658162cdb1b22e3103eabc7dd1dc5579334"}, - {file = "ruff-0.13.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c5da4af5f6418c07d75e6f3224e08147441f5d1eac2e6ce10dcce5e616a3bae"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80524f84a01355a59a93cef98d804e2137639823bcee2931f5028e71134a954e"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff7f5ce8d7988767dd46a148192a14d0f48d1baea733f055d9064875c7d50389"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c55d84715061f8b05469cdc9a446aa6c7294cd4bd55e86a89e572dba14374f8c"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ac57fed932d90fa1624c946dc67a0a3388d65a7edc7d2d8e4ca7bddaa789b3b0"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c366a71d5b4f41f86a008694f7a0d75fe409ec298685ff72dc882f882d532e36"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ea9d1b5ad3e7a83ee8ebb1229c33e5fe771e833d6d3dcfca7b77d95b060d38"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f70202996055b555d3d74b626406476cc692f37b13bac8828acff058c9966a"}, - {file = "ruff-0.13.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f8cff7a105dad631085d9505b491db33848007d6b487c3c1979dd8d9b2963783"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9761e84255443316a258dd7dfbd9bfb59c756e52237ed42494917b2577697c6a"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3d376a88c3102ef228b102211ef4a6d13df330cb0f5ca56fdac04ccec2a99700"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cbefd60082b517a82c6ec8836989775ac05f8991715d228b3c1d86ccc7df7dae"}, - {file = "ruff-0.13.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd16b9a5a499fe73f3c2ef09a7885cb1d97058614d601809d37c422ed1525317"}, - {file = "ruff-0.13.1-py3-none-win32.whl", hash = "sha256:55e9efa692d7cb18580279f1fbb525146adc401f40735edf0aaeabd93099f9a0"}, - {file = "ruff-0.13.1-py3-none-win_amd64.whl", hash = "sha256:3a3fb595287ee556de947183489f636b9f76a72f0fa9c028bdcabf5bab2cc5e5"}, - {file = "ruff-0.13.1-py3-none-win_arm64.whl", hash = "sha256:c0bae9ffd92d54e03c2bf266f466da0a65e145f298ee5b5846ed435f6a00518a"}, - {file = "ruff-0.13.1.tar.gz", hash = "sha256:88074c3849087f153d4bb22e92243ad4c1b366d7055f98726bc19aa08dc12d51"}, + {file = "ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004"}, + {file = "ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9"}, + {file = "ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991"}, + {file = "ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945"}, + {file = "ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823"}, + {file = "ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768"}, + {file = "ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb"}, + {file = "ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e"}, + {file = "ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60"}, ] [[package]] @@ -11157,9 +11162,10 @@ test = ["aiohttp (>=3.10.5)", "flake8 (>=5.0,<6.0)", "mypy (>=0.800)", "psutil", name = "virtualenv" version = "20.34.0" description = "Virtual Python Environment builder" -optional = false +optional = true python-versions = ">=3.8" groups = ["main"] +markers = "extra == \"dev\"" files = [ {file = "virtualenv-20.34.0-py3-none-any.whl", hash = "sha256:341f5afa7eee943e4984a9207c025feedd768baff6753cd660c857ceb3e36026"}, {file = "virtualenv-20.34.0.tar.gz", hash = "sha256:44815b2c9dee7ed86e387b842a84f20b93f7f417f95886ca1996a72a4138eb1a"}, @@ -11913,7 +11919,7 @@ chromadb = ["chromadb", "pypika"] codegraph = ["fastembed", "transformers", "tree-sitter", "tree-sitter-python"] debug = ["debugpy"] deepeval = ["deepeval"] -dev = ["coverage", "deptry", "gitpython", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings", "mypy", "notebook", "pylint", "pytest", "pytest-asyncio", "pytest-cov", "ruff", "tweepy"] +dev = ["coverage", "deptry", "gitpython", "mkdocs-material", "mkdocs-minify-plugin", "mkdocstrings", "mypy", "notebook", "pre-commit", "pylint", "pytest", "pytest-asyncio", "pytest-cov", "ruff", "tweepy"] distributed = ["modal"] docs = ["unstructured"] evals = ["gdown", "plotly"] @@ -11937,4 +11943,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "fc32c4e05914cf364d4feb0c3baec9771d149eb65626e5337fa2eb55e7130499" +content-hash = "3c5f1fbbd1ec57adbc83d1a1d99ed39a4566c518661940fa43c06906c98221de" diff --git a/pyproject.toml b/pyproject.toml index d465f772e..fbf2203e7 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -48,7 +48,6 @@ dependencies = [ "lancedb>=0.24.0,<1.0.0", "nbformat>=5.7.0,<6.0.0", "alembic>=1.13.3,<2", - "pre-commit>=4.0.1,<5", "scikit-learn>=1.6.1,<2", "limits>=4.4.1,<5", "fastapi>=0.115.7,<1.0.0", @@ -130,10 +129,11 @@ dev = [ "pytest-asyncio>=0.21.1,<0.22", "coverage>=7.3.2,<8", "mypy>=1.7.1,<2", + "pre-commit>=4.0.1,<5", "notebook>=7.1.0,<8", "deptry>=0.20.0,<0.21", "pylint>=3.0.3,<4", - "ruff>=0.9.2,<1.0.0", + "ruff>=0.9.2,<=0.13.1", "tweepy>=4.14.0,<5.0.0", "gitpython>=3.1.43,<4", "mkdocs-material>=9.5.42,<10", diff --git a/uv.lock b/uv.lock index 08a474be6..af2cee0b6 100644 --- a/uv.lock +++ b/uv.lock @@ -845,7 +845,6 @@ dependencies = [ { name = "onnxruntime" }, { name = "openai" }, { name = "pandas" }, - { name = "pre-commit" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pylance" }, @@ -898,6 +897,7 @@ dev = [ { name = "mkdocstrings", extra = ["python"] }, { name = "mypy" }, { name = "notebook" }, + { name = "pre-commit" }, { name = "pylint" }, { name = "pytest" }, { name = "pytest-asyncio" }, @@ -1029,7 +1029,7 @@ requires-dist = [ { name = "pgvector", marker = "extra == 'postgres-binary'", specifier = ">=0.3.5,<0.4" }, { name = "plotly", marker = "extra == 'evals'", specifier = ">=6.0.0,<7" }, { name = "posthog", marker = "extra == 'posthog'", specifier = ">=3.5.0,<4" }, - { name = "pre-commit", specifier = ">=4.0.1,<5" }, + { name = "pre-commit", marker = "extra == 'dev'", specifier = ">=4.0.1,<5" }, { name = "psycopg2", marker = "extra == 'postgres'", specifier = ">=2.9.10,<3" }, { name = "psycopg2-binary", marker = "extra == 'postgres-binary'", specifier = ">=2.9.10,<3.0.0" }, { name = "pydantic", specifier = ">=2.10.5,<3.0.0" }, @@ -1048,7 +1048,7 @@ requires-dist = [ { name = "python-multipart", specifier = ">=0.0.20,<1.0.0" }, { name = "qasync", marker = "extra == 'gui'", specifier = ">=0.27.1,<0.28" }, { name = "rdflib", specifier = ">=7.1.4,<7.2.0" }, - { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9.2,<1.0.0" }, + { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9.2,<=0.13.1" }, { name = "s3fs", extras = ["boto3"], specifier = "==2025.3.2" }, { name = "s3fs", extras = ["boto3"], marker = "extra == 'aws'", specifier = "==2025.3.2" }, { name = "scikit-learn", specifier = ">=1.6.1,<2" }, @@ -1785,17 +1785,17 @@ name = "fastembed" version = "0.6.0" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "huggingface-hub" }, - { name = "loguru" }, - { name = "mmh3" }, + { name = "huggingface-hub", marker = "python_full_version < '3.13'" }, + { name = "loguru", marker = "python_full_version < '3.13'" }, + { name = "mmh3", marker = "python_full_version < '3.13'" }, { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "onnxruntime" }, - { name = "pillow" }, - { name = "py-rust-stemmers" }, - { name = "requests" }, - { name = "tokenizers" }, - { name = "tqdm" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.12.*'" }, + { name = "onnxruntime", marker = "python_full_version < '3.13'" }, + { name = "pillow", marker = "python_full_version < '3.13'" }, + { name = "py-rust-stemmers", marker = "python_full_version < '3.13'" }, + { name = "requests", marker = "python_full_version < '3.13'" }, + { name = "tokenizers", marker = "python_full_version < '3.13'" }, + { name = "tqdm", marker = "python_full_version < '3.13'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/c6/f4/036a656c605f63dc25f11284f60f69900a54a19c513e1ae60d21d6977e75/fastembed-0.6.0.tar.gz", hash = "sha256:5c9ead25f23449535b07243bbe1f370b820dcc77ec2931e61674e3fe7ff24733", size = 50731, upload-time = "2025-02-26T13:50:33.031Z" } wheels = [ @@ -3539,8 +3539,8 @@ name = "loguru" version = "0.7.3" source = { registry = "https://pypi.org/simple" } dependencies = [ - { name = "colorama", marker = "sys_platform == 'win32'" }, - { name = "win32-setctime", marker = "sys_platform == 'win32'" }, + { name = "colorama", marker = "python_full_version < '3.13' and sys_platform == 'win32'" }, + { name = "win32-setctime", marker = "python_full_version < '3.13' and sys_platform == 'win32'" }, ] sdist = { url = "https://files.pythonhosted.org/packages/3a/05/a1dae3dffd1116099471c643b8924f5aa6524411dc6c63fdae648c4f1aca/loguru-0.7.3.tar.gz", hash = "sha256:19480589e77d47b8d85b2c827ad95d49bf31b0dcde16593892eb51dd18706eb6", size = 63559, upload-time = "2024-12-06T11:20:56.608Z" } wheels = [ @@ -6786,28 +6786,28 @@ wheels = [ [[package]] name = "ruff" -version = "0.13.1" +version = "0.13.0" source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/ab/33/c8e89216845615d14d2d42ba2bee404e7206a8db782f33400754f3799f05/ruff-0.13.1.tar.gz", hash = "sha256:88074c3849087f153d4bb22e92243ad4c1b366d7055f98726bc19aa08dc12d51", size = 5397987, upload-time = "2025-09-18T19:52:44.33Z" } +sdist = { url = "https://files.pythonhosted.org/packages/6e/1a/1f4b722862840295bcaba8c9e5261572347509548faaa99b2d57ee7bfe6a/ruff-0.13.0.tar.gz", hash = "sha256:5b4b1ee7eb35afae128ab94459b13b2baaed282b1fb0f472a73c82c996c8ae60", size = 5372863, upload-time = "2025-09-10T16:25:37.917Z" } wheels = [ - { url = "https://files.pythonhosted.org/packages/f3/41/ca37e340938f45cfb8557a97a5c347e718ef34702546b174e5300dbb1f28/ruff-0.13.1-py3-none-linux_armv6l.whl", hash = "sha256:b2abff595cc3cbfa55e509d89439b5a09a6ee3c252d92020bd2de240836cf45b", size = 12304308, upload-time = "2025-09-18T19:51:56.253Z" }, - { url = "https://files.pythonhosted.org/packages/ff/84/ba378ef4129415066c3e1c80d84e539a0d52feb250685091f874804f28af/ruff-0.13.1-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:4ee9f4249bf7f8bb3984c41bfaf6a658162cdb1b22e3103eabc7dd1dc5579334", size = 12937258, upload-time = "2025-09-18T19:52:00.184Z" }, - { url = "https://files.pythonhosted.org/packages/8d/b6/ec5e4559ae0ad955515c176910d6d7c93edcbc0ed1a3195a41179c58431d/ruff-0.13.1-py3-none-macosx_11_0_arm64.whl", hash = "sha256:5c5da4af5f6418c07d75e6f3224e08147441f5d1eac2e6ce10dcce5e616a3bae", size = 12214554, upload-time = "2025-09-18T19:52:02.753Z" }, - { url = "https://files.pythonhosted.org/packages/70/d6/cb3e3b4f03b9b0c4d4d8f06126d34b3394f6b4d764912fe80a1300696ef6/ruff-0.13.1-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:80524f84a01355a59a93cef98d804e2137639823bcee2931f5028e71134a954e", size = 12448181, upload-time = "2025-09-18T19:52:05.279Z" }, - { url = "https://files.pythonhosted.org/packages/d2/ea/bf60cb46d7ade706a246cd3fb99e4cfe854efa3dfbe530d049c684da24ff/ruff-0.13.1-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:ff7f5ce8d7988767dd46a148192a14d0f48d1baea733f055d9064875c7d50389", size = 12104599, upload-time = "2025-09-18T19:52:07.497Z" }, - { url = "https://files.pythonhosted.org/packages/2d/3e/05f72f4c3d3a69e65d55a13e1dd1ade76c106d8546e7e54501d31f1dc54a/ruff-0.13.1-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c55d84715061f8b05469cdc9a446aa6c7294cd4bd55e86a89e572dba14374f8c", size = 13791178, upload-time = "2025-09-18T19:52:10.189Z" }, - { url = "https://files.pythonhosted.org/packages/81/e7/01b1fc403dd45d6cfe600725270ecc6a8f8a48a55bc6521ad820ed3ceaf8/ruff-0.13.1-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:ac57fed932d90fa1624c946dc67a0a3388d65a7edc7d2d8e4ca7bddaa789b3b0", size = 14814474, upload-time = "2025-09-18T19:52:12.866Z" }, - { url = "https://files.pythonhosted.org/packages/fa/92/d9e183d4ed6185a8df2ce9faa3f22e80e95b5f88d9cc3d86a6d94331da3f/ruff-0.13.1-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:c366a71d5b4f41f86a008694f7a0d75fe409ec298685ff72dc882f882d532e36", size = 14217531, upload-time = "2025-09-18T19:52:15.245Z" }, - { url = "https://files.pythonhosted.org/packages/3b/4a/6ddb1b11d60888be224d721e01bdd2d81faaf1720592858ab8bac3600466/ruff-0.13.1-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f4ea9d1b5ad3e7a83ee8ebb1229c33e5fe771e833d6d3dcfca7b77d95b060d38", size = 13265267, upload-time = "2025-09-18T19:52:17.649Z" }, - { url = "https://files.pythonhosted.org/packages/81/98/3f1d18a8d9ea33ef2ad508f0417fcb182c99b23258ec5e53d15db8289809/ruff-0.13.1-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b0f70202996055b555d3d74b626406476cc692f37b13bac8828acff058c9966a", size = 13243120, upload-time = "2025-09-18T19:52:20.332Z" }, - { url = "https://files.pythonhosted.org/packages/8d/86/b6ce62ce9c12765fa6c65078d1938d2490b2b1d9273d0de384952b43c490/ruff-0.13.1-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:f8cff7a105dad631085d9505b491db33848007d6b487c3c1979dd8d9b2963783", size = 13443084, upload-time = "2025-09-18T19:52:23.032Z" }, - { url = "https://files.pythonhosted.org/packages/a1/6e/af7943466a41338d04503fb5a81b2fd07251bd272f546622e5b1599a7976/ruff-0.13.1-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:9761e84255443316a258dd7dfbd9bfb59c756e52237ed42494917b2577697c6a", size = 12295105, upload-time = "2025-09-18T19:52:25.263Z" }, - { url = "https://files.pythonhosted.org/packages/3f/97/0249b9a24f0f3ebd12f007e81c87cec6d311de566885e9309fcbac5b24cc/ruff-0.13.1-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:3d376a88c3102ef228b102211ef4a6d13df330cb0f5ca56fdac04ccec2a99700", size = 12072284, upload-time = "2025-09-18T19:52:27.478Z" }, - { url = "https://files.pythonhosted.org/packages/f6/85/0b64693b2c99d62ae65236ef74508ba39c3febd01466ef7f354885e5050c/ruff-0.13.1-py3-none-musllinux_1_2_i686.whl", hash = "sha256:cbefd60082b517a82c6ec8836989775ac05f8991715d228b3c1d86ccc7df7dae", size = 12970314, upload-time = "2025-09-18T19:52:30.212Z" }, - { url = "https://files.pythonhosted.org/packages/96/fc/342e9f28179915d28b3747b7654f932ca472afbf7090fc0c4011e802f494/ruff-0.13.1-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:dd16b9a5a499fe73f3c2ef09a7885cb1d97058614d601809d37c422ed1525317", size = 13422360, upload-time = "2025-09-18T19:52:32.676Z" }, - { url = "https://files.pythonhosted.org/packages/37/54/6177a0dc10bce6f43e392a2192e6018755473283d0cf43cc7e6afc182aea/ruff-0.13.1-py3-none-win32.whl", hash = "sha256:55e9efa692d7cb18580279f1fbb525146adc401f40735edf0aaeabd93099f9a0", size = 12178448, upload-time = "2025-09-18T19:52:35.545Z" }, - { url = "https://files.pythonhosted.org/packages/64/51/c6a3a33d9938007b8bdc8ca852ecc8d810a407fb513ab08e34af12dc7c24/ruff-0.13.1-py3-none-win_amd64.whl", hash = "sha256:3a3fb595287ee556de947183489f636b9f76a72f0fa9c028bdcabf5bab2cc5e5", size = 13286458, upload-time = "2025-09-18T19:52:38.198Z" }, - { url = "https://files.pythonhosted.org/packages/fd/04/afc078a12cf68592345b1e2d6ecdff837d286bac023d7a22c54c7a698c5b/ruff-0.13.1-py3-none-win_arm64.whl", hash = "sha256:c0bae9ffd92d54e03c2bf266f466da0a65e145f298ee5b5846ed435f6a00518a", size = 12437893, upload-time = "2025-09-18T19:52:41.283Z" }, + { url = "https://files.pythonhosted.org/packages/ac/fe/6f87b419dbe166fd30a991390221f14c5b68946f389ea07913e1719741e0/ruff-0.13.0-py3-none-linux_armv6l.whl", hash = "sha256:137f3d65d58ee828ae136a12d1dc33d992773d8f7644bc6b82714570f31b2004", size = 12187826, upload-time = "2025-09-10T16:24:39.5Z" }, + { url = "https://files.pythonhosted.org/packages/e4/25/c92296b1fc36d2499e12b74a3fdb230f77af7bdf048fad7b0a62e94ed56a/ruff-0.13.0-py3-none-macosx_10_12_x86_64.whl", hash = "sha256:21ae48151b66e71fd111b7d79f9ad358814ed58c339631450c66a4be33cc28b9", size = 12933428, upload-time = "2025-09-10T16:24:43.866Z" }, + { url = "https://files.pythonhosted.org/packages/44/cf/40bc7221a949470307d9c35b4ef5810c294e6cfa3caafb57d882731a9f42/ruff-0.13.0-py3-none-macosx_11_0_arm64.whl", hash = "sha256:64de45f4ca5441209e41742d527944635a05a6e7c05798904f39c85bafa819e3", size = 12095543, upload-time = "2025-09-10T16:24:46.638Z" }, + { url = "https://files.pythonhosted.org/packages/f1/03/8b5ff2a211efb68c63a1d03d157e924997ada87d01bebffbd13a0f3fcdeb/ruff-0.13.0-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:2b2c653ae9b9d46e0ef62fc6fbf5b979bda20a0b1d2b22f8f7eb0cde9f4963b8", size = 12312489, upload-time = "2025-09-10T16:24:49.556Z" }, + { url = "https://files.pythonhosted.org/packages/37/fc/2336ef6d5e9c8d8ea8305c5f91e767d795cd4fc171a6d97ef38a5302dadc/ruff-0.13.0-py3-none-manylinux_2_17_armv7l.manylinux2014_armv7l.whl", hash = "sha256:4cec632534332062bc9eb5884a267b689085a1afea9801bf94e3ba7498a2d207", size = 11991631, upload-time = "2025-09-10T16:24:53.439Z" }, + { url = "https://files.pythonhosted.org/packages/39/7f/f6d574d100fca83d32637d7f5541bea2f5e473c40020bbc7fc4a4d5b7294/ruff-0.13.0-py3-none-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:dcd628101d9f7d122e120ac7c17e0a0f468b19bc925501dbe03c1cb7f5415b24", size = 13720602, upload-time = "2025-09-10T16:24:56.392Z" }, + { url = "https://files.pythonhosted.org/packages/fd/c8/a8a5b81d8729b5d1f663348d11e2a9d65a7a9bd3c399763b1a51c72be1ce/ruff-0.13.0-py3-none-manylinux_2_17_ppc64.manylinux2014_ppc64.whl", hash = "sha256:afe37db8e1466acb173bb2a39ca92df00570e0fd7c94c72d87b51b21bb63efea", size = 14697751, upload-time = "2025-09-10T16:24:59.89Z" }, + { url = "https://files.pythonhosted.org/packages/57/f5/183ec292272ce7ec5e882aea74937f7288e88ecb500198b832c24debc6d3/ruff-0.13.0-py3-none-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0f96a8d90bb258d7d3358b372905fe7333aaacf6c39e2408b9f8ba181f4b6ef2", size = 14095317, upload-time = "2025-09-10T16:25:03.025Z" }, + { url = "https://files.pythonhosted.org/packages/9f/8d/7f9771c971724701af7926c14dab31754e7b303d127b0d3f01116faef456/ruff-0.13.0-py3-none-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:94b5e3d883e4f924c5298e3f2ee0f3085819c14f68d1e5b6715597681433f153", size = 13144418, upload-time = "2025-09-10T16:25:06.272Z" }, + { url = "https://files.pythonhosted.org/packages/a8/a6/7985ad1778e60922d4bef546688cd8a25822c58873e9ff30189cfe5dc4ab/ruff-0.13.0-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:03447f3d18479df3d24917a92d768a89f873a7181a064858ea90a804a7538991", size = 13370843, upload-time = "2025-09-10T16:25:09.965Z" }, + { url = "https://files.pythonhosted.org/packages/64/1c/bafdd5a7a05a50cc51d9f5711da704942d8dd62df3d8c70c311e98ce9f8a/ruff-0.13.0-py3-none-manylinux_2_31_riscv64.whl", hash = "sha256:fbc6b1934eb1c0033da427c805e27d164bb713f8e273a024a7e86176d7f462cf", size = 13321891, upload-time = "2025-09-10T16:25:12.969Z" }, + { url = "https://files.pythonhosted.org/packages/bc/3e/7817f989cb9725ef7e8d2cee74186bf90555279e119de50c750c4b7a72fe/ruff-0.13.0-py3-none-musllinux_1_2_aarch64.whl", hash = "sha256:a8ab6a3e03665d39d4a25ee199d207a488724f022db0e1fe4002968abdb8001b", size = 12119119, upload-time = "2025-09-10T16:25:16.621Z" }, + { url = "https://files.pythonhosted.org/packages/58/07/9df080742e8d1080e60c426dce6e96a8faf9a371e2ce22eef662e3839c95/ruff-0.13.0-py3-none-musllinux_1_2_armv7l.whl", hash = "sha256:d2a5c62f8ccc6dd2fe259917482de7275cecc86141ee10432727c4816235bc41", size = 11961594, upload-time = "2025-09-10T16:25:19.49Z" }, + { url = "https://files.pythonhosted.org/packages/6a/f4/ae1185349197d26a2316840cb4d6c3fba61d4ac36ed728bf0228b222d71f/ruff-0.13.0-py3-none-musllinux_1_2_i686.whl", hash = "sha256:b7b85ca27aeeb1ab421bc787009831cffe6048faae08ad80867edab9f2760945", size = 12933377, upload-time = "2025-09-10T16:25:22.371Z" }, + { url = "https://files.pythonhosted.org/packages/b6/39/e776c10a3b349fc8209a905bfb327831d7516f6058339a613a8d2aaecacd/ruff-0.13.0-py3-none-musllinux_1_2_x86_64.whl", hash = "sha256:79ea0c44a3032af768cabfd9616e44c24303af49d633b43e3a5096e009ebe823", size = 13418555, upload-time = "2025-09-10T16:25:25.681Z" }, + { url = "https://files.pythonhosted.org/packages/46/09/dca8df3d48e8b3f4202bf20b1658898e74b6442ac835bfe2c1816d926697/ruff-0.13.0-py3-none-win32.whl", hash = "sha256:4e473e8f0e6a04e4113f2e1de12a5039579892329ecc49958424e5568ef4f768", size = 12141613, upload-time = "2025-09-10T16:25:28.664Z" }, + { url = "https://files.pythonhosted.org/packages/61/21/0647eb71ed99b888ad50e44d8ec65d7148babc0e242d531a499a0bbcda5f/ruff-0.13.0-py3-none-win_amd64.whl", hash = "sha256:48e5c25c7a3713eea9ce755995767f4dcd1b0b9599b638b12946e892123d1efb", size = 13258250, upload-time = "2025-09-10T16:25:31.773Z" }, + { url = "https://files.pythonhosted.org/packages/e1/a3/03216a6a86c706df54422612981fb0f9041dbb452c3401501d4a22b942c9/ruff-0.13.0-py3-none-win_arm64.whl", hash = "sha256:ab80525317b1e1d38614addec8ac954f1b3e662de9d59114ecbf771d00cf613e", size = 12312357, upload-time = "2025-09-10T16:25:35.595Z" }, ] [[package]] From 88655031fffa02e02a780d4ae15725fa62d8c550 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 17:14:56 +0200 Subject: [PATCH 35/71] chore: Remove scikit dependency --- poetry.lock | 218 +------------------------------------------------ pyproject.toml | 1 - uv.lock | 176 --------------------------------------- 3 files changed, 3 insertions(+), 392 deletions(-) diff --git a/poetry.lock b/poetry.lock index 1e16b4ecb..ee8611256 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3867,9 +3867,10 @@ files = [ name = "joblib" version = "1.5.2" description = "Lightweight pipelining with Python functions" -optional = false +optional = true python-versions = ">=3.9" groups = ["main"] +markers = "extra == \"llama-index\" or extra == \"docs\"" files = [ {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, @@ -9579,207 +9580,6 @@ testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2 testingfree = ["huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] torch = ["safetensors[numpy]", "torch (>=1.10)"] -[[package]] -name = "scikit-learn" -version = "1.7.2" -description = "A set of python modules for machine learning and data mining" -optional = false -python-versions = ">=3.10" -groups = ["main"] -files = [ - {file = "scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f"}, - {file = "scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c"}, - {file = "scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8"}, - {file = "scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18"}, - {file = "scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5"}, - {file = "scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e"}, - {file = "scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1"}, - {file = "scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d"}, - {file = "scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1"}, - {file = "scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1"}, - {file = "scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96"}, - {file = "scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476"}, - {file = "scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b"}, - {file = "scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44"}, - {file = "scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290"}, - {file = "scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7"}, - {file = "scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe"}, - {file = "scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f"}, - {file = "scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0"}, - {file = "scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c"}, - {file = "scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973"}, - {file = "scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33"}, - {file = "scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615"}, - {file = "scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106"}, - {file = "scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61"}, - {file = "scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8"}, - {file = "scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda"}, -] - -[package.dependencies] -joblib = ">=1.2.0" -numpy = ">=1.22.0" -scipy = ">=1.8.0" -threadpoolctl = ">=3.1.0" - -[package.extras] -benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] -build = ["cython (>=3.0.10)", "meson-python (>=0.17.1)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] -docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] -examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] -install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] -maintenance = ["conda-lock (==3.0.1)"] -tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] - -[[package]] -name = "scipy" -version = "1.15.3" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = ">=3.10" -groups = ["main"] -markers = "python_version == \"3.10\"" -files = [ - {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, - {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, - {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, - {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, - {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, - {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, - {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, - {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, - {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, - {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, - {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, - {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, - {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, - {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, - {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, - {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, - {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, - {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, - {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, - {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, - {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, - {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, - {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, - {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, - {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, - {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, - {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, - {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, - {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, - {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, - {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, - {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, - {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, - {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, - {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, - {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, - {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, - {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, - {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, - {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, - {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, - {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, - {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, - {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, - {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, - {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, -] - -[package.dependencies] -numpy = ">=1.23.5,<2.5" - -[package.extras] -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 = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] -test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - -[[package]] -name = "scipy" -version = "1.16.2" -description = "Fundamental algorithms for scientific computing in Python" -optional = false -python-versions = ">=3.11" -groups = ["main"] -markers = "python_version >= \"3.11\"" -files = [ - {file = "scipy-1.16.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:6ab88ea43a57da1af33292ebd04b417e8e2eaf9d5aa05700be8d6e1b6501cd92"}, - {file = "scipy-1.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c95e96c7305c96ede73a7389f46ccd6c659c4da5ef1b2789466baeaed3622b6e"}, - {file = "scipy-1.16.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:87eb178db04ece7c698220d523c170125dbffebb7af0345e66c3554f6f60c173"}, - {file = "scipy-1.16.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:4e409eac067dcee96a57fbcf424c13f428037827ec7ee3cb671ff525ca4fc34d"}, - {file = "scipy-1.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e574be127bb760f0dad24ff6e217c80213d153058372362ccb9555a10fc5e8d2"}, - {file = "scipy-1.16.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5db5ba6188d698ba7abab982ad6973265b74bb40a1efe1821b58c87f73892b9"}, - {file = "scipy-1.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec6e74c4e884104ae006d34110677bfe0098203a3fec2f3faf349f4cb05165e3"}, - {file = "scipy-1.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:912f46667d2d3834bc3d57361f854226475f695eb08c08a904aadb1c936b6a88"}, - {file = "scipy-1.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:91e9e8a37befa5a69e9cacbe0bcb79ae5afb4a0b130fd6db6ee6cc0d491695fa"}, - {file = "scipy-1.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:f3bf75a6dcecab62afde4d1f973f1692be013110cad5338007927db8da73249c"}, - {file = "scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d"}, - {file = "scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371"}, - {file = "scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0"}, - {file = "scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232"}, - {file = "scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1"}, - {file = "scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f"}, - {file = "scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef"}, - {file = "scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1"}, - {file = "scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e"}, - {file = "scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851"}, - {file = "scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70"}, - {file = "scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9"}, - {file = "scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5"}, - {file = "scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925"}, - {file = "scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9"}, - {file = "scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7"}, - {file = "scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb"}, - {file = "scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e"}, - {file = "scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c"}, - {file = "scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104"}, - {file = "scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1"}, - {file = "scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a"}, - {file = "scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f"}, - {file = "scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4"}, - {file = "scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21"}, - {file = "scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7"}, - {file = "scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8"}, - {file = "scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472"}, - {file = "scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351"}, - {file = "scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d"}, - {file = "scipy-1.16.2-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:567e77755019bb7461513c87f02bb73fb65b11f049aaaa8ca17cfaa5a5c45d77"}, - {file = "scipy-1.16.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:17d9bb346194e8967296621208fcdfd39b55498ef7d2f376884d5ac47cec1a70"}, - {file = "scipy-1.16.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:0a17541827a9b78b777d33b623a6dcfe2ef4a25806204d08ead0768f4e529a88"}, - {file = "scipy-1.16.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:d7d4c6ba016ffc0f9568d012f5f1eb77ddd99412aea121e6fa8b4c3b7cbad91f"}, - {file = "scipy-1.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9702c4c023227785c779cba2e1d6f7635dbb5b2e0936cdd3a4ecb98d78fd41eb"}, - {file = "scipy-1.16.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1cdf0ac28948d225decdefcc45ad7dd91716c29ab56ef32f8e0d50657dffcc7"}, - {file = "scipy-1.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:70327d6aa572a17c2941cdfb20673f82e536e91850a2e4cb0c5b858b690e1548"}, - {file = "scipy-1.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5221c0b2a4b58aa7c4ed0387d360fd90ee9086d383bb34d9f2789fafddc8a936"}, - {file = "scipy-1.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:f5a85d7b2b708025af08f060a496dd261055b617d776fc05a1a1cc69e09fe9ff"}, - {file = "scipy-1.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:2cc73a33305b4b24556957d5857d6253ce1e2dcd67fa0ff46d87d1670b3e1e1d"}, - {file = "scipy-1.16.2-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:9ea2a3fed83065d77367775d689401a703d0f697420719ee10c0780bcab594d8"}, - {file = "scipy-1.16.2-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7280d926f11ca945c3ef92ba960fa924e1465f8d07ce3a9923080363390624c4"}, - {file = "scipy-1.16.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:8afae1756f6a1fe04636407ef7dbece33d826a5d462b74f3d0eb82deabefd831"}, - {file = "scipy-1.16.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:5c66511f29aa8d233388e7416a3f20d5cae7a2744d5cee2ecd38c081f4e861b3"}, - {file = "scipy-1.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efe6305aeaa0e96b0ccca5ff647a43737d9a092064a3894e46c414db84bc54ac"}, - {file = "scipy-1.16.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f3a337d9ae06a1e8d655ee9d8ecb835ea5ddcdcbd8d23012afa055ab014f374"}, - {file = "scipy-1.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bab3605795d269067d8ce78a910220262711b753de8913d3deeaedb5dded3bb6"}, - {file = "scipy-1.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b0348d8ddb55be2a844c518cd8cc8deeeb8aeba707cf834db5758fc89b476a2c"}, - {file = "scipy-1.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:26284797e38b8a75e14ea6631d29bda11e76ceaa6ddb6fdebbfe4c4d90faf2f9"}, - {file = "scipy-1.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d2a4472c231328d4de38d5f1f68fdd6d28a615138f842580a8a321b5845cf779"}, - {file = "scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b"}, -] - -[package.dependencies] -numpy = ">=1.25.2,<2.6" - -[package.extras] -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 = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] -test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest (>=8.0.0)", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] - [[package]] name = "semver" version = "3.0.4" @@ -10354,18 +10154,6 @@ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] -[[package]] -name = "threadpoolctl" -version = "3.6.0" -description = "threadpoolctl" -optional = false -python-versions = ">=3.9" -groups = ["main"] -files = [ - {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, - {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, -] - [[package]] name = "tiktoken" version = "0.11.0" @@ -11894,4 +11682,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "6d4ead6e6dbff689505852febb754eb5a98de314095d02606ac4921d4d895144" +content-hash = "ba579f479d69c5c5a4c7573b3b60adf6595222e07aa9a48a4997790533fdd574" diff --git a/pyproject.toml b/pyproject.toml index 6addde9a3..81acdd031 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -40,7 +40,6 @@ dependencies = [ "lancedb>=0.24.0,<1.0.0", "nbformat>=5.7.0,<6.0.0", "alembic>=1.13.3,<2", - "scikit-learn>=1.6.1,<2", "limits>=4.4.1,<5", "fastapi>=0.115.7,<1.0.0", "python-multipart>=0.0.20,<1.0.0", diff --git a/uv.lock b/uv.lock index 777ab9702..7bf8e186d 100644 --- a/uv.lock +++ b/uv.lock @@ -849,7 +849,6 @@ dependencies = [ { name = "python-magic-bin", marker = "sys_platform == 'win32'" }, { name = "python-multipart" }, { name = "rdflib" }, - { name = "scikit-learn" }, { name = "sqlalchemy" }, { name = "structlog" }, { name = "tiktoken" }, @@ -1049,7 +1048,6 @@ requires-dist = [ { name = "rdflib", specifier = ">=7.1.4,<7.2.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9.2,<=0.13.1" }, { name = "s3fs", extras = ["boto3"], marker = "extra == 'aws'", specifier = "==2025.3.2" }, - { name = "scikit-learn", specifier = ">=1.6.1,<2" }, { name = "sentry-sdk", extras = ["fastapi"], marker = "extra == 'monitoring'", specifier = ">=2.9.0,<3" }, { name = "sqlalchemy", specifier = ">=2.0.39,<3.0.0" }, { name = "structlog", specifier = ">=25.2.0,<26" }, @@ -6804,171 +6802,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/c3/c0be1135726618dc1e28d181b8c442403d8dbb9e273fd791de2d4384bcdd/safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c", size = 320192, upload-time = "2025-08-08T13:13:59.467Z" }, ] -[[package]] -name = "scikit-learn" -version = "1.7.2" -source = { registry = "https://pypi.org/simple" } -dependencies = [ - { name = "joblib" }, - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, - { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, - { name = "scipy", version = "1.16.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, - { name = "threadpoolctl" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, - { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, - { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, - { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, - { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, - { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, - { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, - { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, - { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, - { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, - { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, - { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, - { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, - { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, - { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, - { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, - { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, - { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, - { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, - { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, - { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, - { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, - { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, - { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, - { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, -] - -[[package]] -name = "scipy" -version = "1.15.3" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version < '3.11' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", - "python_full_version < '3.11' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", - "python_full_version < '3.11' and sys_platform == 'emscripten'", -] -dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, - { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, - { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, - { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, - { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, - { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, - { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, - { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, - { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, - { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, - { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, - { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, - { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, - { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, - { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, - { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, - { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, - { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, - { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, - { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, - { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, - { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, - { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, - { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, - { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, - { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, - { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, - { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, - { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, - { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, - { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, - { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, - { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, - { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, - { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, - { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, - { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, - { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, - { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, - { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, - { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, - { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, - { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, - { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, -] - -[[package]] -name = "scipy" -version = "1.16.2" -source = { registry = "https://pypi.org/simple" } -resolution-markers = [ - "python_full_version >= '3.13' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", - "python_full_version >= '3.13' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", - "python_full_version >= '3.13' and sys_platform == 'emscripten'", - "python_full_version == '3.12.*' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", - "python_full_version == '3.12.*' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", - "python_full_version == '3.12.*' and sys_platform == 'emscripten'", - "python_full_version == '3.11.*' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", - "python_full_version == '3.11.*' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", - "python_full_version == '3.11.*' and sys_platform == 'emscripten'", -] -dependencies = [ - { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, - { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, -] -sdist = { url = "https://files.pythonhosted.org/packages/4c/3b/546a6f0bfe791bbb7f8d591613454d15097e53f906308ec6f7c1ce588e8e/scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b", size = 30580599, upload-time = "2025-09-11T17:48:08.271Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/0b/ef/37ed4b213d64b48422df92560af7300e10fe30b5d665dd79932baebee0c6/scipy-1.16.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:6ab88ea43a57da1af33292ebd04b417e8e2eaf9d5aa05700be8d6e1b6501cd92", size = 36619956, upload-time = "2025-09-11T17:39:20.5Z" }, - { url = "https://files.pythonhosted.org/packages/85/ab/5c2eba89b9416961a982346a4d6a647d78c91ec96ab94ed522b3b6baf444/scipy-1.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c95e96c7305c96ede73a7389f46ccd6c659c4da5ef1b2789466baeaed3622b6e", size = 28931117, upload-time = "2025-09-11T17:39:29.06Z" }, - { url = "https://files.pythonhosted.org/packages/80/d1/eed51ab64d227fe60229a2d57fb60ca5898cfa50ba27d4f573e9e5f0b430/scipy-1.16.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:87eb178db04ece7c698220d523c170125dbffebb7af0345e66c3554f6f60c173", size = 20921997, upload-time = "2025-09-11T17:39:34.892Z" }, - { url = "https://files.pythonhosted.org/packages/be/7c/33ea3e23bbadde96726edba6bf9111fb1969d14d9d477ffa202c67bec9da/scipy-1.16.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:4e409eac067dcee96a57fbcf424c13f428037827ec7ee3cb671ff525ca4fc34d", size = 23523374, upload-time = "2025-09-11T17:39:40.846Z" }, - { url = "https://files.pythonhosted.org/packages/96/0b/7399dc96e1e3f9a05e258c98d716196a34f528eef2ec55aad651ed136d03/scipy-1.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e574be127bb760f0dad24ff6e217c80213d153058372362ccb9555a10fc5e8d2", size = 33583702, upload-time = "2025-09-11T17:39:49.011Z" }, - { url = "https://files.pythonhosted.org/packages/1a/bc/a5c75095089b96ea72c1bd37a4497c24b581ec73db4ef58ebee142ad2d14/scipy-1.16.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5db5ba6188d698ba7abab982ad6973265b74bb40a1efe1821b58c87f73892b9", size = 35883427, upload-time = "2025-09-11T17:39:57.406Z" }, - { url = "https://files.pythonhosted.org/packages/ab/66/e25705ca3d2b87b97fe0a278a24b7f477b4023a926847935a1a71488a6a6/scipy-1.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec6e74c4e884104ae006d34110677bfe0098203a3fec2f3faf349f4cb05165e3", size = 36212940, upload-time = "2025-09-11T17:40:06.013Z" }, - { url = "https://files.pythonhosted.org/packages/d6/fd/0bb911585e12f3abdd603d721d83fc1c7492835e1401a0e6d498d7822b4b/scipy-1.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:912f46667d2d3834bc3d57361f854226475f695eb08c08a904aadb1c936b6a88", size = 38865092, upload-time = "2025-09-11T17:40:15.143Z" }, - { url = "https://files.pythonhosted.org/packages/d6/73/c449a7d56ba6e6f874183759f8483cde21f900a8be117d67ffbb670c2958/scipy-1.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:91e9e8a37befa5a69e9cacbe0bcb79ae5afb4a0b130fd6db6ee6cc0d491695fa", size = 38687626, upload-time = "2025-09-11T17:40:24.041Z" }, - { url = "https://files.pythonhosted.org/packages/68/72/02f37316adf95307f5d9e579023c6899f89ff3a051fa079dbd6faafc48e5/scipy-1.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:f3bf75a6dcecab62afde4d1f973f1692be013110cad5338007927db8da73249c", size = 25503506, upload-time = "2025-09-11T17:40:30.703Z" }, - { url = "https://files.pythonhosted.org/packages/b7/8d/6396e00db1282279a4ddd507c5f5e11f606812b608ee58517ce8abbf883f/scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d", size = 36646259, upload-time = "2025-09-11T17:40:39.329Z" }, - { url = "https://files.pythonhosted.org/packages/3b/93/ea9edd7e193fceb8eef149804491890bde73fb169c896b61aa3e2d1e4e77/scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371", size = 28888976, upload-time = "2025-09-11T17:40:46.82Z" }, - { url = "https://files.pythonhosted.org/packages/91/4d/281fddc3d80fd738ba86fd3aed9202331180b01e2c78eaae0642f22f7e83/scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0", size = 20879905, upload-time = "2025-09-11T17:40:52.545Z" }, - { url = "https://files.pythonhosted.org/packages/69/40/b33b74c84606fd301b2915f0062e45733c6ff5708d121dd0deaa8871e2d0/scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232", size = 23553066, upload-time = "2025-09-11T17:40:59.014Z" }, - { url = "https://files.pythonhosted.org/packages/55/a7/22c739e2f21a42cc8f16bc76b47cff4ed54fbe0962832c589591c2abec34/scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1", size = 33336407, upload-time = "2025-09-11T17:41:06.796Z" }, - { url = "https://files.pythonhosted.org/packages/53/11/a0160990b82999b45874dc60c0c183d3a3a969a563fffc476d5a9995c407/scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f", size = 35673281, upload-time = "2025-09-11T17:41:15.055Z" }, - { url = "https://files.pythonhosted.org/packages/96/53/7ef48a4cfcf243c3d0f1643f5887c81f29fdf76911c4e49331828e19fc0a/scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef", size = 36004222, upload-time = "2025-09-11T17:41:23.868Z" }, - { url = "https://files.pythonhosted.org/packages/49/7f/71a69e0afd460049d41c65c630c919c537815277dfea214031005f474d78/scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1", size = 38664586, upload-time = "2025-09-11T17:41:31.021Z" }, - { url = "https://files.pythonhosted.org/packages/34/95/20e02ca66fb495a95fba0642fd48e0c390d0ece9b9b14c6e931a60a12dea/scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e", size = 38550641, upload-time = "2025-09-11T17:41:36.61Z" }, - { url = "https://files.pythonhosted.org/packages/92/ad/13646b9beb0a95528ca46d52b7babafbe115017814a611f2065ee4e61d20/scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851", size = 25456070, upload-time = "2025-09-11T17:41:41.3Z" }, - { url = "https://files.pythonhosted.org/packages/c1/27/c5b52f1ee81727a9fc457f5ac1e9bf3d6eab311805ea615c83c27ba06400/scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70", size = 36604856, upload-time = "2025-09-11T17:41:47.695Z" }, - { url = "https://files.pythonhosted.org/packages/32/a9/15c20d08e950b540184caa8ced675ba1128accb0e09c653780ba023a4110/scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9", size = 28864626, upload-time = "2025-09-11T17:41:52.642Z" }, - { url = "https://files.pythonhosted.org/packages/4c/fc/ea36098df653cca26062a627c1a94b0de659e97127c8491e18713ca0e3b9/scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5", size = 20855689, upload-time = "2025-09-11T17:41:57.886Z" }, - { url = "https://files.pythonhosted.org/packages/dc/6f/d0b53be55727f3e6d7c72687ec18ea6d0047cf95f1f77488b99a2bafaee1/scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925", size = 23512151, upload-time = "2025-09-11T17:42:02.303Z" }, - { url = "https://files.pythonhosted.org/packages/11/85/bf7dab56e5c4b1d3d8eef92ca8ede788418ad38a7dc3ff50262f00808760/scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9", size = 33329824, upload-time = "2025-09-11T17:42:07.549Z" }, - { url = "https://files.pythonhosted.org/packages/da/6a/1a927b14ddc7714111ea51f4e568203b2bb6ed59bdd036d62127c1a360c8/scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7", size = 35681881, upload-time = "2025-09-11T17:42:13.255Z" }, - { url = "https://files.pythonhosted.org/packages/c1/5f/331148ea5780b4fcc7007a4a6a6ee0a0c1507a796365cc642d4d226e1c3a/scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb", size = 36006219, upload-time = "2025-09-11T17:42:18.765Z" }, - { url = "https://files.pythonhosted.org/packages/46/3a/e991aa9d2aec723b4a8dcfbfc8365edec5d5e5f9f133888067f1cbb7dfc1/scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e", size = 38682147, upload-time = "2025-09-11T17:42:25.177Z" }, - { url = "https://files.pythonhosted.org/packages/a1/57/0f38e396ad19e41b4c5db66130167eef8ee620a49bc7d0512e3bb67e0cab/scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c", size = 38520766, upload-time = "2025-09-11T17:43:25.342Z" }, - { url = "https://files.pythonhosted.org/packages/1b/a5/85d3e867b6822d331e26c862a91375bb7746a0b458db5effa093d34cdb89/scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104", size = 25451169, upload-time = "2025-09-11T17:43:30.198Z" }, - { url = "https://files.pythonhosted.org/packages/09/d9/60679189bcebda55992d1a45498de6d080dcaf21ce0c8f24f888117e0c2d/scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1", size = 37012682, upload-time = "2025-09-11T17:42:30.677Z" }, - { url = "https://files.pythonhosted.org/packages/83/be/a99d13ee4d3b7887a96f8c71361b9659ba4ef34da0338f14891e102a127f/scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a", size = 29389926, upload-time = "2025-09-11T17:42:35.845Z" }, - { url = "https://files.pythonhosted.org/packages/bf/0a/130164a4881cec6ca8c00faf3b57926f28ed429cd6001a673f83c7c2a579/scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f", size = 21381152, upload-time = "2025-09-11T17:42:40.07Z" }, - { url = "https://files.pythonhosted.org/packages/47/a6/503ffb0310ae77fba874e10cddfc4a1280bdcca1d13c3751b8c3c2996cf8/scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4", size = 23914410, upload-time = "2025-09-11T17:42:44.313Z" }, - { url = "https://files.pythonhosted.org/packages/fa/c7/1147774bcea50d00c02600aadaa919facbd8537997a62496270133536ed6/scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21", size = 33481880, upload-time = "2025-09-11T17:42:49.325Z" }, - { url = "https://files.pythonhosted.org/packages/6a/74/99d5415e4c3e46b2586f30cdbecb95e101c7192628a484a40dd0d163811a/scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7", size = 35791425, upload-time = "2025-09-11T17:42:54.711Z" }, - { url = "https://files.pythonhosted.org/packages/1b/ee/a6559de7c1cc710e938c0355d9d4fbcd732dac4d0d131959d1f3b63eb29c/scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8", size = 36178622, upload-time = "2025-09-11T17:43:00.375Z" }, - { url = "https://files.pythonhosted.org/packages/4e/7b/f127a5795d5ba8ece4e0dce7d4a9fb7cb9e4f4757137757d7a69ab7d4f1a/scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472", size = 38783985, upload-time = "2025-09-11T17:43:06.661Z" }, - { url = "https://files.pythonhosted.org/packages/3e/9f/bc81c1d1e033951eb5912cd3750cc005943afa3e65a725d2443a3b3c4347/scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351", size = 38631367, upload-time = "2025-09-11T17:43:14.44Z" }, - { url = "https://files.pythonhosted.org/packages/d6/5e/2cc7555fd81d01814271412a1d59a289d25f8b63208a0a16c21069d55d3e/scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d", size = 25787992, upload-time = "2025-09-11T17:43:19.745Z" }, -] - [[package]] name = "semver" version = "3.0.4" @@ -7287,15 +7120,6 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, ] -[[package]] -name = "threadpoolctl" -version = "3.6.0" -source = { registry = "https://pypi.org/simple" } -sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } -wheels = [ - { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, -] - [[package]] name = "tiktoken" version = "0.11.0" From f2edfaa9b9a5a963458b1b206b79eb7c8bbd9c80 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 17:23:14 +0200 Subject: [PATCH 36/71] refactor: Add scikit learn for evals --- poetry.lock | 221 ++++++++++++++++++++++++++++++++++++++++++++++++- pyproject.toml | 1 + uv.lock | 176 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 395 insertions(+), 3 deletions(-) diff --git a/poetry.lock b/poetry.lock index ee8611256..3e5b68ccf 100644 --- a/poetry.lock +++ b/poetry.lock @@ -3870,7 +3870,7 @@ description = "Lightweight pipelining with Python functions" optional = true python-versions = ">=3.9" groups = ["main"] -markers = "extra == \"llama-index\" or extra == \"docs\"" +markers = "extra == \"llama-index\" or extra == \"docs\" or extra == \"evals\"" files = [ {file = "joblib-1.5.2-py3-none-any.whl", hash = "sha256:4e1f0bdbb987e6d843c70cf43714cb276623def372df3c22fe5266b2670bc241"}, {file = "joblib-1.5.2.tar.gz", hash = "sha256:3faa5c39054b2f03ca547da9b2f52fde67c06240c31853f306aea97f13647b55"}, @@ -9580,6 +9580,208 @@ testing = ["h5py (>=3.7.0)", "huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2 testingfree = ["huggingface-hub (>=0.12.1)", "hypothesis (>=6.70.2)", "pytest (>=7.2.0)", "pytest-benchmark (>=4.0.0)", "safetensors[numpy]", "setuptools-rust (>=1.5.2)"] torch = ["safetensors[numpy]", "torch (>=1.10)"] +[[package]] +name = "scikit-learn" +version = "1.7.2" +description = "A set of python modules for machine learning and data mining" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "extra == \"evals\"" +files = [ + {file = "scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f"}, + {file = "scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c"}, + {file = "scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8"}, + {file = "scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18"}, + {file = "scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5"}, + {file = "scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e"}, + {file = "scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1"}, + {file = "scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d"}, + {file = "scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1"}, + {file = "scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1"}, + {file = "scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96"}, + {file = "scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476"}, + {file = "scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b"}, + {file = "scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44"}, + {file = "scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290"}, + {file = "scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7"}, + {file = "scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe"}, + {file = "scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f"}, + {file = "scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0"}, + {file = "scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c"}, + {file = "scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973"}, + {file = "scikit_learn-1.7.2-cp314-cp314-macosx_10_13_x86_64.whl", hash = "sha256:fa8f63940e29c82d1e67a45d5297bdebbcb585f5a5a50c4914cc2e852ab77f33"}, + {file = "scikit_learn-1.7.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:f95dc55b7902b91331fa4e5845dd5bde0580c9cd9612b1b2791b7e80c3d32615"}, + {file = "scikit_learn-1.7.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:9656e4a53e54578ad10a434dc1f993330568cfee176dff07112b8785fb413106"}, + {file = "scikit_learn-1.7.2-cp314-cp314-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:96dc05a854add0e50d3f47a1ef21a10a595016da5b007c7d9cd9d0bffd1fcc61"}, + {file = "scikit_learn-1.7.2-cp314-cp314-win_amd64.whl", hash = "sha256:bb24510ed3f9f61476181e4db51ce801e2ba37541def12dc9333b946fc7a9cf8"}, + {file = "scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda"}, +] + +[package.dependencies] +joblib = ">=1.2.0" +numpy = ">=1.22.0" +scipy = ">=1.8.0" +threadpoolctl = ">=3.1.0" + +[package.extras] +benchmark = ["matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "pandas (>=1.4.0)"] +build = ["cython (>=3.0.10)", "meson-python (>=0.17.1)", "numpy (>=1.22.0)", "scipy (>=1.8.0)"] +docs = ["Pillow (>=8.4.0)", "matplotlib (>=3.5.0)", "memory_profiler (>=0.57.0)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pydata-sphinx-theme (>=0.15.3)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)", "sphinx (>=7.3.7)", "sphinx-copybutton (>=0.5.2)", "sphinx-design (>=0.5.0)", "sphinx-design (>=0.6.0)", "sphinx-gallery (>=0.17.1)", "sphinx-prompt (>=1.4.0)", "sphinx-remove-toctrees (>=1.0.0.post1)", "sphinxcontrib-sass (>=0.3.4)", "sphinxext-opengraph (>=0.9.1)", "towncrier (>=24.8.0)"] +examples = ["matplotlib (>=3.5.0)", "pandas (>=1.4.0)", "plotly (>=5.14.0)", "pooch (>=1.6.0)", "scikit-image (>=0.19.0)", "seaborn (>=0.9.0)"] +install = ["joblib (>=1.2.0)", "numpy (>=1.22.0)", "scipy (>=1.8.0)", "threadpoolctl (>=3.1.0)"] +maintenance = ["conda-lock (==3.0.1)"] +tests = ["matplotlib (>=3.5.0)", "mypy (>=1.15)", "numpydoc (>=1.2.0)", "pandas (>=1.4.0)", "polars (>=0.20.30)", "pooch (>=1.6.0)", "pyamg (>=4.2.1)", "pyarrow (>=12.0.0)", "pytest (>=7.1.2)", "pytest-cov (>=2.9.0)", "ruff (>=0.11.7)", "scikit-image (>=0.19.0)"] + +[[package]] +name = "scipy" +version = "1.15.3" +description = "Fundamental algorithms for scientific computing in Python" +optional = true +python-versions = ">=3.10" +groups = ["main"] +markers = "python_version == \"3.10\" and extra == \"evals\"" +files = [ + {file = "scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f"}, + {file = "scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82"}, + {file = "scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e"}, + {file = "scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c"}, + {file = "scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65"}, + {file = "scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889"}, + {file = "scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9"}, + {file = "scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594"}, + {file = "scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477"}, + {file = "scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45"}, + {file = "scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e"}, + {file = "scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539"}, + {file = "scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb"}, + {file = "scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825"}, + {file = "scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11"}, + {file = "scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126"}, + {file = "scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e"}, + {file = "scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723"}, + {file = "scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4"}, + {file = "scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5"}, + {file = "scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca"}, + {file = "scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf"}, +] + +[package.dependencies] +numpy = ">=1.23.5,<2.5" + +[package.extras] +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 = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "matplotlib (>=3.5)", "myst-nb", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.0.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.0,<2.1.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + +[[package]] +name = "scipy" +version = "1.16.2" +description = "Fundamental algorithms for scientific computing in Python" +optional = true +python-versions = ">=3.11" +groups = ["main"] +markers = "python_version >= \"3.11\" and extra == \"evals\"" +files = [ + {file = "scipy-1.16.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:6ab88ea43a57da1af33292ebd04b417e8e2eaf9d5aa05700be8d6e1b6501cd92"}, + {file = "scipy-1.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c95e96c7305c96ede73a7389f46ccd6c659c4da5ef1b2789466baeaed3622b6e"}, + {file = "scipy-1.16.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:87eb178db04ece7c698220d523c170125dbffebb7af0345e66c3554f6f60c173"}, + {file = "scipy-1.16.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:4e409eac067dcee96a57fbcf424c13f428037827ec7ee3cb671ff525ca4fc34d"}, + {file = "scipy-1.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e574be127bb760f0dad24ff6e217c80213d153058372362ccb9555a10fc5e8d2"}, + {file = "scipy-1.16.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5db5ba6188d698ba7abab982ad6973265b74bb40a1efe1821b58c87f73892b9"}, + {file = "scipy-1.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec6e74c4e884104ae006d34110677bfe0098203a3fec2f3faf349f4cb05165e3"}, + {file = "scipy-1.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:912f46667d2d3834bc3d57361f854226475f695eb08c08a904aadb1c936b6a88"}, + {file = "scipy-1.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:91e9e8a37befa5a69e9cacbe0bcb79ae5afb4a0b130fd6db6ee6cc0d491695fa"}, + {file = "scipy-1.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:f3bf75a6dcecab62afde4d1f973f1692be013110cad5338007927db8da73249c"}, + {file = "scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d"}, + {file = "scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371"}, + {file = "scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0"}, + {file = "scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232"}, + {file = "scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1"}, + {file = "scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f"}, + {file = "scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef"}, + {file = "scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1"}, + {file = "scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e"}, + {file = "scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851"}, + {file = "scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70"}, + {file = "scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9"}, + {file = "scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5"}, + {file = "scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925"}, + {file = "scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9"}, + {file = "scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7"}, + {file = "scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb"}, + {file = "scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e"}, + {file = "scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c"}, + {file = "scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104"}, + {file = "scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1"}, + {file = "scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a"}, + {file = "scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f"}, + {file = "scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4"}, + {file = "scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21"}, + {file = "scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7"}, + {file = "scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8"}, + {file = "scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472"}, + {file = "scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351"}, + {file = "scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d"}, + {file = "scipy-1.16.2-cp314-cp314-macosx_10_14_x86_64.whl", hash = "sha256:567e77755019bb7461513c87f02bb73fb65b11f049aaaa8ca17cfaa5a5c45d77"}, + {file = "scipy-1.16.2-cp314-cp314-macosx_12_0_arm64.whl", hash = "sha256:17d9bb346194e8967296621208fcdfd39b55498ef7d2f376884d5ac47cec1a70"}, + {file = "scipy-1.16.2-cp314-cp314-macosx_14_0_arm64.whl", hash = "sha256:0a17541827a9b78b777d33b623a6dcfe2ef4a25806204d08ead0768f4e529a88"}, + {file = "scipy-1.16.2-cp314-cp314-macosx_14_0_x86_64.whl", hash = "sha256:d7d4c6ba016ffc0f9568d012f5f1eb77ddd99412aea121e6fa8b4c3b7cbad91f"}, + {file = "scipy-1.16.2-cp314-cp314-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:9702c4c023227785c779cba2e1d6f7635dbb5b2e0936cdd3a4ecb98d78fd41eb"}, + {file = "scipy-1.16.2-cp314-cp314-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:d1cdf0ac28948d225decdefcc45ad7dd91716c29ab56ef32f8e0d50657dffcc7"}, + {file = "scipy-1.16.2-cp314-cp314-musllinux_1_2_aarch64.whl", hash = "sha256:70327d6aa572a17c2941cdfb20673f82e536e91850a2e4cb0c5b858b690e1548"}, + {file = "scipy-1.16.2-cp314-cp314-musllinux_1_2_x86_64.whl", hash = "sha256:5221c0b2a4b58aa7c4ed0387d360fd90ee9086d383bb34d9f2789fafddc8a936"}, + {file = "scipy-1.16.2-cp314-cp314-win_amd64.whl", hash = "sha256:f5a85d7b2b708025af08f060a496dd261055b617d776fc05a1a1cc69e09fe9ff"}, + {file = "scipy-1.16.2-cp314-cp314-win_arm64.whl", hash = "sha256:2cc73a33305b4b24556957d5857d6253ce1e2dcd67fa0ff46d87d1670b3e1e1d"}, + {file = "scipy-1.16.2-cp314-cp314t-macosx_10_14_x86_64.whl", hash = "sha256:9ea2a3fed83065d77367775d689401a703d0f697420719ee10c0780bcab594d8"}, + {file = "scipy-1.16.2-cp314-cp314t-macosx_12_0_arm64.whl", hash = "sha256:7280d926f11ca945c3ef92ba960fa924e1465f8d07ce3a9923080363390624c4"}, + {file = "scipy-1.16.2-cp314-cp314t-macosx_14_0_arm64.whl", hash = "sha256:8afae1756f6a1fe04636407ef7dbece33d826a5d462b74f3d0eb82deabefd831"}, + {file = "scipy-1.16.2-cp314-cp314t-macosx_14_0_x86_64.whl", hash = "sha256:5c66511f29aa8d233388e7416a3f20d5cae7a2744d5cee2ecd38c081f4e861b3"}, + {file = "scipy-1.16.2-cp314-cp314t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:efe6305aeaa0e96b0ccca5ff647a43737d9a092064a3894e46c414db84bc54ac"}, + {file = "scipy-1.16.2-cp314-cp314t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7f3a337d9ae06a1e8d655ee9d8ecb835ea5ddcdcbd8d23012afa055ab014f374"}, + {file = "scipy-1.16.2-cp314-cp314t-musllinux_1_2_aarch64.whl", hash = "sha256:bab3605795d269067d8ce78a910220262711b753de8913d3deeaedb5dded3bb6"}, + {file = "scipy-1.16.2-cp314-cp314t-musllinux_1_2_x86_64.whl", hash = "sha256:b0348d8ddb55be2a844c518cd8cc8deeeb8aeba707cf834db5758fc89b476a2c"}, + {file = "scipy-1.16.2-cp314-cp314t-win_amd64.whl", hash = "sha256:26284797e38b8a75e14ea6631d29bda11e76ceaa6ddb6fdebbfe4c4d90faf2f9"}, + {file = "scipy-1.16.2-cp314-cp314t-win_arm64.whl", hash = "sha256:d2a4472c231328d4de38d5f1f68fdd6d28a615138f842580a8a321b5845cf779"}, + {file = "scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b"}, +] + +[package.dependencies] +numpy = ">=1.25.2,<2.6" + +[package.extras] +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 = ["intersphinx_registry", "jupyterlite-pyodide-kernel", "jupyterlite-sphinx (>=0.19.1)", "jupytext", "linkify-it-py", "matplotlib (>=3.5)", "myst-nb (>=1.2.0)", "numpydoc", "pooch", "pydata-sphinx-theme (>=0.15.2)", "sphinx (>=5.0.0,<8.2.0)", "sphinx-copybutton", "sphinx-design (>=0.4.0)"] +test = ["Cython", "array-api-strict (>=2.3.1)", "asv", "gmpy2", "hypothesis (>=6.30)", "meson", "mpmath", "ninja ; sys_platform != \"emscripten\"", "pooch", "pytest (>=8.0.0)", "pytest-cov", "pytest-timeout", "pytest-xdist", "scikit-umfpack", "threadpoolctl"] + [[package]] name = "semver" version = "3.0.4" @@ -10154,6 +10356,19 @@ docs = ["myst-parser", "pydata-sphinx-theme", "sphinx"] test = ["pre-commit", "pytest (>=7.0)", "pytest-timeout"] typing = ["mypy (>=1.6,<2.0)", "traitlets (>=5.11.1)"] +[[package]] +name = "threadpoolctl" +version = "3.6.0" +description = "threadpoolctl" +optional = true +python-versions = ">=3.9" +groups = ["main"] +markers = "extra == \"evals\"" +files = [ + {file = "threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb"}, + {file = "threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e"}, +] + [[package]] name = "tiktoken" version = "0.11.0" @@ -11661,7 +11876,7 @@ dev = ["coverage", "deptry", "gitpython", "mkdocs-material", "mkdocs-minify-plug distributed = ["modal"] dlt = ["dlt"] docs = ["unstructured"] -evals = ["gdown", "matplotlib", "pandas", "plotly"] +evals = ["gdown", "matplotlib", "pandas", "plotly", "scikit-learn"] falkordb = ["falkordb"] gemini = ["google-generativeai"] graphiti = ["graphiti-core"] @@ -11682,4 +11897,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "ba579f479d69c5c5a4c7573b3b60adf6595222e07aa9a48a4997790533fdd574" +content-hash = "463d131171a4b57481f20ffad9ff98b1a5a08a2b6a64ac51fb65e54d20765e89" diff --git a/pyproject.toml b/pyproject.toml index 81acdd031..549c297b9 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -107,6 +107,7 @@ evals = [ "gdown>=5.2.0,<6", "pandas>=2.2.2,<3.0.0", "matplotlib>=3.8.3,<4", + "scikit-learn>=1.6.1,<2", ] graphiti = ["graphiti-core>=0.7.0,<0.8"] diff --git a/uv.lock b/uv.lock index 7bf8e186d..5d9e4042a 100644 --- a/uv.lock +++ b/uv.lock @@ -914,6 +914,7 @@ evals = [ { name = "matplotlib" }, { name = "pandas" }, { name = "plotly" }, + { name = "scikit-learn" }, ] falkordb = [ { name = "falkordb" }, @@ -1048,6 +1049,7 @@ requires-dist = [ { name = "rdflib", specifier = ">=7.1.4,<7.2.0" }, { name = "ruff", marker = "extra == 'dev'", specifier = ">=0.9.2,<=0.13.1" }, { name = "s3fs", extras = ["boto3"], marker = "extra == 'aws'", specifier = "==2025.3.2" }, + { name = "scikit-learn", marker = "extra == 'evals'", specifier = ">=1.6.1,<2" }, { name = "sentry-sdk", extras = ["fastapi"], marker = "extra == 'monitoring'", specifier = ">=2.9.0,<3" }, { name = "sqlalchemy", specifier = ">=2.0.39,<3.0.0" }, { name = "structlog", specifier = ">=25.2.0,<26" }, @@ -6802,6 +6804,171 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/2c/c3/c0be1135726618dc1e28d181b8c442403d8dbb9e273fd791de2d4384bcdd/safetensors-0.6.2-cp38-abi3-win_amd64.whl", hash = "sha256:c7b214870df923cbc1593c3faee16bec59ea462758699bd3fee399d00aac072c", size = 320192, upload-time = "2025-08-08T13:13:59.467Z" }, ] +[[package]] +name = "scikit-learn" +version = "1.7.2" +source = { registry = "https://pypi.org/simple" } +dependencies = [ + { name = "joblib" }, + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.12'" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, + { name = "scipy", version = "1.15.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, + { name = "scipy", version = "1.16.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.11'" }, + { name = "threadpoolctl" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/98/c2/a7855e41c9d285dfe86dc50b250978105dce513d6e459ea66a6aeb0e1e0c/scikit_learn-1.7.2.tar.gz", hash = "sha256:20e9e49ecd130598f1ca38a1d85090e1a600147b9c02fa6f15d69cb53d968fda", size = 7193136, upload-time = "2025-09-09T08:21:29.075Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/ba/3e/daed796fd69cce768b8788401cc464ea90b306fb196ae1ffed0b98182859/scikit_learn-1.7.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:6b33579c10a3081d076ab403df4a4190da4f4432d443521674637677dc91e61f", size = 9336221, upload-time = "2025-09-09T08:20:19.328Z" }, + { url = "https://files.pythonhosted.org/packages/1c/ce/af9d99533b24c55ff4e18d9b7b4d9919bbc6cd8f22fe7a7be01519a347d5/scikit_learn-1.7.2-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:36749fb62b3d961b1ce4fedf08fa57a1986cd409eff2d783bca5d4b9b5fce51c", size = 8653834, upload-time = "2025-09-09T08:20:22.073Z" }, + { url = "https://files.pythonhosted.org/packages/58/0e/8c2a03d518fb6bd0b6b0d4b114c63d5f1db01ff0f9925d8eb10960d01c01/scikit_learn-1.7.2-cp310-cp310-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:7a58814265dfc52b3295b1900cfb5701589d30a8bb026c7540f1e9d3499d5ec8", size = 9660938, upload-time = "2025-09-09T08:20:24.327Z" }, + { url = "https://files.pythonhosted.org/packages/2b/75/4311605069b5d220e7cf5adabb38535bd96f0079313cdbb04b291479b22a/scikit_learn-1.7.2-cp310-cp310-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:4a847fea807e278f821a0406ca01e387f97653e284ecbd9750e3ee7c90347f18", size = 9477818, upload-time = "2025-09-09T08:20:26.845Z" }, + { url = "https://files.pythonhosted.org/packages/7f/9b/87961813c34adbca21a6b3f6b2bea344c43b30217a6d24cc437c6147f3e8/scikit_learn-1.7.2-cp310-cp310-win_amd64.whl", hash = "sha256:ca250e6836d10e6f402436d6463d6c0e4d8e0234cfb6a9a47835bd392b852ce5", size = 8886969, upload-time = "2025-09-09T08:20:29.329Z" }, + { url = "https://files.pythonhosted.org/packages/43/83/564e141eef908a5863a54da8ca342a137f45a0bfb71d1d79704c9894c9d1/scikit_learn-1.7.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:c7509693451651cd7361d30ce4e86a1347493554f172b1c72a39300fa2aea79e", size = 9331967, upload-time = "2025-09-09T08:20:32.421Z" }, + { url = "https://files.pythonhosted.org/packages/18/d6/ba863a4171ac9d7314c4d3fc251f015704a2caeee41ced89f321c049ed83/scikit_learn-1.7.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:0486c8f827c2e7b64837c731c8feff72c0bd2b998067a8a9cbc10643c31f0fe1", size = 8648645, upload-time = "2025-09-09T08:20:34.436Z" }, + { url = "https://files.pythonhosted.org/packages/ef/0e/97dbca66347b8cf0ea8b529e6bb9367e337ba2e8be0ef5c1a545232abfde/scikit_learn-1.7.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:89877e19a80c7b11a2891a27c21c4894fb18e2c2e077815bcade10d34287b20d", size = 9715424, upload-time = "2025-09-09T08:20:36.776Z" }, + { url = "https://files.pythonhosted.org/packages/f7/32/1f3b22e3207e1d2c883a7e09abb956362e7d1bd2f14458c7de258a26ac15/scikit_learn-1.7.2-cp311-cp311-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:8da8bf89d4d79aaec192d2bda62f9b56ae4e5b4ef93b6a56b5de4977e375c1f1", size = 9509234, upload-time = "2025-09-09T08:20:38.957Z" }, + { url = "https://files.pythonhosted.org/packages/9f/71/34ddbd21f1da67c7a768146968b4d0220ee6831e4bcbad3e03dd3eae88b6/scikit_learn-1.7.2-cp311-cp311-win_amd64.whl", hash = "sha256:9b7ed8d58725030568523e937c43e56bc01cadb478fc43c042a9aca1dacb3ba1", size = 8894244, upload-time = "2025-09-09T08:20:41.166Z" }, + { url = "https://files.pythonhosted.org/packages/a7/aa/3996e2196075689afb9fce0410ebdb4a09099d7964d061d7213700204409/scikit_learn-1.7.2-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:8d91a97fa2b706943822398ab943cde71858a50245e31bc71dba62aab1d60a96", size = 9259818, upload-time = "2025-09-09T08:20:43.19Z" }, + { url = "https://files.pythonhosted.org/packages/43/5d/779320063e88af9c4a7c2cf463ff11c21ac9c8bd730c4a294b0000b666c9/scikit_learn-1.7.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:acbc0f5fd2edd3432a22c69bed78e837c70cf896cd7993d71d51ba6708507476", size = 8636997, upload-time = "2025-09-09T08:20:45.468Z" }, + { url = "https://files.pythonhosted.org/packages/5c/d0/0c577d9325b05594fdd33aa970bf53fb673f051a45496842caee13cfd7fe/scikit_learn-1.7.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:e5bf3d930aee75a65478df91ac1225ff89cd28e9ac7bd1196853a9229b6adb0b", size = 9478381, upload-time = "2025-09-09T08:20:47.982Z" }, + { url = "https://files.pythonhosted.org/packages/82/70/8bf44b933837ba8494ca0fc9a9ab60f1c13b062ad0197f60a56e2fc4c43e/scikit_learn-1.7.2-cp312-cp312-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:b4d6e9deed1a47aca9fe2f267ab8e8fe82ee20b4526b2c0cd9e135cea10feb44", size = 9300296, upload-time = "2025-09-09T08:20:50.366Z" }, + { url = "https://files.pythonhosted.org/packages/c6/99/ed35197a158f1fdc2fe7c3680e9c70d0128f662e1fee4ed495f4b5e13db0/scikit_learn-1.7.2-cp312-cp312-win_amd64.whl", hash = "sha256:6088aa475f0785e01bcf8529f55280a3d7d298679f50c0bb70a2364a82d0b290", size = 8731256, upload-time = "2025-09-09T08:20:52.627Z" }, + { url = "https://files.pythonhosted.org/packages/ae/93/a3038cb0293037fd335f77f31fe053b89c72f17b1c8908c576c29d953e84/scikit_learn-1.7.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:0b7dacaa05e5d76759fb071558a8b5130f4845166d88654a0f9bdf3eb57851b7", size = 9212382, upload-time = "2025-09-09T08:20:54.731Z" }, + { url = "https://files.pythonhosted.org/packages/40/dd/9a88879b0c1104259136146e4742026b52df8540c39fec21a6383f8292c7/scikit_learn-1.7.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:abebbd61ad9e1deed54cca45caea8ad5f79e1b93173dece40bb8e0c658dbe6fe", size = 8592042, upload-time = "2025-09-09T08:20:57.313Z" }, + { url = "https://files.pythonhosted.org/packages/46/af/c5e286471b7d10871b811b72ae794ac5fe2989c0a2df07f0ec723030f5f5/scikit_learn-1.7.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:502c18e39849c0ea1a5d681af1dbcf15f6cce601aebb657aabbfe84133c1907f", size = 9434180, upload-time = "2025-09-09T08:20:59.671Z" }, + { url = "https://files.pythonhosted.org/packages/f1/fd/df59faa53312d585023b2da27e866524ffb8faf87a68516c23896c718320/scikit_learn-1.7.2-cp313-cp313-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:7a4c328a71785382fe3fe676a9ecf2c86189249beff90bf85e22bdb7efaf9ae0", size = 9283660, upload-time = "2025-09-09T08:21:01.71Z" }, + { url = "https://files.pythonhosted.org/packages/a7/c7/03000262759d7b6f38c836ff9d512f438a70d8a8ddae68ee80de72dcfb63/scikit_learn-1.7.2-cp313-cp313-win_amd64.whl", hash = "sha256:63a9afd6f7b229aad94618c01c252ce9e6fa97918c5ca19c9a17a087d819440c", size = 8702057, upload-time = "2025-09-09T08:21:04.234Z" }, + { url = "https://files.pythonhosted.org/packages/55/87/ef5eb1f267084532c8e4aef98a28b6ffe7425acbfd64b5e2f2e066bc29b3/scikit_learn-1.7.2-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:9acb6c5e867447b4e1390930e3944a005e2cb115922e693c08a323421a6966e8", size = 9558731, upload-time = "2025-09-09T08:21:06.381Z" }, + { url = "https://files.pythonhosted.org/packages/93/f8/6c1e3fc14b10118068d7938878a9f3f4e6d7b74a8ddb1e5bed65159ccda8/scikit_learn-1.7.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:2a41e2a0ef45063e654152ec9d8bcfc39f7afce35b08902bfe290c2498a67a6a", size = 9038852, upload-time = "2025-09-09T08:21:08.628Z" }, + { url = "https://files.pythonhosted.org/packages/83/87/066cafc896ee540c34becf95d30375fe5cbe93c3b75a0ee9aa852cd60021/scikit_learn-1.7.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:98335fb98509b73385b3ab2bd0639b1f610541d3988ee675c670371d6a87aa7c", size = 9527094, upload-time = "2025-09-09T08:21:11.486Z" }, + { url = "https://files.pythonhosted.org/packages/9c/2b/4903e1ccafa1f6453b1ab78413938c8800633988c838aa0be386cbb33072/scikit_learn-1.7.2-cp313-cp313t-manylinux_2_27_aarch64.manylinux_2_28_aarch64.whl", hash = "sha256:191e5550980d45449126e23ed1d5e9e24b2c68329ee1f691a3987476e115e09c", size = 9367436, upload-time = "2025-09-09T08:21:13.602Z" }, + { url = "https://files.pythonhosted.org/packages/b5/aa/8444be3cfb10451617ff9d177b3c190288f4563e6c50ff02728be67ad094/scikit_learn-1.7.2-cp313-cp313t-win_amd64.whl", hash = "sha256:57dc4deb1d3762c75d685507fbd0bc17160144b2f2ba4ccea5dc285ab0d0e973", size = 9275749, upload-time = "2025-09-09T08:21:15.96Z" }, +] + +[[package]] +name = "scipy" +version = "1.15.3" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version < '3.11' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", + "python_full_version < '3.11' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", + "python_full_version < '3.11' and sys_platform == 'emscripten'", +] +dependencies = [ + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.11'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/0f/37/6964b830433e654ec7485e45a00fc9a27cf868d622838f6b6d9c5ec0d532/scipy-1.15.3.tar.gz", hash = "sha256:eae3cf522bc7df64b42cad3925c876e1b0b6c35c1337c93e12c0f366f55b0eaf", size = 59419214, upload-time = "2025-05-08T16:13:05.955Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/78/2f/4966032c5f8cc7e6a60f1b2e0ad686293b9474b65246b0c642e3ef3badd0/scipy-1.15.3-cp310-cp310-macosx_10_13_x86_64.whl", hash = "sha256:a345928c86d535060c9c2b25e71e87c39ab2f22fc96e9636bd74d1dbf9de448c", size = 38702770, upload-time = "2025-05-08T16:04:20.849Z" }, + { url = "https://files.pythonhosted.org/packages/a0/6e/0c3bf90fae0e910c274db43304ebe25a6b391327f3f10b5dcc638c090795/scipy-1.15.3-cp310-cp310-macosx_12_0_arm64.whl", hash = "sha256:ad3432cb0f9ed87477a8d97f03b763fd1d57709f1bbde3c9369b1dff5503b253", size = 30094511, upload-time = "2025-05-08T16:04:27.103Z" }, + { url = "https://files.pythonhosted.org/packages/ea/b1/4deb37252311c1acff7f101f6453f0440794f51b6eacb1aad4459a134081/scipy-1.15.3-cp310-cp310-macosx_14_0_arm64.whl", hash = "sha256:aef683a9ae6eb00728a542b796f52a5477b78252edede72b8327a886ab63293f", size = 22368151, upload-time = "2025-05-08T16:04:31.731Z" }, + { url = "https://files.pythonhosted.org/packages/38/7d/f457626e3cd3c29b3a49ca115a304cebb8cc6f31b04678f03b216899d3c6/scipy-1.15.3-cp310-cp310-macosx_14_0_x86_64.whl", hash = "sha256:1c832e1bd78dea67d5c16f786681b28dd695a8cb1fb90af2e27580d3d0967e92", size = 25121732, upload-time = "2025-05-08T16:04:36.596Z" }, + { url = "https://files.pythonhosted.org/packages/db/0a/92b1de4a7adc7a15dcf5bddc6e191f6f29ee663b30511ce20467ef9b82e4/scipy-1.15.3-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:263961f658ce2165bbd7b99fa5135195c3a12d9bef045345016b8b50c315cb82", size = 35547617, upload-time = "2025-05-08T16:04:43.546Z" }, + { url = "https://files.pythonhosted.org/packages/8e/6d/41991e503e51fc1134502694c5fa7a1671501a17ffa12716a4a9151af3df/scipy-1.15.3-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9e2abc762b0811e09a0d3258abee2d98e0c703eee49464ce0069590846f31d40", size = 37662964, upload-time = "2025-05-08T16:04:49.431Z" }, + { url = "https://files.pythonhosted.org/packages/25/e1/3df8f83cb15f3500478c889be8fb18700813b95e9e087328230b98d547ff/scipy-1.15.3-cp310-cp310-musllinux_1_2_aarch64.whl", hash = "sha256:ed7284b21a7a0c8f1b6e5977ac05396c0d008b89e05498c8b7e8f4a1423bba0e", size = 37238749, upload-time = "2025-05-08T16:04:55.215Z" }, + { url = "https://files.pythonhosted.org/packages/93/3e/b3257cf446f2a3533ed7809757039016b74cd6f38271de91682aa844cfc5/scipy-1.15.3-cp310-cp310-musllinux_1_2_x86_64.whl", hash = "sha256:5380741e53df2c566f4d234b100a484b420af85deb39ea35a1cc1be84ff53a5c", size = 40022383, upload-time = "2025-05-08T16:05:01.914Z" }, + { url = "https://files.pythonhosted.org/packages/d1/84/55bc4881973d3f79b479a5a2e2df61c8c9a04fcb986a213ac9c02cfb659b/scipy-1.15.3-cp310-cp310-win_amd64.whl", hash = "sha256:9d61e97b186a57350f6d6fd72640f9e99d5a4a2b8fbf4b9ee9a841eab327dc13", size = 41259201, upload-time = "2025-05-08T16:05:08.166Z" }, + { url = "https://files.pythonhosted.org/packages/96/ab/5cc9f80f28f6a7dff646c5756e559823614a42b1939d86dd0ed550470210/scipy-1.15.3-cp311-cp311-macosx_10_13_x86_64.whl", hash = "sha256:993439ce220d25e3696d1b23b233dd010169b62f6456488567e830654ee37a6b", size = 38714255, upload-time = "2025-05-08T16:05:14.596Z" }, + { url = "https://files.pythonhosted.org/packages/4a/4a/66ba30abe5ad1a3ad15bfb0b59d22174012e8056ff448cb1644deccbfed2/scipy-1.15.3-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:34716e281f181a02341ddeaad584205bd2fd3c242063bd3423d61ac259ca7eba", size = 30111035, upload-time = "2025-05-08T16:05:20.152Z" }, + { url = "https://files.pythonhosted.org/packages/4b/fa/a7e5b95afd80d24313307f03624acc65801846fa75599034f8ceb9e2cbf6/scipy-1.15.3-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:3b0334816afb8b91dab859281b1b9786934392aa3d527cd847e41bb6f45bee65", size = 22384499, upload-time = "2025-05-08T16:05:24.494Z" }, + { url = "https://files.pythonhosted.org/packages/17/99/f3aaddccf3588bb4aea70ba35328c204cadd89517a1612ecfda5b2dd9d7a/scipy-1.15.3-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:6db907c7368e3092e24919b5e31c76998b0ce1684d51a90943cb0ed1b4ffd6c1", size = 25152602, upload-time = "2025-05-08T16:05:29.313Z" }, + { url = "https://files.pythonhosted.org/packages/56/c5/1032cdb565f146109212153339f9cb8b993701e9fe56b1c97699eee12586/scipy-1.15.3-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:721d6b4ef5dc82ca8968c25b111e307083d7ca9091bc38163fb89243e85e3889", size = 35503415, upload-time = "2025-05-08T16:05:34.699Z" }, + { url = "https://files.pythonhosted.org/packages/bd/37/89f19c8c05505d0601ed5650156e50eb881ae3918786c8fd7262b4ee66d3/scipy-1.15.3-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:39cb9c62e471b1bb3750066ecc3a3f3052b37751c7c3dfd0fd7e48900ed52982", size = 37652622, upload-time = "2025-05-08T16:05:40.762Z" }, + { url = "https://files.pythonhosted.org/packages/7e/31/be59513aa9695519b18e1851bb9e487de66f2d31f835201f1b42f5d4d475/scipy-1.15.3-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:795c46999bae845966368a3c013e0e00947932d68e235702b5c3f6ea799aa8c9", size = 37244796, upload-time = "2025-05-08T16:05:48.119Z" }, + { url = "https://files.pythonhosted.org/packages/10/c0/4f5f3eeccc235632aab79b27a74a9130c6c35df358129f7ac8b29f562ac7/scipy-1.15.3-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:18aaacb735ab38b38db42cb01f6b92a2d0d4b6aabefeb07f02849e47f8fb3594", size = 40047684, upload-time = "2025-05-08T16:05:54.22Z" }, + { url = "https://files.pythonhosted.org/packages/ab/a7/0ddaf514ce8a8714f6ed243a2b391b41dbb65251affe21ee3077ec45ea9a/scipy-1.15.3-cp311-cp311-win_amd64.whl", hash = "sha256:ae48a786a28412d744c62fd7816a4118ef97e5be0bee968ce8f0a2fba7acf3bb", size = 41246504, upload-time = "2025-05-08T16:06:00.437Z" }, + { url = "https://files.pythonhosted.org/packages/37/4b/683aa044c4162e10ed7a7ea30527f2cbd92e6999c10a8ed8edb253836e9c/scipy-1.15.3-cp312-cp312-macosx_10_13_x86_64.whl", hash = "sha256:6ac6310fdbfb7aa6612408bd2f07295bcbd3fda00d2d702178434751fe48e019", size = 38766735, upload-time = "2025-05-08T16:06:06.471Z" }, + { url = "https://files.pythonhosted.org/packages/7b/7e/f30be3d03de07f25dc0ec926d1681fed5c732d759ac8f51079708c79e680/scipy-1.15.3-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:185cd3d6d05ca4b44a8f1595af87f9c372bb6acf9c808e99aa3e9aa03bd98cf6", size = 30173284, upload-time = "2025-05-08T16:06:11.686Z" }, + { url = "https://files.pythonhosted.org/packages/07/9c/0ddb0d0abdabe0d181c1793db51f02cd59e4901da6f9f7848e1f96759f0d/scipy-1.15.3-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:05dc6abcd105e1a29f95eada46d4a3f251743cfd7d3ae8ddb4088047f24ea477", size = 22446958, upload-time = "2025-05-08T16:06:15.97Z" }, + { url = "https://files.pythonhosted.org/packages/af/43/0bce905a965f36c58ff80d8bea33f1f9351b05fad4beaad4eae34699b7a1/scipy-1.15.3-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:06efcba926324df1696931a57a176c80848ccd67ce6ad020c810736bfd58eb1c", size = 25242454, upload-time = "2025-05-08T16:06:20.394Z" }, + { url = "https://files.pythonhosted.org/packages/56/30/a6f08f84ee5b7b28b4c597aca4cbe545535c39fe911845a96414700b64ba/scipy-1.15.3-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c05045d8b9bfd807ee1b9f38761993297b10b245f012b11b13b91ba8945f7e45", size = 35210199, upload-time = "2025-05-08T16:06:26.159Z" }, + { url = "https://files.pythonhosted.org/packages/0b/1f/03f52c282437a168ee2c7c14a1a0d0781a9a4a8962d84ac05c06b4c5b555/scipy-1.15.3-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:271e3713e645149ea5ea3e97b57fdab61ce61333f97cfae392c28ba786f9bb49", size = 37309455, upload-time = "2025-05-08T16:06:32.778Z" }, + { url = "https://files.pythonhosted.org/packages/89/b1/fbb53137f42c4bf630b1ffdfc2151a62d1d1b903b249f030d2b1c0280af8/scipy-1.15.3-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:6cfd56fc1a8e53f6e89ba3a7a7251f7396412d655bca2aa5611c8ec9a6784a1e", size = 36885140, upload-time = "2025-05-08T16:06:39.249Z" }, + { url = "https://files.pythonhosted.org/packages/2e/2e/025e39e339f5090df1ff266d021892694dbb7e63568edcfe43f892fa381d/scipy-1.15.3-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:0ff17c0bb1cb32952c09217d8d1eed9b53d1463e5f1dd6052c7857f83127d539", size = 39710549, upload-time = "2025-05-08T16:06:45.729Z" }, + { url = "https://files.pythonhosted.org/packages/e6/eb/3bf6ea8ab7f1503dca3a10df2e4b9c3f6b3316df07f6c0ded94b281c7101/scipy-1.15.3-cp312-cp312-win_amd64.whl", hash = "sha256:52092bc0472cfd17df49ff17e70624345efece4e1a12b23783a1ac59a1b728ed", size = 40966184, upload-time = "2025-05-08T16:06:52.623Z" }, + { url = "https://files.pythonhosted.org/packages/73/18/ec27848c9baae6e0d6573eda6e01a602e5649ee72c27c3a8aad673ebecfd/scipy-1.15.3-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:2c620736bcc334782e24d173c0fdbb7590a0a436d2fdf39310a8902505008759", size = 38728256, upload-time = "2025-05-08T16:06:58.696Z" }, + { url = "https://files.pythonhosted.org/packages/74/cd/1aef2184948728b4b6e21267d53b3339762c285a46a274ebb7863c9e4742/scipy-1.15.3-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:7e11270a000969409d37ed399585ee530b9ef6aa99d50c019de4cb01e8e54e62", size = 30109540, upload-time = "2025-05-08T16:07:04.209Z" }, + { url = "https://files.pythonhosted.org/packages/5b/d8/59e452c0a255ec352bd0a833537a3bc1bfb679944c4938ab375b0a6b3a3e/scipy-1.15.3-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:8c9ed3ba2c8a2ce098163a9bdb26f891746d02136995df25227a20e71c396ebb", size = 22383115, upload-time = "2025-05-08T16:07:08.998Z" }, + { url = "https://files.pythonhosted.org/packages/08/f5/456f56bbbfccf696263b47095291040655e3cbaf05d063bdc7c7517f32ac/scipy-1.15.3-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:0bdd905264c0c9cfa74a4772cdb2070171790381a5c4d312c973382fc6eaf730", size = 25163884, upload-time = "2025-05-08T16:07:14.091Z" }, + { url = "https://files.pythonhosted.org/packages/a2/66/a9618b6a435a0f0c0b8a6d0a2efb32d4ec5a85f023c2b79d39512040355b/scipy-1.15.3-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:79167bba085c31f38603e11a267d862957cbb3ce018d8b38f79ac043bc92d825", size = 35174018, upload-time = "2025-05-08T16:07:19.427Z" }, + { url = "https://files.pythonhosted.org/packages/b5/09/c5b6734a50ad4882432b6bb7c02baf757f5b2f256041da5df242e2d7e6b6/scipy-1.15.3-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:c9deabd6d547aee2c9a81dee6cc96c6d7e9a9b1953f74850c179f91fdc729cb7", size = 37269716, upload-time = "2025-05-08T16:07:25.712Z" }, + { url = "https://files.pythonhosted.org/packages/77/0a/eac00ff741f23bcabd352731ed9b8995a0a60ef57f5fd788d611d43d69a1/scipy-1.15.3-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:dde4fc32993071ac0c7dd2d82569e544f0bdaff66269cb475e0f369adad13f11", size = 36872342, upload-time = "2025-05-08T16:07:31.468Z" }, + { url = "https://files.pythonhosted.org/packages/fe/54/4379be86dd74b6ad81551689107360d9a3e18f24d20767a2d5b9253a3f0a/scipy-1.15.3-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:f77f853d584e72e874d87357ad70f44b437331507d1c311457bed8ed2b956126", size = 39670869, upload-time = "2025-05-08T16:07:38.002Z" }, + { url = "https://files.pythonhosted.org/packages/87/2e/892ad2862ba54f084ffe8cc4a22667eaf9c2bcec6d2bff1d15713c6c0703/scipy-1.15.3-cp313-cp313-win_amd64.whl", hash = "sha256:b90ab29d0c37ec9bf55424c064312930ca5f4bde15ee8619ee44e69319aab163", size = 40988851, upload-time = "2025-05-08T16:08:33.671Z" }, + { url = "https://files.pythonhosted.org/packages/1b/e9/7a879c137f7e55b30d75d90ce3eb468197646bc7b443ac036ae3fe109055/scipy-1.15.3-cp313-cp313t-macosx_10_13_x86_64.whl", hash = "sha256:3ac07623267feb3ae308487c260ac684b32ea35fd81e12845039952f558047b8", size = 38863011, upload-time = "2025-05-08T16:07:44.039Z" }, + { url = "https://files.pythonhosted.org/packages/51/d1/226a806bbd69f62ce5ef5f3ffadc35286e9fbc802f606a07eb83bf2359de/scipy-1.15.3-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:6487aa99c2a3d509a5227d9a5e889ff05830a06b2ce08ec30df6d79db5fcd5c5", size = 30266407, upload-time = "2025-05-08T16:07:49.891Z" }, + { url = "https://files.pythonhosted.org/packages/e5/9b/f32d1d6093ab9eeabbd839b0f7619c62e46cc4b7b6dbf05b6e615bbd4400/scipy-1.15.3-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:50f9e62461c95d933d5c5ef4a1f2ebf9a2b4e83b0db374cb3f1de104d935922e", size = 22540030, upload-time = "2025-05-08T16:07:54.121Z" }, + { url = "https://files.pythonhosted.org/packages/e7/29/c278f699b095c1a884f29fda126340fcc201461ee8bfea5c8bdb1c7c958b/scipy-1.15.3-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:14ed70039d182f411ffc74789a16df3835e05dc469b898233a245cdfd7f162cb", size = 25218709, upload-time = "2025-05-08T16:07:58.506Z" }, + { url = "https://files.pythonhosted.org/packages/24/18/9e5374b617aba742a990581373cd6b68a2945d65cc588482749ef2e64467/scipy-1.15.3-cp313-cp313t-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0a769105537aa07a69468a0eefcd121be52006db61cdd8cac8a0e68980bbb723", size = 34809045, upload-time = "2025-05-08T16:08:03.929Z" }, + { url = "https://files.pythonhosted.org/packages/e1/fe/9c4361e7ba2927074360856db6135ef4904d505e9b3afbbcb073c4008328/scipy-1.15.3-cp313-cp313t-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9db984639887e3dffb3928d118145ffe40eff2fa40cb241a306ec57c219ebbbb", size = 36703062, upload-time = "2025-05-08T16:08:09.558Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8e/038ccfe29d272b30086b25a4960f757f97122cb2ec42e62b460d02fe98e9/scipy-1.15.3-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:40e54d5c7e7ebf1aa596c374c49fa3135f04648a0caabcb66c52884b943f02b4", size = 36393132, upload-time = "2025-05-08T16:08:15.34Z" }, + { url = "https://files.pythonhosted.org/packages/10/7e/5c12285452970be5bdbe8352c619250b97ebf7917d7a9a9e96b8a8140f17/scipy-1.15.3-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:5e721fed53187e71d0ccf382b6bf977644c533e506c4d33c3fb24de89f5c3ed5", size = 38979503, upload-time = "2025-05-08T16:08:21.513Z" }, + { url = "https://files.pythonhosted.org/packages/81/06/0a5e5349474e1cbc5757975b21bd4fad0e72ebf138c5592f191646154e06/scipy-1.15.3-cp313-cp313t-win_amd64.whl", hash = "sha256:76ad1fb5f8752eabf0fa02e4cc0336b4e8f021e2d5f061ed37d6d264db35e3ca", size = 40308097, upload-time = "2025-05-08T16:08:27.627Z" }, +] + +[[package]] +name = "scipy" +version = "1.16.2" +source = { registry = "https://pypi.org/simple" } +resolution-markers = [ + "python_full_version >= '3.13' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", + "python_full_version >= '3.13' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", + "python_full_version >= '3.13' and sys_platform == 'emscripten'", + "python_full_version == '3.12.*' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", + "python_full_version == '3.12.*' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", + "python_full_version == '3.12.*' and sys_platform == 'emscripten'", + "python_full_version == '3.11.*' and platform_python_implementation != 'PyPy' and sys_platform != 'emscripten'", + "python_full_version == '3.11.*' and platform_python_implementation == 'PyPy' and sys_platform != 'emscripten'", + "python_full_version == '3.11.*' and sys_platform == 'emscripten'", +] +dependencies = [ + { name = "numpy", version = "1.26.4", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version == '3.11.*'" }, + { name = "numpy", version = "2.3.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.12'" }, +] +sdist = { url = "https://files.pythonhosted.org/packages/4c/3b/546a6f0bfe791bbb7f8d591613454d15097e53f906308ec6f7c1ce588e8e/scipy-1.16.2.tar.gz", hash = "sha256:af029b153d243a80afb6eabe40b0a07f8e35c9adc269c019f364ad747f826a6b", size = 30580599, upload-time = "2025-09-11T17:48:08.271Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/0b/ef/37ed4b213d64b48422df92560af7300e10fe30b5d665dd79932baebee0c6/scipy-1.16.2-cp311-cp311-macosx_10_14_x86_64.whl", hash = "sha256:6ab88ea43a57da1af33292ebd04b417e8e2eaf9d5aa05700be8d6e1b6501cd92", size = 36619956, upload-time = "2025-09-11T17:39:20.5Z" }, + { url = "https://files.pythonhosted.org/packages/85/ab/5c2eba89b9416961a982346a4d6a647d78c91ec96ab94ed522b3b6baf444/scipy-1.16.2-cp311-cp311-macosx_12_0_arm64.whl", hash = "sha256:c95e96c7305c96ede73a7389f46ccd6c659c4da5ef1b2789466baeaed3622b6e", size = 28931117, upload-time = "2025-09-11T17:39:29.06Z" }, + { url = "https://files.pythonhosted.org/packages/80/d1/eed51ab64d227fe60229a2d57fb60ca5898cfa50ba27d4f573e9e5f0b430/scipy-1.16.2-cp311-cp311-macosx_14_0_arm64.whl", hash = "sha256:87eb178db04ece7c698220d523c170125dbffebb7af0345e66c3554f6f60c173", size = 20921997, upload-time = "2025-09-11T17:39:34.892Z" }, + { url = "https://files.pythonhosted.org/packages/be/7c/33ea3e23bbadde96726edba6bf9111fb1969d14d9d477ffa202c67bec9da/scipy-1.16.2-cp311-cp311-macosx_14_0_x86_64.whl", hash = "sha256:4e409eac067dcee96a57fbcf424c13f428037827ec7ee3cb671ff525ca4fc34d", size = 23523374, upload-time = "2025-09-11T17:39:40.846Z" }, + { url = "https://files.pythonhosted.org/packages/96/0b/7399dc96e1e3f9a05e258c98d716196a34f528eef2ec55aad651ed136d03/scipy-1.16.2-cp311-cp311-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:e574be127bb760f0dad24ff6e217c80213d153058372362ccb9555a10fc5e8d2", size = 33583702, upload-time = "2025-09-11T17:39:49.011Z" }, + { url = "https://files.pythonhosted.org/packages/1a/bc/a5c75095089b96ea72c1bd37a4497c24b581ec73db4ef58ebee142ad2d14/scipy-1.16.2-cp311-cp311-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f5db5ba6188d698ba7abab982ad6973265b74bb40a1efe1821b58c87f73892b9", size = 35883427, upload-time = "2025-09-11T17:39:57.406Z" }, + { url = "https://files.pythonhosted.org/packages/ab/66/e25705ca3d2b87b97fe0a278a24b7f477b4023a926847935a1a71488a6a6/scipy-1.16.2-cp311-cp311-musllinux_1_2_aarch64.whl", hash = "sha256:ec6e74c4e884104ae006d34110677bfe0098203a3fec2f3faf349f4cb05165e3", size = 36212940, upload-time = "2025-09-11T17:40:06.013Z" }, + { url = "https://files.pythonhosted.org/packages/d6/fd/0bb911585e12f3abdd603d721d83fc1c7492835e1401a0e6d498d7822b4b/scipy-1.16.2-cp311-cp311-musllinux_1_2_x86_64.whl", hash = "sha256:912f46667d2d3834bc3d57361f854226475f695eb08c08a904aadb1c936b6a88", size = 38865092, upload-time = "2025-09-11T17:40:15.143Z" }, + { url = "https://files.pythonhosted.org/packages/d6/73/c449a7d56ba6e6f874183759f8483cde21f900a8be117d67ffbb670c2958/scipy-1.16.2-cp311-cp311-win_amd64.whl", hash = "sha256:91e9e8a37befa5a69e9cacbe0bcb79ae5afb4a0b130fd6db6ee6cc0d491695fa", size = 38687626, upload-time = "2025-09-11T17:40:24.041Z" }, + { url = "https://files.pythonhosted.org/packages/68/72/02f37316adf95307f5d9e579023c6899f89ff3a051fa079dbd6faafc48e5/scipy-1.16.2-cp311-cp311-win_arm64.whl", hash = "sha256:f3bf75a6dcecab62afde4d1f973f1692be013110cad5338007927db8da73249c", size = 25503506, upload-time = "2025-09-11T17:40:30.703Z" }, + { url = "https://files.pythonhosted.org/packages/b7/8d/6396e00db1282279a4ddd507c5f5e11f606812b608ee58517ce8abbf883f/scipy-1.16.2-cp312-cp312-macosx_10_14_x86_64.whl", hash = "sha256:89d6c100fa5c48472047632e06f0876b3c4931aac1f4291afc81a3644316bb0d", size = 36646259, upload-time = "2025-09-11T17:40:39.329Z" }, + { url = "https://files.pythonhosted.org/packages/3b/93/ea9edd7e193fceb8eef149804491890bde73fb169c896b61aa3e2d1e4e77/scipy-1.16.2-cp312-cp312-macosx_12_0_arm64.whl", hash = "sha256:ca748936cd579d3f01928b30a17dc474550b01272d8046e3e1ee593f23620371", size = 28888976, upload-time = "2025-09-11T17:40:46.82Z" }, + { url = "https://files.pythonhosted.org/packages/91/4d/281fddc3d80fd738ba86fd3aed9202331180b01e2c78eaae0642f22f7e83/scipy-1.16.2-cp312-cp312-macosx_14_0_arm64.whl", hash = "sha256:fac4f8ce2ddb40e2e3d0f7ec36d2a1e7f92559a2471e59aec37bd8d9de01fec0", size = 20879905, upload-time = "2025-09-11T17:40:52.545Z" }, + { url = "https://files.pythonhosted.org/packages/69/40/b33b74c84606fd301b2915f0062e45733c6ff5708d121dd0deaa8871e2d0/scipy-1.16.2-cp312-cp312-macosx_14_0_x86_64.whl", hash = "sha256:033570f1dcefd79547a88e18bccacff025c8c647a330381064f561d43b821232", size = 23553066, upload-time = "2025-09-11T17:40:59.014Z" }, + { url = "https://files.pythonhosted.org/packages/55/a7/22c739e2f21a42cc8f16bc76b47cff4ed54fbe0962832c589591c2abec34/scipy-1.16.2-cp312-cp312-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ea3421209bf00c8a5ef2227de496601087d8f638a2363ee09af059bd70976dc1", size = 33336407, upload-time = "2025-09-11T17:41:06.796Z" }, + { url = "https://files.pythonhosted.org/packages/53/11/a0160990b82999b45874dc60c0c183d3a3a969a563fffc476d5a9995c407/scipy-1.16.2-cp312-cp312-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:f66bd07ba6f84cd4a380b41d1bf3c59ea488b590a2ff96744845163309ee8e2f", size = 35673281, upload-time = "2025-09-11T17:41:15.055Z" }, + { url = "https://files.pythonhosted.org/packages/96/53/7ef48a4cfcf243c3d0f1643f5887c81f29fdf76911c4e49331828e19fc0a/scipy-1.16.2-cp312-cp312-musllinux_1_2_aarch64.whl", hash = "sha256:5e9feab931bd2aea4a23388c962df6468af3d808ddf2d40f94a81c5dc38f32ef", size = 36004222, upload-time = "2025-09-11T17:41:23.868Z" }, + { url = "https://files.pythonhosted.org/packages/49/7f/71a69e0afd460049d41c65c630c919c537815277dfea214031005f474d78/scipy-1.16.2-cp312-cp312-musllinux_1_2_x86_64.whl", hash = "sha256:03dfc75e52f72cf23ec2ced468645321407faad8f0fe7b1f5b49264adbc29cb1", size = 38664586, upload-time = "2025-09-11T17:41:31.021Z" }, + { url = "https://files.pythonhosted.org/packages/34/95/20e02ca66fb495a95fba0642fd48e0c390d0ece9b9b14c6e931a60a12dea/scipy-1.16.2-cp312-cp312-win_amd64.whl", hash = "sha256:0ce54e07bbb394b417457409a64fd015be623f36e330ac49306433ffe04bc97e", size = 38550641, upload-time = "2025-09-11T17:41:36.61Z" }, + { url = "https://files.pythonhosted.org/packages/92/ad/13646b9beb0a95528ca46d52b7babafbe115017814a611f2065ee4e61d20/scipy-1.16.2-cp312-cp312-win_arm64.whl", hash = "sha256:2a8ffaa4ac0df81a0b94577b18ee079f13fecdb924df3328fc44a7dc5ac46851", size = 25456070, upload-time = "2025-09-11T17:41:41.3Z" }, + { url = "https://files.pythonhosted.org/packages/c1/27/c5b52f1ee81727a9fc457f5ac1e9bf3d6eab311805ea615c83c27ba06400/scipy-1.16.2-cp313-cp313-macosx_10_14_x86_64.whl", hash = "sha256:84f7bf944b43e20b8a894f5fe593976926744f6c185bacfcbdfbb62736b5cc70", size = 36604856, upload-time = "2025-09-11T17:41:47.695Z" }, + { url = "https://files.pythonhosted.org/packages/32/a9/15c20d08e950b540184caa8ced675ba1128accb0e09c653780ba023a4110/scipy-1.16.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:5c39026d12edc826a1ef2ad35ad1e6d7f087f934bb868fc43fa3049c8b8508f9", size = 28864626, upload-time = "2025-09-11T17:41:52.642Z" }, + { url = "https://files.pythonhosted.org/packages/4c/fc/ea36098df653cca26062a627c1a94b0de659e97127c8491e18713ca0e3b9/scipy-1.16.2-cp313-cp313-macosx_14_0_arm64.whl", hash = "sha256:e52729ffd45b68777c5319560014d6fd251294200625d9d70fd8626516fc49f5", size = 20855689, upload-time = "2025-09-11T17:41:57.886Z" }, + { url = "https://files.pythonhosted.org/packages/dc/6f/d0b53be55727f3e6d7c72687ec18ea6d0047cf95f1f77488b99a2bafaee1/scipy-1.16.2-cp313-cp313-macosx_14_0_x86_64.whl", hash = "sha256:024dd4a118cccec09ca3209b7e8e614931a6ffb804b2a601839499cb88bdf925", size = 23512151, upload-time = "2025-09-11T17:42:02.303Z" }, + { url = "https://files.pythonhosted.org/packages/11/85/bf7dab56e5c4b1d3d8eef92ca8ede788418ad38a7dc3ff50262f00808760/scipy-1.16.2-cp313-cp313-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:7a5dc7ee9c33019973a470556081b0fd3c9f4c44019191039f9769183141a4d9", size = 33329824, upload-time = "2025-09-11T17:42:07.549Z" }, + { url = "https://files.pythonhosted.org/packages/da/6a/1a927b14ddc7714111ea51f4e568203b2bb6ed59bdd036d62127c1a360c8/scipy-1.16.2-cp313-cp313-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:c2275ff105e508942f99d4e3bc56b6ef5e4b3c0af970386ca56b777608ce95b7", size = 35681881, upload-time = "2025-09-11T17:42:13.255Z" }, + { url = "https://files.pythonhosted.org/packages/c1/5f/331148ea5780b4fcc7007a4a6a6ee0a0c1507a796365cc642d4d226e1c3a/scipy-1.16.2-cp313-cp313-musllinux_1_2_aarch64.whl", hash = "sha256:af80196eaa84f033e48444d2e0786ec47d328ba00c71e4299b602235ffef9acb", size = 36006219, upload-time = "2025-09-11T17:42:18.765Z" }, + { url = "https://files.pythonhosted.org/packages/46/3a/e991aa9d2aec723b4a8dcfbfc8365edec5d5e5f9f133888067f1cbb7dfc1/scipy-1.16.2-cp313-cp313-musllinux_1_2_x86_64.whl", hash = "sha256:9fb1eb735fe3d6ed1f89918224e3385fbf6f9e23757cacc35f9c78d3b712dd6e", size = 38682147, upload-time = "2025-09-11T17:42:25.177Z" }, + { url = "https://files.pythonhosted.org/packages/a1/57/0f38e396ad19e41b4c5db66130167eef8ee620a49bc7d0512e3bb67e0cab/scipy-1.16.2-cp313-cp313-win_amd64.whl", hash = "sha256:fda714cf45ba43c9d3bae8f2585c777f64e3f89a2e073b668b32ede412d8f52c", size = 38520766, upload-time = "2025-09-11T17:43:25.342Z" }, + { url = "https://files.pythonhosted.org/packages/1b/a5/85d3e867b6822d331e26c862a91375bb7746a0b458db5effa093d34cdb89/scipy-1.16.2-cp313-cp313-win_arm64.whl", hash = "sha256:2f5350da923ccfd0b00e07c3e5cfb316c1c0d6c1d864c07a72d092e9f20db104", size = 25451169, upload-time = "2025-09-11T17:43:30.198Z" }, + { url = "https://files.pythonhosted.org/packages/09/d9/60679189bcebda55992d1a45498de6d080dcaf21ce0c8f24f888117e0c2d/scipy-1.16.2-cp313-cp313t-macosx_10_14_x86_64.whl", hash = "sha256:53d8d2ee29b925344c13bda64ab51785f016b1b9617849dac10897f0701b20c1", size = 37012682, upload-time = "2025-09-11T17:42:30.677Z" }, + { url = "https://files.pythonhosted.org/packages/83/be/a99d13ee4d3b7887a96f8c71361b9659ba4ef34da0338f14891e102a127f/scipy-1.16.2-cp313-cp313t-macosx_12_0_arm64.whl", hash = "sha256:9e05e33657efb4c6a9d23bd8300101536abd99c85cca82da0bffff8d8764d08a", size = 29389926, upload-time = "2025-09-11T17:42:35.845Z" }, + { url = "https://files.pythonhosted.org/packages/bf/0a/130164a4881cec6ca8c00faf3b57926f28ed429cd6001a673f83c7c2a579/scipy-1.16.2-cp313-cp313t-macosx_14_0_arm64.whl", hash = "sha256:7fe65b36036357003b3ef9d37547abeefaa353b237e989c21027b8ed62b12d4f", size = 21381152, upload-time = "2025-09-11T17:42:40.07Z" }, + { url = "https://files.pythonhosted.org/packages/47/a6/503ffb0310ae77fba874e10cddfc4a1280bdcca1d13c3751b8c3c2996cf8/scipy-1.16.2-cp313-cp313t-macosx_14_0_x86_64.whl", hash = "sha256:6406d2ac6d40b861cccf57f49592f9779071655e9f75cd4f977fa0bdd09cb2e4", size = 23914410, upload-time = "2025-09-11T17:42:44.313Z" }, + { url = "https://files.pythonhosted.org/packages/fa/c7/1147774bcea50d00c02600aadaa919facbd8537997a62496270133536ed6/scipy-1.16.2-cp313-cp313t-manylinux2014_aarch64.manylinux_2_17_aarch64.whl", hash = "sha256:ff4dc42bd321991fbf611c23fc35912d690f731c9914bf3af8f417e64aca0f21", size = 33481880, upload-time = "2025-09-11T17:42:49.325Z" }, + { url = "https://files.pythonhosted.org/packages/6a/74/99d5415e4c3e46b2586f30cdbecb95e101c7192628a484a40dd0d163811a/scipy-1.16.2-cp313-cp313t-manylinux2014_x86_64.manylinux_2_17_x86_64.whl", hash = "sha256:654324826654d4d9133e10675325708fb954bc84dae6e9ad0a52e75c6b1a01d7", size = 35791425, upload-time = "2025-09-11T17:42:54.711Z" }, + { url = "https://files.pythonhosted.org/packages/1b/ee/a6559de7c1cc710e938c0355d9d4fbcd732dac4d0d131959d1f3b63eb29c/scipy-1.16.2-cp313-cp313t-musllinux_1_2_aarch64.whl", hash = "sha256:63870a84cd15c44e65220eaed2dac0e8f8b26bbb991456a033c1d9abfe8a94f8", size = 36178622, upload-time = "2025-09-11T17:43:00.375Z" }, + { url = "https://files.pythonhosted.org/packages/4e/7b/f127a5795d5ba8ece4e0dce7d4a9fb7cb9e4f4757137757d7a69ab7d4f1a/scipy-1.16.2-cp313-cp313t-musllinux_1_2_x86_64.whl", hash = "sha256:fa01f0f6a3050fa6a9771a95d5faccc8e2f5a92b4a2e5440a0fa7264a2398472", size = 38783985, upload-time = "2025-09-11T17:43:06.661Z" }, + { url = "https://files.pythonhosted.org/packages/3e/9f/bc81c1d1e033951eb5912cd3750cc005943afa3e65a725d2443a3b3c4347/scipy-1.16.2-cp313-cp313t-win_amd64.whl", hash = "sha256:116296e89fba96f76353a8579820c2512f6e55835d3fad7780fece04367de351", size = 38631367, upload-time = "2025-09-11T17:43:14.44Z" }, + { url = "https://files.pythonhosted.org/packages/d6/5e/2cc7555fd81d01814271412a1d59a289d25f8b63208a0a16c21069d55d3e/scipy-1.16.2-cp313-cp313t-win_arm64.whl", hash = "sha256:98e22834650be81d42982360382b43b17f7ba95e0e6993e2a4f5b9ad9283a94d", size = 25787992, upload-time = "2025-09-11T17:43:19.745Z" }, +] + [[package]] name = "semver" version = "3.0.4" @@ -7120,6 +7287,15 @@ wheels = [ { url = "https://files.pythonhosted.org/packages/6a/9e/2064975477fdc887e47ad42157e214526dcad8f317a948dee17e1659a62f/terminado-0.18.1-py3-none-any.whl", hash = "sha256:a4468e1b37bb318f8a86514f65814e1afc977cf29b3992a4500d9dd305dcceb0", size = 14154, upload-time = "2024-03-12T14:34:36.569Z" }, ] +[[package]] +name = "threadpoolctl" +version = "3.6.0" +source = { registry = "https://pypi.org/simple" } +sdist = { url = "https://files.pythonhosted.org/packages/b7/4d/08c89e34946fce2aec4fbb45c9016efd5f4d7f24af8e5d93296e935631d8/threadpoolctl-3.6.0.tar.gz", hash = "sha256:8ab8b4aa3491d812b623328249fab5302a68d2d71745c8a4c719a2fcaba9f44e", size = 21274, upload-time = "2025-03-13T13:49:23.031Z" } +wheels = [ + { url = "https://files.pythonhosted.org/packages/32/d5/f9a850d79b0851d1d4ef6456097579a9005b31fea68726a4ae5f2d82ddd9/threadpoolctl-3.6.0-py3-none-any.whl", hash = "sha256:43a0b8fd5a2928500110039e43a5eed8480b918967083ea48dc3ab9f13c4a7fb", size = 18638, upload-time = "2025-03-13T13:49:21.846Z" }, +] + [[package]] name = "tiktoken" version = "0.11.0" From 3b9415ee8874975c89449a21b6a7155a5e854262 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 17:27:11 +0200 Subject: [PATCH 37/71] test: Resolve failing unit tests --- .../graph_completion_retriever_context_extension_test.py | 4 ---- .../modules/retrieval/graph_completion_retriever_cot_test.py | 4 ---- .../unit/modules/retrieval/graph_completion_retriever_test.py | 4 ---- 3 files changed, 12 deletions(-) diff --git a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py index 74def2ae7..0e21fe351 100644 --- a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py +++ b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_context_extension_test.py @@ -7,7 +7,6 @@ import cognee from cognee.low_level import setup, DataPoint from cognee.tasks.storage import add_data_points from cognee.modules.graph.utils import resolve_edges_to_text -from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError from cognee.modules.retrieval.graph_completion_context_extension_retriever import ( GraphCompletionContextExtensionRetriever, ) @@ -165,9 +164,6 @@ class TestGraphCompletionWithContextExtensionRetriever: retriever = GraphCompletionContextExtensionRetriever() - with pytest.raises(DatabaseNotCreatedError): - await retriever.get_context("Who works at Figma?") - await setup() context = await retriever.get_context("Who works at Figma?") diff --git a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py index 9a789a1bd..206cfaf84 100644 --- a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py +++ b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_cot_test.py @@ -7,7 +7,6 @@ import cognee from cognee.low_level import setup, DataPoint from cognee.modules.graph.utils import resolve_edges_to_text from cognee.tasks.storage import add_data_points -from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError from cognee.modules.retrieval.graph_completion_cot_retriever import GraphCompletionCotRetriever @@ -158,9 +157,6 @@ class TestGraphCompletionCoTRetriever: retriever = GraphCompletionCotRetriever() - with pytest.raises(DatabaseNotCreatedError): - await retriever.get_context("Who works at Figma?") - await setup() context = await retriever.get_context("Who works at Figma?") diff --git a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py index 18fd94114..f462baced 100644 --- a/cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py +++ b/cognee/tests/unit/modules/retrieval/graph_completion_retriever_test.py @@ -7,7 +7,6 @@ import cognee from cognee.low_level import setup, DataPoint from cognee.modules.graph.utils import resolve_edges_to_text from cognee.tasks.storage import add_data_points -from cognee.infrastructure.databases.exceptions import DatabaseNotCreatedError from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever @@ -218,9 +217,6 @@ class TestGraphCompletionRetriever: retriever = GraphCompletionRetriever() - with pytest.raises(DatabaseNotCreatedError): - await retriever.get_context("Who works at Figma?") - await setup() context = await retriever.get_context("Who works at Figma?") From f09376429bcf9eb7e512b4054e61ee5e041c8638 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Thu, 25 Sep 2025 17:39:29 +0200 Subject: [PATCH 38/71] refactor: Remove telemetry call --- cognee/modules/retrieval/utils/brute_force_triplet_search.py | 1 - 1 file changed, 1 deletion(-) diff --git a/cognee/modules/retrieval/utils/brute_force_triplet_search.py b/cognee/modules/retrieval/utils/brute_force_triplet_search.py index 172c45d6d..8a9bcdeb4 100644 --- a/cognee/modules/retrieval/utils/brute_force_triplet_search.py +++ b/cognee/modules/retrieval/utils/brute_force_triplet_search.py @@ -182,5 +182,4 @@ async def brute_force_triplet_search( query, error, ) - send_telemetry("cognee.brute_force_triplet_search EXECUTION FAILED", {"error": str(error)}) raise error From e3494ca15f43601e3105411ef6be713556ab3ce5 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Thu, 25 Sep 2025 17:43:34 +0100 Subject: [PATCH 39/71] feat: add mcp status display to frontend --- cognee-frontend/src/ui/Layout/Header.tsx | 11 ++++++++++- cognee-frontend/src/ui/elements/StatusDot.tsx | 13 +++++++++++++ cognee-frontend/src/ui/elements/index.ts | 1 + 3 files changed, 24 insertions(+), 1 deletion(-) create mode 100644 cognee-frontend/src/ui/elements/StatusDot.tsx diff --git a/cognee-frontend/src/ui/Layout/Header.tsx b/cognee-frontend/src/ui/Layout/Header.tsx index 7a1d2e906..69968076a 100644 --- a/cognee-frontend/src/ui/Layout/Header.tsx +++ b/cognee-frontend/src/ui/Layout/Header.tsx @@ -5,7 +5,7 @@ import Image from "next/image"; import { useBoolean } from "@/utils"; import { CloseIcon, CloudIcon, CogneeIcon } from "../Icons"; -import { CTAButton, GhostButton, IconButton, Modal } from "../elements"; +import { CTAButton, GhostButton, IconButton, Modal, StatusDot } from "../elements"; import syncData from "@/modules/cloud/syncData"; interface HeaderProps { @@ -23,6 +23,11 @@ export default function Header({ user }: HeaderProps) { setFalse: closeSyncModal, } = useBoolean(false); + const { + value: isMCPStatusOpen, + setTrue: setMCPStatusOpen, + } = useBoolean(false); + const handleDataSyncConfirm = () => { syncData() .finally(() => { @@ -39,6 +44,10 @@ export default function Header({ user }: HeaderProps) {
+ + + MCP status +
Sync
diff --git a/cognee-frontend/src/ui/elements/StatusDot.tsx b/cognee-frontend/src/ui/elements/StatusDot.tsx new file mode 100644 index 000000000..4eb71a6e0 --- /dev/null +++ b/cognee-frontend/src/ui/elements/StatusDot.tsx @@ -0,0 +1,13 @@ +import React from "react"; + +const StatusDot = ({ isActive, className }: { isActive: boolean, className?: string }) => { + return ( + + ); +}; + +export default StatusDot; diff --git a/cognee-frontend/src/ui/elements/index.ts b/cognee-frontend/src/ui/elements/index.ts index 551b06596..0133f56f6 100644 --- a/cognee-frontend/src/ui/elements/index.ts +++ b/cognee-frontend/src/ui/elements/index.ts @@ -8,5 +8,6 @@ export { default as IconButton } from "./IconButton"; export { default as GhostButton } from "./GhostButton"; export { default as NeutralButton } from "./NeutralButton"; export { default as StatusIndicator } from "./StatusIndicator"; +export { default as StatusDot } from "./StatusDot"; export { default as Accordion } from "./Accordion"; export { default as Notebook } from "./Notebook"; From 38e3f11533bceefe9776cd130269c742b850c2a4 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Thu, 25 Sep 2025 20:42:40 +0100 Subject: [PATCH 40/71] fix: update entrypoint script to use cognee-mcp module --- cognee-mcp/entrypoint.sh | 18 +++++++++--------- cognee-mcp/pyproject.toml | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/cognee-mcp/entrypoint.sh b/cognee-mcp/entrypoint.sh index 53da83c11..e3ff849e0 100644 --- a/cognee-mcp/entrypoint.sh +++ b/cognee-mcp/entrypoint.sh @@ -48,27 +48,27 @@ if [ "$ENVIRONMENT" = "dev" ] || [ "$ENVIRONMENT" = "local" ]; then if [ "$DEBUG" = "true" ]; then echo "Waiting for the debugger to attach..." if [ "$TRANSPORT_MODE" = "sse" ]; then - exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee-mcp --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration elif [ "$TRANSPORT_MODE" = "http" ]; then - exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee-mcp --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration else - exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee --transport stdio --no-migration + exec python -m debugpy --wait-for-client --listen 0.0.0.0:$DEBUG_PORT -m cognee-mcp --transport stdio --no-migration fi else if [ "$TRANSPORT_MODE" = "sse" ]; then - exec cognee --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec cognee-mcp --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration elif [ "$TRANSPORT_MODE" = "http" ]; then - exec cognee --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec cognee-mcp --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration else - exec cognee --transport stdio --no-migration + exec cognee-mcp --transport stdio --no-migration fi fi else if [ "$TRANSPORT_MODE" = "sse" ]; then - exec cognee --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec cognee-mcp --transport sse --host 0.0.0.0 --port $HTTP_PORT --no-migration elif [ "$TRANSPORT_MODE" = "http" ]; then - exec cognee --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration + exec cognee-mcp --transport http --host 0.0.0.0 --port $HTTP_PORT --no-migration else - exec cognee --transport stdio --no-migration + exec cognee-mcp --transport stdio --no-migration fi fi diff --git a/cognee-mcp/pyproject.toml b/cognee-mcp/pyproject.toml index a1ee22985..f22396bd4 100644 --- a/cognee-mcp/pyproject.toml +++ b/cognee-mcp/pyproject.toml @@ -36,4 +36,4 @@ dev = [ allow-direct-references = true [project.scripts] -cognee = "src:main" +cognee-mcp = "src:main" From 921c4481f034a5e22968e8067781b1ba63504334 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Thu, 25 Sep 2025 22:04:06 +0100 Subject: [PATCH 41/71] feat: start cognee-mcp as part of cognee -ui --- cognee/api/v1/ui/__init__.py | 2 +- cognee/api/v1/ui/ui.py | 140 +++++++++-------------------------- cognee/cli/_cognee.py | 1 + 3 files changed, 39 insertions(+), 104 deletions(-) diff --git a/cognee/api/v1/ui/__init__.py b/cognee/api/v1/ui/__init__.py index f268a2e54..03876e999 100644 --- a/cognee/api/v1/ui/__init__.py +++ b/cognee/api/v1/ui/__init__.py @@ -1 +1 @@ -from .ui import start_ui, stop_ui, ui +from .ui import start_ui, ui diff --git a/cognee/api/v1/ui/ui.py b/cognee/api/v1/ui/ui.py index 6faca19e8..fb20b0420 100644 --- a/cognee/api/v1/ui/ui.py +++ b/cognee/api/v1/ui/ui.py @@ -334,17 +334,19 @@ def start_ui( start_backend: bool = False, backend_host: str = "localhost", backend_port: int = 8000, + start_mcp: bool = False, ) -> Optional[subprocess.Popen]: """ - Start the cognee frontend UI server, optionally with the backend API server. + Start the cognee frontend UI server, optionally with the backend API server and MCP server. This function will: 1. Optionally start the cognee backend API server - 2. Find the cognee-frontend directory (development) or download it (pip install) - 3. Check if Node.js and npm are available (for development mode) - 4. Install dependencies if needed (development mode) - 5. Start the frontend server - 6. Optionally open the browser + 2. Optionally start the cognee MCP server + 3. Find the cognee-frontend directory (development) or download it (pip install) + 4. Check if Node.js and npm are available (for development mode) + 5. Install dependencies if needed (development mode) + 6. Start the frontend server + 7. Optionally open the browser Args: pid_callback: Callback to notify with PID of each spawned process @@ -355,11 +357,12 @@ def start_ui( start_backend: If True, also start the cognee API backend server (default: False) backend_host: Host to bind the backend server to (default: localhost) backend_port: Port to run the backend server on (default: 8000) + start_mcp: If True, also start the cognee MCP server on port 8001 (default: False) Returns: subprocess.Popen object representing the running frontend server, or None if failed - Note: If backend is started, it runs in a separate process that will be cleaned up - when the frontend process is terminated. + Note: If backend and/or MCP server are started, they run in separate processes + that will be cleaned up when the frontend process is terminated. Example: >>> import cognee @@ -370,12 +373,37 @@ def start_ui( >>> server = cognee.start_ui(start_backend=True) >>> # UI will be available at http://localhost:3000 >>> # API will be available at http://localhost:8000 - >>> # To stop both servers later: + >>> + >>> # Start frontend with MCP server + >>> server = cognee.start_ui(start_mcp=True) + >>> # UI will be available at http://localhost:3000 + >>> # MCP server will be available at http://127.0.0.1:8001/sse + >>> # To stop all servers later: >>> server.terminate() """ logger.info("Starting cognee UI...") backend_process = None + if start_mcp: + logger.info("Starting Cognee MCP server with Docker...") + cwd = os.getcwd() + env_file = os.path.join(cwd, ".env") + try: + mcp_process = subprocess.Popen( + [ + "docker", "run", + "-p", "8001:8000", + "--rm", + "--env-file", env_file, + "-e", "TRANSPORT_MODE=sse", + "cognee/cognee-mcp:daulet-dev" + ], + preexec_fn=os.setsid if hasattr(os, "setsid") else None, + ) + pid_callback(mcp_process.pid) + logger.info("✓ Cognee MCP server starting on http://127.0.0.1:8001/sse") + except Exception as e: + logger.error(f"Failed to start MCP server with Docker: {str(e)}") # Start backend server if requested if start_backend: logger.info("Starting cognee backend API server...") @@ -502,10 +530,6 @@ def start_ui( logger.info(f"✓ Open your browser to: http://{host}:{port}") logger.info("✓ The UI will be available once Next.js finishes compiling") - # Store backend process reference in the frontend process for cleanup - if backend_process: - process._cognee_backend_process = backend_process - return process except Exception as e: @@ -525,86 +549,6 @@ def start_ui( return None -def stop_ui(process: subprocess.Popen) -> bool: - """ - Stop a running UI server process and backend process (if started), along with all their children. - - Args: - process: The subprocess.Popen object returned by start_ui() - - Returns: - bool: True if stopped successfully, False otherwise - """ - if not process: - return False - - success = True - - try: - # First, stop the backend process if it exists - backend_process = getattr(process, "_cognee_backend_process", None) - if backend_process: - logger.info("Stopping backend server...") - try: - backend_process.terminate() - try: - backend_process.wait(timeout=5) - logger.info("Backend server stopped gracefully") - except subprocess.TimeoutExpired: - logger.warning("Backend didn't terminate gracefully, forcing kill") - backend_process.kill() - backend_process.wait() - logger.info("Backend server stopped") - except Exception as e: - logger.error(f"Error stopping backend server: {str(e)}") - success = False - - # Now stop the frontend process - logger.info("Stopping frontend server...") - # Try to terminate the process group (includes child processes like Next.js) - if hasattr(os, "killpg"): - try: - # Kill the entire process group - os.killpg(os.getpgid(process.pid), signal.SIGTERM) - logger.debug("Sent SIGTERM to process group") - except (OSError, ProcessLookupError): - # Fall back to terminating just the main process - process.terminate() - logger.debug("Terminated main process only") - else: - process.terminate() - logger.debug("Terminated main process (Windows)") - - try: - process.wait(timeout=10) - logger.info("Frontend server stopped gracefully") - except subprocess.TimeoutExpired: - logger.warning("Frontend didn't terminate gracefully, forcing kill") - - # Force kill the process group - if hasattr(os, "killpg"): - try: - os.killpg(os.getpgid(process.pid), signal.SIGKILL) - logger.debug("Sent SIGKILL to process group") - except (OSError, ProcessLookupError): - process.kill() - logger.debug("Force killed main process only") - else: - process.kill() - logger.debug("Force killed main process (Windows)") - - process.wait() - - if success: - logger.info("UI servers stopped successfully") - - return success - - except Exception as e: - logger.error(f"Error stopping UI servers: {str(e)}") - return False - - # Convenience function similar to DuckDB's approach def ui() -> Optional[subprocess.Popen]: """ @@ -612,13 +556,3 @@ def ui() -> Optional[subprocess.Popen]: Similar to how DuckDB provides simple ui() function. """ return start_ui() - - -if __name__ == "__main__": - # Test the UI startup - server = start_ui() - if server: - try: - input("Press Enter to stop the server...") - finally: - stop_ui(server) diff --git a/cognee/cli/_cognee.py b/cognee/cli/_cognee.py index 52915594b..6010ea679 100644 --- a/cognee/cli/_cognee.py +++ b/cognee/cli/_cognee.py @@ -209,6 +209,7 @@ def main() -> int: port=3000, open_browser=True, start_backend=True, + start_mcp=True, auto_download=True, pid_callback=pid_callback, ) From 80da5531853059de2960140e091eafe2ae8612e3 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Thu, 25 Sep 2025 22:04:41 +0100 Subject: [PATCH 42/71] format: ruff format --- cognee/api/v1/ui/ui.py | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/cognee/api/v1/ui/ui.py b/cognee/api/v1/ui/ui.py index fb20b0420..3b583ac33 100644 --- a/cognee/api/v1/ui/ui.py +++ b/cognee/api/v1/ui/ui.py @@ -361,7 +361,7 @@ def start_ui( Returns: subprocess.Popen object representing the running frontend server, or None if failed - Note: If backend and/or MCP server are started, they run in separate processes + Note: If backend and/or MCP server are started, they run in separate processes that will be cleaned up when the frontend process is terminated. Example: @@ -391,12 +391,16 @@ def start_ui( try: mcp_process = subprocess.Popen( [ - "docker", "run", - "-p", "8001:8000", + "docker", + "run", + "-p", + "8001:8000", "--rm", - "--env-file", env_file, - "-e", "TRANSPORT_MODE=sse", - "cognee/cognee-mcp:daulet-dev" + "--env-file", + env_file, + "-e", + "TRANSPORT_MODE=sse", + "cognee/cognee-mcp:daulet-dev", ], preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) From 1deab2d54e0a8cabfc26a9a2c23f443948b65aa1 Mon Sep 17 00:00:00 2001 From: Boris Arzentar Date: Fri, 26 Sep 2025 09:57:53 +0200 Subject: [PATCH 43/71] fix: limit onnxruntime version --- poetry.lock | 3 ++- pyproject.toml | 4 ++-- uv.lock | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/poetry.lock b/poetry.lock index 3e5b68ccf..d88b94e5d 100644 --- a/poetry.lock +++ b/poetry.lock @@ -2254,6 +2254,7 @@ files = [ {file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:b9b31dd488d0778c36f8279b306dc92a42f16904cba54acca71e107d65b60b0c"}, {file = "fastuuid-0.12.0-cp313-cp313-manylinux_2_34_x86_64.whl", hash = "sha256:b19361ee649365eefc717ec08005972d3d1eb9ee39908022d98e3bfa9da59e37"}, {file = "fastuuid-0.12.0-cp313-cp313-win_amd64.whl", hash = "sha256:8fc66b11423e6f3e1937385f655bedd67aebe56a3dcec0cb835351cfe7d358c9"}, + {file = "fastuuid-0.12.0-cp38-cp38-macosx_10_12_x86_64.whl", hash = "sha256:2925f67b88d47cb16aa3eb1ab20fdcf21b94d74490e0818c91ea41434b987493"}, {file = "fastuuid-0.12.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:7b15c54d300279ab20a9cc0579ada9c9f80d1bc92997fc61fb7bf3103d7cb26b"}, {file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:458f1bc3ebbd76fdb89ad83e6b81ccd3b2a99fa6707cd3650b27606745cfb170"}, {file = "fastuuid-0.12.0-cp38-cp38-manylinux_2_34_x86_64.whl", hash = "sha256:a8f0f83fbba6dc44271a11b22e15838641b8c45612cdf541b4822a5930f6893c"}, @@ -11897,4 +11898,4 @@ posthog = ["posthog"] [metadata] lock-version = "2.1" python-versions = ">=3.10,<=3.13" -content-hash = "463d131171a4b57481f20ffad9ff98b1a5a08a2b6a64ac51fb65e54d20765e89" +content-hash = "49d2d5207803b6b56e0bbf2be871941f4fc4535d0bc823815e0a7cbe61e12574" diff --git a/pyproject.toml b/pyproject.toml index 549c297b9..b385cb588 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -46,11 +46,11 @@ dependencies = [ "fastapi-users[sqlalchemy]>=14.0.1,<15.0.0", "structlog>=25.2.0,<26", "pympler>=1.1,<2.0.0", - "onnxruntime>=1.0.0,<2.0.0", + "onnxruntime<=1.22.1", "pylance>=0.22.0,<=0.36.0", "kuzu (==0.11.0)", "python-magic-bin<0.5 ; platform_system == 'Windows'", # Only needed for Windows - "fastembed<=0.6.0 ", + "fastembed<=0.6.0", "networkx>=3.4.2,<4", "uvicorn>=0.34.0,<1.0.0", "gunicorn>=20.1.0,<24", diff --git a/uv.lock b/uv.lock index 5d9e4042a..5957f81b2 100644 --- a/uv.lock +++ b/uv.lock @@ -1023,7 +1023,7 @@ requires-dist = [ { name = "notebook", marker = "extra == 'dev'", specifier = ">=7.1.0,<8" }, { name = "notebook", marker = "extra == 'notebook'", specifier = ">=7.1.0,<8" }, { name = "numpy", specifier = ">=1.26.4,<=4.0.0" }, - { name = "onnxruntime", specifier = ">=1.0.0,<2.0.0" }, + { name = "onnxruntime", specifier = "<=1.22.1" }, { name = "openai", specifier = ">=1.80.1" }, { name = "pandas", marker = "extra == 'evals'", specifier = ">=2.2.2,<3.0.0" }, { name = "pgvector", marker = "extra == 'postgres'", specifier = ">=0.3.5,<0.4" }, From a68401ee70ee31b8d01c6b3c7fefd71116845d8d Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 26 Sep 2025 12:54:09 +0100 Subject: [PATCH 44/71] chore: update MCP status text to connected/disconnected --- cognee-frontend/src/ui/Layout/Header.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cognee-frontend/src/ui/Layout/Header.tsx b/cognee-frontend/src/ui/Layout/Header.tsx index 69968076a..30bf7ddb0 100644 --- a/cognee-frontend/src/ui/Layout/Header.tsx +++ b/cognee-frontend/src/ui/Layout/Header.tsx @@ -46,7 +46,7 @@ export default function Header({ user }: HeaderProps) {
- MCP status + { isMCPStatusOpen ? "MCP connected" : "MCP disconnected" } From c518f149f252c96ba8b2195bf14a8ca6ff4bdf5b Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 26 Sep 2025 14:26:43 +0100 Subject: [PATCH 45/71] refactor: streamline UI server startup and port availability checks --- cognee/api/v1/ui/__init__.py | 2 +- cognee/api/v1/ui/ui.py | 96 ++++++++++++++++++++++++++---------- cognee/cli/_cognee.py | 21 +++++--- examples/start_ui_example.py | 5 +- 4 files changed, 89 insertions(+), 35 deletions(-) diff --git a/cognee/api/v1/ui/__init__.py b/cognee/api/v1/ui/__init__.py index 03876e999..d5708da5a 100644 --- a/cognee/api/v1/ui/__init__.py +++ b/cognee/api/v1/ui/__init__.py @@ -1 +1 @@ -from .ui import start_ui, ui +from .ui import start_ui diff --git a/cognee/api/v1/ui/ui.py b/cognee/api/v1/ui/ui.py index 3b583ac33..af499421b 100644 --- a/cognee/api/v1/ui/ui.py +++ b/cognee/api/v1/ui/ui.py @@ -1,5 +1,6 @@ import os import signal +import socket import subprocess import threading import time @@ -7,7 +8,7 @@ import webbrowser import zipfile import requests from pathlib import Path -from typing import Callable, Optional, Tuple +from typing import Callable, Optional, Tuple, List import tempfile import shutil @@ -17,6 +18,40 @@ from cognee.version import get_cognee_version logger = get_logger() +def _is_port_available(port: int) -> bool: + """ + Check if a port is available on localhost. + Returns True if the port is available, False otherwise. + """ + try: + with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as sock: + sock.settimeout(1) # 1 second timeout + result = sock.connect_ex(("localhost", port)) + return result != 0 # Port is available if connection fails + except Exception: + return False + + +def _check_required_ports(ports_to_check: List[Tuple[int, str]]) -> Tuple[bool, List[str]]: + """ + Check if all required ports are available on localhost. + + Args: + ports_to_check: List of (port, service_name) tuples + + Returns: + Tuple of (all_available: bool, unavailable_services: List[str]) + """ + unavailable = [] + + for port, service_name in ports_to_check: + if not _is_port_available(port): + unavailable.append(f"{service_name} (port {port})") + logger.error(f"Port {port} is already in use for {service_name}") + + return len(unavailable) == 0, unavailable + + def normalize_version_for_comparison(version: str) -> str: """ Normalize version string for comparison. @@ -327,14 +362,13 @@ def prompt_user_for_download() -> bool: def start_ui( pid_callback: Callable[[int], None], - host: str = "localhost", port: int = 3000, open_browser: bool = True, auto_download: bool = False, start_backend: bool = False, - backend_host: str = "localhost", backend_port: int = 8000, start_mcp: bool = False, + mcp_port: int = 8001, ) -> Optional[subprocess.Popen]: """ Start the cognee frontend UI server, optionally with the backend API server and MCP server. @@ -350,14 +384,13 @@ def start_ui( Args: pid_callback: Callback to notify with PID of each spawned process - host: Host to bind the frontend server to (default: localhost) port: Port to run the frontend server on (default: 3000) open_browser: Whether to open the browser automatically (default: True) auto_download: If True, download frontend without prompting (default: False) start_backend: If True, also start the cognee API backend server (default: False) - backend_host: Host to bind the backend server to (default: localhost) backend_port: Port to run the backend server on (default: 8000) - start_mcp: If True, also start the cognee MCP server on port 8001 (default: False) + start_mcp: If True, also start the cognee MCP server (default: False) + mcp_port: Port to run the MCP server on (default: 8001) Returns: subprocess.Popen object representing the running frontend server, or None if failed @@ -366,22 +399,42 @@ def start_ui( Example: >>> import cognee + >>> def dummy_callback(pid): pass >>> # Start just the frontend - >>> server = cognee.start_ui() + >>> server = cognee.start_ui(dummy_callback) >>> >>> # Start both frontend and backend - >>> server = cognee.start_ui(start_backend=True) + >>> server = cognee.start_ui(dummy_callback, start_backend=True) >>> # UI will be available at http://localhost:3000 >>> # API will be available at http://localhost:8000 >>> >>> # Start frontend with MCP server - >>> server = cognee.start_ui(start_mcp=True) + >>> server = cognee.start_ui(dummy_callback, start_mcp=True) >>> # UI will be available at http://localhost:3000 >>> # MCP server will be available at http://127.0.0.1:8001/sse >>> # To stop all servers later: >>> server.terminate() """ logger.info("Starting cognee UI...") + + ports_to_check = [(port, "Frontend UI")] + + if start_backend: + ports_to_check.append((backend_port, "Backend API")) + + if start_mcp: + ports_to_check.append((mcp_port, "MCP Server")) + + logger.info("Checking port availability...") + all_ports_available, unavailable_services = _check_required_ports(ports_to_check) + + if not all_ports_available: + error_msg = f"Cannot start cognee UI: The following services have ports already in use: {', '.join(unavailable_services)}" + logger.error(error_msg) + logger.error("Please stop the conflicting services or change the port configuration.") + return None + + logger.info("✓ All required ports are available") backend_process = None if start_mcp: @@ -394,7 +447,7 @@ def start_ui( "docker", "run", "-p", - "8001:8000", + f"{mcp_port}:8000", "--rm", "--env-file", env_file, @@ -405,7 +458,7 @@ def start_ui( preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) pid_callback(mcp_process.pid) - logger.info("✓ Cognee MCP server starting on http://127.0.0.1:8001/sse") + logger.info(f"✓ Cognee MCP server starting on http://127.0.0.1:{mcp_port}/sse") except Exception as e: logger.error(f"Failed to start MCP server with Docker: {str(e)}") # Start backend server if requested @@ -421,7 +474,7 @@ def start_ui( "uvicorn", "cognee.api.client:app", "--host", - backend_host, + "localhost", "--port", str(backend_port), ], @@ -440,7 +493,7 @@ def start_ui( logger.error("Backend server failed to start - process exited early") return None - logger.info(f"✓ Backend API started at http://{backend_host}:{backend_port}") + logger.info(f"✓ Backend API started at http://localhost:{backend_port}") except Exception as e: logger.error(f"Failed to start backend server: {str(e)}") @@ -485,11 +538,11 @@ def start_ui( # Prepare environment variables env = os.environ.copy() - env["HOST"] = host + env["HOST"] = "localhost" env["PORT"] = str(port) # Start the development server - logger.info(f"Starting frontend server at http://{host}:{port}") + logger.info(f"Starting frontend server at http://localhost:{port}") logger.info("This may take a moment to compile and start...") try: @@ -523,7 +576,7 @@ def start_ui( def open_browser_delayed(): time.sleep(5) # Give Next.js time to fully start try: - webbrowser.open(f"http://{host}:{port}") # TODO: use dashboard url? + webbrowser.open(f"http://localhost:{port}") except Exception as e: logger.warning(f"Could not open browser automatically: {e}") @@ -531,7 +584,7 @@ def start_ui( browser_thread.start() logger.info("✓ Cognee UI is starting up...") - logger.info(f"✓ Open your browser to: http://{host}:{port}") + logger.info(f"✓ Open your browser to: http://localhost:{port}") logger.info("✓ The UI will be available once Next.js finishes compiling") return process @@ -551,12 +604,3 @@ def start_ui( except (OSError, ProcessLookupError): pass return None - - -# Convenience function similar to DuckDB's approach -def ui() -> Optional[subprocess.Popen]: - """ - Convenient alias for start_ui() with default parameters. - Similar to how DuckDB provides simple ui() function. - """ - return start_ui() diff --git a/cognee/cli/_cognee.py b/cognee/cli/_cognee.py index 6010ea679..7f2b06c89 100644 --- a/cognee/cli/_cognee.py +++ b/cognee/cli/_cognee.py @@ -204,20 +204,27 @@ def main() -> int: nonlocal spawned_pids spawned_pids.append(pid) + frontend_port = 3000 + start_backend, backend_port = True, 8000 + start_mcp, mcp_port = True, 8001 server_process = start_ui( - host="localhost", - port=3000, - open_browser=True, - start_backend=True, - start_mcp=True, - auto_download=True, pid_callback=pid_callback, + port=frontend_port, + open_browser=True, + auto_download=True, + start_backend=start_backend, + backend_port=backend_port, + start_mcp=start_mcp, + mcp_port=mcp_port, ) if server_process: fmt.success("UI server started successfully!") fmt.echo("The interface is available at: http://localhost:3000") - fmt.echo("The API backend is available at: http://localhost:8000") + if start_backend: + fmt.echo(f"The API backend is available at: http://localhost:{backend_port}") + if start_mcp: + fmt.echo(f"The MCP server is available at: http://localhost:{mcp_port}") fmt.note("Press Ctrl+C to stop the server...") try: diff --git a/examples/start_ui_example.py b/examples/start_ui_example.py index 55796727b..1fb29d239 100644 --- a/examples/start_ui_example.py +++ b/examples/start_ui_example.py @@ -29,8 +29,11 @@ async def main(): print("=" * 60) # Start the UI server + def dummy_callback(pid): + pass + server = cognee.start_ui( - host="localhost", + pid_callback=dummy_callback, port=3000, open_browser=True, # This will automatically open your browser ) From 056da9699558eca2ae5c2a541ea39be2dbad4905 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 26 Sep 2025 14:32:15 +0100 Subject: [PATCH 46/71] feat: add logging distinction for mcp/backend/frontend processes for clearer output --- cognee/api/v1/ui/ui.py | 65 ++++++++++++++++++++++++++++++++++++------ 1 file changed, 57 insertions(+), 8 deletions(-) diff --git a/cognee/api/v1/ui/ui.py b/cognee/api/v1/ui/ui.py index af499421b..4d5674832 100644 --- a/cognee/api/v1/ui/ui.py +++ b/cognee/api/v1/ui/ui.py @@ -1,5 +1,4 @@ import os -import signal import socket import subprocess import threading @@ -18,6 +17,46 @@ from cognee.version import get_cognee_version logger = get_logger() +def _stream_process_output( + process: subprocess.Popen, stream_name: str, prefix: str, color_code: str = "" +) -> threading.Thread: + """ + Stream output from a process with a prefix to identify the source. + + Args: + process: The subprocess to monitor + stream_name: 'stdout' or 'stderr' + prefix: Text prefix for each line (e.g., '[BACKEND]', '[FRONTEND]') + color_code: ANSI color code for the prefix (optional) + + Returns: + Thread that handles the streaming + """ + + def stream_reader(): + stream = getattr(process, stream_name) + if stream is None: + return + + reset_code = "\033[0m" if color_code else "" + + try: + for line in iter(stream.readline, b""): + if line: + line_text = line.decode("utf-8").rstrip() + if line_text: + print(f"{color_code}{prefix}{reset_code} {line_text}", flush=True) + except Exception: + pass + finally: + if stream: + stream.close() + + thread = threading.Thread(target=stream_reader, daemon=True) + thread.start() + return thread + + def _is_port_available(port: int) -> bool: """ Check if a port is available on localhost. @@ -455,8 +494,14 @@ def start_ui( "TRANSPORT_MODE=sse", "cognee/cognee-mcp:daulet-dev", ], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) + + _stream_process_output(mcp_process, "stdout", "[MCP]", "\033[34m") # Blue + _stream_process_output(mcp_process, "stderr", "[MCP]", "\033[34m") # Blue + pid_callback(mcp_process.pid) logger.info(f"✓ Cognee MCP server starting on http://127.0.0.1:{mcp_port}/sse") except Exception as e: @@ -478,12 +523,15 @@ def start_ui( "--port", str(backend_port), ], - # Inherit stdout/stderr from parent process to show logs - stdout=None, - stderr=None, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) + # Start threads to stream backend output with prefix + _stream_process_output(backend_process, "stdout", "[BACKEND]", "\033[32m") # Green + _stream_process_output(backend_process, "stderr", "[BACKEND]", "\033[32m") # Green + pid_callback(backend_process.pid) # Give the backend a moment to start @@ -557,6 +605,10 @@ def start_ui( preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) + # Start threads to stream frontend output with prefix + _stream_process_output(process, "stdout", "[FRONTEND]", "\033[33m") # Yellow + _stream_process_output(process, "stderr", "[FRONTEND]", "\033[33m") # Yellow + pid_callback(process.pid) # Give it a moment to start up @@ -564,10 +616,7 @@ def start_ui( # Check if process is still running if process.poll() is not None: - stdout, stderr = process.communicate() - logger.error("Frontend server failed to start:") - logger.error(f"stdout: {stdout}") - logger.error(f"stderr: {stderr}") + logger.error("Frontend server failed to start - check the logs above for details") return None # Open browser if requested From b7441f81cdf6775110cc050491fd4c1beb52e545 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 26 Sep 2025 16:29:14 +0100 Subject: [PATCH 47/71] feat: add health check endpoint to MCP server --- cognee-mcp/src/server.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cognee-mcp/src/server.py b/cognee-mcp/src/server.py index 9393fe71b..7670db9f4 100755 --- a/cognee-mcp/src/server.py +++ b/cognee-mcp/src/server.py @@ -19,6 +19,7 @@ from cognee.api.v1.cognify.code_graph_pipeline import run_code_graph_pipeline from cognee.modules.search.types import SearchType from cognee.shared.data_models import KnowledgeGraph from cognee.modules.storage.utils import JSONEncoder +from starlette.responses import JSONResponse try: @@ -37,6 +38,9 @@ mcp = FastMCP("Cognee") logger = get_logger() +@mcp.custom_route("/health", methods=["GET"]) +async def health_check(request) -> dict: + return JSONResponse({"status": "ok"}) @mcp.tool() async def cognee_add_developer_rules( From 143d9433b1620ce0925df34e7608c7c0980e1db0 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Fri, 26 Sep 2025 17:53:17 +0100 Subject: [PATCH 48/71] refactor: remove text parameter from subprocess call in UI startup --- cognee-mcp/src/server.py | 2 ++ cognee/api/v1/ui/ui.py | 1 - 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/cognee-mcp/src/server.py b/cognee-mcp/src/server.py index 7670db9f4..f249f1d08 100755 --- a/cognee-mcp/src/server.py +++ b/cognee-mcp/src/server.py @@ -38,10 +38,12 @@ mcp = FastMCP("Cognee") logger = get_logger() + @mcp.custom_route("/health", methods=["GET"]) async def health_check(request) -> dict: return JSONResponse({"status": "ok"}) + @mcp.tool() async def cognee_add_developer_rules( base_path: str = ".", graph_model_file: str = None, graph_model_name: str = None diff --git a/cognee/api/v1/ui/ui.py b/cognee/api/v1/ui/ui.py index 4d5674832..7df0b519a 100644 --- a/cognee/api/v1/ui/ui.py +++ b/cognee/api/v1/ui/ui.py @@ -601,7 +601,6 @@ def start_ui( env=env, stdout=subprocess.PIPE, stderr=subprocess.PIPE, - text=True, preexec_fn=os.setsid if hasattr(os, "setsid") else None, ) From 39fa0180f32edfe6815f4db7e5c40400383fbebc Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Fri, 26 Sep 2025 22:42:39 +0200 Subject: [PATCH 49/71] refactor: Make relational database search more effective --- .../ingestion/migrate_relational_database.py | 6 +-- .../relational_database_migration_example.py | 46 +++++++++++++------ 2 files changed, 36 insertions(+), 16 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 936ea59e0..82319e9f5 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -38,7 +38,7 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True table_node = TableType( id=uuid5(NAMESPACE_OID, name=table_name), name=table_name, - description=f"Table: {table_name}", + description=f'Relational database table with the following name: "{table_name}".', ) # Add TableType node to mapping ( node will be added to the graph later based on this mapping ) @@ -75,7 +75,7 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True name=node_id, is_a=table_node, properties=str(row_properties), - description=f"Row in {table_name} with {primary_key_col}={primary_key_value}", + description=f'Row in relational database table from the table with the name: "{table_name}" with the following row data {str(row_properties)} where the dictionary key value is the column name and the value is the column value. This row has the id of: {node_id}', ) # Store the node object in our mapping @@ -113,7 +113,7 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True id=uuid5(NAMESPACE_OID, name=column_node_id), name=column_node_id, properties=f"{key} {value} {table_name}", - description=f"Column name={key} and value={value} from column from table={table_name}", + description=f"column from relational database table={table_name}. Column name={key} and value={value}. The value of the column is related to the following row with this id: {row_node.id}. This column has the following ID: {column_node_id}", ) node_mapping[column_node_id] = column_node diff --git a/examples/python/relational_database_migration_example.py b/examples/python/relational_database_migration_example.py index fae8cfb3d..6a5c3b78b 100644 --- a/examples/python/relational_database_migration_example.py +++ b/examples/python/relational_database_migration_example.py @@ -1,16 +1,15 @@ +from pathlib import Path import asyncio - -import cognee import os +import cognee +from cognee.infrastructure.databases.relational.config import get_migration_config from cognee.infrastructure.databases.graph import get_graph_engine from cognee.api.v1.visualize.visualize import visualize_graph from cognee.infrastructure.databases.relational import ( get_migration_relational_engine, ) - from cognee.modules.search.types import SearchType - from cognee.infrastructure.databases.relational import ( create_db_and_tables as create_relational_db_and_tables, ) @@ -32,16 +31,29 @@ from cognee.infrastructure.databases.vector.pgvector import ( async def main(): - engine = get_migration_relational_engine() - # Clean all data stored in Cognee await cognee.prune.prune_data() await cognee.prune.prune_system(metadata=True) - # Needed to create appropriate tables only on the Cognee side + # Needed to create appropriate database tables only on the Cognee side await create_relational_db_and_tables() await create_vector_db_and_tables() + # In case environment variables are not set use the example database from the Cognee repo + migration_db_provider = os.environ.get("MIGRATION_DB_PROVIDER", "sqlite") + migration_db_path = os.environ.get( + "MIGRATION_DB_PATH", + os.path.join(Path(__file__).resolve().parent.parent.parent, "cognee/tests/test_data"), + ) + migration_db_name = os.environ.get("MIGRATION_DB_NAME", "migration_database.sqlite") + + migration_config = get_migration_config() + migration_config.migration_db_provider = migration_db_provider + migration_config.migration_db_path = migration_db_path + migration_config.migration_db_name = migration_db_name + + engine = get_migration_relational_engine() + print("\nExtracting schema of database to migrate.") schema = await engine.extract_schema() print(f"Migrated database schema:\n{schema}") @@ -53,10 +65,6 @@ async def main(): await migrate_relational_database(graph, schema=schema) print("Relational database migration complete.") - # Define location where to store html visualization of graph of the migrated database - home_dir = os.path.expanduser("~") - destination_file_path = os.path.join(home_dir, "graph_visualization.html") - # Make sure to set top_k at a high value for a broader search, the default value is only 10! # top_k represent the number of graph tripplets to supply to the LLM to answer your question search_results = await cognee.search( @@ -69,13 +77,25 @@ async def main(): # Having a top_k value set to too high might overwhelm the LLM context when specific questions need to be answered. # For this kind of question we've set the top_k to 30 search_results = await cognee.search( - query_type=SearchType.GRAPH_COMPLETION_COT, + query_type=SearchType.GRAPH_COMPLETION, query_text="What invoices are related to Leonie Köhler?", top_k=30, ) print(f"Search results: {search_results}") - # test.html is a file with visualized data migration + search_results = await cognee.search( + query_type=SearchType.GRAPH_COMPLETION, + query_text="What invoices are related to Luís Gonçalves?", + top_k=30, + ) + print(f"Search results: {search_results}") + + # If you check the relational database for this example you can see that the search results successfully found all + # the invoices related to the two customers, without any hallucinations or additional information + + # Define location where to store html visualization of graph of the migrated database + home_dir = os.path.expanduser("~") + destination_file_path = os.path.join(home_dir, "graph_visualization.html") print("Adding html visualization of graph database after migration.") await visualize_graph(destination_file_path) print(f"Visualization can be found at: {destination_file_path}") From 9d801f5fe0a37267f2ece139152ffa79a280d439 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Fri, 12 Sep 2025 10:42:47 +0530 Subject: [PATCH 50/71] Done creating models.py and ingest_database_schema.py --- cognee/tasks/schema/ingest_database_schema.py | 22 +++++++++++++ cognee/tasks/schema/models.py | 32 +++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 cognee/tasks/schema/ingest_database_schema.py create mode 100644 cognee/tasks/schema/models.py diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py new file mode 100644 index 000000000..6f9c538cd --- /dev/null +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -0,0 +1,22 @@ +from typing import List, Dict +from cognee.infrastructure.engine.models.DataPoint import DataPoint + +async def ingest_database_schema( + database_config: Dict, + schema_name: str = "default", + max_sample_rows: int = 5, + node_set: List[str] = ["database_schema"] +) -> List[DataPoint]: + """ + Ingest database schema with sample data into dedicated nodeset + + Args: + database_config: Database connection configuration + schema_name: Name identifier for this schema + max_sample_rows: Maximum sample rows per table + node_set: Target nodeset (default: ["database_schema"]) + + Returns: + List of created DataPoint objects + """ + pass \ No newline at end of file diff --git a/cognee/tasks/schema/models.py b/cognee/tasks/schema/models.py new file mode 100644 index 000000000..b38ec5ff5 --- /dev/null +++ b/cognee/tasks/schema/models.py @@ -0,0 +1,32 @@ +from cognee.infrastructure.engine.models.DataPoint import DataPoint +from typing import List, Dict, Optional +from datetime import datetime + +class DatabaseSchema(DataPoint): + """Represents a complete database schema with sample data""" + schema_name: str + database_type: str # sqlite, postgres, etc. + tables: Dict[str, Dict] # Reuse existing schema format from SqlAlchemyAdapter + sample_data: Dict[str, List[Dict]] # Limited examples per table + extraction_timestamp: datetime + metadata: dict = {"index_fields": ["schema_name", "database_type"]} + +class SchemaTable(DataPoint): + """Represents an individual table schema with relationships""" + table_name: str + schema_name: str + columns: List[Dict] # Column definitions with types + primary_key: Optional[str] + foreign_keys: List[Dict] # Foreign key relationships + sample_rows: List[Dict] # Max 3-5 example rows + row_count_estimate: Optional[int] # Actual table size + metadata: dict = {"index_fields": ["table_name", "schema_name"]} + +class SchemaRelationship(DataPoint): + """Represents relationships between tables""" + source_table: str + target_table: str + relationship_type: str # "foreign_key", "one_to_many", etc. + source_column: str + target_column: str + metadata: dict = {"index_fields": ["source_table", "target_table"]} \ No newline at end of file From a43f19cc5914f46d9a83e1b3e7a25189f89cf252 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sat, 13 Sep 2025 14:33:06 +0530 Subject: [PATCH 51/71] ingest_database_schema with a slight alteration with return value as Dict[str,List[DataPoint] | DataPoint]] --- cognee/tasks/schema/ingest_database_schema.py | 63 ++++++++++++++++++- 1 file changed, 61 insertions(+), 2 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 6f9c538cd..2b9cd38c5 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -1,12 +1,17 @@ from typing import List, Dict from cognee.infrastructure.engine.models.DataPoint import DataPoint +from cognee.infrastructure.databases.relational.get_migration_relational_engine import get_migration_relational_engine +from sqlalchemy import text +from cognee.tasks.schema.models import DatabaseSchema, SchemaTable, SchemaRelationship +from cognee.infrastructure.databases.relational.create_relational_engine import create_relational_engine +from datetime import datetime async def ingest_database_schema( database_config: Dict, schema_name: str = "default", max_sample_rows: int = 5, node_set: List[str] = ["database_schema"] -) -> List[DataPoint]: +) -> Dict[str, List[DataPoint]|DataPoint]: """ Ingest database schema with sample data into dedicated nodeset @@ -19,4 +24,58 @@ async def ingest_database_schema( Returns: List of created DataPoint objects """ - pass \ No newline at end of file + engine = create_relational_engine( + db_path=database_config.get("db_path", ""), + db_name=database_config.get("db_name", "cognee_db"), + db_host=database_config.get("db_host"), + db_port=database_config.get("db_port"), + db_username=database_config.get("db_username"), + db_password=database_config.get("db_password"), + db_provider=database_config.get("db_provider", "sqlite"), + ) + schema = await engine.extract_schema() + tables={} + sample_data={} + schema_tables = [] + schema_relationships = [] + async with engine.engine.begin() as cursor: + for table_name, details in schema.items(): + rows_result = await cursor.execute(text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}")) + rows = [dict(zip([col["name"] for col in details["columns"]], row)) for row in rows_result.fetchall()] + count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {table_name};")) + row_count_estimate = count_result.scalar() + schema_table = SchemaTable( + table_name=table_name, + schema_name=schema_name, + columns=details["columns"], + primary_key=details.get("primary_key"), + foreign_keys=details.get("foreign_keys", []), + sample_rows=rows, + row_count_estimate=row_count_estimate + ) + schema_tables.append(schema_table) + tables[table_name] = details + sample_data[table_name] = rows + + for fk in details.get("foreign_keys",[]): + relationship = SchemaRelationship( + source_table=table_name, + target_table=fk["ref_table"], + relationship_type=fk["type"], + source_column=fk["source_column"], + target_column=fk["target_column"] + ) + schema_relationships.append(relationship) + database_schema = DatabaseSchema( + schema_name=schema_name, + database_type=database_config.get("db_provider", "sqlite"), + tables=tables, + sample_data=sample_data, + extraction_timestamp=datetime.utcnow() + ) + + return{ + "database_schema": database_schema, + "schema_tables": schema_tables, + "relationships": schema_relationships + } \ No newline at end of file From 17df14363c96e8c01d6927a99932ec751869539e Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sun, 14 Sep 2025 03:26:06 +0530 Subject: [PATCH 52/71] integrated schema only ingestion --- .../ingestion/migrate_relational_database.py | 350 +++++++++++------- 1 file changed, 211 insertions(+), 139 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 936ea59e0..e535a0ed8 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -4,16 +4,19 @@ from sqlalchemy import text from cognee.infrastructure.databases.relational.get_migration_relational_engine import ( get_migration_relational_engine, ) +from cognee.infrastructure.databases.relational.config import get_migration_config from cognee.tasks.storage.index_data_points import index_data_points from cognee.tasks.storage.index_graph_edges import index_graph_edges +from cognee.tasks.schema.ingest_database_schema import ingest_database_schema +from cognee.tasks.schema.models import SchemaTable from cognee.modules.engine.models import TableRow, TableType, ColumnValue logger = logging.getLogger(__name__) -async def migrate_relational_database(graph_db, schema, migrate_column_data=True): +async def migrate_relational_database(graph_db, schema, migrate_column_data=True,schema_only=False): """ Migrates data from a relational database into a graph database. @@ -30,157 +33,226 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True # Create a mapping of node_id to node objects for referencing in edge creation node_mapping = {} edge_mapping = [] - - async with engine.engine.begin() as cursor: - # First, create table type nodes for all tables - for table_name, details in schema.items(): - # Create a TableType node for each table - table_node = TableType( - id=uuid5(NAMESPACE_OID, name=table_name), - name=table_name, - description=f"Table: {table_name}", - ) - - # Add TableType node to mapping ( node will be added to the graph later based on this mapping ) - node_mapping[table_name] = table_node - - # Fetch all rows for the current table - rows_result = await cursor.execute(text(f"SELECT * FROM {table_name};")) - rows = rows_result.fetchall() - - for row in rows: - # Build a dictionary of properties from the row - row_properties = { - col["name"]: row[idx] for idx, col in enumerate(details["columns"]) - } - - # Determine the primary key value - if not details["primary_key"]: - # Use the first column as primary key if not specified - primary_key_col = details["columns"][0]["name"] - primary_key_value = row_properties[primary_key_col] - else: - # Use value of the specified primary key column - primary_key_col = details["primary_key"] - primary_key_value = row_properties[primary_key_col] - - # Create a node ID in the format "table_name:primary_key_value" - node_id = f"{table_name}:{primary_key_value}" - - # Create a TableRow node - # Node id must uniquely map to the id used in the relational database - # To catch the foreign key relationships properly - row_node = TableRow( - id=uuid5(NAMESPACE_OID, name=node_id), - name=node_id, - is_a=table_node, - properties=str(row_properties), - description=f"Row in {table_name} with {primary_key_col}={primary_key_value}", + + if schema_only: + database_config = get_migration_config().to_dict() + # Calling the ingest_database_schema function to return DataPoint subclasses + result = await ingest_database_schema( + database_config=database_config, + schema_name="migrated_schema", + max_sample_rows=5, + node_set=["database_schema", "schema_tables", "relationships"] + ) + database_schema = result["database_schema"] + schema_tables = result["schema_tables"] + schema_relationships = result["relationships"] + database_node_id = database_schema.id + node_mapping[database_node_id] = database_schema + for table in schema_tables: + table_node_id = table.id + # Add TableSchema Datapoint as a node. + node_mapping[table_node_id]=table + edge_mapping.append(( + table_node_id, + database_node_id, + "is_part_of", + dict( + source_node_id=table_node_id, + target_node_id=database_node_id, + relationship_name="is_part_of", + ), + )) + for rel in schema_relationships: + source_table_id = uuid5(NAMESPACE_OID,name=rel.source_table) + target_table_id = uuid5(NAMESPACE_OID,name=rel.target_table) + relationship_id = rel.id + + # Add RelationshipTable DataPoint as a node. + node_mapping[relationship_id]=rel + edge_mapping.append(( + source_table_id, + relationship_id, + "has_relationship", + dict( + source_node_id=source_table_id, + target_node_id=relationship_id, + relationship_name=rel.relationship_type, + ), + )) + edge_mapping.append(( + relationship_id, + target_table_id, + "has_relationship", + dict( + source_node_id=relationship_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ) + )) + edge_mapping.append(( + source_table_id, + target_table_id, + rel.relationship_type, + dict( + source_node_id=source_table_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ), + )) + + + + else: + async with engine.engine.begin() as cursor: + # First, create table type nodes for all tables + for table_name, details in schema.items(): + # Create a TableType node for each table + table_node = TableType( + id=uuid5(NAMESPACE_OID, name=table_name), + name=table_name, + description=f"Table: {table_name}", ) - # Store the node object in our mapping - node_mapping[node_id] = row_node + # Add TableType node to mapping ( node will be added to the graph later based on this mapping ) + node_mapping[table_name] = table_node - # Add edge between row node and table node ( it will be added to the graph later ) - edge_mapping.append( - ( - row_node.id, - table_node.id, - "is_part_of", - dict( - relationship_name="is_part_of", - source_node_id=row_node.id, - target_node_id=table_node.id, - ), + # Fetch all rows for the current table + rows_result = await cursor.execute(text(f"SELECT * FROM {table_name};")) + rows = rows_result.fetchall() + + for row in rows: + # Build a dictionary of properties from the row + row_properties = { + col["name"]: row[idx] for idx, col in enumerate(details["columns"]) + } + + # Determine the primary key value + if not details["primary_key"]: + # Use the first column as primary key if not specified + primary_key_col = details["columns"][0]["name"] + primary_key_value = row_properties[primary_key_col] + else: + # Use value of the specified primary key column + primary_key_col = details["primary_key"] + primary_key_value = row_properties[primary_key_col] + + # Create a node ID in the format "table_name:primary_key_value" + node_id = f"{table_name}:{primary_key_value}" + + # Create a TableRow node + # Node id must uniquely map to the id used in the relational database + # To catch the foreign key relationships properly + row_node = TableRow( + id=uuid5(NAMESPACE_OID, name=node_id), + name=node_id, + is_a=table_node, + properties=str(row_properties), + description=f"Row in {table_name} with {primary_key_col}={primary_key_value}", ) - ) - # Migrate data stored in columns of table rows - if migrate_column_data: - # Get foreign key columns to filter them out from column migration - foreign_keys = [] - for fk in details.get("foreign_keys", []): - foreign_keys.append(fk["ref_column"]) + # Store the node object in our mapping + node_mapping[node_id] = row_node - for key, value in row_properties.items(): - # Skip mapping primary key information to itself and mapping of foreign key information (as it will be mapped bellow) - if key is primary_key_col or key in foreign_keys: - continue - - # Create column value node - column_node_id = f"{table_name}:{key}:{value}" - column_node = ColumnValue( - id=uuid5(NAMESPACE_OID, name=column_node_id), - name=column_node_id, - properties=f"{key} {value} {table_name}", - description=f"Column name={key} and value={value} from column from table={table_name}", - ) - node_mapping[column_node_id] = column_node - - # Create relationship between column value of table row and table row - edge_mapping.append( - ( - row_node.id, - column_node.id, - key, - dict( - relationship_name=key, - source_node_id=row_node.id, - target_node_id=column_node.id, - ), - ) - ) - - # Process foreign key relationships after all nodes are created - for table_name, details in schema.items(): - # Process foreign key relationships for the current table - for fk in details.get("foreign_keys", []): - # Aliases needed for self-referencing tables - alias_1 = f"{table_name}_e1" - alias_2 = f"{fk['ref_table']}_e2" - - # Determine primary key column - if not details["primary_key"]: - primary_key_col = details["columns"][0]["name"] - else: - primary_key_col = details["primary_key"] - - # Query to find relationships based on foreign keys - fk_query = text( - f"SELECT {alias_1}.{primary_key_col} AS source_id, " - f"{alias_2}.{fk['ref_column']} AS ref_value " - f"FROM {table_name} AS {alias_1} " - f"JOIN {fk['ref_table']} AS {alias_2} " - f"ON {alias_1}.{fk['column']} = {alias_2}.{fk['ref_column']};" - ) - - fk_result = await cursor.execute(fk_query) - relations = fk_result.fetchall() - - for source_id, ref_value in relations: - # Construct node ids - source_node_id = f"{table_name}:{source_id}" - target_node_id = f"{fk['ref_table']}:{ref_value}" - - # Get the source and target node objects from our mapping - source_node = node_mapping[source_node_id] - target_node = node_mapping[target_node_id] - - # Add edge representing the foreign key relationship using the node objects - # Create edge to add to graph later + # Add edge between row node and table node ( it will be added to the graph later ) edge_mapping.append( ( - source_node.id, - target_node.id, - fk["column"], + row_node.id, + table_node.id, + "is_part_of", dict( - source_node_id=source_node.id, - target_node_id=target_node.id, - relationship_name=fk["column"], + relationship_name="is_part_of", + source_node_id=row_node.id, + target_node_id=table_node.id, ), ) ) + # Migrate data stored in columns of table rows + if migrate_column_data: + # Get foreign key columns to filter them out from column migration + foreign_keys = [] + for fk in details.get("foreign_keys", []): + foreign_keys.append(fk["ref_column"]) + + for key, value in row_properties.items(): + # Skip mapping primary key information to itself and mapping of foreign key information (as it will be mapped bellow) + if key is primary_key_col or key in foreign_keys: + continue + + # Create column value node + column_node_id = f"{table_name}:{key}:{value}" + column_node = ColumnValue( + id=uuid5(NAMESPACE_OID, name=column_node_id), + name=column_node_id, + properties=f"{key} {value} {table_name}", + description=f"Column name={key} and value={value} from column from table={table_name}", + ) + node_mapping[column_node_id] = column_node + + # Create relationship between column value of table row and table row + edge_mapping.append( + ( + row_node.id, + column_node.id, + key, + dict( + relationship_name=key, + source_node_id=row_node.id, + target_node_id=column_node.id, + ), + ) + ) + + # Process foreign key relationships after all nodes are created + for table_name, details in schema.items(): + # Process foreign key relationships for the current table + for fk in details.get("foreign_keys", []): + # Aliases needed for self-referencing tables + alias_1 = f"{table_name}_e1" + alias_2 = f"{fk['ref_table']}_e2" + + # Determine primary key column + if not details["primary_key"]: + primary_key_col = details["columns"][0]["name"] + else: + primary_key_col = details["primary_key"] + + # Query to find relationships based on foreign keys + fk_query = text( + f"SELECT {alias_1}.{primary_key_col} AS source_id, " + f"{alias_2}.{fk['ref_column']} AS ref_value " + f"FROM {table_name} AS {alias_1} " + f"JOIN {fk['ref_table']} AS {alias_2} " + f"ON {alias_1}.{fk['column']} = {alias_2}.{fk['ref_column']};" + ) + + fk_result = await cursor.execute(fk_query) + relations = fk_result.fetchall() + + for source_id, ref_value in relations: + # Construct node ids + source_node_id = f"{table_name}:{source_id}" + target_node_id = f"{fk['ref_table']}:{ref_value}" + + # Get the source and target node objects from our mapping + source_node = node_mapping[source_node_id] + target_node = node_mapping[target_node_id] + + # Add edge representing the foreign key relationship using the node objects + # Create edge to add to graph later + edge_mapping.append( + ( + source_node.id, + target_node.id, + fk["column"], + dict( + source_node_id=source_node.id, + target_node_id=target_node.id, + relationship_name=fk["column"], + ), + ) + ) + def _remove_duplicate_edges(edge_mapping): seen = set() unique_original_shape = [] From f5bb91e49df908c2eed636c539196aa2c4cba4ca Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sun, 14 Sep 2025 03:29:38 +0530 Subject: [PATCH 53/71] added description attribute to every schema model --- cognee/tasks/schema/ingest_database_schema.py | 53 ++++++++++++------- cognee/tasks/schema/models.py | 5 +- 2 files changed, 37 insertions(+), 21 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 2b9cd38c5..6d6f0b5f3 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -1,4 +1,5 @@ from typing import List, Dict +from uuid import uuid5, NAMESPACE_OID from cognee.infrastructure.engine.models.DataPoint import DataPoint from cognee.infrastructure.databases.relational.get_migration_relational_engine import get_migration_relational_engine from sqlalchemy import text @@ -11,7 +12,7 @@ async def ingest_database_schema( schema_name: str = "default", max_sample_rows: int = 5, node_set: List[str] = ["database_schema"] -) -> Dict[str, List[DataPoint]|DataPoint]: +) -> Dict[str, List[DataPoint] | DataPoint]: """ Ingest database schema with sample data into dedicated nodeset @@ -25,57 +26,69 @@ async def ingest_database_schema( List of created DataPoint objects """ engine = create_relational_engine( - db_path=database_config.get("db_path", ""), - db_name=database_config.get("db_name", "cognee_db"), - db_host=database_config.get("db_host"), - db_port=database_config.get("db_port"), - db_username=database_config.get("db_username"), - db_password=database_config.get("db_password"), - db_provider=database_config.get("db_provider", "sqlite"), + db_path=database_config.get("migration_db_path", ""), + db_name=database_config.get("migration_db_name", "cognee_db"), + db_host=database_config.get("migration_db_host"), + db_port=database_config.get("migration_db_port"), + db_username=database_config.get("migration_db_username"), + db_password=database_config.get("migration_db_password"), + db_provider=database_config.get("migration_db_provider", "sqlite"), ) schema = await engine.extract_schema() - tables={} - sample_data={} + tables = {} + sample_data = {} schema_tables = [] schema_relationships = [] + async with engine.engine.begin() as cursor: for table_name, details in schema.items(): + print(table_name) rows_result = await cursor.execute(text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}")) rows = [dict(zip([col["name"] for col in details["columns"]], row)) for row in rows_result.fetchall()] count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {table_name};")) row_count_estimate = count_result.scalar() + schema_table = SchemaTable( + id=uuid5(NAMESPACE_OID, name=table_name), table_name=table_name, schema_name=schema_name, columns=details["columns"], primary_key=details.get("primary_key"), foreign_keys=details.get("foreign_keys", []), sample_rows=rows, - row_count_estimate=row_count_estimate + row_count_estimate=row_count_estimate, + description=f"Schema table for '{table_name}' with {len(details['columns'])} columns and approx. {row_count_estimate} rows." ) schema_tables.append(schema_table) tables[table_name] = details sample_data[table_name] = rows - - for fk in details.get("foreign_keys",[]): + + for fk in details.get("foreign_keys", []): + print(f"ref_table:{fk['ref_table']}") + print(f"table_name:{table_name}") relationship = SchemaRelationship( + id=uuid5(NAMESPACE_OID, name=f"{fk['column']}:{table_name}:{fk['ref_column']}:{fk['ref_table']}"), source_table=table_name, target_table=fk["ref_table"], - relationship_type=fk["type"], - source_column=fk["source_column"], - target_column=fk["target_column"] + relationship_type="foreign_key", + source_column=fk["column"], + target_column=fk["ref_column"], + description=f"Foreign key relationship: {table_name}.{fk['column']} → {fk['ref_table']}.{fk['ref_column']}" ) schema_relationships.append(relationship) + database_schema = DatabaseSchema( + id=uuid5(NAMESPACE_OID, name=schema_name), schema_name=schema_name, database_type=database_config.get("db_provider", "sqlite"), tables=tables, sample_data=sample_data, - extraction_timestamp=datetime.utcnow() + extraction_timestamp=datetime.utcnow(), + description=f"Database schema '{schema_name}' containing {len(schema_tables)} tables and {len(schema_relationships)} relationships." ) - - return{ + + return { "database_schema": database_schema, "schema_tables": schema_tables, "relationships": schema_relationships - } \ No newline at end of file + } diff --git a/cognee/tasks/schema/models.py b/cognee/tasks/schema/models.py index b38ec5ff5..ef9374163 100644 --- a/cognee/tasks/schema/models.py +++ b/cognee/tasks/schema/models.py @@ -9,6 +9,7 @@ class DatabaseSchema(DataPoint): tables: Dict[str, Dict] # Reuse existing schema format from SqlAlchemyAdapter sample_data: Dict[str, List[Dict]] # Limited examples per table extraction_timestamp: datetime + description: str metadata: dict = {"index_fields": ["schema_name", "database_type"]} class SchemaTable(DataPoint): @@ -20,13 +21,15 @@ class SchemaTable(DataPoint): foreign_keys: List[Dict] # Foreign key relationships sample_rows: List[Dict] # Max 3-5 example rows row_count_estimate: Optional[int] # Actual table size + description: str metadata: dict = {"index_fields": ["table_name", "schema_name"]} class SchemaRelationship(DataPoint): """Represents relationships between tables""" source_table: str target_table: str - relationship_type: str # "foreign_key", "one_to_many", etc. + relationship_type: str source_column: str target_column: str + description: str metadata: dict = {"index_fields": ["source_table", "target_table"]} \ No newline at end of file From 51dfac359debcaa05d685412d53f559547de7f6c Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sun, 14 Sep 2025 21:30:26 +0530 Subject: [PATCH 54/71] Removed print statements used while debugging --- cognee/tasks/schema/ingest_database_schema.py | 9 +++------ cognee/tasks/schema/models.py | 2 +- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 6d6f0b5f3..2ac57d0ba 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -42,7 +42,6 @@ async def ingest_database_schema( async with engine.engine.begin() as cursor: for table_name, details in schema.items(): - print(table_name) rows_result = await cursor.execute(text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}")) rows = [dict(zip([col["name"] for col in details["columns"]], row)) for row in rows_result.fetchall()] count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {table_name};")) @@ -57,15 +56,13 @@ async def ingest_database_schema( foreign_keys=details.get("foreign_keys", []), sample_rows=rows, row_count_estimate=row_count_estimate, - description=f"Schema table for '{table_name}' with {len(details['columns'])} columns and approx. {row_count_estimate} rows." + description=f"" ) schema_tables.append(schema_table) tables[table_name] = details sample_data[table_name] = rows for fk in details.get("foreign_keys", []): - print(f"ref_table:{fk['ref_table']}") - print(f"table_name:{table_name}") relationship = SchemaRelationship( id=uuid5(NAMESPACE_OID, name=f"{fk['column']}:{table_name}:{fk['ref_column']}:{fk['ref_table']}"), source_table=table_name, @@ -73,7 +70,7 @@ async def ingest_database_schema( relationship_type="foreign_key", source_column=fk["column"], target_column=fk["ref_column"], - description=f"Foreign key relationship: {table_name}.{fk['column']} → {fk['ref_table']}.{fk['ref_column']}" + description=f"" ) schema_relationships.append(relationship) @@ -84,7 +81,7 @@ async def ingest_database_schema( tables=tables, sample_data=sample_data, extraction_timestamp=datetime.utcnow(), - description=f"Database schema '{schema_name}' containing {len(schema_tables)} tables and {len(schema_relationships)} relationships." + description=f"" ) return { diff --git a/cognee/tasks/schema/models.py b/cognee/tasks/schema/models.py index ef9374163..0fb248758 100644 --- a/cognee/tasks/schema/models.py +++ b/cognee/tasks/schema/models.py @@ -28,7 +28,7 @@ class SchemaRelationship(DataPoint): """Represents relationships between tables""" source_table: str target_table: str - relationship_type: str + relationship_type: str # "foreign_key", "one_to_many", etc. source_column: str target_column: str description: str From 1ba9e1df317810b0ba796dd3fe75b8ca4c61cb89 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sun, 14 Sep 2025 21:56:31 +0530 Subject: [PATCH 55/71] done with ruff checks --- .../ingestion/migrate_relational_database.py | 117 ++++++++++-------- cognee/tasks/schema/ingest_database_schema.py | 37 ++++-- cognee/tasks/schema/models.py | 8 +- 3 files changed, 95 insertions(+), 67 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index e535a0ed8..62a8a0eac 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -16,7 +16,9 @@ from cognee.modules.engine.models import TableRow, TableType, ColumnValue logger = logging.getLogger(__name__) -async def migrate_relational_database(graph_db, schema, migrate_column_data=True,schema_only=False): +async def migrate_relational_database( + graph_db, schema, migrate_column_data=True, schema_only=False +): """ Migrates data from a relational database into a graph database. @@ -33,15 +35,15 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True # Create a mapping of node_id to node objects for referencing in edge creation node_mapping = {} edge_mapping = [] - + if schema_only: - database_config = get_migration_config().to_dict() + database_config = get_migration_config().to_dict() # Calling the ingest_database_schema function to return DataPoint subclasses result = await ingest_database_schema( database_config=database_config, schema_name="migrated_schema", max_sample_rows=5, - node_set=["database_schema", "schema_tables", "relationships"] + node_set=["database_schema", "schema_tables", "relationships"], ) database_schema = result["database_schema"] schema_tables = result["schema_tables"] @@ -51,57 +53,64 @@ async def migrate_relational_database(graph_db, schema, migrate_column_data=True for table in schema_tables: table_node_id = table.id # Add TableSchema Datapoint as a node. - node_mapping[table_node_id]=table - edge_mapping.append(( - table_node_id, - database_node_id, - "is_part_of", - dict( - source_node_id=table_node_id, - target_node_id=database_node_id, - relationship_name="is_part_of", - ), - )) - for rel in schema_relationships: - source_table_id = uuid5(NAMESPACE_OID,name=rel.source_table) - target_table_id = uuid5(NAMESPACE_OID,name=rel.target_table) - relationship_id = rel.id - - # Add RelationshipTable DataPoint as a node. - node_mapping[relationship_id]=rel - edge_mapping.append(( - source_table_id, - relationship_id, - "has_relationship", - dict( - source_node_id=source_table_id, - target_node_id=relationship_id, - relationship_name=rel.relationship_type, - ), - )) - edge_mapping.append(( - relationship_id, - target_table_id, - "has_relationship", - dict( - source_node_id=relationship_id, - target_node_id=target_table_id, - relationship_name=rel.relationship_type, + node_mapping[table_node_id] = table + edge_mapping.append( + ( + table_node_id, + database_node_id, + "is_part_of", + dict( + source_node_id=table_node_id, + target_node_id=database_node_id, + relationship_name="is_part_of", + ), ) - )) - edge_mapping.append(( - source_table_id, - target_table_id, - rel.relationship_type, - dict( - source_node_id=source_table_id, - target_node_id=target_table_id, - relationship_name=rel.relationship_type, - ), - )) - - - + ) + for rel in schema_relationships: + source_table_id = uuid5(NAMESPACE_OID, name=rel.source_table) + target_table_id = uuid5(NAMESPACE_OID, name=rel.target_table) + + relationship_id = rel.id + + # Add RelationshipTable DataPoint as a node. + node_mapping[relationship_id] = rel + edge_mapping.append( + ( + source_table_id, + relationship_id, + "has_relationship", + dict( + source_node_id=source_table_id, + target_node_id=relationship_id, + relationship_name=rel.relationship_type, + ), + ) + ) + edge_mapping.append( + ( + relationship_id, + target_table_id, + "has_relationship", + dict( + source_node_id=relationship_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ), + ) + ) + edge_mapping.append( + ( + source_table_id, + target_table_id, + rel.relationship_type, + dict( + source_node_id=source_table_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ), + ) + ) + else: async with engine.engine.begin() as cursor: # First, create table type nodes for all tables diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 2ac57d0ba..c4c13449d 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -1,27 +1,32 @@ from typing import List, Dict from uuid import uuid5, NAMESPACE_OID from cognee.infrastructure.engine.models.DataPoint import DataPoint -from cognee.infrastructure.databases.relational.get_migration_relational_engine import get_migration_relational_engine +from cognee.infrastructure.databases.relational.get_migration_relational_engine import ( + get_migration_relational_engine, +) from sqlalchemy import text from cognee.tasks.schema.models import DatabaseSchema, SchemaTable, SchemaRelationship -from cognee.infrastructure.databases.relational.create_relational_engine import create_relational_engine +from cognee.infrastructure.databases.relational.create_relational_engine import ( + create_relational_engine, +) from datetime import datetime + async def ingest_database_schema( database_config: Dict, schema_name: str = "default", max_sample_rows: int = 5, - node_set: List[str] = ["database_schema"] + node_set: List[str] = ["database_schema"], ) -> Dict[str, List[DataPoint] | DataPoint]: """ Ingest database schema with sample data into dedicated nodeset - + Args: database_config: Database connection configuration schema_name: Name identifier for this schema max_sample_rows: Maximum sample rows per table node_set: Target nodeset (default: ["database_schema"]) - + Returns: List of created DataPoint objects """ @@ -42,8 +47,13 @@ async def ingest_database_schema( async with engine.engine.begin() as cursor: for table_name, details in schema.items(): - rows_result = await cursor.execute(text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}")) - rows = [dict(zip([col["name"] for col in details["columns"]], row)) for row in rows_result.fetchall()] + rows_result = await cursor.execute( + text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}") + ) + rows = [ + dict(zip([col["name"] for col in details["columns"]], row)) + for row in rows_result.fetchall() + ] count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {table_name};")) row_count_estimate = count_result.scalar() @@ -56,7 +66,7 @@ async def ingest_database_schema( foreign_keys=details.get("foreign_keys", []), sample_rows=rows, row_count_estimate=row_count_estimate, - description=f"" + description=f"Schema table for '{table_name}' with {len(details['columns'])} columns and approx. {row_count_estimate} rows.", ) schema_tables.append(schema_table) tables[table_name] = details @@ -64,13 +74,16 @@ async def ingest_database_schema( for fk in details.get("foreign_keys", []): relationship = SchemaRelationship( - id=uuid5(NAMESPACE_OID, name=f"{fk['column']}:{table_name}:{fk['ref_column']}:{fk['ref_table']}"), + id=uuid5( + NAMESPACE_OID, + name=f"{fk['column']}:{table_name}:{fk['ref_column']}:{fk['ref_table']}", + ), source_table=table_name, target_table=fk["ref_table"], relationship_type="foreign_key", source_column=fk["column"], target_column=fk["ref_column"], - description=f"" + description=f"Foreign key relationship: {table_name}.{fk['column']} → {fk['ref_table']}.{fk['ref_column']}", ) schema_relationships.append(relationship) @@ -81,11 +94,11 @@ async def ingest_database_schema( tables=tables, sample_data=sample_data, extraction_timestamp=datetime.utcnow(), - description=f"" + description=f"Database schema '{schema_name}' containing {len(schema_tables)} tables and {len(schema_relationships)} relationships.", ) return { "database_schema": database_schema, "schema_tables": schema_tables, - "relationships": schema_relationships + "relationships": schema_relationships, } diff --git a/cognee/tasks/schema/models.py b/cognee/tasks/schema/models.py index 0fb248758..423c92050 100644 --- a/cognee/tasks/schema/models.py +++ b/cognee/tasks/schema/models.py @@ -2,8 +2,10 @@ from cognee.infrastructure.engine.models.DataPoint import DataPoint from typing import List, Dict, Optional from datetime import datetime + class DatabaseSchema(DataPoint): """Represents a complete database schema with sample data""" + schema_name: str database_type: str # sqlite, postgres, etc. tables: Dict[str, Dict] # Reuse existing schema format from SqlAlchemyAdapter @@ -12,8 +14,10 @@ class DatabaseSchema(DataPoint): description: str metadata: dict = {"index_fields": ["schema_name", "database_type"]} + class SchemaTable(DataPoint): """Represents an individual table schema with relationships""" + table_name: str schema_name: str columns: List[Dict] # Column definitions with types @@ -24,12 +28,14 @@ class SchemaTable(DataPoint): description: str metadata: dict = {"index_fields": ["table_name", "schema_name"]} + class SchemaRelationship(DataPoint): """Represents relationships between tables""" + source_table: str target_table: str relationship_type: str # "foreign_key", "one_to_many", etc. source_column: str target_column: str description: str - metadata: dict = {"index_fields": ["source_table", "target_table"]} \ No newline at end of file + metadata: dict = {"index_fields": ["source_table", "target_table"]} From 7cf4a0daeb260318bb2f9db9c32b69c2187f1db5 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 11:12:43 +0530 Subject: [PATCH 56/71] id mismatch risk negated --- cognee/tasks/ingestion/migrate_relational_database.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 62a8a0eac..e857ab34d 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -66,9 +66,10 @@ async def migrate_relational_database( ), ) ) + table_name_to_id = {t.table_name: t.id for t in schema_tables} for rel in schema_relationships: - source_table_id = uuid5(NAMESPACE_OID, name=rel.source_table) - target_table_id = uuid5(NAMESPACE_OID, name=rel.target_table) + source_table_id = table_name_to_id.get(rel.source_table) + target_table_id = table_name_to_id.get(rel.target_table) relationship_id = rel.id From 60016a6b09a76083ce01baeb38b1559b0acd130a Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 12:55:38 +0530 Subject: [PATCH 57/71] more nitpick comments solved --- cognee/tasks/schema/ingest_database_schema.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index c4c13449d..f93314a3d 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -47,8 +47,11 @@ async def ingest_database_schema( async with engine.engine.begin() as cursor: for table_name, details in schema.items(): + qi = engine.engine.dialect.identifier_preparer.quote + tn = qi(table_name) rows_result = await cursor.execute( - text(f"SELECT * FROM {table_name} LIMIT {max_sample_rows}") + text(f"SELECT * FROM {tn} LIMIT :limit;"), + {"limit": max_sample_rows} ) rows = [ dict(zip([col["name"] for col in details["columns"]], row)) @@ -58,7 +61,7 @@ async def ingest_database_schema( row_count_estimate = count_result.scalar() schema_table = SchemaTable( - id=uuid5(NAMESPACE_OID, name=table_name), + id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{table_name}"), table_name=table_name, schema_name=schema_name, columns=details["columns"], From 7ec066111ed0d8323d5dedca74b065186a8a2d73 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 13:39:15 +0530 Subject: [PATCH 58/71] Solved address configuration key inconsistency. --- cognee/tasks/schema/ingest_database_schema.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index f93314a3d..e80ce2e75 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -93,7 +93,7 @@ async def ingest_database_schema( database_schema = DatabaseSchema( id=uuid5(NAMESPACE_OID, name=schema_name), schema_name=schema_name, - database_type=database_config.get("db_provider", "sqlite"), + database_type=database_config.get("migration_db_provider", "sqlite"), tables=tables, sample_data=sample_data, extraction_timestamp=datetime.utcnow(), From 93c733e6871f7232bc847a00829f9903611c6048 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 16:13:32 +0530 Subject: [PATCH 59/71] solved more nitpick comments --- .../ingestion/migrate_relational_database.py | 1 - cognee/tasks/schema/ingest_database_schema.py | 20 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index e857ab34d..824fef2fa 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -43,7 +43,6 @@ async def migrate_relational_database( database_config=database_config, schema_name="migrated_schema", max_sample_rows=5, - node_set=["database_schema", "schema_tables", "relationships"], ) database_schema = result["database_schema"] schema_tables = result["schema_tables"] diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index e80ce2e75..be544408b 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -1,4 +1,4 @@ -from typing import List, Dict +from typing import List, Dict, Optional from uuid import uuid5, NAMESPACE_OID from cognee.infrastructure.engine.models.DataPoint import DataPoint from cognee.infrastructure.databases.relational.get_migration_relational_engine import ( @@ -16,7 +16,6 @@ async def ingest_database_schema( database_config: Dict, schema_name: str = "default", max_sample_rows: int = 5, - node_set: List[str] = ["database_schema"], ) -> Dict[str, List[DataPoint] | DataPoint]: """ Ingest database schema with sample data into dedicated nodeset @@ -25,7 +24,6 @@ async def ingest_database_schema( database_config: Database connection configuration schema_name: Name identifier for this schema max_sample_rows: Maximum sample rows per table - node_set: Target nodeset (default: ["database_schema"]) Returns: List of created DataPoint objects @@ -48,6 +46,8 @@ async def ingest_database_schema( async with engine.engine.begin() as cursor: for table_name, details in schema.items(): qi = engine.engine.dialect.identifier_preparer.quote + qname = lambda name : ".".join(qi(p) for p in name.split(".")) + tn = qname(table_name) tn = qi(table_name) rows_result = await cursor.execute( text(f"SELECT * FROM {tn} LIMIT :limit;"), @@ -57,11 +57,11 @@ async def ingest_database_schema( dict(zip([col["name"] for col in details["columns"]], row)) for row in rows_result.fetchall() ] - count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {table_name};")) + count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {tn};")) row_count_estimate = count_result.scalar() schema_table = SchemaTable( - id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{table_name}"), + id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{tn}"), table_name=table_name, schema_name=schema_name, columns=details["columns"], @@ -76,17 +76,21 @@ async def ingest_database_schema( sample_data[table_name] = rows for fk in details.get("foreign_keys", []): + ref_table_fq = fk["ref_table"] + if '.' not in ref_table_fq and '.' in table_name: + ref_table_fq = f"{table_name.split('.', 1)[0]}.{ref_table_fq}" + relationship = SchemaRelationship( id=uuid5( NAMESPACE_OID, - name=f"{fk['column']}:{table_name}:{fk['ref_column']}:{fk['ref_table']}", + name=f"{schema_name}:{table_name}:{fk['column']}->{ref_table_fq}:{fk['ref_column']}", ), source_table=table_name, - target_table=fk["ref_table"], + target_table=ref_table_fq, relationship_type="foreign_key", source_column=fk["column"], target_column=fk["ref_column"], - description=f"Foreign key relationship: {table_name}.{fk['column']} → {fk['ref_table']}.{fk['ref_column']}", + description=f"Foreign key relationship: {table_name}.{fk['column']} → {ref_table_fq}.{fk['ref_column']}", ) schema_relationships.append(relationship) From 1e59f1594cf6778a866a6f4c8906d58faa98fa76 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 16:30:58 +0530 Subject: [PATCH 60/71] solved more nitpick comments --- cognee/tasks/schema/ingest_database_schema.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index be544408b..2a343ea0d 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -26,7 +26,10 @@ async def ingest_database_schema( max_sample_rows: Maximum sample rows per table Returns: - List of created DataPoint objects + Dict with keys: + "database_schema": DatabaseSchema + "schema_tables": List[SchemaTable] + "relationships": List[SchemaRelationship] """ engine = create_relational_engine( db_path=database_config.get("migration_db_path", ""), @@ -48,7 +51,6 @@ async def ingest_database_schema( qi = engine.engine.dialect.identifier_preparer.quote qname = lambda name : ".".join(qi(p) for p in name.split(".")) tn = qname(table_name) - tn = qi(table_name) rows_result = await cursor.execute( text(f"SELECT * FROM {tn} LIMIT :limit;"), {"limit": max_sample_rows} @@ -61,7 +63,7 @@ async def ingest_database_schema( row_count_estimate = count_result.scalar() schema_table = SchemaTable( - id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{tn}"), + id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{table_name}"), table_name=table_name, schema_name=schema_name, columns=details["columns"], From df8b80d4a9e9b21e1ba8cbeb89ffae1e72b6f8b1 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 19:05:00 +0530 Subject: [PATCH 61/71] solved more nitpick comments --- cognee/tasks/schema/ingest_database_schema.py | 53 +++++++++++++------ 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 2a343ea0d..e362734fc 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -9,13 +9,13 @@ from cognee.tasks.schema.models import DatabaseSchema, SchemaTable, SchemaRelati from cognee.infrastructure.databases.relational.create_relational_engine import ( create_relational_engine, ) -from datetime import datetime +from datetime import datetime, timezone async def ingest_database_schema( database_config: Dict, schema_name: str = "default", - max_sample_rows: int = 5, + max_sample_rows: int = 0, ) -> Dict[str, List[DataPoint] | DataPoint]: """ Ingest database schema with sample data into dedicated nodeset @@ -45,22 +45,41 @@ async def ingest_database_schema( sample_data = {} schema_tables = [] schema_relationships = [] + qi = engine.engine.dialect.identifier_preparer.quote + + def qname(name: str): + split_name = name.split(".") + ".".join(qi(p) for p in split_name) async with engine.engine.begin() as cursor: for table_name, details in schema.items(): - qi = engine.engine.dialect.identifier_preparer.quote - qname = lambda name : ".".join(qi(p) for p in name.split(".")) tn = qname(table_name) - rows_result = await cursor.execute( - text(f"SELECT * FROM {tn} LIMIT :limit;"), - {"limit": max_sample_rows} - ) - rows = [ - dict(zip([col["name"] for col in details["columns"]], row)) - for row in rows_result.fetchall() - ] - count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {tn};")) - row_count_estimate = count_result.scalar() + if max_sample_rows > 0: + rows_result = await cursor.execute( + text(f"SELECT * FROM {tn} LIMIT :limit;"), {"limit": max_sample_rows} + ) + rows = [dict(r) for r in rows_result.mappings().all()] + else: + rows = [] + row_count_estimate = 0 + if engine.engine.dialect.name == "postegresql": + if "." in table_name: + schema_part, table_part = table_name.split(".", 1) + else: + schema_part, table_part = "public", table_name + estimate = await cursor.execute( + text( + "SELECT reltuples:bigint " + "FROM pg_class c " + "JOIN pg_namespace n ON n.oid = c.relnamespace " + "WHERE n.nspname = :schema AND c.relname = :table" + ), + {"schema": schema_part, "table": table_part}, + ) + row_count_estimate = estimate.scalar() + else: + count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {tn};")) + row_count_estimate = count_result.scalar() schema_table = SchemaTable( id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{table_name}"), @@ -79,9 +98,9 @@ async def ingest_database_schema( for fk in details.get("foreign_keys", []): ref_table_fq = fk["ref_table"] - if '.' not in ref_table_fq and '.' in table_name: + if "." not in ref_table_fq and "." in table_name: ref_table_fq = f"{table_name.split('.', 1)[0]}.{ref_table_fq}" - + relationship = SchemaRelationship( id=uuid5( NAMESPACE_OID, @@ -102,7 +121,7 @@ async def ingest_database_schema( database_type=database_config.get("migration_db_provider", "sqlite"), tables=tables, sample_data=sample_data, - extraction_timestamp=datetime.utcnow(), + extraction_timestamp=datetime.now(timezone.utc), description=f"Database schema '{schema_name}' containing {len(schema_tables)} tables and {len(schema_relationships)} relationships.", ) From e7bcf9043f36ab631390beef2be7a1d2a3ecc359 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 19:53:21 +0530 Subject: [PATCH 62/71] solved more nitpick comments --- cognee/tasks/schema/ingest_database_schema.py | 25 +++++++++---------- 1 file changed, 12 insertions(+), 13 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index e362734fc..026bf588c 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -1,9 +1,6 @@ -from typing import List, Dict, Optional +from typing import List, Dict from uuid import uuid5, NAMESPACE_OID from cognee.infrastructure.engine.models.DataPoint import DataPoint -from cognee.infrastructure.databases.relational.get_migration_relational_engine import ( - get_migration_relational_engine, -) from sqlalchemy import text from cognee.tasks.schema.models import DatabaseSchema, SchemaTable, SchemaRelationship from cognee.infrastructure.databases.relational.create_relational_engine import ( @@ -18,12 +15,12 @@ async def ingest_database_schema( max_sample_rows: int = 0, ) -> Dict[str, List[DataPoint] | DataPoint]: """ - Ingest database schema with sample data into dedicated nodeset + Extract database schema metadata (optionally with sample data) and return DataPoint models for graph construction. Args: database_config: Database connection configuration schema_name: Name identifier for this schema - max_sample_rows: Maximum sample rows per table + max_sample_rows: Maximum sample rows per table (0 means no sampling) Returns: Dict with keys: @@ -49,36 +46,37 @@ async def ingest_database_schema( def qname(name: str): split_name = name.split(".") - ".".join(qi(p) for p in split_name) + return ".".join(qi(p) for p in split_name) async with engine.engine.begin() as cursor: for table_name, details in schema.items(): tn = qname(table_name) if max_sample_rows > 0: rows_result = await cursor.execute( - text(f"SELECT * FROM {tn} LIMIT :limit;"), {"limit": max_sample_rows} + text(f"SELECT * FROM {tn} LIMIT :limit;"), + {"limit": max_sample_rows}, # noqa: S608 - tn is fully quoted ) rows = [dict(r) for r in rows_result.mappings().all()] else: rows = [] row_count_estimate = 0 - if engine.engine.dialect.name == "postegresql": + if engine.engine.dialect.name == "postgresql": if "." in table_name: schema_part, table_part = table_name.split(".", 1) else: schema_part, table_part = "public", table_name estimate = await cursor.execute( text( - "SELECT reltuples:bigint " + "SELECT reltuples:bigint AS estimate " "FROM pg_class c " "JOIN pg_namespace n ON n.oid = c.relnamespace " "WHERE n.nspname = :schema AND c.relname = :table" ), {"schema": schema_part, "table": table_part}, ) - row_count_estimate = estimate.scalar() + row_count_estimate = estimate.scalar() or 0 else: - count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {tn};")) + count_result = await cursor.execute(text(f"SELECT COUNT(*) FROM {tn};")) # noqa: S608 - tn is fully quoted row_count_estimate = count_result.scalar() schema_table = SchemaTable( @@ -115,8 +113,9 @@ async def ingest_database_schema( ) schema_relationships.append(relationship) + id_str = f"{database_config.get('migration_db_provider', 'sqlite')}:{database_config.get('migration_db_name', 'cognee_db')}:{schema_name}" database_schema = DatabaseSchema( - id=uuid5(NAMESPACE_OID, name=schema_name), + id=uuid5(NAMESPACE_OID, name=id_str), schema_name=schema_name, database_type=database_config.get("migration_db_provider", "sqlite"), tables=tables, From 67f948a1458e2474641180f530689f939bb29923 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Mon, 15 Sep 2025 20:24:49 +0530 Subject: [PATCH 63/71] solved nitpick comments --- cognee/tasks/schema/ingest_database_schema.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index 026bf588c..be9bf6ff1 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -43,6 +43,10 @@ async def ingest_database_schema( schema_tables = [] schema_relationships = [] qi = engine.engine.dialect.identifier_preparer.quote + try: + max_sample_rows = max(0, int(max_sample_rows)) + except (TypeError, ValueError): + max_sample_rows = 0 def qname(name: str): split_name = name.split(".") @@ -53,8 +57,8 @@ async def ingest_database_schema( tn = qname(table_name) if max_sample_rows > 0: rows_result = await cursor.execute( - text(f"SELECT * FROM {tn} LIMIT :limit;"), - {"limit": max_sample_rows}, # noqa: S608 - tn is fully quoted + text(f"SELECT * FROM {tn} LIMIT :limit;"), # noqa: S608 - tn is fully quoted + {"limit": max_sample_rows}, ) rows = [dict(r) for r in rows_result.mappings().all()] else: @@ -67,7 +71,7 @@ async def ingest_database_schema( schema_part, table_part = "public", table_name estimate = await cursor.execute( text( - "SELECT reltuples:bigint AS estimate " + "SELECT reltuples::bigint AS estimate " "FROM pg_class c " "JOIN pg_namespace n ON n.oid = c.relnamespace " "WHERE n.nspname = :schema AND c.relname = :table" From 656894370e38ef9bf795c1c2b7e448ac7fa109e8 Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Sat, 20 Sep 2025 11:05:39 +0530 Subject: [PATCH 64/71] Edited test_relation_db_migration.py to include schema_only ingestion testcase --- cognee/tests/test_relational_db_migration.py | 75 ++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/cognee/tests/test_relational_db_migration.py b/cognee/tests/test_relational_db_migration.py index 68b46dbf5..cb360f1c2 100644 --- a/cognee/tests/test_relational_db_migration.py +++ b/cognee/tests/test_relational_db_migration.py @@ -197,6 +197,79 @@ async def relational_db_migration(): print(f"All checks passed for {graph_db_provider} provider with '{relationship_label}' edges!") +async def test_schema_only_migration(): + # 1. Setup test DB and extract schema + migration_engine = await setup_test_db() + schema = await migration_engine.extract_schema() + + # 2. Setup graph engine + graph_engine = await get_graph_engine() + + # 4. Migrate schema only + await migrate_relational_database(graph_engine, schema=schema, schema_only=True) + + # 5. Verify number of tables through search + search_results = await cognee.search( + query_text="How many tables are there in this database", + query_type=cognee.SearchType.GRAPH_COMPLETION, + ) + assert any("11" in r for r in search_results), ( + "Number of tables in the database reported in search_results is either None or not equal to 11" + ) + + graph_db_provider = os.getenv("GRAPH_DATABASE_PROVIDER", "networkx").lower() + + edge_counts = { + "is_part_of": 0, + "has_relationship": 0, + "foreign_key": 0, + } + + if graph_db_provider == "neo4j": + for rel_type in edge_counts.keys(): + query_str = f""" + MATCH ()-[r:{rel_type}]->() + RETURN count(r) as c + """ + rows = await graph_engine.query(query_str) + edge_counts[rel_type] = rows[0]["c"] + + elif graph_db_provider == "kuzu": + for rel_type in edge_counts.keys(): + query_str = f""" + MATCH ()-[r:EDGE]->() + WHERE r.relationship_name = '{rel_type}' + RETURN count(r) as c + """ + rows = await graph_engine.query(query_str) + edge_counts[rel_type] = rows[0][0] + + elif graph_db_provider == "networkx": + nodes, edges = await graph_engine.get_graph_data() + for _, _, key, _ in edges: + if key in edge_counts: + edge_counts[key] += 1 + + else: + raise ValueError(f"Unsupported graph database provider: {graph_db_provider}") + + # 7. Assert counts match expected values + expected_counts = { + "is_part_of": 11, + "has_relationship": 22, + "foreign_key": 11, + } + + for rel_type, expected in expected_counts.items(): + actual = edge_counts[rel_type] + assert actual == expected, ( + f"Expected {expected} edges for relationship '{rel_type}', but found {actual}" + ) + + print("Schema-only migration edge counts validated successfully!") + print(f"Edge counts: {edge_counts}") + + async def test_migration_sqlite(): database_to_migrate_path = os.path.join(pathlib.Path(__file__).parent, "test_data/") @@ -209,6 +282,7 @@ async def test_migration_sqlite(): ) await relational_db_migration() + await test_schema_only_migration() async def test_migration_postgres(): @@ -224,6 +298,7 @@ async def test_migration_postgres(): } ) await relational_db_migration() + await test_schema_only_migration() async def main(): From 2921021ca309f631aae49b686f4ec971ff24b0fe Mon Sep 17 00:00:00 2001 From: Geoff-Robin Date: Fri, 26 Sep 2025 00:58:43 +0530 Subject: [PATCH 65/71] improved code readability by splitting code blocks under conditional statements into separate functions --- .../ingestion/migrate_relational_database.py | 462 +++++++++--------- 1 file changed, 238 insertions(+), 224 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 824fef2fa..ffebf442d 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -9,7 +9,6 @@ from cognee.infrastructure.databases.relational.config import get_migration_conf from cognee.tasks.storage.index_data_points import index_data_points from cognee.tasks.storage.index_graph_edges import index_graph_edges from cognee.tasks.schema.ingest_database_schema import ingest_database_schema -from cognee.tasks.schema.models import SchemaTable from cognee.modules.engine.models import TableRow, TableType, ColumnValue @@ -31,236 +30,15 @@ async def migrate_relational_database( Both TableType and TableRow inherit from DataPoint to maintain consistency with Cognee data model. """ - engine = get_migration_relational_engine() # Create a mapping of node_id to node objects for referencing in edge creation node_mapping = {} edge_mapping = [] if schema_only: - database_config = get_migration_config().to_dict() - # Calling the ingest_database_schema function to return DataPoint subclasses - result = await ingest_database_schema( - database_config=database_config, - schema_name="migrated_schema", - max_sample_rows=5, - ) - database_schema = result["database_schema"] - schema_tables = result["schema_tables"] - schema_relationships = result["relationships"] - database_node_id = database_schema.id - node_mapping[database_node_id] = database_schema - for table in schema_tables: - table_node_id = table.id - # Add TableSchema Datapoint as a node. - node_mapping[table_node_id] = table - edge_mapping.append( - ( - table_node_id, - database_node_id, - "is_part_of", - dict( - source_node_id=table_node_id, - target_node_id=database_node_id, - relationship_name="is_part_of", - ), - ) - ) - table_name_to_id = {t.table_name: t.id for t in schema_tables} - for rel in schema_relationships: - source_table_id = table_name_to_id.get(rel.source_table) - target_table_id = table_name_to_id.get(rel.target_table) - - relationship_id = rel.id - - # Add RelationshipTable DataPoint as a node. - node_mapping[relationship_id] = rel - edge_mapping.append( - ( - source_table_id, - relationship_id, - "has_relationship", - dict( - source_node_id=source_table_id, - target_node_id=relationship_id, - relationship_name=rel.relationship_type, - ), - ) - ) - edge_mapping.append( - ( - relationship_id, - target_table_id, - "has_relationship", - dict( - source_node_id=relationship_id, - target_node_id=target_table_id, - relationship_name=rel.relationship_type, - ), - ) - ) - edge_mapping.append( - ( - source_table_id, - target_table_id, - rel.relationship_type, - dict( - source_node_id=source_table_id, - target_node_id=target_table_id, - relationship_name=rel.relationship_type, - ), - ) - ) + node_mapping, edge_mapping = await schema_only_ingestion() else: - async with engine.engine.begin() as cursor: - # First, create table type nodes for all tables - for table_name, details in schema.items(): - # Create a TableType node for each table - table_node = TableType( - id=uuid5(NAMESPACE_OID, name=table_name), - name=table_name, - description=f"Table: {table_name}", - ) - - # Add TableType node to mapping ( node will be added to the graph later based on this mapping ) - node_mapping[table_name] = table_node - - # Fetch all rows for the current table - rows_result = await cursor.execute(text(f"SELECT * FROM {table_name};")) - rows = rows_result.fetchall() - - for row in rows: - # Build a dictionary of properties from the row - row_properties = { - col["name"]: row[idx] for idx, col in enumerate(details["columns"]) - } - - # Determine the primary key value - if not details["primary_key"]: - # Use the first column as primary key if not specified - primary_key_col = details["columns"][0]["name"] - primary_key_value = row_properties[primary_key_col] - else: - # Use value of the specified primary key column - primary_key_col = details["primary_key"] - primary_key_value = row_properties[primary_key_col] - - # Create a node ID in the format "table_name:primary_key_value" - node_id = f"{table_name}:{primary_key_value}" - - # Create a TableRow node - # Node id must uniquely map to the id used in the relational database - # To catch the foreign key relationships properly - row_node = TableRow( - id=uuid5(NAMESPACE_OID, name=node_id), - name=node_id, - is_a=table_node, - properties=str(row_properties), - description=f"Row in {table_name} with {primary_key_col}={primary_key_value}", - ) - - # Store the node object in our mapping - node_mapping[node_id] = row_node - - # Add edge between row node and table node ( it will be added to the graph later ) - edge_mapping.append( - ( - row_node.id, - table_node.id, - "is_part_of", - dict( - relationship_name="is_part_of", - source_node_id=row_node.id, - target_node_id=table_node.id, - ), - ) - ) - - # Migrate data stored in columns of table rows - if migrate_column_data: - # Get foreign key columns to filter them out from column migration - foreign_keys = [] - for fk in details.get("foreign_keys", []): - foreign_keys.append(fk["ref_column"]) - - for key, value in row_properties.items(): - # Skip mapping primary key information to itself and mapping of foreign key information (as it will be mapped bellow) - if key is primary_key_col or key in foreign_keys: - continue - - # Create column value node - column_node_id = f"{table_name}:{key}:{value}" - column_node = ColumnValue( - id=uuid5(NAMESPACE_OID, name=column_node_id), - name=column_node_id, - properties=f"{key} {value} {table_name}", - description=f"Column name={key} and value={value} from column from table={table_name}", - ) - node_mapping[column_node_id] = column_node - - # Create relationship between column value of table row and table row - edge_mapping.append( - ( - row_node.id, - column_node.id, - key, - dict( - relationship_name=key, - source_node_id=row_node.id, - target_node_id=column_node.id, - ), - ) - ) - - # Process foreign key relationships after all nodes are created - for table_name, details in schema.items(): - # Process foreign key relationships for the current table - for fk in details.get("foreign_keys", []): - # Aliases needed for self-referencing tables - alias_1 = f"{table_name}_e1" - alias_2 = f"{fk['ref_table']}_e2" - - # Determine primary key column - if not details["primary_key"]: - primary_key_col = details["columns"][0]["name"] - else: - primary_key_col = details["primary_key"] - - # Query to find relationships based on foreign keys - fk_query = text( - f"SELECT {alias_1}.{primary_key_col} AS source_id, " - f"{alias_2}.{fk['ref_column']} AS ref_value " - f"FROM {table_name} AS {alias_1} " - f"JOIN {fk['ref_table']} AS {alias_2} " - f"ON {alias_1}.{fk['column']} = {alias_2}.{fk['ref_column']};" - ) - - fk_result = await cursor.execute(fk_query) - relations = fk_result.fetchall() - - for source_id, ref_value in relations: - # Construct node ids - source_node_id = f"{table_name}:{source_id}" - target_node_id = f"{fk['ref_table']}:{ref_value}" - - # Get the source and target node objects from our mapping - source_node = node_mapping[source_node_id] - target_node = node_mapping[target_node_id] - - # Add edge representing the foreign key relationship using the node objects - # Create edge to add to graph later - edge_mapping.append( - ( - source_node.id, - target_node.id, - fk["column"], - dict( - source_node_id=source_node.id, - target_node_id=target_node.id, - relationship_name=fk["column"], - ), - ) - ) + node_mapping, edge_mapping = await complete_database_ingestion(schema, migrate_column_data) def _remove_duplicate_edges(edge_mapping): seen = set() @@ -297,3 +75,239 @@ async def migrate_relational_database( logger.info("Data successfully migrated from relational database to desired graph database.") return await graph_db.get_graph_data() + + +async def schema_only_ingestion(): + node_mapping = {} + edge_mapping = [] + database_config = get_migration_config().to_dict() + # Calling the ingest_database_schema function to return DataPoint subclasses + result = await ingest_database_schema( + database_config=database_config, + schema_name="migrated_schema", + max_sample_rows=5, + ) + database_schema = result["database_schema"] + schema_tables = result["schema_tables"] + schema_relationships = result["relationships"] + database_node_id = database_schema.id + node_mapping[database_node_id] = database_schema + for table in schema_tables: + table_node_id = table.id + # Add TableSchema Datapoint as a node. + node_mapping[table_node_id] = table + edge_mapping.append( + ( + table_node_id, + database_node_id, + "is_part_of", + dict( + source_node_id=table_node_id, + target_node_id=database_node_id, + relationship_name="is_part_of", + ), + ) + ) + table_name_to_id = {t.table_name: t.id for t in schema_tables} + for rel in schema_relationships: + source_table_id = table_name_to_id.get(rel.source_table) + target_table_id = table_name_to_id.get(rel.target_table) + + relationship_id = rel.id + + # Add RelationshipTable DataPoint as a node. + node_mapping[relationship_id] = rel + edge_mapping.append( + ( + source_table_id, + relationship_id, + "has_relationship", + dict( + source_node_id=source_table_id, + target_node_id=relationship_id, + relationship_name=rel.relationship_type, + ), + ) + ) + edge_mapping.append( + ( + relationship_id, + target_table_id, + "has_relationship", + dict( + source_node_id=relationship_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ), + ) + ) + edge_mapping.append( + ( + source_table_id, + target_table_id, + rel.relationship_type, + dict( + source_node_id=source_table_id, + target_node_id=target_table_id, + relationship_name=rel.relationship_type, + ), + ) + ) + return node_mapping, edge_mapping + + +async def complete_database_ingestion(schema, migrate_column_data): + engine = get_migration_relational_engine() + # Create a mapping of node_id to node objects for referencing in edge creation + node_mapping = {} + edge_mapping = [] + async with engine.engine.begin() as cursor: + # First, create table type nodes for all tables + for table_name, details in schema.items(): + # Create a TableType node for each table + table_node = TableType( + id=uuid5(NAMESPACE_OID, name=table_name), + name=table_name, + description=f"Table: {table_name}", + ) + + # Add TableType node to mapping ( node will be added to the graph later based on this mapping ) + node_mapping[table_name] = table_node + + # Fetch all rows for the current table + rows_result = await cursor.execute(text(f"SELECT * FROM {table_name};")) + rows = rows_result.fetchall() + + for row in rows: + # Build a dictionary of properties from the row + row_properties = { + col["name"]: row[idx] for idx, col in enumerate(details["columns"]) + } + + # Determine the primary key value + if not details["primary_key"]: + # Use the first column as primary key if not specified + primary_key_col = details["columns"][0]["name"] + primary_key_value = row_properties[primary_key_col] + else: + # Use value of the specified primary key column + primary_key_col = details["primary_key"] + primary_key_value = row_properties[primary_key_col] + + # Create a node ID in the format "table_name:primary_key_value" + node_id = f"{table_name}:{primary_key_value}" + + # Create a TableRow node + # Node id must uniquely map to the id used in the relational database + # To catch the foreign key relationships properly + row_node = TableRow( + id=uuid5(NAMESPACE_OID, name=node_id), + name=node_id, + is_a=table_node, + properties=str(row_properties), + description=f"Row in {table_name} with {primary_key_col}={primary_key_value}", + ) + + # Store the node object in our mapping + node_mapping[node_id] = row_node + + # Add edge between row node and table node ( it will be added to the graph later ) + edge_mapping.append( + ( + row_node.id, + table_node.id, + "is_part_of", + dict( + relationship_name="is_part_of", + source_node_id=row_node.id, + target_node_id=table_node.id, + ), + ) + ) + + # Migrate data stored in columns of table rows + if migrate_column_data: + # Get foreign key columns to filter them out from column migration + foreign_keys = [] + for fk in details.get("foreign_keys", []): + foreign_keys.append(fk["ref_column"]) + + for key, value in row_properties.items(): + # Skip mapping primary key information to itself and mapping of foreign key information (as it will be mapped bellow) + if key is primary_key_col or key in foreign_keys: + continue + + # Create column value node + column_node_id = f"{table_name}:{key}:{value}" + column_node = ColumnValue( + id=uuid5(NAMESPACE_OID, name=column_node_id), + name=column_node_id, + properties=f"{key} {value} {table_name}", + description=f"Column name={key} and value={value} from column from table={table_name}", + ) + node_mapping[column_node_id] = column_node + + # Create relationship between column value of table row and table row + edge_mapping.append( + ( + row_node.id, + column_node.id, + key, + dict( + relationship_name=key, + source_node_id=row_node.id, + target_node_id=column_node.id, + ), + ) + ) + + # Process foreign key relationships after all nodes are created + for table_name, details in schema.items(): + # Process foreign key relationships for the current table + for fk in details.get("foreign_keys", []): + # Aliases needed for self-referencing tables + alias_1 = f"{table_name}_e1" + alias_2 = f"{fk['ref_table']}_e2" + + # Determine primary key column + if not details["primary_key"]: + primary_key_col = details["columns"][0]["name"] + else: + primary_key_col = details["primary_key"] + + # Query to find relationships based on foreign keys + fk_query = text( + f"SELECT {alias_1}.{primary_key_col} AS source_id, " + f"{alias_2}.{fk['ref_column']} AS ref_value " + f"FROM {table_name} AS {alias_1} " + f"JOIN {fk['ref_table']} AS {alias_2} " + f"ON {alias_1}.{fk['column']} = {alias_2}.{fk['ref_column']};" + ) + + fk_result = await cursor.execute(fk_query) + relations = fk_result.fetchall() + + for source_id, ref_value in relations: + # Construct node ids + source_node_id = f"{table_name}:{source_id}" + target_node_id = f"{fk['ref_table']}:{ref_value}" + + # Get the source and target node objects from our mapping + source_node = node_mapping[source_node_id] + target_node = node_mapping[target_node_id] + + # Add edge representing the foreign key relationship using the node objects + # Create edge to add to graph later + edge_mapping.append( + ( + source_node.id, + target_node.id, + fk["column"], + dict( + source_node_id=source_node.id, + target_node_id=target_node.id, + relationship_name=fk["column"], + ), + ) + ) + return node_mapping, edge_mapping From 920bc78f151aa8c6e75334881b8e5cc52fdf814f Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Sat, 27 Sep 2025 00:18:57 +0200 Subject: [PATCH 66/71] refactor: Remove unused code --- cognee/tasks/ingestion/migrate_relational_database.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index ffebf442d..7ea08d5e0 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -31,9 +31,6 @@ async def migrate_relational_database( Both TableType and TableRow inherit from DataPoint to maintain consistency with Cognee data model. """ # Create a mapping of node_id to node objects for referencing in edge creation - node_mapping = {} - edge_mapping = [] - if schema_only: node_mapping, edge_mapping = await schema_only_ingestion() From f93d30ae77f7232e03110a817226539d5eb4d483 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Sat, 27 Sep 2025 00:41:58 +0200 Subject: [PATCH 67/71] refactor: refactor schema migration --- .../ingestion/migrate_relational_database.py | 8 +++--- cognee/tasks/schema/ingest_database_schema.py | 27 ++++++++----------- cognee/tests/test_relational_db_migration.py | 1 + 3 files changed, 16 insertions(+), 20 deletions(-) diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 5ee9f5973..83ad452c3 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -32,7 +32,7 @@ async def migrate_relational_database( """ # Create a mapping of node_id to node objects for referencing in edge creation if schema_only: - node_mapping, edge_mapping = await schema_only_ingestion() + node_mapping, edge_mapping = await schema_only_ingestion(schema) else: node_mapping, edge_mapping = await complete_database_ingestion(schema, migrate_column_data) @@ -74,13 +74,13 @@ async def migrate_relational_database( return await graph_db.get_graph_data() -async def schema_only_ingestion(): +async def schema_only_ingestion(schema): node_mapping = {} edge_mapping = [] - database_config = get_migration_config().to_dict() + # Calling the ingest_database_schema function to return DataPoint subclasses result = await ingest_database_schema( - database_config=database_config, + schema=schema, schema_name="migrated_schema", max_sample_rows=5, ) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index be9bf6ff1..e89b679d2 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -3,14 +3,15 @@ from uuid import uuid5, NAMESPACE_OID from cognee.infrastructure.engine.models.DataPoint import DataPoint from sqlalchemy import text from cognee.tasks.schema.models import DatabaseSchema, SchemaTable, SchemaRelationship -from cognee.infrastructure.databases.relational.create_relational_engine import ( - create_relational_engine, +from cognee.infrastructure.databases.relational.get_migration_relational_engine import ( + get_migration_relational_engine, ) +from cognee.infrastructure.databases.relational.config import get_migration_config from datetime import datetime, timezone async def ingest_database_schema( - database_config: Dict, + schema, schema_name: str = "default", max_sample_rows: int = 0, ) -> Dict[str, List[DataPoint] | DataPoint]: @@ -28,20 +29,13 @@ async def ingest_database_schema( "schema_tables": List[SchemaTable] "relationships": List[SchemaRelationship] """ - engine = create_relational_engine( - db_path=database_config.get("migration_db_path", ""), - db_name=database_config.get("migration_db_name", "cognee_db"), - db_host=database_config.get("migration_db_host"), - db_port=database_config.get("migration_db_port"), - db_username=database_config.get("migration_db_username"), - db_password=database_config.get("migration_db_password"), - db_provider=database_config.get("migration_db_provider", "sqlite"), - ) - schema = await engine.extract_schema() + tables = {} sample_data = {} schema_tables = [] schema_relationships = [] + + engine = get_migration_relational_engine() qi = engine.engine.dialect.identifier_preparer.quote try: max_sample_rows = max(0, int(max_sample_rows)) @@ -63,7 +57,7 @@ async def ingest_database_schema( rows = [dict(r) for r in rows_result.mappings().all()] else: rows = [] - row_count_estimate = 0 + if engine.engine.dialect.name == "postgresql": if "." in table_name: schema_part, table_part = table_name.split(".", 1) @@ -117,11 +111,12 @@ async def ingest_database_schema( ) schema_relationships.append(relationship) - id_str = f"{database_config.get('migration_db_provider', 'sqlite')}:{database_config.get('migration_db_name', 'cognee_db')}:{schema_name}" + migration_config = get_migration_config() + id_str = f"{migration_config.migration_db_provider}:{migration_config.migration_db_name}:{schema_name}" database_schema = DatabaseSchema( id=uuid5(NAMESPACE_OID, name=id_str), schema_name=schema_name, - database_type=database_config.get("migration_db_provider", "sqlite"), + database_type=migration_config.migration_db_provider, tables=tables, sample_data=sample_data, extraction_timestamp=datetime.now(timezone.utc), diff --git a/cognee/tests/test_relational_db_migration.py b/cognee/tests/test_relational_db_migration.py index cb360f1c2..2b69ce854 100644 --- a/cognee/tests/test_relational_db_migration.py +++ b/cognee/tests/test_relational_db_migration.py @@ -212,6 +212,7 @@ async def test_schema_only_migration(): search_results = await cognee.search( query_text="How many tables are there in this database", query_type=cognee.SearchType.GRAPH_COMPLETION, + top_k=30, ) assert any("11" in r for r in search_results), ( "Number of tables in the database reported in search_results is either None or not equal to 11" From 17fb3b49efce5801dc37341bd40967f0fb202017 Mon Sep 17 00:00:00 2001 From: Igor Ilic Date: Sat, 27 Sep 2025 01:15:30 +0200 Subject: [PATCH 68/71] refactor: add visualization to schema migration --- .../cognee_network_visualization.py | 3 ++ .../ingestion/migrate_relational_database.py | 3 +- cognee/tasks/schema/ingest_database_schema.py | 36 ++++++++++--------- cognee/tasks/schema/models.py | 12 +++---- 4 files changed, 30 insertions(+), 24 deletions(-) diff --git a/cognee/modules/visualization/cognee_network_visualization.py b/cognee/modules/visualization/cognee_network_visualization.py index bbdbc0019..c735e70f1 100644 --- a/cognee/modules/visualization/cognee_network_visualization.py +++ b/cognee/modules/visualization/cognee_network_visualization.py @@ -23,6 +23,9 @@ async def cognee_network_visualization(graph_data, destination_file_path: str = "TableRow": "#f47710", "TableType": "#6510f4", "ColumnValue": "#13613a", + "SchemaTable": "#f47710", + "DatabaseSchema": "#6510f4", + "SchemaRelationship": "#13613a", "default": "#D3D3D3", } diff --git a/cognee/tasks/ingestion/migrate_relational_database.py b/cognee/tasks/ingestion/migrate_relational_database.py index 83ad452c3..53ce176e8 100644 --- a/cognee/tasks/ingestion/migrate_relational_database.py +++ b/cognee/tasks/ingestion/migrate_relational_database.py @@ -81,7 +81,6 @@ async def schema_only_ingestion(schema): # Calling the ingest_database_schema function to return DataPoint subclasses result = await ingest_database_schema( schema=schema, - schema_name="migrated_schema", max_sample_rows=5, ) database_schema = result["database_schema"] @@ -105,7 +104,7 @@ async def schema_only_ingestion(schema): ), ) ) - table_name_to_id = {t.table_name: t.id for t in schema_tables} + table_name_to_id = {t.name: t.id for t in schema_tables} for rel in schema_relationships: source_table_id = table_name_to_id.get(rel.source_table) target_table_id = table_name_to_id.get(rel.target_table) diff --git a/cognee/tasks/schema/ingest_database_schema.py b/cognee/tasks/schema/ingest_database_schema.py index e89b679d2..e3823701c 100644 --- a/cognee/tasks/schema/ingest_database_schema.py +++ b/cognee/tasks/schema/ingest_database_schema.py @@ -12,15 +12,13 @@ from datetime import datetime, timezone async def ingest_database_schema( schema, - schema_name: str = "default", max_sample_rows: int = 0, ) -> Dict[str, List[DataPoint] | DataPoint]: """ Extract database schema metadata (optionally with sample data) and return DataPoint models for graph construction. Args: - database_config: Database connection configuration - schema_name: Name identifier for this schema + schema: Database schema max_sample_rows: Maximum sample rows per table (0 means no sampling) Returns: @@ -35,6 +33,7 @@ async def ingest_database_schema( schema_tables = [] schema_relationships = [] + migration_config = get_migration_config() engine = get_migration_relational_engine() qi = engine.engine.dialect.identifier_preparer.quote try: @@ -78,15 +77,17 @@ async def ingest_database_schema( row_count_estimate = count_result.scalar() schema_table = SchemaTable( - id=uuid5(NAMESPACE_OID, name=f"{schema_name}:{table_name}"), - table_name=table_name, - schema_name=schema_name, + id=uuid5(NAMESPACE_OID, name=f"{table_name}"), + name=table_name, columns=details["columns"], primary_key=details.get("primary_key"), foreign_keys=details.get("foreign_keys", []), sample_rows=rows, row_count_estimate=row_count_estimate, - description=f"Schema table for '{table_name}' with {len(details['columns'])} columns and approx. {row_count_estimate} rows.", + description=f"Relational database table with '{table_name}' with {len(details['columns'])} columns and approx. {row_count_estimate} rows." + f"Here are the columns this table contains: {details['columns']}" + f"Here are a few sample_rows to show the contents of the table: {rows}" + f"Table is part of the database: {migration_config.migration_db_name}", ) schema_tables.append(schema_table) tables[table_name] = details @@ -97,30 +98,33 @@ async def ingest_database_schema( if "." not in ref_table_fq and "." in table_name: ref_table_fq = f"{table_name.split('.', 1)[0]}.{ref_table_fq}" + relationship_name = ( + f"{table_name}:{fk['column']}->{ref_table_fq}:{fk['ref_column']}" + ) relationship = SchemaRelationship( - id=uuid5( - NAMESPACE_OID, - name=f"{schema_name}:{table_name}:{fk['column']}->{ref_table_fq}:{fk['ref_column']}", - ), + id=uuid5(NAMESPACE_OID, name=relationship_name), + name=relationship_name, source_table=table_name, target_table=ref_table_fq, relationship_type="foreign_key", source_column=fk["column"], target_column=fk["ref_column"], - description=f"Foreign key relationship: {table_name}.{fk['column']} → {ref_table_fq}.{fk['ref_column']}", + description=f"Relational database table foreign key relationship between: {table_name}.{fk['column']} → {ref_table_fq}.{fk['ref_column']}" + f"This foreing key relationship between table columns is a part of the following database: {migration_config.migration_db_name}", ) schema_relationships.append(relationship) - migration_config = get_migration_config() - id_str = f"{migration_config.migration_db_provider}:{migration_config.migration_db_name}:{schema_name}" + id_str = f"{migration_config.migration_db_provider}:{migration_config.migration_db_name}" database_schema = DatabaseSchema( id=uuid5(NAMESPACE_OID, name=id_str), - schema_name=schema_name, + name=migration_config.migration_db_name, database_type=migration_config.migration_db_provider, tables=tables, sample_data=sample_data, extraction_timestamp=datetime.now(timezone.utc), - description=f"Database schema '{schema_name}' containing {len(schema_tables)} tables and {len(schema_relationships)} relationships.", + description=f"Database schema containing {len(schema_tables)} tables and {len(schema_relationships)} relationships. " + f"The database type is {migration_config.migration_db_provider}." + f"The database contains the following tables: {tables}", ) return { diff --git a/cognee/tasks/schema/models.py b/cognee/tasks/schema/models.py index 423c92050..4b13f420b 100644 --- a/cognee/tasks/schema/models.py +++ b/cognee/tasks/schema/models.py @@ -6,36 +6,36 @@ from datetime import datetime class DatabaseSchema(DataPoint): """Represents a complete database schema with sample data""" - schema_name: str + name: str database_type: str # sqlite, postgres, etc. tables: Dict[str, Dict] # Reuse existing schema format from SqlAlchemyAdapter sample_data: Dict[str, List[Dict]] # Limited examples per table extraction_timestamp: datetime description: str - metadata: dict = {"index_fields": ["schema_name", "database_type"]} + metadata: dict = {"index_fields": ["description", "name"]} class SchemaTable(DataPoint): """Represents an individual table schema with relationships""" - table_name: str - schema_name: str + name: str columns: List[Dict] # Column definitions with types primary_key: Optional[str] foreign_keys: List[Dict] # Foreign key relationships sample_rows: List[Dict] # Max 3-5 example rows row_count_estimate: Optional[int] # Actual table size description: str - metadata: dict = {"index_fields": ["table_name", "schema_name"]} + metadata: dict = {"index_fields": ["description", "name"]} class SchemaRelationship(DataPoint): """Represents relationships between tables""" + name: str source_table: str target_table: str relationship_type: str # "foreign_key", "one_to_many", etc. source_column: str target_column: str description: str - metadata: dict = {"index_fields": ["source_table", "target_table"]} + metadata: dict = {"index_fields": ["description", "name"]} From dc1669a948eaeb04028129e42ee1b2e39e5f9e25 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Sat, 27 Sep 2025 19:31:39 +0100 Subject: [PATCH 69/71] feat: add CORS middleware support for SSE and HTTP transports in MCP server --- cognee-mcp/src/server.py | 60 ++++++++++++++++++++++++++++++++++++++-- 1 file changed, 57 insertions(+), 3 deletions(-) diff --git a/cognee-mcp/src/server.py b/cognee-mcp/src/server.py index f249f1d08..33cd26cb1 100755 --- a/cognee-mcp/src/server.py +++ b/cognee-mcp/src/server.py @@ -20,6 +20,9 @@ from cognee.modules.search.types import SearchType from cognee.shared.data_models import KnowledgeGraph from cognee.modules.storage.utils import JSONEncoder from starlette.responses import JSONResponse +from starlette.middleware import Middleware +from starlette.middleware.cors import CORSMiddleware +import uvicorn try: @@ -39,8 +42,59 @@ mcp = FastMCP("Cognee") logger = get_logger() +cors_middleware = Middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_headers=["*"], +) + + +async def run_sse_with_cors(): + """Custom SSE transport with CORS middleware.""" + sse_app = mcp.sse_app() + sse_app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_headers=["*"], + ) + + config = uvicorn.Config( + sse_app, + host=mcp.settings.host, + port=mcp.settings.port, + log_level=mcp.settings.log_level.lower(), + ) + server = uvicorn.Server(config) + await server.serve() + + +async def run_http_with_cors(): + """Custom HTTP transport with CORS middleware.""" + http_app = mcp.streamable_http_app() + http_app.add_middleware( + CORSMiddleware, + allow_origins=["*"], + allow_credentials=True, + allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_headers=["*"], + ) + + config = uvicorn.Config( + http_app, + host=mcp.settings.host, + port=mcp.settings.port, + log_level=mcp.settings.log_level.lower(), + ) + server = uvicorn.Server(config) + await server.serve() + + @mcp.custom_route("/health", methods=["GET"]) -async def health_check(request) -> dict: +async def health_check(request): return JSONResponse({"status": "ok"}) @@ -981,12 +1035,12 @@ async def main(): await mcp.run_stdio_async() elif args.transport == "sse": logger.info(f"Running MCP server with SSE transport on {args.host}:{args.port}") - await mcp.run_sse_async() + await run_sse_with_cors() elif args.transport == "http": logger.info( f"Running MCP server with Streamable HTTP transport on {args.host}:{args.port}{args.path}" ) - await mcp.run_streamable_http_async() + await run_http_with_cors() if __name__ == "__main__": From c0d2abdf5e7758c8fa9c94c68b6fc8d4351ceab9 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Sat, 27 Sep 2025 19:31:56 +0100 Subject: [PATCH 70/71] feat: implement MCP connection health check in header component --- cognee-frontend/src/ui/Layout/Header.tsx | 25 +++++++++++++++++++----- cognee-frontend/src/utils/fetch.ts | 6 ++++++ 2 files changed, 26 insertions(+), 5 deletions(-) diff --git a/cognee-frontend/src/ui/Layout/Header.tsx b/cognee-frontend/src/ui/Layout/Header.tsx index 30bf7ddb0..1bc57f699 100644 --- a/cognee-frontend/src/ui/Layout/Header.tsx +++ b/cognee-frontend/src/ui/Layout/Header.tsx @@ -2,7 +2,8 @@ import Link from "next/link"; import Image from "next/image"; -import { useBoolean } from "@/utils"; +import { useEffect } from "react"; +import { useBoolean, fetch } from "@/utils"; import { CloseIcon, CloudIcon, CogneeIcon } from "../Icons"; import { CTAButton, GhostButton, IconButton, Modal, StatusDot } from "../elements"; @@ -24,8 +25,9 @@ export default function Header({ user }: HeaderProps) { } = useBoolean(false); const { - value: isMCPStatusOpen, - setTrue: setMCPStatusOpen, + value: isMCPConnected, + setTrue: setMCPConnected, + setFalse: setMCPDisconnected, } = useBoolean(false); const handleDataSyncConfirm = () => { @@ -35,6 +37,19 @@ export default function Header({ user }: HeaderProps) { }); }; + useEffect(() => { + const checkMCPConnection = () => { + fetch.checkMCPHealth() + .then(() => setMCPConnected()) + .catch(() => setMCPDisconnected()); + }; + + checkMCPConnection(); + const interval = setInterval(checkMCPConnection, 30000); + + return () => clearInterval(interval); + }, [setMCPConnected, setMCPDisconnected]); + return ( <>
@@ -45,8 +60,8 @@ export default function Header({ user }: HeaderProps) {
- - { isMCPStatusOpen ? "MCP connected" : "MCP disconnected" } + + { isMCPConnected ? "MCP connected" : "MCP disconnected" } diff --git a/cognee-frontend/src/utils/fetch.ts b/cognee-frontend/src/utils/fetch.ts index 246853fb9..e67845d78 100644 --- a/cognee-frontend/src/utils/fetch.ts +++ b/cognee-frontend/src/utils/fetch.ts @@ -9,6 +9,8 @@ const backendApiUrl = process.env.NEXT_PUBLIC_BACKEND_API_URL || "http://localho const cloudApiUrl = process.env.NEXT_PUBLIC_CLOUD_API_URL || "http://localhost:8001"; +const mcpApiUrl = process.env.NEXT_PUBLIC_MCP_API_URL || "http://localhost:8001"; + let apiKey: string | null = process.env.NEXT_PUBLIC_COGWIT_API_KEY || null; let accessToken: string | null = null; @@ -66,6 +68,10 @@ fetch.checkHealth = () => { return global.fetch(`${backendApiUrl.replace("/api", "")}/health`); }; +fetch.checkMCPHealth = () => { + return global.fetch(`${mcpApiUrl.replace("/api", "")}/health`); +}; + fetch.setApiKey = (newApiKey: string) => { apiKey = newApiKey; }; From 0fac104fc7ec6d757b3fc10a3bd1e114384b7a10 Mon Sep 17 00:00:00 2001 From: Daulet Amirkhanov Date: Sat, 27 Sep 2025 20:11:39 +0100 Subject: [PATCH 71/71] fix: update UI server startup message to reflect dynamic frontend port --- cognee-mcp/src/server.py | 17 ++++------------- cognee/cli/_cognee.py | 2 +- 2 files changed, 5 insertions(+), 14 deletions(-) diff --git a/cognee-mcp/src/server.py b/cognee-mcp/src/server.py index 33cd26cb1..cc6eac09e 100755 --- a/cognee-mcp/src/server.py +++ b/cognee-mcp/src/server.py @@ -42,23 +42,14 @@ mcp = FastMCP("Cognee") logger = get_logger() -cors_middleware = Middleware( - CORSMiddleware, - allow_origins=["*"], - allow_credentials=True, - allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], - allow_headers=["*"], -) - - async def run_sse_with_cors(): """Custom SSE transport with CORS middleware.""" sse_app = mcp.sse_app() sse_app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=["http://localhost:3000"], allow_credentials=True, - allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_methods=["GET"], allow_headers=["*"], ) @@ -77,9 +68,9 @@ async def run_http_with_cors(): http_app = mcp.streamable_http_app() http_app.add_middleware( CORSMiddleware, - allow_origins=["*"], + allow_origins=["http://localhost:3000"], allow_credentials=True, - allow_methods=["GET", "POST", "PUT", "DELETE", "OPTIONS"], + allow_methods=["GET"], allow_headers=["*"], ) diff --git a/cognee/cli/_cognee.py b/cognee/cli/_cognee.py index 7f2b06c89..b68e5c80f 100644 --- a/cognee/cli/_cognee.py +++ b/cognee/cli/_cognee.py @@ -220,7 +220,7 @@ def main() -> int: if server_process: fmt.success("UI server started successfully!") - fmt.echo("The interface is available at: http://localhost:3000") + fmt.echo(f"The interface is available at: http://localhost:{frontend_port}") if start_backend: fmt.echo(f"The API backend is available at: http://localhost:{backend_port}") if start_mcp: