Opera8 commited on
Commit
7857268
·
verified ·
1 Parent(s): 60c957e

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +141 -290
app.py CHANGED
@@ -10,23 +10,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",
17
- c100="#D3E5F0",
18
- c200="#A8CCE1",
19
- c300="#7DB3D2",
20
- c400="#529AC3",
21
- c500="#4682B4",
22
- c600="#3E72A0",
23
- c700="#36638C",
24
- c800="#2E5378",
25
- c900="#264364",
26
- c950="#1E3450",
27
- )
28
-
29
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
 
30
 
31
  # --- بارگذاری مدل ---
32
  from diffusers import FlowMatchEulerDiscreteScheduler
@@ -34,9 +20,6 @@ from qwenimage.pipeline_qwenimage_edit_plus import QwenImageEditPlusPipeline
34
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
35
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
36
 
37
- dtype = torch.bfloat16
38
- device = "cuda" if torch.cuda.is_available() else "cpu"
39
-
40
  print("Loading pipeline...")
41
  pipe = QwenImageEditPlusPipeline.from_pretrained(
42
  "Qwen/Qwen-Image-Edit-2509",
@@ -50,30 +33,22 @@ pipe = QwenImageEditPlusPipeline.from_pretrained(
50
  ).to(device)
51
 
52
  # بارگذاری LoRA ها
53
- pipe.load_lora_weights("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime",
54
- weight_name="Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors",
55
- adapter_name="anime")
56
- pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multiple-angles",
57
- weight_name="镜头转换.safetensors",
58
- adapter_name="multiple-angles")
59
- pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Light_restoration",
60
- weight_name="移除光影.safetensors",
61
- adapter_name="light-restoration")
62
- pipe.load_lora_weights("dx8152/Qwen-Image-Edit-2509-Relight",
63
- weight_name="Qwen-Edit-Relight.safetensors",
64
- adapter_name="relight")
65
- pipe.load_lora_weights("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting",
66
- weight_name="多角度灯光-251116.safetensors",
67
- adapter_name="multi-angle-lighting")
68
- pipe.load_lora_weights("tlennon-ie/qwen-edit-skin",
69
- weight_name="qwen-edit-skin_1.1_000002750.safetensors",
70
- adapter_name="edit-skin")
71
- pipe.load_lora_weights("lovis93/next-scene-qwen-image-lora-2509",
72
- weight_name="next-scene_lora-v2-3000.safetensors",
73
- adapter_name="next-scene")
74
- pipe.load_lora_weights("vafipas663/Qwen-Edit-2509-Upscale-LoRA",
75
- weight_name="qwen-edit-enhance_64-v3_000001000.safetensors",
76
- adapter_name="upscale-image")
77
 
78
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
79
  MAX_SEED = np.iinfo(np.int32).max
@@ -90,71 +65,47 @@ LORA_MAPPING = {
90
  "افزایش کیفیت (Upscale)": "upscale-image"
91
  }
92
 
 
93
  def translate_prompt(text):
94
- if not text:
95
- return ""
96
  try:
97
- translated = GoogleTranslator(source='auto', target='en').translate(text)
98
- return translated
99
- except Exception as e:
100
- print(f"Translation Error: {e}")
101
  return text
102
 
103
  def update_dimensions_on_upload(image):
104
- if image is None:
105
- return 1024, 1024
106
-
107
- original_width, original_height = image.size
108
-
109
- if original_width > original_height:
110
- new_width = 1024
111
- aspect_ratio = original_height / original_width
112
- new_height = int(new_width * aspect_ratio)
113
  else:
114
- new_height = 1024
115
- aspect_ratio = original_width / original_height
116
- new_width = int(new_height * aspect_ratio)
117
-
118
- new_width = (new_width // 8) * 8
119
- new_height = (new_height // 8) * 8
120
-
121
- return new_width, new_height
122
 
123
  @spaces.GPU(duration=30)
124
- def infer(
125
- input_image,
126
- prompt,
127
- lora_adapter_persian,
128
- seed,
129
- randomize_seed,
130
- guidance_scale,
131
- steps,
132
- progress=gr.Progress(track_tqdm=True)
133
- ):
134
  if input_image is None:
135
- raise gr.Error("لطفاً یک تصویر برای ویرایش بارگذاری کنید.")
136
 
137
  english_prompt = translate_prompt(prompt)
138
- adapter_internal_name = LORA_MAPPING.get(lora_adapter_persian)
139
-
140
- if adapter_internal_name:
141
- pipe.set_adapters([adapter_internal_name], adapter_weights=[1.0])
142
 
143
  if randomize_seed:
144
  seed = random.randint(0, MAX_SEED)
145
 
146
  generator = torch.Generator(device=device).manual_seed(seed)
147
- 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"
148
-
149
- original_image = input_image.convert("RGB")
150
- width, height = update_dimensions_on_upload(original_image)
151
 
152
  result = pipe(
153
- image=original_image,
154
  prompt=english_prompt,
155
- negative_prompt=negative_prompt,
156
- height=height,
157
- width=width,
158
  num_inference_steps=steps,
159
  generator=generator,
160
  true_cfg_scale=guidance_scale,
@@ -162,305 +113,205 @@ def infer(
162
 
163
  return result, seed
164
 
165
- @spaces.GPU(duration=30)
166
  def infer_example(input_image, prompt, lora_adapter):
167
- input_pil = input_image.convert("RGB")
168
- guidance_scale = 1.0
169
- steps = 4
170
- result, seed = infer(input_pil, prompt, lora_adapter, 0, True, guidance_scale, steps)
171
- return result, seed
172
 
173
- # --- جاوااسکریپت برای دکمه دانلود ---
174
  js_post_message = """
175
  async (image) => {
176
- if (!image) {
177
- alert("لطفاً ابتدا تصویر را تولید کنید.");
178
- return;
179
- }
180
  let fileUrl = image.url;
181
  if (fileUrl && !fileUrl.startsWith('http')) {
182
  fileUrl = window.location.origin + fileUrl;
183
  } else if (!fileUrl && image.path) {
184
  fileUrl = window.location.origin + "/file=" + image.path;
185
  }
186
- console.log("Sending download request for:", fileUrl);
187
- window.parent.postMessage({
188
- type: 'DOWNLOAD_REQUEST',
189
- url: fileUrl
190
- }, '*');
191
  }
192
  """
193
 
194
- # --- تنظیمات HTML/CSS/JS کامل برای زیبایی و رفع باگ ---
195
- html_code = """
196
  <style>
197
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
198
 
199
- /* --- تنظیمات اجباری تم روشن (Light Mode Force) --- */
200
  :root, .dark, body, .gradio-container {
201
- --body-background-fill: #f4f7fa !important; /* پس زمینه کلی کمی متمایل به آبی خیلی روشن */
202
- --body-text-color: #333333 !important;
203
  --background-fill-primary: #ffffff !important;
204
- --background-fill-secondary: #f9fafb !important;
205
- --border-color-primary: #e0e4e8 !important;
206
- --input-background-fill: #ffffff !important;
207
- --table-row-focus: #f0fdf4 !important;
208
- color-scheme: light !important;
209
  }
210
 
211
- body, .gradio-container {
212
- font-family: 'Vazirmatn', sans-serif !important;
213
- background-color: #f4f7fa !important;
214
  margin: 0;
215
  padding: 0;
216
  }
217
 
218
- /* --- استایل کانتینر اصلی --- */
219
  #col-container {
220
  margin: 20px auto;
221
- max-width: 960px;
222
- direction: rtl;
223
- text-align: right;
224
- padding: 30px;
225
  background: #ffffff !important;
226
  border-radius: 24px;
227
- box-shadow: 0 10px 40px rgba(0,0,0,0.06); /* سایه نرم و مدرن */
 
228
  border: 1px solid #ffffff;
 
 
229
  }
230
 
231
- /* --- هدرها --- */
232
  #main-title h1 {
233
- font-size: 2.4em !important;
 
234
  text-align: center;
235
- color: #1e293b !important;
236
- margin-bottom: 12px;
237
- font-weight: 800;
238
  }
239
-
240
  #main-description {
241
  text-align: center;
242
- font-size: 1.15em;
243
- color: #64748b !important;
244
- margin-bottom: 35px;
245
- line-height: 1.6;
246
- }
247
-
248
- /* --- استایل ورودی‌ها و جعبه‌ها --- */
249
- .gr-input-label, span {
250
- font-weight: 600;
251
- color: #334155 !important;
252
- text-align: right !important;
253
- font-size: 0.95em;
254
- margin-bottom: 5px;
255
- }
256
-
257
- .gr-dropdown, .gr-textbox, .gr-slider, .gr-checkbox, textarea, input {
258
- background-color: #ffffff !important;
259
- color: #333333 !important;
260
- border-radius: 12px !important;
261
- }
262
-
263
- input[type="text"], textarea {
264
- border: 2px solid #e2e8f0 !important;
265
- transition: all 0.3s ease !important;
266
- box-shadow: none !important;
267
  }
268
 
269
- input[type="text"]:focus, textarea:focus {
270
- border-color: #4CAF50 !important;
271
- box-shadow: 0 0 0 4px rgba(76, 175, 80, 0.1) !important;
272
- }
273
-
274
- /* --- دکمه‌ها (طراحی مدرن) --- */
275
- .primary-btn, button.primary {
276
  background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
277
- border: none !important;
278
  color: white !important;
 
 
 
279
  font-weight: 700 !important;
280
- font-size: 1.1em !important;
281
- padding: 14px 28px !important;
282
- border-radius: 14px !important;
283
  box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3) !important;
284
  transition: transform 0.2s, box-shadow 0.2s !important;
285
- cursor: pointer !important;
286
  }
287
-
288
- .primary-btn:hover, button.primary:hover {
289
  transform: translateY(-2px);
290
- box-shadow: 0 8px 25px rgba(16, 185, 129, 0.4) !important;
291
- background: linear-gradient(135deg, #34d399 0%, #059669 100%) !important;
292
  }
293
-
294
  #download-btn {
295
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
296
  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important;
297
- color: white !important;
298
  margin-top: 15px;
299
- }
300
- #download-btn:hover {
301
- transform: translateY(-2px);
302
- box-shadow: 0 8px 25px rgba(59, 130, 246, 0.4) !important;
303
  }
304
 
305
- /* --- اصلاح جدول نمونه‌ها (Examples) --- */
306
- /* هدف قرار دادن دقیق جداول گرادیو برای رفع سیاهی */
307
- .gr-samples-gallery, .gr-samples-table, table {
308
- background-color: #ffffff !important;
309
- border-radius: 12px !important;
310
- overflow: hidden;
311
- border: 1px solid #e2e8f0 !important;
312
  }
313
-
314
- tr, td, th {
 
 
 
 
 
 
 
315
  background-color: #ffffff !important;
316
- color: #333333 !important;
317
- border-color: #f1f5f9 !important;
318
- padding: 12px !important;
319
- text-align: right !important;
320
  }
321
 
322
- /* استایل ردیف‌های زوج برای زیبایی */
323
- tr:nth-child(even) td {
324
- background-color: #f8fafc !important;
 
 
325
  }
326
-
327
- /* هاور روی ردیف‌ها */
328
- tr:hover td {
329
- background-color: #f0fdf4 !important;
330
- cursor: pointer;
331
  }
332
-
333
- /* تصاویر داخل جدول */
334
- td img {
335
- border-radius: 8px !important;
336
- box-shadow: 0 2px 5px rgba(0,0,0,0.1);
337
  }
338
-
339
- /* --- مخفی کردن فوتر و فلگ --- */
340
- footer { display: none !important; }
341
- .gradio-container footer { display: none !important; }
342
- .flagging { display: none !important; }
343
-
344
- /* --- موبایل --- */
345
- @media (max-width: 768px) {
346
- #col-container {
347
- padding: 15px;
348
- margin: 10px;
349
- }
350
- #main-title h1 { font-size: 1.8em !important; }
351
  }
352
 
 
 
353
  </style>
354
 
355
  <script>
356
- // اسکریپت اجبار تم روشن با قدرت بیشتر
357
- function forceLightMode() {
358
- document.documentElement.classList.remove('dark');
359
  document.body.classList.remove('dark');
360
- document.documentElement.style.colorScheme = 'light';
361
-
362
- // جستجو در تمام المنت‌ها
363
- const allElements = document.querySelectorAll('*');
364
- allElements.forEach(el => {
365
- el.style.colorScheme = 'light';
366
- if (el.classList.contains('dark')) {
367
- el.classList.remove('dark');
368
- }
369
- });
370
  }
371
-
372
- // اجرا در زمان‌های مختلف برای اطمینان
373
- forceLightMode();
374
- window.addEventListener('load', forceLightMode);
375
- document.addEventListener('DOMContentLoaded', forceLightMode);
376
-
377
- // آبزرور برای جلوگیری از تغییر تم توسط گرادیو
378
- const observer = new MutationObserver((mutations) => {
379
- mutations.forEach((mutation) => {
380
- if (document.body.classList.contains('dark')) {
381
- forceLightMode();
382
- }
383
- });
384
- });
385
- observer.observe(document.body, { attributes: true, subtree: false });
386
- observer.observe(document.documentElement, { attributes: true, subtree: false });
387
  </script>
388
  """
389
 
 
390
  with gr.Blocks() as demo:
391
- gr.HTML(html_code)
392
-
393
  with gr.Column(elem_id="col-container"):
394
  gr.Markdown("# **ویرایشگر هوشمند آلفا**", elem_id="main-title")
395
- gr.Markdown(
396
- "با هوش مصنوعی آلفا تصاویر تونو به مدل های مختلف ویرایش کنید.",
397
- elem_id="main-description"
398
- )
399
 
400
  with gr.Row(equal_height=True):
 
401
  with gr.Column():
402
- input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=320)
403
-
404
  prompt = gr.Text(
405
  label="دستور ویرایش (به فارسی)",
406
- show_label=True,
407
  placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...",
408
- rtl=True,
409
- lines=3
410
  )
 
411
 
412
- run_button = gr.Button("✨ شروع پردازش و ساخت تصویر", variant="primary", elem_classes="primary-btn")
413
-
414
  with gr.Column():
415
- output_image = gr.Image(label="تصویر نهایی", interactive=False, format="png", height=380)
416
-
417
- download_button = gr.Button("📥 دانلود و ذخیره تصویر", variant="secondary", elem_id="download-btn", elem_classes="primary-btn")
418
 
419
  with gr.Row():
420
- lora_adapter = gr.Dropdown(
421
- label="انتخاب سبک ویرایش (LoRA)",
422
- choices=list(LORA_MAPPING.keys()),
423
- value="تبدیل عکس به انیمه"
424
- )
425
- with gr.Accordion("تنظیمات پیشرفته", open=False, visible=True):
426
- seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
427
- randomize_seed = gr.Checkbox(label="استفاده از Seed تصادفی", value=True)
428
- guidance_scale = gr.Slider(label="میزان وفاداری به متن (Guidance Scale)", minimum=1.0, maximum=10.0, step=0.1, value=1.0)
429
- steps = gr.Slider(label="تعداد مراحل پردازش (Steps)", minimum=1, maximum=50, step=1, value=4)
430
-
431
  gr.Examples(
432
  examples=[
433
  ["examples/1.jpg", "تبدیل به انیمه کن.", "تبدیل عکس به انیمه"],
434
  ["examples/5.jpg", "سایه‌ها را حذف کن و نورپردازی نرم به تصویر بده.", "اصلاح نور و سایه"],
435
  ["examples/4.jpg", "از فیلتر ساعت طلایی با پخش نور ملایم استفاده کن.", "نورپردازی مجدد (Relight)"],
436
  ["examples/2.jpeg", "دوربین را ۴۵ درجه به سمت چپ بچرخان.", "تغییر زاویه دید"],
437
- ["examples/7.jpg", "منبع نور را از سمت راست عقب قرار بده.", "نورپردازی چند زاویه‌ای"],
438
- ["examples/10.jpeg", "کیفیت تصویر را افزایش بده (Upscale).", "افزایش کیفیت (Upscale)"],
439
- ["examples/7.jpg", "منبع نور را از پایین بتابان.", "نورپردازی چند زاویه‌ای"],
440
- ["examples/2.jpeg", "زاویه دوربین را به نمای بالا گوشه راست تغییر بده.", "تغییر زاویه دید"],
441
- ["examples/9.jpg", "دوربین کمی به جلو حرکت می‌کند در حالی که نور خورشید از میان ابرها می‌تابد و درخششی نرم اطراف شبح شخصیت در مه ایجاد می‌کند. سبک سینمایی واقعی.", "صحنه بعدی (سینمایی)"],
442
- ["examples/8.jpg", "جزئیات پوست سوژه را برجسته‌تر و طبیعی‌تر کن.", "روتوش پوست"],
443
- ["examples/6.jpg", "دوربین را به نمای پایین به بالا تغییر بده.", "تغییر زاویه دید"],
444
  ],
445
- inputs=[input_image, prompt, lora_adapter],
446
  outputs=[output_image, seed],
447
  fn=infer_example,
448
  cache_examples=False,
449
- label="نمونه‌ها"
450
  )
451
 
452
- run_button.click(
453
  fn=infer,
454
- inputs=[input_image, prompt, lora_adapter, seed, randomize_seed, guidance_scale, steps],
455
  outputs=[output_image, seed]
456
  )
457
-
458
- download_button.click(
459
- fn=None,
460
- inputs=[output_image],
461
- outputs=None,
462
- js=js_post_message
463
- )
464
 
465
  if __name__ == "__main__":
466
  demo.queue(max_size=30).launch(show_error=True)
 
10
  from gradio.themes.utils import colors, fonts, sizes
11
  from deep_translator import GoogleTranslator
12
 
13
+ # --- تعریف متغیرها ---
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
14
  device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
15
+ dtype = torch.bfloat16
16
 
17
  # --- بارگذاری مدل ---
18
  from diffusers import FlowMatchEulerDiscreteScheduler
 
20
  from qwenimage.transformer_qwenimage import QwenImageTransformer2DModel
21
  from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3
22
 
 
 
 
23
  print("Loading pipeline...")
24
  pipe = QwenImageEditPlusPipeline.from_pretrained(
25
  "Qwen/Qwen-Image-Edit-2509",
 
33
  ).to(device)
34
 
35
  # بارگذاری LoRA ها
36
+ loras = {
37
+ "anime": ("autoweeb/Qwen-Image-Edit-2509-Photo-to-Anime", "Qwen-Image-Edit-2509-Photo-to-Anime_000001000.safetensors"),
38
+ "multiple-angles": ("dx8152/Qwen-Edit-2509-Multiple-angles", "镜头转换.safetensors"),
39
+ "light-restoration": ("dx8152/Qwen-Image-Edit-2509-Light_restoration", "移除光影.safetensors"),
40
+ "relight": ("dx8152/Qwen-Image-Edit-2509-Relight", "Qwen-Edit-Relight.safetensors"),
41
+ "multi-angle-lighting": ("dx8152/Qwen-Edit-2509-Multi-Angle-Lighting", "多角度灯光-251116.safetensors"),
42
+ "edit-skin": ("tlennon-ie/qwen-edit-skin", "qwen-edit-skin_1.1_000002750.safetensors"),
43
+ "next-scene": ("lovis93/next-scene-qwen-image-lora-2509", "next-scene_lora-v2-3000.safetensors"),
44
+ "upscale-image": ("vafipas663/Qwen-Edit-2509-Upscale-LoRA", "qwen-edit-enhance_64-v3_000001000.safetensors")
45
+ }
46
+
47
+ for name, (repo, weight) in loras.items():
48
+ try:
49
+ pipe.load_lora_weights(repo, weight_name=weight, adapter_name=name)
50
+ except Exception as e:
51
+ print(f"Error loading LoRA {name}: {e}")
 
 
 
 
 
 
 
 
52
 
53
  pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3())
54
  MAX_SEED = np.iinfo(np.int32).max
 
65
  "افزایش کیفیت (Upscale)": "upscale-image"
66
  }
67
 
68
+ # --- توابع کمکی ---
69
  def translate_prompt(text):
70
+ if not text: return ""
 
71
  try:
72
+ return GoogleTranslator(source='auto', target='en').translate(text)
73
+ except:
 
 
74
  return text
75
 
76
  def update_dimensions_on_upload(image):
77
+ if image is None: return 1024, 1024
78
+ w, h = image.size
79
+ if w > h:
80
+ new_w = 1024
81
+ new_h = int(new_w * (h / w))
 
 
 
 
82
  else:
83
+ new_h = 1024
84
+ new_w = int(new_h * (w / h))
85
+ return (new_w // 8) * 8, (new_h // 8) * 8
 
 
 
 
 
86
 
87
  @spaces.GPU(duration=30)
88
+ def infer(input_image, prompt, lora_adapter_persian, seed, randomize_seed, guidance_scale, steps, progress=gr.Progress(track_tqdm=True)):
 
 
 
 
 
 
 
 
 
89
  if input_image is None:
90
+ raise gr.Error("لطفاً تصویر را بارگذاری کنید.")
91
 
92
  english_prompt = translate_prompt(prompt)
93
+ adapter_name = LORA_MAPPING.get(lora_adapter_persian)
94
+ if adapter_name:
95
+ pipe.set_adapters([adapter_name], adapter_weights=[1.0])
 
96
 
97
  if randomize_seed:
98
  seed = random.randint(0, MAX_SEED)
99
 
100
  generator = torch.Generator(device=device).manual_seed(seed)
101
+ w, h = update_dimensions_on_upload(input_image)
 
 
 
102
 
103
  result = pipe(
104
+ image=input_image.convert("RGB"),
105
  prompt=english_prompt,
106
+ negative_prompt="worst quality, low quality, blurry, bad anatomy",
107
+ height=h,
108
+ width=w,
109
  num_inference_steps=steps,
110
  generator=generator,
111
  true_cfg_scale=guidance_scale,
 
113
 
114
  return result, seed
115
 
 
116
  def infer_example(input_image, prompt, lora_adapter):
117
+ return infer(input_image, prompt, lora_adapter, 0, True, 1.0, 4)
118
+
119
+ # --- کدهای سمت کلاینت (JS/CSS) ---
 
 
120
 
 
121
  js_post_message = """
122
  async (image) => {
123
+ if (!image) { alert("تصویر هنوز ساخته نشده است!"); return; }
 
 
 
124
  let fileUrl = image.url;
125
  if (fileUrl && !fileUrl.startsWith('http')) {
126
  fileUrl = window.location.origin + fileUrl;
127
  } else if (!fileUrl && image.path) {
128
  fileUrl = window.location.origin + "/file=" + image.path;
129
  }
130
+ window.parent.postMessage({ type: 'DOWNLOAD_REQUEST', url: fileUrl }, '*');
 
 
 
 
131
  }
132
  """
133
 
134
+ html_style_and_script = """
 
135
  <style>
136
  @import url('https://fonts.googleapis.com/css2?family=Vazirmatn:wght@300;400;500;700&display=swap');
137
 
138
+ /* --- تنظیمات کلی و اجبار تم روشن --- */
139
  :root, .dark, body, .gradio-container {
140
+ --body-background-fill: #f0f2f5 !important;
141
+ --body-text-color: #1f2937 !important;
142
  --background-fill-primary: #ffffff !important;
143
+ --border-color-primary: #e5e7eb !important;
144
+ --block-label-text-color: #374151 !important;
145
+ --block-title-text-color: #111827 !important;
146
+ font-family: 'Vazirmatn', sans-serif !important;
 
147
  }
148
 
149
+ body {
150
+ background-color: #f0f2f5 !important;
 
151
  margin: 0;
152
  padding: 0;
153
  }
154
 
155
+ /* --- کانتینر اصلی --- */
156
  #col-container {
157
  margin: 20px auto;
158
+ max-width: 1000px;
 
 
 
159
  background: #ffffff !important;
160
  border-radius: 24px;
161
+ padding: 30px;
162
+ box-shadow: 0 10px 40px rgba(0,0,0,0.06);
163
  border: 1px solid #ffffff;
164
+ direction: rtl;
165
+ text-align: right;
166
  }
167
 
168
+ /* --- هدر و توضیحات --- */
169
  #main-title h1 {
170
+ font-weight: 800 !important;
171
+ color: #111827 !important;
172
  text-align: center;
173
+ margin-bottom: 10px;
174
+ font-size: 2rem !important;
 
175
  }
 
176
  #main-description {
177
  text-align: center;
178
+ color: #6b7280 !important;
179
+ margin-bottom: 30px;
180
+ font-size: 1.1rem;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
181
  }
182
 
183
+ /* --- دکمه‌ها --- */
184
+ button.primary {
 
 
 
 
 
185
  background: linear-gradient(135deg, #10b981 0%, #059669 100%) !important;
 
186
  color: white !important;
187
+ border: none !important;
188
+ border-radius: 12px !important;
189
+ padding: 12px 20px !important;
190
  font-weight: 700 !important;
191
+ font-size: 1rem !important;
 
 
192
  box-shadow: 0 4px 15px rgba(16, 185, 129, 0.3) !important;
193
  transition: transform 0.2s, box-shadow 0.2s !important;
 
194
  }
195
+ button.primary:hover {
 
196
  transform: translateY(-2px);
197
+ box-shadow: 0 6px 20px rgba(16, 185, 129, 0.4) !important;
 
198
  }
 
199
  #download-btn {
200
  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%) !important;
201
  box-shadow: 0 4px 15px rgba(59, 130, 246, 0.3) !important;
 
202
  margin-top: 15px;
203
+ width: 100%;
 
 
 
204
  }
205
 
206
+ /* --- ورودی‌ها و لیبل‌ها --- */
207
+ .gr-input-label {
208
+ font-weight: 600;
209
+ color: #374151 !important;
210
+ margin-bottom: 8px;
 
 
211
  }
212
+ textarea, input[type="text"], .gr-dropdown {
213
+ background-color: #f9fafb !important;
214
+ border: 1px solid #e5e7eb !important;
215
+ border-radius: 10px !important;
216
+ color: #111827 !important;
217
+ box-shadow: none !important;
218
+ }
219
+ textarea:focus, input:focus {
220
+ border-color: #10b981 !important;
221
  background-color: #ffffff !important;
222
+ box-shadow: 0 0 0 3px rgba(16, 185, 129, 0.1) !important;
 
 
 
223
  }
224
 
225
+ /* --- رفع مشکل جدول نمونه‌ها --- */
226
+ .gr-samples-table {
227
+ border-radius: 12px !important;
228
+ overflow: hidden !important;
229
+ border: 1px solid #e5e7eb !important;
230
  }
231
+ .gr-samples-table tr, .gr-samples-table th, .gr-samples-table td {
232
+ background-color: #ffffff !important;
233
+ color: #1f2937 !important;
234
+ border-bottom: 1px solid #f3f4f6 !important;
 
235
  }
236
+ .gr-samples-table tr:nth-child(even) {
237
+ background-color: #f9fafb !important; /* راه‌راه خیلی ملایم */
 
 
 
238
  }
239
+ .gr-samples-table th {
240
+ background-color: #f3f4f6 !important;
241
+ font-weight: 700 !important;
 
 
 
 
 
 
 
 
 
 
242
  }
243
 
244
+ /* --- مخفی کردن اضافات --- */
245
+ footer, .flagging { display: none !important; }
246
  </style>
247
 
248
  <script>
249
+ // اسکریپت اجباری برای حذف کلاس Dark از بدنه اصلی گرادیو
250
+ function forceLight() {
 
251
  document.body.classList.remove('dark');
252
+ document.body.style.backgroundColor = '#f0f2f5';
 
 
 
 
 
 
 
 
 
253
  }
254
+ document.addEventListener('DOMContentLoaded', forceLight);
255
+ const observer = new MutationObserver(() => forceLight());
256
+ observer.observe(document.body, { attributes: true });
 
 
 
 
 
 
 
 
 
 
 
 
 
257
  </script>
258
  """
259
 
260
+ # --- رابط کاربری Gradio ---
261
  with gr.Blocks() as demo:
262
+ gr.HTML(html_style_and_script)
263
+
264
  with gr.Column(elem_id="col-container"):
265
  gr.Markdown("# **ویرایشگر هوشمند آلفا**", elem_id="main-title")
266
+ gr.Markdown("با هوش مصنوعی آلفا تصاویر تونو به مدل های مختلف ویرایش کنید.", elem_id="main-description")
 
 
 
267
 
268
  with gr.Row(equal_height=True):
269
+ # ستون چپ (ورودی)
270
  with gr.Column():
271
+ input_image = gr.Image(label="بارگذاری تصویر", type="pil", height=300)
 
272
  prompt = gr.Text(
273
  label="دستور ویرایش (به فارسی)",
 
274
  placeholder="مثال: تصویر را به سبک انیمه تبدیل کن...",
275
+ rtl=True, lines=3
 
276
  )
277
+ run_btn = gr.Button("✨ شروع پردازش", variant="primary")
278
 
279
+ # ستون راست (خروجی)
 
280
  with gr.Column():
281
+ output_image = gr.Image(label="تصویر نهایی", interactive=False, height=350)
282
+ download_btn = gr.Button("📥 دانلود و ذخیره تصویر", elem_id="download-btn", variant="primary")
 
283
 
284
  with gr.Row():
285
+ adapter = gr.Dropdown(label="سبک ویرایش", choices=list(LORA_MAPPING.keys()), value="تبدیل عکس به انیمه")
286
+
287
+ with gr.Accordion("تنظیمات پیشرفته", open=False):
288
+ seed = gr.Slider(label="Seed", minimum=0, maximum=MAX_SEED, step=1, value=0)
289
+ random_seed = gr.Checkbox(label="Seed تصادفی", value=True)
290
+ scale = gr.Slider(label="Guidance Scale", 1.0, 10.0, step=0.1, value=1.0)
291
+ steps = gr.Slider(label="Steps", 1, 50, step=1, value=4)
292
+
 
 
 
293
  gr.Examples(
294
  examples=[
295
  ["examples/1.jpg", "تبدیل به انیمه کن.", "تبدیل عکس به انیمه"],
296
  ["examples/5.jpg", "سایه‌ها را حذف کن و نورپردازی نرم به تصویر بده.", "اصلاح نور و سایه"],
297
  ["examples/4.jpg", "از فیلتر ساعت طلایی با پخش نور ملایم استفاده کن.", "نورپردازی مجدد (Relight)"],
298
  ["examples/2.jpeg", "دوربین را ۴۵ درجه به سمت چپ بچرخان.", "تغییر زاویه دید"],
299
+ ["examples/9.jpg", "سبک سینمایی واقعی با درخشش نرم.", "صحنه بعدی (سینمایی)"],
 
 
 
 
 
 
300
  ],
301
+ inputs=[input_image, prompt, adapter],
302
  outputs=[output_image, seed],
303
  fn=infer_example,
304
  cache_examples=False,
305
+ label="نمونه‌های آماده"
306
  )
307
 
308
+ run_btn.click(
309
  fn=infer,
310
+ inputs=[input_image, prompt, adapter, seed, random_seed, scale, steps],
311
  outputs=[output_image, seed]
312
  )
313
+
314
+ download_btn.click(None, [output_image], None, js=js_post_message)
 
 
 
 
 
315
 
316
  if __name__ == "__main__":
317
  demo.queue(max_size=30).launch(show_error=True)