Update app.py
Browse files
app.py
CHANGED
|
@@ -14,6 +14,15 @@ from deep_translator import GoogleTranslator
|
|
| 14 |
from transformers import pipeline
|
| 15 |
from diffusers import Flux2Pipeline, Flux2Transformer2DModel
|
| 16 |
from datetime import date
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 17 |
|
| 18 |
# ==========================================
|
| 19 |
# 1. تنظیمات و پیکربندی سیستم (Configuration)
|
|
@@ -27,6 +36,9 @@ MAX_SEED = np.iinfo(np.int32).max
|
|
| 27 |
MAX_IMAGE_SIZE = 1024
|
| 28 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 29 |
|
|
|
|
|
|
|
|
|
|
| 30 |
# بارگذاری مدل تشخیص محتوای نامناسب (Safety Checker)
|
| 31 |
print("Loading Safety Checker...")
|
| 32 |
safety_classifier = pipeline("image-classification", model="Falconsai/nsfw_image_detection", device=-1)
|
|
@@ -55,9 +67,9 @@ BANNED_WORDS = [
|
|
| 55 |
]
|
| 56 |
|
| 57 |
# ==========================================
|
| 58 |
-
# 2. بارگذاری مدل FLUX.2
|
| 59 |
# ==========================================
|
| 60 |
-
print("Loading FLUX.2 Pipeline...")
|
| 61 |
repo_id = "black-forest-labs/FLUX.2-dev"
|
| 62 |
|
| 63 |
dit = Flux2Transformer2DModel.from_pretrained(
|
|
@@ -72,6 +84,17 @@ pipe = Flux2Pipeline.from_pretrained(
|
|
| 72 |
transformer=dit,
|
| 73 |
torch_dtype=torch.bfloat16
|
| 74 |
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 75 |
pipe.to(device)
|
| 76 |
|
| 77 |
# بهینهسازی ZeroGPU
|
|
@@ -102,10 +125,8 @@ usage_data_cache = load_usage_data()
|
|
| 102 |
def is_image_nsfw(image):
|
| 103 |
if image is None: return False
|
| 104 |
try:
|
| 105 |
-
# اگر ورودی لیست گالری باشد، اولین تصویر را چک کن
|
| 106 |
img_to_check = image
|
| 107 |
if isinstance(image, list):
|
| 108 |
-
# هندل کردن فرمت گالری گرادیو
|
| 109 |
if len(image) > 0:
|
| 110 |
img_to_check = image[0][0] if isinstance(image[0], tuple) else image[0]
|
| 111 |
else:
|
|
@@ -213,13 +234,15 @@ def upsample_prompt_logic(prompt, image_list):
|
|
| 213 |
print(f"Upsampling failed: {e}")
|
| 214 |
return prompt
|
| 215 |
|
|
|
|
| 216 |
def get_duration(prompt_embeds, image_list, width, height, num_inference_steps, guidance_scale, seed, progress=gr.Progress(track_tqdm=True)):
|
| 217 |
num_images = 0 if image_list is None else len(image_list)
|
| 218 |
step_duration = 1 + 0.8 * num_images
|
| 219 |
-
|
|
|
|
| 220 |
|
| 221 |
# ==========================================
|
| 222 |
-
# 4. تابع اصلی GPU (Inference)
|
| 223 |
# ==========================================
|
| 224 |
|
| 225 |
@spaces.GPU(duration=get_duration)
|
|
@@ -230,14 +253,18 @@ def generate_image(prompt_embeds, image_list, width, height, num_inference_steps
|
|
| 230 |
pipe_kwargs = {
|
| 231 |
"prompt_embeds": prompt_embeds,
|
| 232 |
"image": image_list,
|
| 233 |
-
"num_inference_steps": num_inference_steps,
|
| 234 |
"guidance_scale": guidance_scale,
|
| 235 |
"generator": generator,
|
| 236 |
"width": width,
|
| 237 |
"height": height,
|
| 238 |
}
|
| 239 |
|
| 240 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 241 |
image = pipe(**pipe_kwargs).images[0]
|
| 242 |
return image
|
| 243 |
|
|
@@ -286,8 +313,9 @@ def infer(
|
|
| 286 |
progress(0.3, desc="Encoding...")
|
| 287 |
prompt_embeds = remote_text_encoder(final_prompt)
|
| 288 |
|
| 289 |
-
# Generation (GPU)
|
| 290 |
-
progress(0.4, desc="Generating...")
|
|
|
|
| 291 |
result_image = generate_image(
|
| 292 |
prompt_embeds, image_list, width, height,
|
| 293 |
num_inference_steps, guidance_scale, seed, progress
|
|
@@ -300,7 +328,7 @@ def infer(
|
|
| 300 |
# 6. محاسبه اعتبار ب��قیمانده
|
| 301 |
user_record = get_user_record(fingerprint)
|
| 302 |
remaining = USAGE_LIMIT - user_record["count"] if user_record else 0
|
| 303 |
-
success_msg = f"تصویر با موفقیت ساخته
|
| 304 |
if subscription_status != 'paid':
|
| 305 |
success_msg += f" (اعتبار باقیمانده امروز: {remaining})"
|
| 306 |
|
|
@@ -505,7 +533,6 @@ footer { display: none !important; }
|
|
| 505 |
# 6. ساخت رابط کاربری (Gradio Blocks)
|
| 506 |
# ==========================================
|
| 507 |
|
| 508 |
-
# ******** این خط اصلاح شده است ********
|
| 509 |
with gr.Blocks() as demo:
|
| 510 |
gr.HTML(js_global_content + css_code)
|
| 511 |
|
|
@@ -513,8 +540,8 @@ with gr.Blocks() as demo:
|
|
| 513 |
status_box_input = gr.Textbox(elem_id="status_storage", visible=True)
|
| 514 |
|
| 515 |
with gr.Column(elem_id="col-container"):
|
| 516 |
-
gr.Markdown("# **ساخت تصویر با FLUX.2 (
|
| 517 |
-
gr.Markdown("با استفاده از مدل قدرتمند FLUX.2 متن فارسی خود را به تصاویر شگفتانگیز تبدیل کنید.", elem_id="main-description")
|
| 518 |
gr.HTML('<div id="badge-container"><span id="user-sub-badge"></span></div>')
|
| 519 |
|
| 520 |
with gr.Row():
|
|
@@ -539,7 +566,7 @@ with gr.Blocks() as demo:
|
|
| 539 |
|
| 540 |
status_box = gr.HTML(label="وضعیت")
|
| 541 |
|
| 542 |
-
run_button = gr.Button("✨ ساخت تصویر", variant="primary", elem_classes="primary-btn", elem_id="run-btn", visible=True)
|
| 543 |
upgrade_button = gr.Button("💎 خرید نسخه نامحدود", variant="primary", elem_classes="upgrade-btn", elem_id="upgrade-btn", visible=False)
|
| 544 |
|
| 545 |
with gr.Accordion("تنظیمات پیشرفته", open=False):
|
|
@@ -550,8 +577,9 @@ with gr.Blocks() as demo:
|
|
| 550 |
width = gr.Slider(label="عرض (Width)", minimum=256, maximum=MAX_IMAGE_SIZE, step=8, value=1024)
|
| 551 |
height = gr.Slider(label="ارتفاع (Height)", minimum=256, maximum=MAX_IMAGE_SIZE, step=8, value=1024)
|
| 552 |
with gr.Row():
|
| 553 |
-
|
| 554 |
-
|
|
|
|
| 555 |
|
| 556 |
with gr.Column():
|
| 557 |
result = gr.Image(label="تصویر نهایی", show_label=True, interactive=False)
|
|
|
|
| 14 |
from transformers import pipeline
|
| 15 |
from diffusers import Flux2Pipeline, Flux2Transformer2DModel
|
| 16 |
from datetime import date
|
| 17 |
+
import subprocess
|
| 18 |
+
import sys
|
| 19 |
+
|
| 20 |
+
# نصب پکیج spaces در صورت نیاز (برای اطمینان)
|
| 21 |
+
try:
|
| 22 |
+
import spaces
|
| 23 |
+
except ImportError:
|
| 24 |
+
subprocess.check_call([sys.executable, "-m", "pip", "install", "spaces==0.43.0"])
|
| 25 |
+
import spaces
|
| 26 |
|
| 27 |
# ==========================================
|
| 28 |
# 1. تنظیمات و پیکربندی سیستم (Configuration)
|
|
|
|
| 36 |
MAX_IMAGE_SIZE = 1024
|
| 37 |
device = "cuda" if torch.cuda.is_available() else "cpu"
|
| 38 |
|
| 39 |
+
# مقادیر سیگما مخصوص حالت توربو (8 مرحله)
|
| 40 |
+
TURBO_SIGMAS = [1.0, 0.6509, 0.4374, 0.2932, 0.1893, 0.1108, 0.0495, 0.00031]
|
| 41 |
+
|
| 42 |
# بارگذاری مدل تشخیص محتوای نامناسب (Safety Checker)
|
| 43 |
print("Loading Safety Checker...")
|
| 44 |
safety_classifier = pipeline("image-classification", model="Falconsai/nsfw_image_detection", device=-1)
|
|
|
|
| 67 |
]
|
| 68 |
|
| 69 |
# ==========================================
|
| 70 |
+
# 2. بارگذاری مدل FLUX.2 با حالت TURBO
|
| 71 |
# ==========================================
|
| 72 |
+
print("Loading FLUX.2 Pipeline with Turbo LoRA...")
|
| 73 |
repo_id = "black-forest-labs/FLUX.2-dev"
|
| 74 |
|
| 75 |
dit = Flux2Transformer2DModel.from_pretrained(
|
|
|
|
| 84 |
transformer=dit,
|
| 85 |
torch_dtype=torch.bfloat16
|
| 86 |
)
|
| 87 |
+
|
| 88 |
+
# بارگذاری وزنهای توربو (Turbo LoRA)
|
| 89 |
+
# این بخش باعث میشود مدل به جای ۳۰ مرحله، در ۸ مرحله تصویر بسازد
|
| 90 |
+
print("Loading Turbo LoRA weights...")
|
| 91 |
+
pipe.load_lora_weights(
|
| 92 |
+
"fal/FLUX.2-dev-Turbo",
|
| 93 |
+
weight_name="flux.2-turbo-lora.safetensors"
|
| 94 |
+
)
|
| 95 |
+
pipe.fuse_lora()
|
| 96 |
+
pipe.unload_lora_weights() # ادغام وزنها برای سرعت بیشتر
|
| 97 |
+
|
| 98 |
pipe.to(device)
|
| 99 |
|
| 100 |
# بهینهسازی ZeroGPU
|
|
|
|
| 125 |
def is_image_nsfw(image):
|
| 126 |
if image is None: return False
|
| 127 |
try:
|
|
|
|
| 128 |
img_to_check = image
|
| 129 |
if isinstance(image, list):
|
|
|
|
| 130 |
if len(image) > 0:
|
| 131 |
img_to_check = image[0][0] if isinstance(image[0], tuple) else image[0]
|
| 132 |
else:
|
|
|
|
| 234 |
print(f"Upsampling failed: {e}")
|
| 235 |
return prompt
|
| 236 |
|
| 237 |
+
# محاسبه زمان برای GPU (برای حالت توربو بسیار کمتر است)
|
| 238 |
def get_duration(prompt_embeds, image_list, width, height, num_inference_steps, guidance_scale, seed, progress=gr.Progress(track_tqdm=True)):
|
| 239 |
num_images = 0 if image_list is None else len(image_list)
|
| 240 |
step_duration = 1 + 0.8 * num_images
|
| 241 |
+
# در حالت توربو همیشه ۸ مرحله داریم، پس زمان محاسبه ثابت و کم است
|
| 242 |
+
return max(30, 8 * step_duration + 10)
|
| 243 |
|
| 244 |
# ==========================================
|
| 245 |
+
# 4. تابع اصلی GPU (Inference) - Turbo Optimized
|
| 246 |
# ==========================================
|
| 247 |
|
| 248 |
@spaces.GPU(duration=get_duration)
|
|
|
|
| 253 |
pipe_kwargs = {
|
| 254 |
"prompt_embeds": prompt_embeds,
|
| 255 |
"image": image_list,
|
| 256 |
+
# "num_inference_steps": num_inference_steps, # نادیده گرفته میشود به نفع توربو
|
| 257 |
"guidance_scale": guidance_scale,
|
| 258 |
"generator": generator,
|
| 259 |
"width": width,
|
| 260 |
"height": height,
|
| 261 |
}
|
| 262 |
|
| 263 |
+
# اعمال تنظیمات اجباری توربو
|
| 264 |
+
pipe_kwargs["sigmas"] = TURBO_SIGMAS
|
| 265 |
+
pipe_kwargs["num_inference_steps"] = 8 # همیشه ۸ مرحله برای توربو
|
| 266 |
+
|
| 267 |
+
if progress: progress(0, desc="Starting Turbo generation...")
|
| 268 |
image = pipe(**pipe_kwargs).images[0]
|
| 269 |
return image
|
| 270 |
|
|
|
|
| 313 |
progress(0.3, desc="Encoding...")
|
| 314 |
prompt_embeds = remote_text_encoder(final_prompt)
|
| 315 |
|
| 316 |
+
# Generation (GPU) - TURBO MODE
|
| 317 |
+
progress(0.4, desc="Generating (Turbo)...")
|
| 318 |
+
# ورودی num_inference_steps از UI گرفته میشود اما در تابع generate_image نادیده گرفته میشود (روی ۸ قفل است)
|
| 319 |
result_image = generate_image(
|
| 320 |
prompt_embeds, image_list, width, height,
|
| 321 |
num_inference_steps, guidance_scale, seed, progress
|
|
|
|
| 328 |
# 6. محاسبه اعتبار ب��قیمانده
|
| 329 |
user_record = get_user_record(fingerprint)
|
| 330 |
remaining = USAGE_LIMIT - user_record["count"] if user_record else 0
|
| 331 |
+
success_msg = f"تصویر با موفقیت ساخته شد (Turbo)."
|
| 332 |
if subscription_status != 'paid':
|
| 333 |
success_msg += f" (اعتبار باقیمانده امروز: {remaining})"
|
| 334 |
|
|
|
|
| 533 |
# 6. ساخت رابط کاربری (Gradio Blocks)
|
| 534 |
# ==========================================
|
| 535 |
|
|
|
|
| 536 |
with gr.Blocks() as demo:
|
| 537 |
gr.HTML(js_global_content + css_code)
|
| 538 |
|
|
|
|
| 540 |
status_box_input = gr.Textbox(elem_id="status_storage", visible=True)
|
| 541 |
|
| 542 |
with gr.Column(elem_id="col-container"):
|
| 543 |
+
gr.Markdown("# **ساخت تصویر با FLUX.2 Turbo (فوق سریع)**", elem_id="main-title")
|
| 544 |
+
gr.Markdown("با استفاده از مدل قدرتمند FLUX.2 Turbo متن فارسی خود را در چند ثانیه به تصاویر شگفتانگیز تبدیل کنید.", elem_id="main-description")
|
| 545 |
gr.HTML('<div id="badge-container"><span id="user-sub-badge"></span></div>')
|
| 546 |
|
| 547 |
with gr.Row():
|
|
|
|
| 566 |
|
| 567 |
status_box = gr.HTML(label="وضعیت")
|
| 568 |
|
| 569 |
+
run_button = gr.Button("✨ ساخت سریع تصویر (Turbo)", variant="primary", elem_classes="primary-btn", elem_id="run-btn", visible=True)
|
| 570 |
upgrade_button = gr.Button("💎 خرید نسخه نامحدود", variant="primary", elem_classes="upgrade-btn", elem_id="upgrade-btn", visible=False)
|
| 571 |
|
| 572 |
with gr.Accordion("تنظیمات پیشرفته", open=False):
|
|
|
|
| 577 |
width = gr.Slider(label="عرض (Width)", minimum=256, maximum=MAX_IMAGE_SIZE, step=8, value=1024)
|
| 578 |
height = gr.Slider(label="ارتفاع (Height)", minimum=256, maximum=MAX_IMAGE_SIZE, step=8, value=1024)
|
| 579 |
with gr.Row():
|
| 580 |
+
# این اسلایدر در حالت توربو بی تاثیر است و روی ۸ قفل می شود
|
| 581 |
+
num_inference_steps = gr.Slider(label="تعداد مراحل (ثابت در حالت Turbo)", minimum=1, maximum=50, step=1, value=8, interactive=False)
|
| 582 |
+
guidance_scale = gr.Slider(label="میزان وفاداری (Guidance)", minimum=1.0, maximum=10.0, step=0.1, value=2.5)
|
| 583 |
|
| 584 |
with gr.Column():
|
| 585 |
result = gr.Image(label="تصویر نهایی", show_label=True, interactive=False)
|