emergent-translator 1.1.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.
- emergent_translator/__init__.py +126 -0
- emergent_translator/adaptive_codebook.py +342 -0
- emergent_translator/api_server.py +4988 -0
- emergent_translator/batch_encoder.py +555 -0
- emergent_translator/chunk_collector.py +978 -0
- emergent_translator/chunk_coordinator.py +738 -0
- emergent_translator/claude_compression.py +375 -0
- emergent_translator/cli.py +413 -0
- emergent_translator/client_sdk.py +903 -0
- emergent_translator/code_skeleton.py +448 -0
- emergent_translator/core.py +1081 -0
- emergent_translator/emergent_symbols.py +690 -0
- emergent_translator/format_handlers.py +901 -0
- emergent_translator/gpu_batch_encoder.py +848 -0
- emergent_translator/intelligent_router.py +509 -0
- emergent_translator/metrics.py +436 -0
- emergent_translator/py.typed +0 -0
- emergent_translator-1.1.0.dist-info/METADATA +568 -0
- emergent_translator-1.1.0.dist-info/RECORD +23 -0
- emergent_translator-1.1.0.dist-info/WHEEL +5 -0
- emergent_translator-1.1.0.dist-info/entry_points.txt +2 -0
- emergent_translator-1.1.0.dist-info/licenses/LICENSE +82 -0
- emergent_translator-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,903 @@
|
|
|
1
|
+
# eudaimonia/translator/client_sdk.py
|
|
2
|
+
|
|
3
|
+
"""
|
|
4
|
+
Emergent Language Translator Client SDK
|
|
5
|
+
|
|
6
|
+
Python and JavaScript SDKs for easy integration with the Emergent Language
|
|
7
|
+
Translator API. Provides simple, high-level interfaces for external AI systems
|
|
8
|
+
to compress their data using Eudaimonia's native θ symbol format.
|
|
9
|
+
|
|
10
|
+
Features:
|
|
11
|
+
- Simple async/sync Python client
|
|
12
|
+
- Batch translation support
|
|
13
|
+
- WebSocket streaming
|
|
14
|
+
- Automatic retries and error handling
|
|
15
|
+
- Compression statistics
|
|
16
|
+
- TypeScript definitions for JavaScript
|
|
17
|
+
"""
|
|
18
|
+
|
|
19
|
+
import asyncio
|
|
20
|
+
import json
|
|
21
|
+
import logging
|
|
22
|
+
import time
|
|
23
|
+
from typing import Dict, List, Optional, Union, Any, AsyncGenerator, Tuple
|
|
24
|
+
from dataclasses import dataclass
|
|
25
|
+
import base64
|
|
26
|
+
|
|
27
|
+
import httpx
|
|
28
|
+
import websockets
|
|
29
|
+
|
|
30
|
+
logger = logging.getLogger(__name__)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
@dataclass
|
|
34
|
+
class TranslationConfig:
|
|
35
|
+
"""Configuration for translator client."""
|
|
36
|
+
api_base_url: str = "http://localhost:8000"
|
|
37
|
+
auth_token: Optional[str] = None
|
|
38
|
+
timeout: float = 30.0
|
|
39
|
+
max_retries: int = 3
|
|
40
|
+
retry_delay: float = 1.0
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
@dataclass
|
|
44
|
+
class ClientTranslationResult:
|
|
45
|
+
"""Client-side translation result."""
|
|
46
|
+
success: bool
|
|
47
|
+
translated_data: Optional[bytes] = None
|
|
48
|
+
original_size: int = 0
|
|
49
|
+
translated_size: int = 0
|
|
50
|
+
compression_ratio: float = 0.0
|
|
51
|
+
efficiency_gain: float = 0.0
|
|
52
|
+
translation_time_ms: float = 0.0
|
|
53
|
+
symbol_count: int = 0
|
|
54
|
+
symbol_families: List[str] = None
|
|
55
|
+
metadata: Dict[str, Any] = None
|
|
56
|
+
errors: List[str] = None
|
|
57
|
+
|
|
58
|
+
def __post_init__(self):
|
|
59
|
+
if self.symbol_families is None:
|
|
60
|
+
self.symbol_families = []
|
|
61
|
+
if self.metadata is None:
|
|
62
|
+
self.metadata = {}
|
|
63
|
+
if self.errors is None:
|
|
64
|
+
self.errors = []
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class EmergentTranslatorClient:
|
|
68
|
+
"""
|
|
69
|
+
Async client for Emergent Language Translator API.
|
|
70
|
+
|
|
71
|
+
Provides high-level interface for translating data to Eudaimonia's
|
|
72
|
+
emergent language format with automatic retries and error handling.
|
|
73
|
+
|
|
74
|
+
Example:
|
|
75
|
+
async with EmergentTranslatorClient() as client:
|
|
76
|
+
result = await client.translate_json({"task": "analyze data"})
|
|
77
|
+
print(f"Compression: {result.efficiency_gain:.1f}%")
|
|
78
|
+
"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, config: Optional[TranslationConfig] = None):
|
|
81
|
+
"""Initialize client with configuration."""
|
|
82
|
+
self.config = config or TranslationConfig()
|
|
83
|
+
self._client: Optional[httpx.AsyncClient] = None
|
|
84
|
+
self._websocket: Optional[websockets.WebSocketServerProtocol] = None
|
|
85
|
+
|
|
86
|
+
async def __aenter__(self):
|
|
87
|
+
"""Async context manager entry."""
|
|
88
|
+
await self._ensure_client()
|
|
89
|
+
return self
|
|
90
|
+
|
|
91
|
+
async def __aexit__(self, exc_type, exc_val, exc_tb):
|
|
92
|
+
"""Async context manager exit."""
|
|
93
|
+
await self.close()
|
|
94
|
+
|
|
95
|
+
async def _ensure_client(self):
|
|
96
|
+
"""Ensure HTTP client is initialized."""
|
|
97
|
+
if self._client is None:
|
|
98
|
+
headers = {}
|
|
99
|
+
if self.config.auth_token:
|
|
100
|
+
headers["Authorization"] = f"Bearer {self.config.auth_token}"
|
|
101
|
+
|
|
102
|
+
self._client = httpx.AsyncClient(
|
|
103
|
+
base_url=self.config.api_base_url,
|
|
104
|
+
headers=headers,
|
|
105
|
+
timeout=self.config.timeout
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
async def close(self):
|
|
109
|
+
"""Close client connections."""
|
|
110
|
+
if self._client:
|
|
111
|
+
await self._client.aclose()
|
|
112
|
+
self._client = None
|
|
113
|
+
|
|
114
|
+
if self._websocket:
|
|
115
|
+
await self._websocket.close()
|
|
116
|
+
self._websocket = None
|
|
117
|
+
|
|
118
|
+
# Core translation methods
|
|
119
|
+
|
|
120
|
+
async def translate_json(
|
|
121
|
+
self,
|
|
122
|
+
data: Union[dict, str],
|
|
123
|
+
intent_type: str = "general",
|
|
124
|
+
epoch: int = 0,
|
|
125
|
+
enable_validation: bool = True
|
|
126
|
+
) -> ClientTranslationResult:
|
|
127
|
+
"""
|
|
128
|
+
Translate JSON data to emergent language symbols.
|
|
129
|
+
|
|
130
|
+
Args:
|
|
131
|
+
data: JSON data (dict or string)
|
|
132
|
+
intent_type: Intent type for better symbol selection
|
|
133
|
+
epoch: Emergent language epoch version
|
|
134
|
+
enable_validation: Enable symbol validation
|
|
135
|
+
|
|
136
|
+
Returns:
|
|
137
|
+
Translation result with compressed data and statistics
|
|
138
|
+
"""
|
|
139
|
+
await self._ensure_client()
|
|
140
|
+
|
|
141
|
+
request_data = {
|
|
142
|
+
"data": data,
|
|
143
|
+
"source_format": "json",
|
|
144
|
+
"target_format": "emergent",
|
|
145
|
+
"intent_type": intent_type,
|
|
146
|
+
"epoch": epoch,
|
|
147
|
+
"enable_validation": enable_validation
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return await self._make_translation_request(request_data)
|
|
151
|
+
|
|
152
|
+
async def translate_text(
|
|
153
|
+
self,
|
|
154
|
+
text: str,
|
|
155
|
+
intent_type: str = "general",
|
|
156
|
+
epoch: int = 0,
|
|
157
|
+
enable_validation: bool = True
|
|
158
|
+
) -> ClientTranslationResult:
|
|
159
|
+
"""
|
|
160
|
+
Translate natural language text to emergent symbols.
|
|
161
|
+
|
|
162
|
+
Args:
|
|
163
|
+
text: Natural language text
|
|
164
|
+
intent_type: Intent type (general, work, governance, social, resource)
|
|
165
|
+
epoch: Emergent language epoch version
|
|
166
|
+
enable_validation: Enable symbol validation
|
|
167
|
+
|
|
168
|
+
Returns:
|
|
169
|
+
Translation result with compressed data and statistics
|
|
170
|
+
"""
|
|
171
|
+
await self._ensure_client()
|
|
172
|
+
|
|
173
|
+
request_data = {
|
|
174
|
+
"data": text,
|
|
175
|
+
"source_format": "text",
|
|
176
|
+
"target_format": "emergent",
|
|
177
|
+
"intent_type": intent_type,
|
|
178
|
+
"epoch": epoch,
|
|
179
|
+
"enable_validation": enable_validation
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
return await self._make_translation_request(request_data)
|
|
183
|
+
|
|
184
|
+
async def translate_from_emergent(
|
|
185
|
+
self,
|
|
186
|
+
symbol_data: bytes,
|
|
187
|
+
target_format: str = "json",
|
|
188
|
+
epoch: int = 0
|
|
189
|
+
) -> ClientTranslationResult:
|
|
190
|
+
"""
|
|
191
|
+
Translate emergent language symbols back to readable format.
|
|
192
|
+
|
|
193
|
+
Args:
|
|
194
|
+
symbol_data: Emergent language symbol bytes
|
|
195
|
+
target_format: Target format (json, text, etc.)
|
|
196
|
+
epoch: Emergent language epoch version
|
|
197
|
+
|
|
198
|
+
Returns:
|
|
199
|
+
Translation result with decompressed data
|
|
200
|
+
"""
|
|
201
|
+
await self._ensure_client()
|
|
202
|
+
|
|
203
|
+
# Encode binary data as base64 for JSON transport
|
|
204
|
+
encoded_data = base64.b64encode(symbol_data).decode('utf-8')
|
|
205
|
+
|
|
206
|
+
request_data = {
|
|
207
|
+
"data": encoded_data,
|
|
208
|
+
"source_format": "binary",
|
|
209
|
+
"target_format": target_format,
|
|
210
|
+
"epoch": epoch
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return await self._make_translation_request(request_data)
|
|
214
|
+
|
|
215
|
+
async def translate_batch(
|
|
216
|
+
self,
|
|
217
|
+
requests: List[Dict[str, Any]],
|
|
218
|
+
parallel: bool = True
|
|
219
|
+
) -> List[ClientTranslationResult]:
|
|
220
|
+
"""
|
|
221
|
+
Translate multiple data items in batch.
|
|
222
|
+
|
|
223
|
+
Args:
|
|
224
|
+
requests: List of translation request dictionaries
|
|
225
|
+
parallel: Process requests in parallel
|
|
226
|
+
|
|
227
|
+
Returns:
|
|
228
|
+
List of translation results
|
|
229
|
+
"""
|
|
230
|
+
await self._ensure_client()
|
|
231
|
+
|
|
232
|
+
request_data = {
|
|
233
|
+
"requests": requests,
|
|
234
|
+
"parallel": parallel
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
try:
|
|
238
|
+
response = await self._client.post("/translate/batch", json=request_data)
|
|
239
|
+
response.raise_for_status()
|
|
240
|
+
|
|
241
|
+
result_data = response.json()
|
|
242
|
+
|
|
243
|
+
results = []
|
|
244
|
+
for result in result_data.get("results", []):
|
|
245
|
+
translated_data = None
|
|
246
|
+
if result.get("translated_data"):
|
|
247
|
+
try:
|
|
248
|
+
translated_data = base64.b64decode(result["translated_data"])
|
|
249
|
+
except:
|
|
250
|
+
translated_data = result["translated_data"].encode('utf-8')
|
|
251
|
+
|
|
252
|
+
results.append(ClientTranslationResult(
|
|
253
|
+
success=result.get("success", False),
|
|
254
|
+
translated_data=translated_data,
|
|
255
|
+
original_size=result.get("original_size", 0),
|
|
256
|
+
translated_size=result.get("translated_size", 0),
|
|
257
|
+
compression_ratio=result.get("compression_ratio", 0.0),
|
|
258
|
+
efficiency_gain=result.get("efficiency_gain", 0.0),
|
|
259
|
+
translation_time_ms=result.get("translation_time_ms", 0.0),
|
|
260
|
+
symbol_count=result.get("symbol_count", 0),
|
|
261
|
+
symbol_families=result.get("symbol_families", []),
|
|
262
|
+
metadata=result.get("metadata", {}),
|
|
263
|
+
errors=result.get("errors", [])
|
|
264
|
+
))
|
|
265
|
+
|
|
266
|
+
return results
|
|
267
|
+
|
|
268
|
+
except httpx.HTTPError as e:
|
|
269
|
+
logger.error(f"Batch translation HTTP error: {e}")
|
|
270
|
+
return [ClientTranslationResult(success=False, errors=[str(e)])]
|
|
271
|
+
except Exception as e:
|
|
272
|
+
logger.error(f"Batch translation error: {e}")
|
|
273
|
+
return [ClientTranslationResult(success=False, errors=[str(e)])]
|
|
274
|
+
|
|
275
|
+
# WebSocket streaming interface
|
|
276
|
+
|
|
277
|
+
async def stream_translations(
|
|
278
|
+
self
|
|
279
|
+
) -> AsyncGenerator[ClientTranslationResult, None]:
|
|
280
|
+
"""
|
|
281
|
+
Open WebSocket connection for streaming translations.
|
|
282
|
+
|
|
283
|
+
Yields:
|
|
284
|
+
Translation results as they are processed
|
|
285
|
+
"""
|
|
286
|
+
ws_url = self.config.api_base_url.replace("http://", "ws://").replace("https://", "wss://")
|
|
287
|
+
ws_url += "/ws/translate"
|
|
288
|
+
|
|
289
|
+
try:
|
|
290
|
+
async with websockets.connect(ws_url) as websocket:
|
|
291
|
+
self._websocket = websocket
|
|
292
|
+
|
|
293
|
+
while True:
|
|
294
|
+
try:
|
|
295
|
+
# Wait for incoming message
|
|
296
|
+
message = await websocket.recv()
|
|
297
|
+
result_data = json.loads(message)
|
|
298
|
+
|
|
299
|
+
# Convert to client result
|
|
300
|
+
translated_data = None
|
|
301
|
+
if result_data.get("translated_data"):
|
|
302
|
+
try:
|
|
303
|
+
translated_data = base64.b64decode(result_data["translated_data"])
|
|
304
|
+
except:
|
|
305
|
+
pass
|
|
306
|
+
|
|
307
|
+
result = ClientTranslationResult(
|
|
308
|
+
success=result_data.get("success", False),
|
|
309
|
+
translated_data=translated_data,
|
|
310
|
+
symbol_families=result_data.get("symbol_families", []),
|
|
311
|
+
errors=result_data.get("errors", [])
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
# Add stats if available
|
|
315
|
+
if "stats" in result_data:
|
|
316
|
+
stats = result_data["stats"]
|
|
317
|
+
result.original_size = stats.get("original_size", 0)
|
|
318
|
+
result.translated_size = stats.get("translated_size", 0)
|
|
319
|
+
result.compression_ratio = stats.get("compression_ratio", 0.0)
|
|
320
|
+
result.efficiency_gain = stats.get("efficiency_gain", 0.0)
|
|
321
|
+
result.symbol_count = stats.get("symbol_count", 0)
|
|
322
|
+
|
|
323
|
+
yield result
|
|
324
|
+
|
|
325
|
+
except websockets.exceptions.ConnectionClosed:
|
|
326
|
+
break
|
|
327
|
+
except json.JSONDecodeError as e:
|
|
328
|
+
yield ClientTranslationResult(success=False, errors=[f"JSON decode error: {e}"])
|
|
329
|
+
except Exception as e:
|
|
330
|
+
yield ClientTranslationResult(success=False, errors=[str(e)])
|
|
331
|
+
|
|
332
|
+
except Exception as e:
|
|
333
|
+
logger.error(f"WebSocket connection error: {e}")
|
|
334
|
+
yield ClientTranslationResult(success=False, errors=[str(e)])
|
|
335
|
+
|
|
336
|
+
async def send_streaming_request(self, request_data: Dict[str, Any]):
|
|
337
|
+
"""
|
|
338
|
+
Send translation request via WebSocket.
|
|
339
|
+
|
|
340
|
+
Args:
|
|
341
|
+
request_data: Translation request data
|
|
342
|
+
"""
|
|
343
|
+
if self._websocket:
|
|
344
|
+
await self._websocket.send(json.dumps(request_data))
|
|
345
|
+
else:
|
|
346
|
+
raise RuntimeError("WebSocket not connected. Use stream_translations() context manager.")
|
|
347
|
+
|
|
348
|
+
# Statistics and service info
|
|
349
|
+
|
|
350
|
+
async def get_compression_stats(self) -> Dict[str, Any]:
|
|
351
|
+
"""Get compression and usage statistics from server."""
|
|
352
|
+
await self._ensure_client()
|
|
353
|
+
|
|
354
|
+
try:
|
|
355
|
+
response = await self._client.get("/stats")
|
|
356
|
+
response.raise_for_status()
|
|
357
|
+
return response.json()
|
|
358
|
+
except httpx.HTTPError as e:
|
|
359
|
+
logger.error(f"Stats request error: {e}")
|
|
360
|
+
return {"error": str(e)}
|
|
361
|
+
|
|
362
|
+
async def get_service_health(self) -> Dict[str, Any]:
|
|
363
|
+
"""Get service health status."""
|
|
364
|
+
await self._ensure_client()
|
|
365
|
+
|
|
366
|
+
try:
|
|
367
|
+
response = await self._client.get("/health")
|
|
368
|
+
response.raise_for_status()
|
|
369
|
+
return response.json()
|
|
370
|
+
except httpx.HTTPError as e:
|
|
371
|
+
logger.error(f"Health check error: {e}")
|
|
372
|
+
return {"status": "unhealthy", "error": str(e)}
|
|
373
|
+
|
|
374
|
+
async def get_supported_formats(self) -> Dict[str, List[str]]:
|
|
375
|
+
"""Get list of supported translation formats."""
|
|
376
|
+
await self._ensure_client()
|
|
377
|
+
|
|
378
|
+
try:
|
|
379
|
+
response = await self._client.get("/formats")
|
|
380
|
+
response.raise_for_status()
|
|
381
|
+
return response.json()
|
|
382
|
+
except httpx.HTTPError as e:
|
|
383
|
+
logger.error(f"Formats request error: {e}")
|
|
384
|
+
return {"error": str(e)}
|
|
385
|
+
|
|
386
|
+
async def get_symbol_families(self) -> Dict[str, Any]:
|
|
387
|
+
"""Get information about emergent language symbol families."""
|
|
388
|
+
await self._ensure_client()
|
|
389
|
+
|
|
390
|
+
try:
|
|
391
|
+
response = await self._client.get("/symbols")
|
|
392
|
+
response.raise_for_status()
|
|
393
|
+
return response.json()
|
|
394
|
+
except httpx.HTTPError as e:
|
|
395
|
+
logger.error(f"Symbols request error: {e}")
|
|
396
|
+
return {"error": str(e)}
|
|
397
|
+
|
|
398
|
+
# Oracle-Enhanced Methods
|
|
399
|
+
|
|
400
|
+
async def explain_emergent_message(
|
|
401
|
+
self,
|
|
402
|
+
emergent_data: bytes,
|
|
403
|
+
mode: str = "verbose"
|
|
404
|
+
) -> Dict[str, Any]:
|
|
405
|
+
"""
|
|
406
|
+
Get human-readable explanation of emergent language symbols using Oracle.
|
|
407
|
+
|
|
408
|
+
Args:
|
|
409
|
+
emergent_data: Emergent language symbol bytes
|
|
410
|
+
mode: Explanation mode ("glyph", "verbose", "json")
|
|
411
|
+
|
|
412
|
+
Returns:
|
|
413
|
+
Oracle explanation with human-readable description
|
|
414
|
+
"""
|
|
415
|
+
await self._ensure_client()
|
|
416
|
+
|
|
417
|
+
try:
|
|
418
|
+
# Encode as base64 for transport
|
|
419
|
+
encoded_data = base64.b64encode(emergent_data).decode('utf-8')
|
|
420
|
+
|
|
421
|
+
request_data = {
|
|
422
|
+
"emergent_data": encoded_data,
|
|
423
|
+
"mode": mode
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
response = await self._client.post("/oracle/explain", json=request_data)
|
|
427
|
+
response.raise_for_status()
|
|
428
|
+
return response.json()
|
|
429
|
+
|
|
430
|
+
except httpx.HTTPError as e:
|
|
431
|
+
logger.error(f"Oracle explanation error: {e}")
|
|
432
|
+
return {"success": False, "error": str(e)}
|
|
433
|
+
|
|
434
|
+
async def validate_translation(
|
|
435
|
+
self,
|
|
436
|
+
original_data: Union[dict, str],
|
|
437
|
+
emergent_data: bytes
|
|
438
|
+
) -> Dict[str, Any]:
|
|
439
|
+
"""
|
|
440
|
+
Validate translation accuracy using Oracle confidence scoring.
|
|
441
|
+
|
|
442
|
+
Args:
|
|
443
|
+
original_data: Original data that was translated
|
|
444
|
+
emergent_data: Resulting emergent language bytes
|
|
445
|
+
|
|
446
|
+
Returns:
|
|
447
|
+
Validation result with confidence score and Oracle explanation
|
|
448
|
+
"""
|
|
449
|
+
await self._ensure_client()
|
|
450
|
+
|
|
451
|
+
try:
|
|
452
|
+
# Encode as base64 for transport
|
|
453
|
+
encoded_data = base64.b64encode(emergent_data).decode('utf-8')
|
|
454
|
+
|
|
455
|
+
request_data = {
|
|
456
|
+
"original_data": original_data,
|
|
457
|
+
"emergent_data": encoded_data
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
response = await self._client.post("/oracle/validate", json=request_data)
|
|
461
|
+
response.raise_for_status()
|
|
462
|
+
return response.json()
|
|
463
|
+
|
|
464
|
+
except httpx.HTTPError as e:
|
|
465
|
+
logger.error(f"Oracle validation error: {e}")
|
|
466
|
+
return {"success": False, "error": str(e)}
|
|
467
|
+
|
|
468
|
+
async def explain_symbol_families(
|
|
469
|
+
self,
|
|
470
|
+
emergent_data: bytes
|
|
471
|
+
) -> Dict[str, Any]:
|
|
472
|
+
"""
|
|
473
|
+
Get Oracle explanations for symbol families in emergent message.
|
|
474
|
+
|
|
475
|
+
Args:
|
|
476
|
+
emergent_data: Emergent language symbol bytes
|
|
477
|
+
|
|
478
|
+
Returns:
|
|
479
|
+
Dictionary with symbol family explanations and contexts
|
|
480
|
+
"""
|
|
481
|
+
await self._ensure_client()
|
|
482
|
+
|
|
483
|
+
try:
|
|
484
|
+
# Encode as base64 for URL path
|
|
485
|
+
encoded_data = base64.b64encode(emergent_data).decode('utf-8')
|
|
486
|
+
|
|
487
|
+
response = await self._client.get(f"/oracle/symbols/{encoded_data}")
|
|
488
|
+
response.raise_for_status()
|
|
489
|
+
return response.json()
|
|
490
|
+
|
|
491
|
+
except httpx.HTTPError as e:
|
|
492
|
+
logger.error(f"Symbol family explanation error: {e}")
|
|
493
|
+
return {"success": False, "error": str(e)}
|
|
494
|
+
|
|
495
|
+
# Internal helper methods
|
|
496
|
+
|
|
497
|
+
async def _make_translation_request(self, request_data: Dict[str, Any]) -> ClientTranslationResult:
|
|
498
|
+
"""Make translation request with retry logic."""
|
|
499
|
+
last_error = None
|
|
500
|
+
|
|
501
|
+
for attempt in range(self.config.max_retries):
|
|
502
|
+
try:
|
|
503
|
+
response = await self._client.post("/translate", json=request_data)
|
|
504
|
+
response.raise_for_status()
|
|
505
|
+
|
|
506
|
+
result_data = response.json()
|
|
507
|
+
|
|
508
|
+
# Decode translated data if present
|
|
509
|
+
translated_data = None
|
|
510
|
+
if result_data.get("translated_data"):
|
|
511
|
+
try:
|
|
512
|
+
translated_data = base64.b64decode(result_data["translated_data"])
|
|
513
|
+
except:
|
|
514
|
+
# Fallback to string encoding if base64 decode fails
|
|
515
|
+
translated_data = result_data["translated_data"].encode('utf-8')
|
|
516
|
+
|
|
517
|
+
return ClientTranslationResult(
|
|
518
|
+
success=result_data.get("success", False),
|
|
519
|
+
translated_data=translated_data,
|
|
520
|
+
original_size=result_data.get("original_size", 0),
|
|
521
|
+
translated_size=result_data.get("translated_size", 0),
|
|
522
|
+
compression_ratio=result_data.get("compression_ratio", 0.0),
|
|
523
|
+
efficiency_gain=result_data.get("efficiency_gain", 0.0),
|
|
524
|
+
translation_time_ms=result_data.get("translation_time_ms", 0.0),
|
|
525
|
+
symbol_count=result_data.get("symbol_count", 0),
|
|
526
|
+
symbol_families=result_data.get("symbol_families", []),
|
|
527
|
+
metadata=result_data.get("metadata", {}),
|
|
528
|
+
errors=result_data.get("errors", [])
|
|
529
|
+
)
|
|
530
|
+
|
|
531
|
+
except httpx.HTTPError as e:
|
|
532
|
+
last_error = e
|
|
533
|
+
if attempt < self.config.max_retries - 1:
|
|
534
|
+
await asyncio.sleep(self.config.retry_delay)
|
|
535
|
+
continue
|
|
536
|
+
else:
|
|
537
|
+
logger.error(f"Translation request failed after {self.config.max_retries} attempts: {e}")
|
|
538
|
+
break
|
|
539
|
+
|
|
540
|
+
except Exception as e:
|
|
541
|
+
last_error = e
|
|
542
|
+
logger.error(f"Unexpected translation error: {e}")
|
|
543
|
+
break
|
|
544
|
+
|
|
545
|
+
return ClientTranslationResult(
|
|
546
|
+
success=False,
|
|
547
|
+
errors=[str(last_error)] if last_error else ["Unknown error"]
|
|
548
|
+
)
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
class SyncEmergentTranslatorClient:
|
|
552
|
+
"""
|
|
553
|
+
Synchronous client for Emergent Language Translator API.
|
|
554
|
+
|
|
555
|
+
Wrapper around async client for synchronous usage.
|
|
556
|
+
"""
|
|
557
|
+
|
|
558
|
+
def __init__(self, config: Optional[TranslationConfig] = None):
|
|
559
|
+
"""Initialize sync client."""
|
|
560
|
+
self.config = config or TranslationConfig()
|
|
561
|
+
self._async_client = EmergentTranslatorClient(config)
|
|
562
|
+
|
|
563
|
+
def __enter__(self):
|
|
564
|
+
"""Sync context manager entry."""
|
|
565
|
+
return self
|
|
566
|
+
|
|
567
|
+
def __exit__(self, exc_type, exc_val, exc_tb):
|
|
568
|
+
"""Sync context manager exit."""
|
|
569
|
+
asyncio.run(self._async_client.close())
|
|
570
|
+
|
|
571
|
+
def translate_json(self, data: Union[dict, str], **kwargs) -> ClientTranslationResult:
|
|
572
|
+
"""Sync version of translate_json."""
|
|
573
|
+
return asyncio.run(self._async_client.translate_json(data, **kwargs))
|
|
574
|
+
|
|
575
|
+
def translate_text(self, text: str, **kwargs) -> ClientTranslationResult:
|
|
576
|
+
"""Sync version of translate_text."""
|
|
577
|
+
return asyncio.run(self._async_client.translate_text(text, **kwargs))
|
|
578
|
+
|
|
579
|
+
def translate_from_emergent(self, symbol_data: bytes, **kwargs) -> ClientTranslationResult:
|
|
580
|
+
"""Sync version of translate_from_emergent."""
|
|
581
|
+
return asyncio.run(self._async_client.translate_from_emergent(symbol_data, **kwargs))
|
|
582
|
+
|
|
583
|
+
def translate_batch(self, requests: List[Dict[str, Any]], **kwargs) -> List[ClientTranslationResult]:
|
|
584
|
+
"""Sync version of translate_batch."""
|
|
585
|
+
return asyncio.run(self._async_client.translate_batch(requests, **kwargs))
|
|
586
|
+
|
|
587
|
+
def get_compression_stats(self) -> Dict[str, Any]:
|
|
588
|
+
"""Sync version of get_compression_stats."""
|
|
589
|
+
return asyncio.run(self._async_client.get_compression_stats())
|
|
590
|
+
|
|
591
|
+
def get_service_health(self) -> Dict[str, Any]:
|
|
592
|
+
"""Sync version of get_service_health."""
|
|
593
|
+
return asyncio.run(self._async_client.get_service_health())
|
|
594
|
+
|
|
595
|
+
# Oracle-Enhanced Sync Methods
|
|
596
|
+
|
|
597
|
+
def explain_emergent_message(self, emergent_data: bytes, mode: str = "verbose") -> Dict[str, Any]:
|
|
598
|
+
"""Sync version of explain_emergent_message."""
|
|
599
|
+
return asyncio.run(self._async_client.explain_emergent_message(emergent_data, mode))
|
|
600
|
+
|
|
601
|
+
def validate_translation(self, original_data: Union[dict, str], emergent_data: bytes) -> Dict[str, Any]:
|
|
602
|
+
"""Sync version of validate_translation."""
|
|
603
|
+
return asyncio.run(self._async_client.validate_translation(original_data, emergent_data))
|
|
604
|
+
|
|
605
|
+
def explain_symbol_families(self, emergent_data: bytes) -> Dict[str, Any]:
|
|
606
|
+
"""Sync version of explain_symbol_families."""
|
|
607
|
+
return asyncio.run(self._async_client.explain_symbol_families(emergent_data))
|
|
608
|
+
|
|
609
|
+
|
|
610
|
+
# High-level SDK class
|
|
611
|
+
|
|
612
|
+
class TranslatorSDK:
|
|
613
|
+
"""
|
|
614
|
+
High-level SDK for Emergent Language Translation.
|
|
615
|
+
|
|
616
|
+
Provides the simplest possible interface for external AIs to integrate
|
|
617
|
+
with Eudaimonia's emergent language system.
|
|
618
|
+
|
|
619
|
+
Example:
|
|
620
|
+
sdk = TranslatorSDK(api_url="https://translator.eudaimonia.ai")
|
|
621
|
+
|
|
622
|
+
# Compress JSON data
|
|
623
|
+
compressed = sdk.compress({"task": "analyze market"})
|
|
624
|
+
print(f"60x smaller: {len(compressed)} bytes")
|
|
625
|
+
|
|
626
|
+
# Decompress back to JSON
|
|
627
|
+
original = sdk.decompress(compressed, format="json")
|
|
628
|
+
"""
|
|
629
|
+
|
|
630
|
+
def __init__(self, api_url: str = "http://localhost:8000", auth_token: Optional[str] = None, api_key: Optional[str] = None):
|
|
631
|
+
"""
|
|
632
|
+
Initialize SDK with API configuration.
|
|
633
|
+
|
|
634
|
+
Args:
|
|
635
|
+
api_url: Base URL of the translator API
|
|
636
|
+
auth_token: Optional authentication token
|
|
637
|
+
api_key: Alias for auth_token (for CLI compatibility)
|
|
638
|
+
"""
|
|
639
|
+
token = auth_token or api_key
|
|
640
|
+
self.api_url = api_url
|
|
641
|
+
config = TranslationConfig(api_base_url=api_url, auth_token=token)
|
|
642
|
+
self.client = SyncEmergentTranslatorClient(config)
|
|
643
|
+
|
|
644
|
+
def compress(
|
|
645
|
+
self,
|
|
646
|
+
data: Union[dict, str],
|
|
647
|
+
intent: str = "general"
|
|
648
|
+
) -> bytes:
|
|
649
|
+
"""
|
|
650
|
+
Compress data to emergent language symbols.
|
|
651
|
+
|
|
652
|
+
Args:
|
|
653
|
+
data: JSON data or text string to compress
|
|
654
|
+
intent: Intent type for better compression
|
|
655
|
+
|
|
656
|
+
Returns:
|
|
657
|
+
Compressed emergent language bytes (typically 60x smaller)
|
|
658
|
+
"""
|
|
659
|
+
if isinstance(data, dict):
|
|
660
|
+
result = self.client.translate_json(data, intent_type=intent)
|
|
661
|
+
elif isinstance(data, str):
|
|
662
|
+
result = self.client.translate_text(data, intent_type=intent)
|
|
663
|
+
else:
|
|
664
|
+
raise ValueError("Data must be dict or str")
|
|
665
|
+
|
|
666
|
+
if not result.success:
|
|
667
|
+
raise RuntimeError(f"Compression failed: {', '.join(result.errors)}")
|
|
668
|
+
|
|
669
|
+
return result.translated_data
|
|
670
|
+
|
|
671
|
+
def decompress(self, compressed_data: bytes, format: str = "json") -> Union[dict, str]:
|
|
672
|
+
"""
|
|
673
|
+
Decompress emergent language symbols back to readable format.
|
|
674
|
+
|
|
675
|
+
Args:
|
|
676
|
+
compressed_data: Emergent language symbol bytes
|
|
677
|
+
format: Target format (json, text)
|
|
678
|
+
|
|
679
|
+
Returns:
|
|
680
|
+
Decompressed data
|
|
681
|
+
"""
|
|
682
|
+
result = self.client.translate_from_emergent(compressed_data, target_format=format)
|
|
683
|
+
|
|
684
|
+
if not result.success:
|
|
685
|
+
raise RuntimeError(f"Decompression failed: {', '.join(result.errors)}")
|
|
686
|
+
|
|
687
|
+
if format == "json":
|
|
688
|
+
try:
|
|
689
|
+
return json.loads(result.translated_data.decode('utf-8'))
|
|
690
|
+
except:
|
|
691
|
+
return {"data": result.translated_data.decode('utf-8', errors='ignore')}
|
|
692
|
+
else:
|
|
693
|
+
return result.translated_data.decode('utf-8', errors='ignore')
|
|
694
|
+
|
|
695
|
+
def get_compression_ratio(self, data: Union[dict, str]) -> float:
|
|
696
|
+
"""
|
|
697
|
+
Get compression ratio without actually compressing (estimate).
|
|
698
|
+
|
|
699
|
+
Args:
|
|
700
|
+
data: Data to analyze
|
|
701
|
+
|
|
702
|
+
Returns:
|
|
703
|
+
Estimated compression ratio (e.g., 0.016 for 60x compression)
|
|
704
|
+
"""
|
|
705
|
+
if isinstance(data, dict):
|
|
706
|
+
original_size = len(json.dumps(data))
|
|
707
|
+
else:
|
|
708
|
+
original_size = len(data.encode('utf-8'))
|
|
709
|
+
|
|
710
|
+
# Typical emergent language message is 8-16 bytes
|
|
711
|
+
estimated_compressed_size = 12
|
|
712
|
+
|
|
713
|
+
return estimated_compressed_size / original_size
|
|
714
|
+
|
|
715
|
+
def get_stats(self) -> Dict[str, Any]:
|
|
716
|
+
"""Get compression statistics from the service."""
|
|
717
|
+
return self.client.get_compression_stats()
|
|
718
|
+
|
|
719
|
+
def get_health(self) -> Dict[str, Any]:
|
|
720
|
+
"""Get full health status from the service."""
|
|
721
|
+
return self.client.get_service_health()
|
|
722
|
+
|
|
723
|
+
def is_healthy(self) -> bool:
|
|
724
|
+
"""Check if the translator service is healthy."""
|
|
725
|
+
health = self.get_health()
|
|
726
|
+
return health.get("status") == "healthy"
|
|
727
|
+
|
|
728
|
+
# Oracle-Powered Methods
|
|
729
|
+
|
|
730
|
+
def explain(self, compressed_data: bytes, mode: str = "verbose") -> str:
|
|
731
|
+
"""
|
|
732
|
+
Get human explanation of compressed emergent data.
|
|
733
|
+
|
|
734
|
+
Args:
|
|
735
|
+
compressed_data: Emergent language bytes
|
|
736
|
+
mode: Explanation mode ("glyph", "verbose", "json")
|
|
737
|
+
|
|
738
|
+
Returns:
|
|
739
|
+
Human-readable explanation of what the symbols mean
|
|
740
|
+
"""
|
|
741
|
+
result = self.client.explain_emergent_message(compressed_data, mode)
|
|
742
|
+
if result.get("success"):
|
|
743
|
+
return result.get("explanation", "No explanation available")
|
|
744
|
+
else:
|
|
745
|
+
raise RuntimeError(f"Oracle explanation failed: {result.get('error', 'Unknown error')}")
|
|
746
|
+
|
|
747
|
+
def validate(self, original_data: Union[dict, str], compressed_data: bytes) -> float:
|
|
748
|
+
"""
|
|
749
|
+
Validate that compressed data preserves the meaning of original data.
|
|
750
|
+
|
|
751
|
+
Args:
|
|
752
|
+
original_data: Original data before compression
|
|
753
|
+
compressed_data: Compressed emergent language bytes
|
|
754
|
+
|
|
755
|
+
Returns:
|
|
756
|
+
Confidence score (0.0-1.0) indicating translation accuracy
|
|
757
|
+
"""
|
|
758
|
+
result = self.client.validate_translation(original_data, compressed_data)
|
|
759
|
+
if result.get("success") and result.get("validation_available"):
|
|
760
|
+
return result.get("confidence_score", 0.0)
|
|
761
|
+
else:
|
|
762
|
+
raise RuntimeError(f"Oracle validation failed: {result.get('error', 'Unknown error')}")
|
|
763
|
+
|
|
764
|
+
def get_symbol_info(self, compressed_data: bytes) -> Dict[str, str]:
|
|
765
|
+
"""
|
|
766
|
+
Get detailed information about symbol families in compressed data.
|
|
767
|
+
|
|
768
|
+
Args:
|
|
769
|
+
compressed_data: Emergent language bytes
|
|
770
|
+
|
|
771
|
+
Returns:
|
|
772
|
+
Dictionary mapping symbol families to their explanations
|
|
773
|
+
"""
|
|
774
|
+
result = self.client.explain_symbol_families(compressed_data)
|
|
775
|
+
if result.get("success"):
|
|
776
|
+
return result.get("symbol_families", {})
|
|
777
|
+
else:
|
|
778
|
+
raise RuntimeError(f"Symbol explanation failed: {result.get('error', 'Unknown error')}")
|
|
779
|
+
|
|
780
|
+
def compress_with_explanation(
|
|
781
|
+
self,
|
|
782
|
+
data: Union[dict, str],
|
|
783
|
+
intent: str = "general"
|
|
784
|
+
) -> Tuple[bytes, str]:
|
|
785
|
+
"""
|
|
786
|
+
Compress data and get Oracle explanation in one call.
|
|
787
|
+
|
|
788
|
+
Args:
|
|
789
|
+
data: Data to compress
|
|
790
|
+
intent: Intent type for optimization
|
|
791
|
+
|
|
792
|
+
Returns:
|
|
793
|
+
Tuple of (compressed_bytes, human_explanation)
|
|
794
|
+
"""
|
|
795
|
+
# Compress the data
|
|
796
|
+
compressed = self.compress(data, intent)
|
|
797
|
+
|
|
798
|
+
# Get Oracle explanation
|
|
799
|
+
explanation = self.explain(compressed)
|
|
800
|
+
|
|
801
|
+
return compressed, explanation
|
|
802
|
+
|
|
803
|
+
|
|
804
|
+
# Convenience functions for quick usage
|
|
805
|
+
|
|
806
|
+
def compress_json(data: dict, api_url: str = "http://localhost:8000") -> bytes:
|
|
807
|
+
"""
|
|
808
|
+
Quick function to compress JSON data.
|
|
809
|
+
|
|
810
|
+
Args:
|
|
811
|
+
data: JSON data to compress
|
|
812
|
+
api_url: Translator API URL
|
|
813
|
+
|
|
814
|
+
Returns:
|
|
815
|
+
Compressed emergent language bytes
|
|
816
|
+
"""
|
|
817
|
+
sdk = TranslatorSDK(api_url)
|
|
818
|
+
return sdk.compress(data)
|
|
819
|
+
|
|
820
|
+
|
|
821
|
+
def decompress_to_json(compressed_data: bytes, api_url: str = "http://localhost:8000") -> dict:
|
|
822
|
+
"""
|
|
823
|
+
Quick function to decompress to JSON.
|
|
824
|
+
|
|
825
|
+
Args:
|
|
826
|
+
compressed_data: Emergent language bytes
|
|
827
|
+
api_url: Translator API URL
|
|
828
|
+
|
|
829
|
+
Returns:
|
|
830
|
+
Decompressed JSON data
|
|
831
|
+
"""
|
|
832
|
+
sdk = TranslatorSDK(api_url)
|
|
833
|
+
return sdk.decompress(compressed_data, format="json")
|
|
834
|
+
|
|
835
|
+
|
|
836
|
+
# Oracle-Enhanced Convenience Functions
|
|
837
|
+
|
|
838
|
+
def explain_emergent(compressed_data: bytes, api_url: str = "http://localhost:8000") -> str:
|
|
839
|
+
"""
|
|
840
|
+
Quick function to get Oracle explanation of emergent data.
|
|
841
|
+
|
|
842
|
+
Args:
|
|
843
|
+
compressed_data: Emergent language bytes
|
|
844
|
+
api_url: Translator API URL
|
|
845
|
+
|
|
846
|
+
Returns:
|
|
847
|
+
Human-readable explanation
|
|
848
|
+
"""
|
|
849
|
+
sdk = TranslatorSDK(api_url)
|
|
850
|
+
return sdk.explain(compressed_data)
|
|
851
|
+
|
|
852
|
+
|
|
853
|
+
def validate_compression(
|
|
854
|
+
original_data: Union[dict, str],
|
|
855
|
+
compressed_data: bytes,
|
|
856
|
+
api_url: str = "http://localhost:8000"
|
|
857
|
+
) -> float:
|
|
858
|
+
"""
|
|
859
|
+
Quick function to validate compression accuracy.
|
|
860
|
+
|
|
861
|
+
Args:
|
|
862
|
+
original_data: Original data
|
|
863
|
+
compressed_data: Compressed bytes
|
|
864
|
+
api_url: Translator API URL
|
|
865
|
+
|
|
866
|
+
Returns:
|
|
867
|
+
Confidence score (0.0-1.0)
|
|
868
|
+
"""
|
|
869
|
+
sdk = TranslatorSDK(api_url)
|
|
870
|
+
return sdk.validate(original_data, compressed_data)
|
|
871
|
+
|
|
872
|
+
|
|
873
|
+
def compress_with_oracle(
|
|
874
|
+
data: Union[dict, str],
|
|
875
|
+
api_url: str = "http://localhost:8000"
|
|
876
|
+
) -> Tuple[bytes, str]:
|
|
877
|
+
"""
|
|
878
|
+
Quick function to compress data and get Oracle explanation.
|
|
879
|
+
|
|
880
|
+
Args:
|
|
881
|
+
data: Data to compress
|
|
882
|
+
api_url: Translator API URL
|
|
883
|
+
|
|
884
|
+
Returns:
|
|
885
|
+
Tuple of (compressed_bytes, explanation)
|
|
886
|
+
"""
|
|
887
|
+
sdk = TranslatorSDK(api_url)
|
|
888
|
+
return sdk.compress_with_explanation(data)
|
|
889
|
+
|
|
890
|
+
|
|
891
|
+
# Export main classes
|
|
892
|
+
__all__ = [
|
|
893
|
+
'EmergentTranslatorClient',
|
|
894
|
+
'SyncEmergentTranslatorClient',
|
|
895
|
+
'TranslatorSDK',
|
|
896
|
+
'TranslationConfig',
|
|
897
|
+
'ClientTranslationResult',
|
|
898
|
+
'compress_json',
|
|
899
|
+
'decompress_to_json',
|
|
900
|
+
'explain_emergent',
|
|
901
|
+
'validate_compression',
|
|
902
|
+
'compress_with_oracle'
|
|
903
|
+
]
|