2023-10-27 19:19:22 -06:00
|
|
|
import pickle
|
2023-09-23 23:14:22 -06:00
|
|
|
import traceback
|
2024-05-07 17:03:41 -06:00
|
|
|
from typing import Union
|
2023-08-29 13:46:41 -06:00
|
|
|
|
2023-09-25 17:20:21 -06:00
|
|
|
import simplejson as json
|
2023-08-21 21:28:52 -06:00
|
|
|
from flask_caching import Cache
|
2023-08-23 01:14:19 -06:00
|
|
|
from redis import Redis
|
2024-05-07 17:03:41 -06:00
|
|
|
from redis.typing import ExpiryT, KeyT, PatternT
|
2023-08-21 21:28:52 -06:00
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
flask_cache = Cache(config={'CACHE_TYPE': 'RedisCache', 'CACHE_REDIS_URL': 'redis://localhost:6379/15', 'CACHE_KEY_PREFIX': 'local_llm_flask'})
|
2023-08-23 22:01:06 -06:00
|
|
|
|
2023-09-24 21:45:30 -06:00
|
|
|
ONE_MONTH_SECONDS = 2678000
|
2023-08-23 22:01:06 -06:00
|
|
|
|
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
class RedisCustom(Redis):
|
2023-08-23 22:01:06 -06:00
|
|
|
"""
|
2023-10-27 19:19:22 -06:00
|
|
|
A simple wrapper class for Redis to create a "namespace" within a DB,
|
2024-01-10 15:01:26 -07:00
|
|
|
which simplifies key management.
|
2023-08-23 22:01:06 -06:00
|
|
|
"""
|
|
|
|
|
2024-01-10 15:01:26 -07:00
|
|
|
# TODO: is there a better way to do this instead of overriding every single method?
|
|
|
|
|
2023-08-23 22:01:06 -06:00
|
|
|
def __init__(self, prefix, **kwargs):
|
2023-10-27 19:19:22 -06:00
|
|
|
super().__init__()
|
2023-08-23 22:01:06 -06:00
|
|
|
self.redis = Redis(**kwargs)
|
|
|
|
self.prefix = prefix
|
|
|
|
|
2023-09-14 14:05:50 -06:00
|
|
|
def _key(self, key):
|
|
|
|
return f"{self.prefix}:{key}"
|
|
|
|
|
2024-05-07 17:03:41 -06:00
|
|
|
def execute_command(self, *args, **options):
|
|
|
|
if args[0] != 'GET':
|
|
|
|
args = list(args)
|
|
|
|
args[1] = self._key(args[1])
|
|
|
|
return super().execute_command(*args, **options)
|
2023-08-23 22:01:06 -06:00
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
def get(self, key, default=None, dtype=None):
|
|
|
|
# TODO: use pickle
|
|
|
|
import inspect
|
|
|
|
if inspect.isclass(default):
|
|
|
|
raise Exception
|
2023-09-25 17:20:21 -06:00
|
|
|
|
2023-09-23 23:14:22 -06:00
|
|
|
d = self.redis.get(self._key(key))
|
|
|
|
if dtype and d:
|
|
|
|
try:
|
|
|
|
if dtype == str:
|
|
|
|
return d.decode('utf-8')
|
2023-09-25 17:20:21 -06:00
|
|
|
if dtype in [dict, list]:
|
|
|
|
return json.loads(d.decode("utf-8"))
|
2023-09-23 23:14:22 -06:00
|
|
|
else:
|
|
|
|
return dtype(d)
|
|
|
|
except:
|
|
|
|
traceback.print_exc()
|
2023-09-25 17:20:21 -06:00
|
|
|
if not d:
|
|
|
|
return default
|
|
|
|
else:
|
|
|
|
return d
|
2023-08-23 22:01:06 -06:00
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
def keys(self, pattern: PatternT = "*", **kwargs):
|
|
|
|
raw_keys = self.redis.keys(self._key(pattern), **kwargs)
|
|
|
|
keys = []
|
|
|
|
for key in raw_keys:
|
|
|
|
p = key.decode('utf-8').split(':')
|
|
|
|
if len(p) >= 2:
|
|
|
|
# Delete prefix
|
|
|
|
del p[0]
|
|
|
|
k = ':'.join(p)
|
2024-05-07 17:41:53 -06:00
|
|
|
keys.append(k)
|
2023-10-27 19:19:22 -06:00
|
|
|
return keys
|
|
|
|
|
|
|
|
def exists(self, *names: KeyT):
|
|
|
|
n = []
|
|
|
|
for name in names:
|
|
|
|
n.append(self._key(name))
|
|
|
|
return self.redis.exists(*n)
|
|
|
|
|
2023-09-25 17:20:21 -06:00
|
|
|
def set_dict(self, key: Union[list, dict], dict_value, ex: Union[ExpiryT, None] = None):
|
|
|
|
return self.set(key, json.dumps(dict_value), ex=ex)
|
2023-08-29 13:46:41 -06:00
|
|
|
|
|
|
|
def get_dict(self, key):
|
2023-09-25 17:20:21 -06:00
|
|
|
r = self.get(key)
|
2023-08-29 13:46:41 -06:00
|
|
|
if not r:
|
|
|
|
return dict()
|
|
|
|
else:
|
2023-09-14 14:05:50 -06:00
|
|
|
return json.loads(r.decode("utf-8"))
|
2023-08-29 13:46:41 -06:00
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
def setp(self, name, value):
|
|
|
|
self.redis.set(self._key(name), pickle.dumps(value))
|
|
|
|
|
|
|
|
def getp(self, name: str):
|
|
|
|
r = self.redis.get(self._key(name))
|
|
|
|
if r:
|
|
|
|
return pickle.loads(r)
|
|
|
|
return r
|
|
|
|
|
2023-08-23 22:01:06 -06:00
|
|
|
def flush(self):
|
|
|
|
flushed = []
|
|
|
|
for key in self.redis.scan_iter(f'{self.prefix}:*'):
|
|
|
|
flushed.append(key)
|
|
|
|
self.redis.delete(key)
|
|
|
|
return flushed
|
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
def flushall(self, asynchronous: bool = ..., **kwargs) -> bool:
|
|
|
|
self.flush()
|
|
|
|
return True
|
|
|
|
|
|
|
|
def flushdb(self, asynchronous: bool = ..., **kwargs) -> bool:
|
|
|
|
self.flush()
|
|
|
|
return True
|
|
|
|
|
2023-08-23 22:01:06 -06:00
|
|
|
|
2023-10-27 19:19:22 -06:00
|
|
|
redis = RedisCustom('local_llm')
|