# AGENT.md This file provides guidance to AI coding agents when working with code in this repository. ## Project Overview This is a Gradio Space that implements "Next Scene" cinematic image generation using Qwen-Image-Edit-2509 with LoRA fine-tuning. The application generates visually progressive image sequences with natural cinematic transitions from frame to frame, optimized for fast 4-step inference. **Key Model Components:** - Base model: `Qwen/Qwen-Image-Edit-2509` (image editing diffusion model) - Accelerated transformer: `linoyts/Qwen-Image-Edit-Rapid-AIO` (4-step optimized variant) - LoRA adapter: `lovis93/next-scene-qwen-image-lora-2509` (cinematic progression fine-tune) - Text encoder: `Qwen2.5-VL-72B-Instruct` (via Hugging Face InferenceClient for prompt enhancement) ## Running the Application **Start the Gradio interface:** ```bash python app.py ``` **Install dependencies:** ```bash pip install -r requirements.txt ``` The app requires GPU access. It uses the `@spaces.GPU` decorator for Hugging Face Spaces zero-GPU allocation. ## Architecture ### Pipeline Flow 1. **Input Processing** (`app.py:infer`): - Accepts input images via Gradio Gallery (filepath-based) - Optional prompt rewriting using `Qwen2.5-VL-72B-Instruct` API - Automatic "Next Scene" prompt generation from images 2. **Image Generation** (`qwenimage/pipeline_qwenimage_edit_plus.py`): - Custom pipeline extending `DiffusionPipeline` - Encodes images using VAE at 1024x1024 for latents - Encodes conditioning images at 384x384 for text encoder - Packs latents into 2x2 patches (latent dims must be divisible by 2) - Uses `FlowMatchEulerDiscreteScheduler` for denoising 3. **Optimization** (`optimization.py`): - Ahead-of-time (AOT) compilation using `torch.export` and `spaces.aoti_compile` - Dynamic shapes for variable sequence lengths - Custom inductor configs for performance (max_autotune, cudagraphs) - FlashAttention 3 integration via `QwenDoubleStreamAttnProcessorFA3` 4. **Output Handling**: - Saves outputs to `outputs/` directory with unique timestamps - Maintains 20-image history gallery - Optional video generation via `multimodalart/wan-2-2-first-last-frame` Space ### Custom QwenImage Components **Location:** `qwenimage/` package - `pipeline_qwenimage_edit_plus.py` - Main diffusion pipeline with LoRA support - `transformer_qwenimage.py` - Custom transformer model with cache management - `qwen_fa3_processor.py` - FlashAttention 3 attention processor **Key architectural features:** - Latent packing/unpacking for 2x2 patch processing - Multi-image conditioning support - True CFG (classifier-free guidance) with separate pos/neg paths - Dual-stream attention with rotary embeddings - Cache contexts for conditional/unconditional forward passes ### Prompt Engineering **Two-stage prompt system:** 1. **Edit Instruction Rewriter** (`SYSTEM_PROMPT`): - Normalizes user prompts into professional editing instructions - Handles text replacement (requires quotes), object manipulation, style transfer - Used when `rewrite_prompt=True` checkbox is enabled 2. **Next Scene Generator** (`NEXT_SCENE_SYSTEM_PROMPT`): - Automatically suggests cinematic camera movements - Focus on visual progression (dolly, pan, zoom, framing changes) - Auto-triggers when input images change Both use `Qwen2.5-VL-72B-Instruct` via Hugging Face InferenceClient with Nebius provider. Requires `HF_TOKEN` environment variable. ## Important Implementation Details ### Image Dimension Handling Images are automatically resized based on `calculate_dimensions()` function: - VAE images: resized to maintain 1024×1024 area (1,048,576 pixels) - Condition images: resized to maintain 384×384 area (147,456 pixels) - Output dimensions must be divisible by 16 (vae_scale_factor × 2) - Height/width default to `None` which auto-calculates from input aspect ratio ### LoRA Integration The pipeline fuses the "next-scene" LoRA adapter at initialization: ```python pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509", ...) pipe.set_adapters(["next-scene"], adapter_weights=[1.]) pipe.fuse_lora(adapter_names=["next-scene"], lora_scale=1.) pipe.unload_lora_weights() ``` After fusion, the adapter weights are merged into the base model and cannot be unfused. ### Video Generation Integration The `turn_into_video()` function: - Connects to external Gradio Space `multimodalart/wan-2-2-first-last-frame` - Requires first input image and last output image - Uses the original prompt (or "smooth cinematic transition" fallback) - Returns video path for display ### Gradio Gallery Format Input/output galleries use `type="filepath"` (string paths) rather than PIL Image tuples. Helper functions handle format compatibility for legacy tuple support. ## Environment Variables - `HF_TOKEN` - Required for Qwen2.5-VL API access (prompt rewriting/generation) ## File Outputs Generated images are saved to `outputs/` directory with format: ``` output_{seed}_{index}_{timestamp_ms}.png ``` ## Local Development and API Testing The `custom/` directory is fully gitignored and used for local development files. Specifically, it contains: - **API client scripts** - For testing the Gradio Space remotely via API after deployment to Hugging Face - **`API_GUIDE.txt`** - Auto-generated Gradio API documentation showing endpoint signatures and example usage - **Local testing environments** - Virtual environments or test data that shouldn't be committed **API Integration Pattern:** Once the Space is deployed to Hugging Face, you can interact with it programmatically using `gradio_client`: ```python from gradio_client import Client, handle_file client = Client("Sneak-Moose/Qwen-Image-Edit-next-scene") result = client.predict( images=[], prompt="Next Scene: Camera dollies forward...", seed=42, randomize_seed=False, true_guidance_scale=1.0, num_inference_steps=4, height=1024, width=1024, rewrite_prompt=False, api_name="/infer" ) ``` The `custom/API_GUIDE.txt` contains full documentation of all available endpoints including `/infer`, `/turn_into_video`, `/suggest_next_scene_prompt`, and utility functions. ## Development Notes - The model loads on startup and applies AOT compilation during first inference - Compilation uses dynamic shapes to support variable text/image sequence lengths - The transformer uses custom cache contexts ("cond"/"uncond") to optimize CFG passes - True CFG applies norm-based rescaling: `comb_pred * (cond_norm / noise_norm)` - FlashAttention 3 processor must be set before compilation