Spaces:
Running
Running
Commit
·
46c5397
1
Parent(s):
c94174a
init
Browse files
app.py
CHANGED
|
@@ -4,7 +4,6 @@ import os
|
|
| 4 |
import shutil
|
| 5 |
import tempfile
|
| 6 |
import time
|
| 7 |
-
from collections import defaultdict, deque
|
| 8 |
from util import process_image_edit, get_country_info_safe, get_location_info_safe, contains_chinese
|
| 9 |
from nfsw import NSFWDetector
|
| 10 |
|
|
@@ -14,11 +13,38 @@ NSFW_LIMIT = 6 # 限制次数:6次
|
|
| 14 |
|
| 15 |
IP_Dict = {}
|
| 16 |
NSFW_Dict = {} # 记录每个IP的NSFW违规次数
|
| 17 |
-
NSFW_Time_Dict =
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 18 |
|
| 19 |
def check_nsfw_rate_limit(client_ip):
|
| 20 |
"""
|
| 21 |
-
检查IP的NSFW
|
| 22 |
|
| 23 |
Args:
|
| 24 |
client_ip (str): 客户端IP地址
|
|
@@ -27,36 +53,81 @@ def check_nsfw_rate_limit(client_ip):
|
|
| 27 |
tuple: (是否超过限制, 剩余等待时间)
|
| 28 |
"""
|
| 29 |
current_time = time.time()
|
| 30 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 31 |
|
| 32 |
-
#
|
| 33 |
-
|
| 34 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 35 |
|
| 36 |
-
|
| 37 |
-
|
| 38 |
-
|
| 39 |
-
|
| 40 |
-
|
|
|
|
|
|
|
| 41 |
return True, max(0, wait_time)
|
| 42 |
|
| 43 |
return False, 0
|
| 44 |
|
| 45 |
def record_nsfw_detection(client_ip):
|
| 46 |
"""
|
| 47 |
-
记录IP的NSFW
|
| 48 |
|
| 49 |
Args:
|
| 50 |
client_ip (str): 客户端IP地址
|
| 51 |
"""
|
| 52 |
-
|
| 53 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 54 |
|
| 55 |
# 记录到NSFW_Dict中(兼容现有逻辑)
|
| 56 |
if client_ip not in NSFW_Dict:
|
| 57 |
NSFW_Dict[client_ip] = 0
|
| 58 |
NSFW_Dict[client_ip] += 1
|
| 59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 60 |
# 初始化NSFW检测器(从Hugging Face���载)
|
| 61 |
try:
|
| 62 |
nsfw_detector = NSFWDetector() # 自动从Hugging Face下载falconsai_yolov9_nsfw_model_quantized.pt
|
|
@@ -105,7 +176,7 @@ def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.P
|
|
| 105 |
# warning_msg = f"您的ip地址为{client_ip},地点为{prov}-{city},您的网络服务商为{isp_name},检测到您目前正在浏览,制作淫秽内容,已经上报给 {city_name}市公安局,已加急处理,请耐心等待警察上门调查"
|
| 106 |
# return None, f"❌ {warning_msg}"
|
| 107 |
# else:
|
| 108 |
-
# return None, f"❌ Your ip {client_ip}
|
| 109 |
|
| 110 |
if input_image is None:
|
| 111 |
return None, "Please upload an image first"
|
|
@@ -130,40 +201,21 @@ def edit_image_interface(input_image, prompt, request: gr.Request, progress=gr.P
|
|
| 130 |
is_rate_limited, wait_time = check_nsfw_rate_limit(client_ip)
|
| 131 |
|
| 132 |
if is_rate_limited:
|
| 133 |
-
#
|
| 134 |
wait_minutes = int(wait_time / 60) + 1 # 向上取整到分钟
|
| 135 |
-
|
| 136 |
-
|
| 137 |
-
|
| 138 |
-
|
| 139 |
-
|
| 140 |
-
|
| 141 |
-
|
| 142 |
-
|
| 143 |
-
|
| 144 |
-
|
| 145 |
-
|
| 146 |
-
|
| 147 |
-
|
| 148 |
-
# isp = location_info.get("isp", "Unknown")
|
| 149 |
-
|
| 150 |
-
# # 处理城市名称
|
| 151 |
-
# city_name = city.replace("市", "") if city != "未知城市" else "当地"
|
| 152 |
-
|
| 153 |
-
# # 处理ISP名称,去掉"中国"前缀
|
| 154 |
-
# isp_name = isp.replace("中国", "") if isp != "Unknown" else "未知"
|
| 155 |
-
|
| 156 |
-
# warning_msg = f"您的ip地址为{client_ip},地点为{prov}-{city},您的网络服务商为{isp_name},检测到您目前正在浏览,制作淫秽内容,已经上报给 {city_name}市公安局,已加急处理,请耐心等待警察上门调查"
|
| 157 |
-
|
| 158 |
-
# print(f"⚠️ 特殊NSFW警告 - IP: {client_ip}, 位置: {prov}-{city}, ISP: {isp_name}, 中文Prompt: {has_chinese}, 中国IP: {is_china_ip}")
|
| 159 |
-
# print(warning_msg)
|
| 160 |
-
|
| 161 |
-
# return None, f"❌ {warning_msg}"
|
| 162 |
-
# else:
|
| 163 |
-
# # 常规NSFW提示
|
| 164 |
-
# print(f"❌ NSFW image detected - IP: {client_ip}({country_info}), violations: {NSFW_Dict[client_ip]}")
|
| 165 |
-
# return None, f"❌ Your ip {client_ip},your region has been blocked for too much nsfw content"
|
| 166 |
-
|
| 167 |
|
| 168 |
except Exception as e:
|
| 169 |
print(f"⚠️ NSFW检测失败: {e}")
|
|
|
|
| 4 |
import shutil
|
| 5 |
import tempfile
|
| 6 |
import time
|
|
|
|
| 7 |
from util import process_image_edit, get_country_info_safe, get_location_info_safe, contains_chinese
|
| 8 |
from nfsw import NSFWDetector
|
| 9 |
|
|
|
|
| 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地址
|
|
|
|
| 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
|
|
|
|
| 176 |
# warning_msg = f"您的ip地址为{client_ip},地点为{prov}-{city},您的网络服务商为{isp_name},检测到您目前正在浏览,制作淫秽内容,已经上报给 {city_name}市公安局,已加急处理,请耐心等待警察上门调查"
|
| 177 |
# return None, f"❌ {warning_msg}"
|
| 178 |
# else:
|
| 179 |
+
# return None, f"❌ Your ip {client_ip}, your region has been blocked for too much nsfw content"
|
| 180 |
|
| 181 |
if input_image is None:
|
| 182 |
return None, "Please upload an image first"
|
|
|
|
| 201 |
is_rate_limited, wait_time = check_nsfw_rate_limit(client_ip)
|
| 202 |
|
| 203 |
if is_rate_limited:
|
| 204 |
+
# 超过频率限制,显示等待提示并阻止继续
|
| 205 |
wait_minutes = int(wait_time / 60) + 1 # 向上取整到分钟
|
| 206 |
+
window_info = get_current_window_info(client_ip)
|
| 207 |
+
print(f"⚠️ NSFW频率限制 - IP: {client_ip}({country_info})")
|
| 208 |
+
print(f" 时间窗口: {window_info['window_start']} - {window_info['window_end']}")
|
| 209 |
+
print(f" 当前计数: {window_info['current_count']}/{NSFW_LIMIT}, 需要等待 {wait_minutes} 分钟")
|
| 210 |
+
return None, f"❌ Please wait {wait_minutes} minutes before generating again"
|
| 211 |
+
else:
|
| 212 |
+
# 未超过频率限制,记录此次检测但允许继续处理
|
| 213 |
+
record_nsfw_detection(client_ip)
|
| 214 |
+
window_info = get_current_window_info(client_ip)
|
| 215 |
+
# print(f"🔍 NSFW检测记录 - IP: {client_ip}({country_info})")
|
| 216 |
+
# print(f" 时间窗口: {window_info['window_start']} - {window_info['window_end']}")
|
| 217 |
+
# print(f" 当前计数: {window_info['current_count']}/{NSFW_LIMIT}, 允许继续处理")
|
| 218 |
+
# 不return,允许继续处理图片编辑
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 219 |
|
| 220 |
except Exception as e:
|
| 221 |
print(f"⚠️ NSFW检测失败: {e}")
|
util.py
CHANGED
|
@@ -265,11 +265,11 @@ def submit_image_edit_task(user_image_url, prompt):
|
|
| 265 |
if result.get('code') == 0:
|
| 266 |
return result['data']['task_id'], None
|
| 267 |
else:
|
| 268 |
-
return None, f"API
|
| 269 |
else:
|
| 270 |
-
return None, f"HTTP
|
| 271 |
except Exception as e:
|
| 272 |
-
return None, f"
|
| 273 |
|
| 274 |
|
| 275 |
def check_task_status(task_id):
|
|
@@ -298,11 +298,11 @@ def check_task_status(task_id):
|
|
| 298 |
task_data = result['data']
|
| 299 |
return task_data['status'], task_data.get('output1'), task_data
|
| 300 |
else:
|
| 301 |
-
return 'error', None, result.get('message', '
|
| 302 |
else:
|
| 303 |
-
return 'error', None, f"HTTP
|
| 304 |
except Exception as e:
|
| 305 |
-
return 'error', None, f"
|
| 306 |
|
| 307 |
|
| 308 |
def process_image_edit(img_input, prompt, progress_callback=None):
|
|
@@ -369,7 +369,7 @@ def process_image_edit(img_input, prompt, progress_callback=None):
|
|
| 369 |
if output_url:
|
| 370 |
return output_url, "image edit completed"
|
| 371 |
else:
|
| 372 |
-
return None, "
|
| 373 |
elif status == 'error' or status == 'failed':
|
| 374 |
return None, f"task processing failed: {task_data}"
|
| 375 |
elif status in ['queued', 'processing', 'running', 'created', 'working']:
|
|
|
|
| 265 |
if result.get('code') == 0:
|
| 266 |
return result['data']['task_id'], None
|
| 267 |
else:
|
| 268 |
+
return None, f"API Error: {result.get('message', 'Unknown error')}"
|
| 269 |
else:
|
| 270 |
+
return None, f"HTTP Error: {response.status_code}"
|
| 271 |
except Exception as e:
|
| 272 |
+
return None, f"Request Exception: {str(e)}"
|
| 273 |
|
| 274 |
|
| 275 |
def check_task_status(task_id):
|
|
|
|
| 298 |
task_data = result['data']
|
| 299 |
return task_data['status'], task_data.get('output1'), task_data
|
| 300 |
else:
|
| 301 |
+
return 'error', None, result.get('message', 'Unknown error')
|
| 302 |
else:
|
| 303 |
+
return 'error', None, f"HTTP Error: {response.status_code}"
|
| 304 |
except Exception as e:
|
| 305 |
+
return 'error', None, f"Request Exception: {str(e)}"
|
| 306 |
|
| 307 |
|
| 308 |
def process_image_edit(img_input, prompt, progress_callback=None):
|
|
|
|
| 369 |
if output_url:
|
| 370 |
return output_url, "image edit completed"
|
| 371 |
else:
|
| 372 |
+
return None, "Task completed but no result image returned"
|
| 373 |
elif status == 'error' or status == 'failed':
|
| 374 |
return None, f"task processing failed: {task_data}"
|
| 375 |
elif status in ['queued', 'processing', 'running', 'created', 'working']:
|