Update app.py
Browse files
app.py
CHANGED
|
@@ -21,7 +21,7 @@ from datetime import date
|
|
| 21 |
|
| 22 |
# رنگها و تنظیمات ظاهری
|
| 23 |
USAGE_LIMIT = 5
|
| 24 |
-
DATA_FILE = "usage_data.json"
|
| 25 |
PREMIUM_PAGE_ID = '1149636'
|
| 26 |
MAX_SEED = np.iinfo(np.int32).max
|
| 27 |
MAX_IMAGE_SIZE = 1024
|
|
@@ -104,13 +104,13 @@ def is_image_nsfw(image):
|
|
| 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:
|
| 112 |
return False
|
| 113 |
-
|
| 114 |
results = safety_classifier(img_to_check)
|
| 115 |
for result in results:
|
| 116 |
if result['label'] == 'nsfw' and result['score'] > 0.75:
|
|
@@ -126,9 +126,9 @@ def check_text_safety(text):
|
|
| 126 |
padded_text = f" {text_lower} "
|
| 127 |
for char in [".", ",", "!", "?", "-", "_", "(", ")", "[", "]", "{", "}"]:
|
| 128 |
padded_text = padded_text.replace(char, " ")
|
| 129 |
-
|
| 130 |
for word in BANNED_WORDS:
|
| 131 |
-
if f" {word} " in padded_text:
|
| 132 |
return False
|
| 133 |
return True
|
| 134 |
|
|
@@ -206,7 +206,7 @@ def upsample_prompt_logic(prompt, image_list):
|
|
| 206 |
else:
|
| 207 |
system_content = SYSTEM_PROMPT_TEXT_ONLY
|
| 208 |
messages = [{"role": "system", "content": system_content}, {"role": "user", "content": prompt}]
|
| 209 |
-
|
| 210 |
completion = hf_client.chat.completions.create(model=VLM_MODEL, messages=messages, max_tokens=1024)
|
| 211 |
return completion.choices[0].message.content
|
| 212 |
except Exception as e:
|
|
@@ -226,7 +226,7 @@ def get_duration(prompt_embeds, image_list, width, height, num_inference_steps,
|
|
| 226 |
def generate_image(prompt_embeds, image_list, width, height, num_inference_steps, guidance_scale, seed, progress=gr.Progress(track_tqdm=True)):
|
| 227 |
prompt_embeds = prompt_embeds.to(device)
|
| 228 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 229 |
-
|
| 230 |
pipe_kwargs = {
|
| 231 |
"prompt_embeds": prompt_embeds,
|
| 232 |
"image": image_list,
|
|
@@ -236,13 +236,13 @@ def generate_image(prompt_embeds, image_list, width, height, num_inference_steps
|
|
| 236 |
"width": width,
|
| 237 |
"height": height,
|
| 238 |
}
|
| 239 |
-
|
| 240 |
if progress: progress(0, desc="Starting generation...")
|
| 241 |
image = pipe(**pipe_kwargs).images[0]
|
| 242 |
return image
|
| 243 |
|
| 244 |
def infer(
|
| 245 |
-
prompt, input_images, seed, randomize_seed, width, height,
|
| 246 |
num_inference_steps, guidance_scale, prompt_upsampling,
|
| 247 |
fingerprint, subscription_status,
|
| 248 |
progress=gr.Progress(track_tqdm=True)
|
|
@@ -274,36 +274,36 @@ def infer(
|
|
| 274 |
# 4. آمادهسازی تنظیمات
|
| 275 |
if randomize_seed:
|
| 276 |
seed = random.randint(0, MAX_SEED)
|
| 277 |
-
|
| 278 |
try:
|
| 279 |
# Upsampling Prompt (Optional)
|
| 280 |
final_prompt = english_prompt
|
| 281 |
if prompt_upsampling:
|
| 282 |
progress(0.2, desc="Enhancing prompt...")
|
| 283 |
final_prompt = upsample_prompt_logic(english_prompt, image_list)
|
| 284 |
-
|
| 285 |
# Text Encoding (CPU/Network)
|
| 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
|
| 294 |
)
|
| 295 |
-
|
| 296 |
# 5. بررسی تصویر خروجی
|
| 297 |
if is_image_nsfw(result_image):
|
| 298 |
return None, seed, get_error_html("تصویر تولید شده حاوی محتوای نامناسب بود."), gr.update(visible=True), gr.update(visible=False)
|
| 299 |
-
|
| 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 |
-
|
| 307 |
btn_run_update = gr.update(visible=True)
|
| 308 |
btn_upg_update = gr.update(visible=False)
|
| 309 |
|
|
@@ -370,9 +370,9 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 370 |
for (let i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
|
| 371 |
return 'fp_' + Math.abs(hash).toString(16);
|
| 372 |
}
|
| 373 |
-
|
| 374 |
function isUserPaid(userObject) {
|
| 375 |
-
const PREMIUM_PAGE_ID = '1149636';
|
| 376 |
if (userObject && userObject.isLogin && userObject.accessible_pages) {
|
| 377 |
if (Array.isArray(userObject.accessible_pages)) return userObject.accessible_pages.some(page => String(page) === String(PREMIUM_PAGE_ID));
|
| 378 |
}
|
|
@@ -401,7 +401,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 401 |
|
| 402 |
async function initUserIdentity() {
|
| 403 |
window.userFingerprint = await getBrowserFingerprint();
|
| 404 |
-
window.userStatus = 'free';
|
| 405 |
window.parent.postMessage({ type: 'REQUEST_USER_STATUS' }, '*');
|
| 406 |
updateSubscriptionBadge('free');
|
| 407 |
updateHiddenInputs(window.userFingerprint, window.userStatus);
|
|
@@ -425,7 +425,7 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 425 |
// GPU Quota Modal
|
| 426 |
window.retryGeneration = function() { document.getElementById('custom-quota-modal')?.remove(); document.getElementById('run-btn')?.click(); };
|
| 427 |
window.closeErrorModal = function() { document.getElementById('custom-quota-modal')?.remove(); };
|
| 428 |
-
|
| 429 |
const showQuotaModal = () => {
|
| 430 |
if (document.getElementById('custom-quota-modal')) return;
|
| 431 |
const modalHtml = `
|
|
@@ -437,8 +437,8 @@ document.addEventListener('DOMContentLoaded', () => {
|
|
| 437 |
<div class="guide-content">
|
| 438 |
<p>برای ادامه ساخت تصویر، لطفاً طبق آموزش زیر IP خود را تغییر دهید (اینترنت را خاموش/روشن کنید یا VPN را قطع کنید) و سپس دکمه تلاش مجدد را بزنید.</p>
|
| 439 |
<div class="video-button-container">
|
| 440 |
-
<button onclick="parent.postMessage({ type: 'NAVIGATE_TO_URL', url: '#/nav/online/news/getSingle/1149635' }, '*')" class="elegant-video-button">
|
| 441 |
-
<span>دیدن ویدیو آموزشی</span>
|
| 442 |
</button>
|
| 443 |
</div>
|
| 444 |
</div>
|
|
@@ -505,17 +505,18 @@ footer { display: none !important; }
|
|
| 505 |
# 6. ساخت رابط کاربری (Gradio Blocks)
|
| 506 |
# ==========================================
|
| 507 |
|
| 508 |
-
|
|
|
|
| 509 |
gr.HTML(js_global_content + css_code)
|
| 510 |
-
|
| 511 |
fingerprint_box = gr.Textbox(elem_id="fingerprint_storage", visible=True)
|
| 512 |
status_box_input = gr.Textbox(elem_id="status_storage", visible=True)
|
| 513 |
-
|
| 514 |
with gr.Column(elem_id="col-container"):
|
| 515 |
gr.Markdown("# **ساخت تصویر با FLUX.2 (پیشرفته)**", elem_id="main-title")
|
| 516 |
gr.Markdown("با استفاده از مدل قدرتمند FLUX.2 متن فارسی خود را به تصاویر شگفتانگیز تبدیل کنید.", elem_id="main-description")
|
| 517 |
gr.HTML('<div id="badge-container"><span id="user-sub-badge"></span></div>')
|
| 518 |
-
|
| 519 |
with gr.Row():
|
| 520 |
with gr.Column():
|
| 521 |
with gr.Row():
|
|
@@ -526,7 +527,7 @@ with gr.Blocks(css=css_code) as demo:
|
|
| 526 |
placeholder="یک منظره زیبا از...",
|
| 527 |
rtl=True
|
| 528 |
)
|
| 529 |
-
|
| 530 |
with gr.Accordion("بارگذاری تصویر (اختیاری برای ویرایش/ایده)", open=False):
|
| 531 |
input_images = gr.Gallery(
|
| 532 |
label="تصاویر ورودی",
|
|
@@ -535,12 +536,12 @@ with gr.Blocks(css=css_code) as demo:
|
|
| 535 |
rows=1,
|
| 536 |
height=200
|
| 537 |
)
|
| 538 |
-
|
| 539 |
status_box = gr.HTML(label="وضعیت")
|
| 540 |
-
|
| 541 |
run_button = gr.Button("✨ ساخت تصویر", variant="primary", elem_classes="primary-btn", elem_id="run-btn", visible=True)
|
| 542 |
upgrade_button = gr.Button("💎 خرید نسخه نامحدود", variant="primary", elem_classes="upgrade-btn", elem_id="upgrade-btn", visible=False)
|
| 543 |
-
|
| 544 |
with gr.Accordion("تنظیمات پیشرفته", open=False):
|
| 545 |
prompt_upsampling = gr.Checkbox(label="بهبود خودکار پرامپت (هوشمند)", value=True)
|
| 546 |
seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
|
|
@@ -557,7 +558,7 @@ with gr.Blocks(css=css_code) as demo:
|
|
| 557 |
download_button = gr.Button("📥 دانلود تصویر", variant="secondary", elem_id="download-btn")
|
| 558 |
|
| 559 |
# اتصال رویدادها
|
| 560 |
-
|
| 561 |
# 1. آپدیت ابعاد بر اساس تصویر آپلودی
|
| 562 |
input_images.upload(
|
| 563 |
fn=update_dimensions_from_image,
|
|
@@ -576,7 +577,7 @@ with gr.Blocks(css=css_code) as demo:
|
|
| 576 |
run_button.click(
|
| 577 |
fn=infer,
|
| 578 |
inputs=[
|
| 579 |
-
prompt, input_images, seed, randomize_seed, width, height,
|
| 580 |
num_inference_steps, guidance_scale, prompt_upsampling,
|
| 581 |
fingerprint_box, status_box_input
|
| 582 |
],
|
|
|
|
| 21 |
|
| 22 |
# رنگها و تنظیمات ظاهری
|
| 23 |
USAGE_LIMIT = 5
|
| 24 |
+
DATA_FILE = "usage_data.json"
|
| 25 |
PREMIUM_PAGE_ID = '1149636'
|
| 26 |
MAX_SEED = np.iinfo(np.int32).max
|
| 27 |
MAX_IMAGE_SIZE = 1024
|
|
|
|
| 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:
|
| 112 |
return False
|
| 113 |
+
|
| 114 |
results = safety_classifier(img_to_check)
|
| 115 |
for result in results:
|
| 116 |
if result['label'] == 'nsfw' and result['score'] > 0.75:
|
|
|
|
| 126 |
padded_text = f" {text_lower} "
|
| 127 |
for char in [".", ",", "!", "?", "-", "_", "(", ")", "[", "]", "{", "}"]:
|
| 128 |
padded_text = padded_text.replace(char, " ")
|
| 129 |
+
|
| 130 |
for word in BANNED_WORDS:
|
| 131 |
+
if f" {word} " in padded_text:
|
| 132 |
return False
|
| 133 |
return True
|
| 134 |
|
|
|
|
| 206 |
else:
|
| 207 |
system_content = SYSTEM_PROMPT_TEXT_ONLY
|
| 208 |
messages = [{"role": "system", "content": system_content}, {"role": "user", "content": prompt}]
|
| 209 |
+
|
| 210 |
completion = hf_client.chat.completions.create(model=VLM_MODEL, messages=messages, max_tokens=1024)
|
| 211 |
return completion.choices[0].message.content
|
| 212 |
except Exception as e:
|
|
|
|
| 226 |
def generate_image(prompt_embeds, image_list, width, height, num_inference_steps, guidance_scale, seed, progress=gr.Progress(track_tqdm=True)):
|
| 227 |
prompt_embeds = prompt_embeds.to(device)
|
| 228 |
generator = torch.Generator(device=device).manual_seed(seed)
|
| 229 |
+
|
| 230 |
pipe_kwargs = {
|
| 231 |
"prompt_embeds": prompt_embeds,
|
| 232 |
"image": image_list,
|
|
|
|
| 236 |
"width": width,
|
| 237 |
"height": height,
|
| 238 |
}
|
| 239 |
+
|
| 240 |
if progress: progress(0, desc="Starting generation...")
|
| 241 |
image = pipe(**pipe_kwargs).images[0]
|
| 242 |
return image
|
| 243 |
|
| 244 |
def infer(
|
| 245 |
+
prompt, input_images, seed, randomize_seed, width, height,
|
| 246 |
num_inference_steps, guidance_scale, prompt_upsampling,
|
| 247 |
fingerprint, subscription_status,
|
| 248 |
progress=gr.Progress(track_tqdm=True)
|
|
|
|
| 274 |
# 4. آمادهسازی تنظیمات
|
| 275 |
if randomize_seed:
|
| 276 |
seed = random.randint(0, MAX_SEED)
|
| 277 |
+
|
| 278 |
try:
|
| 279 |
# Upsampling Prompt (Optional)
|
| 280 |
final_prompt = english_prompt
|
| 281 |
if prompt_upsampling:
|
| 282 |
progress(0.2, desc="Enhancing prompt...")
|
| 283 |
final_prompt = upsample_prompt_logic(english_prompt, image_list)
|
| 284 |
+
|
| 285 |
# Text Encoding (CPU/Network)
|
| 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
|
| 294 |
)
|
| 295 |
+
|
| 296 |
# 5. بررسی تصویر خروجی
|
| 297 |
if is_image_nsfw(result_image):
|
| 298 |
return None, seed, get_error_html("تصویر تولید شده حاوی محتوای نامناسب بود."), gr.update(visible=True), gr.update(visible=False)
|
| 299 |
+
|
| 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 |
+
|
| 307 |
btn_run_update = gr.update(visible=True)
|
| 308 |
btn_upg_update = gr.update(visible=False)
|
| 309 |
|
|
|
|
| 370 |
for (let i = 0; i < str.length; i++) { hash = ((hash << 5) - hash) + str.charCodeAt(i); hash |= 0; }
|
| 371 |
return 'fp_' + Math.abs(hash).toString(16);
|
| 372 |
}
|
| 373 |
+
|
| 374 |
function isUserPaid(userObject) {
|
| 375 |
+
const PREMIUM_PAGE_ID = '1149636';
|
| 376 |
if (userObject && userObject.isLogin && userObject.accessible_pages) {
|
| 377 |
if (Array.isArray(userObject.accessible_pages)) return userObject.accessible_pages.some(page => String(page) === String(PREMIUM_PAGE_ID));
|
| 378 |
}
|
|
|
|
| 401 |
|
| 402 |
async function initUserIdentity() {
|
| 403 |
window.userFingerprint = await getBrowserFingerprint();
|
| 404 |
+
window.userStatus = 'free';
|
| 405 |
window.parent.postMessage({ type: 'REQUEST_USER_STATUS' }, '*');
|
| 406 |
updateSubscriptionBadge('free');
|
| 407 |
updateHiddenInputs(window.userFingerprint, window.userStatus);
|
|
|
|
| 425 |
// GPU Quota Modal
|
| 426 |
window.retryGeneration = function() { document.getElementById('custom-quota-modal')?.remove(); document.getElementById('run-btn')?.click(); };
|
| 427 |
window.closeErrorModal = function() { document.getElementById('custom-quota-modal')?.remove(); };
|
| 428 |
+
|
| 429 |
const showQuotaModal = () => {
|
| 430 |
if (document.getElementById('custom-quota-modal')) return;
|
| 431 |
const modalHtml = `
|
|
|
|
| 437 |
<div class="guide-content">
|
| 438 |
<p>برای ادامه ساخت تصویر، لطفاً طبق آموزش زیر IP خود را تغییر دهید (اینترنت را خاموش/روشن کنید یا VPN را قطع کنید) و سپس دکمه تلاش مجدد را بزنید.</p>
|
| 439 |
<div class="video-button-container">
|
| 440 |
+
<button onclick="parent.postMessage({ type: 'NAVIGATE_TO_URL', url: '#/nav/online/news/getSingle/1149635' }, '*')" class="elegant-video-button">
|
| 441 |
+
<span>دیدن ویدیو آموزشی</span>
|
| 442 |
</button>
|
| 443 |
</div>
|
| 444 |
</div>
|
|
|
|
| 505 |
# 6. ساخت رابط کاربری (Gradio Blocks)
|
| 506 |
# ==========================================
|
| 507 |
|
| 508 |
+
# ******** این خط اصلاح شده است ********
|
| 509 |
+
with gr.Blocks() as demo:
|
| 510 |
gr.HTML(js_global_content + css_code)
|
| 511 |
+
|
| 512 |
fingerprint_box = gr.Textbox(elem_id="fingerprint_storage", visible=True)
|
| 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 (پیشرفته)**", elem_id="main-title")
|
| 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():
|
| 521 |
with gr.Column():
|
| 522 |
with gr.Row():
|
|
|
|
| 527 |
placeholder="یک منظره زیبا از...",
|
| 528 |
rtl=True
|
| 529 |
)
|
| 530 |
+
|
| 531 |
with gr.Accordion("بارگذاری تصویر (اختیاری برای ویرایش/ایده)", open=False):
|
| 532 |
input_images = gr.Gallery(
|
| 533 |
label="تصاویر ورودی",
|
|
|
|
| 536 |
rows=1,
|
| 537 |
height=200
|
| 538 |
)
|
| 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):
|
| 546 |
prompt_upsampling = gr.Checkbox(label="بهبود خودکار پرامپت (هوشمند)", value=True)
|
| 547 |
seed = gr.Slider(label="دانه تصادفی (Seed)", minimum=0, maximum=MAX_SEED, step=1, value=0)
|
|
|
|
| 558 |
download_button = gr.Button("📥 دانلود تصویر", variant="secondary", elem_id="download-btn")
|
| 559 |
|
| 560 |
# اتصال رویدادها
|
| 561 |
+
|
| 562 |
# 1. آپدیت ابعاد بر اساس تصویر آپلودی
|
| 563 |
input_images.upload(
|
| 564 |
fn=update_dimensions_from_image,
|
|
|
|
| 577 |
run_button.click(
|
| 578 |
fn=infer,
|
| 579 |
inputs=[
|
| 580 |
+
prompt, input_images, seed, randomize_seed, width, height,
|
| 581 |
num_inference_steps, guidance_scale, prompt_upsampling,
|
| 582 |
fingerprint_box, status_box_input
|
| 583 |
],
|