Opera8 commited on
Commit
2210ab4
·
verified ·
1 Parent(s): ad1b5e0

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +114 -69
app.py CHANGED
@@ -8,7 +8,9 @@ from PIL import Image
8
  from typing import Iterable
9
  from gradio.themes import Soft
10
  from gradio.themes.utils import colors, fonts, sizes
 
11
 
 
12
  colors.steel_blue = colors.Color(
13
  name="steel_blue",
14
  c50="#EBF3F8",
@@ -33,7 +35,7 @@ class SteelBlueTheme(Soft):
33
  neutral_hue: colors.Color | str = colors.slate,
34
  text_size: sizes.Size | str = sizes.text_lg,
35
  font: fonts.Font | str | Iterable[fonts.Font | str] = (
36
- fonts.GoogleFont("Outfit"), "Arial", "sans-serif",
37
  ),
38
  font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
39
  fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
@@ -79,17 +81,7 @@ steel_blue_theme = SteelBlueTheme()
79
 
80
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
81
 
82
- print("CUDA_VISIBLE_DEVICES=", os.environ.get("CUDA_VISIBLE_DEVICES"))
83
- print("torch.__version__ =", torch.__version__)
84
- print("torch.version.cuda =", torch.version.cuda)
85
- print("cuda available:", torch.cuda.is_available())
86
- print("cuda device count:", torch.cuda.device_count())
87
- if torch.cuda.is_available():
88
- print("current device:", torch.cuda.current_device())
89
- print("device name:", torch.cuda.get_device_name(torch.cuda.current_device()))
90
-
91
- print("Using device:", device)
92
-
93
  from diffusers import FlowMatchEulerDiscreteScheduler
94
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
95
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
@@ -98,10 +90,11 @@ from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
98
  dtype = torch.bfloat16
99
  device = "cuda" if torch.cuda.is_available() else "cpu"
100
 
 
101
  pipe = QwenImageEditPlusPipeline.from_pretrained(
102
  "Qwen/Qwen-Image-Edit-2509",
103
  transformer=QwenImageTransformer2DModel.from_pretrained(
104
- "linoyts/Qwen-Image-Edit-Rapid-AIO", # [transformer weights extracted from: Phr00t/Qwen-Image-Edit-Rapid-AIO]
105
  subfolder='transformer',
106
  torch_dtype=dtype,
107
  device_map='cuda'
@@ -109,6 +102,7 @@ pipe = QwenImageEditPlusPipeline.from_pretrained(
109
  torch_dtype=dtype
110
  ).to(device)
111
 
 
112
  pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
113
  weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
114
  adapter_name="anime")
@@ -137,6 +131,31 @@ pipe.load_lora_weights("vafipas663/Qwen-Edit-2509-Upscale-LoRA",
137
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
138
  MAX_SEED = np.iinfo(np.int32).max
139
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
140
  def update_dimensions_on_upload(image):
141
  if image is None:
142
  return 1024, 1024
@@ -162,7 +181,7 @@ def update_dimensions_on_upload(image):
162
  def infer(
163
  input_image,
164
  prompt,
165
- lora_adapter,
166
  seed,
167
  randomize_seed,
168
  guidance_scale,
@@ -170,39 +189,34 @@ def infer(
170
  progress=gr.Progress(track_tqdm=True)
171
  ):
172
  if input_image is None:
173
- raise gr.Error("Please upload an image to edit.")
174
-
175
- if lora_adapter == "Photo-to-Anime":
176
- pipe.set_adapters(["anime"], adapter_weights=[1.0])
177
- elif lora_adapter == "Multiple-Angles":
178
- pipe.set_adapters(["multiple-angles"], adapter_weights=[1.0])
179
- elif lora_adapter == "Light-Restoration":
180
- pipe.set_adapters(["light-restoration"], adapter_weights=[1.0])
181
- elif lora_adapter == "Relight":
182
- pipe.set_adapters(["relight"], adapter_weights=[1.0])
183
- elif lora_adapter == "Multi-Angle-Lighting":
184
- pipe.set_adapters(["multi-angle-lighting"], adapter_weights=[1.0])
185
- elif lora_adapter == "Edit-Skin":
186
- pipe.set_adapters(["edit-skin"], adapter_weights=[1.0])
187
- elif lora_adapter == "Next-Scene":
188
- pipe.set_adapters(["next-scene"], adapter_weights=[1.0])
189
- elif lora_adapter == "Upscale-Image":
190
- pipe.set_adapters(["upscale-image"], adapter_weights=[1.0])
191
-
192
  if randomize_seed:
193
  seed = random.randint(0, MAX_SEED)
194
 
195
  generator = torch.Generator(device=device).manual_seed(seed)
 
196
  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"
197
 
198
  original_image = input_image.convert("RGB")
199
 
200
- # Use the new function to update dimensions
201
  width, height = update_dimensions_on_upload(original_image)
202
 
203
  result = pipe(
204
  image=original_image,
205
- prompt=prompt,
206
  negative_prompt=negative_prompt,
207
  height=height,
208
  width=width,
@@ -218,73 +232,104 @@ def infer_example(input_image, prompt, lora_adapter):
218
  input_pil = input_image.convert("RGB")
219
  guidance_scale = 1.0
220
  steps = 4
 
221
  result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
222
  return result, seed
223
 
224
 
 
225
  css="""
 
 
 
 
 
 
226
  #col-container {
227
  margin: 0 auto;
228
  max-width: 960px;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
229
  }
230
- #main-title h1 {font-size: 2.1em !important;}
231
  """
232
 
233
- with gr.Blocks() as demo:
234
  with gr.Column(elem_id="col-container"):
235
- gr.Markdown("# **Qwen-Image-Edit-2509-LoRAs-Fast**", elem_id="main-title")
236
- gr.Markdown("Perform diverse image edits using specialized [LoRA](https://huggingface.co/models?other=base_model:adapter:Qwen/Qwen-Image-Edit-2509) adapters for the [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) model.")
 
 
 
 
237
 
238
  with gr.Row(equal_height=True):
239
  with gr.Column():
240
- input_image = gr.Image(label="Upload Image", type="pil", height=290)
241
 
242
  prompt = gr.Text(
243
- label="Edit Prompt",
244
  show_label=True,
245
- placeholder="e.g., transform into anime..",
 
246
  )
247
 
248
- run_button = gr.Button("Edit Image", variant="primary")
249
 
250
  with gr.Column():
251
- output_image = gr.Image(label="Output Image", interactive=False, format="png", height=353)
252
 
253
  with gr.Row():
254
  lora_adapter = gr.Dropdown(
255
- label="Choose Editing Style",
256
- choices=["Photo-to-Anime", "Multiple-Angles", "Light-Restoration", "Multi-Angle-Lighting", "Upscale-Image", "Relight", "Next-Scene", "Edit-Skin"],
257
- value="Photo-to-Anime"
258
  )
259
- with gr.Accordion("Advanced Settings", open=False, visible=False):
260
- seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
261
- randomize_seed = gr.Checkbox(label="Randomize Seed", value=True)
262
- guidance_scale = gr.Slider(label="Guidance Scale", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
263
- steps = gr.Slider(label="Inference Steps", minimum=1, maximum=50, step=1, value=4)
264
 
 
265
  gr.Examples(
266
  examples=[
267
- ["examples/1.jpg", "Transform into anime.", "Photo-to-Anime"],
268
- ["examples/5.jpg", "Remove shadows and relight the image using soft lighting.", "Light-Restoration"],
269
- ["examples/4.jpg", "Use a subtle golden-hour filter with smooth light diffusion.", "Relight"],
270
- ["examples/2.jpeg", "Rotate the camera 45 degrees to the left.", "Multiple-Angles"],
271
- ["examples/7.jpg", "Light source from the Right Rear", "Multi-Angle-Lighting"],
272
- ["examples/10.jpeg", "Upscale the image.", "Upscale-Image"],
273
- ["examples/7.jpg", "Light source from the Below", "Multi-Angle-Lighting"],
274
- ["examples/2.jpeg", "Switch the camera to a top-down right corner view.", "Multiple-Angles"],
275
- ["examples/9.jpg", "The camera moves slightly forward as sunlight breaks through the clouds, casting a soft glow around the character's silhouette in the mist. Realistic cinematic style, atmospheric depth.", "Next-Scene"],
276
- ["examples/8.jpg", "Make the subjects skin details more prominent and natural.", "Edit-Skin"],
277
- ["examples/6.jpg", "Switch the camera to a bottom-up view.", "Multiple-Angles"],
278
- ["examples/6.jpg", "Rotate the camera 180 degrees upside down.", "Multiple-Angles"],
279
- ["examples/4.jpg", "Rotate the camera 45 degrees to the right.", "Multiple-Angles"],
280
- ["examples/4.jpg", "Switch the camera to a top-down view.", "Multiple-Angles"],
281
- ["examples/4.jpg", "Switch the camera to a wide-angle lens.", "Multiple-Angles"],
282
  ],
283
  inputs=[input_image, prompt, lora_adapter],
284
  outputs=[output_image, seed],
285
  fn=infer_example,
286
  cache_examples=False,
287
- label="Examples"
288
  )
289
 
290
  run_button.click(
@@ -294,4 +339,4 @@ with gr.Blocks() as demo:
294
  )
295
 
296
  if __name__ == "__main__":
297
- demo.queue(max_size=30).launch(css=css, theme=steel_blue_theme, mcp_server=True, ssr_mode=False, show_error=True)
 
8
  from typing import Iterable
9
  from gradio.themes import Soft
10
  from gradio.themes.utils import colors, fonts, sizes
11
+ from deep_translator import GoogleTranslator # کتابخانه ترجمه اضافه شد
12
 
13
+ # --- تنظیمات تم ---
14
  colors.steel_blue = colors.Color(
15
  name="steel_blue",
16
  c50="#EBF3F8",
 
35
  neutral_hue: colors.Color | str = colors.slate,
36
  text_size: sizes.Size | str = sizes.text_lg,
37
  font: fonts.Font | str | Iterable[fonts.Font | str] = (
38
+ fonts.GoogleFont("Vazirmatn"), "Arial", "sans-serif", # فونت وزیر برای فارسی بهتر است
39
  ),
40
  font_mono: fonts.Font | str | Iterable[fonts.Font | str] = (
41
  fonts.GoogleFont("IBM Plex Mono"), "ui-monospace", "monospace",
 
81
 
82
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
83
 
84
+ # --- بارگذاری مدل ---
 
 
 
 
 
 
 
 
 
 
85
  from diffusers import FlowMatchEulerDiscreteScheduler
86
  from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
87
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
 
90
  dtype = torch.bfloat16
91
  device = "cuda" if torch.cuda.is_available() else "cpu"
92
 
93
+ print("Loading pipeline...")
94
  pipe = QwenImageEditPlusPipeline.from_pretrained(
95
  "Qwen/Qwen-Image-Edit-2509",
96
  transformer=QwenImageTransformer2DModel.from_pretrained(
97
+ "linoyts/Qwen-Image-Edit-Rapid-AIO",
98
  subfolder='transformer',
99
  torch_dtype=dtype,
100
  device_map='cuda'
 
102
  torch_dtype=dtype
103
  ).to(device)
104
 
105
+ # بارگذاری LoRA ها
106
  pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
107
  weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
108
  adapter_name="anime")
 
131
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
132
  MAX_SEED = np.iinfo(np.int32).max
133
 
134
+ # --- نگاشت نام‌های فارسی به نام‌های داخلی مدل ---
135
+ LORA_MAPPING = {
136
+ "تبدیل عکس به انیمه": "anime",
137
+ "تغییر زاویه دید": "multiple-angles",
138
+ "اصلاح نور و سایه": "light-restoration",
139
+ "نورپردازی مجدد (Relight)": "relight",
140
+ "نورپردازی چند زاویه‌ای": "multi-angle-lighting",
141
+ "روتوش پوست": "edit-skin",
142
+ "صحنه بعدی (سینمایی)": "next-scene",
143
+ "افزایش کیفیت (Upscale)": "upscale-image"
144
+ }
145
+
146
+ def translate_prompt(text):
147
+ """ترجمه متن فارسی به انگلیسی"""
148
+ if not text:
149
+ return ""
150
+ try:
151
+ # اگر متن تماماً انگلیسی باشد، ممکن است نیازی به ترجمه نباشد اما auto هندل می‌کند
152
+ translated = GoogleTranslator(source='auto', target='en').translate(text)
153
+ print(f"Original: {text} -> Translated: {translated}")
154
+ return translated
155
+ except Exception as e:
156
+ print(f"Translation Error: {e}")
157
+ return text # در صورت خطا متن اصلی را برمی‌گرداند
158
+
159
  def update_dimensions_on_upload(image):
160
  if image is None:
161
  return 1024, 1024
 
181
  def infer(
182
  input_image,
183
  prompt,
184
+ lora_adapter_persian, # ورودی نام فارسی است
185
  seed,
186
  randomize_seed,
187
  guidance_scale,
 
189
  progress=gr.Progress(track_tqdm=True)
190
  ):
191
  if input_image is None:
192
+ raise gr.Error("لطفاً یک تصویر برای ویرایش بارگذاری کنید.")
193
+
194
+ # ترجمه متن کاربر
195
+ english_prompt = translate_prompt(prompt)
196
+
197
+ # انتخاب آداپتور بر اساس نام فارسی
198
+ adapter_internal_name = LORA_MAPPING.get(lora_adapter_persian)
199
+
200
+ # غیرفعال کردن همه آداپتورها ابتدا (برای اطمینان)
201
+ # pipe.disable_lora() # متد دقیق ممکن است متفاوت باشد اما set_adapters جایگزین می‌کند
202
+
203
+ if adapter_internal_name:
204
+ pipe.set_adapters([adapter_internal_name], adapter_weights=[1.0])
205
+
 
 
 
 
 
206
  if randomize_seed:
207
  seed = random.randint(0, MAX_SEED)
208
 
209
  generator = torch.Generator(device=device).manual_seed(seed)
210
+ # پرامپت منفی به انگلیسی (ثابت)
211
  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"
212
 
213
  original_image = input_image.convert("RGB")
214
 
 
215
  width, height = update_dimensions_on_upload(original_image)
216
 
217
  result = pipe(
218
  image=original_image,
219
+ prompt=english_prompt, # استفاده از متن ترجمه شده
220
  negative_prompt=negative_prompt,
221
  height=height,
222
  width=width,
 
232
  input_pil = input_image.convert("RGB")
233
  guidance_scale = 1.0
234
  steps = 4
235
+ # infer به صورت خودکار ترجمه را انجام می‌دهد
236
  result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
237
  return result, seed
238
 
239
 
240
+ # استایل CSS برای راست‌چین کردن (RTL) و فونت فارسی
241
  css="""
242
+ @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@400;700&display=swap');
243
+
244
+ body, .gradio-container {
245
+ font-family: 'Vazirmatn', sans-serif !important;
246
+ }
247
+
248
  #col-container {
249
  margin: 0 auto;
250
  max-width: 960px;
251
+ direction: rtl; /* راست‌چین */
252
+ text-align: right;
253
+ }
254
+
255
+ #main-title h1 {
256
+ font-size: 2.1em !important;
257
+ text-align: center;
258
+ }
259
+
260
+ #main-description {
261
+ text-align: center;
262
+ font-size: 1.1em;
263
+ margin-bottom: 20px;
264
+ }
265
+
266
+ /* اصلاح جهت ورودی‌ها و لیست‌ها */
267
+ .gr-dropdown, .gr-textbox, .gr-slider, .gr-checkbox {
268
+ direction: rtl;
269
+ text-align: right;
270
+ }
271
+ .gr-input-label {
272
+ text-align: right !important;
273
  }
 
274
  """
275
 
276
+ with gr.Blocks(css=css, theme=steel_blue_theme) as demo:
277
  with gr.Column(elem_id="col-container"):
278
+ gr.Markdown("# **Qwen-Image-Edit-2509: ویرایشگر هوشمند تصاویر**", elem_id="main-title")
279
+ gr.Markdown(
280
+ "ویرایش تصاویر با استفاده از مدل قدرتمند [Qwen-Image-Edit](https://huggingface.co/Qwen/Qwen-Image-Edit-2509) و آداپتورهای اختصاصی LoRA. "
281
+ "شما می‌توانید دستورات خود را به **فارسی** بنویسید.",
282
+ elem_id="main-description"
283
+ )
284
 
285
  with gr.Row(equal_height=True):
286
  with gr.Column():
287
+ input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=290)
288
 
289
  prompt = gr.Text(
290
+ label="دستور ویرایش (به فارسی)",
291
  show_label=True,
292
+ placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...",
293
+ rtl=True # فعال کردن RTL برای ورودی متن
294
  )
295
 
296
+ run_button = gr.Button("شروع ویرایش تصویر", variant="primary")
297
 
298
  with gr.Column():
299
+ output_image = gr.Image(label="تصویر خروجی", interactive=False, format="png", height=353)
300
 
301
  with gr.Row():
302
  lora_adapter = gr.Dropdown(
303
+ label="انتخاب سبک ویرایش (LoRA)",
304
+ choices=list(LORA_MAPPING.keys()), # نمایش نام‌های فارسی
305
+ value="تبدیل عکس به انیمه"
306
  )
307
+ with gr.Accordion("تنظیمات پیشرفته", open=False, visible=True): # Accordion visible
308
+ seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
309
+ randomize_seed = gr.Checkbox(label="استفاده از Seed تصادفی", value=True)
310
+ guidance_scale = gr.Slider(label="میزان وفاداری به متن (Guidance Scale)", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
311
+ steps = gr.Slider(label="تعداد مراحل پردازش (Steps)", minimum=1, maximum=50, step=1, value=4)
312
 
313
+ # مثال‌های فارسی شده
314
  gr.Examples(
315
  examples=[
316
+ ["examples/1.jpg", "تبدیل به انیمه کن.", "تبدیل عکس به انیمه"],
317
+ ["examples/5.jpg", "سایه‌ها را حذف کن و نورپردازی نرم به تصویر بده.", "اصلاح نور و سایه"],
318
+ ["examples/4.jpg", "از فیلتر ساعت طلایی با پخش نور ملایم استفاده کن.", "نورپردازی مجدد (Relight)"],
319
+ ["examples/2.jpeg", "دوربین را ۴۵ درجه به سمت چپ بچرخان.", "تغییر زاویه دید"],
320
+ ["examples/7.jpg", "منبع نور را از سمت راست عقب قرار بده.", "نورپردازی چند زاویه‌ای"],
321
+ ["examples/10.jpeg", "کیفیت تصویر را افزایش بده (Upscale).", "افزایش کیفیت (Upscale)"],
322
+ ["examples/7.jpg", "منبع نور را از پایین بتابان.", "نورپردازی چند زاویه‌ای"],
323
+ ["examples/2.jpeg", "زاویه دوربین را به نمای بالا گوشه راست تغییر بده.", "تغییر زاویه دید"],
324
+ ["examples/9.jpg", "دوربین کمی به جلو حرکت می‌کند در حالی که نور خورشید از میان ابرها می‌تابد و درخششی نرم اطراف شبح شخصیت در مه ایجاد می‌کند. سبک سینمایی واقعی.", "صحنه ��عدی (سینمایی)"],
325
+ ["examples/8.jpg", "جزئیات پوست سوژه را برجسته‌تر و طبیعی‌تر کن.", "روتوش پوست"],
326
+ ["examples/6.jpg", "دوربین را به نمای پایین به بالا تغییر بده.", "تغییر زاویه دید"],
 
 
 
 
327
  ],
328
  inputs=[input_image, prompt, lora_adapter],
329
  outputs=[output_image, seed],
330
  fn=infer_example,
331
  cache_examples=False,
332
+ label="نمونه‌ها"
333
  )
334
 
335
  run_button.click(
 
339
  )
340
 
341
  if __name__ == "__main__":
342
+ demo.queue(max_size=30).launch(show_error=True)