diff --git a/bot_notifier.py b/bot_notifier.py
index 7b3284d..3ccb6c1 100644
--- a/bot_notifier.py
+++ b/bot_notifier.py
@@ -14,7 +14,7 @@ from config import (
)
-def make_progress_bar(current: int, total: int, width: int = 10) -> str:
+def make_progress_bar(current: int, total: int, width: int = 20) -> str:
"""生成文本进度条
Args:
@@ -23,19 +23,16 @@ def make_progress_bar(current: int, total: int, width: int = 10) -> str:
width: 进度条宽度 (字符数)
Returns:
- 进度条字符串,如 "████████░░ 80%"
+ 进度条字符串,如 "▓▓▓▓░░░░░░"
"""
if total <= 0:
- return "░" * width + " 0%"
+ return "░" * width
percent = min(current / total, 1.0)
filled = int(width * percent)
empty = width - filled
- bar = "█" * filled + "░" * empty
- percent_text = f"{int(percent * 100)}%"
-
- return f"{bar} {percent_text}"
+ return "▓" * filled + "░" * empty
class ProgressTracker:
@@ -54,6 +51,7 @@ class ProgressTracker:
self.success = 0
self.failed = 0
self.current_account = ""
+ self.current_phase = "" # 当前阶段 (注册/授权/验证)
self.current_step = ""
self.current_role = "" # 当前账号角色 (member/owner)
self.messages: Dict[int, Message] = {} # chat_id -> Message
@@ -63,29 +61,34 @@ class ProgressTracker:
def _get_progress_text(self) -> str:
"""生成进度消息文本"""
- bar = make_progress_bar(self.current, self.total, 12)
+ bar = make_progress_bar(self.current, self.total, 20)
# 标题行:显示 Team 序号
if self.teams_total > 0:
- title = f"📦 Team [{self.team_index}/{self.teams_total}]: {self.team_name}"
+ title = f"◈ Team [{self.team_index}/{self.teams_total}]: {self.team_name}"
else:
- title = f"📦 正在处理: {self.team_name}"
+ title = f"◈ 正在处理: {self.team_name}"
+ owner_tag = " (含 Owner)" if self.include_owner else ""
lines = [
title,
"",
- f"进度: {bar}",
- f"账号: {self.current}/{self.total}" + (f" (含 Owner)" if self.include_owner else ""),
- f"成功: {self.success} | 失败: {self.failed}",
+ f"🔄 注册进度 {self.current}/{self.total}{owner_tag}",
+ bar,
+ "",
+ f"✅ 成功: {self.success}",
+ f"❌ 失败: {self.failed}",
]
if self.current_account:
lines.append("")
role_tag = " 👑" if self.current_role == "owner" else ""
- lines.append(f"当前: {self.current_account}{role_tag}")
+ lines.append(f"⏳ 正在处理: {self.current_account}{role_tag}")
- if self.current_step:
- lines.append(f"步骤: {self.current_step}")
+ if self.current_phase and self.current_step:
+ lines.append(f" ▸ [{self.current_phase}] {self.current_step}")
+ elif self.current_step:
+ lines.append(f" ▸ {self.current_step}")
return "\n".join(lines)
@@ -137,12 +140,14 @@ class ProgressTracker:
self._loop = loop
asyncio.run_coroutine_threadsafe(self._send_initial_message(), loop)
- def update(self, current: int = None, account: str = None, step: str = None, role: str = None):
+ def update(self, current: int = None, account: str = None, phase: str = None, step: str = None, role: str = None):
"""更新进度 (供同步代码调用)"""
if current is not None:
self.current = current
if account is not None:
self.current_account = account
+ if phase is not None:
+ self.current_phase = phase
if step is not None:
self.current_step = step
if role is not None:
@@ -158,6 +163,7 @@ class ProgressTracker:
else:
self.failed += 1
self.current_account = ""
+ self.current_phase = ""
self.current_step = ""
self.current_role = ""
# 最后一个账号完成时强制更新,确保显示 100%
@@ -440,10 +446,17 @@ def progress_start(team_name: str, total: int, team_index: int = 0,
return None
-def progress_update(account: str = None, step: str = None, role: str = None):
- """更新当前进度"""
+def progress_update(account: str = None, phase: str = None, step: str = None, role: str = None):
+ """更新当前进度
+
+ Args:
+ account: 当前处理的账号
+ phase: 当前阶段 (注册/授权/验证)
+ step: 当前步骤
+ role: 账号角色
+ """
if _notifier and _notifier.get_progress():
- _notifier.get_progress().update(account=account, step=step, role=role)
+ _notifier.get_progress().update(account=account, phase=phase, step=step, role=role)
def progress_account_done(email: str, success: bool):
diff --git a/browser_automation.py b/browser_automation.py
index af338d6..eef05b7 100644
--- a/browser_automation.py
+++ b/browser_automation.py
@@ -34,6 +34,12 @@ from s2a_service import (
)
from logger import log
+# 进度更新 (Telegram Bot 使用)
+try:
+ from bot_notifier import progress_update
+except ImportError:
+ def progress_update(account=None, phase=None, step=None, role=None): pass
+
# ==================== 停止检查 ====================
class ShutdownRequested(Exception):
@@ -1106,6 +1112,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
# 步骤1: 输入邮箱 (在 log-in-or-create-account 页面)
if "auth.openai.com/log-in-or-create-account" in current_url:
+ progress_update(phase="注册", step="输入邮箱...")
log.step("等待邮箱输入框...")
email_input = wait_for_element(page, 'css:input[type="email"]', timeout=15)
if not email_input:
@@ -1129,6 +1136,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
# 步骤2: 输入密码 (在密码页面: log-in/password 或 create-account/password)
if "auth.openai.com/log-in/password" in current_url or "auth.openai.com/create-account/password" in current_url:
+ progress_update(phase="注册", step="输入密码...")
# 先检查是否有密码错误提示,如果有则使用一次性验证码登录
try:
error_text = page.ele('text:Incorrect email address or password', timeout=1)
@@ -1229,6 +1237,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
# 检测到姓名/年龄输入页面 (账号已存在,只需补充信息)
if "auth.openai.com/about-you" in current_url:
+ progress_update(phase="注册", step="补充个人信息...")
log_current_url(page, "个人信息页面")
log.info("检测到姓名输入页面,账号已存在,补充信息...")
@@ -1282,6 +1291,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
return False
# 获取验证码
+ progress_update(phase="注册", step="等待验证码...")
log.step("等待验证码邮件...")
verification_code, error, email_time = unified_get_verification_code(email)
@@ -1296,6 +1306,7 @@ def register_openai_account(page, email: str, password: str) -> bool:
max_code_retries = 3
for code_attempt in range(max_code_retries):
# 输入验证码
+ progress_update(phase="注册", step="输入验证码...")
log.step(f"输入验证码: {verification_code}")
while check_and_handle_error(page):
time.sleep(1)
@@ -2473,6 +2484,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
bool: 授权是否成功
"""
log.info(f"开始 S2A 授权: {email}", icon="code")
+ progress_update(phase="授权", step="开始 S2A 授权...")
# 生成授权 URL
auth_url, session_id = s2a_generate_auth_url()
@@ -2481,6 +2493,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
return False
# 打开授权页面
+ progress_update(phase="授权", step="打开授权页面...")
log.step("打开 S2A 授权页面...")
log.info(f"[URL] S2A授权URL: {auth_url}", icon="browser")
page.get(auth_url)
@@ -2492,6 +2505,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
try:
# 输入邮箱
+ progress_update(phase="授权", step="输入邮箱...")
log.step("输入邮箱...")
email_input = wait_for_element(page, 'css:input[type="email"]', timeout=10)
if not email_input:
@@ -2516,6 +2530,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
current_url = page.url
if "/password" in current_url:
try:
+ progress_update(phase="授权", step="输入密码...")
log.step("输入密码...")
password_input = wait_for_element(page, 'css:input[type="password"]', timeout=10)
@@ -2540,6 +2555,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
callback_url = None
progress_shown = False
last_url_in_loop = None
+ progress_update(phase="授权", step="等待回调...")
log.step(f"等待 S2A 授权回调 (最多 {max_wait}s)...")
while time.time() - start_time < max_wait:
@@ -2604,6 +2620,7 @@ def perform_s2a_authorization(page, email: str, password: str) -> bool:
return False
# S2A 特有流程: 用授权码创建账号 (传入完整邮箱用于验证)
+ progress_update(phase="授权", step="提交授权码...")
log.step("正在提交 S2A 授权码...")
result = s2a_create_account_from_oauth(code, session_id, name=email)
if result:
diff --git a/run.py b/run.py
index 4bc5fa4..00ed482 100644
--- a/run.py
+++ b/run.py
@@ -48,7 +48,7 @@ try:
except ImportError:
# 如果没有 bot_notifier,使用空函数
def progress_start(team_name, total): pass
- def progress_update(account=None, step=None): pass
+ def progress_update(account=None, phase=None, step=None, role=None): pass
def progress_account_done(email, success): pass
def progress_finish(): pass
def notify_team_completed_sync(team_name, results): pass
@@ -319,7 +319,7 @@ def process_accounts(accounts: list, team_name: str, team_index: int = 0,
log.separator("#", 50)
# 更新进度: 当前账号
- progress_update(account=email, step="Starting...", role=role)
+ progress_update(account=email, phase="准备", step="开始处理...", role=role)
result = {
"team": team_name,
@@ -370,13 +370,13 @@ def process_accounts(accounts: list, team_name: str, team_index: int = 0,
if is_team_owner_otp:
# 旧格式 Team Owner: 使用 OTP 登录授权
log.info("Team Owner 账号 (旧格式),使用一次性验证码登录...", icon="auth")
- progress_update(step="OTP Login...")
+ progress_update(phase="授权", step="OTP 登录...")
auth_success, codex_data = login_and_authorize_with_otp(email)
register_success = auth_success
elif need_crs_only:
# 已授权但未入库: 跳过授权,直接尝试入库
log.info(f"已授权账号 (状态: {account_status}),跳过授权,直接入库...", icon="auth")
- progress_update(step="Adding to CRS...")
+ progress_update(phase="入库", step="添加到 CRS...")
register_success = True
codex_data = None # CPA/S2A 模式不需要 codex_data
# CRS 模式下,由于没有 codex_data,无法入库,需要重新授权
@@ -387,12 +387,12 @@ def process_accounts(accounts: list, team_name: str, team_index: int = 0,
elif need_auth_only:
# 已注册账号 (包括新格式 Owner): 使用密码登录授权
log.info(f"已注册账号 (状态: {account_status}, 角色: {account_role}),使用密码登录授权...", icon="auth")
- progress_update(step="Authorizing...")
+ progress_update(phase="授权", step="密码登录授权...")
auth_success, codex_data = authorize_only(email, password)
register_success = True
else:
# 新账号: 注册 + Codex 授权
- progress_update(step="Registering...")
+ progress_update(phase="注册", step="注册 OpenAI...")
register_success, codex_data = register_and_authorize(email, password)
# 检查是否是域名黑名单错误
@@ -436,7 +436,7 @@ def process_accounts(accounts: list, team_name: str, team_index: int = 0,
# 验证账号是否成功入库
log.step("正在验证 S2A 账号入库状态...")
- progress_update(step="验证入库...")
+ progress_update(phase="验证", step="检查入库状态...")
verified, account_data = s2a_verify_account_in_pool(email)
if verified:
diff --git a/telegram_bot.py b/telegram_bot.py
index a581d46..c1592e4 100644
--- a/telegram_bot.py
+++ b/telegram_bot.py
@@ -1207,19 +1207,19 @@ class ProvisionerBot:
# 创建时间选择按钮
keyboard = [
[
- InlineKeyboardButton("📅 今天", callback_data="keys_usage:today"),
- InlineKeyboardButton("📅 昨天", callback_data="keys_usage:yesterday"),
+ InlineKeyboardButton("📍 今天", callback_data="keys_usage:today"),
+ InlineKeyboardButton("◀ 昨天", callback_data="keys_usage:yesterday"),
],
[
- InlineKeyboardButton("📆 近 7 天", callback_data="keys_usage:7d"),
- InlineKeyboardButton("📆 近 14 天", callback_data="keys_usage:14d"),
+ InlineKeyboardButton("◀ 近 7 天", callback_data="keys_usage:7d"),
+ InlineKeyboardButton("◀ 近 14 天", callback_data="keys_usage:14d"),
],
[
- InlineKeyboardButton("📆 近 30 天", callback_data="keys_usage:30d"),
- InlineKeyboardButton("📆 本月", callback_data="keys_usage:this_month"),
+ InlineKeyboardButton("◀ 近 30 天", callback_data="keys_usage:30d"),
+ InlineKeyboardButton("📅 本月", callback_data="keys_usage:this_month"),
],
[
- InlineKeyboardButton("📆 上月", callback_data="keys_usage:last_month"),
+ InlineKeyboardButton("📅 上月", callback_data="keys_usage:last_month"),
],
]
reply_markup = InlineKeyboardMarkup(keyboard)