memoryintelligence 1.0.0__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.
- memoryintelligence/__init__.py +153 -0
- memoryintelligence/edge_client.py +384 -0
- memoryintelligence/memory_client.py +688 -0
- memoryintelligence/mi_types.py +364 -0
- memoryintelligence-1.0.0.dist-info/METADATA +428 -0
- memoryintelligence-1.0.0.dist-info/RECORD +9 -0
- memoryintelligence-1.0.0.dist-info/WHEEL +5 -0
- memoryintelligence-1.0.0.dist-info/licenses/LICENSE +31 -0
- memoryintelligence-1.0.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory Intelligence SDK
|
|
3
|
+
=======================
|
|
4
|
+
|
|
5
|
+
The official Python SDK for Memory Intelligence.
|
|
6
|
+
|
|
7
|
+
Quick Start:
|
|
8
|
+
from memoryintelligence import MemoryClient
|
|
9
|
+
|
|
10
|
+
mi = MemoryClient(api_key="mi_sk_...")
|
|
11
|
+
|
|
12
|
+
# Process content → meaning (raw content discarded)
|
|
13
|
+
umo = mi.process("Important meeting notes", user_ulid="01ABC...")
|
|
14
|
+
|
|
15
|
+
# Search with explanation
|
|
16
|
+
results = mi.search("What did we discuss?", user_ulid="01ABC...", explain=True)
|
|
17
|
+
|
|
18
|
+
# Match for recommendations
|
|
19
|
+
match = mi.match(user_ulid, candidate_ulid, explain=True)
|
|
20
|
+
|
|
21
|
+
# Delete for GDPR
|
|
22
|
+
mi.delete(user_ulid="01ABC...")
|
|
23
|
+
|
|
24
|
+
For regulated industries (HIPAA, legal, finance):
|
|
25
|
+
from memoryintelligence import EdgeClient
|
|
26
|
+
|
|
27
|
+
mi = EdgeClient(
|
|
28
|
+
endpoint="https://mi.internal.yourcompany.com",
|
|
29
|
+
api_key="mi_sk_...",
|
|
30
|
+
hipaa_mode=True
|
|
31
|
+
)
|
|
32
|
+
|
|
33
|
+
# Process locally—data never leaves your infrastructure
|
|
34
|
+
umo = mi.process(clinical_note, patient_ulid="01ABC...")
|
|
35
|
+
|
|
36
|
+
Core Operations:
|
|
37
|
+
- process() → Convert raw content to meaning
|
|
38
|
+
- search() → Find relevant memories
|
|
39
|
+
- match() → Compare memories for relevance
|
|
40
|
+
- explain() → Get explanation for any UMO
|
|
41
|
+
- delete() → Remove all user data
|
|
42
|
+
- verify_provenance() → Verify authorship/timestamp
|
|
43
|
+
|
|
44
|
+
Version: 1.0.0
|
|
45
|
+
Author: Memory Intelligence Team
|
|
46
|
+
"""
|
|
47
|
+
|
|
48
|
+
__version__ = "1.0.0"
|
|
49
|
+
__author__ = "Memory Intelligence Team"
|
|
50
|
+
|
|
51
|
+
# ============================================================================
|
|
52
|
+
# Public API
|
|
53
|
+
# ============================================================================
|
|
54
|
+
|
|
55
|
+
# Main clients
|
|
56
|
+
from .memory_client import MemoryClient
|
|
57
|
+
from .edge_client import EdgeClient, connect_edge
|
|
58
|
+
|
|
59
|
+
# Enums
|
|
60
|
+
from .mi_types import (
|
|
61
|
+
Scope,
|
|
62
|
+
RetentionPolicy,
|
|
63
|
+
PIIHandling,
|
|
64
|
+
ProvenanceMode,
|
|
65
|
+
ExplainLevel,
|
|
66
|
+
)
|
|
67
|
+
|
|
68
|
+
# Response types
|
|
69
|
+
from .mi_types import (
|
|
70
|
+
MeaningObject,
|
|
71
|
+
SearchResponse,
|
|
72
|
+
SearchResult,
|
|
73
|
+
MatchResult,
|
|
74
|
+
DeleteResult,
|
|
75
|
+
VerifyResult,
|
|
76
|
+
Explanation,
|
|
77
|
+
ExplainHuman,
|
|
78
|
+
ExplainAudit,
|
|
79
|
+
Entity,
|
|
80
|
+
Topic,
|
|
81
|
+
SVOTriple,
|
|
82
|
+
Provenance,
|
|
83
|
+
PIIDetection,
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
# Config types
|
|
87
|
+
from .mi_types import (
|
|
88
|
+
ProcessConfig,
|
|
89
|
+
SearchConfig,
|
|
90
|
+
MatchConfig,
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
# Exceptions
|
|
94
|
+
from .mi_types import (
|
|
95
|
+
MIError,
|
|
96
|
+
AuthenticationError,
|
|
97
|
+
RateLimitError,
|
|
98
|
+
ScopeViolationError,
|
|
99
|
+
PIIViolationError,
|
|
100
|
+
GovernanceError,
|
|
101
|
+
ProvenenaceError,
|
|
102
|
+
)
|
|
103
|
+
|
|
104
|
+
# ============================================================================
|
|
105
|
+
# Convenience exports
|
|
106
|
+
# ============================================================================
|
|
107
|
+
|
|
108
|
+
__all__ = [
|
|
109
|
+
# Version
|
|
110
|
+
"__version__",
|
|
111
|
+
|
|
112
|
+
# Clients
|
|
113
|
+
"MemoryClient",
|
|
114
|
+
"EdgeClient",
|
|
115
|
+
"connect_edge",
|
|
116
|
+
|
|
117
|
+
# Enums
|
|
118
|
+
"Scope",
|
|
119
|
+
"RetentionPolicy",
|
|
120
|
+
"PIIHandling",
|
|
121
|
+
"ProvenanceMode",
|
|
122
|
+
"ExplainLevel",
|
|
123
|
+
|
|
124
|
+
# Response types
|
|
125
|
+
"MeaningObject",
|
|
126
|
+
"SearchResponse",
|
|
127
|
+
"SearchResult",
|
|
128
|
+
"MatchResult",
|
|
129
|
+
"DeleteResult",
|
|
130
|
+
"VerifyResult",
|
|
131
|
+
"Explanation",
|
|
132
|
+
"ExplainHuman",
|
|
133
|
+
"ExplainAudit",
|
|
134
|
+
"Entity",
|
|
135
|
+
"Topic",
|
|
136
|
+
"SVOTriple",
|
|
137
|
+
"Provenance",
|
|
138
|
+
"PIIDetection",
|
|
139
|
+
|
|
140
|
+
# Config types
|
|
141
|
+
"ProcessConfig",
|
|
142
|
+
"SearchConfig",
|
|
143
|
+
"MatchConfig",
|
|
144
|
+
|
|
145
|
+
# Exceptions
|
|
146
|
+
"MIError",
|
|
147
|
+
"AuthenticationError",
|
|
148
|
+
"RateLimitError",
|
|
149
|
+
"ScopeViolationError",
|
|
150
|
+
"PIIViolationError",
|
|
151
|
+
"GovernanceError",
|
|
152
|
+
"ProvenenaceError",
|
|
153
|
+
]
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Memory Intelligence SDK - Edge Client
|
|
3
|
+
=====================================
|
|
4
|
+
|
|
5
|
+
On-premises / VPC deployment for regulated industries.
|
|
6
|
+
Data never leaves your infrastructure—only metering crosses the network.
|
|
7
|
+
|
|
8
|
+
Problem Solved: Proprietary Data Paralysis
|
|
9
|
+
- HIPAA: Clinical notes processed locally
|
|
10
|
+
- Legal: Attorney-client privileged documents
|
|
11
|
+
- Finance: Trading data, internal communications
|
|
12
|
+
- Competitive: Trade secrets, internal strategy
|
|
13
|
+
|
|
14
|
+
Architecture:
|
|
15
|
+
┌─────────────────────────────────────────────────────────┐
|
|
16
|
+
│ YOUR INFRASTRUCTURE │
|
|
17
|
+
│ │
|
|
18
|
+
│ ┌──────────────┐ ┌──────────────────────────┐ │
|
|
19
|
+
│ │ Your App │ │ MI Edge Container │ │
|
|
20
|
+
│ │ │ ──────> │ - 12-phase pipeline │ │
|
|
21
|
+
│ │ EdgeClient │ │ - NER engine │ │
|
|
22
|
+
│ │ │ <────── │ - Embedding engine │ │
|
|
23
|
+
│ └──────────────┘ │ - Provenance ledger │ │
|
|
24
|
+
│ └──────────────────────────┘ │
|
|
25
|
+
│ │ │
|
|
26
|
+
└──────────────────────────────────────│───────────────────┘
|
|
27
|
+
│ Metering only
|
|
28
|
+
▼
|
|
29
|
+
┌───────────────────────┐
|
|
30
|
+
│ MI Cloud (optional) │
|
|
31
|
+
│ - Usage tracking │
|
|
32
|
+
│ - License validation │
|
|
33
|
+
└───────────────────────┘
|
|
34
|
+
|
|
35
|
+
Usage:
|
|
36
|
+
from memoryintelligence import EdgeClient
|
|
37
|
+
|
|
38
|
+
# Connect to your on-prem MI container
|
|
39
|
+
mi = EdgeClient(
|
|
40
|
+
endpoint="https://mi.internal.yourcompany.com",
|
|
41
|
+
api_key="mi_sk_...", # For metering only
|
|
42
|
+
hipaa_mode=True
|
|
43
|
+
)
|
|
44
|
+
|
|
45
|
+
# Process locally—data never leaves
|
|
46
|
+
umo = mi.process(clinical_note, patient_ulid="01ABC...")
|
|
47
|
+
|
|
48
|
+
Author: Memory Intelligence Team
|
|
49
|
+
Version: 1.0.0
|
|
50
|
+
"""
|
|
51
|
+
|
|
52
|
+
import httpx
|
|
53
|
+
import logging
|
|
54
|
+
from datetime import datetime
|
|
55
|
+
from typing import Any, Dict, List, Optional, Union
|
|
56
|
+
|
|
57
|
+
from .mi_types import (
|
|
58
|
+
Scope,
|
|
59
|
+
RetentionPolicy,
|
|
60
|
+
PIIHandling,
|
|
61
|
+
ProvenanceMode,
|
|
62
|
+
ExplainLevel,
|
|
63
|
+
MeaningObject,
|
|
64
|
+
SearchResponse,
|
|
65
|
+
MatchResult,
|
|
66
|
+
DeleteResult,
|
|
67
|
+
Explanation,
|
|
68
|
+
MIError,
|
|
69
|
+
AuthenticationError,
|
|
70
|
+
)
|
|
71
|
+
from .memory_client import MemoryClient
|
|
72
|
+
|
|
73
|
+
logger = logging.getLogger(__name__)
|
|
74
|
+
|
|
75
|
+
|
|
76
|
+
class EdgeClient(MemoryClient):
|
|
77
|
+
"""
|
|
78
|
+
Edge deployment client for regulated industries.
|
|
79
|
+
|
|
80
|
+
All processing happens in your infrastructure.
|
|
81
|
+
Only metering/licensing data crosses the network (optional).
|
|
82
|
+
|
|
83
|
+
Key Features:
|
|
84
|
+
- HIPAA mode: Enhanced PHI detection, audit logging
|
|
85
|
+
- Air-gapped mode: No network calls at all
|
|
86
|
+
- Federated aggregation: Query across deployments without sharing data
|
|
87
|
+
|
|
88
|
+
Args:
|
|
89
|
+
endpoint: Your internal MI container endpoint
|
|
90
|
+
api_key: MI API key (for metering, can be disabled)
|
|
91
|
+
hipaa_mode: Enable HIPAA-compliant processing
|
|
92
|
+
air_gapped: Disable all external network calls
|
|
93
|
+
metering_enabled: Whether to report usage to MI cloud
|
|
94
|
+
|
|
95
|
+
Example:
|
|
96
|
+
# Standard edge deployment
|
|
97
|
+
mi = EdgeClient(
|
|
98
|
+
endpoint="https://mi.internal.yourcompany.com",
|
|
99
|
+
api_key="mi_sk_...",
|
|
100
|
+
hipaa_mode=True
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
# Air-gapped (no external calls)
|
|
104
|
+
mi = EdgeClient(
|
|
105
|
+
endpoint="https://mi.internal.yourcompany.com",
|
|
106
|
+
air_gapped=True
|
|
107
|
+
)
|
|
108
|
+
"""
|
|
109
|
+
|
|
110
|
+
def __init__(
|
|
111
|
+
self,
|
|
112
|
+
endpoint: str,
|
|
113
|
+
api_key: Optional[str] = None,
|
|
114
|
+
hipaa_mode: bool = False,
|
|
115
|
+
air_gapped: bool = False,
|
|
116
|
+
metering_enabled: bool = True,
|
|
117
|
+
timeout: float = 30.0,
|
|
118
|
+
):
|
|
119
|
+
self.endpoint = endpoint.rstrip("/")
|
|
120
|
+
self.hipaa_mode = hipaa_mode
|
|
121
|
+
self.air_gapped = air_gapped
|
|
122
|
+
self.metering_enabled = metering_enabled and not air_gapped
|
|
123
|
+
|
|
124
|
+
# For air-gapped mode, API key is optional
|
|
125
|
+
if not air_gapped and not api_key:
|
|
126
|
+
raise AuthenticationError(
|
|
127
|
+
"API key required for metered edge deployment. "
|
|
128
|
+
"Use air_gapped=True for offline mode."
|
|
129
|
+
)
|
|
130
|
+
|
|
131
|
+
self.api_key = api_key
|
|
132
|
+
self.timeout = timeout
|
|
133
|
+
|
|
134
|
+
# Edge client connects to internal endpoint
|
|
135
|
+
self._client = httpx.Client(
|
|
136
|
+
base_url=self.endpoint,
|
|
137
|
+
timeout=self.timeout,
|
|
138
|
+
headers={
|
|
139
|
+
"X-MI-Edge-Mode": "true",
|
|
140
|
+
"X-MI-HIPAA-Mode": str(hipaa_mode).lower(),
|
|
141
|
+
"Content-Type": "application/json",
|
|
142
|
+
}
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
# Separate client for metering (if enabled)
|
|
146
|
+
if self.metering_enabled and api_key:
|
|
147
|
+
self._metering_client = httpx.Client(
|
|
148
|
+
base_url="https://api.memoryintelligence.dev",
|
|
149
|
+
timeout=5.0, # Fast timeout for metering
|
|
150
|
+
headers={
|
|
151
|
+
"Authorization": f"Bearer {api_key}",
|
|
152
|
+
"X-MI-Edge-Metering": "true",
|
|
153
|
+
}
|
|
154
|
+
)
|
|
155
|
+
else:
|
|
156
|
+
self._metering_client = None
|
|
157
|
+
|
|
158
|
+
logger.info(
|
|
159
|
+
f"EdgeClient initialized (endpoint={endpoint}, "
|
|
160
|
+
f"hipaa={hipaa_mode}, air_gapped={air_gapped})"
|
|
161
|
+
)
|
|
162
|
+
|
|
163
|
+
def process(
|
|
164
|
+
self,
|
|
165
|
+
content: str,
|
|
166
|
+
user_ulid: str,
|
|
167
|
+
*,
|
|
168
|
+
retention_policy: RetentionPolicy = RetentionPolicy.MEANING_ONLY,
|
|
169
|
+
pii_handling: PIIHandling = PIIHandling.EXTRACT_AND_REDACT,
|
|
170
|
+
provenance_mode: ProvenanceMode = ProvenanceMode.STANDARD,
|
|
171
|
+
scope: Scope = Scope.USER,
|
|
172
|
+
scope_id: Optional[str] = None,
|
|
173
|
+
source: str = "edge",
|
|
174
|
+
metadata: Optional[Dict[str, Any]] = None,
|
|
175
|
+
) -> MeaningObject:
|
|
176
|
+
"""
|
|
177
|
+
Process content locally in your infrastructure.
|
|
178
|
+
|
|
179
|
+
In HIPAA mode:
|
|
180
|
+
- Enhanced PHI detection (ICD-10, medical terms)
|
|
181
|
+
- All PHI hashed, never stored
|
|
182
|
+
- Audit log proves data never left
|
|
183
|
+
|
|
184
|
+
Args:
|
|
185
|
+
content: Raw content (processed locally, never transmitted)
|
|
186
|
+
user_ulid: Owner ULID (can be patient ULID in HIPAA mode)
|
|
187
|
+
retention_policy: What to retain (meaning_only recommended)
|
|
188
|
+
pii_handling: PHI/PII handling (hash recommended for HIPAA)
|
|
189
|
+
... (same as MemoryClient.process)
|
|
190
|
+
|
|
191
|
+
Returns:
|
|
192
|
+
MeaningObject with entities, embedding, provenance
|
|
193
|
+
|
|
194
|
+
Note:
|
|
195
|
+
In HIPAA mode, the response includes phi_status showing
|
|
196
|
+
what PHI was detected and how it was handled.
|
|
197
|
+
"""
|
|
198
|
+
# Override PII handling in HIPAA mode
|
|
199
|
+
if self.hipaa_mode:
|
|
200
|
+
pii_handling = PIIHandling.HASH
|
|
201
|
+
provenance_mode = ProvenanceMode.AUDIT
|
|
202
|
+
|
|
203
|
+
payload = {
|
|
204
|
+
"content": content,
|
|
205
|
+
"user_ulid": user_ulid,
|
|
206
|
+
"retention_policy": retention_policy.value,
|
|
207
|
+
"pii_handling": pii_handling.value,
|
|
208
|
+
"provenance_mode": provenance_mode.value,
|
|
209
|
+
"scope": scope.value,
|
|
210
|
+
"scope_id": scope_id,
|
|
211
|
+
"source": source,
|
|
212
|
+
"metadata": metadata or {},
|
|
213
|
+
"hipaa_mode": self.hipaa_mode,
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
# Process locally
|
|
217
|
+
response = self._request("POST", "/v1/process", json=payload)
|
|
218
|
+
result = self._parse_meaning_object(response)
|
|
219
|
+
|
|
220
|
+
# Report usage (async, non-blocking, fails silently)
|
|
221
|
+
if self.metering_enabled:
|
|
222
|
+
self._report_usage("process", user_ulid)
|
|
223
|
+
|
|
224
|
+
return result
|
|
225
|
+
|
|
226
|
+
def aggregate(
|
|
227
|
+
self,
|
|
228
|
+
query: str,
|
|
229
|
+
scope: Scope = Scope.ORGANIZATION,
|
|
230
|
+
return_format: str = "statistics_only",
|
|
231
|
+
minimum_cohort_size: int = 50,
|
|
232
|
+
) -> Dict[str, Any]:
|
|
233
|
+
"""
|
|
234
|
+
Aggregate insights across records without exposing individual data.
|
|
235
|
+
|
|
236
|
+
Federated querying with differential privacy for regulated data.
|
|
237
|
+
|
|
238
|
+
Args:
|
|
239
|
+
query: Natural language query for aggregation
|
|
240
|
+
scope: Aggregation scope (typically ORGANIZATION)
|
|
241
|
+
return_format: "statistics_only" (no individual records)
|
|
242
|
+
minimum_cohort_size: K-anonymity threshold
|
|
243
|
+
|
|
244
|
+
Returns:
|
|
245
|
+
Aggregated statistics with privacy guarantees
|
|
246
|
+
|
|
247
|
+
Example:
|
|
248
|
+
insights = mi.aggregate(
|
|
249
|
+
"Patients with chest pain who responded to nitroglycerin",
|
|
250
|
+
scope=Scope.ORGANIZATION,
|
|
251
|
+
minimum_cohort_size=50
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
# Returns:
|
|
255
|
+
# {
|
|
256
|
+
# "count": 1247,
|
|
257
|
+
# "avg_response_time": "4.2 minutes",
|
|
258
|
+
# "audit_proof": {"no_phi_returned": True, ...}
|
|
259
|
+
# }
|
|
260
|
+
"""
|
|
261
|
+
payload = {
|
|
262
|
+
"query": query,
|
|
263
|
+
"scope": scope.value,
|
|
264
|
+
"return_format": return_format,
|
|
265
|
+
"minimum_cohort_size": minimum_cohort_size,
|
|
266
|
+
"hipaa_mode": self.hipaa_mode,
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
response = self._request("POST", "/v1/aggregate", json=payload)
|
|
270
|
+
|
|
271
|
+
# Report usage
|
|
272
|
+
if self.metering_enabled:
|
|
273
|
+
self._report_usage("aggregate", "aggregate")
|
|
274
|
+
|
|
275
|
+
return response
|
|
276
|
+
|
|
277
|
+
def verify_phi_handling(self, umo_id: str) -> Dict[str, Any]:
|
|
278
|
+
"""
|
|
279
|
+
Verify how PHI was handled for a specific UMO.
|
|
280
|
+
|
|
281
|
+
Returns audit proof showing:
|
|
282
|
+
- What PHI types were detected
|
|
283
|
+
- How each was handled (hashed, redacted)
|
|
284
|
+
- Proof that raw PHI was never stored/transmitted
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
umo_id: ULID of the processed memory
|
|
288
|
+
|
|
289
|
+
Returns:
|
|
290
|
+
PHI handling audit proof
|
|
291
|
+
|
|
292
|
+
Example:
|
|
293
|
+
proof = mi.verify_phi_handling(umo_id)
|
|
294
|
+
|
|
295
|
+
# Returns:
|
|
296
|
+
# {
|
|
297
|
+
# "phi_detected": ["PERSON", "DATE", "MRN"],
|
|
298
|
+
# "handling_method": "hash",
|
|
299
|
+
# "raw_phi_stored": False,
|
|
300
|
+
# "raw_phi_transmitted": False,
|
|
301
|
+
# "audit_hash": "sha256:...",
|
|
302
|
+
# "timestamp": "2025-12-26T..."
|
|
303
|
+
# }
|
|
304
|
+
"""
|
|
305
|
+
response = self._request("GET", f"/v1/phi/verify/{umo_id}")
|
|
306
|
+
return response
|
|
307
|
+
|
|
308
|
+
def export_audit_log(
|
|
309
|
+
self,
|
|
310
|
+
start_date: datetime,
|
|
311
|
+
end_date: datetime,
|
|
312
|
+
format: str = "json",
|
|
313
|
+
) -> Dict[str, Any]:
|
|
314
|
+
"""
|
|
315
|
+
Export audit log for compliance review.
|
|
316
|
+
|
|
317
|
+
Returns complete processing audit trail for the date range.
|
|
318
|
+
|
|
319
|
+
Args:
|
|
320
|
+
start_date: Audit period start
|
|
321
|
+
end_date: Audit period end
|
|
322
|
+
format: Export format ("json", "csv")
|
|
323
|
+
|
|
324
|
+
Returns:
|
|
325
|
+
Audit log with all processing events
|
|
326
|
+
"""
|
|
327
|
+
payload = {
|
|
328
|
+
"start_date": start_date.isoformat(),
|
|
329
|
+
"end_date": end_date.isoformat(),
|
|
330
|
+
"format": format,
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
response = self._request("POST", "/v1/audit/export", json=payload)
|
|
334
|
+
return response
|
|
335
|
+
|
|
336
|
+
def _report_usage(self, operation: str, user_ulid: str):
|
|
337
|
+
"""Report usage to MI cloud for metering (non-blocking)."""
|
|
338
|
+
if not self._metering_client:
|
|
339
|
+
return
|
|
340
|
+
|
|
341
|
+
try:
|
|
342
|
+
self._metering_client.post(
|
|
343
|
+
"/v1/metering/report",
|
|
344
|
+
json={
|
|
345
|
+
"operation": operation,
|
|
346
|
+
"user_ulid": user_ulid,
|
|
347
|
+
"timestamp": datetime.utcnow().isoformat(),
|
|
348
|
+
"hipaa_mode": self.hipaa_mode,
|
|
349
|
+
}
|
|
350
|
+
)
|
|
351
|
+
except Exception as e:
|
|
352
|
+
# Metering failures should never block processing
|
|
353
|
+
logger.debug(f"Metering report failed (non-blocking): {e}")
|
|
354
|
+
|
|
355
|
+
def close(self):
|
|
356
|
+
"""Close HTTP clients."""
|
|
357
|
+
self._client.close()
|
|
358
|
+
if self._metering_client:
|
|
359
|
+
self._metering_client.close()
|
|
360
|
+
|
|
361
|
+
|
|
362
|
+
# ============================================================================
|
|
363
|
+
# Convenience function for quick edge setup
|
|
364
|
+
# ============================================================================
|
|
365
|
+
|
|
366
|
+
def connect_edge(
|
|
367
|
+
endpoint: str,
|
|
368
|
+
api_key: Optional[str] = None,
|
|
369
|
+
hipaa_mode: bool = False,
|
|
370
|
+
) -> EdgeClient:
|
|
371
|
+
"""
|
|
372
|
+
Quick helper to connect to an edge deployment.
|
|
373
|
+
|
|
374
|
+
Example:
|
|
375
|
+
from memoryintelligence import connect_edge
|
|
376
|
+
|
|
377
|
+
mi = connect_edge("https://mi.internal.hospital.com", hipaa_mode=True)
|
|
378
|
+
umo = mi.process(clinical_note, patient_ulid="01ABC...")
|
|
379
|
+
"""
|
|
380
|
+
return EdgeClient(
|
|
381
|
+
endpoint=endpoint,
|
|
382
|
+
api_key=api_key,
|
|
383
|
+
hipaa_mode=hipaa_mode,
|
|
384
|
+
)
|