Skip to content

fix: add media cache limits and restore multi-image video references#477

Open
PigeonXianxian wants to merge 1 commit intochenyme:mainfrom
PigeonXianxian:pr/upstream-all
Open

fix: add media cache limits and restore multi-image video references#477
PigeonXianxian wants to merge 1 commit intochenyme:mainfrom
PigeonXianxian:pr/upstream-all

Conversation

@PigeonXianxian
Copy link
Copy Markdown

Summary

This PR bundles three related improvements around local media handling and video generation inputs:

  • Restore multi-reference image support for video generation so multiple input images are preserved and passed through correctly.
  • Fix local image proxy URL handling so locally served image references work consistently in the video flow.
  • Add configurable local media cache limits for image/video storage to prevent unbounded cache growth from filling the server disk.
    • New config keys:
      • storage.media_max_mb
      • storage.image_max_mb
      • storage.video_max_mb
    • When a limit is exceeded, the server evicts the oldest cached files first.
  • Expose the new storage limit settings in the admin config page so they can be updated from the web UI.

The cache limit change is mainly to prevent local cached media from accumulating indefinitely and eventually exhausting disk space.

Testing

  • Added/updated tests for:
    • media cache eviction behavior
    • image output/local proxy URL handling
    • video reference helper behavior for multi-image inputs
  • Attempted to run:
    • pytest -q tests/test_media_cache_limits.py tests/test_image_output_format.py tests/test_video_reference_helpers.py
  • In the current local environment, test collection was blocked by missing Python dependencies:
    • loguru
    • orjson

Related

  • No linked issue.

Copilot AI review requested due to automatic review settings April 15, 2026 16:48
@PigeonXianxian PigeonXianxian changed the title Add media cache limits and restore multi-image video references fix: add media cache limits and restore multi-image video references Apr 15, 2026
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR improves local media handling by adding cache size limits with eviction, restoring multi-image reference support for video generation, and making local proxy image URLs work more consistently through the image/video flows.

Changes:

  • Add configurable local media cache limits (total + per-type) with oldest-first eviction and expose settings in the admin config UI/i18n.
  • Restore multi-image reference extraction and payload construction for video generation (including placeholder replacement).
  • Adjust image output resolution and local caching behavior (including better file-id extraction from upstream asset URLs).

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_video_reference_helpers.py Adds coverage for placeholder replacement, multi-image extraction, and video payload reference fields.
tests/test_media_cache_limits.py Adds coverage for cache eviction when per-type or total limits are exceeded.
tests/test_image_output_format.py Adds coverage for local proxy URL output and local save behavior.
config.defaults.toml Introduces new [storage] cache limit defaults.
app/statics/i18n/zh.json Adds i18n strings for storage config group and cache limit fields (ZH).
app/statics/i18n/en.json Adds i18n strings for storage config group and cache limit fields (EN).
app/statics/admin/config.html Exposes new storage/cache-limit settings in the admin config UI.
app/products/openai/video.py Restores multi-reference image support for video generation; integrates cache-saving helper for videos.
app/products/openai/router.py Updates /v1/videos to accept multiple uploaded reference images (including input_reference[]).
app/products/openai/images.py Improves upstream asset ID extraction; integrates cache-saving helper; adjusts output formatting logic.
app/products/openai/chat.py Integrates cache-saving helper for locally stored chat images.
app/products/openai/init.py Switches to lazy export of router via __getattr__.
app/platform/storage/media_cache.py Adds the new cache writer + eviction logic based on configured MB limits.
app/platform/storage/init.py Exports save_media_bytes from the storage package.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +80 to +90
def _enforce_limits_locked(media_type: MediaType) -> None:
removed = _prune_paths(_list_files(media_type), _specific_limit_bytes(media_type))
if removed:
logger.info(
"media cache pruned: scope={} removed_count={}",
media_type,
len(removed),
)

removed = _prune_paths(_list_files(), _total_limit_bytes())
if removed:
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

_enforce_limits_locked() always calls _list_files() (directory glob) even when the configured limit is disabled (0). This adds unnecessary O(N) filesystem scans on every media write. Consider computing the specific/total limit first and skipping _list_files/_prune_paths entirely when the corresponding limit_bytes <= 0.

Copilot uses AI. Check for mistakes.
Comment on lines +93 to +99

def save_media_bytes(raw: bytes, path: Path, *, media_type: MediaType) -> Path:
path.parent.mkdir(parents=True, exist_ok=True)
with _CACHE_LOCK:
if not path.exists():
path.write_bytes(raw)
_enforce_limits_locked(media_type)
Copy link

Copilot AI Apr 15, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

save_media_bytes() writes the file and then prunes the cache. If the newly written file itself causes the cache to exceed the limit (e.g., file size > limit), _prune_paths() can delete the just-written path, but save_media_bytes() still returns that Path to callers. Consider pruning before writing to make room, and/or ensuring the returned path still exists (or raising a clear error) when the file cannot be retained under the configured limits.

Suggested change
def save_media_bytes(raw: bytes, path: Path, *, media_type: MediaType) -> Path:
path.parent.mkdir(parents=True, exist_ok=True)
with _CACHE_LOCK:
if not path.exists():
path.write_bytes(raw)
_enforce_limits_locked(media_type)
def _prepare_capacity_locked(media_type: MediaType, incoming_size: int) -> None:
specific_limit = _specific_limit_bytes(media_type)
if 0 < specific_limit < incoming_size:
raise OSError(
f"media cache write exceeds configured {media_type} cache limit: "
f"size={incoming_size} limit={specific_limit}"
)
total_limit = _total_limit_bytes()
if 0 < total_limit < incoming_size:
raise OSError(
"media cache write exceeds configured total cache limit: "
f"size={incoming_size} limit={total_limit}"
)
if specific_limit > 0:
removed = _prune_paths(_list_files(media_type), max(specific_limit - incoming_size, 0))
if removed:
logger.info(
"media cache pruned before write: scope={} removed_count={}",
media_type,
len(removed),
)
if total_limit > 0:
removed = _prune_paths(_list_files(), max(total_limit - incoming_size, 0))
if removed:
logger.info("media cache pruned before write: scope=all removed_count={}", len(removed))
def save_media_bytes(raw: bytes, path: Path, *, media_type: MediaType) -> Path:
path.parent.mkdir(parents=True, exist_ok=True)
with _CACHE_LOCK:
if not path.exists():
_prepare_capacity_locked(media_type, len(raw))
path.write_bytes(raw)
_enforce_limits_locked(media_type)
if not path.exists():
raise OSError(f"media cache could not retain file within configured limits: {path}")

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants