selfit-camera commited on
Commit
224425b
·
1 Parent(s): 56a6511
Files changed (2) hide show
  1. app.py +614 -184
  2. util.py +50 -12
app.py CHANGED
@@ -4,144 +4,185 @@ import os
4
  import shutil
5
  import tempfile
6
  import time
7
- from util import process_image_edit, process_local_image_edit
8
  from nfsw import NSFWDetector
9
 
10
- # 配置参数
11
- NSFW_TIME_WINDOW = 5 # 时间窗口:5分钟
12
- NSFW_LIMIT = 10 # 限制次数:6次
 
 
 
 
 
 
 
 
13
 
14
  IP_Dict = {}
15
- NSFW_Dict = {} # 记录每个IP的NSFW违规次数
16
- NSFW_Time_Dict = {} # 记录每个IP在特定时间窗口的NSFW检测次数,键格式: "ip_timestamp"
 
 
 
 
 
 
 
 
 
17
 
18
- def get_current_time_window():
19
  """
20
- 获取当前的整点时间窗口
 
 
 
 
 
 
 
 
 
21
 
22
  Returns:
23
- tuple: (窗口开始时间戳, 窗口结束时间戳)
24
  """
25
- current_time = time.time()
26
- # 获取当前时间的分钟数
27
- current_struct = time.localtime(current_time)
28
- current_minute = current_struct.tm_min
29
 
30
- # 计算当前5分钟时间窗口的开始分钟
31
- window_start_minute = (current_minute // NSFW_TIME_WINDOW) * NSFW_TIME_WINDOW
32
-
33
- # 构建窗口开始时间
34
- window_start_struct = time.struct_time((
35
- current_struct.tm_year, current_struct.tm_mon, current_struct.tm_mday,
36
- current_struct.tm_hour, window_start_minute, 0,
37
- current_struct.tm_wday, current_struct.tm_yday, current_struct.tm_isdst
38
- ))
39
-
40
- window_start_time = time.mktime(window_start_struct)
41
- window_end_time = window_start_time + (NSFW_TIME_WINDOW * 60)
42
-
43
- return window_start_time, window_end_time
44
 
45
- def check_nsfw_rate_limit(client_ip):
46
  """
47
- 检查IP的NSFW检测频率限制(基于整点时间窗口)
48
-
49
- Args:
50
- client_ip (str): 客户端IP地址
51
 
52
  Returns:
53
- tuple: (是否超过限制, 剩余等待时间)
54
  """
55
- current_time = time.time()
56
- window_start_time, window_end_time = get_current_time_window()
57
 
58
- # 清理不在当前时间窗口的记录
59
- current_window_key = f"{client_ip}_{int(window_start_time)}"
 
 
 
 
 
60
 
61
- # 如果没有当前窗口的记录,创建新的
62
- if current_window_key not in NSFW_Time_Dict:
63
- NSFW_Time_Dict[current_window_key] = 0
64
 
65
- # 清理旧的窗口记录(保持内存清洁)
66
- keys_to_remove = []
67
- for key in NSFW_Time_Dict:
68
- if key.startswith(client_ip + "_"):
69
- window_time = int(key.split("_")[1])
70
- if window_time < window_start_time:
71
- keys_to_remove.append(key)
 
 
 
 
 
 
 
 
 
 
 
72
 
73
- for key in keys_to_remove:
74
- del NSFW_Time_Dict[key]
75
 
76
- # 检查当前窗口是否超过限制
77
- if NSFW_Time_Dict[current_window_key] >= NSFW_LIMIT:
78
- # 计算到下一个时间窗口的等待时间
79
- wait_time = window_end_time - current_time
80
- return True, max(0, wait_time)
 
 
81
 
82
- return False, 0
83
 
84
- def record_nsfw_detection(client_ip):
85
  """
86
- 记录IP的NSFW检测时间(基于整点时间窗口)
87
-
88
- Args:
89
- client_ip (str): 客户端IP地址
90
  """
91
- window_start_time, _ = get_current_time_window()
92
- current_window_key = f"{client_ip}_{int(window_start_time)}"
93
-
94
- # 增加当前窗口的计数
95
- if current_window_key not in NSFW_Time_Dict:
96
- NSFW_Time_Dict[current_window_key] = 0
97
- NSFW_Time_Dict[current_window_key] += 1
98
 
99
- # 记录到NSFW_Dict中(兼容现有逻辑)
100
- if client_ip not in NSFW_Dict:
101
- NSFW_Dict[client_ip] = 0
102
- NSFW_Dict[client_ip] += 1
 
 
 
 
 
 
 
 
 
 
103
 
104
- def get_current_window_info(client_ip):
105
  """
106
- 获取当前窗口的统计信息(用于调试)
107
 
108
  Args:
109
- client_ip (str): 客户端IP地址
 
110
 
111
  Returns:
112
- dict: 当前窗口的统计信息
113
  """
114
- window_start_time, window_end_time = get_current_time_window()
115
- current_window_key = f"{client_ip}_{int(window_start_time)}"
116
-
117
- current_count = NSFW_Time_Dict.get(current_window_key, 0)
118
-
119
- # 格式化时间显示
120
- start_time_str = time.strftime("%H:%M:%S", time.localtime(window_start_time))
121
- end_time_str = time.strftime("%H:%M:%S", time.localtime(window_end_time))
122
-
123
- return {
124
- "window_start": start_time_str,
125
- "window_end": end_time_str,
126
- "current_count": current_count,
127
- "limit": NSFW_LIMIT,
128
- "window_key": current_window_key
129
- }
130
-
131
- # 初始化NSFW检测器(从Hugging Face下载)
 
 
 
 
 
 
132
  try:
133
- nsfw_detector = NSFWDetector() # 自动从Hugging Face下载falconsai_yolov9_nsfw_model_quantized.pt
134
- print("✅ NSFW检测器初始化成功")
135
  except Exception as e:
136
- print(f"❌ NSFW检测器初始化失败: {e}")
137
  nsfw_detector = None
138
 
139
  def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.Progress()):
140
  """
141
- Interface function for processing image editing
142
  """
143
  try:
144
- # 提取用户IP
145
  client_ip = request.client.host
146
  x_forwarded_for = dict(request.headers).get('x-forwarded-for')
147
  if x_forwarded_for:
@@ -150,52 +191,54 @@ def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.P
150
  IP_Dict[client_ip] = 0
151
  IP_Dict[client_ip] += 1
152
 
153
-
154
  if input_image is None:
155
  return None, "Please upload an image first"
156
 
157
  if not prompt or prompt.strip() == "":
158
  return None, "Please enter editing prompt"
159
 
160
- # 检查prompt长度是否大于3个字符
161
  if len(prompt.strip()) <= 3:
162
  return None, "❌ Editing prompt must be more than 3 characters"
163
  except Exception as e:
164
  print(f"⚠️ Request preprocessing error: {e}")
165
  return None, "❌ Request processing error"
166
 
167
- # 检查图片是否包含NSFW内容
168
- nsfw_result = None
169
- if nsfw_detector is not None and input_image is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
170
  try:
171
- # 直接使用PIL Image对象进行检测,避免文件路径问题
172
  nsfw_result = nsfw_detector.predict_pil_label_only(input_image)
173
 
174
  if nsfw_result.lower() == "nsfw":
175
- print(f"🔍 NSFW检测结果: ❌❌❌ {nsfw_result} - IP: {client_ip}")
176
- # 检查NSFW频率限制
177
- is_rate_limited, wait_time = check_nsfw_rate_limit(client_ip)
178
-
179
- if is_rate_limited:
180
- # 超过频率限制,显示等待提示并阻止继续
181
- wait_minutes = int(wait_time / 60) + 1 # 向上取整到分钟
182
- window_info = get_current_window_info(client_ip)
183
- print(f"⚠️ NSFW频率限制 - IP: {client_ip}")
184
- print(f" 时间窗口: {window_info['window_start']} - {window_info['window_end']}")
185
- print(f" 当前计数: {window_info['current_count']}/{NSFW_LIMIT}, 需要等待 {wait_minutes} 分钟")
186
- return None, f"❌ Please wait {wait_minutes} minutes before generating again"
187
- else:
188
- # 未超过频率限制,记录此次检测但允许继续处理
189
- record_nsfw_detection(client_ip)
190
- window_info = get_current_window_info(client_ip)
191
  else:
192
- print(f"🔍 NSFW检测结果: ✅✅✅ {nsfw_result} - IP: {client_ip}")
193
 
194
  except Exception as e:
195
- print(f"⚠️ NSFW检测失败: {e}")
196
- # 检测失败时允许继续处理
197
 
198
-
199
  result_url = None
200
  status_message = ""
201
 
@@ -203,27 +246,75 @@ def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.P
203
  try:
204
  nonlocal status_message
205
  status_message = message
206
- # 增加错误处理,防止 progress 更新失败
207
  if progress is not None:
208
  progress(0.5, desc=message)
209
  except Exception as e:
210
  print(f"⚠️ Progress update failed: {e}")
211
 
212
  try:
213
- # 打印成功访问的信息
214
- print(f"✅ Processing started - IP: {client_ip}, count: {IP_Dict[client_ip]}, prompt: {prompt.strip()}", flush=True)
 
 
 
215
 
216
  # Call image editing processing function
217
  result_url, message = process_image_edit(input_image, prompt.strip(), progress_callback)
218
 
219
  if result_url:
220
  print(f"✅ Processing completed successfully - IP: {client_ip}, result_url: {result_url}", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
221
  try:
222
  if progress is not None:
223
  progress(1.0, desc="Processing completed")
224
  except Exception as e:
225
  print(f"⚠️ Final progress update failed: {e}")
226
- return result_url, "✅ " + message
 
227
  else:
228
  print(f"❌ Processing failed - IP: {client_ip}, error: {message}", flush=True)
229
  return None, "❌ " + message
@@ -232,14 +323,12 @@ def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.P
232
  print(f"❌ Processing exception - IP: {client_ip}, error: {str(e)}")
233
  return None, f"❌ Error occurred during processing: {str(e)}"
234
 
235
- # 不再需要复杂的状态管理函数,已简化为内联函数
236
-
237
  def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Progress()):
238
  """
239
- 处理局部编辑请求
240
  """
241
  try:
242
- # 提取用户IP
243
  client_ip = request.client.host
244
  x_forwarded_for = dict(request.headers).get('x-forwarded-for')
245
  if x_forwarded_for:
@@ -248,7 +337,6 @@ def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Pr
248
  IP_Dict[client_ip] = 0
249
  IP_Dict[client_ip] += 1
250
 
251
-
252
  if image_dict is None:
253
  return None, "Please upload an image and draw the area to edit"
254
 
@@ -272,34 +360,40 @@ def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Pr
272
  print(f"⚠️ Local edit request preprocessing error: {e}")
273
  return None, "❌ Request processing error"
274
 
275
- # 检查图片是否包含NSFW内容
276
- nsfw_result = None
277
- if nsfw_detector is not None and base_image is not None:
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  try:
279
  nsfw_result = nsfw_detector.predict_pil_label_only(base_image)
280
 
281
  if nsfw_result.lower() == "nsfw":
282
- print(f"🔍 NSFW检测结果: ❌❌❌ {nsfw_result} - IP: {client_ip}")
283
- # 检查NSFW频率限制
284
- is_rate_limited, wait_time = check_nsfw_rate_limit(client_ip)
285
-
286
- if is_rate_limited:
287
- wait_minutes = int(wait_time / 60) + 1
288
- window_info = get_current_window_info(client_ip)
289
- print(f"⚠️ NSFW频率限制 - IP: {client_ip}")
290
- print(f" 时间窗口: {window_info['window_start']} - {window_info['window_end']}")
291
- print(f" 当前计数: {window_info['current_count']}/{NSFW_LIMIT}, 需要等待 {wait_minutes} 分钟")
292
- return None, f"❌ Please wait {wait_minutes} minutes before generating again"
293
- else:
294
- record_nsfw_detection(client_ip)
295
- window_info = get_current_window_info(client_ip)
296
  else:
297
- print(f"🔍 NSFW检测结果: ✅✅✅ {nsfw_result} - IP: {client_ip}")
298
 
299
  except Exception as e:
300
- print(f"⚠️ NSFW检测失败: {e}")
301
-
302
- # IP访问限制检查
303
 
304
  result_url = None
305
  status_message = ""
@@ -308,26 +402,75 @@ def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Pr
308
  try:
309
  nonlocal status_message
310
  status_message = message
311
- # 增加错误处理,防止 progress 更新失败
312
  if progress is not None:
313
  progress(0.5, desc=message)
314
  except Exception as e:
315
  print(f"⚠️ Local edit progress update failed: {e}")
316
 
317
  try:
318
- print(f"✅ Local editing started - IP: {client_ip}, count: {IP_Dict[client_ip]}, prompt: {prompt.strip()}", flush=True)
 
 
 
 
319
 
320
- # 调用局部图像编辑处理函数
321
  result_url, message = process_local_image_edit(base_image, layers, prompt.strip(), progress_callback)
322
 
323
  if result_url:
324
  print(f"✅ Local editing completed successfully - IP: {client_ip}, result_url: {result_url}", flush=True)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
325
  try:
326
  if progress is not None:
327
  progress(1.0, desc="Processing completed")
328
  except Exception as e:
329
  print(f"⚠️ Local edit final progress update failed: {e}")
330
- return result_url, "✅ " + message
 
331
  else:
332
  print(f"❌ Local editing processing failed - IP: {client_ip}, error: {message}", flush=True)
333
  return None, "❌ " + message
@@ -363,20 +506,17 @@ def create_app():
363
  width: 100%;
364
  }
365
  """,
366
- # 改善并发性能的配置
367
  head="""
368
  <script>
369
- // 减少客户端状态更新频率,避免过度的 SSE 连接
370
  if (window.gradio) {
371
- window.gradio.update_frequency = 2000; // 2秒更新一次
372
  }
373
  </script>
374
  """
375
  ) as app:
376
 
377
- # 减少State组件,只保留必要的
378
- # 移除了大部分State组件以减少状态管理复杂度
379
-
380
  gr.Markdown(
381
  """
382
  # 🎨 AI Image Editor
@@ -384,6 +524,15 @@ def create_app():
384
  elem_classes=["main-container"]
385
  )
386
 
 
 
 
 
 
 
 
 
 
387
  with gr.Tabs():
388
  # Global editing tab
389
  with gr.Tab("🌍 Global Editing"):
@@ -419,7 +568,7 @@ def create_app():
419
  elem_classes=["result-area"]
420
  )
421
 
422
- # 添加 "Use as Input" 按钮
423
  use_as_input_btn = gr.Button(
424
  "🔄 Use as Input",
425
  variant="secondary",
@@ -454,18 +603,18 @@ def create_app():
454
  outputs=prompt_input
455
  )
456
 
457
- # 绑定按钮点击事件 - 简��,移除状态管理
458
  edit_button.click(
459
  fn=edit_image_interface,
460
  inputs=[input_image, prompt_input],
461
  outputs=[output_image, status_output],
462
  show_progress=True,
463
- # 增加并发设置
464
- concurrency_limit=10, # 限制并发数
465
  api_name="global_edit"
466
  )
467
 
468
- # 简化 "Use as Input" 按钮,直接复制图片
469
  def simple_use_as_input(output_img):
470
  if output_img is not None:
471
  return output_img
@@ -486,7 +635,7 @@ def create_app():
486
  label="Upload image and draw mask",
487
  type="pil",
488
  height=512,
489
- brush=gr.Brush(colors=["#ff0000"], default_size=60),
490
  elem_classes=["upload-area"]
491
  )
492
 
@@ -512,7 +661,7 @@ def create_app():
512
  elem_classes=["result-area"]
513
  )
514
 
515
- # 添加 "Use as Input" 按钮
516
  local_use_as_input_btn = gr.Button(
517
  "🔄 Use as Input",
518
  variant="secondary",
@@ -547,21 +696,21 @@ def create_app():
547
  outputs=local_prompt_input
548
  )
549
 
550
- # 绑定局部编辑按钮点击事件 - 简化,移除状态管理
551
  local_edit_button.click(
552
  fn=local_edit_interface,
553
  inputs=[local_input_image, local_prompt_input],
554
  outputs=[local_output_image, local_status_output],
555
  show_progress=True,
556
- # 增加并发设置
557
- concurrency_limit=8, # 局部编辑更复杂,限制更少的并发
558
  api_name="local_edit"
559
  )
560
 
561
- # 简化局部编辑 "Use as Input" 按钮
562
  def simple_local_use_as_input(output_img):
563
  if output_img is not None:
564
- # 创建简单的 ImageEditor 格式
565
  editor_data = {
566
  "background": output_img,
567
  "layers": [],
@@ -575,22 +724,303 @@ def create_app():
575
  inputs=[local_output_image],
576
  outputs=[local_input_image]
577
  )
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
578
 
579
  return app
580
 
581
  if __name__ == "__main__":
582
  app = create_app()
583
- # 改善队列配置以处理高并发和防止 SSE 连接问题
584
  app.queue(
585
- default_concurrency_limit=20, # 默认并发限制
586
- max_size=50, # 队列最大大小
587
- api_open=False # 关闭 API 访问,减少资源消耗
588
  )
589
  app.launch(
590
  server_name="0.0.0.0",
591
- show_error=True, # 显示详细错误信息
592
- quiet=False, # 保持日志输出
593
- max_threads=40, # 增加线程池大小
594
  height=800,
595
- favicon_path=None # 减少资源加载
596
  )
 
4
  import shutil
5
  import tempfile
6
  import time
7
+ from util import process_image_edit, process_local_image_edit, download_and_check_result_nsfw
8
  from nfsw import NSFWDetector
9
 
10
+ # Configuration parameters
11
+ FREE_TRY_N = 20 # Free phase: first 20 tries without restrictions
12
+ SLOW_TRY_N = 30 # Slow phase start: 30 tries
13
+ SLOW2_TRY_N = 40 # Slow phase start: 30 tries
14
+ RATE_LIMIT_60 = 75 # Full restriction: blocked after 60 tries
15
+
16
+ # Time window configuration (minutes)
17
+ PHASE_1_WINDOW = 5 # 20-30 tries: 3 minutes
18
+ PHASE_2_WINDOW = 8 # 30-40 tries: 6 minutes
19
+ PHASE_3_WINDOW = 15 # 40-60 tries: 10 minutes
20
+ MAX_IMAGES_PER_WINDOW = 2 # Max images per time window
21
 
22
  IP_Dict = {}
23
+ # IP generation statistics and time window tracking
24
+ IP_Generation_Count = {} # Record total generation count for each IP
25
+ IP_Rate_Limit_Track = {} # Record generation count and timestamp in current time window for each IP
26
+
27
+ def get_ip_generation_count(client_ip):
28
+ """
29
+ Get IP generation count
30
+ """
31
+ if client_ip not in IP_Generation_Count:
32
+ IP_Generation_Count[client_ip] = 0
33
+ return IP_Generation_Count[client_ip]
34
 
35
+ def increment_ip_generation_count(client_ip):
36
  """
37
+ Increment IP generation count
38
+ """
39
+ if client_ip not in IP_Generation_Count:
40
+ IP_Generation_Count[client_ip] = 0
41
+ IP_Generation_Count[client_ip] += 1
42
+ return IP_Generation_Count[client_ip]
43
+
44
+ def get_ip_phase(client_ip):
45
+ """
46
+ Get current phase for IP
47
 
48
  Returns:
49
+ str: 'free', 'rate_limit_1', 'rate_limit_2', 'rate_limit_3', 'blocked'
50
  """
51
+ count = get_ip_generation_count(client_ip)
 
 
 
52
 
53
+ if count < FREE_TRY_N: # 0-19 tries
54
+ return 'free'
55
+ elif count < SLOW_TRY_N: # 20-29 tries
56
+ return 'rate_limit_1' # NSFW blur + 3 minutes 2 images
57
+ elif count < SLOW2_TRY_N: # 30-39 tries
58
+ return 'rate_limit_2' # NSFW blur + 6 minutes 2 images
59
+ elif count < RATE_LIMIT_60: # 40-59 tries
60
+ return 'rate_limit_3' # NSFW blur + 10 minutes 2 images
61
+ else: # 60+ tries
62
+ return 'blocked' # Generation blocked
 
 
 
 
63
 
64
+ def check_rate_limit_for_phase(client_ip, phase):
65
  """
66
+ Check rate limit for specific phase
 
 
 
67
 
68
  Returns:
69
+ tuple: (is_limited, wait_time_minutes, current_count)
70
  """
71
+ if phase not in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
72
+ return False, 0, 0
73
 
74
+ # Determine time window
75
+ if phase == 'rate_limit_1':
76
+ window_minutes = PHASE_1_WINDOW # 3 minutes
77
+ elif phase == 'rate_limit_2':
78
+ window_minutes = PHASE_2_WINDOW # 6 minutes
79
+ else: # rate_limit_3
80
+ window_minutes = PHASE_3_WINDOW # 10 minutes
81
 
82
+ current_time = time.time()
83
+ window_key = f"{client_ip}_{phase}"
 
84
 
85
+ # Clean expired records
86
+ if window_key in IP_Rate_Limit_Track:
87
+ track_data = IP_Rate_Limit_Track[window_key]
88
+ # Check if within current time window
89
+ if current_time - track_data['start_time'] > window_minutes * 60:
90
+ # Time window expired, reset
91
+ IP_Rate_Limit_Track[window_key] = {
92
+ 'count': 0,
93
+ 'start_time': current_time,
94
+ 'last_generation': current_time
95
+ }
96
+ else:
97
+ # Initialize
98
+ IP_Rate_Limit_Track[window_key] = {
99
+ 'count': 0,
100
+ 'start_time': current_time,
101
+ 'last_generation': current_time
102
+ }
103
 
104
+ track_data = IP_Rate_Limit_Track[window_key]
 
105
 
106
+ # Check if exceeded limit
107
+ if track_data['count'] >= MAX_IMAGES_PER_WINDOW:
108
+ # Calculate remaining wait time
109
+ elapsed = current_time - track_data['start_time']
110
+ wait_time = (window_minutes * 60) - elapsed
111
+ wait_minutes = max(0, wait_time / 60)
112
+ return True, wait_minutes, track_data['count']
113
 
114
+ return False, 0, track_data['count']
115
 
116
+ def record_generation_attempt(client_ip, phase):
117
  """
118
+ Record generation attempt
 
 
 
119
  """
120
+ # Increment total count
121
+ increment_ip_generation_count(client_ip)
 
 
 
 
 
122
 
123
+ # Record time window count
124
+ if phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
125
+ window_key = f"{client_ip}_{phase}"
126
+ current_time = time.time()
127
+
128
+ if window_key in IP_Rate_Limit_Track:
129
+ IP_Rate_Limit_Track[window_key]['count'] += 1
130
+ IP_Rate_Limit_Track[window_key]['last_generation'] = current_time
131
+ else:
132
+ IP_Rate_Limit_Track[window_key] = {
133
+ 'count': 1,
134
+ 'start_time': current_time,
135
+ 'last_generation': current_time
136
+ }
137
 
138
+ def apply_gaussian_blur_to_image_url(image_url, blur_strength=50):
139
  """
140
+ Apply Gaussian blur to image URL
141
 
142
  Args:
143
+ image_url (str): Original image URL
144
+ blur_strength (int): Blur strength, default 50 (heavy blur)
145
 
146
  Returns:
147
+ PIL.Image: Blurred PIL Image object
148
  """
149
+ try:
150
+ import requests
151
+ from PIL import Image, ImageFilter
152
+ import io
153
+
154
+ # Download image
155
+ response = requests.get(image_url, timeout=30)
156
+ if response.status_code != 200:
157
+ return None
158
+
159
+ # Convert to PIL Image
160
+ image_data = io.BytesIO(response.content)
161
+ image = Image.open(image_data)
162
+
163
+ # Apply heavy Gaussian blur
164
+ blurred_image = image.filter(ImageFilter.GaussianBlur(radius=blur_strength))
165
+
166
+ return blurred_image
167
+
168
+ except Exception as e:
169
+ print(f"⚠️ Failed to apply Gaussian blur: {e}")
170
+ return None
171
+
172
+ # Initialize NSFW detector (download from Hugging Face)
173
  try:
174
+ nsfw_detector = NSFWDetector() # Auto download falconsai_yolov9_nsfw_model_quantized.pt from Hugging Face
175
+ print("✅ NSFW detector initialized successfully")
176
  except Exception as e:
177
+ print(f"❌ NSFW detector initialization failed: {e}")
178
  nsfw_detector = None
179
 
180
  def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.Progress()):
181
  """
182
+ Interface function for processing image editing with phase-based limitations
183
  """
184
  try:
185
+ # Extract user IP
186
  client_ip = request.client.host
187
  x_forwarded_for = dict(request.headers).get('x-forwarded-for')
188
  if x_forwarded_for:
 
191
  IP_Dict[client_ip] = 0
192
  IP_Dict[client_ip] += 1
193
 
 
194
  if input_image is None:
195
  return None, "Please upload an image first"
196
 
197
  if not prompt or prompt.strip() == "":
198
  return None, "Please enter editing prompt"
199
 
200
+ # Check if prompt length is greater than 3 characters
201
  if len(prompt.strip()) <= 3:
202
  return None, "❌ Editing prompt must be more than 3 characters"
203
  except Exception as e:
204
  print(f"⚠️ Request preprocessing error: {e}")
205
  return None, "❌ Request processing error"
206
 
207
+ # Get user current phase
208
+ current_phase = get_ip_phase(client_ip)
209
+ current_count = get_ip_generation_count(client_ip)
210
+
211
+ print(f"📊 User phase info - IP: {client_ip}, current phase: {current_phase}, generation count: {current_count}")
212
+
213
+ # Check if completely blocked
214
+ if current_phase == 'blocked':
215
+ return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/#generator for unlimited generation"
216
+
217
+ # Check rate limit (applies to rate_limit phases)
218
+ if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
219
+ is_limited, wait_minutes, window_count = check_rate_limit_for_phase(client_ip, current_phase)
220
+ if is_limited:
221
+ wait_minutes_int = int(wait_minutes) + 1
222
+ return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/#generator for unlimited generation, or wait {wait_minutes_int} minutes before generating again"
223
+
224
+ # Handle NSFW detection based on phase
225
+ is_nsfw_task = False # Track if this task involves NSFW content
226
+
227
+ # Skip NSFW detection in free phase
228
+ if current_phase != 'free' and nsfw_detector is not None and input_image is not None:
229
  try:
 
230
  nsfw_result = nsfw_detector.predict_pil_label_only(input_image)
231
 
232
  if nsfw_result.lower() == "nsfw":
233
+ is_nsfw_task = True
234
+ print(f"🔍 Input NSFW detected in {current_phase} phase: ❌❌❌ {nsfw_result} - IP: {client_ip} (will blur result)")
 
 
 
 
 
 
 
 
 
 
 
 
 
 
235
  else:
236
+ print(f"🔍 Input NSFW check passed: ✅✅✅ {nsfw_result} - IP: {client_ip}")
237
 
238
  except Exception as e:
239
+ print(f"⚠️ Input NSFW detection failed: {e}")
240
+ # Allow continuation when detection fails
241
 
 
242
  result_url = None
243
  status_message = ""
244
 
 
246
  try:
247
  nonlocal status_message
248
  status_message = message
249
+ # Add error handling to prevent progress update failure
250
  if progress is not None:
251
  progress(0.5, desc=message)
252
  except Exception as e:
253
  print(f"⚠️ Progress update failed: {e}")
254
 
255
  try:
256
+ # Record generation attempt (before actual generation to ensure correct count)
257
+ record_generation_attempt(client_ip, current_phase)
258
+ updated_count = get_ip_generation_count(client_ip)
259
+
260
+ print(f"✅ Processing started - IP: {client_ip}, phase: {current_phase}, total count: {updated_count}, prompt: {prompt.strip()}", flush=True)
261
 
262
  # Call image editing processing function
263
  result_url, message = process_image_edit(input_image, prompt.strip(), progress_callback)
264
 
265
  if result_url:
266
  print(f"✅ Processing completed successfully - IP: {client_ip}, result_url: {result_url}", flush=True)
267
+
268
+ # Detect result image NSFW content (only in rate limit phases)
269
+ if nsfw_detector is not None and current_phase != 'free':
270
+ try:
271
+ if progress is not None:
272
+ progress(0.9, desc="Checking result image...")
273
+
274
+ is_nsfw, nsfw_error = download_and_check_result_nsfw(result_url, nsfw_detector)
275
+
276
+ if nsfw_error:
277
+ print(f"⚠️ Result image NSFW detection error - IP: {client_ip}, error: {nsfw_error}")
278
+ elif is_nsfw:
279
+ is_nsfw_task = True # Mark task as NSFW
280
+ print(f"🔍 Result image NSFW detected in {current_phase} phase: ❌❌❌ - IP: {client_ip} (will blur result)")
281
+ else:
282
+ print(f"🔍 Result image NSFW check passed: ✅✅✅ - IP: {client_ip}")
283
+
284
+ except Exception as e:
285
+ print(f"⚠️ Result image NSFW detection exception - IP: {client_ip}, error: {str(e)}")
286
+
287
+ # Apply blur if this is an NSFW task in rate limit phases
288
+ should_blur = False
289
+
290
+ if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3'] and is_nsfw_task:
291
+ should_blur = True
292
+
293
+ # Apply blur processing
294
+ if should_blur:
295
+ if progress is not None:
296
+ progress(0.95, desc="Applying content filter...")
297
+
298
+ blurred_image = apply_gaussian_blur_to_image_url(result_url)
299
+ if blurred_image is not None:
300
+ final_result = blurred_image # Return PIL Image object
301
+ final_message = f"⚠️ NSFW content detected, content filter applied. NSFW content is prohibited by Hugging Face, but you can generate unlimited content at our official website https://omnicreator.net/#generator"
302
+ print(f"🔒 Applied Gaussian blur for NSFW content - IP: {client_ip}")
303
+ else:
304
+ # Blur failed, return original URL with warning
305
+ final_result = result_url
306
+ final_message = f"⚠️ NSFW content detected, but content filter failed. Please visit https://omnicreator.net/#generator for better experience"
307
+ else:
308
+ final_result = result_url
309
+ final_message = "✅ " + message
310
+
311
  try:
312
  if progress is not None:
313
  progress(1.0, desc="Processing completed")
314
  except Exception as e:
315
  print(f"⚠️ Final progress update failed: {e}")
316
+
317
+ return final_result, final_message
318
  else:
319
  print(f"❌ Processing failed - IP: {client_ip}, error: {message}", flush=True)
320
  return None, "❌ " + message
 
323
  print(f"❌ Processing exception - IP: {client_ip}, error: {str(e)}")
324
  return None, f"❌ Error occurred during processing: {str(e)}"
325
 
 
 
326
  def local_edit_interface(image_dict, prompt, request: gr.Request, progress=gr.Progress()):
327
  """
328
+ Handle local editing requests (with phase-based limitations)
329
  """
330
  try:
331
+ # Extract user IP
332
  client_ip = request.client.host
333
  x_forwarded_for = dict(request.headers).get('x-forwarded-for')
334
  if x_forwarded_for:
 
337
  IP_Dict[client_ip] = 0
338
  IP_Dict[client_ip] += 1
339
 
 
340
  if image_dict is None:
341
  return None, "Please upload an image and draw the area to edit"
342
 
 
360
  print(f"⚠️ Local edit request preprocessing error: {e}")
361
  return None, "❌ Request processing error"
362
 
363
+ # Get user current phase
364
+ current_phase = get_ip_phase(client_ip)
365
+ current_count = get_ip_generation_count(client_ip)
366
+
367
+ print(f"📊 Local edit user phase info - IP: {client_ip}, current phase: {current_phase}, generation count: {current_count}")
368
+
369
+ # Check if completely blocked
370
+ if current_phase == 'blocked':
371
+ return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/#generator for unlimited generation"
372
+
373
+ # Check rate limit (applies to rate_limit phases)
374
+ if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3']:
375
+ is_limited, wait_minutes, window_count = check_rate_limit_for_phase(client_ip, current_phase)
376
+ if is_limited:
377
+ wait_minutes_int = int(wait_minutes) + 1
378
+ return None, f"❌ You have reached Hugging Face's free generation limit. Please visit https://omnicreator.net/#generator for unlimited generation, or wait {wait_minutes_int} minutes before generating again"
379
+
380
+ # Handle NSFW detection based on phase
381
+ is_nsfw_task = False # Track if this task involves NSFW content
382
+
383
+ # Skip NSFW detection in free phase
384
+ if current_phase != 'free' and nsfw_detector is not None and base_image is not None:
385
  try:
386
  nsfw_result = nsfw_detector.predict_pil_label_only(base_image)
387
 
388
  if nsfw_result.lower() == "nsfw":
389
+ is_nsfw_task = True
390
+ print(f"🔍 Local edit input NSFW detected in {current_phase} phase: ❌❌❌ {nsfw_result} - IP: {client_ip} (will blur result)")
 
 
 
 
 
 
 
 
 
 
 
 
391
  else:
392
+ print(f"🔍 Local edit input NSFW check passed: ✅✅✅ {nsfw_result} - IP: {client_ip}")
393
 
394
  except Exception as e:
395
+ print(f"⚠️ Local edit input NSFW detection failed: {e}")
396
+ # Allow continuation when detection fails
 
397
 
398
  result_url = None
399
  status_message = ""
 
402
  try:
403
  nonlocal status_message
404
  status_message = message
405
+ # Add error handling to prevent progress update failure
406
  if progress is not None:
407
  progress(0.5, desc=message)
408
  except Exception as e:
409
  print(f"⚠️ Local edit progress update failed: {e}")
410
 
411
  try:
412
+ # Record generation attempt (before actual generation to ensure correct count)
413
+ record_generation_attempt(client_ip, current_phase)
414
+ updated_count = get_ip_generation_count(client_ip)
415
+
416
+ print(f"✅ Local editing started - IP: {client_ip}, phase: {current_phase}, total count: {updated_count}, prompt: {prompt.strip()}", flush=True)
417
 
418
+ # Call local image editing processing function
419
  result_url, message = process_local_image_edit(base_image, layers, prompt.strip(), progress_callback)
420
 
421
  if result_url:
422
  print(f"✅ Local editing completed successfully - IP: {client_ip}, result_url: {result_url}", flush=True)
423
+
424
+ # Detect result image NSFW content (only in rate limit phases)
425
+ if nsfw_detector is not None and current_phase != 'free':
426
+ try:
427
+ if progress is not None:
428
+ progress(0.9, desc="Checking result image...")
429
+
430
+ is_nsfw, nsfw_error = download_and_check_result_nsfw(result_url, nsfw_detector)
431
+
432
+ if nsfw_error:
433
+ print(f"⚠️ Local edit result image NSFW detection error - IP: {client_ip}, error: {nsfw_error}")
434
+ elif is_nsfw:
435
+ is_nsfw_task = True # Mark task as NSFW
436
+ print(f"🔍 Local edit result image NSFW detected in {current_phase} phase: ❌❌❌ - IP: {client_ip} (will blur result)")
437
+ else:
438
+ print(f"🔍 Local edit result image NSFW check passed: ✅✅✅ - IP: {client_ip}")
439
+
440
+ except Exception as e:
441
+ print(f"⚠️ Local edit result image NSFW detection exception - IP: {client_ip}, error: {str(e)}")
442
+
443
+ # Apply blur if this is an NSFW task in rate limit phases
444
+ should_blur = False
445
+
446
+ if current_phase in ['rate_limit_1', 'rate_limit_2', 'rate_limit_3'] and is_nsfw_task:
447
+ should_blur = True
448
+
449
+ # Apply blur processing
450
+ if should_blur:
451
+ if progress is not None:
452
+ progress(0.95, desc="Applying content filter...")
453
+
454
+ blurred_image = apply_gaussian_blur_to_image_url(result_url)
455
+ if blurred_image is not None:
456
+ final_result = blurred_image # Return PIL Image object
457
+ final_message = f"⚠️ NSFW content detected, content filter applied. NSFW content is prohibited by Hugging Face, but you can generate unlimited content at our official website https://omnicreator.net/#generator"
458
+ print(f"🔒 Local edit applied Gaussian blur for NSFW content - IP: {client_ip}")
459
+ else:
460
+ # Blur failed, return original URL with warning
461
+ final_result = result_url
462
+ final_message = f"⚠️ NSFW content detected, but content filter failed. Please visit https://omnicreator.net/#generator for better experience"
463
+ else:
464
+ final_result = result_url
465
+ final_message = "✅ " + message
466
+
467
  try:
468
  if progress is not None:
469
  progress(1.0, desc="Processing completed")
470
  except Exception as e:
471
  print(f"⚠️ Local edit final progress update failed: {e}")
472
+
473
+ return final_result, final_message
474
  else:
475
  print(f"❌ Local editing processing failed - IP: {client_ip}, error: {message}", flush=True)
476
  return None, "❌ " + message
 
506
  width: 100%;
507
  }
508
  """,
509
+ # Improve concurrency performance configuration
510
  head="""
511
  <script>
512
+ // Reduce client-side state update frequency, avoid excessive SSE connections
513
  if (window.gradio) {
514
+ window.gradio.update_frequency = 2000; // Update every 2 seconds
515
  }
516
  </script>
517
  """
518
  ) as app:
519
 
 
 
 
520
  gr.Markdown(
521
  """
522
  # 🎨 AI Image Editor
 
524
  elem_classes=["main-container"]
525
  )
526
 
527
+ # Powered by line below title
528
+ gr.HTML("""
529
+ <div style="text-align: center; margin: -10px auto 30px auto;">
530
+ <p style="margin: 0; font-size: 16px; color: #999; font-weight: 400;">
531
+ powered by <a href="https://omnicreator.net/#generator" target="_blank" style="color: #667eea; text-decoration: none;">omnicreator.net</a>
532
+ </p>
533
+ </div>
534
+ """, padding=False)
535
+
536
  with gr.Tabs():
537
  # Global editing tab
538
  with gr.Tab("🌍 Global Editing"):
 
568
  elem_classes=["result-area"]
569
  )
570
 
571
+ # Add "Use as Input" button
572
  use_as_input_btn = gr.Button(
573
  "🔄 Use as Input",
574
  variant="secondary",
 
603
  outputs=prompt_input
604
  )
605
 
606
+ # Bind button click events - simplified, remove state management
607
  edit_button.click(
608
  fn=edit_image_interface,
609
  inputs=[input_image, prompt_input],
610
  outputs=[output_image, status_output],
611
  show_progress=True,
612
+ # Increase concurrency settings
613
+ concurrency_limit=10, # Limit concurrent requests
614
  api_name="global_edit"
615
  )
616
 
617
+ # Simplify "Use as Input" button, directly copy image
618
  def simple_use_as_input(output_img):
619
  if output_img is not None:
620
  return output_img
 
635
  label="Upload image and draw mask",
636
  type="pil",
637
  height=512,
638
+ brush=gr.Brush(colors=["#ff0000"], default_size=180),
639
  elem_classes=["upload-area"]
640
  )
641
 
 
661
  elem_classes=["result-area"]
662
  )
663
 
664
+ # Add "Use as Input" button
665
  local_use_as_input_btn = gr.Button(
666
  "🔄 Use as Input",
667
  variant="secondary",
 
696
  outputs=local_prompt_input
697
  )
698
 
699
+ # Bind local edit button click events - simplified, remove state management
700
  local_edit_button.click(
701
  fn=local_edit_interface,
702
  inputs=[local_input_image, local_prompt_input],
703
  outputs=[local_output_image, local_status_output],
704
  show_progress=True,
705
+ # Increase concurrency settings
706
+ concurrency_limit=8, # Local editing is more complex, allow fewer concurrent requests
707
  api_name="local_edit"
708
  )
709
 
710
+ # Simplify local edit "Use as Input" button
711
  def simple_local_use_as_input(output_img):
712
  if output_img is not None:
713
+ # Create simple ImageEditor format
714
  editor_data = {
715
  "background": output_img,
716
  "layers": [],
 
724
  inputs=[local_output_image],
725
  outputs=[local_input_image]
726
  )
727
+
728
+ # SEO Content Section
729
+ gr.HTML("""
730
+ <div style="width: 100%; margin: 50px 0; padding: 0 20px;">
731
+
732
+ <!-- Showcase Section -->
733
+ <div style="text-align: center; background: linear-gradient(135deg, #667eea 0%, #764ba2 100%); color: white; padding: 40px; border-radius: 20px; margin: 40px 0;">
734
+ <h2 style="margin: 0 0 20px 0; font-size: 2.2em; font-weight: 700;">
735
+ 🎨 Unlimited AI Image Generation & Editing
736
+ </h2>
737
+ <p style="margin: 0 0 25px 0; font-size: 1.2em; opacity: 0.95; line-height: 1.6;">
738
+ Experience the ultimate freedom in AI image creation! Generate and edit unlimited images without restrictions,
739
+ including NSFW content, with our premium AI image editing platform.
740
+ </p>
741
+
742
+ <div style="display: flex; justify-content: center; gap: 25px; flex-wrap: wrap; margin: 30px 0;">
743
+ <a href="https://omnicreator.net/#generator" target="_blank" style="
744
+ display: inline-flex;
745
+ align-items: center;
746
+ justify-content: center;
747
+ padding: 20px 40px;
748
+ background: linear-gradient(135deg, #ff6b6b 0%, #feca57 100%);
749
+ color: white;
750
+ text-decoration: none;
751
+ border-radius: 15px;
752
+ font-weight: 700;
753
+ font-size: 18px;
754
+ text-align: center;
755
+ min-width: 250px;
756
+ box-shadow: 0 8px 25px rgba(255, 107, 107, 0.4);
757
+ transition: all 0.3s ease;
758
+ border: none;
759
+ transform: scale(1);
760
+ " onmouseover="this.style.transform='scale(1.05)'" onmouseout="this.style.transform='scale(1)'">
761
+ 🚀 Get Unlimited Access Now
762
+ </a>
763
+
764
+ </div>
765
+
766
+ <p style="color: rgba(255,255,255,0.9); font-size: 1em; margin: 20px 0 0 0;">
767
+ Join thousands of creators who trust Omni Creator for unrestricted AI image generation!
768
+ </p>
769
+ </div>
770
+
771
+ <!-- Hero Description -->
772
+ <div style="text-align: center; margin: 25px auto; background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); padding: 35px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
773
+ <h2 style="color: #2c3e50; margin: 0 0 20px 0; font-size: 1.9em; font-weight: 700;">
774
+ 🌟 Professional AI Image Editor - No Restrictions
775
+ </h2>
776
+ <p style="color: #555; font-size: 1.1em; line-height: 1.6; margin: 0 0 20px 0; padding: 0 20px;">
777
+ Transform your creative vision into reality with our advanced AI image editing platform. Whether you're creating
778
+ art, editing photos, designing content, or working with any type of imagery - our powerful AI removes all limitations
779
+ and gives you complete creative freedom.
780
+ </p>
781
+ </div>
782
+
783
+ <!-- Features Grid -->
784
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 25px; margin: 40px 0;">
785
+
786
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #e74c3c;">
787
+ <h3 style="color: #e74c3c; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
788
+ 🎯 Unlimited Generation
789
+ </h3>
790
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
791
+ Premium users enjoy unlimited image generation without daily limits, rate restrictions, or content barriers.
792
+ Create as many images as you need, whenever you need them.
793
+ </p>
794
+ </div>
795
+
796
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #3498db;">
797
+ <h3 style="color: #3498db; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
798
+ 🔓 No Content Restrictions
799
+ </h3>
800
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
801
+ Generate and edit any type of content without NSFW filters or content limitations. Complete creative
802
+ freedom for artists, designers, and content creators.
803
+ </p>
804
+ </div>
805
+
806
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #27ae60;">
807
+ <h3 style="color: #27ae60; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
808
+ ⚡ Lightning Fast Processing
809
+ </h3>
810
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
811
+ Advanced AI infrastructure delivers high-quality results in seconds. No waiting in queues,
812
+ no processing delays - just instant, professional-grade image editing.
813
+ </p>
814
+ </div>
815
+
816
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #9b59b6;">
817
+ <h3 style="color: #9b59b6; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
818
+ 🎨 Advanced Editing Tools
819
+ </h3>
820
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
821
+ Global transformations, precision local editing, style transfer, object removal, background replacement,
822
+ and dozens of other professional editing capabilities.
823
+ </p>
824
+ </div>
825
+
826
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #f39c12;">
827
+ <h3 style="color: #f39c12; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
828
+ 💎 Premium Quality
829
+ </h3>
830
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
831
+ State-of-the-art AI models trained on millions of images deliver exceptional quality and realism.
832
+ Professional results suitable for commercial use and high-end projects.
833
+ </p>
834
+ </div>
835
+
836
+ <div style="background: white; padding: 30px; border-radius: 15px; box-shadow: 0 5px 20px rgba(0,0,0,0.08); border-left: 5px solid #34495e;">
837
+ <h3 style="color: #34495e; margin: 0 0 15px 0; font-size: 1.4em; font-weight: 600;">
838
+ 🌍 Multi-Modal Support
839
+ </h3>
840
+ <p style="color: #666; margin: 0; line-height: 1.6; font-size: 1em;">
841
+ Support for all image formats, styles, and use cases. From photorealistic portraits to artistic creations,
842
+ product photography to digital art - we handle everything.
843
+ </p>
844
+ </div>
845
+
846
+ </div>
847
+
848
+ <!-- Premium Benefits Section -->
849
+ <div style="background: linear-gradient(135deg, #11998e 0%, #38ef7d 100%); color: white; padding: 40px; border-radius: 20px; margin: 40px 0; text-align: center;">
850
+ <h2 style="margin: 0 0 25px 0; font-size: 1.8em; font-weight: 700;">
851
+ 💎 Why Choose Omni Creator Premium?
852
+ </h2>
853
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(250px, 1fr)); gap: 20px; margin: 30px 0;">
854
+
855
+ <div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
856
+ <h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🚫 No Rate Limits</h4>
857
+ <p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Generate unlimited images without waiting periods or daily restrictions</p>
858
+ </div>
859
+
860
+ <div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
861
+ <h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🎭 Unrestricted Content</h4>
862
+ <p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Create any type of content without NSFW filters or censorship</p>
863
+ </div>
864
+
865
+ <div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
866
+ <h4 style="margin: 0 0 10px 0; font-size: 1.2em;">⚡ Priority Processing</h4>
867
+ <p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Skip queues and get instant results with dedicated processing power</p>
868
+ </div>
869
+
870
+ <div style="background: rgba(255,255,255,0.15); padding: 20px; border-radius: 12px;">
871
+ <h4 style="margin: 0 0 10px 0; font-size: 1.2em;">🎨 Advanced Features</h4>
872
+ <p style="margin: 0; opacity: 0.9; font-size: 0.95em;">Access to latest AI models and cutting-edge editing capabilities</p>
873
+ </div>
874
+
875
+ </div>
876
+ <div style="display: flex; justify-content: center; margin: 25px 0 0 0;">
877
+ <a href="https://omnicreator.net/#generator" target="_blank" style="
878
+ display: inline-flex;
879
+ align-items: center;
880
+ justify-content: center;
881
+ padding: 18px 35px;
882
+ background: rgba(255,255,255,0.9);
883
+ color: #333;
884
+ text-decoration: none;
885
+ border-radius: 15px;
886
+ font-weight: 700;
887
+ font-size: 16px;
888
+ text-align: center;
889
+ min-width: 200px;
890
+ box-shadow: 0 6px 20px rgba(0,0,0,0.3);
891
+ transition: all 0.3s ease;
892
+ border: none;
893
+ ">🌟 Start Creating Now</a>
894
+ </div>
895
+ </div>
896
+
897
+ <!-- Tips Section -->
898
+ <div style="background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 50%, #fecfef 100%); padding: 30px; border-radius: 15px; margin: 40px 0;">
899
+ <h3 style="color: #8b5cf6; text-align: center; margin: 0 0 25px 0; font-size: 1.5em; font-weight: 700;">
900
+ 💡 Pro Tips for Best Results
901
+ </h3>
902
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); gap: 18px;">
903
+
904
+ <div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
905
+ <strong style="color: #8b5cf6; font-size: 1.1em;">📝 Clear Descriptions:</strong>
906
+ <p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use detailed, specific prompts for better results. Describe colors, styles, lighting, and composition clearly.</p>
907
+ </div>
908
+
909
+ <div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
910
+ <strong style="color: #8b5cf6; font-size: 1.1em;">🎯 Local Editing:</strong>
911
+ <p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use precise brush strokes to select areas for local editing. Smaller, focused edits often yield better results.</p>
912
+ </div>
913
+
914
+ <div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
915
+ <strong style="color: #8b5cf6; font-size: 1.1em;">⚡ Iterative Process:</strong>
916
+ <p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Use "Use as Input" feature to refine results. Multiple iterations can achieve complex transformations.</p>
917
+ </div>
918
+
919
+ <div style="background: rgba(255,255,255,0.85); padding: 18px; border-radius: 12px;">
920
+ <strong style="color: #8b5cf6; font-size: 1.1em;">🖼️ Image Quality:</strong>
921
+ <p style="color: #555; margin: 5px 0 0 0; line-height: 1.5;">Higher resolution input images (up to 10MB) generally produce better editing results and finer details.</p>
922
+ </div>
923
+
924
+ </div>
925
+ </div>
926
+
927
+ <!-- Use Cases Section -->
928
+ <div style="text-align: center; margin: 25px auto; background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%); padding: 35px; border-radius: 20px; box-shadow: 0 10px 30px rgba(0,0,0,0.1);">
929
+ <h2 style="color: #2c3e50; margin: 0 0 20px 0; font-size: 1.8em; font-weight: 700;">
930
+ 🚀 Perfect For Every Creative Need
931
+ </h2>
932
+ <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px; margin: 25px 0; text-align: left;">
933
+
934
+ <div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
935
+ <h4 style="color: #e74c3c; margin: 0 0 10px 0;">🎨 Digital Art</h4>
936
+ <ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
937
+ <li>Character design</li>
938
+ <li>Concept art</li>
939
+ <li>Style transfer</li>
940
+ <li>Artistic effects</li>
941
+ </ul>
942
+ </div>
943
+
944
+ <div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
945
+ <h4 style="color: #3498db; margin: 0 0 10px 0;">📸 Photography</h4>
946
+ <ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
947
+ <li>Background replacement</li>
948
+ <li>Object removal</li>
949
+ <li>Lighting adjustment</li>
950
+ <li>Portrait enhancement</li>
951
+ </ul>
952
+ </div>
953
+
954
+ <div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
955
+ <h4 style="color: #27ae60; margin: 0 0 10px 0;">🛍️ E-commerce</h4>
956
+ <ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
957
+ <li>Product photography</li>
958
+ <li>Lifestyle shots</li>
959
+ <li>Color variations</li>
960
+ <li>Context placement</li>
961
+ </ul>
962
+ </div>
963
+
964
+ <div style="background: rgba(255,255,255,0.8); padding: 20px; border-radius: 12px;">
965
+ <h4 style="color: #9b59b6; margin: 0 0 10px 0;">📱 Social Media</h4>
966
+ <ul style="color: #555; margin: 0; padding-left: 18px; line-height: 1.6;">
967
+ <li>Content creation</li>
968
+ <li>Meme generation</li>
969
+ <li>Brand visuals</li>
970
+ <li>Viral content</li>
971
+ </ul>
972
+ </div>
973
+
974
+ </div>
975
+ <div style="text-align: center; margin: 25px 0 0 0;">
976
+ <a href="https://omnicreator.net/#generator" target="_blank" style="
977
+ display: inline-flex;
978
+ align-items: center;
979
+ justify-content: center;
980
+ padding: 18px 35px;
981
+ background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
982
+ color: white;
983
+ text-decoration: none;
984
+ border-radius: 15px;
985
+ font-weight: 700;
986
+ font-size: 16px;
987
+ text-align: center;
988
+ min-width: 220px;
989
+ box-shadow: 0 8px 25px rgba(102, 126, 234, 0.4);
990
+ transition: all 0.3s ease;
991
+ border: none;
992
+ ">🎯 Start Your Project Now</a>
993
+ </div>
994
+ </div>
995
+
996
+ </div>
997
+
998
+ <!-- Powered by footer -->
999
+ <div style="text-align: center; margin: 30px auto 20px auto; padding: 20px;">
1000
+ <p style="margin: 0 0 10px 0; font-size: 18px; color: #333; font-weight: 500;">
1001
+ Powered by <a href="https://omnicreator.net/#generator" target="_blank" style="color: #667eea; text-decoration: none; font-weight: bold;">Omni Creator</a>
1002
+ </p>
1003
+ <p style="margin: 0; font-size: 14px; color: #999; font-weight: 400;">
1004
+ The ultimate AI image generation and editing platform • Unlimited creativity, zero restrictions
1005
+ </p>
1006
+ </div>
1007
+ """, padding=False)
1008
 
1009
  return app
1010
 
1011
  if __name__ == "__main__":
1012
  app = create_app()
1013
+ # Improve queue configuration to handle high concurrency and prevent SSE connection issues
1014
  app.queue(
1015
+ default_concurrency_limit=20, # Default concurrency limit
1016
+ max_size=50, # Maximum queue size
1017
+ api_open=False # Close API access to reduce resource consumption
1018
  )
1019
  app.launch(
1020
  server_name="0.0.0.0",
1021
+ show_error=True, # Show detailed error information
1022
+ quiet=False, # Keep log output
1023
+ max_threads=40, # Increase thread pool size
1024
  height=800,
1025
+ favicon_path=None # Reduce resource loading
1026
  )
util.py CHANGED
@@ -77,8 +77,8 @@ class R2Api:
77
 
78
  def __init__(self, session=None):
79
  super().__init__()
80
- self.R2_BUCKET = "trump-ai-voice"
81
- self.domain = "https://www.trumpaivoice.net/"
82
  self.R2_ACCESS_KEY = R2_ACCESS_KEY
83
  self.R2_SECRET_KEY = R2_SECRET_KEY
84
  self.R2_ENDPOINT = R2_ENDPOINT
@@ -290,7 +290,7 @@ def upload_mask_image_r2(client_ip, time_id, mask_image):
290
 
291
  def submit_image_edit_task(user_image_url, prompt, task_type="80", mask_image_url=""):
292
  """
293
- Submit image editing task with improved error handling
294
  """
295
  headers = {
296
  'Content-Type': 'application/json',
@@ -299,11 +299,12 @@ def submit_image_edit_task(user_image_url, prompt, task_type="80", mask_image_ur
299
 
300
  data = {
301
  "user_image": user_image_url,
302
- "mask_image": mask_image_url,
303
- "task_type": task_type,
304
- "prompt": prompt,
305
- "secret_key": "219ngu",
306
- "is_private": "0"
 
307
  }
308
 
309
  retry_count = 0
@@ -312,7 +313,7 @@ def submit_image_edit_task(user_image_url, prompt, task_type="80", mask_image_ur
312
  while retry_count < max_retries:
313
  try:
314
  response = requests.post(
315
- f'{UKAPIURL}/public_image_edit',
316
  headers=headers,
317
  json=data,
318
  timeout=30 # 增加超时时间
@@ -351,7 +352,7 @@ def submit_image_edit_task(user_image_url, prompt, task_type="80", mask_image_ur
351
 
352
  def check_task_status(task_id):
353
  """
354
- Query task status with improved error handling
355
  """
356
  headers = {
357
  'Content-Type': 'application/json',
@@ -368,7 +369,7 @@ def check_task_status(task_id):
368
  while retry_count < max_retries:
369
  try:
370
  response = requests.post(
371
- f'{UKAPIURL}/status_image_edit',
372
  headers=headers,
373
  json=data,
374
  timeout=15 # 状态查询超时时间短一些
@@ -378,7 +379,7 @@ def check_task_status(task_id):
378
  result = response.json()
379
  if result.get('code') == 0:
380
  task_data = result['data']
381
- return task_data['status'], task_data.get('output1'), task_data
382
  else:
383
  return 'error', None, result.get('message', 'Unknown error')
384
  elif response.status_code in [502, 503, 504]: # 服务器错误,可以重试
@@ -577,6 +578,43 @@ def process_local_image_edit(base_image, layers, prompt, progress_callback=None)
577
  return None, f"error occurred during processing: {str(e)}"
578
 
579
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
580
  if __name__ == "__main__":
581
 
582
  pass
 
77
 
78
  def __init__(self, session=None):
79
  super().__init__()
80
+ self.R2_BUCKET = "omni-creator"
81
+ self.domain = "https://www.omnicreator.net/"
82
  self.R2_ACCESS_KEY = R2_ACCESS_KEY
83
  self.R2_SECRET_KEY = R2_SECRET_KEY
84
  self.R2_ENDPOINT = R2_ENDPOINT
 
290
 
291
  def submit_image_edit_task(user_image_url, prompt, task_type="80", mask_image_url=""):
292
  """
293
+ Submit image editing task with improved error handling using API v2
294
  """
295
  headers = {
296
  'Content-Type': 'application/json',
 
299
 
300
  data = {
301
  "user_image": user_image_url,
302
+ "user_mask": mask_image_url,
303
+ "type": task_type,
304
+ "text": prompt,
305
+ "user_uuid": APIKEY,
306
+ "priority": 0,
307
+ "secret_key": "219ngu"
308
  }
309
 
310
  retry_count = 0
 
313
  while retry_count < max_retries:
314
  try:
315
  response = requests.post(
316
+ f'{UKAPIURL}/public_image_edit_v2',
317
  headers=headers,
318
  json=data,
319
  timeout=30 # 增加超时时间
 
352
 
353
  def check_task_status(task_id):
354
  """
355
+ Query task status with improved error handling using API v2
356
  """
357
  headers = {
358
  'Content-Type': 'application/json',
 
369
  while retry_count < max_retries:
370
  try:
371
  response = requests.post(
372
+ f'{UKAPIURL}/status_image_edit_v2',
373
  headers=headers,
374
  json=data,
375
  timeout=15 # 状态查询超时时间短一些
 
379
  result = response.json()
380
  if result.get('code') == 0:
381
  task_data = result['data']
382
+ return task_data['status'], task_data.get('image_url'), task_data
383
  else:
384
  return 'error', None, result.get('message', 'Unknown error')
385
  elif response.status_code in [502, 503, 504]: # 服务器错误,可以重试
 
578
  return None, f"error occurred during processing: {str(e)}"
579
 
580
 
581
+ def download_and_check_result_nsfw(image_url, nsfw_detector=None):
582
+ """
583
+ 下载结果图片并进行NSFW检测
584
+
585
+ Args:
586
+ image_url (str): 结果图片URL
587
+ nsfw_detector: NSFW检测器实例
588
+
589
+ Returns:
590
+ tuple: (is_nsfw, error_message)
591
+ """
592
+ if nsfw_detector is None:
593
+ return False, None
594
+
595
+ try:
596
+ # 下载图片
597
+ response = requests.get(image_url, timeout=30)
598
+ if response.status_code != 200:
599
+ return False, f"Failed to download result image: HTTP {response.status_code}"
600
+
601
+ # 将图片数据转换为PIL Image
602
+ image_data = io.BytesIO(response.content)
603
+ result_image = Image.open(image_data)
604
+
605
+ # 进行NSFW检测
606
+ nsfw_result = nsfw_detector.predict_pil_label_only(result_image)
607
+
608
+ is_nsfw = nsfw_result.lower() == "nsfw"
609
+ print(f"🔍 结果图片NSFW检测: {'❌❌❌ ' + nsfw_result if is_nsfw else '✅✅✅ ' + nsfw_result}")
610
+
611
+ return is_nsfw, None
612
+
613
+ except Exception as e:
614
+ print(f"⚠️ 结果图片NSFW检测失败: {e}")
615
+ return False, f"Failed to check result image: {str(e)}"
616
+
617
+
618
  if __name__ == "__main__":
619
 
620
  pass