Skip to content

Commit 3a26a50

Browse files
committed
Enable Flask context in parallel AI moderation tasks
Introduces a context wrapper in AIModerator to ensure Flask application context is available during parallel chunk processing. Also updates logging for chunking and refines cache info reporting in ModerationOrchestrator for improved clarity and accuracy.
1 parent 9e632da commit 3a26a50

2 files changed

Lines changed: 18 additions & 10 deletions

File tree

app/services/ai/ai_moderator.py

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ class AIModerator:
1616
def __init__(self):
1717
self.client_manager = OpenAIClient()
1818
self.cache = ResultCache()
19+
# Capture Flask app instance for context propagation in parallel processing
20+
self.app = current_app._get_current_object()
1921
# Load model and token settings from config
2022
cfg = current_app.config
2123
self.model_name = cfg.get('OPENAI_CHAT_MODEL', 'gpt-5-2025-08-07')
@@ -30,6 +32,14 @@ def __init__(self):
3032
except (KeyError, ValueError):
3133
self.tokenizer = tiktoken.get_encoding("cl100k_base")
3234

35+
def _context_wrapper(self, func, *args, **kwargs):
36+
"""
37+
Wrapper to execute functions within Flask application context.
38+
Required for parallel processing to access current_app.
39+
"""
40+
with self.app.app_context():
41+
return func(*args, **kwargs)
42+
3343
def count_tokens(self, text):
3444
"""Count the number of tokens in a text string"""
3545
try:
@@ -303,8 +313,8 @@ def moderate_content(self, content, content_type='text', custom_prompt=None):
303313

304314
# Force chunking if content is too large BY CHARACTER COUNT
305315
if content_chars > MAX_CHARS_PER_CHUNK:
306-
current_app.logger.warning(
307-
f"FORCING CHUNKING: Content too large ({content_chars} chars > {MAX_CHARS_PER_CHUNK})")
316+
current_app.logger.debug(f"Chunking content: {content_chars} chars split into {
317+
(content_chars // MAX_CHARS_PER_CHUNK) + 1} chunks")
308318

309319
# Split by character count, not tokens
310320
chunks = []
@@ -314,9 +324,9 @@ def moderate_content(self, content, content_type='text', custom_prompt=None):
314324
# Process all chunks IN PARALLEL for maximum speed
315325
chunk_results = []
316326
with ThreadPoolExecutor(max_workers=min(len(chunks), 10)) as executor:
317-
# Submit all chunks at once
327+
# Submit all chunks at once with context wrapper
318328
future_to_chunk = {
319-
executor.submit(self._analyze_with_custom_prompt, chunk, custom_prompt): i
329+
executor.submit(self._context_wrapper, self._analyze_with_custom_prompt, chunk, custom_prompt): i
320330
for i, chunk in enumerate(chunks)
321331
}
322332

@@ -349,9 +359,9 @@ def moderate_content(self, content, content_type='text', custom_prompt=None):
349359
# Process all chunks IN PARALLEL for maximum speed
350360
chunk_results = []
351361
with ThreadPoolExecutor(max_workers=min(len(chunks), 10)) as executor:
352-
# Submit all chunks at once
362+
# Submit all chunks at once with context wrapper
353363
future_to_chunk = {
354-
executor.submit(self._run_enhanced_default_moderation, chunk): i
364+
executor.submit(self._context_wrapper, self._run_enhanced_default_moderation, chunk): i
355365
for i, chunk in enumerate(chunks)
356366
}
357367

app/services/moderation_orchestrator.py

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -80,10 +80,8 @@ async def moderate_content(self, content_id, request_start_time=None):
8080

8181
# Get cache summary for this request
8282
cache_summary = self.ai_moderator.cache.get_request_cache_summary()
83-
if cache_summary['stores'] > 0:
84-
cache_info = f" [Cached {cache_summary['stores']} results, total: {cache_summary['total']}]"
85-
elif total_time < 1.0:
86-
cache_info = " [Cache hit]"
83+
if total_time < 0.5 and cache_summary['hits'] > 0:
84+
cache_info = " [cached]"
8785
else:
8886
cache_info = ""
8987

0 commit comments

Comments
 (0)