mcli-framework 7.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.

Potentially problematic release.


This version of mcli-framework might be problematic. Click here for more details.

Files changed (186) hide show
  1. mcli/app/chat_cmd.py +42 -0
  2. mcli/app/commands_cmd.py +226 -0
  3. mcli/app/completion_cmd.py +216 -0
  4. mcli/app/completion_helpers.py +288 -0
  5. mcli/app/cron_test_cmd.py +697 -0
  6. mcli/app/logs_cmd.py +419 -0
  7. mcli/app/main.py +492 -0
  8. mcli/app/model/model.py +1060 -0
  9. mcli/app/model_cmd.py +227 -0
  10. mcli/app/redis_cmd.py +269 -0
  11. mcli/app/video/video.py +1114 -0
  12. mcli/app/visual_cmd.py +303 -0
  13. mcli/chat/chat.py +2409 -0
  14. mcli/chat/command_rag.py +514 -0
  15. mcli/chat/enhanced_chat.py +652 -0
  16. mcli/chat/system_controller.py +1010 -0
  17. mcli/chat/system_integration.py +1016 -0
  18. mcli/cli.py +25 -0
  19. mcli/config.toml +20 -0
  20. mcli/lib/api/api.py +586 -0
  21. mcli/lib/api/daemon_client.py +203 -0
  22. mcli/lib/api/daemon_client_local.py +44 -0
  23. mcli/lib/api/daemon_decorator.py +217 -0
  24. mcli/lib/api/mcli_decorators.py +1032 -0
  25. mcli/lib/auth/auth.py +85 -0
  26. mcli/lib/auth/aws_manager.py +85 -0
  27. mcli/lib/auth/azure_manager.py +91 -0
  28. mcli/lib/auth/credential_manager.py +192 -0
  29. mcli/lib/auth/gcp_manager.py +93 -0
  30. mcli/lib/auth/key_manager.py +117 -0
  31. mcli/lib/auth/mcli_manager.py +93 -0
  32. mcli/lib/auth/token_manager.py +75 -0
  33. mcli/lib/auth/token_util.py +1011 -0
  34. mcli/lib/config/config.py +47 -0
  35. mcli/lib/discovery/__init__.py +1 -0
  36. mcli/lib/discovery/command_discovery.py +274 -0
  37. mcli/lib/erd/erd.py +1345 -0
  38. mcli/lib/erd/generate_graph.py +453 -0
  39. mcli/lib/files/files.py +76 -0
  40. mcli/lib/fs/fs.py +109 -0
  41. mcli/lib/lib.py +29 -0
  42. mcli/lib/logger/logger.py +611 -0
  43. mcli/lib/performance/optimizer.py +409 -0
  44. mcli/lib/performance/rust_bridge.py +502 -0
  45. mcli/lib/performance/uvloop_config.py +154 -0
  46. mcli/lib/pickles/pickles.py +50 -0
  47. mcli/lib/search/cached_vectorizer.py +479 -0
  48. mcli/lib/services/data_pipeline.py +460 -0
  49. mcli/lib/services/lsh_client.py +441 -0
  50. mcli/lib/services/redis_service.py +387 -0
  51. mcli/lib/shell/shell.py +137 -0
  52. mcli/lib/toml/toml.py +33 -0
  53. mcli/lib/ui/styling.py +47 -0
  54. mcli/lib/ui/visual_effects.py +634 -0
  55. mcli/lib/watcher/watcher.py +185 -0
  56. mcli/ml/api/app.py +215 -0
  57. mcli/ml/api/middleware.py +224 -0
  58. mcli/ml/api/routers/admin_router.py +12 -0
  59. mcli/ml/api/routers/auth_router.py +244 -0
  60. mcli/ml/api/routers/backtest_router.py +12 -0
  61. mcli/ml/api/routers/data_router.py +12 -0
  62. mcli/ml/api/routers/model_router.py +302 -0
  63. mcli/ml/api/routers/monitoring_router.py +12 -0
  64. mcli/ml/api/routers/portfolio_router.py +12 -0
  65. mcli/ml/api/routers/prediction_router.py +267 -0
  66. mcli/ml/api/routers/trade_router.py +12 -0
  67. mcli/ml/api/routers/websocket_router.py +76 -0
  68. mcli/ml/api/schemas.py +64 -0
  69. mcli/ml/auth/auth_manager.py +425 -0
  70. mcli/ml/auth/models.py +154 -0
  71. mcli/ml/auth/permissions.py +302 -0
  72. mcli/ml/backtesting/backtest_engine.py +502 -0
  73. mcli/ml/backtesting/performance_metrics.py +393 -0
  74. mcli/ml/cache.py +400 -0
  75. mcli/ml/cli/main.py +398 -0
  76. mcli/ml/config/settings.py +394 -0
  77. mcli/ml/configs/dvc_config.py +230 -0
  78. mcli/ml/configs/mlflow_config.py +131 -0
  79. mcli/ml/configs/mlops_manager.py +293 -0
  80. mcli/ml/dashboard/app.py +532 -0
  81. mcli/ml/dashboard/app_integrated.py +738 -0
  82. mcli/ml/dashboard/app_supabase.py +560 -0
  83. mcli/ml/dashboard/app_training.py +615 -0
  84. mcli/ml/dashboard/cli.py +51 -0
  85. mcli/ml/data_ingestion/api_connectors.py +501 -0
  86. mcli/ml/data_ingestion/data_pipeline.py +567 -0
  87. mcli/ml/data_ingestion/stream_processor.py +512 -0
  88. mcli/ml/database/migrations/env.py +94 -0
  89. mcli/ml/database/models.py +667 -0
  90. mcli/ml/database/session.py +200 -0
  91. mcli/ml/experimentation/ab_testing.py +845 -0
  92. mcli/ml/features/ensemble_features.py +607 -0
  93. mcli/ml/features/political_features.py +676 -0
  94. mcli/ml/features/recommendation_engine.py +809 -0
  95. mcli/ml/features/stock_features.py +573 -0
  96. mcli/ml/features/test_feature_engineering.py +346 -0
  97. mcli/ml/logging.py +85 -0
  98. mcli/ml/mlops/data_versioning.py +518 -0
  99. mcli/ml/mlops/experiment_tracker.py +377 -0
  100. mcli/ml/mlops/model_serving.py +481 -0
  101. mcli/ml/mlops/pipeline_orchestrator.py +614 -0
  102. mcli/ml/models/base_models.py +324 -0
  103. mcli/ml/models/ensemble_models.py +675 -0
  104. mcli/ml/models/recommendation_models.py +474 -0
  105. mcli/ml/models/test_models.py +487 -0
  106. mcli/ml/monitoring/drift_detection.py +676 -0
  107. mcli/ml/monitoring/metrics.py +45 -0
  108. mcli/ml/optimization/portfolio_optimizer.py +834 -0
  109. mcli/ml/preprocessing/data_cleaners.py +451 -0
  110. mcli/ml/preprocessing/feature_extractors.py +491 -0
  111. mcli/ml/preprocessing/ml_pipeline.py +382 -0
  112. mcli/ml/preprocessing/politician_trading_preprocessor.py +569 -0
  113. mcli/ml/preprocessing/test_preprocessing.py +294 -0
  114. mcli/ml/scripts/populate_sample_data.py +200 -0
  115. mcli/ml/tasks.py +400 -0
  116. mcli/ml/tests/test_integration.py +429 -0
  117. mcli/ml/tests/test_training_dashboard.py +387 -0
  118. mcli/public/oi/oi.py +15 -0
  119. mcli/public/public.py +4 -0
  120. mcli/self/self_cmd.py +1246 -0
  121. mcli/workflow/daemon/api_daemon.py +800 -0
  122. mcli/workflow/daemon/async_command_database.py +681 -0
  123. mcli/workflow/daemon/async_process_manager.py +591 -0
  124. mcli/workflow/daemon/client.py +530 -0
  125. mcli/workflow/daemon/commands.py +1196 -0
  126. mcli/workflow/daemon/daemon.py +905 -0
  127. mcli/workflow/daemon/daemon_api.py +59 -0
  128. mcli/workflow/daemon/enhanced_daemon.py +571 -0
  129. mcli/workflow/daemon/process_cli.py +244 -0
  130. mcli/workflow/daemon/process_manager.py +439 -0
  131. mcli/workflow/daemon/test_daemon.py +275 -0
  132. mcli/workflow/dashboard/dashboard_cmd.py +113 -0
  133. mcli/workflow/docker/docker.py +0 -0
  134. mcli/workflow/file/file.py +100 -0
  135. mcli/workflow/gcloud/config.toml +21 -0
  136. mcli/workflow/gcloud/gcloud.py +58 -0
  137. mcli/workflow/git_commit/ai_service.py +328 -0
  138. mcli/workflow/git_commit/commands.py +430 -0
  139. mcli/workflow/lsh_integration.py +355 -0
  140. mcli/workflow/model_service/client.py +594 -0
  141. mcli/workflow/model_service/download_and_run_efficient_models.py +288 -0
  142. mcli/workflow/model_service/lightweight_embedder.py +397 -0
  143. mcli/workflow/model_service/lightweight_model_server.py +714 -0
  144. mcli/workflow/model_service/lightweight_test.py +241 -0
  145. mcli/workflow/model_service/model_service.py +1955 -0
  146. mcli/workflow/model_service/ollama_efficient_runner.py +425 -0
  147. mcli/workflow/model_service/pdf_processor.py +386 -0
  148. mcli/workflow/model_service/test_efficient_runner.py +234 -0
  149. mcli/workflow/model_service/test_example.py +315 -0
  150. mcli/workflow/model_service/test_integration.py +131 -0
  151. mcli/workflow/model_service/test_new_features.py +149 -0
  152. mcli/workflow/openai/openai.py +99 -0
  153. mcli/workflow/politician_trading/commands.py +1790 -0
  154. mcli/workflow/politician_trading/config.py +134 -0
  155. mcli/workflow/politician_trading/connectivity.py +490 -0
  156. mcli/workflow/politician_trading/data_sources.py +395 -0
  157. mcli/workflow/politician_trading/database.py +410 -0
  158. mcli/workflow/politician_trading/demo.py +248 -0
  159. mcli/workflow/politician_trading/models.py +165 -0
  160. mcli/workflow/politician_trading/monitoring.py +413 -0
  161. mcli/workflow/politician_trading/scrapers.py +966 -0
  162. mcli/workflow/politician_trading/scrapers_california.py +412 -0
  163. mcli/workflow/politician_trading/scrapers_eu.py +377 -0
  164. mcli/workflow/politician_trading/scrapers_uk.py +350 -0
  165. mcli/workflow/politician_trading/scrapers_us_states.py +438 -0
  166. mcli/workflow/politician_trading/supabase_functions.py +354 -0
  167. mcli/workflow/politician_trading/workflow.py +852 -0
  168. mcli/workflow/registry/registry.py +180 -0
  169. mcli/workflow/repo/repo.py +223 -0
  170. mcli/workflow/scheduler/commands.py +493 -0
  171. mcli/workflow/scheduler/cron_parser.py +238 -0
  172. mcli/workflow/scheduler/job.py +182 -0
  173. mcli/workflow/scheduler/monitor.py +139 -0
  174. mcli/workflow/scheduler/persistence.py +324 -0
  175. mcli/workflow/scheduler/scheduler.py +679 -0
  176. mcli/workflow/sync/sync_cmd.py +437 -0
  177. mcli/workflow/sync/test_cmd.py +314 -0
  178. mcli/workflow/videos/videos.py +242 -0
  179. mcli/workflow/wakatime/wakatime.py +11 -0
  180. mcli/workflow/workflow.py +37 -0
  181. mcli_framework-7.0.0.dist-info/METADATA +479 -0
  182. mcli_framework-7.0.0.dist-info/RECORD +186 -0
  183. mcli_framework-7.0.0.dist-info/WHEEL +5 -0
  184. mcli_framework-7.0.0.dist-info/entry_points.txt +7 -0
  185. mcli_framework-7.0.0.dist-info/licenses/LICENSE +21 -0
  186. mcli_framework-7.0.0.dist-info/top_level.txt +1 -0
mcli/ml/cache.py ADDED
@@ -0,0 +1,400 @@
1
+ """Redis caching layer for ML system"""
2
+
3
+ import json
4
+ import pickle
5
+ import hashlib
6
+ import asyncio
7
+ from typing import Optional, Any, Union, Callable
8
+ from functools import wraps
9
+ from datetime import timedelta
10
+
11
+ import redis
12
+ from redis import asyncio as aioredis
13
+
14
+ from mcli.ml.config import settings
15
+ from mcli.ml.logging import get_logger
16
+
17
+ logger = get_logger(__name__)
18
+
19
+
20
+ class CacheManager:
21
+ """Manage Redis cache connections and operations"""
22
+
23
+ def __init__(self):
24
+ self.redis_client: Optional[redis.Redis] = None
25
+ self.async_redis_client: Optional[aioredis.Redis] = None
26
+ self._initialized = False
27
+
28
+ def initialize(self):
29
+ """Initialize Redis connections"""
30
+ if self._initialized:
31
+ return
32
+
33
+ try:
34
+ # Sync Redis client
35
+ self.redis_client = redis.Redis(
36
+ host=settings.redis.host,
37
+ port=settings.redis.port,
38
+ db=settings.redis.db,
39
+ password=settings.redis.password,
40
+ decode_responses=False,
41
+ socket_connect_timeout=5,
42
+ socket_timeout=5,
43
+ connection_pool=redis.ConnectionPool(
44
+ host=settings.redis.host,
45
+ port=settings.redis.port,
46
+ db=settings.redis.db,
47
+ password=settings.redis.password,
48
+ max_connections=settings.redis.max_connections
49
+ )
50
+ )
51
+
52
+ # Test connection
53
+ self.redis_client.ping()
54
+ self._initialized = True
55
+ logger.info("Cache manager initialized successfully")
56
+
57
+ except Exception as e:
58
+ logger.error(f"Failed to initialize cache: {e}")
59
+ self.redis_client = None
60
+
61
+ async def initialize_async(self):
62
+ """Initialize async Redis connection"""
63
+ if self.async_redis_client:
64
+ return
65
+
66
+ try:
67
+ self.async_redis_client = await aioredis.from_url(
68
+ settings.redis.url,
69
+ encoding="utf-8",
70
+ decode_responses=False,
71
+ max_connections=settings.redis.max_connections
72
+ )
73
+
74
+ # Test connection
75
+ await self.async_redis_client.ping()
76
+ logger.info("Async cache manager initialized successfully")
77
+
78
+ except Exception as e:
79
+ logger.error(f"Failed to initialize async cache: {e}")
80
+ self.async_redis_client = None
81
+
82
+ def _make_key(self, key: str, prefix: str = "mcli:ml:") -> str:
83
+ """Create cache key with prefix"""
84
+ return f"{prefix}{key}"
85
+
86
+ def _serialize(self, value: Any) -> bytes:
87
+ """Serialize value for storage"""
88
+ try:
89
+ # Try JSON first (for simple types)
90
+ if isinstance(value, (dict, list, str, int, float, bool, type(None))):
91
+ return json.dumps(value).encode('utf-8')
92
+ except:
93
+ pass
94
+
95
+ # Fall back to pickle for complex objects
96
+ return pickle.dumps(value)
97
+
98
+ def _deserialize(self, value: bytes) -> Any:
99
+ """Deserialize value from storage"""
100
+ if value is None:
101
+ return None
102
+
103
+ # Try JSON first
104
+ try:
105
+ return json.loads(value.decode('utf-8'))
106
+ except:
107
+ pass
108
+
109
+ # Fall back to pickle
110
+ try:
111
+ return pickle.loads(value)
112
+ except:
113
+ logger.error("Failed to deserialize cache value")
114
+ return None
115
+
116
+ def set(self, key: str, value: Any, expire: int = 3600) -> bool:
117
+ """Set cache value"""
118
+ if not self.redis_client:
119
+ self.initialize()
120
+
121
+ if not self.redis_client:
122
+ return False
123
+
124
+ try:
125
+ cache_key = self._make_key(key)
126
+ serialized_value = self._serialize(value)
127
+ return self.redis_client.setex(cache_key, expire, serialized_value)
128
+ except Exception as e:
129
+ logger.error(f"Cache set error: {e}")
130
+ return False
131
+
132
+ def get(self, key: str) -> Any:
133
+ """Get cache value"""
134
+ if not self.redis_client:
135
+ self.initialize()
136
+
137
+ if not self.redis_client:
138
+ return None
139
+
140
+ try:
141
+ cache_key = self._make_key(key)
142
+ value = self.redis_client.get(cache_key)
143
+ return self._deserialize(value)
144
+ except Exception as e:
145
+ logger.error(f"Cache get error: {e}")
146
+ return None
147
+
148
+ async def set_async(self, key: str, value: Any, expire: int = 3600) -> bool:
149
+ """Set cache value asynchronously"""
150
+ if not self.async_redis_client:
151
+ await self.initialize_async()
152
+
153
+ if not self.async_redis_client:
154
+ return False
155
+
156
+ try:
157
+ cache_key = self._make_key(key)
158
+ serialized_value = self._serialize(value)
159
+ await self.async_redis_client.setex(cache_key, expire, serialized_value)
160
+ return True
161
+ except Exception as e:
162
+ logger.error(f"Async cache set error: {e}")
163
+ return False
164
+
165
+ async def get_async(self, key: str) -> Any:
166
+ """Get cache value asynchronously"""
167
+ if not self.async_redis_client:
168
+ await self.initialize_async()
169
+
170
+ if not self.async_redis_client:
171
+ return None
172
+
173
+ try:
174
+ cache_key = self._make_key(key)
175
+ value = await self.async_redis_client.get(cache_key)
176
+ return self._deserialize(value) if value else None
177
+ except Exception as e:
178
+ logger.error(f"Async cache get error: {e}")
179
+ return None
180
+
181
+ def delete(self, key: str) -> bool:
182
+ """Delete cache entry"""
183
+ if not self.redis_client:
184
+ return False
185
+
186
+ try:
187
+ cache_key = self._make_key(key)
188
+ return bool(self.redis_client.delete(cache_key))
189
+ except Exception as e:
190
+ logger.error(f"Cache delete error: {e}")
191
+ return False
192
+
193
+ async def delete_async(self, key: str) -> bool:
194
+ """Delete cache entry asynchronously"""
195
+ if not self.async_redis_client:
196
+ return False
197
+
198
+ try:
199
+ cache_key = self._make_key(key)
200
+ result = await self.async_redis_client.delete(cache_key)
201
+ return bool(result)
202
+ except Exception as e:
203
+ logger.error(f"Async cache delete error: {e}")
204
+ return False
205
+
206
+ def invalidate_pattern(self, pattern: str) -> int:
207
+ """Invalidate all keys matching pattern"""
208
+ if not self.redis_client:
209
+ return 0
210
+
211
+ try:
212
+ pattern_key = self._make_key(pattern)
213
+ keys = self.redis_client.keys(pattern_key)
214
+ if keys:
215
+ return self.redis_client.delete(*keys)
216
+ return 0
217
+ except Exception as e:
218
+ logger.error(f"Pattern invalidation error: {e}")
219
+ return 0
220
+
221
+ def get_or_set(self, key: str, func: Callable, expire: int = 3600) -> Any:
222
+ """Get from cache or compute and set"""
223
+ value = self.get(key)
224
+ if value is not None:
225
+ return value
226
+
227
+ value = func()
228
+ self.set(key, value, expire)
229
+ return value
230
+
231
+ async def get_or_set_async(self, key: str, func: Callable, expire: int = 3600) -> Any:
232
+ """Get from cache or compute and set asynchronously"""
233
+ value = await self.get_async(key)
234
+ if value is not None:
235
+ return value
236
+
237
+ if asyncio.iscoroutinefunction(func):
238
+ value = await func()
239
+ else:
240
+ value = func()
241
+
242
+ await self.set_async(key, value, expire)
243
+ return value
244
+
245
+ def close(self):
246
+ """Close Redis connections"""
247
+ if self.redis_client:
248
+ self.redis_client.close()
249
+ self.redis_client = None
250
+
251
+ async def close_async(self):
252
+ """Close async Redis connection"""
253
+ if self.async_redis_client:
254
+ await self.async_redis_client.close()
255
+ self.async_redis_client = None
256
+
257
+
258
+ # Global cache manager instance
259
+ cache_manager = CacheManager()
260
+
261
+
262
+ # Decorator for caching function results
263
+ def cached(expire: int = 3600, key_prefix: str = None):
264
+ """Decorator to cache function results"""
265
+
266
+ def decorator(func: Callable):
267
+ @wraps(func)
268
+ async def async_wrapper(*args, **kwargs):
269
+ # Generate cache key
270
+ key_parts = [func.__module__, func.__name__]
271
+ if key_prefix:
272
+ key_parts.insert(0, key_prefix)
273
+
274
+ # Add function arguments to key
275
+ key_data = {
276
+ 'args': args,
277
+ 'kwargs': kwargs
278
+ }
279
+ key_hash = hashlib.md5(
280
+ json.dumps(key_data, sort_keys=True, default=str).encode()
281
+ ).hexdigest()
282
+ cache_key = f"{':'.join(key_parts)}:{key_hash}"
283
+
284
+ # Try to get from cache
285
+ cached_value = await cache_manager.get_async(cache_key)
286
+ if cached_value is not None:
287
+ logger.debug(f"Cache hit for {cache_key}")
288
+ return cached_value
289
+
290
+ # Compute value
291
+ logger.debug(f"Cache miss for {cache_key}")
292
+ if asyncio.iscoroutinefunction(func):
293
+ value = await func(*args, **kwargs)
294
+ else:
295
+ value = func(*args, **kwargs)
296
+
297
+ # Store in cache
298
+ await cache_manager.set_async(cache_key, value, expire)
299
+
300
+ return value
301
+
302
+ @wraps(func)
303
+ def sync_wrapper(*args, **kwargs):
304
+ # Generate cache key
305
+ key_parts = [func.__module__, func.__name__]
306
+ if key_prefix:
307
+ key_parts.insert(0, key_prefix)
308
+
309
+ key_data = {
310
+ 'args': args,
311
+ 'kwargs': kwargs
312
+ }
313
+ key_hash = hashlib.md5(
314
+ json.dumps(key_data, sort_keys=True, default=str).encode()
315
+ ).hexdigest()
316
+ cache_key = f"{':'.join(key_parts)}:{key_hash}"
317
+
318
+ # Try to get from cache
319
+ cached_value = cache_manager.get(cache_key)
320
+ if cached_value is not None:
321
+ logger.debug(f"Cache hit for {cache_key}")
322
+ return cached_value
323
+
324
+ # Compute value
325
+ logger.debug(f"Cache miss for {cache_key}")
326
+ value = func(*args, **kwargs)
327
+
328
+ # Store in cache
329
+ cache_manager.set(cache_key, value, expire)
330
+
331
+ return value
332
+
333
+ if asyncio.iscoroutinefunction(func):
334
+ return async_wrapper
335
+ else:
336
+ return sync_wrapper
337
+
338
+ return decorator
339
+
340
+
341
+ # Cache invalidation helpers
342
+ def invalidate_user_cache(user_id: str):
343
+ """Invalidate all cache entries for a user"""
344
+ pattern = f"user:{user_id}:*"
345
+ return cache_manager.invalidate_pattern(pattern)
346
+
347
+
348
+ def invalidate_model_cache(model_id: str):
349
+ """Invalidate all cache entries for a model"""
350
+ pattern = f"model:{model_id}:*"
351
+ return cache_manager.invalidate_pattern(pattern)
352
+
353
+
354
+ def invalidate_prediction_cache(prediction_id: str = None):
355
+ """Invalidate prediction cache"""
356
+ if prediction_id:
357
+ pattern = f"prediction:{prediction_id}:*"
358
+ else:
359
+ pattern = "prediction:*"
360
+ return cache_manager.invalidate_pattern(pattern)
361
+
362
+
363
+ # Convenience functions
364
+ async def init_cache():
365
+ """Initialize cache manager"""
366
+ await cache_manager.initialize_async()
367
+
368
+
369
+ async def close_cache():
370
+ """Close cache connections"""
371
+ await cache_manager.close_async()
372
+
373
+
374
+ async def check_cache_health() -> bool:
375
+ """Check if cache is healthy"""
376
+ try:
377
+ if not cache_manager.async_redis_client:
378
+ await cache_manager.initialize_async()
379
+
380
+ if cache_manager.async_redis_client:
381
+ await cache_manager.async_redis_client.ping()
382
+ return True
383
+ return False
384
+ except:
385
+ return False
386
+
387
+
388
+ def cache_set(key: str, value: Any, expire: int = 3600):
389
+ """Set cache value"""
390
+ return cache_manager.set(key, value, expire)
391
+
392
+
393
+ def cache_get(key: str):
394
+ """Get cache value"""
395
+ return cache_manager.get(key)
396
+
397
+
398
+ def cache_delete(key: str):
399
+ """Delete cache entry"""
400
+ return cache_manager.delete(key)