From 8130171b7f1ae89cf3553fb73783adbcc304f588 Mon Sep 17 00:00:00 2001 From: ANUSHKA KATHARE Date: Mon, 21 Oct 2024 22:01:21 +0530 Subject: [PATCH 1/2] Fixed Some grammatical errors in the file. --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 909538030..76cd833b8 100644 --- a/README.md +++ b/README.md @@ -55,7 +55,7 @@ cognee.config.llm_api_key = "YOUR_OPENAI_API_KEY" You can also set the variables by creating .env file, here is our template. To use different LLM providers, for more info check out our documentation -If you are using Networkx, create an account on Graphistry to visualize results: +If you are using Network, create an account on Graphistry to visualize results: ``` cognee.config.set_graphistry_config({ "username": "YOUR_USERNAME", @@ -162,7 +162,7 @@ async def chunk_naive_llm_classifier( ``` -We have a large number of tasks that can be used in your pipelines, and you can also create your own tasks to fit your business logic. +We have many tasks that can be used in your pipelines, and you can also create your tasks to fit your business logic. 3. Once we have our tasks, it is time to group them into a pipeline. From 2f832b190cacc2127534f0ee0c60e2111a3c0866 Mon Sep 17 00:00:00 2001 From: Boris Date: Tue, 22 Oct 2024 11:26:48 +0200 Subject: [PATCH 2/2] 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 @@ if db_engine.engine.dialect.name == "sqlite": 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 @@ from cognee.modules.users.methods import create_default_user, delete_user 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 @@ class config(): 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 @@ class config(): @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 @@ class VectorConfig(BaseSettings): 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 @@ class WeaviateAdapter(VectorDBInterface): 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 @@ import os from pathlib import Path from typing import List, Type -import aiofiles import openai import instructor from pydantic import BaseModel @@ -13,9 +12,7 @@ from tenacity import retry, stop_after_attempt 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 @@ from cognee.api.v1.search import SearchType 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 @@ from cognee.api.v1.search import SearchType 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"