llama-index
157 строк · 4.6 Кб
1import math2from typing import Any, List3
4from llama_index.legacy.schema import BaseNode, MetadataMode, TextNode5from llama_index.legacy.vector_stores.types import (6MetadataFilters,7VectorStore,8VectorStoreQuery,9VectorStoreQueryResult,10)
11from llama_index.legacy.vector_stores.utils import (12legacy_metadata_dict_to_node,13metadata_dict_to_node,14node_to_metadata_dict,15)
16
17
18def _to_metal_filters(standard_filters: MetadataFilters) -> list:19filters = []20for filter in standard_filters.legacy_filters():21filters.append(22{23"field": filter.key,24"value": filter.value,25}26)27return filters28
29
30class MetalVectorStore(VectorStore):31def __init__(32self,33api_key: str,34client_id: str,35index_id: str,36):37"""Init params."""38import_err_msg = (39"`metal_sdk` package not found, please run `pip install metal_sdk`"40)41try:42import metal_sdk # noqa43except ImportError:44raise ImportError(import_err_msg)45from metal_sdk.metal import Metal46
47self.api_key = api_key48self.client_id = client_id49self.index_id = index_id50
51self.metal_client = Metal(api_key, client_id, index_id)52self.stores_text = True53self.flat_metadata = False54self.is_embedding_query = True55
56def query(self, query: VectorStoreQuery, **kwargs: Any) -> VectorStoreQueryResult:57if query.filters is not None:58if "filters" in kwargs:59raise ValueError(60"Cannot specify filter via both query and kwargs. "61"Use kwargs only for metal specific items that are "62"not supported via the generic query interface."63)64filters = _to_metal_filters(query.filters)65else:66filters = kwargs.get("filters", {})67
68payload = {69"embedding": query.query_embedding, # Query Embedding70"filters": filters, # Metadata Filters71}72response = self.metal_client.search(payload, limit=query.similarity_top_k)73
74nodes = []75ids = []76similarities = []77
78for item in response["data"]:79text = item["text"]80id_ = item["id"]81
82# load additional Node data83try:84node = metadata_dict_to_node(item["metadata"])85node.text = text86except Exception:87# NOTE: deprecated legacy logic for backward compatibility88metadata, node_info, relationships = legacy_metadata_dict_to_node(89item["metadata"]90)91
92node = TextNode(93text=text,94id_=id_,95metadata=metadata,96start_char_idx=node_info.get("start", None),97end_char_idx=node_info.get("end", None),98relationships=relationships,99)100
101nodes.append(node)102ids.append(id_)103
104similarity_score = 1.0 - math.exp(-item["dist"])105similarities.append(similarity_score)106
107return VectorStoreQueryResult(nodes=nodes, similarities=similarities, ids=ids)108
109@property110def client(self) -> Any:111"""Return Metal client."""112return self.metal_client113
114def add(self, nodes: List[BaseNode], **add_kwargs: Any) -> List[str]:115"""Add nodes to index.116
117Args:
118nodes: List[BaseNode]: list of nodes with embeddings.
119
120"""
121if not self.metal_client:122raise ValueError("metal_client not initialized")123
124ids = []125for node in nodes:126ids.append(node.node_id)127
128metadata = {}129metadata["text"] = node.get_content(metadata_mode=MetadataMode.NONE) or ""130
131additional_metadata = node_to_metadata_dict(132node, remove_text=True, flat_metadata=self.flat_metadata133)134metadata.update(additional_metadata)135
136payload = {137"embedding": node.get_embedding(),138"metadata": metadata,139"id": node.node_id,140}141
142self.metal_client.index(payload)143
144return ids145
146def delete(self, ref_doc_id: str, **delete_kwargs: Any) -> None:147"""148Delete nodes using with ref_doc_id.
149
150Args:
151ref_doc_id (str): The doc_id of the document to delete.
152
153"""
154if not self.metal_client:155raise ValueError("metal_client not initialized")156
157self.metal_client.deleteOne(ref_doc_id)158