cognee 0.3.5__py3-none-any.whl → 0.3.7__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/__init__.py +1 -0
- cognee/api/health.py +2 -12
- cognee/api/v1/add/add.py +46 -6
- cognee/api/v1/add/routers/get_add_router.py +5 -1
- cognee/api/v1/cognify/cognify.py +29 -9
- cognee/api/v1/datasets/datasets.py +11 -0
- cognee/api/v1/responses/default_tools.py +0 -1
- cognee/api/v1/responses/dispatch_function.py +1 -1
- cognee/api/v1/responses/routers/default_tools.py +0 -1
- cognee/api/v1/search/search.py +11 -9
- cognee/api/v1/settings/routers/get_settings_router.py +7 -1
- cognee/api/v1/ui/ui.py +47 -16
- cognee/api/v1/update/routers/get_update_router.py +1 -1
- cognee/api/v1/update/update.py +3 -3
- cognee/cli/_cognee.py +61 -10
- cognee/cli/commands/add_command.py +3 -3
- cognee/cli/commands/cognify_command.py +3 -3
- cognee/cli/commands/config_command.py +9 -7
- cognee/cli/commands/delete_command.py +3 -3
- cognee/cli/commands/search_command.py +3 -7
- cognee/cli/config.py +0 -1
- cognee/context_global_variables.py +5 -0
- cognee/exceptions/exceptions.py +1 -1
- cognee/infrastructure/databases/cache/__init__.py +2 -0
- cognee/infrastructure/databases/cache/cache_db_interface.py +79 -0
- cognee/infrastructure/databases/cache/config.py +44 -0
- cognee/infrastructure/databases/cache/get_cache_engine.py +67 -0
- cognee/infrastructure/databases/cache/redis/RedisAdapter.py +243 -0
- cognee/infrastructure/databases/exceptions/__init__.py +1 -0
- cognee/infrastructure/databases/exceptions/exceptions.py +18 -2
- cognee/infrastructure/databases/graph/get_graph_engine.py +1 -1
- cognee/infrastructure/databases/graph/graph_db_interface.py +5 -0
- cognee/infrastructure/databases/graph/kuzu/adapter.py +67 -44
- cognee/infrastructure/databases/graph/neo4j_driver/adapter.py +13 -3
- cognee/infrastructure/databases/graph/neo4j_driver/deadlock_retry.py +1 -1
- cognee/infrastructure/databases/graph/neptune_driver/neptune_utils.py +1 -1
- cognee/infrastructure/databases/relational/sqlalchemy/SqlAlchemyAdapter.py +1 -1
- cognee/infrastructure/databases/vector/embeddings/FastembedEmbeddingEngine.py +21 -3
- cognee/infrastructure/databases/vector/embeddings/LiteLLMEmbeddingEngine.py +17 -10
- cognee/infrastructure/databases/vector/embeddings/OllamaEmbeddingEngine.py +17 -4
- cognee/infrastructure/databases/vector/embeddings/config.py +2 -3
- cognee/infrastructure/databases/vector/exceptions/exceptions.py +1 -1
- cognee/infrastructure/databases/vector/lancedb/LanceDBAdapter.py +0 -1
- cognee/infrastructure/files/exceptions.py +1 -1
- cognee/infrastructure/files/storage/LocalFileStorage.py +9 -9
- cognee/infrastructure/files/storage/S3FileStorage.py +11 -11
- cognee/infrastructure/files/utils/guess_file_type.py +6 -0
- cognee/infrastructure/llm/prompts/search_type_selector_prompt.txt +0 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/anthropic/adapter.py +19 -9
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/gemini/adapter.py +17 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/generic_llm_api/adapter.py +17 -5
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/get_llm_client.py +32 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/__init__.py +0 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/mistral/adapter.py +109 -0
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/ollama/adapter.py +33 -8
- cognee/infrastructure/llm/structured_output_framework/litellm_instructor/llm/openai/adapter.py +40 -18
- cognee/infrastructure/loaders/LoaderEngine.py +27 -7
- cognee/infrastructure/loaders/external/__init__.py +7 -0
- cognee/infrastructure/loaders/external/advanced_pdf_loader.py +2 -8
- cognee/infrastructure/loaders/external/beautiful_soup_loader.py +310 -0
- cognee/infrastructure/loaders/supported_loaders.py +7 -0
- cognee/modules/data/exceptions/exceptions.py +1 -1
- cognee/modules/data/methods/__init__.py +3 -0
- cognee/modules/data/methods/get_dataset_data.py +4 -1
- cognee/modules/data/methods/has_dataset_data.py +21 -0
- cognee/modules/engine/models/TableRow.py +0 -1
- cognee/modules/ingestion/save_data_to_file.py +9 -2
- cognee/modules/pipelines/exceptions/exceptions.py +1 -1
- cognee/modules/pipelines/operations/pipeline.py +12 -1
- cognee/modules/pipelines/operations/run_tasks.py +25 -197
- cognee/modules/pipelines/operations/run_tasks_data_item.py +260 -0
- cognee/modules/pipelines/operations/run_tasks_distributed.py +121 -38
- cognee/modules/retrieval/EntityCompletionRetriever.py +48 -8
- cognee/modules/retrieval/base_graph_retriever.py +3 -1
- cognee/modules/retrieval/base_retriever.py +3 -1
- cognee/modules/retrieval/chunks_retriever.py +5 -1
- cognee/modules/retrieval/code_retriever.py +20 -2
- cognee/modules/retrieval/completion_retriever.py +50 -9
- cognee/modules/retrieval/cypher_search_retriever.py +11 -1
- cognee/modules/retrieval/graph_completion_context_extension_retriever.py +47 -8
- cognee/modules/retrieval/graph_completion_cot_retriever.py +32 -1
- cognee/modules/retrieval/graph_completion_retriever.py +54 -10
- cognee/modules/retrieval/lexical_retriever.py +20 -2
- cognee/modules/retrieval/natural_language_retriever.py +10 -1
- cognee/modules/retrieval/summaries_retriever.py +5 -1
- cognee/modules/retrieval/temporal_retriever.py +62 -10
- cognee/modules/retrieval/user_qa_feedback.py +3 -2
- cognee/modules/retrieval/utils/completion.py +5 -0
- cognee/modules/retrieval/utils/description_to_codepart_search.py +1 -1
- cognee/modules/retrieval/utils/session_cache.py +156 -0
- cognee/modules/search/methods/get_search_type_tools.py +0 -5
- cognee/modules/search/methods/no_access_control_search.py +12 -1
- cognee/modules/search/methods/search.py +34 -2
- cognee/modules/search/types/SearchType.py +0 -1
- cognee/modules/settings/get_settings.py +23 -0
- cognee/modules/users/methods/get_authenticated_user.py +3 -1
- cognee/modules/users/methods/get_default_user.py +1 -6
- cognee/modules/users/roles/methods/create_role.py +2 -2
- cognee/modules/users/tenants/methods/create_tenant.py +2 -2
- cognee/shared/exceptions/exceptions.py +1 -1
- cognee/tasks/codingagents/coding_rule_associations.py +1 -2
- cognee/tasks/documents/exceptions/exceptions.py +1 -1
- cognee/tasks/graph/extract_graph_from_data.py +2 -0
- cognee/tasks/ingestion/data_item_to_text_file.py +3 -3
- cognee/tasks/ingestion/ingest_data.py +11 -5
- cognee/tasks/ingestion/save_data_item_to_storage.py +12 -1
- cognee/tasks/storage/add_data_points.py +3 -10
- cognee/tasks/storage/index_data_points.py +19 -14
- cognee/tasks/storage/index_graph_edges.py +25 -11
- cognee/tasks/web_scraper/__init__.py +34 -0
- cognee/tasks/web_scraper/config.py +26 -0
- cognee/tasks/web_scraper/default_url_crawler.py +446 -0
- cognee/tasks/web_scraper/models.py +46 -0
- cognee/tasks/web_scraper/types.py +4 -0
- cognee/tasks/web_scraper/utils.py +142 -0
- cognee/tasks/web_scraper/web_scraper_task.py +396 -0
- cognee/tests/cli_tests/cli_unit_tests/test_cli_utils.py +0 -1
- cognee/tests/integration/web_url_crawler/test_default_url_crawler.py +13 -0
- cognee/tests/integration/web_url_crawler/test_tavily_crawler.py +19 -0
- cognee/tests/integration/web_url_crawler/test_url_adding_e2e.py +344 -0
- cognee/tests/subprocesses/reader.py +25 -0
- cognee/tests/subprocesses/simple_cognify_1.py +31 -0
- cognee/tests/subprocesses/simple_cognify_2.py +31 -0
- cognee/tests/subprocesses/writer.py +32 -0
- cognee/tests/tasks/descriptive_metrics/metrics_test_utils.py +0 -2
- cognee/tests/tasks/descriptive_metrics/neo4j_metrics_test.py +8 -3
- cognee/tests/tasks/entity_extraction/entity_extraction_test.py +89 -0
- cognee/tests/tasks/web_scraping/web_scraping_test.py +172 -0
- cognee/tests/test_add_docling_document.py +56 -0
- cognee/tests/test_chromadb.py +7 -11
- cognee/tests/test_concurrent_subprocess_access.py +76 -0
- cognee/tests/test_conversation_history.py +240 -0
- cognee/tests/test_kuzu.py +27 -15
- cognee/tests/test_lancedb.py +7 -11
- cognee/tests/test_library.py +32 -2
- cognee/tests/test_neo4j.py +24 -16
- cognee/tests/test_neptune_analytics_vector.py +7 -11
- cognee/tests/test_permissions.py +9 -13
- cognee/tests/test_pgvector.py +4 -4
- cognee/tests/test_remote_kuzu.py +8 -11
- cognee/tests/test_s3_file_storage.py +1 -1
- cognee/tests/test_search_db.py +6 -8
- cognee/tests/unit/infrastructure/databases/cache/test_cache_config.py +89 -0
- cognee/tests/unit/modules/retrieval/conversation_history_test.py +154 -0
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/METADATA +22 -7
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/RECORD +155 -128
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/entry_points.txt +1 -0
- distributed/Dockerfile +0 -3
- distributed/entrypoint.py +21 -9
- distributed/signal.py +5 -0
- distributed/workers/data_point_saving_worker.py +64 -34
- distributed/workers/graph_saving_worker.py +71 -47
- cognee/infrastructure/databases/graph/memgraph/memgraph_adapter.py +0 -1116
- cognee/modules/retrieval/insights_retriever.py +0 -133
- cognee/tests/test_memgraph.py +0 -109
- cognee/tests/unit/modules/retrieval/insights_retriever_test.py +0 -251
- distributed/poetry.lock +0 -12238
- distributed/pyproject.toml +0 -185
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/WHEEL +0 -0
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/licenses/LICENSE +0 -0
- {cognee-0.3.5.dist-info → cognee-0.3.7.dist-info}/licenses/NOTICE.md +0 -0
|
@@ -1,20 +1,26 @@
|
|
|
1
|
+
import asyncio
|
|
1
2
|
from typing import Any, Optional, Type, List
|
|
2
3
|
from uuid import NAMESPACE_OID, uuid5
|
|
3
4
|
|
|
4
5
|
from cognee.infrastructure.engine import DataPoint
|
|
5
6
|
from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
|
|
6
|
-
from cognee.modules.users.methods import get_default_user
|
|
7
7
|
from cognee.tasks.storage import add_data_points
|
|
8
8
|
from cognee.modules.graph.utils import resolve_edges_to_text
|
|
9
9
|
from cognee.modules.graph.utils.convert_node_to_data_point import get_all_subclasses
|
|
10
10
|
from cognee.modules.retrieval.base_graph_retriever import BaseGraphRetriever
|
|
11
11
|
from cognee.modules.retrieval.utils.brute_force_triplet_search import brute_force_triplet_search
|
|
12
|
-
from cognee.modules.retrieval.utils.completion import generate_completion
|
|
12
|
+
from cognee.modules.retrieval.utils.completion import generate_completion, summarize_text
|
|
13
|
+
from cognee.modules.retrieval.utils.session_cache import (
|
|
14
|
+
save_conversation_history,
|
|
15
|
+
get_conversation_history,
|
|
16
|
+
)
|
|
13
17
|
from cognee.shared.logging_utils import get_logger
|
|
14
18
|
from cognee.modules.retrieval.utils.extract_uuid_from_node import extract_uuid_from_node
|
|
15
19
|
from cognee.modules.retrieval.utils.models import CogneeUserInteraction
|
|
16
20
|
from cognee.modules.engine.models.node_set import NodeSet
|
|
17
21
|
from cognee.infrastructure.databases.graph import get_graph_engine
|
|
22
|
+
from cognee.context_global_variables import session_user
|
|
23
|
+
from cognee.infrastructure.databases.cache.config import CacheConfig
|
|
18
24
|
|
|
19
25
|
logger = get_logger("GraphCompletionRetriever")
|
|
20
26
|
|
|
@@ -118,6 +124,13 @@ class GraphCompletionRetriever(BaseGraphRetriever):
|
|
|
118
124
|
- str: A string representing the resolved context from the retrieved triplets, or an
|
|
119
125
|
empty string if no triplets are found.
|
|
120
126
|
"""
|
|
127
|
+
graph_engine = await get_graph_engine()
|
|
128
|
+
is_empty = await graph_engine.is_empty()
|
|
129
|
+
|
|
130
|
+
if is_empty:
|
|
131
|
+
logger.warning("Search attempt on an empty knowledge graph")
|
|
132
|
+
return []
|
|
133
|
+
|
|
121
134
|
triplets = await self.get_triplets(query)
|
|
122
135
|
|
|
123
136
|
if len(triplets) == 0:
|
|
@@ -132,6 +145,7 @@ class GraphCompletionRetriever(BaseGraphRetriever):
|
|
|
132
145
|
self,
|
|
133
146
|
query: str,
|
|
134
147
|
context: Optional[List[Edge]] = None,
|
|
148
|
+
session_id: Optional[str] = None,
|
|
135
149
|
) -> List[str]:
|
|
136
150
|
"""
|
|
137
151
|
Generates a completion using graph connections context based on a query.
|
|
@@ -142,6 +156,8 @@ class GraphCompletionRetriever(BaseGraphRetriever):
|
|
|
142
156
|
- query (str): The query string for which a completion is generated.
|
|
143
157
|
- context (Optional[Any]): Optional context to use for generating the completion; if
|
|
144
158
|
not provided, context is retrieved based on the query. (default None)
|
|
159
|
+
- session_id (Optional[str]): Optional session identifier for caching. If None,
|
|
160
|
+
defaults to 'default_session'. (default None)
|
|
145
161
|
|
|
146
162
|
Returns:
|
|
147
163
|
--------
|
|
@@ -155,19 +171,47 @@ class GraphCompletionRetriever(BaseGraphRetriever):
|
|
|
155
171
|
|
|
156
172
|
context_text = await resolve_edges_to_text(triplets)
|
|
157
173
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
174
|
+
cache_config = CacheConfig()
|
|
175
|
+
user = session_user.get()
|
|
176
|
+
user_id = getattr(user, "id", None)
|
|
177
|
+
session_save = user_id and cache_config.caching
|
|
178
|
+
|
|
179
|
+
if session_save:
|
|
180
|
+
conversation_history = await get_conversation_history(session_id=session_id)
|
|
181
|
+
|
|
182
|
+
context_summary, completion = await asyncio.gather(
|
|
183
|
+
summarize_text(context_text),
|
|
184
|
+
generate_completion(
|
|
185
|
+
query=query,
|
|
186
|
+
context=context_text,
|
|
187
|
+
user_prompt_path=self.user_prompt_path,
|
|
188
|
+
system_prompt_path=self.system_prompt_path,
|
|
189
|
+
system_prompt=self.system_prompt,
|
|
190
|
+
conversation_history=conversation_history,
|
|
191
|
+
),
|
|
192
|
+
)
|
|
193
|
+
else:
|
|
194
|
+
completion = await generate_completion(
|
|
195
|
+
query=query,
|
|
196
|
+
context=context_text,
|
|
197
|
+
user_prompt_path=self.user_prompt_path,
|
|
198
|
+
system_prompt_path=self.system_prompt_path,
|
|
199
|
+
system_prompt=self.system_prompt,
|
|
200
|
+
)
|
|
165
201
|
|
|
166
202
|
if self.save_interaction and context and triplets and completion:
|
|
167
203
|
await self.save_qa(
|
|
168
204
|
question=query, answer=completion, context=context_text, triplets=triplets
|
|
169
205
|
)
|
|
170
206
|
|
|
207
|
+
if session_save:
|
|
208
|
+
await save_conversation_history(
|
|
209
|
+
query=query,
|
|
210
|
+
context_summary=context_summary,
|
|
211
|
+
answer=completion,
|
|
212
|
+
session_id=session_id,
|
|
213
|
+
)
|
|
214
|
+
|
|
171
215
|
return [completion]
|
|
172
216
|
|
|
173
217
|
async def save_qa(self, question: str, answer: str, context: str, triplets: List) -> None:
|
|
@@ -194,7 +238,7 @@ class GraphCompletionRetriever(BaseGraphRetriever):
|
|
|
194
238
|
belongs_to_set=interactions_node_set,
|
|
195
239
|
)
|
|
196
240
|
|
|
197
|
-
await add_data_points(data_points=[cognee_user_interaction]
|
|
241
|
+
await add_data_points(data_points=[cognee_user_interaction])
|
|
198
242
|
|
|
199
243
|
relationships = []
|
|
200
244
|
relationship_name = "used_graph_element_to_answer"
|
|
@@ -116,8 +116,26 @@ class LexicalRetriever(BaseRetriever):
|
|
|
116
116
|
else:
|
|
117
117
|
return [self.payloads[chunk_id] for chunk_id, _ in top_results]
|
|
118
118
|
|
|
119
|
-
async def get_completion(
|
|
120
|
-
|
|
119
|
+
async def get_completion(
|
|
120
|
+
self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None
|
|
121
|
+
) -> Any:
|
|
122
|
+
"""
|
|
123
|
+
Returns context for the given query (retrieves if not provided).
|
|
124
|
+
|
|
125
|
+
Parameters:
|
|
126
|
+
-----------
|
|
127
|
+
|
|
128
|
+
- query (str): The query string to retrieve context for.
|
|
129
|
+
- context (Optional[Any]): Optional pre-fetched context; if None, it retrieves
|
|
130
|
+
the context for the query. (default None)
|
|
131
|
+
- session_id (Optional[str]): Optional session identifier for caching. If None,
|
|
132
|
+
defaults to 'default_session'. (default None)
|
|
133
|
+
|
|
134
|
+
Returns:
|
|
135
|
+
--------
|
|
136
|
+
|
|
137
|
+
- Any: The context, either provided or retrieved.
|
|
138
|
+
"""
|
|
121
139
|
if context is None:
|
|
122
140
|
context = await self.get_context(query)
|
|
123
141
|
return context
|
|
@@ -122,10 +122,17 @@ class NaturalLanguageRetriever(BaseRetriever):
|
|
|
122
122
|
query.
|
|
123
123
|
"""
|
|
124
124
|
graph_engine = await get_graph_engine()
|
|
125
|
+
is_empty = await graph_engine.is_empty()
|
|
126
|
+
|
|
127
|
+
if is_empty:
|
|
128
|
+
logger.warning("Search attempt on an empty knowledge graph")
|
|
129
|
+
return []
|
|
125
130
|
|
|
126
131
|
return await self._execute_cypher_query(query, graph_engine)
|
|
127
132
|
|
|
128
|
-
async def get_completion(
|
|
133
|
+
async def get_completion(
|
|
134
|
+
self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None
|
|
135
|
+
) -> Any:
|
|
129
136
|
"""
|
|
130
137
|
Returns a completion based on the query and context.
|
|
131
138
|
|
|
@@ -139,6 +146,8 @@ class NaturalLanguageRetriever(BaseRetriever):
|
|
|
139
146
|
- query (str): The natural language query to get a completion from.
|
|
140
147
|
- context (Optional[Any]): The context in which to base the completion; if not
|
|
141
148
|
provided, it will be retrieved using the query. (default None)
|
|
149
|
+
- session_id (Optional[str]): Optional session identifier for caching. If None,
|
|
150
|
+
defaults to 'default_session'. (default None)
|
|
142
151
|
|
|
143
152
|
Returns:
|
|
144
153
|
--------
|
|
@@ -62,7 +62,9 @@ class SummariesRetriever(BaseRetriever):
|
|
|
62
62
|
logger.info(f"Returning {len(summary_payloads)} summary payloads")
|
|
63
63
|
return summary_payloads
|
|
64
64
|
|
|
65
|
-
async def get_completion(
|
|
65
|
+
async def get_completion(
|
|
66
|
+
self, query: str, context: Optional[Any] = None, session_id: Optional[str] = None, **kwargs
|
|
67
|
+
) -> Any:
|
|
66
68
|
"""
|
|
67
69
|
Generates a completion using summaries context.
|
|
68
70
|
|
|
@@ -75,6 +77,8 @@ class SummariesRetriever(BaseRetriever):
|
|
|
75
77
|
- query (str): The search query for generating the completion.
|
|
76
78
|
- context (Optional[Any]): Optional context for the completion; if not provided,
|
|
77
79
|
will be retrieved based on the query. (default None)
|
|
80
|
+
- session_id (Optional[str]): Optional session identifier for caching. If None,
|
|
81
|
+
defaults to 'default_session'. (default None)
|
|
78
82
|
|
|
79
83
|
Returns:
|
|
80
84
|
--------
|
|
@@ -1,16 +1,22 @@
|
|
|
1
1
|
import os
|
|
2
|
+
import asyncio
|
|
2
3
|
from typing import Any, Optional, List, Type
|
|
3
4
|
|
|
4
5
|
|
|
5
6
|
from operator import itemgetter
|
|
6
7
|
from cognee.infrastructure.databases.vector import get_vector_engine
|
|
7
|
-
from cognee.modules.retrieval.utils.completion import generate_completion
|
|
8
|
+
from cognee.modules.retrieval.utils.completion import generate_completion, summarize_text
|
|
9
|
+
from cognee.modules.retrieval.utils.session_cache import (
|
|
10
|
+
save_conversation_history,
|
|
11
|
+
get_conversation_history,
|
|
12
|
+
)
|
|
8
13
|
from cognee.infrastructure.databases.graph import get_graph_engine
|
|
9
14
|
from cognee.infrastructure.llm.prompts import render_prompt
|
|
10
15
|
from cognee.infrastructure.llm import LLMGateway
|
|
11
16
|
from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
|
|
12
17
|
from cognee.shared.logging_utils import get_logger
|
|
13
|
-
|
|
18
|
+
from cognee.context_global_variables import session_user
|
|
19
|
+
from cognee.infrastructure.databases.cache.config import CacheConfig
|
|
14
20
|
|
|
15
21
|
from cognee.tasks.temporal_graph.models import QueryInterval
|
|
16
22
|
|
|
@@ -137,17 +143,63 @@ class TemporalRetriever(GraphCompletionRetriever):
|
|
|
137
143
|
|
|
138
144
|
return self.descriptions_to_string(top_k_events)
|
|
139
145
|
|
|
140
|
-
async def get_completion(
|
|
141
|
-
|
|
146
|
+
async def get_completion(
|
|
147
|
+
self, query: str, context: Optional[str] = None, session_id: Optional[str] = None
|
|
148
|
+
) -> List[str]:
|
|
149
|
+
"""
|
|
150
|
+
Generates a response using the query and optional context.
|
|
151
|
+
|
|
152
|
+
Parameters:
|
|
153
|
+
-----------
|
|
154
|
+
|
|
155
|
+
- query (str): The query string for which a completion is generated.
|
|
156
|
+
- context (Optional[str]): Optional context to use; if None, it will be
|
|
157
|
+
retrieved based on the query. (default None)
|
|
158
|
+
- session_id (Optional[str]): Optional session identifier for caching. If None,
|
|
159
|
+
defaults to 'default_session'. (default None)
|
|
160
|
+
|
|
161
|
+
Returns:
|
|
162
|
+
--------
|
|
163
|
+
|
|
164
|
+
- List[str]: A list containing the generated completion.
|
|
165
|
+
"""
|
|
142
166
|
if not context:
|
|
143
167
|
context = await self.get_context(query=query)
|
|
144
168
|
|
|
145
169
|
if context:
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
170
|
+
# Check if we need to generate context summary for caching
|
|
171
|
+
cache_config = CacheConfig()
|
|
172
|
+
user = session_user.get()
|
|
173
|
+
user_id = getattr(user, "id", None)
|
|
174
|
+
session_save = user_id and cache_config.caching
|
|
175
|
+
|
|
176
|
+
if session_save:
|
|
177
|
+
conversation_history = await get_conversation_history(session_id=session_id)
|
|
178
|
+
|
|
179
|
+
context_summary, completion = await asyncio.gather(
|
|
180
|
+
summarize_text(context),
|
|
181
|
+
generate_completion(
|
|
182
|
+
query=query,
|
|
183
|
+
context=context,
|
|
184
|
+
user_prompt_path=self.user_prompt_path,
|
|
185
|
+
system_prompt_path=self.system_prompt_path,
|
|
186
|
+
conversation_history=conversation_history,
|
|
187
|
+
),
|
|
188
|
+
)
|
|
189
|
+
else:
|
|
190
|
+
completion = await generate_completion(
|
|
191
|
+
query=query,
|
|
192
|
+
context=context,
|
|
193
|
+
user_prompt_path=self.user_prompt_path,
|
|
194
|
+
system_prompt_path=self.system_prompt_path,
|
|
195
|
+
)
|
|
196
|
+
|
|
197
|
+
if session_save:
|
|
198
|
+
await save_conversation_history(
|
|
199
|
+
query=query,
|
|
200
|
+
context_summary=context_summary,
|
|
201
|
+
answer=completion,
|
|
202
|
+
session_id=session_id,
|
|
203
|
+
)
|
|
152
204
|
|
|
153
205
|
return [completion]
|
|
@@ -8,7 +8,7 @@ from cognee.shared.logging_utils import get_logger
|
|
|
8
8
|
from cognee.modules.retrieval.base_feedback import BaseFeedback
|
|
9
9
|
from cognee.modules.retrieval.utils.models import CogneeUserFeedback
|
|
10
10
|
from cognee.modules.retrieval.utils.models import UserFeedbackEvaluation
|
|
11
|
-
from cognee.tasks.storage import add_data_points
|
|
11
|
+
from cognee.tasks.storage import add_data_points, index_graph_edges
|
|
12
12
|
|
|
13
13
|
logger = get_logger("CompletionRetriever")
|
|
14
14
|
|
|
@@ -47,7 +47,7 @@ class UserQAFeedback(BaseFeedback):
|
|
|
47
47
|
belongs_to_set=feedbacks_node_set,
|
|
48
48
|
)
|
|
49
49
|
|
|
50
|
-
await add_data_points(data_points=[cognee_user_feedback]
|
|
50
|
+
await add_data_points(data_points=[cognee_user_feedback])
|
|
51
51
|
|
|
52
52
|
relationships = []
|
|
53
53
|
relationship_name = "gives_feedback_to"
|
|
@@ -76,6 +76,7 @@ class UserQAFeedback(BaseFeedback):
|
|
|
76
76
|
if len(relationships) > 0:
|
|
77
77
|
graph_engine = await get_graph_engine()
|
|
78
78
|
await graph_engine.add_edges(relationships)
|
|
79
|
+
await index_graph_edges(relationships)
|
|
79
80
|
await graph_engine.apply_feedback_weight(
|
|
80
81
|
node_ids=to_node_ids, weight=feedback_sentiment.score
|
|
81
82
|
)
|
|
@@ -9,12 +9,17 @@ async def generate_completion(
|
|
|
9
9
|
user_prompt_path: str,
|
|
10
10
|
system_prompt_path: str,
|
|
11
11
|
system_prompt: Optional[str] = None,
|
|
12
|
+
conversation_history: Optional[str] = None,
|
|
12
13
|
) -> str:
|
|
13
14
|
"""Generates a completion using LLM with given context and prompts."""
|
|
14
15
|
args = {"question": query, "context": context}
|
|
15
16
|
user_prompt = render_prompt(user_prompt_path, args)
|
|
16
17
|
system_prompt = system_prompt if system_prompt else read_query_prompt(system_prompt_path)
|
|
17
18
|
|
|
19
|
+
if conversation_history:
|
|
20
|
+
#:TODO: I would separate the history and put it into the system prompt but we have to test what works best with longer convos
|
|
21
|
+
system_prompt = conversation_history + "\nTASK:" + system_prompt
|
|
22
|
+
|
|
18
23
|
return await LLMGateway.acreate_structured_output(
|
|
19
24
|
text_input=user_prompt,
|
|
20
25
|
system_prompt=system_prompt,
|
|
@@ -62,7 +62,7 @@ async def code_description_to_code_part(
|
|
|
62
62
|
|
|
63
63
|
try:
|
|
64
64
|
if include_docs:
|
|
65
|
-
search_results = await search(query_text=query, query_type="
|
|
65
|
+
search_results = await search(query_text=query, query_type="GRAPH_COMPLETION")
|
|
66
66
|
|
|
67
67
|
concatenated_descriptions = " ".join(
|
|
68
68
|
obj["description"]
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
from typing import Optional, List, Dict, Any
|
|
2
|
+
from cognee.context_global_variables import session_user
|
|
3
|
+
from cognee.infrastructure.databases.cache.config import CacheConfig
|
|
4
|
+
from cognee.infrastructure.databases.exceptions import CacheConnectionError
|
|
5
|
+
from cognee.shared.logging_utils import get_logger
|
|
6
|
+
|
|
7
|
+
logger = get_logger("session_cache")
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def save_conversation_history(
|
|
11
|
+
query: str,
|
|
12
|
+
context_summary: str,
|
|
13
|
+
answer: str,
|
|
14
|
+
session_id: Optional[str] = None,
|
|
15
|
+
) -> bool:
|
|
16
|
+
"""
|
|
17
|
+
Saves Q&A interaction to the session cache if user is authenticated and caching is enabled.
|
|
18
|
+
|
|
19
|
+
Handles cache unavailability gracefully by logging warnings instead of failing.
|
|
20
|
+
|
|
21
|
+
Parameters:
|
|
22
|
+
-----------
|
|
23
|
+
|
|
24
|
+
- query (str): The user's query/question.
|
|
25
|
+
- context_summary (str): Summarized context used for generating the answer.
|
|
26
|
+
- answer (str): The generated answer/completion.
|
|
27
|
+
- session_id (Optional[str]): Session identifier. Defaults to 'default_session' if None.
|
|
28
|
+
|
|
29
|
+
Returns:
|
|
30
|
+
--------
|
|
31
|
+
|
|
32
|
+
- bool: True if successfully saved to cache, False otherwise.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
cache_config = CacheConfig()
|
|
36
|
+
user = session_user.get()
|
|
37
|
+
user_id = getattr(user, "id", None)
|
|
38
|
+
|
|
39
|
+
if not (user_id and cache_config.caching):
|
|
40
|
+
logger.debug("Session caching disabled or user not authenticated")
|
|
41
|
+
return False
|
|
42
|
+
|
|
43
|
+
if session_id is None:
|
|
44
|
+
session_id = "default_session"
|
|
45
|
+
|
|
46
|
+
from cognee.infrastructure.databases.cache.get_cache_engine import get_cache_engine
|
|
47
|
+
|
|
48
|
+
cache_engine = get_cache_engine()
|
|
49
|
+
|
|
50
|
+
if cache_engine is None:
|
|
51
|
+
logger.warning("Cache engine not available, skipping session save")
|
|
52
|
+
return False
|
|
53
|
+
|
|
54
|
+
await cache_engine.add_qa(
|
|
55
|
+
str(user_id),
|
|
56
|
+
session_id=session_id,
|
|
57
|
+
question=query,
|
|
58
|
+
context=context_summary,
|
|
59
|
+
answer=answer,
|
|
60
|
+
)
|
|
61
|
+
|
|
62
|
+
logger.info(
|
|
63
|
+
f"Successfully saved Q&A to session cache: user_id={user_id}, session_id={session_id}"
|
|
64
|
+
)
|
|
65
|
+
return True
|
|
66
|
+
|
|
67
|
+
except CacheConnectionError as e:
|
|
68
|
+
logger.warning(f"Cache unavailable, continuing without session save: {e.message}")
|
|
69
|
+
return False
|
|
70
|
+
|
|
71
|
+
except Exception as e:
|
|
72
|
+
logger.error(
|
|
73
|
+
f"Unexpected error saving to session cache: {type(e).__name__}: {str(e)}. Continuing without caching."
|
|
74
|
+
)
|
|
75
|
+
return False
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
async def get_conversation_history(
|
|
79
|
+
session_id: Optional[str] = None,
|
|
80
|
+
) -> str:
|
|
81
|
+
"""
|
|
82
|
+
Retrieves conversation history from cache and formats it as text.
|
|
83
|
+
|
|
84
|
+
Returns formatted conversation history with time, question, context, and answer
|
|
85
|
+
for the last N Q&A pairs (N is determined by cache engine default).
|
|
86
|
+
|
|
87
|
+
Parameters:
|
|
88
|
+
-----------
|
|
89
|
+
|
|
90
|
+
- session_id (Optional[str]): Session identifier. Defaults to 'default_session' if None.
|
|
91
|
+
|
|
92
|
+
Returns:
|
|
93
|
+
--------
|
|
94
|
+
|
|
95
|
+
- str: Formatted conversation history string, or empty string if no history or error.
|
|
96
|
+
|
|
97
|
+
Format:
|
|
98
|
+
-------
|
|
99
|
+
|
|
100
|
+
Previous conversation:
|
|
101
|
+
|
|
102
|
+
[2024-01-15 10:30:45]
|
|
103
|
+
QUESTION: What is X?
|
|
104
|
+
CONTEXT: X is a concept...
|
|
105
|
+
ANSWER: X is...
|
|
106
|
+
|
|
107
|
+
[2024-01-15 10:31:20]
|
|
108
|
+
QUESTION: How does Y work?
|
|
109
|
+
CONTEXT: Y is related to...
|
|
110
|
+
ANSWER: Y works by...
|
|
111
|
+
"""
|
|
112
|
+
try:
|
|
113
|
+
cache_config = CacheConfig()
|
|
114
|
+
user = session_user.get()
|
|
115
|
+
user_id = getattr(user, "id", None)
|
|
116
|
+
|
|
117
|
+
if not (user_id and cache_config.caching):
|
|
118
|
+
logger.debug("Session caching disabled or user not authenticated")
|
|
119
|
+
return ""
|
|
120
|
+
|
|
121
|
+
if session_id is None:
|
|
122
|
+
session_id = "default_session"
|
|
123
|
+
|
|
124
|
+
from cognee.infrastructure.databases.cache.get_cache_engine import get_cache_engine
|
|
125
|
+
|
|
126
|
+
cache_engine = get_cache_engine()
|
|
127
|
+
|
|
128
|
+
if cache_engine is None:
|
|
129
|
+
logger.warning("Cache engine not available, skipping conversation history retrieval")
|
|
130
|
+
return ""
|
|
131
|
+
|
|
132
|
+
history_entries = await cache_engine.get_latest_qa(str(user_id), session_id)
|
|
133
|
+
|
|
134
|
+
if not history_entries:
|
|
135
|
+
logger.debug("No conversation history found")
|
|
136
|
+
return ""
|
|
137
|
+
|
|
138
|
+
history_text = "Previous conversation:\n\n"
|
|
139
|
+
for entry in history_entries:
|
|
140
|
+
history_text += f"[{entry.get('time', 'Unknown time')}]\n"
|
|
141
|
+
history_text += f"QUESTION: {entry.get('question', '')}\n"
|
|
142
|
+
history_text += f"CONTEXT: {entry.get('context', '')}\n"
|
|
143
|
+
history_text += f"ANSWER: {entry.get('answer', '')}\n\n"
|
|
144
|
+
|
|
145
|
+
logger.debug(f"Retrieved {len(history_entries)} conversation history entries")
|
|
146
|
+
return history_text
|
|
147
|
+
|
|
148
|
+
except CacheConnectionError as e:
|
|
149
|
+
logger.warning(f"Cache unavailable, continuing without conversation history: {e.message}")
|
|
150
|
+
return ""
|
|
151
|
+
|
|
152
|
+
except Exception as e:
|
|
153
|
+
logger.warning(
|
|
154
|
+
f"Unexpected error retrieving conversation history: {type(e).__name__}: {str(e)}"
|
|
155
|
+
)
|
|
156
|
+
return ""
|
|
@@ -9,7 +9,6 @@ from cognee.modules.search.exceptions import UnsupportedSearchTypeError
|
|
|
9
9
|
# Retrievers
|
|
10
10
|
from cognee.modules.retrieval.user_qa_feedback import UserQAFeedback
|
|
11
11
|
from cognee.modules.retrieval.chunks_retriever import ChunksRetriever
|
|
12
|
-
from cognee.modules.retrieval.insights_retriever import InsightsRetriever
|
|
13
12
|
from cognee.modules.retrieval.summaries_retriever import SummariesRetriever
|
|
14
13
|
from cognee.modules.retrieval.completion_retriever import CompletionRetriever
|
|
15
14
|
from cognee.modules.retrieval.graph_completion_retriever import GraphCompletionRetriever
|
|
@@ -44,10 +43,6 @@ async def get_search_type_tools(
|
|
|
44
43
|
SummariesRetriever(top_k=top_k).get_completion,
|
|
45
44
|
SummariesRetriever(top_k=top_k).get_context,
|
|
46
45
|
],
|
|
47
|
-
SearchType.INSIGHTS: [
|
|
48
|
-
InsightsRetriever(top_k=top_k).get_completion,
|
|
49
|
-
InsightsRetriever(top_k=top_k).get_context,
|
|
50
|
-
],
|
|
51
46
|
SearchType.CHUNKS: [
|
|
52
47
|
ChunksRetriever(top_k=top_k).get_completion,
|
|
53
48
|
ChunksRetriever(top_k=top_k).get_context,
|
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
from typing import Any, List, Optional, Tuple, Type, Union
|
|
2
2
|
|
|
3
|
+
from cognee.infrastructure.databases.graph import get_graph_engine
|
|
3
4
|
from cognee.modules.data.models.Dataset import Dataset
|
|
4
5
|
from cognee.modules.engine.models.node_set import NodeSet
|
|
5
6
|
from cognee.modules.graph.cognee_graph.CogneeGraphElements import Edge
|
|
6
7
|
from cognee.modules.search.types import SearchType
|
|
8
|
+
from cognee.shared.logging_utils import get_logger
|
|
7
9
|
|
|
8
10
|
from .get_search_type_tools import get_search_type_tools
|
|
9
11
|
|
|
12
|
+
logger = get_logger()
|
|
13
|
+
|
|
10
14
|
|
|
11
15
|
async def no_access_control_search(
|
|
12
16
|
query_type: SearchType,
|
|
@@ -19,6 +23,7 @@ async def no_access_control_search(
|
|
|
19
23
|
save_interaction: bool = False,
|
|
20
24
|
last_k: Optional[int] = None,
|
|
21
25
|
only_context: bool = False,
|
|
26
|
+
session_id: Optional[str] = None,
|
|
22
27
|
) -> Tuple[Any, Union[str, List[Edge]], List[Dataset]]:
|
|
23
28
|
search_tools = await get_search_type_tools(
|
|
24
29
|
query_type=query_type,
|
|
@@ -31,6 +36,12 @@ async def no_access_control_search(
|
|
|
31
36
|
save_interaction=save_interaction,
|
|
32
37
|
last_k=last_k,
|
|
33
38
|
)
|
|
39
|
+
graph_engine = await get_graph_engine()
|
|
40
|
+
is_empty = await graph_engine.is_empty()
|
|
41
|
+
|
|
42
|
+
if is_empty:
|
|
43
|
+
# TODO: we can log here, but not all search types use graph. Still keeping this here for reviewer input
|
|
44
|
+
logger.warning("Search attempt on an empty knowledge graph")
|
|
34
45
|
if len(search_tools) == 2:
|
|
35
46
|
[get_completion, get_context] = search_tools
|
|
36
47
|
|
|
@@ -38,7 +49,7 @@ async def no_access_control_search(
|
|
|
38
49
|
return None, await get_context(query_text), []
|
|
39
50
|
|
|
40
51
|
context = await get_context(query_text)
|
|
41
|
-
result = await get_completion(query_text, context)
|
|
52
|
+
result = await get_completion(query_text, context, session_id=session_id)
|
|
42
53
|
else:
|
|
43
54
|
unknown_tool = search_tools[0]
|
|
44
55
|
result = await unknown_tool(query_text)
|