feat(payment): Integrate Stripe API and refactor payment flow
- Add new stripe_api.py module with StripePaymentAPI class and payment retry logic - Import Stripe payment module in auto_gpt_team.py with graceful fallback handling - Refactor run_payment_flow() to extract form filling logic into _fill_payment_form() - Simplify error handling by returning structured tuples (success, error_type, error_msg) - Remove redundant comments and streamline selector logic for payment form elements - Improve code maintainability by separating concerns between form filling and flow orchestration - Add STRIPE_API_AVAILABLE flag to track payment module availability at runtime
This commit is contained in:
951
auto_gpt_team.py
951
auto_gpt_team.py
File diff suppressed because it is too large
Load Diff
418
stripe_api.py
Normal file
418
stripe_api.py
Normal file
@@ -0,0 +1,418 @@
|
||||
"""
|
||||
Stripe SEPA 支付 API 模块
|
||||
- 使用纯 API 方式完成 Stripe SEPA 支付
|
||||
- 参考 team-reg-go/stripe/stripe.go 实现
|
||||
"""
|
||||
|
||||
import re
|
||||
import time
|
||||
import uuid
|
||||
import random
|
||||
|
||||
try:
|
||||
from curl_cffi import requests as curl_requests
|
||||
CURL_CFFI_AVAILABLE = True
|
||||
except ImportError:
|
||||
CURL_CFFI_AVAILABLE = False
|
||||
curl_requests = None
|
||||
|
||||
import requests
|
||||
|
||||
|
||||
def log_status(step, message):
|
||||
"""日志输出"""
|
||||
timestamp = time.strftime("%H:%M:%S")
|
||||
print(f"[{timestamp}] [{step}] {message}")
|
||||
|
||||
|
||||
def log_progress(message):
|
||||
"""进度输出"""
|
||||
print(f" {message}")
|
||||
|
||||
|
||||
# Stripe 配置常量
|
||||
STRIPE_VERSION = "2024-12-18.acacia"
|
||||
STRIPE_JS_VERSION = "d7c0c7e0e4e3e8e9e0e1e2e3e4e5e6e7"
|
||||
OPENAI_STRIPE_PUBLIC_KEY = "pk_live_51LVfqJKa3k6aumIYFMNZILdA00QBnLMNa"
|
||||
|
||||
|
||||
def generate_stripe_fingerprint() -> str:
|
||||
"""生成 Stripe 指纹 ID"""
|
||||
return uuid.uuid4().hex
|
||||
|
||||
|
||||
def extract_session_id(checkout_url: str) -> str:
|
||||
"""从 checkout URL 提取 session_id"""
|
||||
match = re.search(r'(cs_(?:live|test)_[a-zA-Z0-9]+)', checkout_url)
|
||||
if match:
|
||||
return match.group(1)
|
||||
return ""
|
||||
|
||||
|
||||
class StripePaymentAPI:
|
||||
"""Stripe SEPA 支付 API 处理器"""
|
||||
|
||||
def __init__(self, checkout_url: str, session=None, proxy: str = None):
|
||||
"""初始化
|
||||
|
||||
Args:
|
||||
checkout_url: Stripe checkout URL
|
||||
session: 可选的 curl_cffi session (复用已有会话)
|
||||
proxy: 代理地址
|
||||
"""
|
||||
self.checkout_url = checkout_url
|
||||
self.session_id = extract_session_id(checkout_url)
|
||||
self.stripe_public_key = OPENAI_STRIPE_PUBLIC_KEY
|
||||
self.init_checksum = ""
|
||||
self.js_checksum = ""
|
||||
self.guid = generate_stripe_fingerprint()
|
||||
self.muid = generate_stripe_fingerprint()
|
||||
self.sid = generate_stripe_fingerprint()
|
||||
self.client_session_id = ""
|
||||
self.checkout_config_id = ""
|
||||
|
||||
# 创建或复用 session
|
||||
if session:
|
||||
self.session = session
|
||||
elif CURL_CFFI_AVAILABLE:
|
||||
self.session = curl_requests.Session(
|
||||
impersonate="chrome",
|
||||
verify=False,
|
||||
proxies={"http": proxy, "https": proxy} if proxy else {}
|
||||
)
|
||||
else:
|
||||
self.session = requests.Session()
|
||||
if proxy:
|
||||
self.session.proxies = {"http": proxy, "https": proxy}
|
||||
|
||||
def _get_stripe_headers(self) -> dict:
|
||||
"""获取 Stripe API 请求头"""
|
||||
return {
|
||||
"Content-Type": "application/x-www-form-urlencoded",
|
||||
"Accept": "application/json",
|
||||
"Origin": "https://pay.openai.com",
|
||||
"Referer": "https://pay.openai.com/",
|
||||
"Sec-Fetch-Site": "cross-site",
|
||||
"Sec-Fetch-Mode": "cors",
|
||||
"Sec-Fetch-Dest": "empty",
|
||||
"Sec-Ch-Ua-Platform": '"Windows"',
|
||||
"Accept-Language": "en-US,en;q=0.9",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
|
||||
}
|
||||
|
||||
def fetch_checkout_page(self) -> bool:
|
||||
"""获取 checkout 页面参数"""
|
||||
try:
|
||||
headers = {
|
||||
"Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8",
|
||||
"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
|
||||
}
|
||||
resp = self.session.get(self.checkout_url, headers=headers, timeout=30)
|
||||
|
||||
if resp.status_code == 200:
|
||||
html = resp.text
|
||||
|
||||
# 提取 initChecksum
|
||||
init_match = re.search(r'"initChecksum":\s*"([^"]+)"', html)
|
||||
if init_match:
|
||||
self.init_checksum = init_match.group(1)
|
||||
|
||||
# 提取 jsChecksum
|
||||
js_match = re.search(r'"jsChecksum":\s*"([^"]+)"', html)
|
||||
if js_match:
|
||||
self.js_checksum = js_match.group(1)
|
||||
|
||||
return True
|
||||
return False
|
||||
except Exception as e:
|
||||
log_progress(f"[!] 获取 checkout 页面失败: {e}")
|
||||
return False
|
||||
|
||||
def create_payment_method(self, iban: str, name: str, email: str,
|
||||
address: str, city: str, postal_code: str,
|
||||
country: str = "DE") -> str:
|
||||
"""Step 1: 创建支付方式
|
||||
|
||||
Returns:
|
||||
str: payment_method_id,失败返回空字符串
|
||||
"""
|
||||
api_url = "https://api.stripe.com/v1/payment_methods"
|
||||
|
||||
self.client_session_id = str(uuid.uuid4())
|
||||
self.checkout_config_id = str(uuid.uuid4())
|
||||
|
||||
data = {
|
||||
"type": "sepa_debit",
|
||||
"sepa_debit[iban]": iban,
|
||||
"billing_details[name]": name,
|
||||
"billing_details[email]": email,
|
||||
"billing_details[address][country]": country,
|
||||
"billing_details[address][line1]": address,
|
||||
"billing_details[address][city]": city,
|
||||
"billing_details[address][postal_code]": postal_code,
|
||||
"guid": self.guid,
|
||||
"muid": self.muid,
|
||||
"sid": self.sid,
|
||||
"_stripe_version": STRIPE_VERSION,
|
||||
"key": self.stripe_public_key,
|
||||
"payment_user_agent": f"stripe.js/{STRIPE_JS_VERSION}; stripe-js-v3/{STRIPE_JS_VERSION}; checkout",
|
||||
"client_attribution_metadata[client_session_id]": self.client_session_id,
|
||||
"client_attribution_metadata[checkout_session_id]": self.session_id,
|
||||
"client_attribution_metadata[merchant_integration_source]": "checkout",
|
||||
"client_attribution_metadata[merchant_integration_version]": "hosted_checkout",
|
||||
"client_attribution_metadata[payment_method_selection_flow]": "automatic",
|
||||
"client_attribution_metadata[checkout_config_id]": self.checkout_config_id,
|
||||
}
|
||||
|
||||
try:
|
||||
resp = self.session.post(api_url, data=data, headers=self._get_stripe_headers(), timeout=30)
|
||||
|
||||
if resp.status_code == 200:
|
||||
result = resp.json()
|
||||
payment_method_id = result.get("id", "")
|
||||
if payment_method_id:
|
||||
return payment_method_id
|
||||
|
||||
error_text = resp.text[:200] if resp.text else "无响应"
|
||||
log_progress(f"[X] 创建支付方式失败: {resp.status_code} - {error_text}")
|
||||
return ""
|
||||
except Exception as e:
|
||||
log_progress(f"[X] 创建支付方式异常: {e}")
|
||||
return ""
|
||||
|
||||
def confirm_payment(self, payment_method_id: str, captcha_token: str = "",
|
||||
rv_timestamp: str = "") -> tuple:
|
||||
"""Step 2: 确认支付
|
||||
|
||||
Returns:
|
||||
tuple: (success: bool, error_message: str)
|
||||
"""
|
||||
api_url = f"https://api.stripe.com/v1/payment_pages/{self.session_id}/confirm"
|
||||
|
||||
data = {
|
||||
"eid": "NA",
|
||||
"payment_method": payment_method_id,
|
||||
"expected_amount": "0",
|
||||
"consent[terms_of_service]": "accepted",
|
||||
"tax_id_collection[purchasing_as_business]": "false",
|
||||
"expected_payment_method_type": "sepa_debit",
|
||||
"_stripe_version": STRIPE_VERSION,
|
||||
"guid": self.guid,
|
||||
"muid": self.muid,
|
||||
"sid": self.sid,
|
||||
"key": self.stripe_public_key,
|
||||
"version": STRIPE_JS_VERSION,
|
||||
"referrer": "https://chatgpt.com",
|
||||
"client_attribution_metadata[client_session_id]": self.client_session_id,
|
||||
"client_attribution_metadata[checkout_session_id]": self.session_id,
|
||||
"client_attribution_metadata[merchant_integration_source]": "checkout",
|
||||
"client_attribution_metadata[merchant_integration_version]": "hosted_checkout",
|
||||
"client_attribution_metadata[payment_method_selection_flow]": "automatic",
|
||||
"client_attribution_metadata[checkout_config_id]": self.checkout_config_id,
|
||||
}
|
||||
|
||||
if self.init_checksum:
|
||||
data["init_checksum"] = self.init_checksum
|
||||
if self.js_checksum:
|
||||
data["js_checksum"] = self.js_checksum
|
||||
if captcha_token:
|
||||
data["passive_captcha_token"] = captcha_token
|
||||
data["passive_captcha_ekey"] = ""
|
||||
if rv_timestamp:
|
||||
data["rv_timestamp"] = rv_timestamp
|
||||
|
||||
try:
|
||||
resp = self.session.post(api_url, data=data, headers=self._get_stripe_headers(), timeout=30)
|
||||
|
||||
if resp.status_code == 200:
|
||||
result = resp.json()
|
||||
state = result.get("state", "")
|
||||
|
||||
if state in ["succeeded", "processing", "processing_subscription"]:
|
||||
return True, ""
|
||||
elif state == "failed":
|
||||
error = result.get("error", {})
|
||||
error_msg = error.get("message", str(error)) if isinstance(error, dict) else str(error)
|
||||
return False, f"支付失败: {error_msg}"
|
||||
else:
|
||||
# 其他状态继续轮询
|
||||
return True, ""
|
||||
|
||||
error_text = resp.text[:200] if resp.text else "无响应"
|
||||
return False, f"确认失败: {resp.status_code} - {error_text}"
|
||||
except Exception as e:
|
||||
return False, f"确认异常: {e}"
|
||||
|
||||
def poll_payment_status(self, max_attempts: int = 20) -> tuple:
|
||||
"""Step 3: 轮询支付状态
|
||||
|
||||
Returns:
|
||||
tuple: (state: str, error_message: str)
|
||||
"""
|
||||
api_url = f"https://api.stripe.com/v1/payment_pages/{self.session_id}/poll?key={self.stripe_public_key}"
|
||||
|
||||
for attempt in range(max_attempts):
|
||||
try:
|
||||
resp = self.session.get(api_url, headers=self._get_stripe_headers(), timeout=30)
|
||||
|
||||
if resp.status_code == 200:
|
||||
result = resp.json()
|
||||
state = result.get("state", "")
|
||||
|
||||
if state == "succeeded":
|
||||
return "succeeded", ""
|
||||
elif state in ["failed", "canceled"]:
|
||||
return state, f"支付 {state}"
|
||||
|
||||
time.sleep(2)
|
||||
except Exception as e:
|
||||
log_progress(f"[!] 轮询异常: {e}")
|
||||
time.sleep(2)
|
||||
|
||||
return "timeout", "轮询超时"
|
||||
|
||||
def complete_payment(self, iban: str, name: str, email: str,
|
||||
address: str, city: str, postal_code: str,
|
||||
country: str = "DE") -> tuple:
|
||||
"""执行完整支付流程
|
||||
|
||||
Returns:
|
||||
tuple: (success: bool, error_message: str)
|
||||
"""
|
||||
# 获取页面参数
|
||||
self.fetch_checkout_page()
|
||||
|
||||
# Step 1: 创建支付方式
|
||||
payment_method_id = self.create_payment_method(
|
||||
iban, name, email, address, city, postal_code, country
|
||||
)
|
||||
if not payment_method_id:
|
||||
return False, "创建支付方式失败"
|
||||
|
||||
# Step 2: 确认支付
|
||||
success, error = self.confirm_payment(payment_method_id)
|
||||
if not success:
|
||||
return False, error
|
||||
|
||||
# Step 3: 轮询状态
|
||||
state, error = self.poll_payment_status(15)
|
||||
if state == "succeeded":
|
||||
return True, ""
|
||||
|
||||
return False, error or f"支付失败: {state}"
|
||||
|
||||
|
||||
def api_payment_with_retry(checkout_url: str, email: str, session=None, proxy: str = None,
|
||||
max_retries: int = 3, get_iban_func=None,
|
||||
get_address_func=None, get_name_func=None,
|
||||
progress_callback=None) -> tuple:
|
||||
"""使用 API 完成支付流程(带 IBAN 重试)
|
||||
|
||||
Args:
|
||||
checkout_url: Stripe checkout URL
|
||||
email: 邮箱地址
|
||||
session: 可选的 curl_cffi session
|
||||
proxy: 代理地址
|
||||
max_retries: 最大重试次数
|
||||
get_iban_func: 获取 IBAN 的函数,签名: func() -> str
|
||||
get_address_func: 获取地址的函数,签名: func() -> tuple(street, postal_code, city)
|
||||
get_name_func: 获取姓名的函数,签名: func() -> str
|
||||
progress_callback: 进度回调函数
|
||||
|
||||
Returns:
|
||||
tuple: (success: bool, error_message: str)
|
||||
"""
|
||||
def log_cb(msg):
|
||||
if progress_callback:
|
||||
progress_callback(msg)
|
||||
else:
|
||||
log_progress(msg)
|
||||
|
||||
# 默认的 IBAN/地址/姓名生成函数
|
||||
if get_iban_func is None:
|
||||
def get_iban_func():
|
||||
# 从 auto_gpt_team 导入
|
||||
try:
|
||||
from auto_gpt_team import get_sepa_ibans
|
||||
ibans = get_sepa_ibans()
|
||||
return random.choice(ibans) if ibans else ""
|
||||
except:
|
||||
return ""
|
||||
|
||||
if get_address_func is None:
|
||||
def get_address_func():
|
||||
try:
|
||||
from auto_gpt_team import SEPA_ADDRESSES
|
||||
return random.choice(SEPA_ADDRESSES)
|
||||
except:
|
||||
return ("Alexanderplatz 1", "10178", "Berlin")
|
||||
|
||||
if get_name_func is None:
|
||||
def get_name_func():
|
||||
try:
|
||||
from auto_gpt_team import FIRST_NAMES, LAST_NAMES
|
||||
return f"{random.choice(FIRST_NAMES)} {random.choice(LAST_NAMES)}"
|
||||
except:
|
||||
return "Max Mustermann"
|
||||
|
||||
# 初始化 Stripe 支付处理器
|
||||
stripe_handler = StripePaymentAPI(checkout_url, session=session, proxy=proxy)
|
||||
|
||||
last_error = ""
|
||||
|
||||
for retry in range(max_retries):
|
||||
# 生成支付信息
|
||||
iban = get_iban_func()
|
||||
if not iban:
|
||||
return False, "没有可用的 IBAN"
|
||||
|
||||
street, postal_code, city = get_address_func()
|
||||
account_name = get_name_func()
|
||||
|
||||
if retry == 0:
|
||||
log_status("API支付", "SEPA 支付处理中...")
|
||||
log_cb(f"IBAN: {iban[:8]}...")
|
||||
log_cb(f"地址: {street}, {postal_code} {city}")
|
||||
log_cb(f"姓名: {account_name}")
|
||||
else:
|
||||
log_cb(f"[!] 重试 {retry}/{max_retries-1},更换 IBAN...")
|
||||
log_cb(f"新 IBAN: {iban[:8]}...")
|
||||
|
||||
success, error = stripe_handler.complete_payment(
|
||||
iban, account_name, email, street, city, postal_code, "DE"
|
||||
)
|
||||
|
||||
if success:
|
||||
log_status("API支付", "[OK] 支付成功")
|
||||
return True, ""
|
||||
|
||||
last_error = error
|
||||
|
||||
# 分析错误类型,决定是否重试
|
||||
error_lower = error.lower() if error else ""
|
||||
|
||||
# IBAN/BIC 相关错误 - 换 IBAN 重试
|
||||
if "bank_account_unusable" in error_lower or "bic" in error_lower or "iban" in error_lower:
|
||||
log_cb(f"[!] IBAN 无效: {error}")
|
||||
if retry < max_retries - 1:
|
||||
continue
|
||||
|
||||
# 可恢复错误 - 重试
|
||||
retryable_errors = ["400", "500", "timeout", "eof", "connection", "确认失败"]
|
||||
is_retryable = any(e in error_lower for e in retryable_errors)
|
||||
|
||||
if is_retryable and retry < max_retries - 1:
|
||||
log_cb(f"[!] 支付错误: {error},重试中...")
|
||||
time.sleep(1)
|
||||
continue
|
||||
|
||||
# 不可恢复错误或重试用尽
|
||||
break
|
||||
|
||||
log_status("API支付", f"[X] 支付失败: {last_error}")
|
||||
return False, last_error
|
||||
|
||||
|
||||
def is_stripe_api_available() -> bool:
|
||||
"""检查 Stripe API 模式是否可用"""
|
||||
return CURL_CFFI_AVAILABLE
|
||||
130
telegram_bot.py
130
telegram_bot.py
@@ -3861,6 +3861,13 @@ class ProvisionerBot:
|
||||
api_supported = False
|
||||
current_mode = "browser"
|
||||
|
||||
# 获取当前并发数
|
||||
try:
|
||||
from config import CONCURRENT_WORKERS, CONCURRENT_ENABLED
|
||||
current_workers = CONCURRENT_WORKERS if CONCURRENT_ENABLED else 1
|
||||
except ImportError:
|
||||
current_workers = 1
|
||||
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton("📋 查看配置", callback_data="autogptplus:config"),
|
||||
@@ -3887,6 +3894,11 @@ class ProvisionerBot:
|
||||
InlineKeyboardButton(f"⚙️ 注册模式: {mode_icon} {mode_text}", callback_data="autogptplus:select_mode"),
|
||||
])
|
||||
|
||||
# 添加并发设置按钮
|
||||
keyboard.append([
|
||||
InlineKeyboardButton(f"⚡ 并发数: {current_workers}", callback_data="autogptplus:set_concurrent"),
|
||||
])
|
||||
|
||||
keyboard.append([
|
||||
InlineKeyboardButton("🚀 开始注册", callback_data="autogptplus:register"),
|
||||
])
|
||||
@@ -3932,6 +3944,10 @@ class ProvisionerBot:
|
||||
await self._set_autogptplus_mode(query, sub_action)
|
||||
elif action == "register":
|
||||
await self._start_autogptplus_register(query, context)
|
||||
elif action == "set_concurrent":
|
||||
await self._show_autogptplus_concurrent_selection(query)
|
||||
elif action == "concurrent":
|
||||
await self._set_autogptplus_concurrent(query, sub_action)
|
||||
elif action == "back":
|
||||
# 返回主菜单
|
||||
await query.edit_message_text(
|
||||
@@ -4086,7 +4102,119 @@ class ProvisionerBot:
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
|
||||
async def _test_autogptplus_email(self, query):
|
||||
async def _show_autogptplus_concurrent_selection(self, query):
|
||||
"""显示并发数选择界面"""
|
||||
try:
|
||||
from config import CONCURRENT_WORKERS, CONCURRENT_ENABLED
|
||||
current_workers = CONCURRENT_WORKERS if CONCURRENT_ENABLED else 1
|
||||
except ImportError:
|
||||
current_workers = 1
|
||||
|
||||
keyboard = [
|
||||
[
|
||||
InlineKeyboardButton(
|
||||
f"{'✅ ' if current_workers == 1 else ''}1 并发",
|
||||
callback_data="autogptplus:concurrent:1"
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
f"{'✅ ' if current_workers == 3 else ''}3 并发",
|
||||
callback_data="autogptplus:concurrent:3"
|
||||
),
|
||||
InlineKeyboardButton(
|
||||
f"{'✅ ' if current_workers == 5 else ''}5 并发",
|
||||
callback_data="autogptplus:concurrent:5"
|
||||
),
|
||||
],
|
||||
[InlineKeyboardButton("◀️ 返回", callback_data="autogptplus:back")],
|
||||
]
|
||||
reply_markup = InlineKeyboardMarkup(keyboard)
|
||||
|
||||
await query.edit_message_text(
|
||||
"<b>⚡ 设置并发数</b>\n\n"
|
||||
f"当前并发数: <b>{current_workers}</b>\n\n"
|
||||
"选择注册时的并发数量:\n"
|
||||
"• 1 并发 - 稳定,适合测试\n"
|
||||
"• 3 并发 - 平衡速度和稳定性\n"
|
||||
"• 5 并发 - 最快,需要较好的网络",
|
||||
parse_mode="HTML",
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
|
||||
async def _set_autogptplus_concurrent(self, query, workers_str: str):
|
||||
"""设置并发数"""
|
||||
try:
|
||||
workers = int(workers_str)
|
||||
if workers not in [1, 3, 5]:
|
||||
await query.answer("❌ 无效的并发数", show_alert=True)
|
||||
return
|
||||
except ValueError:
|
||||
await query.answer("❌ 无效的并发数", show_alert=True)
|
||||
return
|
||||
|
||||
# 更新 config.toml
|
||||
try:
|
||||
from config import CONFIG_FILE
|
||||
|
||||
# 读取当前配置文件
|
||||
with open(CONFIG_FILE, "r", encoding="utf-8") as f:
|
||||
content = f.read()
|
||||
|
||||
# 检查是否存在 [concurrent] section
|
||||
if "[concurrent]" not in content:
|
||||
# 添加 [concurrent] section
|
||||
content += f"\n\n[concurrent]\nenabled = true\nworkers = {workers}\n"
|
||||
else:
|
||||
# 更新 workers 值
|
||||
import re
|
||||
# 更新 enabled
|
||||
if re.search(r"^\s*enabled\s*=", content, re.MULTILINE):
|
||||
content = re.sub(
|
||||
r"^(\s*enabled\s*=\s*).*$",
|
||||
f"\\g<1>true",
|
||||
content,
|
||||
flags=re.MULTILINE
|
||||
)
|
||||
else:
|
||||
# 在 [concurrent] 后添加 enabled
|
||||
content = content.replace("[concurrent]", "[concurrent]\nenabled = true")
|
||||
|
||||
# 更新 workers
|
||||
if re.search(r"^\s*workers\s*=", content, re.MULTILINE):
|
||||
content = re.sub(
|
||||
r"^(\s*workers\s*=\s*).*$",
|
||||
f"\\g<1>{workers}",
|
||||
content,
|
||||
flags=re.MULTILINE
|
||||
)
|
||||
else:
|
||||
# 在 [concurrent] section 中添加 workers
|
||||
content = re.sub(
|
||||
r"(\[concurrent\][^\[]*)",
|
||||
f"\\g<1>workers = {workers}\n",
|
||||
content
|
||||
)
|
||||
|
||||
# 写回配置文件
|
||||
with open(CONFIG_FILE, "w", encoding="utf-8") as f:
|
||||
f.write(content)
|
||||
|
||||
# 重载配置
|
||||
from config import reload_config
|
||||
reload_config()
|
||||
|
||||
await query.answer(f"✅ 并发数已设置为 {workers}", show_alert=True)
|
||||
|
||||
# 返回主菜单
|
||||
await query.edit_message_text(
|
||||
"<b>🤖 AutoGPTPlus 管理面板</b>\n\n"
|
||||
"ChatGPT 订阅自动化配置管理\n\n"
|
||||
"请选择功能:",
|
||||
parse_mode="HTML",
|
||||
reply_markup=self._get_autogptplus_main_keyboard()
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
await query.answer(f"❌ 设置失败: {e}", show_alert=True)
|
||||
"""测试 AutoGPTPlus 邮件创建"""
|
||||
await query.edit_message_text("⏳ 正在测试邮件创建...")
|
||||
|
||||
|
||||
Reference in New Issue
Block a user