Spaces:
Sleeping
Sleeping
lijunke commited on
Commit ·
da3203c
1
Parent(s): 18081cf
Fix GPTMail code polling defaults and HF timeout stability
Browse files- .env.example +5 -1
- core/config.py +1 -1
- core/gemini_automation.py +16 -5
- core/gptmail_client.py +42 -13
.env.example
CHANGED
|
@@ -27,10 +27,14 @@ ADMIN_KEY=your-admin-secret-key
|
|
| 27 |
# 配置保存在 data/settings.yaml
|
| 28 |
# ============================================
|
| 29 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 30 |
# ============================================
|
| 31 |
# 账户配置
|
| 32 |
# ============================================
|
| 33 |
# 使用 accounts.json 文件
|
| 34 |
# 账户配置保存在 accounts.json 文件中
|
| 35 |
# 首次启动时会自动创建空配置
|
| 36 |
-
# 请在管理面板中添加账户,或直接编辑 accounts.json
|
|
|
|
| 27 |
# 配置保存在 data/settings.yaml
|
| 28 |
# ============================================
|
| 29 |
|
| 30 |
+
# 注册验证码轮询参数(可选,适合云环境/HuggingFace)
|
| 31 |
+
# REGISTER_CODE_TIMEOUT_SECONDS=60
|
| 32 |
+
# REGISTER_CODE_INTERVAL_SECONDS=5
|
| 33 |
+
|
| 34 |
# ============================================
|
| 35 |
# 账户配置
|
| 36 |
# ============================================
|
| 37 |
# 使用 accounts.json 文件
|
| 38 |
# 账户配置保存在 accounts.json 文件中
|
| 39 |
# 首次启动时会自动创建空配置
|
| 40 |
+
# 请在管理面板中添加账户,或直接编辑 accounts.json
|
core/config.py
CHANGED
|
@@ -231,7 +231,7 @@ class ConfigManager:
|
|
| 231 |
freemail_domain=str(basic_data.get("freemail_domain") or "").strip(),
|
| 232 |
mail_proxy_enabled=_parse_bool(basic_data.get("mail_proxy_enabled"), False),
|
| 233 |
gptmail_base_url=str(basic_data.get("gptmail_base_url") or "https://mail.chatgpt.org.uk").strip(),
|
| 234 |
-
gptmail_api_key=str(basic_data.get("gptmail_api_key") or "").strip(),
|
| 235 |
gptmail_verify_ssl=_parse_bool(basic_data.get("gptmail_verify_ssl"), True),
|
| 236 |
gptmail_domain=str(basic_data.get("gptmail_domain") or "").strip(),
|
| 237 |
cfmail_base_url=str(basic_data.get("cfmail_base_url") or "").strip(),
|
|
|
|
| 231 |
freemail_domain=str(basic_data.get("freemail_domain") or "").strip(),
|
| 232 |
mail_proxy_enabled=_parse_bool(basic_data.get("mail_proxy_enabled"), False),
|
| 233 |
gptmail_base_url=str(basic_data.get("gptmail_base_url") or "https://mail.chatgpt.org.uk").strip(),
|
| 234 |
+
gptmail_api_key=str(basic_data.get("gptmail_api_key") or "gpt-test").strip(),
|
| 235 |
gptmail_verify_ssl=_parse_bool(basic_data.get("gptmail_verify_ssl"), True),
|
| 236 |
gptmail_domain=str(basic_data.get("gptmail_domain") or "").strip(),
|
| 237 |
cfmail_base_url=str(basic_data.get("cfmail_base_url") or "").strip(),
|
core/gemini_automation.py
CHANGED
|
@@ -293,17 +293,28 @@ class GeminiAutomation:
|
|
| 293 |
self._save_screenshot(page, "code_input_missing")
|
| 294 |
return {"success": False, "error": "code input not found"}
|
| 295 |
|
| 296 |
-
# Step 5: 轮询邮件获取验证码(
|
| 297 |
-
|
| 298 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 299 |
|
| 300 |
if not code:
|
| 301 |
self._log("warning", "⚠️ 验证码超时,等待后重新发送...")
|
| 302 |
time.sleep(random.uniform(12, 18))
|
| 303 |
# 尝试点击重新发送按钮
|
| 304 |
if self._click_resend_code_button(page):
|
| 305 |
-
# 再次轮询验证码
|
| 306 |
-
code = mail_client.poll_for_code(timeout=
|
| 307 |
if not code:
|
| 308 |
self._log("error", "❌ 重新发送后仍未收到验证码")
|
| 309 |
self._save_screenshot(page, "code_timeout_after_resend")
|
|
|
|
| 293 |
self._save_screenshot(page, "code_input_missing")
|
| 294 |
return {"success": False, "error": "code input not found"}
|
| 295 |
|
| 296 |
+
# Step 5: 轮询邮件获取验证码(云环境默认延长,支持环境变量覆盖)
|
| 297 |
+
try:
|
| 298 |
+
code_timeout = int(str(os.getenv("REGISTER_CODE_TIMEOUT_SECONDS", "60")).strip() or "60")
|
| 299 |
+
except Exception:
|
| 300 |
+
code_timeout = 60
|
| 301 |
+
try:
|
| 302 |
+
code_interval = int(str(os.getenv("REGISTER_CODE_INTERVAL_SECONDS", "5")).strip() or "5")
|
| 303 |
+
except Exception:
|
| 304 |
+
code_interval = 5
|
| 305 |
+
code_timeout = max(15, code_timeout)
|
| 306 |
+
code_interval = max(2, code_interval)
|
| 307 |
+
|
| 308 |
+
self._log("info", f"📬 等待邮箱验证码... (timeout={code_timeout}s, interval={code_interval}s)")
|
| 309 |
+
code = mail_client.poll_for_code(timeout=code_timeout, interval=code_interval, since_time=task_start_time)
|
| 310 |
|
| 311 |
if not code:
|
| 312 |
self._log("warning", "⚠️ 验证码超时,等待后重新发送...")
|
| 313 |
time.sleep(random.uniform(12, 18))
|
| 314 |
# 尝试点击重新发送按钮
|
| 315 |
if self._click_resend_code_button(page):
|
| 316 |
+
# 再次轮询验证码
|
| 317 |
+
code = mail_client.poll_for_code(timeout=code_timeout, interval=code_interval, since_time=task_start_time)
|
| 318 |
if not code:
|
| 319 |
self._log("error", "❌ 重新发送后仍未收到验证码")
|
| 320 |
self._save_screenshot(page, "code_timeout_after_resend")
|
core/gptmail_client.py
CHANGED
|
@@ -74,6 +74,22 @@ class GPTMailClient:
|
|
| 74 |
pass
|
| 75 |
return res
|
| 76 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 77 |
def generate_email(self, domain: Optional[str] = None) -> Optional[str]:
|
| 78 |
"""生成一个新的邮箱地址。"""
|
| 79 |
if not self.base_url:
|
|
@@ -151,7 +167,11 @@ class GPTMailClient:
|
|
| 151 |
self._log("info", "📭 邮箱为空,暂无邮件")
|
| 152 |
return None
|
| 153 |
|
| 154 |
-
emails = sorted(
|
|
|
|
|
|
|
|
|
|
|
|
|
| 155 |
self._log("info", f"📨 收到 {len(emails)} 封邮件,开始检查验证码...")
|
| 156 |
|
| 157 |
for msg in emails:
|
|
@@ -161,12 +181,14 @@ class GPTMailClient:
|
|
| 161 |
|
| 162 |
ts = msg.get("timestamp")
|
| 163 |
if since_time and ts:
|
| 164 |
-
|
| 165 |
-
|
| 166 |
-
|
| 167 |
-
|
| 168 |
-
|
| 169 |
-
|
|
|
|
|
|
|
| 170 |
|
| 171 |
content = (msg.get("content") or "") + (msg.get("html_content") or "")
|
| 172 |
code = extract_verification_code(content)
|
|
@@ -203,17 +225,24 @@ class GPTMailClient:
|
|
| 203 |
if not self.email:
|
| 204 |
return None
|
| 205 |
|
| 206 |
-
|
|
|
|
|
|
|
| 207 |
self._log("info", f"⏱️ 开始轮询验证码 (超时 {timeout}秒, 间隔 {interval}秒, 最多 {max_retries} 次)")
|
| 208 |
|
| 209 |
-
|
| 210 |
-
|
|
|
|
|
|
|
|
|
|
| 211 |
code = self.fetch_verification_code(since_time=since_time)
|
| 212 |
if code:
|
| 213 |
self._log("info", f"🎉 验证码获取成功: {code}")
|
| 214 |
return code
|
| 215 |
-
|
| 216 |
-
|
|
|
|
|
|
|
| 217 |
|
| 218 |
-
self._log("error", "❌ 验证码获取超时")
|
| 219 |
return None
|
|
|
|
| 74 |
pass
|
| 75 |
return res
|
| 76 |
|
| 77 |
+
@staticmethod
|
| 78 |
+
def _normalize_unix_ts(value: Any) -> Optional[float]:
|
| 79 |
+
"""兼容秒/毫秒时间戳,统一转换为秒。"""
|
| 80 |
+
if value in (None, ""):
|
| 81 |
+
return None
|
| 82 |
+
try:
|
| 83 |
+
ts = float(str(value).strip())
|
| 84 |
+
except Exception:
|
| 85 |
+
return None
|
| 86 |
+
# 毫秒时间戳降级为秒
|
| 87 |
+
if ts > 1e12:
|
| 88 |
+
ts /= 1000.0
|
| 89 |
+
if ts <= 0:
|
| 90 |
+
return None
|
| 91 |
+
return ts
|
| 92 |
+
|
| 93 |
def generate_email(self, domain: Optional[str] = None) -> Optional[str]:
|
| 94 |
"""生成一个新的邮箱地址。"""
|
| 95 |
if not self.base_url:
|
|
|
|
| 167 |
self._log("info", "📭 邮箱为空,暂无邮件")
|
| 168 |
return None
|
| 169 |
|
| 170 |
+
emails = sorted(
|
| 171 |
+
emails,
|
| 172 |
+
key=lambda item: self._normalize_unix_ts(item.get("timestamp")) or 0,
|
| 173 |
+
reverse=True,
|
| 174 |
+
)
|
| 175 |
self._log("info", f"📨 收到 {len(emails)} 封邮件,开始检查验证码...")
|
| 176 |
|
| 177 |
for msg in emails:
|
|
|
|
| 181 |
|
| 182 |
ts = msg.get("timestamp")
|
| 183 |
if since_time and ts:
|
| 184 |
+
ts_value = self._normalize_unix_ts(ts)
|
| 185 |
+
if ts_value:
|
| 186 |
+
try:
|
| 187 |
+
msg_time = datetime.fromtimestamp(ts_value)
|
| 188 |
+
if msg_time < since_time:
|
| 189 |
+
continue
|
| 190 |
+
except Exception:
|
| 191 |
+
pass
|
| 192 |
|
| 193 |
content = (msg.get("content") or "") + (msg.get("html_content") or "")
|
| 194 |
code = extract_verification_code(content)
|
|
|
|
| 225 |
if not self.email:
|
| 226 |
return None
|
| 227 |
|
| 228 |
+
timeout = max(1, int(timeout))
|
| 229 |
+
interval = max(1, int(interval))
|
| 230 |
+
max_retries = max(1, timeout // interval + 1)
|
| 231 |
self._log("info", f"⏱️ 开始轮询验证码 (超时 {timeout}秒, 间隔 {interval}秒, 最多 {max_retries} 次)")
|
| 232 |
|
| 233 |
+
deadline = time.monotonic() + timeout
|
| 234 |
+
attempt = 0
|
| 235 |
+
while True:
|
| 236 |
+
attempt += 1
|
| 237 |
+
self._log("info", f"🔄 第 {attempt}/{max_retries} 次轮询...")
|
| 238 |
code = self.fetch_verification_code(since_time=since_time)
|
| 239 |
if code:
|
| 240 |
self._log("info", f"🎉 验证码获取成功: {code}")
|
| 241 |
return code
|
| 242 |
+
now = time.monotonic()
|
| 243 |
+
if now >= deadline:
|
| 244 |
+
break
|
| 245 |
+
time.sleep(min(interval, max(0.0, deadline - now)))
|
| 246 |
|
| 247 |
+
self._log("error", f"❌ 验证码获取超时 ({timeout}秒)")
|
| 248 |
return None
|