From 84e425bd3b10c49ae28b70d9998ef5ec2bf8868f Mon Sep 17 00:00:00 2001 From: Mathieu Virbel Date: Fri, 10 Nov 2023 19:06:18 +0100 Subject: [PATCH] server: fix slow profanity filter --- server/reflector/processors/types.py | 7 +++- server/reflector/redis_cache.py | 50 ++++++++++++++++++++++++++++ server/reflector/settings.py | 1 + 3 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 server/reflector/redis_cache.py diff --git a/server/reflector/processors/types.py b/server/reflector/processors/types.py index 312f5433..93e565df 100644 --- a/server/reflector/processors/types.py +++ b/server/reflector/processors/types.py @@ -5,6 +5,7 @@ from pathlib import Path from profanityfilter import ProfanityFilter from pydantic import BaseModel, PrivateAttr +from reflector.redis_cache import redis_cache PUNC_RE = re.compile(r"[.;:?!…]") @@ -68,10 +69,14 @@ class Transcript(BaseModel): # Uncensored text return "".join([word.text for word in self.words]) + @redis_cache(prefix="profanity", duration=3600 * 24 * 7) + def _get_censored_text(self, text: str): + return profanity_filter.censor(text).strip() + @property def text(self): # Censored text - return profanity_filter.censor(self.raw_text).strip() + return self._get_censored_text(self.raw_text) @property def human_timestamp(self): diff --git a/server/reflector/redis_cache.py b/server/reflector/redis_cache.py new file mode 100644 index 00000000..c31471cf --- /dev/null +++ b/server/reflector/redis_cache.py @@ -0,0 +1,50 @@ +import functools +import json + +import redis +from reflector.settings import settings + +redis_clients = {} + + +def get_redis_client(db=0): + """ + Get a Redis client for the specified database. + """ + if db not in redis_clients: + redis_clients[db] = redis.StrictRedis( + host=settings.REDIS_HOST, + port=settings.REDIS_PORT, + db=db, + ) + return redis_clients[db] + + +def redis_cache(prefix="cache", duration=3600, db=settings.REDIS_CACHE_DB, argidx=1): + """ + Cache the result of a function in Redis. + """ + + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + # Check if the first argument is a string + if len(args) < (argidx + 1) or not isinstance(args[argidx], str): + return func(*args, **kwargs) + + # Compute the cache key based on the arguments and prefix + cache_key = prefix + ":" + args[argidx] + redis_client = get_redis_client(db=db) + cached_result = redis_client.get(cache_key) + + if cached_result: + return json.loads(cached_result.decode("utf-8")) + + # If the result is not cached, call the original function + result = func(*args, **kwargs) + redis_client.setex(cache_key, duration, json.dumps(result)) + return result + + return wrapper + + return decorator diff --git a/server/reflector/settings.py b/server/reflector/settings.py index 7ce91195..013ab9b7 100644 --- a/server/reflector/settings.py +++ b/server/reflector/settings.py @@ -124,6 +124,7 @@ class Settings(BaseSettings): # Redis REDIS_HOST: str = "localhost" REDIS_PORT: int = 6379 + REDIS_CACHE_DB: int = 2 # Secret key SECRET_KEY: str = "changeme-f02f86fd8b3e4fd892c6043e5a298e21"