feat(telegram_bot): Add verify_all command for force account re-verification

- Add new /verify_all command to force re-verify all accounts with tokens
- Update command registration to include verify_all handler
- Modify _validate_and_cleanup_accounts() to accept force_all parameter
- Add progress bar visualization using block characters (█░)
- Implement progress bar helper function with percentage display
- Update verification logic to handle two modes: normal and force-all
- Enhance user messages with token count and mode-specific text
- Update help text and command descriptions in Chinese
- Improve progress tracking with visual feedback during verification
- Separate /verify (unverified only) from /verify_all (all with tokens)
This commit is contained in:
2026-01-30 08:53:40 +08:00
parent 75a0dccebe
commit 20e2719d0e

View File

@@ -137,6 +137,7 @@ class ProvisionerBot:
("dashboard", self.cmd_dashboard), ("dashboard", self.cmd_dashboard),
("import", self.cmd_import), ("import", self.cmd_import),
("verify", self.cmd_verify), ("verify", self.cmd_verify),
("verify_all", self.cmd_verify_all),
("stock", self.cmd_stock), ("stock", self.cmd_stock),
("gptmail_keys", self.cmd_gptmail_keys), ("gptmail_keys", self.cmd_gptmail_keys),
("gptmail_add", self.cmd_gptmail_add), ("gptmail_add", self.cmd_gptmail_add),
@@ -270,7 +271,8 @@ class ProvisionerBot:
BotCommand("stock", "查看账号库存"), BotCommand("stock", "查看账号库存"),
BotCommand("s2a_config", "配置 S2A 参数"), BotCommand("s2a_config", "配置 S2A 参数"),
BotCommand("import", "导入账号到 team.json"), BotCommand("import", "导入账号到 team.json"),
BotCommand("verify", "验证账号并移除无效账号"), BotCommand("verify", "验证未验证的账号"),
BotCommand("verify_all", "强制重新验证所有账号"),
# GPTMail # GPTMail
BotCommand("gptmail_keys", "查看 GPTMail API Keys"), BotCommand("gptmail_keys", "查看 GPTMail API Keys"),
BotCommand("gptmail_add", "添加 GPTMail API Key"), BotCommand("gptmail_add", "添加 GPTMail API Key"),
@@ -338,7 +340,8 @@ class ProvisionerBot:
<b>📤 导入账号:</b> <b>📤 导入账号:</b>
/import - 导入账号到 team.json /import - 导入账号到 team.json
/verify - 验证账号并移除无效账号 /verify - 验证未验证的账号
/verify_all - 强制重新验证所有账号
或直接发送 JSON 文件 或直接发送 JSON 文件
<b>📧 GPTMail 管理:</b> <b>📧 GPTMail 管理:</b>
@@ -2041,20 +2044,23 @@ class ProvisionerBot:
if added_count > 0: if added_count > 0:
await self._validate_and_cleanup_accounts(chat_id) await self._validate_and_cleanup_accounts(chat_id)
async def _validate_and_cleanup_accounts(self, chat_id: int): async def _validate_and_cleanup_accounts(self, chat_id: int, force_all: bool = False):
"""验证新导入账号的 account_id移除无效账号 """验证新导入账号的 account_id移除无效账号
Args: Args:
chat_id: Telegram 聊天 ID用于发送进度消息 chat_id: Telegram 聊天 ID用于发送进度消息
force_all: 是否强制重新验证所有有 token 的账号
""" """
import json import json
from pathlib import Path from pathlib import Path
from concurrent.futures import ThreadPoolExecutor, as_completed from concurrent.futures import ThreadPoolExecutor, as_completed
mode_text = "重新验证" if force_all else "验证"
# 发送开始验证的消息 # 发送开始验证的消息
progress_msg = await self.app.bot.send_message( progress_msg = await self.app.bot.send_message(
chat_id=chat_id, chat_id=chat_id,
text="<b>🔍 正在验证账号...</b>\n\n⏳ 获取 account_id 中...", text=f"<b>🔍 正在{mode_text}账号...</b>\n\n⏳ 获取 account_id 中...",
parse_mode="HTML" parse_mode="HTML"
) )
@@ -2075,13 +2081,19 @@ class ProvisionerBot:
if not isinstance(accounts, list): if not isinstance(accounts, list):
accounts = [accounts] accounts = [accounts]
# 筛选需要验证的账号 (有 token 但没有 account_id) # 筛选需要验证的账号
accounts_to_verify = [] accounts_to_verify = []
for i, acc in enumerate(accounts): for i, acc in enumerate(accounts):
token = acc.get("token", "") token = acc.get("token", "")
account_id = acc.get("account_id", "") account_id = acc.get("account_id", "")
if token and not account_id: if force_all:
accounts_to_verify.append((i, acc)) # 强制模式:验证所有有 token 的账号
if token:
accounts_to_verify.append((i, acc))
else:
# 普通模式:只验证有 token 但没有 account_id 的账号
if token and not account_id:
accounts_to_verify.append((i, acc))
if not accounts_to_verify: if not accounts_to_verify:
await self.app.bot.edit_message_text( await self.app.bot.edit_message_text(
@@ -2093,10 +2105,23 @@ class ProvisionerBot:
return return
total = len(accounts_to_verify) total = len(accounts_to_verify)
# 生成进度条的辅助函数
def make_progress_bar(current: int, total: int, width: int = 16) -> str:
"""生成进度条字符串"""
if total == 0:
return "[" + "" * width + "]"
filled = int(width * current / total)
empty = width - filled
percent = int(100 * current / total)
return f"[{'' * filled}{'' * empty}] {current}/{total} ({percent}%)"
await self.app.bot.edit_message_text( await self.app.bot.edit_message_text(
chat_id=chat_id, chat_id=chat_id,
message_id=progress_msg.message_id, message_id=progress_msg.message_id,
text=f"<b>🔍 正在验证账号...</b>\n\n⏳ 验证 {total} 个账号的 account_id (20 并发)...", text=f"<b>🔍 正在{mode_text}账号...</b>\n\n"
f"<code>{make_progress_bar(0, total)}</code>\n\n"
f"⏳ 验证 {total} 个账号的 account_id (20 并发)...",
parse_mode="HTML" parse_mode="HTML"
) )
@@ -2148,11 +2173,12 @@ class ProvisionerBot:
if completed_count % 10 == 0 or completed_count == total or current_time - last_update_time > 1: if completed_count % 10 == 0 or completed_count == total or current_time - last_update_time > 1:
last_update_time = current_time last_update_time = current_time
try: try:
progress_bar = make_progress_bar(completed_count, total)
await self.app.bot.edit_message_text( await self.app.bot.edit_message_text(
chat_id=chat_id, chat_id=chat_id,
message_id=progress_msg.message_id, message_id=progress_msg.message_id,
text=f"<b>🔍 正在验证账号...</b>\n\n" text=f"<b>🔍 正在{mode_text}账号...</b>\n\n"
f"进度: {completed_count}/{total}\n" f"<code>{progress_bar}</code>\n\n"
f"✅ 成功: {len(valid_indices)}\n" f"✅ 成功: {len(valid_indices)}\n"
f"❌ 失败: {len(failed_accounts)}", f"❌ 失败: {len(failed_accounts)}",
parse_mode="HTML" parse_mode="HTML"
@@ -2176,6 +2202,8 @@ class ProvisionerBot:
lines = [ lines = [
"<b>✅ 账号验证完成</b>", "<b>✅ 账号验证完成</b>",
"", "",
f"<code>{make_progress_bar(total, total)}</code>",
"",
f"📊 验证结果:", f"📊 验证结果:",
f" • 验证总数: {total}", f" • 验证总数: {total}",
f" • 成功: {len(valid_indices)}", f" • 成功: {len(valid_indices)}",
@@ -2217,7 +2245,83 @@ class ProvisionerBot:
@admin_only @admin_only
async def cmd_verify(self, update: Update, context: ContextTypes.DEFAULT_TYPE): async def cmd_verify(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""手动验证 team.json 中的账号,获取 account_id 并移除无效账号""" """手动验证 team.json 中的账号,获取 account_id 并移除无效账号
用法:
/verify - 验证未验证的账号
/verify_all - 强制重新验证所有账号
"""
chat_id = update.effective_chat.id
# 检查是否有任务正在运行
if self.current_task and not self.current_task.done():
await update.message.reply_text(
f"⚠️ 有任务正在运行: {self.current_team}\n"
"请等待任务完成或使用 /stop 停止后再验证"
)
return
# 解析参数
force_all = context.args and context.args[0].lower() == "all"
# 检查 team.json 是否存在
from pathlib import Path
team_json_path = Path(TEAM_JSON_FILE)
if not team_json_path.exists():
await update.message.reply_text("❌ team.json 不存在,请先导入账号")
return
# 统计需要验证的账号
import json
try:
with open(team_json_path, "r", encoding="utf-8") as f:
accounts = json.load(f)
if not isinstance(accounts, list):
accounts = [accounts]
except Exception as e:
await update.message.reply_text(f"❌ 读取 team.json 失败: {e}")
return
total_accounts = len(accounts)
has_token = sum(1 for acc in accounts if acc.get("token"))
already_verified = sum(1 for acc in accounts if acc.get("account_id"))
if force_all:
# 强制重新验证所有有 token 的账号
need_verify = has_token
else:
# 只验证未验证的账号
need_verify = sum(1 for acc in accounts if acc.get("token") and not acc.get("account_id"))
if need_verify == 0:
await update.message.reply_text(
f"<b>✅ 无需验证</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n"
f"有 Token: {has_token}\n"
f"已验证: {already_verified}\n"
f"待验证: 0\n\n"
f"💡 使用 /verify_all 强制重新验证所有账号",
parse_mode="HTML"
)
return
mode_text = "强制重新验证" if force_all else "验证"
await update.message.reply_text(
f"<b>🔍 开始{mode_text}账号</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n"
f"有 Token: {has_token}\n"
f"已验证: {already_verified}\n"
f"待验证: {need_verify}\n\n"
f"⏳ 正在验证...",
parse_mode="HTML"
)
# 执行验证
await self._validate_and_cleanup_accounts(chat_id, force_all=force_all)
@admin_only
async def cmd_verify_all(self, update: Update, context: ContextTypes.DEFAULT_TYPE):
"""强制重新验证所有账号"""
chat_id = update.effective_chat.id chat_id = update.effective_chat.id
# 检查是否有任务正在运行 # 检查是否有任务正在运行
@@ -2247,30 +2351,31 @@ class ProvisionerBot:
return return
total_accounts = len(accounts) total_accounts = len(accounts)
need_verify = sum(1 for acc in accounts if acc.get("token") and not acc.get("account_id")) has_token = sum(1 for acc in accounts if acc.get("token"))
already_verified = sum(1 for acc in accounts if acc.get("account_id")) already_verified = sum(1 for acc in accounts if acc.get("account_id"))
if need_verify == 0: if has_token == 0:
await update.message.reply_text( await update.message.reply_text(
f"<b>验证</b>\n\n" f"<b>验证</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n" f"team.json 共 {total_accounts} 个账号\n"
f"已验证: {already_verified}\n" f"有 Token: 0\n\n"
f"待验证: 0", f"没有可验证的账号",
parse_mode="HTML" parse_mode="HTML"
) )
return return
await update.message.reply_text( await update.message.reply_text(
f"<b>🔍 开始验证账号</b>\n\n" f"<b>🔍 开始强制重新验证所有账号</b>\n\n"
f"team.json 共 {total_accounts} 个账号\n" f"team.json 共 {total_accounts} 个账号\n"
f"有 Token: {has_token}\n"
f"已验证: {already_verified}\n" f"已验证: {already_verified}\n"
f"待验证: {need_verify}\n\n" f"待验证: {has_token}\n\n"
f"⏳ 正在验证...", f"⏳ 正在验证...",
parse_mode="HTML" parse_mode="HTML"
) )
# 执行验证 # 执行验证 (强制模式)
await self._validate_and_cleanup_accounts(chat_id) await self._validate_and_cleanup_accounts(chat_id, force_all=True)
async def _import_batch_timeout_callback(self, context: ContextTypes.DEFAULT_TYPE): async def _import_batch_timeout_callback(self, context: ContextTypes.DEFAULT_TYPE):
"""批量导入超时回调 - 由 job_queue 调用""" """批量导入超时回调 - 由 job_queue 调用"""