prithivMLmods commited on
Commit
73d18ae
·
verified ·
1 Parent(s): d019470

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +125 -361
app.py CHANGED
@@ -1,395 +1,159 @@
1
  import os
 
2
  import gc
 
3
  import gradio as gr
4
- import numpy as np
5
- import spaces
6
  import torch
7
- import random
8
- from PIL import Image
9
- from typing import Iterable
10
- from gradio.themes import Soft
11
- from gradio.themes.utils import colors, fonts, sizes
12
-
13
- colors.orange_red = colors.Color(
14
- name="orange_red",
15
- c50="#FFF0E5",
16
- c100="#FFE0CC",
17
- c200="#FFC299",
18
- c300="#FFA366",
19
- c400="#FF8533",
20
- c500="#FF4500",
21
- c600="#E63E00",
22
- c700="#CC3700",
23
- c800="#B33000",
24
- c900="#992900",
25
- c950="#802200",
26
- )
27
-
28
- class OrangeRedTheme(Soft):
29
- def __init__(
30
- self,
31
- *,
32
- primary_hue: colors.Color | str = colors.gray,
33
- secondary_hue: colors.Color | str = colors.orange_red,
34
- neutral_hue: colors.Color | str = colors.slate,
35
- text_size: sizes.Size | str = sizes.text_lg,
36
- font: fonts.Font | str | Iterable[fonts.Font | str] = (
37
- fonts.GoogleFont("Outfit"), "Arial", "sans-serif",
38
- ),
39
- font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
40
- fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
41
- ),
42
- ):
43
- super().__init__(
44
- primary_hue=primary_hue,
45
- secondary_hue=secondary_hue,
46
- neutral_hue=neutral_hue,
47
- text_size=text_size,
48
- font=font,
49
- font_mono=font_mono,
50
- )
51
- super().set(
52
- background_fill_primary="*primary_50",
53
- background_fill_primary_dark="*primary_900",
54
- body_background_fill="linear-gradient(135deg, *primary_200, *primary_100)",
55
- body_background_fill_dark="linear-gradient(135deg, *primary_900, *primary_800)",
56
- button_primary_text_color="white",
57
- button_primary_text_color_hover="white",
58
- button_primary_background_fill="linear-gradient(90deg, *secondary_500, *secondary_600)",
59
- button_primary_background_fill_hover="linear-gradient(90deg, *secondary_600, *secondary_700)",
60
- button_primary_background_fill_dark="linear-gradient(90deg, *secondary_600, *secondary_700)",
61
- button_primary_background_fill_hover_dark="linear-gradient(90deg, *secondary_500, *secondary_600)",
62
- button_secondary_text_color="black",
63
- button_secondary_text_color_hover="white",
64
- button_secondary_background_fill="linear-gradient(90deg, *primary_300, *primary_300)",
65
- button_secondary_background_fill_hover="linear-gradient(90deg, *primary_400, *primary_400)",
66
- button_secondary_background_fill_dark="linear-gradient(90deg, *primary_500, *primary_600)",
67
- button_secondary_background_fill_hover_dark="linear-gradient(90deg, *primary_500, *primary_500)",
68
- slider_color="*secondary_500",
69
- slider_color_dark="*secondary_600",
70
- block_title_text_weight="600",
71
- block_border_width="3px",
72
- block_shadow="*shadow_drop_lg",
73
- button_primary_shadow="*shadow_drop_lg",
74
- button_large_padding="11px",
75
- color_accent_soft="*primary_100",
76
- block_label_background_fill="*primary_200",
77
- )
78
-
79
- orange_red_theme = OrangeRedTheme()
80
 
81
- device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
82
-
83
- print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
84
- print("torch.__version__ =", torch.__version__)
85
- print("Using device:", device)
86
-
87
- from diffusers import FlowMatchEulerDiscreteScheduler
88
- from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
89
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
90
- from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
91
-
92
- dtype = torch.bfloat16
93
-
94
- pipe = QwenImageEditPlusPipeline.from_pretrained(
95
- "Qwen/Qwen-Image-Edit-2511",
96
- transformer=QwenImageTransformer2DModel.from_pretrained(
97
- "linoyts/Qwen-Image-Edit-Rapid-AIO",
98
- subfolder='transformer',
99
- torch_dtype=dtype,
100
- device_map='cuda'
101
- ),
102
- torch_dtype=dtype
103
- ).to(device)
104
 
105
- try:
106
- pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
107
- print("Flash Attention 3 Processor set successfully.")
108
- except Exception as e:
109
- print(f"Warning: Could not set FA3 processor: {e}")
110
-
111
- MAX_SEED = np.iinfo(np.int32).max
112
-
113
- ADAPTER_SPECS = {
114
- "Multiple-Angles": {
115
- "repo": "dx8152/Qwen-Edit-2509-Multiple-angles",
116
- "weights": "镜头转换.safetensors",
117
- "adapter_name": "multiple-angles"
118
- },
119
- "Photo-to-Anime": {
120
- "repo": "autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
121
- "weights": "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
122
- "adapter_name": "photo-to-anime"
123
- },
124
- "Anime-V2": {
125
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Anime",
126
- "weights": "Qwen-Image-Edit-2511-Anime-2000.safetensors",
127
- "adapter_name": "anime-v2"
128
- },
129
- "Light-Migration": {
130
- "repo": "dx8152/Qwen-Edit-2509-Light-Migration",
131
- "weights": "参考色调.safetensors",
132
- "adapter_name": "light-migration"
133
- },
134
- "Upscaler": {
135
- "repo": "starsfriday/Qwen-Image-Edit-2511-Upscale2K",
136
- "weights": "qwen_image_edit_2511_upscale.safetensors",
137
- "adapter_name": "upscale-2k"
138
- },
139
- "Style-Transfer": {
140
- "repo": "zooeyy/Style-Transfer",
141
- "weights": "Style Transfer-Alpha-V0.1.safetensors",
142
- "adapter_name": "style-transfer"
143
- },
144
- "Manga-Tone": {
145
- "repo": "nappa114514/Qwen-Image-Edit-2509-Manga-Tone",
146
- "weights": "tone001.safetensors",
147
- "adapter_name": "manga-tone"
148
- },
149
- "Anything2Real": {
150
- "repo": "lrzjason/Anything2Real_2601",
151
- "weights": "anything2real_2601.safetensors",
152
- "adapter_name": "anything2real"
153
- },
154
- "Fal-Multiple-Angles": {
155
- "repo": "fal/Qwen-Image-Edit-2511-Multiple-Angles-LoRA",
156
- "weights": "qwen-image-edit-2511-multiple-angles-lora.safetensors",
157
- "adapter_name": "fal-multiple-angles"
158
- },
159
- "Polaroid-Photo": {
160
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Polaroid-Photo",
161
- "weights": "Qwen-Image-Edit-2511-Polaroid-Photo.safetensors",
162
- "adapter_name": "polaroid-photo"
163
- },
164
- "Unblur-Anything": {
165
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Unblur-Upscale",
166
- "weights": "Qwen-Image-Edit-Unblur-Upscale_15.safetensors",
167
- "adapter_name": "unblur-anything"
168
- },
169
- "Midnight-Noir-Eyes-Spotlight": {
170
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Midnight-Noir-Eyes-Spotlight",
171
- "weights": "Qwen-Image-Edit-2511-Midnight-Noir-Eyes-Spotlight.safetensors",
172
- "adapter_name": "midnight-noir-eyes-spotlight"
173
- },
174
- "Hyper-Realistic-Portrait": {
175
- "repo": "prithivMLmods/Qwen-Image-Edit-2511-Hyper-Realistic-Portrait",
176
- "weights": "HRP_20.safetensors",
177
- "adapter_name": "hyper-realistic-portrait"
178
- },
179
  }
180
 
181
- LOADED_ADAPTERS = set()
182
-
183
- def update_dimensions_on_upload(image):
184
- if image is None:
185
- return 1024, 1024
 
 
 
186
 
187
- original_width, original_height = image.size
188
 
189
- if original_width > original_height:
190
- new_width = 1024
191
- aspect_ratio = original_height / original_width
192
- new_height = int(new_width * aspect_ratio)
193
- else:
194
- new_height = 1024
195
- aspect_ratio = original_width / original_height
196
- new_width = int(new_height * aspect_ratio)
197
-
198
- new_width = (new_width // 8) * 8
199
- new_height = (new_height // 8) * 8
200
 
201
- return new_width, new_height
 
 
 
 
202
 
203
- @spaces.GPU
204
- def infer(
205
- images,
206
- prompt,
207
- lora_adapter,
208
- seed,
209
- randomize_seed,
210
- guidance_scale,
211
- steps,
212
- progress=gr.Progress(track_tqdm=True)
213
- ):
214
- gc.collect()
215
- torch.cuda.empty_cache()
216
 
217
- if not images:
218
- raise gr.Error("Please upload at least one image to edit.")
 
 
219
 
220
- pil_images = []
221
- if images is not None:
222
- for item in images:
223
- try:
224
- if isinstance(item, tuple) or isinstance(item, list):
225
- path_or_img = item[0]
226
- else:
227
- path_or_img = item
228
 
229
- if isinstance(path_or_img, str):
230
- pil_images.append(Image.open(path_or_img).convert("RGB"))
231
- elif isinstance(path_or_img, Image.Image):
232
- pil_images.append(path_or_img.convert("RGB"))
233
- else:
234
- pil_images.append(Image.open(path_or_img.name).convert("RGB"))
235
- except Exception as e:
236
- print(f"Skipping invalid image item: {e}")
237
  continue
 
 
 
 
 
 
 
 
238
 
239
- if not pil_images:
240
- raise gr.Error("Could not process uploaded images.")
241
-
242
- spec = ADAPTER_SPECS.get(lora_adapter)
243
- if not spec:
244
- raise gr.Error(f"Configuration not found for: {lora_adapter}")
245
-
246
- adapter_name = spec["adapter_name"]
247
-
248
- if adapter_name not in LOADED_ADAPTERS:
249
- print(f"--- Downloading and Loading Adapter: {lora_adapter} ---")
250
- try:
251
- pipe.load_lora_weights(
252
- spec["repo"],
253
- weight_name=spec["weights"],
254
- adapter_name=adapter_name
255
- )
256
- LOADED_ADAPTERS.add(adapter_name)
257
- except Exception as e:
258
- raise gr.Error(f"Failed to load adapter {lora_adapter}: {e}")
259
- else:
260
- print(f"--- Adapter {lora_adapter} is already loaded. ---")
261
-
262
- pipe.set_adapters([adapter_name], adapter_weights=[1.0])
263
-
264
- if randomize_seed:
265
- seed = random.randint(0, MAX_SEED)
266
-
267
- generator = torch.Generator(device=device).manual_seed(seed)
268
- negative_prompt = "worst quality, low quality, bad anatomy, bad hands, text, error, missing fingers, extra digit, fewer digits, cropped, jpeg artifacts, signature, watermark, username, blurry"
269
 
270
- width, height = update_dimensions_on_upload(pil_images[0])
 
 
 
 
 
 
 
 
 
 
271
 
 
 
272
  try:
273
- result_image = pipe(
274
- image=pil_images,
275
- prompt=prompt,
276
- negative_prompt=negative_prompt,
277
- height=height,
278
- width=width,
279
- num_inference_steps=steps,
280
- generator=generator,
281
- true_cfg_scale=guidance_scale,
282
- ).images[0]
283
 
284
- return result_image, seed
285
-
 
 
 
286
  except Exception as e:
287
- raise e
288
- finally:
289
- gc.collect()
290
- torch.cuda.empty_cache()
291
-
292
- @spaces.GPU
293
- def infer_example(images, prompt, lora_adapter):
294
- if not images:
295
- return None, 0
296
-
297
- if isinstance(images, str):
298
- images_list = [images]
299
- else:
300
- images_list = images
301
 
302
- result, seed = infer(
303
- images=images_list,
304
- prompt=prompt,
305
- lora_adapter=lora_adapter,
306
- seed=0,
307
- randomize_seed=True,
308
- guidance_scale=1.0,
309
- steps=4
310
- )
311
- return result, seed
312
 
313
- css="""
314
- #col-container {
315
- margin: 0 auto;
316
- max-width: 1000px;
317
- }
318
- #main-title h1 {font-size: 2.3em !important;}
319
  """
320
 
321
  with gr.Blocks() as demo:
322
  with gr.Column(elem_id="col-container"):
323
- gr.Markdown("# **Qwen-Image-Edit-2511-LoRAs-Fast**", elem_id="main-title")
324
- gr.Markdown("Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2511) adapters. Upload one or more images.")
325
-
326
- with gr.Row(equal_height=True):
327
- with gr.Column():
328
- images = gr.Gallery(
329
- label="Upload Images",
330
- type="filepath",
331
- columns=2,
332
- rows=1,
333
- height=300,
334
- allow_preview=True
335
- )
336
-
337
- prompt = gr.Text(
338
- label="Edit Prompt",
339
- show_label=True,
340
- placeholder="e.g., transform into anime..",
341
- )
342
-
343
- run_button = gr.Button("Edit Image", variant="primary")
344
-
345
- with gr.Column():
346
- output_image = gr.Image(label="Output Image", interactive=False, format="png", height=363)
347
-
348
- with gr.Row():
349
- lora_adapter = gr.Dropdown(
350
- label="Choose Editing Style",
351
- choices=list(ADAPTER_SPECS.keys()),
352
- value="Photo-to-Anime"
353
- )
354
-
355
- with gr.Accordion("Advanced Settings", open=False, visible=False):
356
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
357
- randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
358
- guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
359
- steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
360
-
361
- gr.Examples(
362
- examples=[
363
- [["examples/B.jpg"], "Transform into anime.", "Photo-to-Anime"],
364
- [["examples/A.jpeg"], "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
365
- [["examples/U.jpg"], "Upscale this picture to 4K resolution.", "Upscaler"],
366
- [["examples/PP1.jpg"], "cinematic polaroid with soft grain subtle vignette gentle lighting white frame handwritten photographed by hf‪‪‬ preserving realistic texture and details", "Polaroid-Photo"],
367
- [["examples/Z1.jpg"], "Front-right quarter view.", "Fal-Multiple-Angles"],
368
- [["examples/Z2.jpg"], "Back-left quarter view.", "Fal-Multiple-Angles"],
369
- [["examples/Z3.jpg"], "Left side view, Balanced, standard.", "Fal-Multiple-Angles"],
370
- [["examples/HRP.jpg"], "Transform into a hyper-realistic face portrait.", "Hyper-Realistic-Portrait"],
371
- [["examples/MT.jpg"], "Paint with manga tone.", "Manga-Tone"],
372
- [["examples/MN.jpg"], "Transform into Midnight Noir Eyes Spotlight.", "Midnight-Noir-Eyes-Spotlight"],
373
- [["examples/ST1.jpg", "examples/ST2.jpg"], "Convert Image 1 to the style of Image 2.", "Style-Transfer"],
374
- [["examples/R1.jpg"], "Change the picture to realistic photograph.", "Anything2Real"],
375
- [["examples/UA.jpeg"], "Unblur and upscale.", "Unblur-Anything"],
376
- [["examples/L1.jpg", "examples/L2.jpg"], "Refer to the color tone, remove the original lighting from Image 1, and relight Image 1 based on the lighting and color tone of Image 2.", "Light-Migration"],
377
- [["examples/P1.jpg"], "Transform into anime (while preserving the background and remaining elements maintaining realism and original details.)", "Anime-V2"],
378
- ],
379
- inputs=[images, prompt, lora_adapter],
380
- outputs=[output_image, seed],
381
- fn=infer_example,
382
- cache_examples=False,
383
- label="Examples"
384
  )
385
 
386
- gr.Markdown("[*](https://huggingface.co/spaces/prithivMLmods/Qwen-Image-Edit-2511-LoRAs-Fast)This is still an experimental Space for Qwen-Image-Edit-2511.")
387
-
388
- run_button.click(
389
- fn=infer,
390
- inputs=[images, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
391
- outputs=[output_image, seed]
 
 
 
 
 
 
 
 
 
 
 
 
 
392
  )
393
 
394
  if __name__ == "__main__":
395
- demo.queue(max_size=30).launch(css=css, theme=orange_red_theme, mcp_server=True, ssr_mode=False, show_error=True)
 
1
  import os
2
+ import spaces
3
  import gc
4
+ import shutil
5
  import gradio as gr
 
 
6
  import torch
7
+ import safetensors.torch
8
+ from huggingface_hub import hf_hub_download, HfApi, login
9
+ from accelerate import init_empty_weights
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
10
 
11
+ # --- Imports from your local modules ---
12
+ # Ensure the folder 'qwenimage' is present in the root directory
 
 
 
 
 
 
13
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
 
15
+ # Configuration for the specific Qwen Transformer
16
+ TRANSFORMER_CONFIG = {
17
+ "attention_head_dim": 128,
18
+ "axes_dims_rope": [16, 56, 56],
19
+ "guidance_embeds": False,
20
+ "in_channels": 64,
21
+ "joint_attention_dim": 3584,
22
+ "num_attention_heads": 24,
23
+ "num_layers": 60,
24
+ "out_channels": 16,
25
+ "patch_size": 2
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  }
27
 
28
+ @spaces.GPU(duration=300)
29
+ def convert_and_upload(hf_token, target_repo_id, private_repo):
30
+ """
31
+ Downloads raw weights, converts keys, saves locally, and uploads to HF.
32
+ """
33
+ local_dir = "converted_qwen_transformer"
34
+ source_repo = "Phr00t/Qwen-Image-Edit-Rapid-AIO"
35
+ source_filename = "v19/Qwen-Rapid-AIO-NSFW-v19.safetensors"
36
 
37
+ yield f"🚀 Starting process...\nAuthenticating with Hugging Face..."
38
 
39
+ if not hf_token:
40
+ raise gr.Error("Please provide a Write-enabled Hugging Face Token.")
 
 
 
 
 
 
 
 
 
41
 
42
+ try:
43
+ login(token=hf_token)
44
+ api = HfApi(token=hf_token)
45
+ except Exception as e:
46
+ raise gr.Error(f"Authentication failed: {e}")
47
 
48
+ # 1. Download
49
+ yield f"📥 Downloading {source_filename} from {source_repo}..."
50
+ try:
51
+ checkpoint_path = hf_hub_download(repo_id=source_repo, filename=source_filename)
52
+ except Exception as e:
53
+ raise gr.Error(f"Download failed: {e}")
 
 
 
 
 
 
 
54
 
55
+ # 2. Initialize Empty Model
56
+ yield "🏗️ Initializing empty model architecture..."
57
+ with init_empty_weights():
58
+ model = QwenImageTransformer2DModel(**TRANSFORMER_CONFIG)
59
 
60
+ # 3. Load and Filter Keys
61
+ yield "🔑 Loading state dict and filtering keys (removing 'model.diffusion_model.')..."
62
+ try:
63
+ state_dict = safetensors.torch.load_file(checkpoint_path, device="cpu")
64
+
65
+ new_state_dict = {}
66
+ prefix = "model.diffusion_model."
67
+ ignored_keys = ["__index_timestep_zero__", "iteration", "global_step"]
68
 
69
+ for key, value in state_dict.items():
70
+ if key in ignored_keys:
 
 
 
 
 
 
71
  continue
72
+ if key.startswith(prefix):
73
+ new_key = key[len(prefix):]
74
+ new_state_dict[new_key] = value
75
+
76
+ del state_dict
77
+ gc.collect()
78
+ except Exception as e:
79
+ raise gr.Error(f"Error processing keys: {e}")
80
 
81
+ # 4. Load Weights into Model
82
+ yield "⚖️ Loading weights into the model object..."
83
+ try:
84
+ # assign=True is needed for accelerate's init_empty_weights
85
+ model.load_state_dict(new_state_dict, assign=True, strict=False)
86
+ del new_state_dict
87
+ gc.collect()
88
+ except Exception as e:
89
+ raise gr.Error(f"Error loading weights into model: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
90
 
91
+ # 5. Save Locally
92
+ if os.path.exists(local_dir):
93
+ shutil.rmtree(local_dir)
94
+ os.makedirs(local_dir, exist_ok=True)
95
+
96
+ yield f"💾 Saving converted model to local directory: {local_dir}..."
97
+ try:
98
+ # This saves both config.json and diffusion_pytorch_model.safetensors
99
+ model.save_pretrained(local_dir, safe_serialization=True)
100
+ except Exception as e:
101
+ raise gr.Error(f"Error saving local model: {e}")
102
 
103
+ # 6. Upload to Hugging Face
104
+ yield f"☁️ Uploading to Hugging Face Repo: {target_repo_id}..."
105
  try:
106
+ # Create repo if it doesn't exist
107
+ api.create_repo(repo_id=target_repo_id, private=private_repo, exist_ok=True)
 
 
 
 
 
 
 
 
108
 
109
+ api.upload_folder(
110
+ folder_path=local_dir,
111
+ repo_id=target_repo_id,
112
+ commit_message="Upload converted Qwen-Image-Edit Transformer"
113
+ )
114
  except Exception as e:
115
+ raise gr.Error(f"Upload failed: {e}")
 
 
 
 
 
 
 
 
 
 
 
 
 
116
 
117
+ # Cleanup
118
+ shutil.rmtree(local_dir)
119
+ gc.collect()
120
+
121
+ yield f"✅ Success! Model uploaded to https://huggingface.co/{target_repo_id}"
 
 
 
 
 
122
 
123
+ # --- Gradio UI ---
124
+
125
+ css = """
126
+ #col-container { max_width: 700px; margin: 0 auto; }
 
 
127
  """
128
 
129
  with gr.Blocks() as demo:
130
  with gr.Column(elem_id="col-container"):
131
+ gr.Markdown("# 🔄 Qwen Transformer Converter & Uploader")
132
+ gr.Markdown(
133
+ "This tool downloads the raw checkpoints for `Qwen-Image-Edit`, extracts the transformer, "
134
+ "fixes the key names, and uploads the clean `diffusers`-ready model to your Hugging Face account."
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
135
  )
136
 
137
+ with gr.Group():
138
+ hf_token = gr.Textbox(
139
+ label="Hugging Face Token (Write Access)",
140
+ placeholder="hf_...",
141
+ type="password"
142
+ )
143
+ target_repo = gr.Textbox(
144
+ label="Target Repository ID",
145
+ placeholder="username/my-converted-qwen-transformer"
146
+ )
147
+ is_private = gr.Checkbox(label="Make Repo Private", value=True)
148
+
149
+ convert_btn = gr.Button("Convert & Upload", variant="primary")
150
+ status_output = gr.Textbox(label="Status Log", interactive=False, lines=6)
151
+
152
+ convert_btn.click(
153
+ fn=convert_and_upload,
154
+ inputs=[hf_token, target_repo, is_private],
155
+ outputs=[status_output]
156
  )
157
 
158
  if __name__ == "__main__":
159
+ demo.queue().launch(theme=gr.themes.Soft(), css=css)