mirror of
https://github.com/zc-zhangchen/any-auto-register.git
synced 2026-05-07 15:54:07 +08:00
183 lines
6.4 KiB
Python
183 lines
6.4 KiB
Python
"""ChatGPT 专用功能 API"""
|
||
from fastapi import APIRouter, Depends, HTTPException
|
||
from sqlmodel import Session
|
||
from pydantic import BaseModel
|
||
from typing import Optional
|
||
from core.db import AccountModel, get_session
|
||
from services.chatgpt_account_state import apply_chatgpt_status_policy
|
||
import json, sys
|
||
|
||
|
||
router = APIRouter(prefix="/chatgpt", tags=["chatgpt"])
|
||
|
||
COUNTRIES = ["SG", "US", "TR", "JP", "HK", "GB", "AU", "CA", "IN", "BR", "MX"]
|
||
|
||
|
||
class UploadRequest(BaseModel):
|
||
account_ids: list[int]
|
||
cpa_api_url: Optional[str] = None
|
||
cpa_api_token: Optional[str] = None
|
||
team_manager_url: Optional[str] = None
|
||
team_manager_key: Optional[str] = None
|
||
|
||
|
||
def _get_account(account_id: int, session: Session) -> AccountModel:
|
||
acc = session.get(AccountModel, account_id)
|
||
if not acc or acc.platform != "chatgpt":
|
||
raise HTTPException(404, "账号不存在")
|
||
return acc
|
||
|
||
|
||
def _to_codex_account(acc: AccountModel):
|
||
"""转换为 codex-register 的 Account 对象(duck-typing)"""
|
||
extra = acc.get_extra()
|
||
|
||
class _Acc:
|
||
pass
|
||
|
||
a = _Acc()
|
||
a.email = acc.email
|
||
a.access_token = extra.get("access_token") or acc.token
|
||
a.refresh_token = extra.get("refresh_token", "")
|
||
a.id_token = extra.get("id_token", "")
|
||
a.session_token = extra.get("session_token", "")
|
||
a.client_id = extra.get("client_id", "app_EMoamEEZ73f0CkXaXp7hrann")
|
||
a.cookies = extra.get("cookies", "")
|
||
a.user_id = acc.user_id
|
||
return a
|
||
|
||
|
||
def _persist_local_probe(acc: AccountModel, probe: dict, session: Session) -> None:
|
||
extra = acc.get_extra()
|
||
extra["chatgpt_local"] = probe
|
||
acc.set_extra(extra)
|
||
apply_chatgpt_status_policy(acc, local_probe=probe)
|
||
from datetime import datetime
|
||
acc.updated_at = datetime.utcnow()
|
||
session.add(acc)
|
||
session.commit()
|
||
|
||
|
||
# ── Token 刷新 ──────────────────────────────────────────────
|
||
@router.post("/{account_id}/refresh-token")
|
||
def refresh_token(account_id: int, proxy: Optional[str] = None,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.token_refresh import TokenRefreshManager
|
||
manager = TokenRefreshManager(proxy_url=proxy)
|
||
result = manager.refresh_account(codex_acc)
|
||
|
||
if result.success:
|
||
extra = acc.get_extra()
|
||
extra["access_token"] = result.access_token
|
||
if result.refresh_token:
|
||
extra["refresh_token"] = result.refresh_token
|
||
acc.set_extra(extra)
|
||
acc.token = result.access_token
|
||
from datetime import datetime
|
||
acc.updated_at = datetime.utcnow()
|
||
session.add(acc)
|
||
session.commit()
|
||
return {"ok": True, "access_token": result.access_token[:40] + "..."}
|
||
raise HTTPException(400, result.error_message)
|
||
|
||
|
||
# ── 生成支付链接 ────────────────────────────────────────────
|
||
class PaymentReq(BaseModel):
|
||
plan: str = "plus" # plus | team
|
||
country: str = "SG"
|
||
proxy: Optional[str] = None
|
||
workspace_name: str = "MyTeam"
|
||
seat_quantity: int = 5
|
||
price_interval: str = "month"
|
||
|
||
|
||
@router.post("/{account_id}/payment-link")
|
||
def generate_payment_link(account_id: int, req: PaymentReq,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.payment import generate_plus_link, generate_team_link
|
||
if req.plan == "plus":
|
||
url = generate_plus_link(codex_acc, proxy=req.proxy, country=req.country)
|
||
else:
|
||
url = generate_team_link(
|
||
codex_acc, workspace_name=req.workspace_name,
|
||
price_interval=req.price_interval, seat_quantity=req.seat_quantity,
|
||
proxy=req.proxy, country=req.country
|
||
)
|
||
return {"url": url, "plan": req.plan, "country": req.country}
|
||
|
||
|
||
# ── 检查订阅状态 ────────────────────────────────────────────
|
||
@router.get("/{account_id}/subscription")
|
||
def check_subscription(account_id: int, proxy: Optional[str] = None,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.status_probe import probe_local_chatgpt_status
|
||
|
||
probe = probe_local_chatgpt_status(codex_acc, proxy=proxy)
|
||
_persist_local_probe(acc, probe, session)
|
||
return {
|
||
"email": acc.email,
|
||
"subscription": probe.get("subscription", {}).get("plan", "unknown"),
|
||
"probe": probe,
|
||
}
|
||
|
||
|
||
@router.post("/{account_id}/probe-local")
|
||
def probe_local_status(account_id: int, proxy: Optional[str] = None,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.status_probe import probe_local_chatgpt_status
|
||
|
||
probe = probe_local_chatgpt_status(codex_acc, proxy=proxy)
|
||
_persist_local_probe(acc, probe, session)
|
||
return {"ok": True, "email": acc.email, "probe": probe}
|
||
|
||
|
||
# ── CPA 上传 ────────────────────────────────────────────────
|
||
class CpaUploadReq(BaseModel):
|
||
api_url: str
|
||
api_key: str = ""
|
||
|
||
|
||
@router.post("/{account_id}/upload-cpa")
|
||
def upload_cpa(account_id: int, req: CpaUploadReq,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.cpa_upload import upload_to_cpa, generate_token_json
|
||
token_data = generate_token_json(codex_acc)
|
||
ok, msg = upload_to_cpa(token_data, api_url=req.api_url, api_key=req.api_key)
|
||
return {"ok": ok, "message": msg}
|
||
|
||
|
||
class Sub2ApiUploadReq(BaseModel):
|
||
api_url: str
|
||
api_key: str = ""
|
||
|
||
|
||
@router.post("/{account_id}/upload-sub2api")
|
||
def upload_sub2api(account_id: int, req: Sub2ApiUploadReq,
|
||
session: Session = Depends(get_session)):
|
||
acc = _get_account(account_id, session)
|
||
codex_acc = _to_codex_account(acc)
|
||
|
||
from platforms.chatgpt.sub2api_upload import upload_to_sub2api
|
||
|
||
ok, msg = upload_to_sub2api(
|
||
codex_acc,
|
||
api_url=req.api_url,
|
||
api_key=req.api_key,
|
||
)
|
||
return {"ok": ok, "message": msg}
|