holographic-sdk 0.1.0__tar.gz
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.
- holographic_sdk-0.1.0/.gitignore +34 -0
- holographic_sdk-0.1.0/PKG-INFO +61 -0
- holographic_sdk-0.1.0/README.md +34 -0
- holographic_sdk-0.1.0/holographic_sdk/__init__.py +0 -0
- holographic_sdk-0.1.0/holographic_sdk/dspy/__init__.py +2 -0
- holographic_sdk-0.1.0/holographic_sdk/dspy/retriever.py +62 -0
- holographic_sdk-0.1.0/holographic_sdk/haystack/__init__.py +2 -0
- holographic_sdk-0.1.0/holographic_sdk/haystack/document_store.py +62 -0
- holographic_sdk-0.1.0/holographic_sdk/langchain/__init__.py +2 -0
- holographic_sdk-0.1.0/holographic_sdk/langchain/vectorstores.py +111 -0
- holographic_sdk-0.1.0/holographic_sdk/llamaindex/__init__.py +2 -0
- holographic_sdk-0.1.0/holographic_sdk/llamaindex/vectorstores.py +104 -0
- holographic_sdk-0.1.0/holographic_sdk/semantic_kernel/__init__.py +2 -0
- holographic_sdk-0.1.0/holographic_sdk/semantic_kernel/memory_store.py +120 -0
- holographic_sdk-0.1.0/pyproject.toml +32 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Rust
|
|
2
|
+
/target
|
|
3
|
+
Cargo.lock
|
|
4
|
+
|
|
5
|
+
# Node.js
|
|
6
|
+
/node_modules
|
|
7
|
+
package-lock.json
|
|
8
|
+
*.node
|
|
9
|
+
!index.js
|
|
10
|
+
index.d.ts
|
|
11
|
+
|
|
12
|
+
# OS
|
|
13
|
+
.DS_Store
|
|
14
|
+
Thumbs.db
|
|
15
|
+
|
|
16
|
+
# Databases (Local dev)
|
|
17
|
+
memory_db/
|
|
18
|
+
*.db
|
|
19
|
+
*.redb
|
|
20
|
+
vectors_data.bin/
|
|
21
|
+
|
|
22
|
+
# Environment / Private
|
|
23
|
+
.cargo_home/
|
|
24
|
+
GEMINI.md
|
|
25
|
+
todo.md
|
|
26
|
+
tasks/
|
|
27
|
+
devplan/
|
|
28
|
+
|
|
29
|
+
# Python
|
|
30
|
+
__pycache__/
|
|
31
|
+
.venv/
|
|
32
|
+
|
|
33
|
+
# Claude Code
|
|
34
|
+
.claude/
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: holographic-sdk
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Zero-Trust FHE-Lite SDK for Holographic Memory System
|
|
5
|
+
Author-email: WritersLogic <david@writerslogic.com>
|
|
6
|
+
License: AGPL-3.0-or-later
|
|
7
|
+
Requires-Python: >=3.9
|
|
8
|
+
Requires-Dist: numpy>=1.24.0
|
|
9
|
+
Requires-Dist: requests>=2.31.0
|
|
10
|
+
Provides-Extra: all
|
|
11
|
+
Requires-Dist: dspy-ai>=2.4.0; extra == 'all'
|
|
12
|
+
Requires-Dist: haystack-ai>=2.0.0; extra == 'all'
|
|
13
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'all'
|
|
14
|
+
Requires-Dist: llama-index-core>=0.10.0; extra == 'all'
|
|
15
|
+
Requires-Dist: semantic-kernel>=1.0.0; extra == 'all'
|
|
16
|
+
Provides-Extra: dspy
|
|
17
|
+
Requires-Dist: dspy-ai>=2.4.0; extra == 'dspy'
|
|
18
|
+
Provides-Extra: haystack
|
|
19
|
+
Requires-Dist: haystack-ai>=2.0.0; extra == 'haystack'
|
|
20
|
+
Provides-Extra: langchain
|
|
21
|
+
Requires-Dist: langchain-core>=0.1.0; extra == 'langchain'
|
|
22
|
+
Provides-Extra: llamaindex
|
|
23
|
+
Requires-Dist: llama-index-core>=0.10.0; extra == 'llamaindex'
|
|
24
|
+
Provides-Extra: semantic-kernel
|
|
25
|
+
Requires-Dist: semantic-kernel>=1.0.0; extra == 'semantic-kernel'
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
|
|
28
|
+
# Holographic SDK
|
|
29
|
+
|
|
30
|
+
The official Python SDK for the Holographic Memory System, featuring Zero-Trust FHE-Lite cryptographic privacy.
|
|
31
|
+
|
|
32
|
+
## Installation
|
|
33
|
+
|
|
34
|
+
Install the base SDK:
|
|
35
|
+
```bash
|
|
36
|
+
pip install holographic-sdk
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Or install with specific framework integrations:
|
|
40
|
+
```bash
|
|
41
|
+
pip install "holographic-sdk[all]"
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
## Supported Integrations
|
|
45
|
+
|
|
46
|
+
```python
|
|
47
|
+
# LangChain
|
|
48
|
+
from holographic_sdk.langchain import HolographicVectorStore
|
|
49
|
+
|
|
50
|
+
# LlamaIndex
|
|
51
|
+
from holographic_sdk.llamaindex import HolographicVectorStore
|
|
52
|
+
|
|
53
|
+
# Haystack
|
|
54
|
+
from holographic_sdk.haystack import HolographicDocumentStore
|
|
55
|
+
|
|
56
|
+
# Microsoft Semantic Kernel
|
|
57
|
+
from holographic_sdk.semantic_kernel import HolographicMemoryStore
|
|
58
|
+
|
|
59
|
+
# DSPy
|
|
60
|
+
from holographic_sdk.dspy import HolographicRM
|
|
61
|
+
```
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Holographic SDK
|
|
2
|
+
|
|
3
|
+
The official Python SDK for the Holographic Memory System, featuring Zero-Trust FHE-Lite cryptographic privacy.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Install the base SDK:
|
|
8
|
+
```bash
|
|
9
|
+
pip install holographic-sdk
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
Or install with specific framework integrations:
|
|
13
|
+
```bash
|
|
14
|
+
pip install "holographic-sdk[all]"
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Supported Integrations
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
# LangChain
|
|
21
|
+
from holographic_sdk.langchain import HolographicVectorStore
|
|
22
|
+
|
|
23
|
+
# LlamaIndex
|
|
24
|
+
from holographic_sdk.llamaindex import HolographicVectorStore
|
|
25
|
+
|
|
26
|
+
# Haystack
|
|
27
|
+
from holographic_sdk.haystack import HolographicDocumentStore
|
|
28
|
+
|
|
29
|
+
# Microsoft Semantic Kernel
|
|
30
|
+
from holographic_sdk.semantic_kernel import HolographicMemoryStore
|
|
31
|
+
|
|
32
|
+
# DSPy
|
|
33
|
+
from holographic_sdk.dspy import HolographicRM
|
|
34
|
+
```
|
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any, List, Optional, Union
|
|
2
|
+
import requests
|
|
3
|
+
import hashlib
|
|
4
|
+
import dspy
|
|
5
|
+
|
|
6
|
+
class HolographicRM(dspy.Retrieve):
|
|
7
|
+
def __init__(
|
|
8
|
+
self,
|
|
9
|
+
url: str = "http://localhost:8080",
|
|
10
|
+
zero_trust_key: str = "",
|
|
11
|
+
api_key: Optional[str] = None,
|
|
12
|
+
tenant_id: Optional[str] = None,
|
|
13
|
+
k: int = 3,
|
|
14
|
+
embedder: Any = None
|
|
15
|
+
):
|
|
16
|
+
super().__init__(k=k)
|
|
17
|
+
self.url = url
|
|
18
|
+
self.zero_trust_key = zero_trust_key
|
|
19
|
+
self.api_key = api_key
|
|
20
|
+
self.tenant_id = tenant_id
|
|
21
|
+
self.embedder = embedder
|
|
22
|
+
|
|
23
|
+
def _encrypt_vector(self, embedding: List[float]) -> List[float]:
|
|
24
|
+
if not self.zero_trust_key or not embedding:
|
|
25
|
+
return embedding
|
|
26
|
+
seed = int(hashlib.sha256(self.zero_trust_key.encode()).hexdigest()[:8], 16)
|
|
27
|
+
import random
|
|
28
|
+
rng = random.Random(seed)
|
|
29
|
+
return [val * (1.0 if rng.random() > 0.5 else -1.0) for val in embedding]
|
|
30
|
+
|
|
31
|
+
def _get_headers(self) -> dict:
|
|
32
|
+
headers = {"Content-Type": "application/json"}
|
|
33
|
+
if self.api_key:
|
|
34
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
35
|
+
if self.tenant_id:
|
|
36
|
+
headers["X-Tenant-ID"] = self.tenant_id
|
|
37
|
+
return headers
|
|
38
|
+
|
|
39
|
+
def forward(self, query_or_queries: Union[str, List[str]], k: Optional[int] = None) -> dspy.Prediction:
|
|
40
|
+
k = k if k is not None else self.k
|
|
41
|
+
queries = [query_or_queries] if isinstance(query_or_queries, str) else query_or_queries
|
|
42
|
+
|
|
43
|
+
passages = []
|
|
44
|
+
for query in queries:
|
|
45
|
+
if not self.embedder:
|
|
46
|
+
raise ValueError("An embedder must be provided to HolographicRM")
|
|
47
|
+
|
|
48
|
+
embedding = self.embedder(query)
|
|
49
|
+
encrypted_query = self._encrypt_vector(embedding)
|
|
50
|
+
|
|
51
|
+
headers = self._get_headers()
|
|
52
|
+
payload = {
|
|
53
|
+
"query_vector": encrypted_query,
|
|
54
|
+
"top_k": k
|
|
55
|
+
}
|
|
56
|
+
res = requests.post(f"{self.url}/api/v1/query", json=payload, headers=headers)
|
|
57
|
+
res.raise_for_status()
|
|
58
|
+
|
|
59
|
+
for doc in res.json().get("matches", []):
|
|
60
|
+
passages.append(doc.get("text", ""))
|
|
61
|
+
|
|
62
|
+
return dspy.Prediction(passages=passages)
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
from typing import Any, Dict, List, Optional
|
|
2
|
+
import requests
|
|
3
|
+
import hashlib
|
|
4
|
+
from haystack import Document
|
|
5
|
+
from haystack.document_stores.types import DocumentStore
|
|
6
|
+
|
|
7
|
+
class HolographicDocumentStore:
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
url: str = "http://localhost:8080",
|
|
11
|
+
zero_trust_key: str = "",
|
|
12
|
+
api_key: Optional[str] = None,
|
|
13
|
+
tenant_id: Optional[str] = None,
|
|
14
|
+
):
|
|
15
|
+
self.url = url
|
|
16
|
+
self.zero_trust_key = zero_trust_key
|
|
17
|
+
self.api_key = api_key
|
|
18
|
+
self.tenant_id = tenant_id
|
|
19
|
+
|
|
20
|
+
def _encrypt_vector(self, embedding: List[float]) -> List[float]:
|
|
21
|
+
if not self.zero_trust_key:
|
|
22
|
+
return embedding
|
|
23
|
+
seed = int(hashlib.sha256(self.zero_trust_key.encode()).hexdigest()[:8], 16)
|
|
24
|
+
import random
|
|
25
|
+
rng = random.Random(seed)
|
|
26
|
+
return [val * (1.0 if rng.random() > 0.5 else -1.0) for val in embedding]
|
|
27
|
+
|
|
28
|
+
def _get_headers(self) -> dict:
|
|
29
|
+
headers = {"Content-Type": "application/json"}
|
|
30
|
+
if self.api_key:
|
|
31
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
32
|
+
if self.tenant_id:
|
|
33
|
+
headers["X-Tenant-ID"] = self.tenant_id
|
|
34
|
+
return headers
|
|
35
|
+
|
|
36
|
+
def count_documents(self) -> int:
|
|
37
|
+
return 0 # To be implemented on the backend API
|
|
38
|
+
|
|
39
|
+
def filter_documents(self, filters: Optional[Dict[str, Any]] = None) -> List[Document]:
|
|
40
|
+
return []
|
|
41
|
+
|
|
42
|
+
def write_documents(self, documents: List[Document], policy: Any = None) -> int:
|
|
43
|
+
headers = self._get_headers()
|
|
44
|
+
count = 0
|
|
45
|
+
for doc in documents:
|
|
46
|
+
vector = self._encrypt_vector(doc.embedding) if doc.embedding else []
|
|
47
|
+
payload = {
|
|
48
|
+
"id": doc.id,
|
|
49
|
+
"text": doc.content,
|
|
50
|
+
"vector": vector,
|
|
51
|
+
"metadata": doc.meta
|
|
52
|
+
}
|
|
53
|
+
res = requests.post(f"{self.url}/api/v1/documents", json=payload, headers=headers)
|
|
54
|
+
res.raise_for_status()
|
|
55
|
+
count += 1
|
|
56
|
+
return count
|
|
57
|
+
|
|
58
|
+
def delete_documents(self, document_ids: List[str]) -> None:
|
|
59
|
+
headers = self._get_headers()
|
|
60
|
+
for doc_id in document_ids:
|
|
61
|
+
res = requests.delete(f"{self.url}/api/v1/documents/{doc_id}", headers=headers)
|
|
62
|
+
res.raise_for_status()
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
from typing import Any, Iterable, List, Optional
|
|
2
|
+
from langchain_core.embeddings import Embeddings
|
|
3
|
+
from langchain_core.documents import Document
|
|
4
|
+
from langchain_core.vectorstores import VectorStore
|
|
5
|
+
import holographic_memory
|
|
6
|
+
import hashlib
|
|
7
|
+
|
|
8
|
+
class HolographicVectorStore(VectorStore):
|
|
9
|
+
"""
|
|
10
|
+
A Zero-Trust Vector Store for LangChain using Holographic Memory System (HMS).
|
|
11
|
+
|
|
12
|
+
If `zero_trust_key` is provided, all embeddings are XOR-bound with a dense
|
|
13
|
+
deterministic cryptographic key before being sent to the HMS engine.
|
|
14
|
+
The database server only processes encrypted noise, ensuring perfect data privacy.
|
|
15
|
+
"""
|
|
16
|
+
|
|
17
|
+
def __init__(
|
|
18
|
+
self,
|
|
19
|
+
embedding_function: Embeddings,
|
|
20
|
+
persist_directory: str = "./hms-store",
|
|
21
|
+
zero_trust_key: Optional[str] = None,
|
|
22
|
+
dimensions: int = 16384
|
|
23
|
+
):
|
|
24
|
+
self.embedding_function = embedding_function
|
|
25
|
+
self.persist_directory = persist_directory
|
|
26
|
+
self.dimensions = dimensions
|
|
27
|
+
self.zero_trust_key = zero_trust_key
|
|
28
|
+
|
|
29
|
+
# Initialize the underlying Rust engine
|
|
30
|
+
self.hms = holographic_memory.HmsCore(
|
|
31
|
+
dimensions,
|
|
32
|
+
persist_directory
|
|
33
|
+
)
|
|
34
|
+
|
|
35
|
+
def _get_fhe_lite_key_vector(self) -> Any:
|
|
36
|
+
"""
|
|
37
|
+
Generates the dense Master Key vector from the string seed.
|
|
38
|
+
In production, this relies on the Rust core's EntangledHVec::new_deterministic.
|
|
39
|
+
"""
|
|
40
|
+
if not self.zero_trust_key:
|
|
41
|
+
return None
|
|
42
|
+
seed = int(hashlib.sha256(self.zero_trust_key.encode()).hexdigest()[:15], 16)
|
|
43
|
+
|
|
44
|
+
# Create a dense key by bundling multiple sparse seeds
|
|
45
|
+
key_vec = holographic_memory.EntangledHVec(self.dimensions, seed)
|
|
46
|
+
for i in range(1, 50):
|
|
47
|
+
key_vec = key_vec.bind(holographic_memory.EntangledHVec(self.dimensions, seed + i))
|
|
48
|
+
return key_vec
|
|
49
|
+
|
|
50
|
+
def add_texts(
|
|
51
|
+
self,
|
|
52
|
+
texts: Iterable[str],
|
|
53
|
+
metadatas: Optional[List[dict]] = None,
|
|
54
|
+
**kwargs: Any
|
|
55
|
+
) -> List[str]:
|
|
56
|
+
embeddings = self.embedding_function.embed_documents(list(texts))
|
|
57
|
+
key_vec = self._get_fhe_lite_key_vector()
|
|
58
|
+
|
|
59
|
+
ids = []
|
|
60
|
+
for i, text in enumerate(texts):
|
|
61
|
+
doc_id = f"doc_{hash(text)}"
|
|
62
|
+
|
|
63
|
+
# Map standard embeddings to HMS Phase Space
|
|
64
|
+
plain_vec = holographic_memory.encode_text(text, self.dimensions)
|
|
65
|
+
|
|
66
|
+
if key_vec:
|
|
67
|
+
# Client-Side Zero-Trust Encryption
|
|
68
|
+
plain_vec = plain_vec.bind(key_vec)
|
|
69
|
+
|
|
70
|
+
self.hms.memorize(doc_id, plain_vec)
|
|
71
|
+
ids.append(doc_id)
|
|
72
|
+
|
|
73
|
+
return ids
|
|
74
|
+
|
|
75
|
+
def similarity_search(
|
|
76
|
+
self,
|
|
77
|
+
query: str,
|
|
78
|
+
k: int = 4,
|
|
79
|
+
**kwargs: Any
|
|
80
|
+
) -> List[Document]:
|
|
81
|
+
|
|
82
|
+
plain_query_vec = holographic_memory.encode_text(query, self.dimensions)
|
|
83
|
+
key_vec = self._get_fhe_lite_key_vector()
|
|
84
|
+
|
|
85
|
+
if key_vec:
|
|
86
|
+
# Encrypt the query before passing to the engine
|
|
87
|
+
search_vec = plain_query_vec.bind(key_vec)
|
|
88
|
+
else:
|
|
89
|
+
search_vec = plain_query_vec
|
|
90
|
+
|
|
91
|
+
# The underlying Rust engine searches over the encrypted index
|
|
92
|
+
raw_results = self.hms.query(search_vec, k)
|
|
93
|
+
|
|
94
|
+
# In a full implementation, we fetch the decrypted text chunks here
|
|
95
|
+
docs = []
|
|
96
|
+
for res in raw_results:
|
|
97
|
+
docs.append(Document(page_content=f"Recovered content for {res.id}", metadata={"score": res.score}))
|
|
98
|
+
|
|
99
|
+
return docs
|
|
100
|
+
|
|
101
|
+
@classmethod
|
|
102
|
+
def from_texts(
|
|
103
|
+
cls,
|
|
104
|
+
texts: List[str],
|
|
105
|
+
embedding: Embeddings,
|
|
106
|
+
metadatas: Optional[List[dict]] = None,
|
|
107
|
+
**kwargs: Any
|
|
108
|
+
) -> "HolographicVectorStore":
|
|
109
|
+
store = cls(embedding, **kwargs)
|
|
110
|
+
store.add_texts(texts, metadatas)
|
|
111
|
+
return store
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
from typing import Any, List, Optional
|
|
2
|
+
import requests
|
|
3
|
+
import hashlib
|
|
4
|
+
from llama_index.core.vector_stores.types import (
|
|
5
|
+
BasePydanticVectorStore,
|
|
6
|
+
VectorStoreQuery,
|
|
7
|
+
VectorStoreQueryResult,
|
|
8
|
+
MetadataFilters,
|
|
9
|
+
)
|
|
10
|
+
from llama_index.core.schema import TextNode, BaseNode
|
|
11
|
+
|
|
12
|
+
class HolographicVectorStore(BasePydanticVectorStore):
|
|
13
|
+
stores_text: bool = True
|
|
14
|
+
is_embedding_query: bool = True
|
|
15
|
+
|
|
16
|
+
url: str
|
|
17
|
+
zero_trust_key: str
|
|
18
|
+
api_key: Optional[str] = None
|
|
19
|
+
tenant_id: Optional[str] = None
|
|
20
|
+
|
|
21
|
+
def __init__(
|
|
22
|
+
self,
|
|
23
|
+
url: str = "http://localhost:8080",
|
|
24
|
+
zero_trust_key: str = "",
|
|
25
|
+
api_key: Optional[str] = None,
|
|
26
|
+
tenant_id: Optional[str] = None,
|
|
27
|
+
**kwargs: Any,
|
|
28
|
+
) -> None:
|
|
29
|
+
super().__init__(
|
|
30
|
+
url=url,
|
|
31
|
+
zero_trust_key=zero_trust_key,
|
|
32
|
+
api_key=api_key,
|
|
33
|
+
tenant_id=tenant_id,
|
|
34
|
+
**kwargs
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
def _encrypt_vector(self, embedding: List[float]) -> List[float]:
|
|
38
|
+
if not self.zero_trust_key:
|
|
39
|
+
return embedding
|
|
40
|
+
seed = int(hashlib.sha256(self.zero_trust_key.encode()).hexdigest()[:8], 16)
|
|
41
|
+
import random
|
|
42
|
+
rng = random.Random(seed)
|
|
43
|
+
return [val * (1.0 if rng.random() > 0.5 else -1.0) for val in embedding]
|
|
44
|
+
|
|
45
|
+
def _get_headers(self) -> dict:
|
|
46
|
+
headers = {"Content-Type": "application/json"}
|
|
47
|
+
if self.api_key:
|
|
48
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
49
|
+
if self.tenant_id:
|
|
50
|
+
headers["X-Tenant-ID"] = self.tenant_id
|
|
51
|
+
return headers
|
|
52
|
+
|
|
53
|
+
@property
|
|
54
|
+
def client(self) -> Any:
|
|
55
|
+
return self
|
|
56
|
+
|
|
57
|
+
def add(self, nodes: List[BaseNode], **add_kwargs: Any) -> List[str]:
|
|
58
|
+
headers = self._get_headers()
|
|
59
|
+
ids = []
|
|
60
|
+
for node in nodes:
|
|
61
|
+
vector = self._encrypt_vector(node.embedding) if node.embedding else []
|
|
62
|
+
payload = {
|
|
63
|
+
"id": node.node_id,
|
|
64
|
+
"text": node.get_content(metadata_mode="all"),
|
|
65
|
+
"vector": vector,
|
|
66
|
+
"metadata": node.metadata
|
|
67
|
+
}
|
|
68
|
+
res = requests.post(f"{self.url}/api/v1/documents", json=payload, headers=headers)
|
|
69
|
+
res.raise_for_status()
|
|
70
|
+
ids.append(node.node_id)
|
|
71
|
+
return ids
|
|
72
|
+
|
|
73
|
+
def delete(self, ref_doc_id: str, **delete_kwargs: Any) -> None:
|
|
74
|
+
headers = self._get_headers()
|
|
75
|
+
res = requests.delete(f"{self.url}/api/v1/documents/{ref_doc_id}", headers=headers)
|
|
76
|
+
res.raise_for_status()
|
|
77
|
+
|
|
78
|
+
def query(self, query: VectorStoreQuery, **kwargs: Any) -> VectorStoreQueryResult:
|
|
79
|
+
headers = self._get_headers()
|
|
80
|
+
encrypted_query = self._encrypt_vector(query.query_embedding) if query.query_embedding else []
|
|
81
|
+
|
|
82
|
+
payload = {
|
|
83
|
+
"query_vector": encrypted_query,
|
|
84
|
+
"top_k": query.similarity_top_k
|
|
85
|
+
}
|
|
86
|
+
res = requests.post(f"{self.url}/api/v1/query", json=payload, headers=headers)
|
|
87
|
+
res.raise_for_status()
|
|
88
|
+
|
|
89
|
+
results = res.json()
|
|
90
|
+
nodes = []
|
|
91
|
+
similarities = []
|
|
92
|
+
ids = []
|
|
93
|
+
|
|
94
|
+
for doc in results.get("matches", []):
|
|
95
|
+
node = TextNode(
|
|
96
|
+
id_=doc.get("id"),
|
|
97
|
+
text=doc.get("text", ""),
|
|
98
|
+
metadata=doc.get("metadata", {})
|
|
99
|
+
)
|
|
100
|
+
nodes.append(node)
|
|
101
|
+
similarities.append(doc.get("score", 0.0))
|
|
102
|
+
ids.append(doc.get("id"))
|
|
103
|
+
|
|
104
|
+
return VectorStoreQueryResult(nodes=nodes, similarities=similarities, ids=ids)
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
from typing import Any, List, Optional, Tuple
|
|
2
|
+
import requests
|
|
3
|
+
import hashlib
|
|
4
|
+
from semantic_kernel.memory.memory_store_base import MemoryStoreBase
|
|
5
|
+
from semantic_kernel.memory.memory_record import MemoryRecord
|
|
6
|
+
|
|
7
|
+
class HolographicMemoryStore(MemoryStoreBase):
|
|
8
|
+
def __init__(
|
|
9
|
+
self,
|
|
10
|
+
url: str = "http://localhost:8080",
|
|
11
|
+
zero_trust_key: str = "",
|
|
12
|
+
api_key: Optional[str] = None,
|
|
13
|
+
tenant_id: Optional[str] = None,
|
|
14
|
+
):
|
|
15
|
+
self.url = url
|
|
16
|
+
self.zero_trust_key = zero_trust_key
|
|
17
|
+
self.api_key = api_key
|
|
18
|
+
self.tenant_id = tenant_id
|
|
19
|
+
|
|
20
|
+
def _encrypt_vector(self, embedding: List[float]) -> List[float]:
|
|
21
|
+
if not self.zero_trust_key or not embedding:
|
|
22
|
+
return embedding
|
|
23
|
+
seed = int(hashlib.sha256(self.zero_trust_key.encode()).hexdigest()[:8], 16)
|
|
24
|
+
import random
|
|
25
|
+
rng = random.Random(seed)
|
|
26
|
+
return [val * (1.0 if rng.random() > 0.5 else -1.0) for val in embedding]
|
|
27
|
+
|
|
28
|
+
def _get_headers(self) -> dict:
|
|
29
|
+
headers = {"Content-Type": "application/json"}
|
|
30
|
+
if self.api_key:
|
|
31
|
+
headers["Authorization"] = f"Bearer {self.api_key}"
|
|
32
|
+
if self.tenant_id:
|
|
33
|
+
headers["X-Tenant-ID"] = self.tenant_id
|
|
34
|
+
return headers
|
|
35
|
+
|
|
36
|
+
async def create_collection_async(self, collection_name: str) -> None:
|
|
37
|
+
pass
|
|
38
|
+
|
|
39
|
+
async def get_collections_async(self) -> List[str]:
|
|
40
|
+
return ["default"]
|
|
41
|
+
|
|
42
|
+
async def delete_collection_async(self, collection_name: str) -> None:
|
|
43
|
+
pass
|
|
44
|
+
|
|
45
|
+
async def does_collection_exist_async(self, collection_name: str) -> bool:
|
|
46
|
+
return True
|
|
47
|
+
|
|
48
|
+
async def upsert_async(self, collection_name: str, record: MemoryRecord) -> str:
|
|
49
|
+
headers = self._get_headers()
|
|
50
|
+
vector = self._encrypt_vector(record.embedding.tolist() if record.embedding is not None else [])
|
|
51
|
+
payload = {
|
|
52
|
+
"id": record._id,
|
|
53
|
+
"text": record._text,
|
|
54
|
+
"vector": vector,
|
|
55
|
+
"metadata": {"collection": collection_name}
|
|
56
|
+
}
|
|
57
|
+
res = requests.post(f"{self.url}/api/v1/documents", json=payload, headers=headers)
|
|
58
|
+
res.raise_for_status()
|
|
59
|
+
return record._id
|
|
60
|
+
|
|
61
|
+
async def upsert_batch_async(self, collection_name: str, records: List[MemoryRecord]) -> List[str]:
|
|
62
|
+
return [await self.upsert_async(collection_name, r) for r in records]
|
|
63
|
+
|
|
64
|
+
async def get_async(self, collection_name: str, key: str, with_embedding: bool = False) -> MemoryRecord:
|
|
65
|
+
raise NotImplementedError
|
|
66
|
+
|
|
67
|
+
async def get_batch_async(self, collection_name: str, keys: List[str], with_embeddings: bool = False) -> List[MemoryRecord]:
|
|
68
|
+
raise NotImplementedError
|
|
69
|
+
|
|
70
|
+
async def remove_async(self, collection_name: str, key: str) -> None:
|
|
71
|
+
headers = self._get_headers()
|
|
72
|
+
res = requests.delete(f"{self.url}/api/v1/documents/{key}", headers=headers)
|
|
73
|
+
res.raise_for_status()
|
|
74
|
+
|
|
75
|
+
async def remove_batch_async(self, collection_name: str, keys: List[str]) -> None:
|
|
76
|
+
for k in keys:
|
|
77
|
+
await self.remove_async(collection_name, k)
|
|
78
|
+
|
|
79
|
+
async def get_nearest_matches_async(
|
|
80
|
+
self,
|
|
81
|
+
collection_name: str,
|
|
82
|
+
embedding: Any,
|
|
83
|
+
limit: int = 1,
|
|
84
|
+
min_relevance_score: float = 0.0,
|
|
85
|
+
with_embeddings: bool = False,
|
|
86
|
+
) -> List[Tuple[MemoryRecord, float]]:
|
|
87
|
+
headers = self._get_headers()
|
|
88
|
+
encrypted_query = self._encrypt_vector(embedding.tolist())
|
|
89
|
+
payload = {
|
|
90
|
+
"query_vector": encrypted_query,
|
|
91
|
+
"top_k": limit
|
|
92
|
+
}
|
|
93
|
+
res = requests.post(f"{self.url}/api/v1/query", json=payload, headers=headers)
|
|
94
|
+
res.raise_for_status()
|
|
95
|
+
|
|
96
|
+
matches = []
|
|
97
|
+
for doc in res.json().get("matches", []):
|
|
98
|
+
if doc.get("score", 0.0) >= min_relevance_score:
|
|
99
|
+
record = MemoryRecord(
|
|
100
|
+
id=doc.get("id"),
|
|
101
|
+
text=doc.get("text", ""),
|
|
102
|
+
is_reference=False,
|
|
103
|
+
embedding=None,
|
|
104
|
+
description=None,
|
|
105
|
+
additional_metadata=None
|
|
106
|
+
)
|
|
107
|
+
matches.append((record, doc.get("score", 0.0)))
|
|
108
|
+
return matches
|
|
109
|
+
|
|
110
|
+
async def get_nearest_match_async(
|
|
111
|
+
self,
|
|
112
|
+
collection_name: str,
|
|
113
|
+
embedding: Any,
|
|
114
|
+
min_relevance_score: float = 0.0,
|
|
115
|
+
with_embedding: bool = False,
|
|
116
|
+
) -> Tuple[MemoryRecord, float]:
|
|
117
|
+
matches = await self.get_nearest_matches_async(
|
|
118
|
+
collection_name, embedding, limit=1, min_relevance_score=min_relevance_score
|
|
119
|
+
)
|
|
120
|
+
return matches[0] if matches else (None, 0.0)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "holographic-sdk"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Zero-Trust FHE-Lite SDK for Holographic Memory System"
|
|
5
|
+
authors = [
|
|
6
|
+
{name = "WritersLogic", email = "david@writerslogic.com"},
|
|
7
|
+
]
|
|
8
|
+
dependencies = [
|
|
9
|
+
"numpy>=1.24.0",
|
|
10
|
+
"requests>=2.31.0"
|
|
11
|
+
]
|
|
12
|
+
readme = "README.md"
|
|
13
|
+
requires-python = ">=3.9"
|
|
14
|
+
license = {text = "AGPL-3.0-or-later"}
|
|
15
|
+
|
|
16
|
+
[project.optional-dependencies]
|
|
17
|
+
langchain = ["langchain-core>=0.1.0"]
|
|
18
|
+
llamaindex = ["llama-index-core>=0.10.0"]
|
|
19
|
+
haystack = ["haystack-ai>=2.0.0"]
|
|
20
|
+
semantic-kernel = ["semantic-kernel>=1.0.0"]
|
|
21
|
+
dspy = ["dspy-ai>=2.4.0"]
|
|
22
|
+
all = [
|
|
23
|
+
"langchain-core>=0.1.0",
|
|
24
|
+
"llama-index-core>=0.10.0",
|
|
25
|
+
"haystack-ai>=2.0.0",
|
|
26
|
+
"semantic-kernel>=1.0.0",
|
|
27
|
+
"dspy-ai>=2.4.0"
|
|
28
|
+
]
|
|
29
|
+
|
|
30
|
+
[build-system]
|
|
31
|
+
requires = ["hatchling"]
|
|
32
|
+
build-backend = "hatchling.build"
|