topoteretes--cognee
c889a57b6b
Test Suites / Build CI Environment (push) Has been cancelled
Test Suites / Basic Tests (push) Has been cancelled
Test Suites / End-to-End Tests (push) Has been cancelled
Test Suites / CLI Tests (push) Has been cancelled
Test Suites / Slow End-to-End Tests (push) Has been cancelled
Test Suites / Graph Database Tests (push) Has been cancelled
Test Suites / Vector DB Tests (push) Has been cancelled
Test Suites / Temporal Graph Test (push) Has been cancelled
Test Suites / Search Test on Different DBs (push) Has been cancelled
Test Suites / Example Tests (push) Has been cancelled
Test Suites / Notebook Tests (push) Has been cancelled
Test Suites / OS and Python Tests Ubuntu (push) Has been cancelled
Test Suites / OS and Python Tests Extended (push) Has been cancelled
Test Suites / LLM Test Suite (push) Has been cancelled
Test Suites / S3 File Storage Test (push) Has been cancelled
Test Suites / Run Integration Tests (push) Has been cancelled
Test Suites / MCP Tests (push) Has been cancelled
Test Suites / Docker Compose Test (push) Has been cancelled
Test Suites / Docker CI test (push) Has been cancelled
Test Suites / Relational DB Migration Tests (push) Has been cancelled
Test Suites / Distributed Cognee Test (push) Has been cancelled
Test Suites / DB Examples Tests (push) Has been cancelled
Test Suites / Test Completion Status (push) Has been cancelled
Test Suites / Claude Code Review (push) Has been cancelled
Test Suites / basic checks (push) Has been cancelled
build | Build and Push Cognee MCP Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Scorecard supply-chain security / Scorecard analysis (push) Has been cancelled
build | Build and Push Docker Image to dockerhub / docker-build-and-push (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.11) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Core Functionality (3.12) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (kuzu, kuzu) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges with Different Graph Databases (neo4j, neo4j) (push) Has been cancelled
Weighted Edges Tests / Test Weighted Edges Examples (push) Has been cancelled
Weighted Edges Tests / Code Quality for Weighted Edges (push) Has been cancelled
157 行
5.7 KiB
Python
157 行
5.7 KiB
Python
"""Adapter from retriever payloads to the normalized SearchResponse.
|
|
|
|
Retrievers produce heterogeneous payloads (strings, chunk dicts, graph
|
|
rows, edge lists). This module flattens them into a uniform list of
|
|
``SearchResultItem`` so every call to ``cognee.search`` returns the
|
|
same wire shape regardless of search type.
|
|
"""
|
|
|
|
import json
|
|
from typing import Any, Optional
|
|
|
|
from pydantic import BaseModel
|
|
|
|
from cognee.modules.recall.types.SearchResultItem import (
|
|
SearchResultItem,
|
|
SearchResultKind,
|
|
)
|
|
from cognee.modules.search.models.SearchResultPayload import SearchResultPayload
|
|
from cognee.modules.search.types import SearchType
|
|
|
|
_KIND_BY_SEARCH_TYPE: dict[SearchType, SearchResultKind] = {
|
|
SearchType.GRAPH_COMPLETION: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.GRAPH_COMPLETION_COT: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.GRAPH_COMPLETION_DECOMPOSITION: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.GRAPH_COMPLETION_CONTEXT_EXTENSION: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.GRAPH_SUMMARY_COMPLETION: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.HYBRID_COMPLETION: SearchResultKind.GRAPH_COMPLETION,
|
|
SearchType.RAG_COMPLETION: SearchResultKind.RAG_COMPLETION,
|
|
SearchType.TRIPLET_COMPLETION: SearchResultKind.TRIPLET_COMPLETION,
|
|
SearchType.CYPHER: SearchResultKind.CYPHER,
|
|
SearchType.NATURAL_LANGUAGE: SearchResultKind.NATURAL_LANGUAGE,
|
|
SearchType.TEMPORAL: SearchResultKind.TEMPORAL,
|
|
SearchType.CODING_RULES: SearchResultKind.CODING_RULE,
|
|
SearchType.CHUNKS: SearchResultKind.CHUNK,
|
|
SearchType.CHUNKS_LEXICAL: SearchResultKind.CHUNK,
|
|
SearchType.SUMMARIES: SearchResultKind.SUMMARY,
|
|
}
|
|
|
|
|
|
def _coerce_to_dict(value: Any) -> dict:
|
|
"""Best-effort coerce any object to a dict for the ``raw`` field."""
|
|
if isinstance(value, dict):
|
|
return value
|
|
if isinstance(value, BaseModel):
|
|
return value.model_dump(mode="json")
|
|
if hasattr(value, "__dict__"):
|
|
try:
|
|
return {k: v for k, v in vars(value).items() if not k.startswith("_")}
|
|
except TypeError:
|
|
pass
|
|
return {
|
|
"value": value if isinstance(value, (int, float, bool, str, type(None))) else str(value)
|
|
}
|
|
|
|
|
|
def _text_from_dict(payload: dict) -> str:
|
|
"""Pick the most human-readable text field from a dict payload."""
|
|
for key in ("text", "completion", "summary", "name", "content", "answer"):
|
|
value = payload.get(key)
|
|
if isinstance(value, str) and value:
|
|
return value
|
|
try:
|
|
return json.dumps(payload, default=str, ensure_ascii=False)
|
|
except (TypeError, ValueError):
|
|
return str(payload)
|
|
|
|
|
|
def _score_from(value: Any) -> Optional[float]:
|
|
if isinstance(value, dict):
|
|
score = value.get("score")
|
|
if isinstance(score, (int, float)):
|
|
return float(score)
|
|
return None
|
|
|
|
|
|
def _provenance_metadata(raw: dict) -> dict:
|
|
"""Surface stable source identifiers from a chunk/summary payload.
|
|
|
|
Lets callers map a result back to the data they ingested and inspect the
|
|
cited chunk. ``document_id`` is the ingested Data item's id (cognify sets
|
|
``Document.id = data.id``), exposed here as ``data_id``; ``id`` is the
|
|
chunk's own node id. Only keys actually present are included.
|
|
"""
|
|
metadata: dict[str, Any] = {}
|
|
data_id = raw.get("document_id")
|
|
if data_id is not None:
|
|
metadata["data_id"] = str(data_id)
|
|
chunk_id = raw.get("id")
|
|
if chunk_id is not None:
|
|
metadata["chunk_id"] = str(chunk_id)
|
|
chunk_index = raw.get("chunk_index")
|
|
if isinstance(chunk_index, int) and not isinstance(chunk_index, bool):
|
|
metadata["chunk_index"] = chunk_index
|
|
document_name = raw.get("document_name")
|
|
if document_name is not None:
|
|
metadata["document_name"] = str(document_name)
|
|
return metadata
|
|
|
|
|
|
def _build_item(
|
|
entry: Any,
|
|
payload: SearchResultPayload,
|
|
kind: SearchResultKind,
|
|
) -> SearchResultItem:
|
|
"""Build a single SearchResultItem from one retriever output element."""
|
|
if isinstance(entry, str):
|
|
text = entry
|
|
raw: dict = {"value": entry}
|
|
elif isinstance(entry, BaseModel):
|
|
raw = entry.model_dump(mode="json")
|
|
text = _text_from_dict(raw)
|
|
elif isinstance(entry, dict):
|
|
raw = entry
|
|
text = _text_from_dict(entry)
|
|
elif isinstance(entry, (list, tuple)):
|
|
raw = {"value": [_coerce_to_dict(item) for item in entry]}
|
|
text = json.dumps(raw["value"], default=str, ensure_ascii=False)
|
|
else:
|
|
raw = _coerce_to_dict(entry)
|
|
text = _text_from_dict(raw) if raw else str(entry)
|
|
|
|
return SearchResultItem(
|
|
kind=kind,
|
|
search_type=payload.search_type,
|
|
text=text,
|
|
score=_score_from(entry),
|
|
dataset_id=str(payload.dataset_id) if payload.dataset_id else None,
|
|
dataset_name=payload.dataset_name,
|
|
metadata=_provenance_metadata(raw),
|
|
raw=raw,
|
|
)
|
|
|
|
|
|
def _flatten(value: Any) -> list[Any]:
|
|
"""Return a flat list of entries from completion/context/result_object."""
|
|
if value is None:
|
|
return []
|
|
if isinstance(value, list):
|
|
return value
|
|
return [value]
|
|
|
|
|
|
def normalize_search_payload(payload: SearchResultPayload) -> list[SearchResultItem]:
|
|
"""Normalize one dataset's retriever payload into SearchResultItems."""
|
|
kind = _KIND_BY_SEARCH_TYPE.get(payload.search_type, SearchResultKind.UNKNOWN)
|
|
|
|
if payload.only_context:
|
|
entries = _flatten(payload.context)
|
|
elif payload.completion is not None:
|
|
entries = _flatten(payload.completion)
|
|
elif payload.context is not None:
|
|
entries = _flatten(payload.context)
|
|
else:
|
|
entries = _flatten(payload.result_object)
|
|
|
|
return [_build_item(entry, payload, kind) for entry in entries]
|