Truncate base64 blobs in request debug log; add ftfy dependency

- log.py: _redact_blobs() recursively truncates data-URI / base64 fields
  (init_image, image, mask, character_references, …) to their first 48 chars
  in the FULL REQUEST DEBUG dump, so a clip request no longer prints tens of KB
  of base64. Prompts and normal fields are left intact (base64-charset check
  excludes anything with spaces/punctuation).
- requirements.txt: add ftfy (required by the diffusers Wan/T5 prompt_clean
  path; its absence surfaced as "name 'ftfy' is not defined" at generation).
Co-Authored-By: 's avatarClaude Opus 4.8 <noreply@anthropic.com>
parent d27ebf43
...@@ -19,6 +19,7 @@ Request logging middleware for the codai API. ...@@ -19,6 +19,7 @@ Request logging middleware for the codai API.
""" """
import json import json
import re
import time import time
from collections import deque from collections import deque
from fastapi import Request from fastapi import Request
...@@ -26,6 +27,32 @@ from fastapi import Request ...@@ -26,6 +27,32 @@ from fastapi import Request
# In-memory ring buffer of recent API requests (max 50) # In-memory ring buffer of recent API requests (max 50)
_activity: deque = deque(maxlen=50) _activity: deque = deque(maxlen=50)
# Number of leading characters of a base64/data-URI blob to keep in debug output.
_BLOB_PREVIEW_CHARS = 48
# A string is treated as a binary blob (and truncated) when it is a data: URI, or
# when it is long and made up only of base64 characters (real prompts contain
# spaces/punctuation, so they never match this).
_B64_RE = re.compile(r'^[A-Za-z0-9+/=\s]+$')
def _is_blob(s: str) -> bool:
if s.startswith("data:"):
return True
return len(s) > 256 and bool(_B64_RE.match(s[:256]))
def _redact_blobs(obj):
"""Recursively copy a JSON-ish value, truncating base64/data-URI blobs (e.g.
init_image, image, mask, character_references) to their first few bytes so the
debug log stays readable instead of dumping tens of KB of base64."""
if isinstance(obj, dict):
return {k: _redact_blobs(v) for k, v in obj.items()}
if isinstance(obj, list):
return [_redact_blobs(v) for v in obj]
if isinstance(obj, str) and _is_blob(obj):
return f"{obj[:_BLOB_PREVIEW_CHARS]}…[{len(obj)} chars total, truncated]"
return obj
def get_recent_activity(): def get_recent_activity():
return list(_activity) return list(_activity)
...@@ -91,7 +118,7 @@ async def log_requests(request: Request, call_next): ...@@ -91,7 +118,7 @@ async def log_requests(request: Request, call_next):
print(f"\n{'='*80}") print(f"\n{'='*80}")
print(f"=== FULL REQUEST DEBUG ===") print(f"=== FULL REQUEST DEBUG ===")
print(f"Method: {request.method} URL: {request.url}") print(f"Method: {request.method} URL: {request.url}")
print(json.dumps(parsed, indent=2)) print(json.dumps(_redact_blobs(parsed), indent=2))
print(f"{'='*80}\n") print(f"{'='*80}\n")
except Exception as e: except Exception as e:
if global_debug: if global_debug:
......
...@@ -36,6 +36,7 @@ transformers>=4.35.0 ...@@ -36,6 +36,7 @@ transformers>=4.35.0
accelerate>=0.24.0 accelerate>=0.24.0
diffusers>=0.25.0 # For Stable Diffusion image generation diffusers>=0.25.0 # For Stable Diffusion image generation
safetensors>=0.4.0 # Required by diffusers safetensors>=0.4.0 # Required by diffusers
ftfy>=6.0 # Prompt text cleaning for diffusers Wan/T5 pipelines (prompt_clean)
# stable-diffusion-cpp-python is installed by build.sh with CMAKE_ARGS to fix the libwebm submodule issue # stable-diffusion-cpp-python is installed by build.sh with CMAKE_ARGS to fix the libwebm submodule issue
# System resource detection # System resource detection
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment