From 2f832b190cacc2127534f0ee0c60e2111a3c0866 Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 22 Oct 2024 11:26:48 +0200 Subject: [PATCH] fix: various fixes for the deployment * fix: remove groups from UserRead model * fix: add missing system dependencies for postgres * fix: change vector db provider environment variable name * fix: WeaviateAdapter retrieve bug * fix: correctly return data point objects from retrieve method * fix: align graph object properties * feat: add node example --- .env.template | 2 +- .gitignore | 2 + Dockerfile | 17 +- alembic/env.py | 2 + .../versions/482cd6517ce4_add_default_user.py | 2 +- cognee/api/client.py | 12 +- cognee/api/v1/config/config.py | 6 +- .../infrastructure/databases/vector/config.py | 4 +- .../vector/weaviate_db/WeaviateAdapter.py | 5 +- cognee/infrastructure/llm/openai/adapter.py | 5 +- cognee/modules/settings/get_settings.py | 4 +- .../modules/settings/save_vector_db_config.py | 2 +- cognee/modules/users/models/User.py | 3 +- .../chunk_update_check/chunk_update_check.py | 2 +- cognee/tasks/graph/query_graph_connections.py | 4 +- cognee/tests/test_qdrant.py | 2 +- cognee/tests/test_weaviate.py | 2 +- entrypoint.sh | 15 +- examples/data/artificial_intelligence.pdf | Bin 0 -> 55375 bytes examples/node/fetch.js | 14 ++ examples/node/handleServerErrors.js | 16 ++ examples/node/main.js | 122 ++++++++++++++ examples/node/package-lock.json | 156 ++++++++++++++++++ examples/node/package.json | 14 ++ notebooks/cognee_demo.ipynb | 2 +- poetry.lock | 38 ++++- pyproject.toml | 5 +- 27 files changed, 413 insertions(+), 45 deletions(-) create mode 100644 examples/data/artificial_intelligence.pdf create mode 100644 examples/node/fetch.js create mode 100644 examples/node/handleServerErrors.js create mode 100644 examples/node/main.js create mode 100644 examples/node/package-lock.json create mode 100644 examples/node/package.json diff --git a/.env.template b/.env.template index 43cdedee2..acdac04cd 100644 --- a/.env.template +++ b/.env.template @@ -13,7 +13,7 @@ GRAPH_DATABASE_URL= GRAPH_DATABASE_USERNAME= GRAPH_DATABASE_PASSWORD= -VECTOR_ENGINE_PROVIDER="qdrant" # or "weaviate" or "lancedb" +VECTOR_DB_PROVIDER="qdrant" # or "weaviate" or "lancedb" # Not needed if using "lancedb" VECTOR_DB_URL= VECTOR_DB_KEY= diff --git a/.gitignore b/.gitignore index 438f466f9..fef10cd63 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,5 @@ cognee/cache/ # Default cognee system directory, used in development .cognee_system/ .data_storage/ + +node_modules/ diff --git a/Dockerfile b/Dockerfile index 3b0f5f3ae..ec3dd8119 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,9 +8,17 @@ ENV DEBUG=${DEBUG} ENV PIP_NO_CACHE_DIR=true ENV PATH="${PATH}:/root/.poetry/bin" +RUN apt-get update && apt-get install + +RUN apt-get install -y \ + gcc \ + libpq-dev + + WORKDIR /app COPY pyproject.toml poetry.lock /app/ + RUN pip install poetry # Don't create virtualenv since docker is already isolated @@ -18,15 +26,16 @@ RUN poetry config virtualenvs.create false # Install the dependencies RUN poetry install --no-root --no-dev - + + # Set the PYTHONPATH environment variable to include the /app directory ENV PYTHONPATH=/app -COPY cognee/ cognee/ +COPY cognee/ /app/cognee # Copy Alembic configuration -COPY alembic.ini ./ -COPY alembic/ alembic/ +COPY alembic.ini /app/alembic.ini +COPY alembic/ /app/alembic COPY entrypoint.sh /app/entrypoint.sh RUN chmod +x /app/entrypoint.sh diff --git a/alembic/env.py b/alembic/env.py index fe501d6cd..1675e4168 100644 --- a/alembic/env.py +++ b/alembic/env.py @@ -92,6 +92,8 @@ def run_migrations_online() -> None: db_config = get_relational_config() LocalStorage.ensure_directory_exists(db_config.db_path) +print("Using database:", db_engine.db_uri) + config.set_section_option( config.config_ini_section, "SQLALCHEMY_DATABASE_URI", diff --git a/alembic/versions/482cd6517ce4_add_default_user.py b/alembic/versions/482cd6517ce4_add_default_user.py index ec916829e..b744c8821 100644 --- a/alembic/versions/482cd6517ce4_add_default_user.py +++ b/alembic/versions/482cd6517ce4_add_default_user.py @@ -16,7 +16,7 @@ revision: str = '482cd6517ce4' down_revision: Union[str, None] = '8057ae7329c2' branch_labels: Union[str, Sequence[str], None] = None -depends_on: Union[str, Sequence[str], None] = None +depends_on: Union[str, Sequence[str], None] = "8057ae7329c2" def upgrade() -> None: diff --git a/cognee/api/client.py b/cognee/api/client.py index b6ceea224..b8d56bc56 100644 --- a/cognee/api/client.py +++ b/cognee/api/client.py @@ -43,13 +43,13 @@ async def lifespan(app: FastAPI): # from cognee.modules.data.deletion import prune_system, prune_data # await prune_data() # await prune_system(metadata = True) - if app_environment == "local" or app_environment == "dev": - from cognee.infrastructure.databases.relational import get_relational_engine - db_engine = get_relational_engine() - await db_engine.create_database() + # if app_environment == "local" or app_environment == "dev": + from cognee.infrastructure.databases.relational import get_relational_engine + db_engine = get_relational_engine() + await db_engine.create_database() - from cognee.modules.users.methods import get_default_user - await get_default_user() + from cognee.modules.users.methods import get_default_user + await get_default_user() yield diff --git a/cognee/api/v1/config/config.py b/cognee/api/v1/config/config.py index 7d2c7c6f4..225f67814 100644 --- a/cognee/api/v1/config/config.py +++ b/cognee/api/v1/config/config.py @@ -21,7 +21,7 @@ def system_root_directory(system_root_directory: str): graph_config.graph_file_path = os.path.join(databases_directory_path, "cognee.graph") vector_config = get_vectordb_config() - if vector_config.vector_engine_provider == "lancedb": + if vector_config.vector_db_provider == "lancedb": vector_config.vector_db_url = os.path.join(databases_directory_path, "cognee.lancedb") @staticmethod @@ -91,9 +91,9 @@ def set_chunk_size(chunk_size: object): @staticmethod - def set_vector_engine_provider(vector_engine_provider: str): + def set_vector_db_provider(vector_db_provider: str): vector_db_config = get_vectordb_config() - vector_db_config.vector_engine_provider = vector_engine_provider + vector_db_config.vector_db_provider = vector_db_provider @staticmethod def set_vector_db_key(db_key: str): diff --git a/cognee/infrastructure/databases/vector/config.py b/cognee/infrastructure/databases/vector/config.py index 8137a067c..1d79b3cb6 100644 --- a/cognee/infrastructure/databases/vector/config.py +++ b/cognee/infrastructure/databases/vector/config.py @@ -9,7 +9,7 @@ class VectorConfig(BaseSettings): "cognee.lancedb" ) vector_db_key: str = "" - vector_engine_provider: str = "lancedb" + vector_db_provider: str = "lancedb" model_config = SettingsConfigDict(env_file = ".env", extra = "allow") @@ -17,7 +17,7 @@ def to_dict(self) -> dict: return { "vector_db_url": self.vector_db_url, "vector_db_key": self.vector_db_key, - "vector_db_provider": self.vector_engine_provider, + "vector_db_provider": self.vector_db_provider, } @lru_cache diff --git a/cognee/infrastructure/databases/vector/weaviate_db/WeaviateAdapter.py b/cognee/infrastructure/databases/vector/weaviate_db/WeaviateAdapter.py index e569c5a49..8aae831a1 100644 --- a/cognee/infrastructure/databases/vector/weaviate_db/WeaviateAdapter.py +++ b/cognee/infrastructure/databases/vector/weaviate_db/WeaviateAdapter.py @@ -108,11 +108,12 @@ async def retrieve(self, collection_name: str, data_point_ids: list[str]): filters = Filter.by_id().contains_any(data_point_ids) ) - for data_point in data_points: + for data_point in data_points.objects: data_point.payload = data_point.properties + data_point.id = data_point.uuid del data_point.properties - future.set_result(data_points) + future.set_result(data_points.objects) return await future diff --git a/cognee/infrastructure/llm/openai/adapter.py b/cognee/infrastructure/llm/openai/adapter.py index 6cac81959..2ad275e22 100644 --- a/cognee/infrastructure/llm/openai/adapter.py +++ b/cognee/infrastructure/llm/openai/adapter.py @@ -4,7 +4,6 @@ from pathlib import Path from typing import List, Type -import aiofiles import openai import instructor from pydantic import BaseModel @@ -13,9 +12,7 @@ from cognee.base_config import get_base_config from cognee.infrastructure.llm.llm_interface import LLMInterface from cognee.infrastructure.llm.prompts import read_query_prompt -from cognee.shared.data_models import MonitoringTool -import logging -logging.basicConfig(level=logging.DEBUG) +# from cognee.shared.data_models import MonitoringTool class OpenAIAdapter(LLMInterface): name = "OpenAI" diff --git a/cognee/modules/settings/get_settings.py b/cognee/modules/settings/get_settings.py index b15c0afad..fccbc3161 100644 --- a/cognee/modules/settings/get_settings.py +++ b/cognee/modules/settings/get_settings.py @@ -100,8 +100,8 @@ def get_settings() -> SettingsDict: }, vector_db = { "provider": { - "label": vector_config.vector_engine_provider, - "value": vector_config.vector_engine_provider.lower(), + "label": vector_config.vector_db_provider, + "value": vector_config.vector_db_provider.lower(), }, "url": vector_config.vector_db_url, "api_key": vector_config.vector_db_key, diff --git a/cognee/modules/settings/save_vector_db_config.py b/cognee/modules/settings/save_vector_db_config.py index ebb3de93d..1a5895bc6 100644 --- a/cognee/modules/settings/save_vector_db_config.py +++ b/cognee/modules/settings/save_vector_db_config.py @@ -12,4 +12,4 @@ async def save_vector_db_config(vector_db_config: VectorDBConfig): vector_config.vector_db_url = vector_db_config.url vector_config.vector_db_key = vector_db_config.api_key - vector_config.vector_engine_provider = vector_db_config.provider + vector_config.vector_db_provider = vector_db_config.provider diff --git a/cognee/modules/users/models/User.py b/cognee/modules/users/models/User.py index c85abaec7..96f78b12f 100644 --- a/cognee/modules/users/models/User.py +++ b/cognee/modules/users/models/User.py @@ -25,7 +25,8 @@ class User(SQLAlchemyBaseUserTableUUID, Principal): from fastapi_users import schemas class UserRead(schemas.BaseUser[uuid_UUID]): - groups: list[uuid_UUID] # Add groups attribute + # groups: list[uuid_UUID] # Add groups attribute + pass class UserCreate(schemas.BaseUserCreate): pass diff --git a/cognee/tasks/chunk_update_check/chunk_update_check.py b/cognee/tasks/chunk_update_check/chunk_update_check.py index 76f7dd274..1c1a534d0 100644 --- a/cognee/tasks/chunk_update_check/chunk_update_check.py +++ b/cognee/tasks/chunk_update_check/chunk_update_check.py @@ -14,7 +14,7 @@ async def chunk_update_check(data_chunks: list[DocumentChunk], collection_name: [str(chunk.chunk_id) for chunk in data_chunks], ) - existing_chunks_map = {chunk.id: chunk.payload for chunk in existing_chunks} + existing_chunks_map = {str(chunk.id): chunk.payload for chunk in existing_chunks} affected_data_chunks = [] diff --git a/cognee/tasks/graph/query_graph_connections.py b/cognee/tasks/graph/query_graph_connections.py index be29ac74a..3f1b52264 100644 --- a/cognee/tasks/graph/query_graph_connections.py +++ b/cognee/tasks/graph/query_graph_connections.py @@ -23,7 +23,7 @@ async def query_graph_connections(query: str, exploration_levels = 1) -> list[(s exact_node = await graph_engine.extract_node(node_id) if exact_node is not None and "uuid" in exact_node: - node_connections = await graph_engine.get_connections(exact_node["uuid"]) + node_connections = await graph_engine.get_connections(str(exact_node["uuid"])) else: vector_engine = get_vector_engine() results = await asyncio.gather( @@ -37,7 +37,7 @@ async def query_graph_connections(query: str, exploration_levels = 1) -> list[(s return [] node_connections_results = await asyncio.gather( - *[graph_engine.get_connections(result.payload["uuid"]) for result in relevant_results] + *[graph_engine.get_connections(str(result.payload["uuid"])) for result in relevant_results] ) node_connections = [] diff --git a/cognee/tests/test_qdrant.py b/cognee/tests/test_qdrant.py index 5f74b2d02..2ea011eb5 100644 --- a/cognee/tests/test_qdrant.py +++ b/cognee/tests/test_qdrant.py @@ -9,7 +9,7 @@ logging.basicConfig(level=logging.DEBUG) async def main(): - cognee.config.set_vector_engine_provider("qdrant") + cognee.config.set_vector_db_provider("qdrant") data_directory_path = str(pathlib.Path(os.path.join(pathlib.Path(__file__).parent, ".data_storage/test_qdrant")).resolve()) cognee.config.data_root_directory(data_directory_path) cognee_directory_path = str(pathlib.Path(os.path.join(pathlib.Path(__file__).parent, ".cognee_system/test_qdrant")).resolve()) diff --git a/cognee/tests/test_weaviate.py b/cognee/tests/test_weaviate.py index d542098de..7ad29a9af 100644 --- a/cognee/tests/test_weaviate.py +++ b/cognee/tests/test_weaviate.py @@ -7,7 +7,7 @@ logging.basicConfig(level=logging.DEBUG) async def main(): - cognee.config.set_vector_engine_provider("weaviate") + cognee.config.set_vector_db_provider("weaviate") data_directory_path = str(pathlib.Path(os.path.join(pathlib.Path(__file__).parent, ".data_storage/test_weaviate")).resolve()) cognee.config.data_root_directory(data_directory_path) cognee_directory_path = str(pathlib.Path(os.path.join(pathlib.Path(__file__).parent, ".cognee_system/test_weaviate")).resolve()) diff --git a/entrypoint.sh b/entrypoint.sh index cc6918371..ea9da9dd6 100755 --- a/entrypoint.sh +++ b/entrypoint.sh @@ -3,8 +3,19 @@ echo "Debug mode: $DEBUG" echo "Environment: $ENVIRONMENT" -# Run migrations -poetry run alembic upgrade head + +# # Run Alembic migrations +# echo "Running database migrations..." +# poetry run alembic upgrade head + +# # Check if the migrations were successful +# if [ $? -eq 0 ]; then +# echo "Migrations completed successfully." +# else +# echo "Migration failed, exiting." +# exit 1 +# fi + echo "Starting Gunicorn" diff --git a/examples/data/artificial_intelligence.pdf b/examples/data/artificial_intelligence.pdf new file mode 100644 index 0000000000000000000000000000000000000000..601c6297da4f44d7f75fb4b8a59c5673b5fc8fff GIT binary patch literal 55375 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

@}vN+ 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 { + if (response.status === 401) { + return reject(new Error('Unauthorized')); + } + if (!response.ok) { + if (response.json) { + return response.json().then(error => reject(error)); + } else { + return reject(response.detail || response.body || response); + } + } + + return resolve(response); + }); +} diff --git a/examples/node/main.js b/examples/node/main.js new file mode 100644 index 000000000..252facdd3 --- /dev/null +++ b/examples/node/main.js @@ -0,0 +1,122 @@ +import fs from 'fs'; +import FormData from 'form-data'; +import fetch from './fetch.js'; + +async function run() { + try { + // Default user is created automatically, you can create a new user if needed. + // const registerResponse = await fetch('/v1/auth/register', { + // method: 'POST', + // body: { + // email: 'default_user@example.com', + // password: 'default_password', + // is_active: true, + // is_superuser: true, + // is_verified: true + // }, + // headers: { + // 'Content-Type': 'application/json', + // }, + // }); + // const user = await registerResponse.json(); + + const authCredentials = new FormData(); + authCredentials.append('username', 'default_user@example.com'); + authCredentials.append('password', 'default_password'); + + const loginResponse = await fetch('/v1/auth/login', { + method: 'POST', + body: authCredentials, + }); + + const bearer = await loginResponse.json(); + const token = bearer.access_token; + + const response = await fetch('/v1/datasets', {}, token); + const datasets = await response.json(); + console.log(datasets); + + const files = [ + fs.createReadStream('../data/artificial_intelligence.pdf'), + ]; + + const addData = new FormData(); + files.forEach((file) => { + addData.append('data', file, file.name); + }) + addData.append('datasetId', 'main'); + + await fetch('/v1/add', { + method: 'POST', + body: addData, + headers: addData.getHeaders(), + }, token); + + await fetch('/v1/cognify', { + method: 'POST', + body: JSON.stringify({ + datasets: ['main'], + }), + headers: { + 'Content-Type': 'application/json', + } + }, token); + + const graphResponse = await fetch('/v1/datasets/main/graph', { + method: 'GET', + }, token); + + const graphUrl = await graphResponse.text(); + console.log('Graph URL:', graphUrl); + + // Search for summaries + const summariesResponse = await fetch('/v1/search', { + method: 'POST', + body: JSON.stringify({ + searchType: 'SUMMARIES', + query: 'Artificial Intelligence', + }), + headers: { + 'Content-Type': 'application/json', + } + }, token); + + + const summariesResults = await summariesResponse.json(); + console.log('Summaries Results:', summariesResults); + + // Search for chunks + const chunksResponse = await fetch('/v1/search', { + method: 'POST', + body: JSON.stringify({ + searchType: 'CHUNKS', + query: 'Artificial Intelligence', + }), + headers: { + 'Content-Type': 'application/json', + } + }, token); + + const chunksResults = await chunksResponse.json(); + console.log('Chunks Results:', chunksResults); + + // Search for insights + const insightsResponse = await fetch('/v1/search', { + method: 'POST', + body: JSON.stringify({ + searchType: 'INSIGHTS', + query: 'Artificial Intelligence', + }), + headers: { + 'Content-Type': 'application/json', + } + }, token); + + const insightsResults = await insightsResponse.json(); + console.log('Insights Results:', insightsResults); + } catch (error) { + console.error('Error:', error); + } +} + +run(); diff --git a/examples/node/package-lock.json b/examples/node/package-lock.json new file mode 100644 index 000000000..42d3e46bd --- /dev/null +++ b/examples/node/package-lock.json @@ -0,0 +1,156 @@ +{ + "name": "node-example", + "version": "1.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "node-example", + "version": "1.0.0", + "dependencies": { + "form-data": "^4.0.1", + "node-fetch": "^3.3.2" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/data-uri-to-buffer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/data-uri-to-buffer/-/data-uri-to-buffer-4.0.1.tgz", + "integrity": "sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fetch-blob": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", + "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "paypal", + "url": "https://paypal.me/jimmywarting" + } + ], + "dependencies": { + "node-domexception": "^1.0.0", + "web-streams-polyfill": "^3.0.3" + }, + "engines": { + "node": "^12.20 || >= 14.13" + } + }, + "node_modules/form-data": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.1.tgz", + "integrity": "sha512-tzN8e4TX8+kkxGPK8D5u0FNmjPUjw3lwC9lSLxxoB/+GtsJG91CO8bSWy73APlgAZzZbXEYZJuxjkHH2w+Ezhw==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/formdata-polyfill": { + "version": "4.0.10", + "resolved": "https://registry.npmjs.org/formdata-polyfill/-/formdata-polyfill-4.0.10.tgz", + "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==", + "dependencies": { + "fetch-blob": "^3.1.2" + }, + "engines": { + "node": ">=12.20.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-3.3.2.tgz", + "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==", + "dependencies": { + "data-uri-to-buffer": "^4.0.0", + "fetch-blob": "^3.1.4", + "formdata-polyfill": "^4.0.10" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/node-fetch" + } + }, + "node_modules/web-streams-polyfill": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", + "integrity": "sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==", + "engines": { + "node": ">= 8" + } + } + } +} diff --git a/examples/node/package.json b/examples/node/package.json new file mode 100644 index 000000000..bcbd98057 --- /dev/null +++ b/examples/node/package.json @@ -0,0 +1,14 @@ +{ + "type": "module", + "name": "node-example", + "version": "1.0.0", + "description": "Node example calling Cognee API", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "dependencies": { + "form-data": "^4.0.1", + "node-fetch": "^3.3.2" + } +} diff --git a/notebooks/cognee_demo.ipynb b/notebooks/cognee_demo.ipynb index 4b5c82d7d..ba5a89c86 100644 --- a/notebooks/cognee_demo.ipynb +++ b/notebooks/cognee_demo.ipynb @@ -548,7 +548,7 @@ "#GRAPH_DATABASE_USERNAME=\"\"\n", "#GRAPH_DATABASE_PASSWORD=\"\"\n", "\n", - "os.environ[\"VECTOR_ENGINE_PROVIDER\"]=\"lancedb\" # \"qdrant\", \"weaviate\" or \"lancedb\"\n", + "os.environ[\"VECTOR_DB_PROVIDER\"]=\"lancedb\" # \"qdrant\", \"weaviate\" or \"lancedb\"\n", "# Not needed if using \"lancedb\"\n", "# os.environ[\"VECTOR_DB_URL\"]=\"\"\n", "# os.environ[\"VECTOR_DB_KEY\"]=\"\"\n", diff --git a/poetry.lock b/poetry.lock index a8df04148..03dcc023b 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,4 +1,4 @@ -# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. +# This file is automatically @generated by Poetry 1.8.4 and should not be changed by hand. [[package]] name = "aiofiles" @@ -1350,13 +1350,13 @@ files = [ [[package]] name = "dlt" -version = "1.0.0" +version = "1.2.0" description = "dlt is an open-source python-first scalable data loading library that does not require any backend to run." optional = false python-versions = "<3.13,>=3.8.1" files = [ - {file = "dlt-1.0.0-py3-none-any.whl", hash = "sha256:730474cadcbc8151854d2c2999099225df3fe2b03fcfe716bc42e0b1a7707484"}, - {file = "dlt-1.0.0.tar.gz", hash = "sha256:757ca3b1fe19d47720f22ad45d0642077ccafe2e64094ef30da478ca50a392c4"}, + {file = "dlt-1.2.0-py3-none-any.whl", hash = "sha256:85256c0f87fe3cc1eedc390e6e3a31820250ac1f75bb9510bcf4085d069427ce"}, + {file = "dlt-1.2.0.tar.gz", hash = "sha256:3e3c8604ea2fb213f0901cecab018909570824e5addbb45954c2c274f1439b2c"}, ] [package.dependencies] @@ -1397,12 +1397,12 @@ clickhouse = ["adlfs (>=2022.4.0)", "clickhouse-connect (>=0.7.7)", "clickhouse- databricks = ["databricks-sql-connector (>=2.9.3)"] deltalake = ["deltalake (>=0.19.0)", "pyarrow (>=12.0.0)"] dremio = ["pyarrow (>=12.0.0)"] -duckdb = ["duckdb (>=0.6.1,<0.11)"] +duckdb = ["duckdb (>=0.9)"] filesystem = ["botocore (>=1.28)", "s3fs (>=2022.4.0)"] gcp = ["gcsfs (>=2022.4.0)", "google-cloud-bigquery (>=2.26.0)", "grpcio (>=1.50.0)"] gs = ["gcsfs (>=2022.4.0)"] lancedb = ["lancedb (>=0.8.2)", "pyarrow (>=12.0.0)", "tantivy (>=0.22.0)"] -motherduck = ["duckdb (>=0.6.1,<0.11)", "pyarrow (>=12.0.0)"] +motherduck = ["duckdb (>=0.9)", "pyarrow (>=12.0.0)"] mssql = ["pyodbc (>=4.0.39)"] parquet = ["pyarrow (>=12.0.0)"] postgres = ["psycopg2-binary (>=2.9.1)", "psycopg2cffi (>=2.9.0)"] @@ -3685,6 +3685,7 @@ optional = false python-versions = ">=3.6" files = [ {file = "mkdocs-redirects-1.2.1.tar.gz", hash = "sha256:9420066d70e2a6bb357adf86e67023dcdca1857f97f07c7fe450f8f1fb42f861"}, + {file = "mkdocs_redirects-1.2.1-py3-none-any.whl", hash = "sha256:497089f9e0219e7389304cffefccdfa1cac5ff9509f2cb706f4c9b221726dffb"}, ] [package.dependencies] @@ -4913,6 +4914,24 @@ files = [ [package.extras] test = ["enum34", "ipaddress", "mock", "pywin32", "wmi"] +[[package]] +name = "psycopg2" +version = "2.9.10" +description = "psycopg2 - Python-PostgreSQL Database Adapter" +optional = false +python-versions = ">=3.8" +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"}, + {file = "psycopg2-2.9.10-cp311-cp311-win32.whl", hash = "sha256:47c4f9875125344f4c2b870e41b6aad585901318068acd01de93f3677a6522c2"}, + {file = "psycopg2-2.9.10-cp311-cp311-win_amd64.whl", hash = "sha256:0435034157049f6846e95103bd8f5a668788dd913a7c30162ca9503fdf542cb4"}, + {file = "psycopg2-2.9.10-cp312-cp312-win32.whl", hash = "sha256:65a63d7ab0e067e2cdb3cf266de39663203d38d6a8ed97f5ca0cb315c73fe067"}, + {file = "psycopg2-2.9.10-cp312-cp312-win_amd64.whl", hash = "sha256:4a579d6243da40a7b3182e0430493dbd55950c493d8c68f4eec0b302f6bbf20e"}, + {file = "psycopg2-2.9.10-cp39-cp39-win32.whl", hash = "sha256:9d5b3b94b79a844a986d029eee38998232451119ad653aea42bb9220a8c5066b"}, + {file = "psycopg2-2.9.10-cp39-cp39-win_amd64.whl", hash = "sha256:88138c8dedcbfa96408023ea2b0c369eda40fe5d75002c0964c78f46f11fa442"}, + {file = "psycopg2-2.9.10.tar.gz", hash = "sha256:12ec0b40b0273f95296233e8750441339298e6a572f7039da5b260e3c8b60e11"}, +] + [[package]] name = "ptyprocess" version = "0.7.0" @@ -6259,6 +6278,11 @@ files = [ {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f60021ec1574e56632be2a36b946f8143bf4e5e6af4a06d85281adc22938e0dd"}, {file = "scikit_learn-1.5.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:394397841449853c2290a32050382edaec3da89e35b3e03d6cc966aebc6a8ae6"}, {file = "scikit_learn-1.5.2-cp312-cp312-win_amd64.whl", hash = "sha256:57cc1786cfd6bd118220a92ede80270132aa353647684efa385a74244a41e3b1"}, + {file = "scikit_learn-1.5.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:e9a702e2de732bbb20d3bad29ebd77fc05a6b427dc49964300340e4c9328b3f5"}, + {file = "scikit_learn-1.5.2-cp313-cp313-macosx_12_0_arm64.whl", hash = "sha256:b0768ad641981f5d3a198430a1d31c3e044ed2e8a6f22166b4d546a5116d7908"}, + {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:178ddd0a5cb0044464fc1bfc4cca5b1833bfc7bb022d70b05db8530da4bb3dd3"}, + {file = "scikit_learn-1.5.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:f7284ade780084d94505632241bf78c44ab3b6f1e8ccab3d2af58e0e950f9c12"}, + {file = "scikit_learn-1.5.2-cp313-cp313-win_amd64.whl", hash = "sha256:b7b0f9a0b1040830d38c39b91b3a44e1b643f4b36e36567b80b7c6bd2202a27f"}, {file = "scikit_learn-1.5.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:757c7d514ddb00ae249832fe87100d9c73c6ea91423802872d9e74970a0e40b9"}, {file = "scikit_learn-1.5.2-cp39-cp39-macosx_12_0_arm64.whl", hash = "sha256:52788f48b5d8bca5c0736c175fa6bdaab2ef00a8f536cda698db61bd89c551c1"}, {file = "scikit_learn-1.5.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:643964678f4b5fbdc95cbf8aec638acc7aa70f5f79ee2cdad1eec3df4ba6ead8"}, @@ -7727,4 +7751,4 @@ weaviate = ["weaviate-client"] [metadata] lock-version = "2.0" python-versions = ">=3.9.0,<3.12" -content-hash = "75d65fd1b99bf9db84fe026d140f6cb05b02afd31d4ad82a6286076256bd7609" +content-hash = "4cba654100a455c8691dd3d4e1b588f00bbb2acca89168954037017b3a6aced9" diff --git a/pyproject.toml b/pyproject.toml index 0199bb1f9..ab686cb83 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -38,7 +38,7 @@ greenlet = "^3.0.3" ruff = "^0.2.2" filetype = "^1.2.0" nltk = "^3.8.1" -dlt = {extras = ["sqlalchemy"], version = "^1.0.0"} +dlt = {extras = ["sqlalchemy"], version = "^1.2.0"} overrides = "^7.7.0" aiofiles = "^23.2.1" qdrant-client = "^1.9.0" @@ -70,7 +70,7 @@ sentry-sdk = {extras = ["fastapi"], version = "^2.9.0"} fastapi-users = { version = "*", extras = ["sqlalchemy"] } asyncpg = "^0.29.0" alembic = "^1.13.3" - +psycopg2 = "^2.9.10" [tool.poetry.extras] @@ -98,7 +98,6 @@ mkdocs-jupyter = "^0.24.6" mkdocs-minify-plugin = "^0.8.0" mkdocs-redirects = "^1.2.1" - [tool.poetry.group.test-docs.dependencies] fastapi = "^0.109.2" diskcache = "^5.6.3"