cognee 0.5.0.dev0__py3-none-any.whl → 0.5.0.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- cognee/api/client.py +1 -5
- cognee/api/v1/add/add.py +2 -1
- cognee/api/v1/cognify/cognify.py +24 -16
- cognee/api/v1/cognify/routers/__init__.py +0 -1
- cognee/api/v1/cognify/routers/get_cognify_router.py +3 -1
- cognee/api/v1/datasets/routers/get_datasets_router.py +3 -3
- cognee/api/v1/ontologies/ontologies.py +12 -37
- cognee/api/v1/ontologies/routers/get_ontology_router.py +27 -25
- cognee/api/v1/search/search.py +4 -0
- cognee/api/v1/ui/node_setup.py +360 -0
- cognee/api/v1/ui/npm_utils.py +50 -0
- cognee/api/v1/ui/ui.py +38 -68
- cognee/context_global_variables.py +61 -16
- cognee/eval_framework/Dockerfile +29 -0
- cognee/eval_framework/answer_generation/answer_generation_executor.py +10 -0
- cognee/eval_framework/answer_generation/run_question_answering_module.py +1 -1
- cognee/eval_framework/corpus_builder/task_getters/get_cascade_graph_tasks.py +0 -2
- cognee/eval_framework/corpus_builder/task_getters/get_default_tasks_by_indices.py +4 -4
- cognee/eval_framework/eval_config.py +2 -2
- cognee/eval_framework/modal_run_eval.py +16 -28
- cognee/infrastructure/databases/dataset_database_handler/__init__.py +3 -0
- cognee/infrastructure/databases/dataset_database_handler/dataset_database_handler_interface.py +80 -0
- cognee/infrastructure/databases/dataset_database_handler/supported_dataset_database_handlers.py +18 -0
- cognee/infrastructure/databases/dataset_database_handler/use_dataset_database_handler.py +10 -0
- cognee/infrastructure/databases/graph/config.py +3 -0
- cognee/infrastructure/databases/graph/get_graph_engine.py +1 -0
- cognee/infrastructure/databases/graph/graph_db_interface.py +15 -0
- cognee/infrastructure/databases/graph/kuzu/KuzuDatasetDatabaseHandler.py +81 -0
- cognee/infrastructure/databases/graph/kuzu/adapter.py +228 -0
- cognee/infrastructure/databases/graph/neo4j_driver/Neo4jAuraDevDatasetDatabaseHandler.py +168 -0
- cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +80 -1
- cognee/infrastructure/databases/utils/__init__.py +3 -0
- cognee/infrastructure/databases/utils/get_graph_dataset_database_handler.py +10 -0
- cognee/infrastructure/databases/utils/get_or_create_dataset_database.py +62 -48
- cognee/infrastructure/databases/utils/get_vector_dataset_database_handler.py +10 -0
- cognee/infrastructure/databases/utils/resolve_dataset_database_connection_info.py +30 -0
- cognee/infrastructure/databases/vector/config.py +2 -0
- cognee/infrastructure/databases/vector/create_vector_engine.py +1 -0
- cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +8 -6
- cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +9 -7
- cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +11 -10
- cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +2 -0
- cognee/infrastructure/databases/vector/lancedb/LanceDBDatasetDatabaseHandler.py +50 -0
- cognee/infrastructure/databases/vector/vector_db_interface.py +35 -0
- cognee/infrastructure/files/storage/s3_config.py +2 -0
- cognee/infrastructure/llm/LLMGateway.py +5 -2
- cognee/infrastructure/llm/config.py +35 -0
- cognee/infrastructure/llm/extraction/knowledge_graph/extract_content_graph.py +2 -2
- cognee/infrastructure/llm/structured_output_framework/baml/baml_src/extraction/acreate_structured_output.py +23 -8
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +17 -16
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/__init__.py +5 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/bedrock/adapter.py +153 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +40 -37
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +39 -36
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +19 -1
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +11 -9
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +23 -21
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +42 -34
- cognee/memify_pipelines/create_triplet_embeddings.py +53 -0
- cognee/modules/cognify/config.py +2 -0
- cognee/modules/data/deletion/prune_system.py +52 -2
- cognee/modules/data/methods/delete_dataset.py +26 -0
- cognee/modules/engine/models/Triplet.py +9 -0
- cognee/modules/engine/models/__init__.py +1 -0
- cognee/modules/graph/cognee_graph/CogneeGraph.py +85 -37
- cognee/modules/graph/cognee_graph/CogneeGraphElements.py +8 -3
- cognee/modules/memify/memify.py +1 -7
- cognee/modules/pipelines/operations/pipeline.py +18 -2
- cognee/modules/retrieval/__init__.py +1 -1
- cognee/modules/retrieval/graph_completion_context_extension_retriever.py +4 -0
- cognee/modules/retrieval/graph_completion_cot_retriever.py +4 -0
- cognee/modules/retrieval/graph_completion_retriever.py +10 -0
- cognee/modules/retrieval/graph_summary_completion_retriever.py +4 -0
- cognee/modules/retrieval/register_retriever.py +10 -0
- cognee/modules/retrieval/registered_community_retrievers.py +1 -0
- cognee/modules/retrieval/temporal_retriever.py +4 -0
- cognee/modules/retrieval/triplet_retriever.py +182 -0
- cognee/modules/retrieval/utils/brute_force_triplet_search.py +42 -10
- cognee/modules/run_custom_pipeline/run_custom_pipeline.py +8 -1
- cognee/modules/search/methods/get_search_type_tools.py +54 -8
- cognee/modules/search/methods/no_access_control_search.py +4 -0
- cognee/modules/search/methods/search.py +21 -0
- cognee/modules/search/types/SearchType.py +1 -1
- cognee/modules/settings/get_settings.py +19 -0
- cognee/modules/users/methods/get_authenticated_user.py +2 -2
- cognee/modules/users/models/DatasetDatabase.py +15 -3
- cognee/shared/logging_utils.py +4 -0
- cognee/shared/rate_limiting.py +30 -0
- cognee/tasks/documents/__init__.py +0 -1
- cognee/tasks/graph/extract_graph_from_data.py +9 -10
- cognee/tasks/memify/get_triplet_datapoints.py +289 -0
- cognee/tasks/storage/add_data_points.py +142 -2
- cognee/tests/integration/retrieval/test_triplet_retriever.py +84 -0
- cognee/tests/integration/tasks/test_add_data_points.py +139 -0
- cognee/tests/integration/tasks/test_get_triplet_datapoints.py +69 -0
- cognee/tests/test_cognee_server_start.py +2 -4
- cognee/tests/test_conversation_history.py +23 -1
- cognee/tests/test_dataset_database_handler.py +137 -0
- cognee/tests/test_dataset_delete.py +76 -0
- cognee/tests/test_edge_centered_payload.py +170 -0
- cognee/tests/test_pipeline_cache.py +164 -0
- cognee/tests/test_search_db.py +37 -1
- cognee/tests/unit/api/test_ontology_endpoint.py +77 -89
- cognee/tests/unit/infrastructure/llm/test_llm_config.py +46 -0
- cognee/tests/unit/infrastructure/mock_embedding_engine.py +3 -7
- cognee/tests/unit/infrastructure/test_embedding_rate_limiting_realistic.py +0 -5
- cognee/tests/unit/modules/graph/cognee_graph_elements_test.py +2 -2
- cognee/tests/unit/modules/graph/cognee_graph_test.py +406 -0
- cognee/tests/unit/modules/memify_tasks/test_get_triplet_datapoints.py +214 -0
- cognee/tests/unit/modules/retrieval/test_brute_force_triplet_search.py +608 -0
- cognee/tests/unit/modules/retrieval/triplet_retriever_test.py +83 -0
- cognee/tests/unit/tasks/storage/test_add_data_points.py +288 -0
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/METADATA +76 -89
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/RECORD +118 -97
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/WHEEL +1 -1
- cognee/api/v1/cognify/code_graph_pipeline.py +0 -119
- cognee/api/v1/cognify/routers/get_code_pipeline_router.py +0 -90
- cognee/infrastructure/databases/vector/embeddings/embedding_rate_limiter.py +0 -544
- cognee/modules/retrieval/code_retriever.py +0 -232
- cognee/tasks/code/enrich_dependency_graph_checker.py +0 -35
- cognee/tasks/code/get_local_dependencies_checker.py +0 -20
- cognee/tasks/code/get_repo_dependency_graph_checker.py +0 -35
- cognee/tasks/documents/check_permissions_on_dataset.py +0 -26
- cognee/tasks/repo_processor/__init__.py +0 -2
- cognee/tasks/repo_processor/get_local_dependencies.py +0 -335
- cognee/tasks/repo_processor/get_non_code_files.py +0 -158
- cognee/tasks/repo_processor/get_repo_file_dependencies.py +0 -243
- cognee/tests/test_delete_bmw_example.py +0 -60
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/entry_points.txt +0 -0
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.5.0.dev0.dist-info → cognee-0.5.0.dev1.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -0,0 +1,360 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import platform
|
|
3
|
+
import subprocess
|
|
4
|
+
import tempfile
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
|
|
7
|
+
import requests
|
|
8
|
+
|
|
9
|
+
from cognee.shared.logging_utils import get_logger
|
|
10
|
+
|
|
11
|
+
logger = get_logger()
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def get_nvm_dir() -> Path:
|
|
15
|
+
"""
|
|
16
|
+
Get the nvm directory path following standard nvm installation logic.
|
|
17
|
+
Uses XDG_CONFIG_HOME if set, otherwise falls back to ~/.nvm.
|
|
18
|
+
"""
|
|
19
|
+
xdg_config_home = os.environ.get("XDG_CONFIG_HOME")
|
|
20
|
+
if xdg_config_home:
|
|
21
|
+
return Path(xdg_config_home) / "nvm"
|
|
22
|
+
return Path.home() / ".nvm"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
def get_nvm_sh_path() -> Path:
|
|
26
|
+
"""
|
|
27
|
+
Get the path to nvm.sh following standard nvm installation logic.
|
|
28
|
+
"""
|
|
29
|
+
return get_nvm_dir() / "nvm.sh"
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
def check_nvm_installed() -> bool:
|
|
33
|
+
"""
|
|
34
|
+
Check if nvm (Node Version Manager) is installed.
|
|
35
|
+
"""
|
|
36
|
+
try:
|
|
37
|
+
# Check if nvm is available in the shell
|
|
38
|
+
# nvm is typically sourced in shell config files, so we need to check via shell
|
|
39
|
+
if platform.system() == "Windows":
|
|
40
|
+
# On Windows, nvm-windows uses a different approach
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["nvm", "version"],
|
|
43
|
+
capture_output=True,
|
|
44
|
+
text=True,
|
|
45
|
+
timeout=10,
|
|
46
|
+
shell=True,
|
|
47
|
+
)
|
|
48
|
+
else:
|
|
49
|
+
# On Unix-like systems, nvm is a shell function, so we need to source it
|
|
50
|
+
# First check if nvm.sh exists
|
|
51
|
+
nvm_path = get_nvm_sh_path()
|
|
52
|
+
if not nvm_path.exists():
|
|
53
|
+
logger.debug(f"nvm.sh not found at {nvm_path}")
|
|
54
|
+
return False
|
|
55
|
+
|
|
56
|
+
# Try to source nvm and check version, capturing errors
|
|
57
|
+
result = subprocess.run(
|
|
58
|
+
["bash", "-c", f"source {nvm_path} && nvm --version"],
|
|
59
|
+
capture_output=True,
|
|
60
|
+
text=True,
|
|
61
|
+
timeout=10,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
if result.returncode != 0:
|
|
65
|
+
# Log the error to help diagnose configuration issues
|
|
66
|
+
if result.stderr:
|
|
67
|
+
logger.debug(f"nvm check failed: {result.stderr.strip()}")
|
|
68
|
+
return False
|
|
69
|
+
|
|
70
|
+
return result.returncode == 0
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.debug(f"Exception checking nvm: {str(e)}")
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
def install_nvm() -> bool:
|
|
77
|
+
"""
|
|
78
|
+
Install nvm (Node Version Manager) on Unix-like systems.
|
|
79
|
+
"""
|
|
80
|
+
if platform.system() == "Windows":
|
|
81
|
+
logger.error("nvm installation on Windows requires nvm-windows.")
|
|
82
|
+
logger.error(
|
|
83
|
+
"Please install nvm-windows manually from: https://github.com/coreybutler/nvm-windows"
|
|
84
|
+
)
|
|
85
|
+
return False
|
|
86
|
+
|
|
87
|
+
logger.info("Installing nvm (Node Version Manager)...")
|
|
88
|
+
|
|
89
|
+
try:
|
|
90
|
+
# Download and install nvm
|
|
91
|
+
nvm_install_script = "https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.3/install.sh"
|
|
92
|
+
logger.info(f"Downloading nvm installer from {nvm_install_script}...")
|
|
93
|
+
|
|
94
|
+
response = requests.get(nvm_install_script, timeout=60)
|
|
95
|
+
response.raise_for_status()
|
|
96
|
+
|
|
97
|
+
# Create a temporary script file
|
|
98
|
+
with tempfile.NamedTemporaryFile(mode="w", suffix=".sh", delete=False) as f:
|
|
99
|
+
f.write(response.text)
|
|
100
|
+
install_script_path = f.name
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
# Make the script executable and run it
|
|
104
|
+
os.chmod(install_script_path, 0o755)
|
|
105
|
+
result = subprocess.run(
|
|
106
|
+
["bash", install_script_path],
|
|
107
|
+
capture_output=True,
|
|
108
|
+
text=True,
|
|
109
|
+
timeout=120,
|
|
110
|
+
)
|
|
111
|
+
|
|
112
|
+
if result.returncode == 0:
|
|
113
|
+
logger.info("✓ nvm installed successfully")
|
|
114
|
+
# Source nvm in current shell session
|
|
115
|
+
nvm_dir = get_nvm_dir()
|
|
116
|
+
if nvm_dir.exists():
|
|
117
|
+
return True
|
|
118
|
+
else:
|
|
119
|
+
logger.warning(
|
|
120
|
+
f"nvm installation completed but nvm directory not found at {nvm_dir}"
|
|
121
|
+
)
|
|
122
|
+
return False
|
|
123
|
+
else:
|
|
124
|
+
logger.error(f"nvm installation failed: {result.stderr}")
|
|
125
|
+
return False
|
|
126
|
+
finally:
|
|
127
|
+
# Clean up temporary script
|
|
128
|
+
try:
|
|
129
|
+
os.unlink(install_script_path)
|
|
130
|
+
except Exception:
|
|
131
|
+
pass
|
|
132
|
+
|
|
133
|
+
except requests.exceptions.RequestException as e:
|
|
134
|
+
logger.error(f"Failed to download nvm installer: {str(e)}")
|
|
135
|
+
return False
|
|
136
|
+
except Exception as e:
|
|
137
|
+
logger.error(f"Failed to install nvm: {str(e)}")
|
|
138
|
+
return False
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def install_node_with_nvm() -> bool:
|
|
142
|
+
"""
|
|
143
|
+
Install the latest Node.js version using nvm.
|
|
144
|
+
Returns True if installation succeeds, False otherwise.
|
|
145
|
+
"""
|
|
146
|
+
if platform.system() == "Windows":
|
|
147
|
+
logger.error("Node.js installation via nvm on Windows requires nvm-windows.")
|
|
148
|
+
logger.error("Please install Node.js manually from: https://nodejs.org/")
|
|
149
|
+
return False
|
|
150
|
+
|
|
151
|
+
logger.info("Installing latest Node.js version using nvm...")
|
|
152
|
+
|
|
153
|
+
try:
|
|
154
|
+
# Source nvm and install latest Node.js
|
|
155
|
+
nvm_path = get_nvm_sh_path()
|
|
156
|
+
if not nvm_path.exists():
|
|
157
|
+
logger.error(f"nvm.sh not found at {nvm_path}. nvm may not be properly installed.")
|
|
158
|
+
return False
|
|
159
|
+
|
|
160
|
+
nvm_source_cmd = f"source {nvm_path}"
|
|
161
|
+
install_cmd = f"{nvm_source_cmd} && nvm install node"
|
|
162
|
+
|
|
163
|
+
result = subprocess.run(
|
|
164
|
+
["bash", "-c", install_cmd],
|
|
165
|
+
capture_output=True,
|
|
166
|
+
text=True,
|
|
167
|
+
timeout=300, # 5 minutes timeout for Node.js installation
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
if result.returncode == 0:
|
|
171
|
+
logger.info("✓ Node.js installed successfully via nvm")
|
|
172
|
+
|
|
173
|
+
# Set as default version
|
|
174
|
+
use_cmd = f"{nvm_source_cmd} && nvm alias default node"
|
|
175
|
+
subprocess.run(
|
|
176
|
+
["bash", "-c", use_cmd],
|
|
177
|
+
capture_output=True,
|
|
178
|
+
text=True,
|
|
179
|
+
timeout=30,
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
# Add nvm to PATH for current session
|
|
183
|
+
# This ensures node/npm are available in subsequent commands
|
|
184
|
+
nvm_dir = get_nvm_dir()
|
|
185
|
+
if nvm_dir.exists():
|
|
186
|
+
# Update PATH for current process
|
|
187
|
+
nvm_bin = nvm_dir / "versions" / "node"
|
|
188
|
+
# Find the latest installed version
|
|
189
|
+
if nvm_bin.exists():
|
|
190
|
+
versions = sorted(nvm_bin.iterdir(), reverse=True)
|
|
191
|
+
if versions:
|
|
192
|
+
latest_node_bin = versions[0] / "bin"
|
|
193
|
+
if latest_node_bin.exists():
|
|
194
|
+
current_path = os.environ.get("PATH", "")
|
|
195
|
+
os.environ["PATH"] = f"{latest_node_bin}:{current_path}"
|
|
196
|
+
|
|
197
|
+
return True
|
|
198
|
+
else:
|
|
199
|
+
logger.error(f"Failed to install Node.js: {result.stderr}")
|
|
200
|
+
return False
|
|
201
|
+
|
|
202
|
+
except subprocess.TimeoutExpired:
|
|
203
|
+
logger.error("Timeout installing Node.js (this can take several minutes)")
|
|
204
|
+
return False
|
|
205
|
+
except Exception as e:
|
|
206
|
+
logger.error(f"Error installing Node.js: {str(e)}")
|
|
207
|
+
return False
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
def check_node_npm() -> tuple[bool, str]: # (is_available, error_message)
|
|
211
|
+
"""
|
|
212
|
+
Check if Node.js and npm are available.
|
|
213
|
+
If not available, attempts to install nvm and Node.js automatically.
|
|
214
|
+
"""
|
|
215
|
+
|
|
216
|
+
try:
|
|
217
|
+
# Check Node.js - try direct command first, then with nvm if needed
|
|
218
|
+
result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
|
|
219
|
+
if result.returncode != 0:
|
|
220
|
+
# If direct command fails, try with nvm sourced (in case nvm is installed but not in PATH)
|
|
221
|
+
nvm_path = get_nvm_sh_path()
|
|
222
|
+
if nvm_path.exists():
|
|
223
|
+
result = subprocess.run(
|
|
224
|
+
["bash", "-c", f"source {nvm_path} && node --version"],
|
|
225
|
+
capture_output=True,
|
|
226
|
+
text=True,
|
|
227
|
+
timeout=10,
|
|
228
|
+
)
|
|
229
|
+
if result.returncode != 0 and result.stderr:
|
|
230
|
+
logger.debug(f"Failed to source nvm or run node: {result.stderr.strip()}")
|
|
231
|
+
if result.returncode != 0:
|
|
232
|
+
# Node.js is not installed, try to install it
|
|
233
|
+
logger.info("Node.js is not installed. Attempting to install automatically...")
|
|
234
|
+
|
|
235
|
+
# Check if nvm is installed
|
|
236
|
+
if not check_nvm_installed():
|
|
237
|
+
logger.info("nvm is not installed. Installing nvm first...")
|
|
238
|
+
if not install_nvm():
|
|
239
|
+
return (
|
|
240
|
+
False,
|
|
241
|
+
"Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# Install Node.js using nvm
|
|
245
|
+
if not install_node_with_nvm():
|
|
246
|
+
return (
|
|
247
|
+
False,
|
|
248
|
+
"Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
# Verify installation after automatic setup
|
|
252
|
+
# Try with nvm sourced first
|
|
253
|
+
nvm_path = get_nvm_sh_path()
|
|
254
|
+
if nvm_path.exists():
|
|
255
|
+
result = subprocess.run(
|
|
256
|
+
["bash", "-c", f"source {nvm_path} && node --version"],
|
|
257
|
+
capture_output=True,
|
|
258
|
+
text=True,
|
|
259
|
+
timeout=10,
|
|
260
|
+
)
|
|
261
|
+
if result.returncode != 0 and result.stderr:
|
|
262
|
+
logger.debug(
|
|
263
|
+
f"Failed to verify node after installation: {result.stderr.strip()}"
|
|
264
|
+
)
|
|
265
|
+
else:
|
|
266
|
+
result = subprocess.run(
|
|
267
|
+
["node", "--version"], capture_output=True, text=True, timeout=10
|
|
268
|
+
)
|
|
269
|
+
if result.returncode != 0:
|
|
270
|
+
nvm_path = get_nvm_sh_path()
|
|
271
|
+
return (
|
|
272
|
+
False,
|
|
273
|
+
f"Node.js installation completed but node command is not available. Please restart your terminal or source {nvm_path}",
|
|
274
|
+
)
|
|
275
|
+
|
|
276
|
+
node_version = result.stdout.strip()
|
|
277
|
+
logger.debug(f"Found Node.js version: {node_version}")
|
|
278
|
+
|
|
279
|
+
# Check npm - handle Windows PowerShell scripts
|
|
280
|
+
if platform.system() == "Windows":
|
|
281
|
+
# On Windows, npm might be a PowerShell script, so we need to use shell=True
|
|
282
|
+
result = subprocess.run(
|
|
283
|
+
["npm", "--version"], capture_output=True, text=True, timeout=10, shell=True
|
|
284
|
+
)
|
|
285
|
+
else:
|
|
286
|
+
# On Unix-like systems, if we just installed via nvm, we may need to source nvm
|
|
287
|
+
# Try direct command first
|
|
288
|
+
result = subprocess.run(
|
|
289
|
+
["npm", "--version"], capture_output=True, text=True, timeout=10
|
|
290
|
+
)
|
|
291
|
+
if result.returncode != 0:
|
|
292
|
+
# Try with nvm sourced
|
|
293
|
+
nvm_path = get_nvm_sh_path()
|
|
294
|
+
if nvm_path.exists():
|
|
295
|
+
result = subprocess.run(
|
|
296
|
+
["bash", "-c", f"source {nvm_path} && npm --version"],
|
|
297
|
+
capture_output=True,
|
|
298
|
+
text=True,
|
|
299
|
+
timeout=10,
|
|
300
|
+
)
|
|
301
|
+
if result.returncode != 0 and result.stderr:
|
|
302
|
+
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
|
|
303
|
+
|
|
304
|
+
if result.returncode != 0:
|
|
305
|
+
return False, "npm is not installed or not in PATH"
|
|
306
|
+
|
|
307
|
+
npm_version = result.stdout.strip()
|
|
308
|
+
logger.debug(f"Found npm version: {npm_version}")
|
|
309
|
+
|
|
310
|
+
return True, f"Node.js {node_version}, npm {npm_version}"
|
|
311
|
+
|
|
312
|
+
except subprocess.TimeoutExpired:
|
|
313
|
+
return False, "Timeout checking Node.js/npm installation"
|
|
314
|
+
except FileNotFoundError:
|
|
315
|
+
# Node.js is not installed, try to install it
|
|
316
|
+
logger.info("Node.js is not found. Attempting to install automatically...")
|
|
317
|
+
|
|
318
|
+
# Check if nvm is installed
|
|
319
|
+
if not check_nvm_installed():
|
|
320
|
+
logger.info("nvm is not installed. Installing nvm first...")
|
|
321
|
+
if not install_nvm():
|
|
322
|
+
return (
|
|
323
|
+
False,
|
|
324
|
+
"Failed to install nvm. Please install Node.js manually from https://nodejs.org/",
|
|
325
|
+
)
|
|
326
|
+
|
|
327
|
+
# Install Node.js using nvm
|
|
328
|
+
if not install_node_with_nvm():
|
|
329
|
+
return (
|
|
330
|
+
False,
|
|
331
|
+
"Failed to install Node.js. Please install Node.js manually from https://nodejs.org/",
|
|
332
|
+
)
|
|
333
|
+
|
|
334
|
+
# Retry checking Node.js after installation
|
|
335
|
+
try:
|
|
336
|
+
result = subprocess.run(
|
|
337
|
+
["node", "--version"], capture_output=True, text=True, timeout=10
|
|
338
|
+
)
|
|
339
|
+
if result.returncode == 0:
|
|
340
|
+
node_version = result.stdout.strip()
|
|
341
|
+
# Check npm
|
|
342
|
+
nvm_path = get_nvm_sh_path()
|
|
343
|
+
if nvm_path.exists():
|
|
344
|
+
result = subprocess.run(
|
|
345
|
+
["bash", "-c", f"source {nvm_path} && npm --version"],
|
|
346
|
+
capture_output=True,
|
|
347
|
+
text=True,
|
|
348
|
+
timeout=10,
|
|
349
|
+
)
|
|
350
|
+
if result.returncode == 0:
|
|
351
|
+
npm_version = result.stdout.strip()
|
|
352
|
+
return True, f"Node.js {node_version}, npm {npm_version}"
|
|
353
|
+
elif result.stderr:
|
|
354
|
+
logger.debug(f"Failed to source nvm or run npm: {result.stderr.strip()}")
|
|
355
|
+
except Exception as e:
|
|
356
|
+
logger.debug(f"Exception retrying node/npm check: {str(e)}")
|
|
357
|
+
|
|
358
|
+
return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
|
|
359
|
+
except Exception as e:
|
|
360
|
+
return False, f"Error checking Node.js/npm: {str(e)}"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import subprocess
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
from typing import List
|
|
5
|
+
|
|
6
|
+
from cognee.shared.logging_utils import get_logger
|
|
7
|
+
from .node_setup import get_nvm_sh_path
|
|
8
|
+
|
|
9
|
+
logger = get_logger()
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def run_npm_command(cmd: List[str], cwd: Path, timeout: int = 300) -> subprocess.CompletedProcess:
|
|
13
|
+
"""
|
|
14
|
+
Run an npm command, ensuring nvm is sourced if needed (Unix-like systems only).
|
|
15
|
+
Returns the CompletedProcess result.
|
|
16
|
+
"""
|
|
17
|
+
if platform.system() == "Windows":
|
|
18
|
+
# On Windows, use shell=True for npm commands
|
|
19
|
+
return subprocess.run(
|
|
20
|
+
cmd,
|
|
21
|
+
cwd=cwd,
|
|
22
|
+
capture_output=True,
|
|
23
|
+
text=True,
|
|
24
|
+
timeout=timeout,
|
|
25
|
+
shell=True,
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
# On Unix-like systems, try direct command first
|
|
29
|
+
result = subprocess.run(
|
|
30
|
+
cmd,
|
|
31
|
+
cwd=cwd,
|
|
32
|
+
capture_output=True,
|
|
33
|
+
text=True,
|
|
34
|
+
timeout=timeout,
|
|
35
|
+
)
|
|
36
|
+
# If it fails and nvm might be installed, try with nvm sourced
|
|
37
|
+
if result.returncode != 0:
|
|
38
|
+
nvm_path = get_nvm_sh_path()
|
|
39
|
+
if nvm_path.exists():
|
|
40
|
+
nvm_cmd = f"source {nvm_path} && {' '.join(cmd)}"
|
|
41
|
+
result = subprocess.run(
|
|
42
|
+
["bash", "-c", nvm_cmd],
|
|
43
|
+
cwd=cwd,
|
|
44
|
+
capture_output=True,
|
|
45
|
+
text=True,
|
|
46
|
+
timeout=timeout,
|
|
47
|
+
)
|
|
48
|
+
if result.returncode != 0 and result.stderr:
|
|
49
|
+
logger.debug(f"npm command failed with nvm: {result.stderr.strip()}")
|
|
50
|
+
return result
|
cognee/api/v1/ui/ui.py
CHANGED
|
@@ -15,6 +15,8 @@ import shutil
|
|
|
15
15
|
|
|
16
16
|
from cognee.shared.logging_utils import get_logger
|
|
17
17
|
from cognee.version import get_cognee_version
|
|
18
|
+
from .node_setup import check_node_npm, get_nvm_dir, get_nvm_sh_path
|
|
19
|
+
from .npm_utils import run_npm_command
|
|
18
20
|
|
|
19
21
|
logger = get_logger()
|
|
20
22
|
|
|
@@ -285,48 +287,6 @@ def find_frontend_path() -> Optional[Path]:
|
|
|
285
287
|
return None
|
|
286
288
|
|
|
287
289
|
|
|
288
|
-
def check_node_npm() -> tuple[bool, str]:
|
|
289
|
-
"""
|
|
290
|
-
Check if Node.js and npm are available.
|
|
291
|
-
Returns (is_available, error_message)
|
|
292
|
-
"""
|
|
293
|
-
|
|
294
|
-
try:
|
|
295
|
-
# Check Node.js
|
|
296
|
-
result = subprocess.run(["node", "--version"], capture_output=True, text=True, timeout=10)
|
|
297
|
-
if result.returncode != 0:
|
|
298
|
-
return False, "Node.js is not installed or not in PATH"
|
|
299
|
-
|
|
300
|
-
node_version = result.stdout.strip()
|
|
301
|
-
logger.debug(f"Found Node.js version: {node_version}")
|
|
302
|
-
|
|
303
|
-
# Check npm - handle Windows PowerShell scripts
|
|
304
|
-
if platform.system() == "Windows":
|
|
305
|
-
# On Windows, npm might be a PowerShell script, so we need to use shell=True
|
|
306
|
-
result = subprocess.run(
|
|
307
|
-
["npm", "--version"], capture_output=True, text=True, timeout=10, shell=True
|
|
308
|
-
)
|
|
309
|
-
else:
|
|
310
|
-
result = subprocess.run(
|
|
311
|
-
["npm", "--version"], capture_output=True, text=True, timeout=10
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
if result.returncode != 0:
|
|
315
|
-
return False, "npm is not installed or not in PATH"
|
|
316
|
-
|
|
317
|
-
npm_version = result.stdout.strip()
|
|
318
|
-
logger.debug(f"Found npm version: {npm_version}")
|
|
319
|
-
|
|
320
|
-
return True, f"Node.js {node_version}, npm {npm_version}"
|
|
321
|
-
|
|
322
|
-
except subprocess.TimeoutExpired:
|
|
323
|
-
return False, "Timeout checking Node.js/npm installation"
|
|
324
|
-
except FileNotFoundError:
|
|
325
|
-
return False, "Node.js/npm not found. Please install Node.js from https://nodejs.org/"
|
|
326
|
-
except Exception as e:
|
|
327
|
-
return False, f"Error checking Node.js/npm: {str(e)}"
|
|
328
|
-
|
|
329
|
-
|
|
330
290
|
def install_frontend_dependencies(frontend_path: Path) -> bool:
|
|
331
291
|
"""
|
|
332
292
|
Install frontend dependencies if node_modules doesn't exist.
|
|
@@ -341,24 +301,7 @@ def install_frontend_dependencies(frontend_path: Path) -> bool:
|
|
|
341
301
|
logger.info("Installing frontend dependencies (this may take a few minutes)...")
|
|
342
302
|
|
|
343
303
|
try:
|
|
344
|
-
|
|
345
|
-
if platform.system() == "Windows":
|
|
346
|
-
result = subprocess.run(
|
|
347
|
-
["npm", "install"],
|
|
348
|
-
cwd=frontend_path,
|
|
349
|
-
capture_output=True,
|
|
350
|
-
text=True,
|
|
351
|
-
timeout=300, # 5 minutes timeout
|
|
352
|
-
shell=True,
|
|
353
|
-
)
|
|
354
|
-
else:
|
|
355
|
-
result = subprocess.run(
|
|
356
|
-
["npm", "install"],
|
|
357
|
-
cwd=frontend_path,
|
|
358
|
-
capture_output=True,
|
|
359
|
-
text=True,
|
|
360
|
-
timeout=300, # 5 minutes timeout
|
|
361
|
-
)
|
|
304
|
+
result = run_npm_command(["npm", "install"], frontend_path, timeout=300)
|
|
362
305
|
|
|
363
306
|
if result.returncode == 0:
|
|
364
307
|
logger.info("Frontend dependencies installed successfully")
|
|
@@ -642,6 +585,21 @@ def start_ui(
|
|
|
642
585
|
env["HOST"] = "localhost"
|
|
643
586
|
env["PORT"] = str(port)
|
|
644
587
|
|
|
588
|
+
# If nvm is installed, ensure it's available in the environment
|
|
589
|
+
nvm_path = get_nvm_sh_path()
|
|
590
|
+
if platform.system() != "Windows" and nvm_path.exists():
|
|
591
|
+
# Add nvm to PATH for the subprocess
|
|
592
|
+
nvm_dir = get_nvm_dir()
|
|
593
|
+
# Find the latest Node.js version installed via nvm
|
|
594
|
+
nvm_versions = nvm_dir / "versions" / "node"
|
|
595
|
+
if nvm_versions.exists():
|
|
596
|
+
versions = sorted(nvm_versions.iterdir(), reverse=True)
|
|
597
|
+
if versions:
|
|
598
|
+
latest_node_bin = versions[0] / "bin"
|
|
599
|
+
if latest_node_bin.exists():
|
|
600
|
+
current_path = env.get("PATH", "")
|
|
601
|
+
env["PATH"] = f"{latest_node_bin}:{current_path}"
|
|
602
|
+
|
|
645
603
|
# Start the development server
|
|
646
604
|
logger.info(f"Starting frontend server at http://localhost:{port}")
|
|
647
605
|
logger.info("This may take a moment to compile and start...")
|
|
@@ -659,14 +617,26 @@ def start_ui(
|
|
|
659
617
|
shell=True,
|
|
660
618
|
)
|
|
661
619
|
else:
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
620
|
+
# On Unix-like systems, use bash with nvm sourced if available
|
|
621
|
+
if nvm_path.exists():
|
|
622
|
+
# Use bash to source nvm and run npm
|
|
623
|
+
process = subprocess.Popen(
|
|
624
|
+
["bash", "-c", f"source {nvm_path} && npm run dev"],
|
|
625
|
+
cwd=frontend_path,
|
|
626
|
+
env=env,
|
|
627
|
+
stdout=subprocess.PIPE,
|
|
628
|
+
stderr=subprocess.PIPE,
|
|
629
|
+
preexec_fn=os.setsid if hasattr(os, "setsid") else None,
|
|
630
|
+
)
|
|
631
|
+
else:
|
|
632
|
+
process = subprocess.Popen(
|
|
633
|
+
["npm", "run", "dev"],
|
|
634
|
+
cwd=frontend_path,
|
|
635
|
+
env=env,
|
|
636
|
+
stdout=subprocess.PIPE,
|
|
637
|
+
stderr=subprocess.PIPE,
|
|
638
|
+
preexec_fn=os.setsid if hasattr(os, "setsid") else None,
|
|
639
|
+
)
|
|
670
640
|
|
|
671
641
|
# Start threads to stream frontend output with prefix
|
|
672
642
|
_stream_process_output(process, "stdout", "[FRONTEND]", "\033[33m") # Yellow
|
|
@@ -4,9 +4,10 @@ from typing import Union
|
|
|
4
4
|
from uuid import UUID
|
|
5
5
|
|
|
6
6
|
from cognee.base_config import get_base_config
|
|
7
|
-
from cognee.infrastructure.databases.vector.config import
|
|
8
|
-
from cognee.infrastructure.databases.graph.config import
|
|
7
|
+
from cognee.infrastructure.databases.vector.config import get_vectordb_config
|
|
8
|
+
from cognee.infrastructure.databases.graph.config import get_graph_config
|
|
9
9
|
from cognee.infrastructure.databases.utils import get_or_create_dataset_database
|
|
10
|
+
from cognee.infrastructure.databases.utils import resolve_dataset_database_connection_info
|
|
10
11
|
from cognee.infrastructure.files.storage.config import file_storage_config
|
|
11
12
|
from cognee.modules.users.methods import get_user
|
|
12
13
|
|
|
@@ -16,22 +17,59 @@ vector_db_config = ContextVar("vector_db_config", default=None)
|
|
|
16
17
|
graph_db_config = ContextVar("graph_db_config", default=None)
|
|
17
18
|
session_user = ContextVar("session_user", default=None)
|
|
18
19
|
|
|
19
|
-
VECTOR_DBS_WITH_MULTI_USER_SUPPORT = ["lancedb", "falkor"]
|
|
20
|
-
GRAPH_DBS_WITH_MULTI_USER_SUPPORT = ["kuzu", "falkor"]
|
|
21
|
-
|
|
22
20
|
|
|
23
21
|
async def set_session_user_context_variable(user):
|
|
24
22
|
session_user.set(user)
|
|
25
23
|
|
|
26
24
|
|
|
27
25
|
def multi_user_support_possible():
|
|
28
|
-
graph_db_config =
|
|
29
|
-
vector_db_config =
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
26
|
+
graph_db_config = get_graph_config()
|
|
27
|
+
vector_db_config = get_vectordb_config()
|
|
28
|
+
|
|
29
|
+
graph_handler = graph_db_config.graph_dataset_database_handler
|
|
30
|
+
vector_handler = vector_db_config.vector_dataset_database_handler
|
|
31
|
+
from cognee.infrastructure.databases.dataset_database_handler import (
|
|
32
|
+
supported_dataset_database_handlers,
|
|
33
33
|
)
|
|
34
34
|
|
|
35
|
+
if graph_handler not in supported_dataset_database_handlers:
|
|
36
|
+
raise EnvironmentError(
|
|
37
|
+
"Unsupported graph dataset to database handler configured. Cannot add support for multi-user access control mode. Please use a supported graph dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
|
|
38
|
+
f"Selected graph dataset to database handler: {graph_handler}\n"
|
|
39
|
+
f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
|
|
40
|
+
)
|
|
41
|
+
|
|
42
|
+
if vector_handler not in supported_dataset_database_handlers:
|
|
43
|
+
raise EnvironmentError(
|
|
44
|
+
"Unsupported vector dataset to database handler configured. Cannot add support for multi-user access control mode. Please use a supported vector dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
|
|
45
|
+
f"Selected vector dataset to database handler: {vector_handler}\n"
|
|
46
|
+
f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
if (
|
|
50
|
+
supported_dataset_database_handlers[graph_handler]["handler_provider"]
|
|
51
|
+
!= graph_db_config.graph_database_provider
|
|
52
|
+
):
|
|
53
|
+
raise EnvironmentError(
|
|
54
|
+
"The selected graph dataset to database handler does not work with the configured graph database provider. Cannot add support for multi-user access control mode. Please use a supported graph dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
|
|
55
|
+
f"Selected graph database provider: {graph_db_config.graph_database_provider}\n"
|
|
56
|
+
f"Selected graph dataset to database handler: {graph_handler}\n"
|
|
57
|
+
f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
|
|
58
|
+
)
|
|
59
|
+
|
|
60
|
+
if (
|
|
61
|
+
supported_dataset_database_handlers[vector_handler]["handler_provider"]
|
|
62
|
+
!= vector_db_config.vector_db_provider
|
|
63
|
+
):
|
|
64
|
+
raise EnvironmentError(
|
|
65
|
+
"The selected vector dataset to database handler does not work with the configured vector database provider. Cannot add support for multi-user access control mode. Please use a supported vector dataset to database handler or set the environment variables ENABLE_BACKEND_ACCESS_CONTROL to false to switch off multi-user access control mode.\n"
|
|
66
|
+
f"Selected vector database provider: {vector_db_config.vector_db_provider}\n"
|
|
67
|
+
f"Selected vector dataset to database handler: {vector_handler}\n"
|
|
68
|
+
f"Supported dataset to database handlers: {list(supported_dataset_database_handlers.keys())}\n"
|
|
69
|
+
)
|
|
70
|
+
|
|
71
|
+
return True
|
|
72
|
+
|
|
35
73
|
|
|
36
74
|
def backend_access_control_enabled():
|
|
37
75
|
backend_access_control = os.environ.get("ENABLE_BACKEND_ACCESS_CONTROL", None)
|
|
@@ -41,12 +79,7 @@ def backend_access_control_enabled():
|
|
|
41
79
|
return multi_user_support_possible()
|
|
42
80
|
elif backend_access_control.lower() == "true":
|
|
43
81
|
# If enabled, ensure that the current graph and vector DBs can support it
|
|
44
|
-
|
|
45
|
-
if not multi_user_support:
|
|
46
|
-
raise EnvironmentError(
|
|
47
|
-
"ENABLE_BACKEND_ACCESS_CONTROL is set to true but the current graph and/or vector databases do not support multi-user access control. Please use supported databases or disable backend access control."
|
|
48
|
-
)
|
|
49
|
-
return True
|
|
82
|
+
return multi_user_support_possible()
|
|
50
83
|
return False
|
|
51
84
|
|
|
52
85
|
|
|
@@ -76,6 +109,8 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
|
|
|
76
109
|
|
|
77
110
|
# To ensure permissions are enforced properly all datasets will have their own databases
|
|
78
111
|
dataset_database = await get_or_create_dataset_database(dataset, user)
|
|
112
|
+
# Ensure that all connection info is resolved properly
|
|
113
|
+
dataset_database = await resolve_dataset_database_connection_info(dataset_database)
|
|
79
114
|
|
|
80
115
|
base_config = get_base_config()
|
|
81
116
|
data_root_directory = os.path.join(
|
|
@@ -86,6 +121,8 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
|
|
|
86
121
|
)
|
|
87
122
|
|
|
88
123
|
# Set vector and graph database configuration based on dataset database information
|
|
124
|
+
# TODO: Add better handling of vector and graph config accross Cognee.
|
|
125
|
+
# LRU_CACHE takes into account order of inputs, if order of inputs is changed it will be registered as a new DB adapter
|
|
89
126
|
vector_config = {
|
|
90
127
|
"vector_db_provider": dataset_database.vector_database_provider,
|
|
91
128
|
"vector_db_url": dataset_database.vector_database_url,
|
|
@@ -101,6 +138,14 @@ async def set_database_global_context_variables(dataset: Union[str, UUID], user_
|
|
|
101
138
|
"graph_file_path": os.path.join(
|
|
102
139
|
databases_directory_path, dataset_database.graph_database_name
|
|
103
140
|
),
|
|
141
|
+
"graph_database_username": dataset_database.graph_database_connection_info.get(
|
|
142
|
+
"graph_database_username", ""
|
|
143
|
+
),
|
|
144
|
+
"graph_database_password": dataset_database.graph_database_connection_info.get(
|
|
145
|
+
"graph_database_password", ""
|
|
146
|
+
),
|
|
147
|
+
"graph_dataset_database_handler": "",
|
|
148
|
+
"graph_database_port": "",
|
|
104
149
|
}
|
|
105
150
|
|
|
106
151
|
storage_config = {
|