AgentNewTwo commited on
Commit
e01757b
·
1 Parent(s): 272b5bf

Harden privacy and pin four-step model stack

Browse files
Files changed (5) hide show
  1. AGENT.md +33 -153
  2. CLAUDE.md +3 -153
  3. README.md +10 -1
  4. app.py +28 -104
  5. requirements.txt +2 -3
AGENT.md CHANGED
@@ -1,169 +1,49 @@
1
- # AGENT.md
2
 
3
- This file provides guidance to AI coding agents when working with code in this repository.
4
 
5
- ## Project Overview
6
 
7
- 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.
 
 
 
8
 
9
- **Key Model Components:**
10
- - Base model: `Qwen/Qwen-Image-Edit-2509` (image editing diffusion model)
11
- - Accelerated transformer: `linoyts/Qwen-Image-Edit-Rapid-AIO` (4-step optimized variant)
12
- - LoRA adapter: `lovis93/next-scene-qwen-image-lora-2509` (cinematic progression fine-tune)
13
- - Text encoder: `Qwen2.5-VL-72B-Instruct` (via Hugging Face InferenceClient for prompt enhancement)
14
 
15
- ## Running the Application
16
 
17
- **Start the Gradio interface:**
18
- ```bash
19
- python app.py
20
- ```
21
-
22
- **Install dependencies:**
23
- ```bash
24
- pip install -r requirements.txt
25
- ```
26
-
27
- The app requires GPU access. It uses the `@spaces.GPU` decorator for Hugging Face Spaces zero-GPU allocation.
28
-
29
- ## Architecture
30
-
31
- ### Pipeline Flow
32
-
33
- 1. **Input Processing** (`app.py:infer`):
34
- - Accepts input images via Gradio Gallery (filepath-based)
35
- - Optional prompt rewriting using `Qwen2.5-VL-72B-Instruct` API
36
- - Automatic "Next Scene" prompt generation from images
37
-
38
- 2. **Image Generation** (`qwenimage/pipeline_qwenimage_edit_plus.py`):
39
- - Custom pipeline extending `DiffusionPipeline`
40
- - Encodes images using VAE at 1024x1024 for latents
41
- - Encodes conditioning images at 384x384 for text encoder
42
- - Packs latents into 2x2 patches (latent dims must be divisible by 2)
43
- - Uses `FlowMatchEulerDiscreteScheduler` for denoising
44
-
45
- 3. **Optimization** (`optimization.py`):
46
- - Ahead-of-time (AOT) compilation using `torch.export` and `spaces.aoti_compile`
47
- - Dynamic shapes for variable sequence lengths
48
- - Custom inductor configs for performance (max_autotune, cudagraphs)
49
- - FlashAttention 3 integration via `QwenDoubleStreamAttnProcessorFA3`
50
-
51
- 4. **Output Handling**:
52
- - Saves outputs to `outputs/` directory with unique timestamps
53
- - Maintains 20-image history gallery
54
- - Optional video generation via `multimodalart/wan-2-2-first-last-frame` Space
55
-
56
- ### Custom QwenImage Components
57
-
58
- **Location:** `qwenimage/` package
59
-
60
- - `pipeline_qwenimage_edit_plus.py` - Main diffusion pipeline with LoRA support
61
- - `transformer_qwenimage.py` - Custom transformer model with cache management
62
- - `qwen_fa3_processor.py` - FlashAttention 3 attention processor
63
-
64
- **Key architectural features:**
65
- - Latent packing/unpacking for 2x2 patch processing
66
- - Multi-image conditioning support
67
- - True CFG (classifier-free guidance) with separate pos/neg paths
68
- - Dual-stream attention with rotary embeddings
69
- - Cache contexts for conditional/unconditional forward passes
70
-
71
- ### Prompt Engineering
72
-
73
- **Two-stage prompt system:**
74
-
75
- 1. **Edit Instruction Rewriter** (`SYSTEM_PROMPT`):
76
- - Normalizes user prompts into professional editing instructions
77
- - Handles text replacement (requires quotes), object manipulation, style transfer
78
- - Used when `rewrite_prompt=True` checkbox is enabled
79
-
80
- 2. **Next Scene Generator** (`NEXT_SCENE_SYSTEM_PROMPT`):
81
- - Automatically suggests cinematic camera movements
82
- - Focus on visual progression (dolly, pan, zoom, framing changes)
83
- - Auto-triggers when input images change
84
 
85
- Both use `Qwen2.5-VL-72B-Instruct` via Hugging Face InferenceClient with Nebius provider. Requires `HF_TOKEN` environment variable.
 
86
 
87
- ## Important Implementation Details
88
 
89
- ### Image Dimension Handling
 
 
 
90
 
91
- Images are automatically resized based on `calculate_dimensions()` function:
92
- - VAE images: resized to maintain 1024×1024 area (1,048,576 pixels)
93
- - Condition images: resized to maintain 384×384 area (147,456 pixels)
94
- - Output dimensions must be divisible by 16 (vae_scale_factor × 2)
95
- - Height/width default to `None` which auto-calculates from input aspect ratio
96
 
97
- ### LoRA Integration
98
 
99
- The pipeline fuses the "next-scene" LoRA adapter at initialization:
100
- ```python
101
- pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509", ...)
102
- pipe.set_adapters(["next-scene"], adapter_weights=[1.])
103
- pipe.fuse_lora(adapter_names=["next-scene"], lora_scale=1.)
104
- pipe.unload_lora_weights()
105
- ```
106
-
107
- After fusion, the adapter weights are merged into the base model and cannot be unfused.
108
-
109
- ### Video Generation Integration
110
-
111
- The `turn_into_video()` function:
112
- - Connects to external Gradio Space `multimodalart/wan-2-2-first-last-frame`
113
- - Requires first input image and last output image
114
- - Uses the original prompt (or "smooth cinematic transition" fallback)
115
- - Returns video path for display
116
-
117
- ### Gradio Gallery Format
118
-
119
- Input/output galleries use `type="filepath"` (string paths) rather than PIL Image tuples. Helper functions handle format compatibility for legacy tuple support.
120
-
121
- ## Environment Variables
122
-
123
- - `HF_TOKEN` - Required for Qwen2.5-VL API access (prompt rewriting/generation)
124
-
125
- ## File Outputs
126
-
127
- Generated images are saved to `outputs/` directory with format:
128
- ```
129
- output_{seed}_{index}_{timestamp_ms}.png
130
- ```
131
-
132
- ## Local Development and API Testing
133
-
134
- The `custom/` directory is fully gitignored and used for local development files. Specifically, it contains:
135
-
136
- - **API client scripts** - For testing the Gradio Space remotely via API after deployment to Hugging Face
137
- - **`API_GUIDE.txt`** - Auto-generated Gradio API documentation showing endpoint signatures and example usage
138
- - **Local testing environments** - Virtual environments or test data that shouldn't be committed
139
-
140
- **API Integration Pattern:**
141
- Once the Space is deployed to Hugging Face, you can interact with it programmatically using `gradio_client`:
142
-
143
- ```python
144
- from gradio_client import Client, handle_file
145
-
146
- client = Client("Sneak-Moose/Qwen-Image-Edit-next-scene")
147
- result = client.predict(
148
- images=[],
149
- prompt="Next Scene: Camera dollies forward...",
150
- seed=42,
151
- randomize_seed=False,
152
- true_guidance_scale=1.0,
153
- num_inference_steps=4,
154
- height=1024,
155
- width=1024,
156
- rewrite_prompt=False,
157
- api_name="/infer"
158
- )
159
  ```
160
 
161
- The `custom/API_GUIDE.txt` contains full documentation of all available endpoints including `/infer`, `/turn_into_video`, `/suggest_next_scene_prompt`, and utility functions.
162
 
163
- ## Development Notes
 
 
 
164
 
165
- - The model loads on startup and applies AOT compilation during first inference
166
- - Compilation uses dynamic shapes to support variable text/image sequence lengths
167
- - The transformer uses custom cache contexts ("cond"/"uncond") to optimize CFG passes
168
- - True CFG applies norm-based rescaling: `comb_pred * (cond_norm / noise_norm)`
169
- - FlashAttention 3 processor must be set before compilation
 
1
+ # Agent guidance
2
 
3
+ ## Project
4
 
5
+ This repository is a Hugging Face Gradio Space for image editing with:
6
 
7
+ - `Qwen/Qwen-Image-Edit-2511`
8
+ - a four-step Rapid-AIO transformer
9
+ - a custom Qwen pipeline under `qwenimage/`
10
+ - optional FA3 attention acceleration
11
 
12
+ The base model, accelerated transformer, and Diffusers dependency are pinned to
13
+ exact revisions. Update those pins deliberately and test the deployed Space
14
+ before merging.
 
 
15
 
16
+ ## Privacy boundary
17
 
18
+ Image inference runs inside the Space. Do not add application code that sends
19
+ prompts, input images, generated images, or generation parameters to another
20
+ service without explicit user consent and prominent UI/README disclosure.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
 
22
+ Do not print prompt text or image contents to application logs. Let Gradio
23
+ manage temporary files and keep `delete_cache` enabled.
24
 
25
+ ## Model-loading boundary
26
 
27
+ The four-step UI must use the matching accelerated transformer. Do not silently
28
+ fall back to the standard Qwen transformer while retaining a four-step default;
29
+ that produces broken or misleading output. A clear startup failure is safer
30
+ than silently changing model behavior.
31
 
32
+ ## Validation
 
 
 
 
33
 
34
+ Before deployment:
35
 
36
+ ```bash
37
+ python3 -m compileall -q .
38
+ git diff --check
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  ```
40
 
41
+ After deployment, verify:
42
 
43
+ - the Space reaches `RUNNING`
44
+ - a harmless synthetic edit succeeds
45
+ - prompts do not appear in application logs
46
+ - no unexpected application-level outbound upload paths exist
47
 
48
+ The Space uses ZeroGPU and requires Hugging Face infrastructure for model
49
+ downloads, builds, uploads, and inference hosting.
 
 
 
CLAUDE.md CHANGED
@@ -1,154 +1,4 @@
1
- # CLAUDE.md
2
 
3
- This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
4
-
5
- ## Project Overview
6
-
7
- This is a Gradio Space that implements "Next Scene" cinematic image generation using Qwen-Image-Edit-2511 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.
8
-
9
- **Key Model Components:**
10
- - Base model: `Qwen/Qwen-Image-Edit-2511` (image editing diffusion model)
11
- - Accelerated transformer: `Sneak-Moose/Qwen-Rapid-AIO-v18-NSFW-diffusers` (extracted from Phr00t's v18, 4-step optimized)
12
- - LoRA adapter: `lovis93/next-scene-qwen-image-lora-2509` (cinematic progression fine-tune, trained on 2509)
13
-
14
- ## Running the Application
15
-
16
- **Start the Gradio interface:**
17
- ```bash
18
- python app.py
19
- ```
20
-
21
- **Install dependencies:**
22
- ```bash
23
- pip install -r requirements.txt
24
- ```
25
-
26
- The app requires GPU access. It uses the `@spaces.GPU` decorator for Hugging Face Spaces zero-GPU allocation.
27
-
28
- ## Architecture
29
-
30
- ### Pipeline Flow
31
-
32
- 1. **Input Processing** (`app.py:infer`):
33
- - Accepts input images via Gradio Gallery (filepath-based)
34
- - Uses user-provided prompts directly without modification
35
-
36
- 2. **Image Generation** (`qwenimage/pipeline_qwenimage_edit_plus.py`):
37
- - Custom pipeline extending `DiffusionPipeline`
38
- - Encodes images using VAE at 1024x1024 for latents
39
- - Encodes conditioning images at 384x384 for text encoder
40
- - Packs latents into 2x2 patches (latent dims must be divisible by 2)
41
- - Uses `FlowMatchEulerDiscreteScheduler` for denoising
42
-
43
- 3. **Optimization** (`optimization.py`):
44
- - Ahead-of-time (AOT) compilation using `torch.export` and `spaces.aoti_compile`
45
- - Dynamic shapes for variable sequence lengths
46
- - Custom inductor configs for performance (max_autotune, cudagraphs)
47
- - FlashAttention 3 integration via `QwenDoubleStreamAttnProcessorFA3`
48
-
49
- 4. **Output Handling**:
50
- - Saves outputs to `outputs/` directory with unique timestamps
51
- - Maintains 20-image history gallery
52
- - Optional video generation via `multimodalart/wan-2-2-first-last-frame` Space
53
-
54
- ### Custom QwenImage Components
55
-
56
- **Location:** `qwenimage/` package
57
-
58
- - `pipeline_qwenimage_edit_plus.py` - Main diffusion pipeline with LoRA support
59
- - `transformer_qwenimage.py` - Custom transformer model with cache management
60
- - `qwen_fa3_processor.py` - FlashAttention 3 attention processor
61
-
62
- **Key architectural features:**
63
- - Latent packing/unpacking for 2x2 patch processing
64
- - Multi-image conditioning support
65
- - True CFG (classifier-free guidance) with separate pos/neg paths
66
- - Dual-stream attention with rotary embeddings
67
- - Cache contexts for conditional/unconditional forward passes
68
-
69
- ### Prompt Handling
70
-
71
- The application uses user-provided prompts directly without any preprocessing, rewriting, or AI-based enhancement. Users have full control over the exact prompt text that gets passed to the diffusion model.
72
-
73
- ## Important Implementation Details
74
-
75
- ### Image Dimension Handling
76
-
77
- Images are automatically resized based on `calculate_dimensions()` function:
78
- - VAE images: resized to maintain 1024×1024 area (1,048,576 pixels)
79
- - Condition images: resized to maintain 384×384 area (147,456 pixels)
80
- - Output dimensions must be divisible by 16 (vae_scale_factor × 2)
81
- - Height/width default to `None` which auto-calculates from input aspect ratio
82
-
83
- ### LoRA Integration
84
-
85
- The pipeline fuses the "next-scene" LoRA adapter at initialization:
86
- ```python
87
- pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509", ...)
88
- pipe.set_adapters(["next-scene"], adapter_weights=[1.])
89
- pipe.fuse_lora(adapter_names=["next-scene"], lora_scale=1.)
90
- pipe.unload_lora_weights()
91
- ```
92
-
93
- After fusion, the adapter weights are merged into the base model and cannot be unfused.
94
-
95
- ### Video Generation Integration
96
-
97
- The `turn_into_video()` function:
98
- - Connects to external Gradio Space `multimodalart/wan-2-2-first-last-frame`
99
- - Requires first input image and last output image
100
- - Uses the original prompt (or "smooth cinematic transition" fallback)
101
- - Returns video path for display
102
-
103
- ### Gradio Gallery Format
104
-
105
- Input/output galleries use `type="filepath"` (string paths) rather than PIL Image tuples. Helper functions handle format compatibility for legacy tuple support.
106
-
107
- ## Environment Variables
108
-
109
- No environment variables are required for basic operation. The application runs entirely with local models.
110
-
111
- ## File Outputs
112
-
113
- Generated images are saved to `outputs/` directory with format:
114
- ```
115
- output_{seed}_{index}_{timestamp_ms}.png
116
- ```
117
-
118
- ## Local Development and API Testing
119
-
120
- The `custom/` directory is fully gitignored and used for local development files. Specifically, it contains:
121
-
122
- - **API client scripts** - For testing the Gradio Space remotely via API after deployment to Hugging Face
123
- - **`API_GUIDE.txt`** - Auto-generated Gradio API documentation showing endpoint signatures and example usage
124
- - **Local testing environments** - Virtual environments or test data that shouldn't be committed
125
-
126
- **API Integration Pattern:**
127
- Once the Space is deployed to Hugging Face, you can interact with it programmatically using `gradio_client`:
128
-
129
- ```python
130
- from gradio_client import Client, handle_file
131
-
132
- client = Client("Sneak-Moose/Qwen-Image-Edit-next-scene")
133
- result = client.predict(
134
- images=[],
135
- prompt="Camera dollies forward, revealing more of the scene",
136
- seed=42,
137
- randomize_seed=False,
138
- true_guidance_scale=1.0,
139
- num_inference_steps=4,
140
- height=1024,
141
- width=1024,
142
- api_name="/infer"
143
- )
144
- ```
145
-
146
- The `custom/API_GUIDE.txt` contains full documentation of all available endpoints including `/infer`, `/turn_into_video`, and utility functions.
147
-
148
- ## Development Notes
149
-
150
- - The model loads on startup and applies AOT compilation during first inference
151
- - Compilation uses dynamic shapes to support variable text/image sequence lengths
152
- - The transformer uses custom cache contexts ("cond"/"uncond") to optimize CFG passes
153
- - True CFG applies norm-based rescaling: `comb_pred * (cond_norm / noise_norm)`
154
- - FlashAttention 3 processor must be set before compilation
 
1
+ # Claude Code guidance
2
 
3
+ Follow [AGENT.md](AGENT.md). It is the canonical contributor and agent guide
4
+ for this repository.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
README.md CHANGED
@@ -13,4 +13,13 @@ short_description: Powerful image editing - supports one or two input images.
13
 
14
  Pro Realism Edit Studio is a powerful image editor powered by [Qwen-Image-Edit-2511](https://huggingface.co/Qwen/Qwen-Image-Edit-2511) with [Phr00t's Rapid-AIO v18](https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO) accelerated transformer for 4-step inference. Upload one or two input images, write a prompt, get high-quality results.
15
 
16
- *This space includes a Debug Diagnostic Dashboard that collects anonymous usage data for ongoing performance monitoring.*
 
 
 
 
 
 
 
 
 
 
13
 
14
  Pro Realism Edit Studio is a powerful image editor powered by [Qwen-Image-Edit-2511](https://huggingface.co/Qwen/Qwen-Image-Edit-2511) with [Phr00t's Rapid-AIO v18](https://huggingface.co/Phr00t/Qwen-Image-Edit-Rapid-AIO) accelerated transformer for 4-step inference. Upload one or two input images, write a prompt, get high-quality results.
15
 
16
+ ## Privacy
17
+
18
+ - Image editing runs inside this Hugging Face Space using locally loaded model weights.
19
+ - The application does not send prompts or images to a separate diagnostics, analytics, or video-generation service.
20
+ - Prompts are not written to application logs.
21
+ - Hugging Face and Gradio necessarily process uploads to operate the Space. Gradio-managed temporary files are configured to expire after 24 hours.
22
+
23
+ ## Reproducibility
24
+
25
+ The base model, accelerated transformer, and development version of Diffusers are pinned to exact revisions. If the accelerated four-step transformer cannot load, the Space stops with a clear error rather than silently switching to an incompatible model.
app.py CHANGED
@@ -5,68 +5,12 @@ import torch
5
  import spaces
6
 
7
  from PIL import Image
8
- from diffusers import FlowMatchEulerDiscreteScheduler
9
- from optimization import optimize_pipeline_
10
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
11
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
12
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
13
 
14
- import math
15
- from huggingface_hub import hf_hub_download
16
- from safetensors.torch import load_file
17
-
18
- import os
19
- import time # Added for history update delay
20
- import threading
21
-
22
- from gradio_client import Client, handle_file
23
- import tempfile
24
- from PIL import Image
25
  import os
26
- import gradio as gr
27
-
28
- def turn_into_video(input_image, output_images, prompt, progress=gr.Progress(track_tqdm=True)):
29
- if not input_image or not output_images:
30
- raise gr.Error("Please generate an output image first.")
31
-
32
- progress(0.02, desc="Preparing images...")
33
-
34
- def extract_pil(img_entry):
35
- if isinstance(img_entry, tuple) and isinstance(img_entry[0], Image.Image):
36
- return img_entry[0]
37
- elif isinstance(img_entry, Image.Image):
38
- return img_entry
39
- elif isinstance(img_entry, str):
40
- return Image.open(img_entry)
41
- else:
42
- raise gr.Error(f"Unsupported image format: {type(img_entry)}")
43
-
44
- start_img = extract_pil(input_image)
45
- end_img = extract_pil(output_images[0])
46
-
47
- progress(0.10, desc="Saving temp files...")
48
-
49
- with tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_start, \
50
- tempfile.NamedTemporaryFile(suffix=".png", delete=False) as tmp_end:
51
- start_img.save(tmp_start.name)
52
- end_img.save(tmp_end.name)
53
-
54
- progress(0.20, desc="Connecting to Wan space...")
55
-
56
- client = Client("multimodalart/wan-2-2-first-last-frame")
57
-
58
- progress(0.35, desc="Generating video...")
59
-
60
- video_path, seed = client.predict(
61
- start_image_pil=handle_file(tmp_start.name),
62
- end_image_pil=handle_file(tmp_end.name),
63
- prompt=prompt or "smooth cinematic transition",
64
- api_name="/generate_video"
65
- )
66
-
67
- progress(0.95, desc="Finalizing...")
68
- print(video_path)
69
- return video_path['video']
70
 
71
 
72
  def update_history(new_images, history):
@@ -93,32 +37,32 @@ def use_history_as_input(evt: gr.SelectData):
93
  dtype = torch.bfloat16
94
  device = "cuda" if torch.cuda.is_available() else "cpu"
95
  hf_token = os.environ.get("HF_TOKEN") or None
96
-
97
- # Load Qwen-Image-Edit-2511. The upstream Space points at a private/unlisted
98
- # Sneak-Moose accelerated transformer, which breaks duplicated Spaces unless
99
- # the duplicating account has explicit access. Try it when available, but fall
100
- # back to the public Qwen transformer so this Space can boot independently.
 
 
 
101
  try:
102
  transformer = QwenImageTransformer2DModel.from_pretrained(
103
- "Sneak-Moose/Qwen-Rapid-AIO-v18-NSFW-diffusers",
104
  subfolder="transformer",
 
105
  torch_dtype=dtype,
106
  device_map="cuda" if torch.cuda.is_available() else None,
107
  token=hf_token,
108
  )
109
- print("Loaded accelerated Sneak-Moose transformer.")
110
  except Exception as exc:
111
- print(f"Accelerated transformer unavailable; falling back to public Qwen transformer: {exc}")
112
- transformer = QwenImageTransformer2DModel.from_pretrained(
113
- "Qwen/Qwen-Image-Edit-2511",
114
- subfolder="transformer",
115
- torch_dtype=dtype,
116
- device_map="cuda" if torch.cuda.is_available() else None,
117
- token=hf_token,
118
- )
119
 
120
  pipe = QwenImageEditPlusPipeline.from_pretrained(
121
- "Qwen/Qwen-Image-Edit-2511",
 
122
  transformer=transformer,
123
  torch_dtype=dtype,
124
  token=hf_token,
@@ -213,9 +157,10 @@ def infer(
213
 
214
  if height==256 and width==256:
215
  height, width = None, None
216
- print(f"Calling pipeline with prompt: '{prompt}'")
217
- print(f"Negative Prompt: '{negative_prompt}'")
218
- print(f"Seed: {seed}, Steps: {num_inference_steps}, Guidance: {true_guidance_scale}, Size: {width}x{height}")
 
219
 
220
  # Generate the image
221
  images_pil = pipe(
@@ -230,16 +175,8 @@ def infer(
230
  num_images_per_prompt=num_images_per_prompt,
231
  ).images
232
 
233
- # Save images to temporary files for proper serving
234
- output_paths = []
235
- os.makedirs("outputs", exist_ok=True)
236
- for idx, img in enumerate(images_pil):
237
- output_path = f"outputs/output_{seed}_{idx}_{int(time.time()*1000)}.png"
238
- img.save(output_path)
239
- output_paths.append(output_path)
240
-
241
- # Return image paths, seed, and make button visible
242
- return output_paths, seed, gr.update(visible=True), gr.update(visible=True)
243
 
244
 
245
  # --- UI Layout ---
@@ -257,12 +194,12 @@ css = """
257
  #edit_text{margin-top: -62px !important}
258
  """
259
 
260
- with gr.Blocks(css=css) as demo:
261
  with gr.Column(elem_id="col-container"):
262
  gr.HTML("""
263
  <div id="logo-title">
264
- <img src="https://qianwen-res.oss-cn-beijing.aliyuncs.com/Qwen-Image/qwen_image_edit_logo.png" alt="Qwen-Image Edit Logo" width="400" style="display: block; margin: 0 auto;">
265
- <h2 style="font-style: italic;color: #5b47d1;margin-top: -27px !important;margin-left: 96px">Rapid Edit ⚡</h2>
266
  </div>
267
  """)
268
  gr.Markdown("""
@@ -336,8 +273,6 @@ with gr.Blocks(css=css) as demo:
336
  result = gr.Gallery(label="Result", show_label=False, type="filepath")
337
  with gr.Row():
338
  use_output_btn = gr.Button("↗️ Use as input", variant="secondary", size="sm", visible=False)
339
- turn_video_btn = gr.Button("🎬 Turn into Video", variant="secondary", size="sm", visible=False)
340
- output_video = gr.Video(label="Generated Video", autoplay=True, visible=False)
341
 
342
  with gr.Row(visible=False):
343
  gr.Markdown("### 📜 History")
@@ -368,7 +303,7 @@ with gr.Blocks(css=css) as demo:
368
  height,
369
  width,
370
  ],
371
- outputs=[result, seed, use_output_btn, turn_video_btn],
372
 
373
  ).then(
374
  fn=update_history,
@@ -399,16 +334,5 @@ with gr.Blocks(css=css) as demo:
399
 
400
  )
401
 
402
- turn_video_btn.click(
403
- fn=lambda: gr.update(visible=True),
404
- inputs=None,
405
- outputs=[output_video],
406
- ).then(
407
- fn=turn_into_video,
408
- inputs=[image_1, result, prompt],
409
- outputs=[output_video],
410
- )
411
-
412
-
413
  if __name__ == "__main__":
414
- demo.launch()
 
5
  import spaces
6
 
7
  from PIL import Image
 
 
8
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
9
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
10
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
11
 
 
 
 
 
 
 
 
 
 
 
 
12
  import os
13
+ import time
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
 
16
  def update_history(new_images, history):
 
37
  dtype = torch.bfloat16
38
  device = "cuda" if torch.cuda.is_available() else "cpu"
39
  hf_token = os.environ.get("HF_TOKEN") or None
40
+ BASE_MODEL_ID = "Qwen/Qwen-Image-Edit-2511"
41
+ BASE_MODEL_REVISION = "6f3ccc0b56e431dc6a0c2b2039706d7d26f22cb9"
42
+ ACCELERATED_TRANSFORMER_ID = "Sneak-Moose/Qwen-Rapid-AIO-v18-NSFW-diffusers"
43
+ ACCELERATED_TRANSFORMER_REVISION = "5641245ab83ffd498c986485eb8c3e9f6f3f2184"
44
+
45
+ # This UI is tuned for four-step inference and must use the matching accelerated
46
+ # transformer. Do not silently fall back to the standard transformer: doing so
47
+ # produces misleading low-quality output while presenting the app as healthy.
48
  try:
49
  transformer = QwenImageTransformer2DModel.from_pretrained(
50
+ ACCELERATED_TRANSFORMER_ID,
51
  subfolder="transformer",
52
+ revision=ACCELERATED_TRANSFORMER_REVISION,
53
  torch_dtype=dtype,
54
  device_map="cuda" if torch.cuda.is_available() else None,
55
  token=hf_token,
56
  )
 
57
  except Exception as exc:
58
+ raise RuntimeError(
59
+ "The pinned four-step accelerated transformer could not be loaded. "
60
+ "Generation is disabled rather than silently using an incompatible fallback."
61
+ ) from exc
 
 
 
 
62
 
63
  pipe = QwenImageEditPlusPipeline.from_pretrained(
64
+ BASE_MODEL_ID,
65
+ revision=BASE_MODEL_REVISION,
66
  transformer=transformer,
67
  torch_dtype=dtype,
68
  token=hf_token,
 
157
 
158
  if height==256 and width==256:
159
  height, width = None, None
160
+ print(
161
+ f"Starting generation: seed={seed}, steps={num_inference_steps}, "
162
+ f"guidance={true_guidance_scale}, size={width}x{height}, inputs={len(pil_images)}"
163
+ )
164
 
165
  # Generate the image
166
  images_pil = pipe(
 
175
  num_images_per_prompt=num_images_per_prompt,
176
  ).images
177
 
178
+ # Let Gradio manage temporary result files so delete_cache can expire them.
179
+ return images_pil, seed, gr.update(visible=True)
 
 
 
 
 
 
 
 
180
 
181
 
182
  # --- UI Layout ---
 
194
  #edit_text{margin-top: -62px !important}
195
  """
196
 
197
+ with gr.Blocks(css=css, delete_cache=(3600, 86400)) as demo:
198
  with gr.Column(elem_id="col-container"):
199
  gr.HTML("""
200
  <div id="logo-title">
201
+ <h1>Pro Realism Edit Studio 🎨</h1>
202
+ <h2 style="font-style: italic;color: #5b47d1">Rapid Edit ⚡</h2>
203
  </div>
204
  """)
205
  gr.Markdown("""
 
273
  result = gr.Gallery(label="Result", show_label=False, type="filepath")
274
  with gr.Row():
275
  use_output_btn = gr.Button("↗️ Use as input", variant="secondary", size="sm", visible=False)
 
 
276
 
277
  with gr.Row(visible=False):
278
  gr.Markdown("### 📜 History")
 
303
  height,
304
  width,
305
  ],
306
+ outputs=[result, seed, use_output_btn],
307
 
308
  ).then(
309
  fn=update_history,
 
334
 
335
  )
336
 
 
 
 
 
 
 
 
 
 
 
 
337
  if __name__ == "__main__":
338
+ demo.launch()
requirements.txt CHANGED
@@ -1,11 +1,10 @@
1
- git+https://github.com/huggingface/diffusers.git
2
 
3
  transformers
4
  accelerate
5
  safetensors
6
  sentencepiece
7
- dashscope
8
  kernels<0.15.1
9
  torchvision
10
  peft
11
- torchao==0.11.0
 
1
+ git+https://github.com/huggingface/diffusers.git@7685bffe89041496c2c0ae07ea933df1c80d1f43
2
 
3
  transformers
4
  accelerate
5
  safetensors
6
  sentencepiece
 
7
  kernels<0.15.1
8
  torchvision
9
  peft
10
+ torchao==0.11.0