update
This commit is contained in:
1523
auto_gpt_team.py
Normal file
1523
auto_gpt_team.py
Normal file
File diff suppressed because it is too large
Load Diff
@@ -220,3 +220,17 @@ notify_on_error = true
|
|||||||
check_interval = 3600
|
check_interval = 3600
|
||||||
# 低库存预警阈值 (正常账号数低于此值时预警)
|
# 低库存预警阈值 (正常账号数低于此值时预警)
|
||||||
low_stock_threshold = 10
|
low_stock_threshold = 10
|
||||||
|
|
||||||
|
# ==================== AutoGPTPlus 配置 ====================
|
||||||
|
# 独立的 ChatGPT 订阅自动化脚本配置
|
||||||
|
[autogptplus]
|
||||||
|
# Cloud Mail API Token
|
||||||
|
mail_api_token = "your-cloud-mail-token"
|
||||||
|
# Cloud Mail API 地址
|
||||||
|
mail_api_base = "https://your-cloud-mail.com"
|
||||||
|
# 可用邮箱域名列表
|
||||||
|
email_domains = ["@example.com", "@example.org"]
|
||||||
|
# SEPA IBAN 列表 (也可通过 Bot /iban_add 命令导入到 sepa_ibans.txt)
|
||||||
|
sepa_ibans = []
|
||||||
|
# 是否启用随机指纹 (User-Agent, WebGL, 分辨率等)
|
||||||
|
random_fingerprint = true
|
||||||
|
|||||||
702
telegram_bot.py
702
telegram_bot.py
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import sys
|
import sys
|
||||||
|
import time
|
||||||
from concurrent.futures import ThreadPoolExecutor
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from functools import wraps
|
from functools import wraps
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
@@ -130,6 +131,15 @@ class ProvisionerBot:
|
|||||||
("gptmail_keys", self.cmd_gptmail_keys),
|
("gptmail_keys", self.cmd_gptmail_keys),
|
||||||
("gptmail_add", self.cmd_gptmail_add),
|
("gptmail_add", self.cmd_gptmail_add),
|
||||||
("gptmail_del", self.cmd_gptmail_del),
|
("gptmail_del", self.cmd_gptmail_del),
|
||||||
|
("iban_list", self.cmd_iban_list),
|
||||||
|
("iban_add", self.cmd_iban_add),
|
||||||
|
("iban_clear", self.cmd_iban_clear),
|
||||||
|
("domain_list", self.cmd_domain_list),
|
||||||
|
("domain_add", self.cmd_domain_add),
|
||||||
|
("domain_del", self.cmd_domain_del),
|
||||||
|
("domain_clear", self.cmd_domain_clear),
|
||||||
|
("team_fingerprint", self.cmd_team_fingerprint),
|
||||||
|
("team_register", self.cmd_team_register),
|
||||||
("test_email", self.cmd_test_email),
|
("test_email", self.cmd_test_email),
|
||||||
("include_owners", self.cmd_include_owners),
|
("include_owners", self.cmd_include_owners),
|
||||||
("reload", self.cmd_reload),
|
("reload", self.cmd_reload),
|
||||||
@@ -161,6 +171,16 @@ class ProvisionerBot:
|
|||||||
self.callback_clean_teams,
|
self.callback_clean_teams,
|
||||||
pattern="^clean_teams:"
|
pattern="^clean_teams:"
|
||||||
))
|
))
|
||||||
|
self.app.add_handler(CallbackQueryHandler(
|
||||||
|
self.callback_team_register,
|
||||||
|
pattern="^team_reg:"
|
||||||
|
))
|
||||||
|
|
||||||
|
# 注册自定义数量输入处理器 (GPT Team 注册)
|
||||||
|
self.app.add_handler(MessageHandler(
|
||||||
|
filters.TEXT & ~filters.COMMAND,
|
||||||
|
self.handle_team_custom_count
|
||||||
|
))
|
||||||
|
|
||||||
# 注册定时检查任务
|
# 注册定时检查任务
|
||||||
if TELEGRAM_CHECK_INTERVAL > 0 and AUTH_PROVIDER == "s2a":
|
if TELEGRAM_CHECK_INTERVAL > 0 and AUTH_PROVIDER == "s2a":
|
||||||
@@ -285,10 +305,27 @@ class ProvisionerBot:
|
|||||||
/gptmail_del <key> - 删除 API Key
|
/gptmail_del <key> - 删除 API Key
|
||||||
/test_email - 测试邮箱创建
|
/test_email - 测试邮箱创建
|
||||||
|
|
||||||
|
<b>💳 IBAN 管理 (GPT Team):</b>
|
||||||
|
/iban_list - 查看 IBAN 列表
|
||||||
|
/iban_add <ibans> - 添加 IBAN (每行一个或逗号分隔)
|
||||||
|
/iban_clear - 清空 IBAN 列表
|
||||||
|
|
||||||
|
<b>📧 域名管理 (GPT Team):</b>
|
||||||
|
/domain_list - 查看邮箱域名列表
|
||||||
|
/domain_add <domains> - 添加域名 (每行一个或逗号分隔)
|
||||||
|
/domain_del <domain> - 删除指定域名
|
||||||
|
/domain_clear - 清空域名列表
|
||||||
|
|
||||||
|
<b>🤖 GPT Team:</b>
|
||||||
|
/team_fingerprint - 开启/关闭随机指纹
|
||||||
|
/team_register - 开始自动订阅注册
|
||||||
|
|
||||||
<b>💡 示例:</b>
|
<b>💡 示例:</b>
|
||||||
<code>/list</code> - 查看所有待处理账号
|
<code>/list</code> - 查看所有待处理账号
|
||||||
<code>/run 0</code> - 处理第一个 Team
|
<code>/run 0</code> - 处理第一个 Team
|
||||||
<code>/gptmail_add my-api-key</code> - 添加 Key"""
|
<code>/gptmail_add my-api-key</code> - 添加 Key
|
||||||
|
<code>/iban_add DE123...,DE456...</code> - 添加 IBAN
|
||||||
|
<code>/domain_add @example.com</code> - 添加域名"""
|
||||||
await update.message.reply_text(help_text, parse_mode="HTML")
|
await update.message.reply_text(help_text, parse_mode="HTML")
|
||||||
|
|
||||||
@admin_only
|
@admin_only
|
||||||
@@ -2338,6 +2375,669 @@ class ProvisionerBot:
|
|||||||
except Exception as e:
|
except Exception as e:
|
||||||
await update.message.reply_text(f"❌ 测试失败: {e}")
|
await update.message.reply_text(f"❌ 测试失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_iban_list(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""查看 IBAN 列表"""
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import get_sepa_ibans
|
||||||
|
ibans = get_sepa_ibans()
|
||||||
|
|
||||||
|
if not ibans:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>💳 SEPA IBAN 列表</b>\n\n"
|
||||||
|
"📭 暂无 IBAN\n\n"
|
||||||
|
"使用 /iban_add 添加 IBAN",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 显示 IBAN 列表
|
||||||
|
lines = [f"<b>💳 SEPA IBAN 列表 ({len(ibans)} 个)</b>\n"]
|
||||||
|
for i, iban in enumerate(ibans[:50], 1): # 最多显示 50 个
|
||||||
|
lines.append(f"{i}. <code>{iban}</code>")
|
||||||
|
|
||||||
|
if len(ibans) > 50:
|
||||||
|
lines.append(f"\n... 还有 {len(ibans) - 50} 个未显示")
|
||||||
|
|
||||||
|
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 获取 IBAN 列表失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_iban_add(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""添加 IBAN"""
|
||||||
|
if not context.args:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>💳 添加 IBAN</b>\n\n"
|
||||||
|
"用法:\n"
|
||||||
|
"<code>/iban_add DE123... DE456...</code>\n"
|
||||||
|
"<code>/iban_add DE123...,DE456...</code>\n\n"
|
||||||
|
"支持空格或逗号分隔,每行一个也可以",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import add_sepa_ibans
|
||||||
|
|
||||||
|
# 解析输入 (支持空格、逗号、换行分隔)
|
||||||
|
raw_input = " ".join(context.args)
|
||||||
|
# 替换逗号和换行为空格,然后按空格分割
|
||||||
|
ibans = [s.strip() for s in raw_input.replace(",", " ").replace("\n", " ").split() if s.strip()]
|
||||||
|
|
||||||
|
if not ibans:
|
||||||
|
await update.message.reply_text("❌ 未提供有效的 IBAN")
|
||||||
|
return
|
||||||
|
|
||||||
|
added, skipped, total = add_sepa_ibans(ibans)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>✅ IBAN 导入完成</b>\n\n"
|
||||||
|
f"新增: {added}\n"
|
||||||
|
f"跳过 (重复): {skipped}\n"
|
||||||
|
f"当前总数: {total}",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 添加 IBAN 失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_iban_clear(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""清空 IBAN 列表"""
|
||||||
|
# 需要确认
|
||||||
|
if not context.args or context.args[0].lower() != "confirm":
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import get_sepa_ibans
|
||||||
|
count = len(get_sepa_ibans())
|
||||||
|
except:
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>⚠️ 确认清空 IBAN 列表?</b>\n\n"
|
||||||
|
f"当前共有 {count} 个 IBAN\n\n"
|
||||||
|
f"确认请发送:\n"
|
||||||
|
f"<code>/iban_clear confirm</code>",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import clear_sepa_ibans
|
||||||
|
clear_sepa_ibans()
|
||||||
|
await update.message.reply_text("<b>✅ IBAN 列表已清空</b>", parse_mode="HTML")
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 清空 IBAN 失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_domain_list(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""查看邮箱域名列表"""
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import get_email_domains
|
||||||
|
domains = get_email_domains()
|
||||||
|
|
||||||
|
if not domains:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>📧 邮箱域名列表</b>\n\n"
|
||||||
|
"📭 暂无域名\n\n"
|
||||||
|
"使用 /domain_add 添加域名",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 显示域名列表
|
||||||
|
lines = [f"<b>📧 邮箱域名列表 ({len(domains)} 个)</b>\n"]
|
||||||
|
for i, domain in enumerate(domains[:50], 1): # 最多显示 50 个
|
||||||
|
lines.append(f"{i}. <code>{domain}</code>")
|
||||||
|
|
||||||
|
if len(domains) > 50:
|
||||||
|
lines.append(f"\n... 还有 {len(domains) - 50} 个未显示")
|
||||||
|
|
||||||
|
await update.message.reply_text("\n".join(lines), parse_mode="HTML")
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 获取域名列表失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_domain_add(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""添加邮箱域名"""
|
||||||
|
if not context.args:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>📧 添加邮箱域名</b>\n\n"
|
||||||
|
"用法:\n"
|
||||||
|
"<code>/domain_add @example.com</code>\n"
|
||||||
|
"<code>/domain_add @a.com,@b.com</code>\n\n"
|
||||||
|
"支持空格或逗号分隔\n"
|
||||||
|
"@ 符号可省略,会自动添加",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import add_email_domains
|
||||||
|
|
||||||
|
# 解析输入 (支持空格、逗号、换行分隔)
|
||||||
|
raw_input = " ".join(context.args)
|
||||||
|
# 替换逗号和换行为空格,然后按空格分割
|
||||||
|
domains = [s.strip() for s in raw_input.replace(",", " ").replace("\n", " ").split() if s.strip()]
|
||||||
|
|
||||||
|
if not domains:
|
||||||
|
await update.message.reply_text("❌ 未提供有效的域名")
|
||||||
|
return
|
||||||
|
|
||||||
|
added, skipped, total = add_email_domains(domains)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>✅ 域名导入完成</b>\n\n"
|
||||||
|
f"新增: {added}\n"
|
||||||
|
f"跳过 (重复): {skipped}\n"
|
||||||
|
f"当前总数: {total}",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 添加域名失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_domain_del(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""删除指定域名"""
|
||||||
|
if not context.args:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>📧 删除域名</b>\n\n"
|
||||||
|
"用法:\n"
|
||||||
|
"<code>/domain_del @example.com</code>\n\n"
|
||||||
|
"@ 符号可省略",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import remove_email_domain, get_email_domains
|
||||||
|
|
||||||
|
domain = context.args[0].strip()
|
||||||
|
|
||||||
|
if remove_email_domain(domain):
|
||||||
|
total = len(get_email_domains())
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>✅ 域名已删除</b>\n\n"
|
||||||
|
f"已删除: <code>{domain}</code>\n"
|
||||||
|
f"剩余: {total} 个",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"❌ 域名不存在: <code>{domain}</code>",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 删除域名失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_domain_clear(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""清空域名列表"""
|
||||||
|
# 需要确认
|
||||||
|
if not context.args or context.args[0].lower() != "confirm":
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import get_email_domains
|
||||||
|
count = len(get_email_domains())
|
||||||
|
except:
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>⚠️ 确认清空域名列表?</b>\n\n"
|
||||||
|
f"当前共有 {count} 个域名\n\n"
|
||||||
|
f"确认请发送:\n"
|
||||||
|
f"<code>/domain_clear confirm</code>",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import clear_email_domains
|
||||||
|
clear_email_domains()
|
||||||
|
await update.message.reply_text("<b>✅ 域名列表已清空</b>", parse_mode="HTML")
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 清空域名失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_team_fingerprint(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""切换 GPT Team 随机指纹"""
|
||||||
|
import tomli_w
|
||||||
|
|
||||||
|
try:
|
||||||
|
# 读取当前配置
|
||||||
|
with open(CONFIG_FILE, "rb") as f:
|
||||||
|
import tomllib
|
||||||
|
config = tomllib.load(f)
|
||||||
|
|
||||||
|
# 确保 GPT Team section 存在
|
||||||
|
if "GPT Team" not in config:
|
||||||
|
config["GPT Team"] = {}
|
||||||
|
|
||||||
|
# 获取当前状态
|
||||||
|
current = config.get("GPT Team", {}).get("random_fingerprint", True)
|
||||||
|
new_value = not current
|
||||||
|
|
||||||
|
# 更新配置
|
||||||
|
config["GPT Team"]["random_fingerprint"] = new_value
|
||||||
|
|
||||||
|
# 写回文件
|
||||||
|
with open(CONFIG_FILE, "wb") as f:
|
||||||
|
tomli_w.dump(config, f)
|
||||||
|
|
||||||
|
status = "✅ 已开启" if new_value else "❌ 已关闭"
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>🎭 GPT Team 随机指纹</b>\n\n"
|
||||||
|
f"状态: {status}\n\n"
|
||||||
|
f"开启后每次运行将随机使用不同的:\n"
|
||||||
|
f"• User-Agent (Chrome 139-144)\n"
|
||||||
|
f"• WebGL 显卡指纹 (NVIDIA/AMD/Intel)\n"
|
||||||
|
f"• 屏幕分辨率 (1080p/1440p/4K)\n\n"
|
||||||
|
f"💡 下次运行 auto_gpt_team.py 时生效",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ 缺少 tomli_w 依赖\n"
|
||||||
|
"请运行: uv add tomli_w"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
await update.message.reply_text(f"❌ 修改配置失败: {e}")
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def cmd_team_register(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""开始 GPT Team 自动订阅注册"""
|
||||||
|
# 检查是否有任务正在运行
|
||||||
|
if self.current_task and not self.current_task.done():
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"⚠️ 有任务正在运行: {self.current_team}\n"
|
||||||
|
"请等待任务完成或使用 /stop 停止后再开始注册"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 检查配置
|
||||||
|
try:
|
||||||
|
from auto_gpt_team import MAIL_API_TOKEN, MAIL_API_BASE, get_email_domains, get_sepa_ibans
|
||||||
|
if not MAIL_API_TOKEN or not MAIL_API_BASE:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>❌ 配置错误</b>\n\n"
|
||||||
|
"请在 config.toml 中配置 [GPT Team] 段:\n"
|
||||||
|
"• mail_api_token\n"
|
||||||
|
"• mail_api_base",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
domains = get_email_domains()
|
||||||
|
if not domains:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>❌ 没有可用的邮箱域名</b>\n\n"
|
||||||
|
"请先使用 /domain_add 导入域名",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
ibans = get_sepa_ibans()
|
||||||
|
if not ibans:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>❌ 没有可用的 IBAN</b>\n\n"
|
||||||
|
"请先使用 /iban_add 导入 IBAN",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
except ImportError:
|
||||||
|
await update.message.reply_text("❌ auto_gpt_team 模块未找到")
|
||||||
|
return
|
||||||
|
|
||||||
|
# 显示数量选择
|
||||||
|
keyboard = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("1 个", callback_data="team_reg:count:1"),
|
||||||
|
InlineKeyboardButton("3 个", callback_data="team_reg:count:3"),
|
||||||
|
InlineKeyboardButton("5 个", callback_data="team_reg:count:5"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("10 个", callback_data="team_reg:count:10"),
|
||||||
|
InlineKeyboardButton("20 个", callback_data="team_reg:count:20"),
|
||||||
|
InlineKeyboardButton("自定义", callback_data="team_reg:count:custom"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
"<b>🚀 GPT Team 自动订阅</b>\n\n"
|
||||||
|
f"📧 邮箱域名: {len(domains)} 个\n"
|
||||||
|
f"💳 可用 IBAN: {len(ibans)} 个\n\n"
|
||||||
|
"请选择注册数量:",
|
||||||
|
parse_mode="HTML",
|
||||||
|
reply_markup=reply_markup
|
||||||
|
)
|
||||||
|
|
||||||
|
async def callback_team_register(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""处理 GPT Team 注册回调"""
|
||||||
|
query = update.callback_query
|
||||||
|
|
||||||
|
# 权限检查
|
||||||
|
user_id = update.effective_user.id
|
||||||
|
if user_id not in TELEGRAM_ADMIN_CHAT_IDS:
|
||||||
|
await query.answer("⛔ 无权限", show_alert=True)
|
||||||
|
return
|
||||||
|
|
||||||
|
await query.answer()
|
||||||
|
|
||||||
|
data = query.data.split(":")
|
||||||
|
action = data[1] if len(data) > 1 else ""
|
||||||
|
value = data[2] if len(data) > 2 else ""
|
||||||
|
|
||||||
|
if action == "count":
|
||||||
|
if value == "custom":
|
||||||
|
await query.edit_message_text(
|
||||||
|
"<b>📝 自定义数量</b>\n\n"
|
||||||
|
"请发送数量 (1-50):\n"
|
||||||
|
"直接回复一个数字即可\n\n"
|
||||||
|
"例如: <code>20</code>",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
# 设置等待输入状态
|
||||||
|
context.user_data["team_waiting_count"] = True
|
||||||
|
return
|
||||||
|
|
||||||
|
count = int(value)
|
||||||
|
# 显示输出方式选择
|
||||||
|
keyboard = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("📄 JSON 文件", callback_data=f"team_reg:output:json:{count}"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("📥 添加到 team.json", callback_data=f"team_reg:output:team:{count}"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"<b>⚙️ 配置完成</b>\n\n"
|
||||||
|
f"注册数量: {count} 个\n\n"
|
||||||
|
f"请选择输出方式:",
|
||||||
|
parse_mode="HTML",
|
||||||
|
reply_markup=reply_markup
|
||||||
|
)
|
||||||
|
|
||||||
|
elif action == "output":
|
||||||
|
output_type = value # json 或 team
|
||||||
|
count = int(data[3]) if len(data) > 3 else 1
|
||||||
|
|
||||||
|
await query.edit_message_text(
|
||||||
|
f"<b>⚙️ 配置完成</b>\n\n"
|
||||||
|
f"注册数量: {count} 个\n"
|
||||||
|
f"输出方式: {'📄 JSON 文件' if output_type == 'json' else '📥 team.json'}\n\n"
|
||||||
|
f"即将开始完整注册流程...",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 开始注册任务
|
||||||
|
self.current_team = f"GPT Team 注册 ({count}个)"
|
||||||
|
self.current_task = asyncio.create_task(
|
||||||
|
self._run_team_registration(query.message.chat_id, count, output_type)
|
||||||
|
)
|
||||||
|
|
||||||
|
async def _run_team_registration(self, chat_id: int, count: int, output_type: str):
|
||||||
|
"""执行 GPT Team 注册任务"""
|
||||||
|
from auto_gpt_team import run_single_registration, cleanup_chrome_processes
|
||||||
|
import json
|
||||||
|
import threading
|
||||||
|
|
||||||
|
results = []
|
||||||
|
success_count = 0
|
||||||
|
fail_count = 0
|
||||||
|
|
||||||
|
# 当前步骤 (用于显示)
|
||||||
|
current_step = ["初始化..."]
|
||||||
|
current_account = [""]
|
||||||
|
step_lock = threading.Lock()
|
||||||
|
|
||||||
|
def step_callback(step: str):
|
||||||
|
"""步骤回调 - 更新当前步骤"""
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = step
|
||||||
|
|
||||||
|
# 发送开始消息
|
||||||
|
progress_msg = await self.app.bot.send_message(
|
||||||
|
chat_id,
|
||||||
|
f"<b>🚀 开始注册</b>\n\n"
|
||||||
|
f"进度: 0/{count}\n"
|
||||||
|
f"{'▱' * 20}",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 进度更新任务
|
||||||
|
async def update_progress_loop():
|
||||||
|
"""定期更新进度消息"""
|
||||||
|
last_step = ""
|
||||||
|
while True:
|
||||||
|
await asyncio.sleep(1.5) # 每 1.5 秒更新一次
|
||||||
|
try:
|
||||||
|
with step_lock:
|
||||||
|
step = current_step[0]
|
||||||
|
account = current_account[0]
|
||||||
|
|
||||||
|
# 只有步骤变化时才更新
|
||||||
|
if step != last_step:
|
||||||
|
last_step = step
|
||||||
|
progress = int((success_count + fail_count) / count * 20) if count > 0 else 0
|
||||||
|
progress_bar = '▰' * progress + '▱' * (20 - progress)
|
||||||
|
|
||||||
|
text = (
|
||||||
|
f"<b>🚀 注册中...</b>\n\n"
|
||||||
|
f"进度: {success_count + fail_count}/{count}\n"
|
||||||
|
f"{progress_bar}\n\n"
|
||||||
|
f"✅ 成功: {success_count}\n"
|
||||||
|
f"❌ 失败: {fail_count}\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
if account:
|
||||||
|
text += f"\n⏳ 账号: <code>{account[:20]}...</code>"
|
||||||
|
|
||||||
|
if step:
|
||||||
|
text += f"\n ▸ {step}"
|
||||||
|
|
||||||
|
try:
|
||||||
|
await progress_msg.edit_text(text, parse_mode="HTML")
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 启动进度更新任务
|
||||||
|
progress_task = asyncio.create_task(update_progress_loop())
|
||||||
|
|
||||||
|
for i in range(count):
|
||||||
|
# 检查停止请求
|
||||||
|
try:
|
||||||
|
import run
|
||||||
|
if run._shutdown_requested:
|
||||||
|
break
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 执行注册
|
||||||
|
try:
|
||||||
|
# 使用 functools.partial 传递回调
|
||||||
|
import functools
|
||||||
|
|
||||||
|
def run_with_callback():
|
||||||
|
return run_single_registration(
|
||||||
|
progress_callback=None,
|
||||||
|
step_callback=step_callback
|
||||||
|
)
|
||||||
|
|
||||||
|
# 更新当前账号
|
||||||
|
with step_lock:
|
||||||
|
current_step[0] = "生成账号信息..."
|
||||||
|
current_account[0] = f"第 {i+1} 个"
|
||||||
|
|
||||||
|
result = await asyncio.get_event_loop().run_in_executor(
|
||||||
|
self.executor,
|
||||||
|
run_with_callback
|
||||||
|
)
|
||||||
|
|
||||||
|
if result.get("success"):
|
||||||
|
success_count += 1
|
||||||
|
results.append({
|
||||||
|
"account": result["account"],
|
||||||
|
"password": result["password"],
|
||||||
|
"token": result["token"],
|
||||||
|
"account_id": result.get("account_id", "")
|
||||||
|
})
|
||||||
|
with step_lock:
|
||||||
|
current_account[0] = result["account"]
|
||||||
|
else:
|
||||||
|
fail_count += 1
|
||||||
|
log.warning(f"注册失败: {result.get('error', '未知错误')}")
|
||||||
|
except Exception as e:
|
||||||
|
fail_count += 1
|
||||||
|
log.error(f"注册异常: {e}")
|
||||||
|
|
||||||
|
# 清理浏览器进程
|
||||||
|
cleanup_chrome_processes()
|
||||||
|
|
||||||
|
# 停止进度更新任务
|
||||||
|
progress_task.cancel()
|
||||||
|
try:
|
||||||
|
await progress_task
|
||||||
|
except asyncio.CancelledError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
# 完成进度
|
||||||
|
progress_bar = '▰' * 20
|
||||||
|
await progress_msg.edit_text(
|
||||||
|
f"<b>🎉 注册完成!</b> {success_count}/{count}\n"
|
||||||
|
f"{progress_bar}\n\n"
|
||||||
|
f"✅ 成功: {success_count}\n"
|
||||||
|
f"❌ 失败: {fail_count}",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 处理结果
|
||||||
|
if results:
|
||||||
|
if output_type == "json":
|
||||||
|
# 生成 JSON 文件
|
||||||
|
timestamp = time.strftime("%Y%m%d_%H%M%S")
|
||||||
|
filename = f"team_accounts_{timestamp}.json"
|
||||||
|
filepath = Path(filename)
|
||||||
|
|
||||||
|
with open(filepath, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(results, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
# 发送文件
|
||||||
|
await self.app.bot.send_document(
|
||||||
|
chat_id,
|
||||||
|
document=open(filepath, "rb"),
|
||||||
|
filename=filename,
|
||||||
|
caption=f"📄 注册结果 ({success_count} 个账号)"
|
||||||
|
)
|
||||||
|
|
||||||
|
# 删除临时文件
|
||||||
|
filepath.unlink()
|
||||||
|
|
||||||
|
elif output_type == "team":
|
||||||
|
# 添加到 team.json
|
||||||
|
try:
|
||||||
|
team_file = TEAM_JSON_FILE
|
||||||
|
existing = []
|
||||||
|
if team_file.exists():
|
||||||
|
with open(team_file, "r", encoding="utf-8") as f:
|
||||||
|
existing = json.load(f)
|
||||||
|
|
||||||
|
existing.extend(results)
|
||||||
|
|
||||||
|
with open(team_file, "w", encoding="utf-8") as f:
|
||||||
|
json.dump(existing, f, ensure_ascii=False, indent=2)
|
||||||
|
|
||||||
|
# 重载配置
|
||||||
|
reload_config()
|
||||||
|
|
||||||
|
await self.app.bot.send_message(
|
||||||
|
chat_id,
|
||||||
|
f"<b>✅ 已添加到 team.json</b>\n\n"
|
||||||
|
f"新增: {success_count} 个账号\n"
|
||||||
|
f"当前总数: {len(existing)} 个",
|
||||||
|
parse_mode="HTML"
|
||||||
|
)
|
||||||
|
except Exception as e:
|
||||||
|
await self.app.bot.send_message(
|
||||||
|
chat_id,
|
||||||
|
f"❌ 保存到 team.json 失败: {e}"
|
||||||
|
)
|
||||||
|
|
||||||
|
self.current_task = None
|
||||||
|
self.current_team = None
|
||||||
|
|
||||||
|
@admin_only
|
||||||
|
async def handle_team_custom_count(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
|
||||||
|
"""处理 GPT Team 自定义数量输入"""
|
||||||
|
# 检查是否在等待输入状态
|
||||||
|
if not context.user_data.get("team_waiting_count"):
|
||||||
|
return # 不在等待状态,忽略消息
|
||||||
|
|
||||||
|
# 清除等待状态
|
||||||
|
context.user_data["team_waiting_count"] = False
|
||||||
|
|
||||||
|
text = update.message.text.strip()
|
||||||
|
|
||||||
|
# 验证输入
|
||||||
|
try:
|
||||||
|
count = int(text)
|
||||||
|
if count < 1 or count > 50:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ 数量必须在 1-50 之间\n\n"
|
||||||
|
"请重新使用 /team_register 开始"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
except ValueError:
|
||||||
|
await update.message.reply_text(
|
||||||
|
"❌ 请输入有效的数字\n\n"
|
||||||
|
"请重新使用 /team_register 开始"
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
# 显示输出方式选择
|
||||||
|
keyboard = [
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("📄 JSON 文件", callback_data=f"team_reg:output:json:{count}"),
|
||||||
|
],
|
||||||
|
[
|
||||||
|
InlineKeyboardButton("📥 添加到 team.json", callback_data=f"team_reg:output:team:{count}"),
|
||||||
|
],
|
||||||
|
]
|
||||||
|
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||||
|
|
||||||
|
await update.message.reply_text(
|
||||||
|
f"<b>⚙️ 配置完成</b>\n\n"
|
||||||
|
f"注册数量: {count} 个\n\n"
|
||||||
|
f"请选择输出方式:",
|
||||||
|
parse_mode="HTML",
|
||||||
|
reply_markup=reply_markup
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
async def main():
|
async def main():
|
||||||
"""主函数"""
|
"""主函数"""
|
||||||
|
|||||||
Reference in New Issue
Block a user