import { httpRequest, request } from "@/lib/request"; export type AccountType = string; export type AccountStatus = "正常" | "限流" | "异常" | "禁用"; export type ImageModel = "gpt-image-2" | "codex-gpt-image-2"; export type AuthRole = "admin" | "user"; export type Account = { access_token: string; type: AccountType; status: AccountStatus; quota: number; image_quota_unknown?: boolean; email?: string | null; password?: string | null; user_id?: string | null; limits_progress?: Array<{ feature_name?: string; remaining?: number; reset_after?: string; }>; default_model_slug?: string | null; restore_at?: string | null; success: number; fail: number; last_used_at?: string | null; }; type AccountListResponse = { items: Account[]; }; type AccountMutationResponse = { items: Account[]; added?: number; skipped?: number; removed?: number; refreshed?: number; errors?: Array<{ access_token: string; error: string }>; }; type AccountRefreshResponse = { items: Account[]; refreshed: number; errors: Array<{ access_token: string; error: string }>; }; type AccountUpdateResponse = { item: Account; items: Account[]; }; export type SettingsConfig = { proxy: string; base_url?: string; global_system_prompt?: string; sensitive_words?: string[]; ai_review?: { enabled?: boolean; base_url?: string; api_key?: string; model?: string; prompt?: string; }; refresh_account_interval_minute?: number | string; image_retention_days?: number | string; image_poll_timeout_secs?: number | string; image_account_concurrency?: number | string; auto_remove_invalid_accounts?: boolean; auto_remove_rate_limited_accounts?: boolean; log_levels?: string[]; backup?: BackupSettings; backup_state?: BackupState; [key: string]: unknown; }; export type BackupInclude = { config: boolean; register: boolean; cpa: boolean; sub2api: boolean; logs: boolean; image_tasks: boolean; accounts_snapshot: boolean; auth_keys_snapshot: boolean; images: boolean; }; export type BackupSettings = { enabled: boolean; provider: "cloudflare_r2" | string; account_id: string; access_key_id: string; secret_access_key: string; bucket: string; prefix: string; interval_minutes: number | string; rotation_keep: number | string; encrypt: boolean; passphrase: string; include: BackupInclude; }; export type BackupState = { running: boolean; last_started_at?: string | null; last_finished_at?: string | null; last_status?: string; last_error?: string | null; last_object_key?: string | null; }; export type BackupItem = { key: string; name: string; size: number; updated_at?: string | null; encrypted: boolean; }; export type BackupDetail = { key: string; name: string; encrypted: boolean; created_at?: string | null; trigger?: string | null; app_version?: string | null; storage_backend?: Record | null; files: Array<{ name: string; exists: boolean; content_type?: string; size: number; sha256?: string; }>; snapshots: Array<{ name: string; count: number; }>; }; export type ManagedImage = { rel: string; path?: string; name: string; date: string; size: number; url: string; thumbnail_url?: string; created_at: string; width?: number; height?: number; tags?: string[]; }; export type SystemLog = { id: string; time: string; type: "call" | "account" | string; summary?: string; detail?: Record; [key: string]: unknown; }; export type ImageResponse = { created: number; data: Array<{ b64_json?: string; url?: string; revised_prompt?: string }>; }; export type ImageTask = { id: string; status: "queued" | "running" | "success" | "error"; mode: "generate" | "edit"; model?: ImageModel; size?: string; created_at: string; updated_at: string; data?: Array<{ b64_json?: string; url?: string; revised_prompt?: string }>; error?: string; }; type ImageTaskListResponse = { items: ImageTask[]; missing_ids: string[]; }; export type LoginResponse = { ok: boolean; version: string; role: AuthRole; subject_id: string; name: string; }; export type UserKey = { id: string; name: string; role: "user"; enabled: boolean; created_at: string | null; last_used_at: string | null; }; export type RegisterConfig = { enabled: boolean; mail: { request_timeout: number; wait_timeout: number; wait_interval: number; providers: Array>; }; hero_sms: { enabled: boolean; api_key: string; service: string; country: number; country_pool: number[]; country_blacklist: number[]; operator: string; wait_timeout: number; poll_interval: number; reuse_activation_id: string; reuse_phone: string; auto_buy: boolean; min_price_usd: number | string; max_price_usd: number | string; cancel_on_send_fail: boolean; }; proxy: string; total: number; threads: number; mode: "total" | "quota" | "available"; target_quota: number; target_available: number; check_interval: number; stats: { job_id?: string; success: number; fail: number; done: number; running: number; threads: number; elapsed_seconds?: number; avg_seconds?: number; success_rate?: number; current_quota?: number; current_available?: number; started_at?: string; updated_at?: string; finished_at?: string; }; logs?: Array<{ time: string; text: string; level: string; }>; }; export type OpenAIKeyStatus = "unchecked" | "ok" | "invalid" | "rate_limited" | "forbidden" | "error" | string; export type OpenAIKeyItem = { id: string; name: string; key_hint: string; status: OpenAIKeyStatus; http_status?: number | null; models_count: number; sample_models: string[]; last_error?: string | null; last_checked_at?: string | null; created_at: string; updated_at: string; }; type OpenAIKeyListResponse = { items: OpenAIKeyItem[]; }; type OpenAIKeyMutationResponse = { item?: OpenAIKeyItem; items: OpenAIKeyItem[]; }; export async function login(authKey: string) { const normalizedAuthKey = String(authKey || "").trim(); return httpRequest("/auth/login", { method: "POST", body: {}, headers: { Authorization: `Bearer ${normalizedAuthKey}`, }, redirectOnUnauthorized: false, }); } export async function fetchAccounts() { return httpRequest("/api/accounts"); } export async function createAccounts(tokens: string[]) { return httpRequest("/api/accounts", { method: "POST", body: { tokens }, }); } export async function deleteAccounts(tokens: string[]) { return httpRequest("/api/accounts", { method: "DELETE", body: { tokens }, }); } export async function refreshAccounts(accessTokens: string[]) { return httpRequest("/api/accounts/refresh", { method: "POST", body: { access_tokens: accessTokens }, }); } export async function updateAccount( accessToken: string, updates: { type?: AccountType; status?: AccountStatus; quota?: number; }, ) { return httpRequest("/api/accounts/update", { method: "POST", body: { access_token: accessToken, ...updates, }, }); } export async function generateImage(prompt: string, model?: ImageModel, size?: string) { return httpRequest( "/v1/images/generations", { method: "POST", body: { prompt, ...(model ? { model } : {}), ...(size ? { size } : {}), n: 1, response_format: "b64_json", }, }, ); } export async function editImage(files: File | File[], prompt: string, model?: ImageModel, size?: string) { const formData = new FormData(); const uploadFiles = Array.isArray(files) ? files : [files]; uploadFiles.forEach((file) => { formData.append("image", file); }); formData.append("prompt", prompt); if (model) { formData.append("model", model); } if (size) { formData.append("size", size); } formData.append("n", "1"); return httpRequest( "/v1/images/edits", { method: "POST", body: formData, }, ); } export async function createImageGenerationTask(clientTaskId: string, prompt: string, model?: ImageModel, size?: string) { return httpRequest("/api/image-tasks/generations", { method: "POST", body: { client_task_id: clientTaskId, prompt, ...(model ? { model } : {}), ...(size ? { size } : {}), }, }); } export async function createImageEditTask( clientTaskId: string, files: File | File[], prompt: string, model?: ImageModel, size?: string, ) { const formData = new FormData(); const uploadFiles = Array.isArray(files) ? files : [files]; uploadFiles.forEach((file) => { formData.append("image", file); }); formData.append("client_task_id", clientTaskId); formData.append("prompt", prompt); if (model) { formData.append("model", model); } if (size) { formData.append("size", size); } return httpRequest("/api/image-tasks/edits", { method: "POST", body: formData, }); } export async function fetchImageTasks(ids: string[]) { const params = new URLSearchParams(); if (ids.length > 0) { params.set("ids", ids.join(",")); } return httpRequest(`/api/image-tasks${params.toString() ? `?${params.toString()}` : ""}`); } export async function fetchSettingsConfig() { return httpRequest<{ config: SettingsConfig }>("/api/settings"); } export async function updateSettingsConfig(settings: SettingsConfig) { return httpRequest<{ config: SettingsConfig }>("/api/settings", { method: "POST", body: settings, }); } export async function testBackupConnection() { return httpRequest<{ result: { ok: boolean; status: number } }>("/api/backup/test", { method: "POST", body: {}, }); } export async function fetchBackups() { return httpRequest<{ items: BackupItem[]; state: BackupState; settings: BackupSettings }>("/api/backups"); } export async function runBackupNow() { return httpRequest<{ result: { key: string; size: number; encrypted: boolean } }>("/api/backups/run", { method: "POST", body: {}, }); } export async function deleteBackup(key: string) { return httpRequest<{ ok: boolean }>("/api/backups/delete", { method: "POST", body: { key }, }); } export async function fetchBackupDetail(key: string) { const params = new URLSearchParams(); params.set("key", key); return httpRequest<{ item: BackupDetail }>(`/api/backups/detail?${params.toString()}`); } export function getBackupDownloadUrl(key: string) { const params = new URLSearchParams(); params.set("key", key); return `/api/backups/download?${params.toString()}`; } export async function fetchManagedImages(filters: { start_date?: string; end_date?: string }) { const params = new URLSearchParams(); if (filters.start_date) params.set("start_date", filters.start_date); if (filters.end_date) params.set("end_date", filters.end_date); return httpRequest<{ items: ManagedImage[]; groups: Array<{ date: string; items: ManagedImage[] }> }>( `/api/images${params.toString() ? `?${params.toString()}` : ""}`, ); } export async function deleteManagedImages(body: { paths?: string[]; start_date?: string; end_date?: string; all_matching?: boolean }) { return httpRequest<{ removed: number }>("/api/images/delete", { method: "POST", body }); } export async function downloadImages(paths: string[]) { const response = await request.post("/api/images/download", { paths }, { responseType: "blob" }); const blob = response.data as Blob; const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = "images.zip"; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } export async function downloadSingleImage(path: string) { const response = await request.get(`/api/images/download/${path}`, { responseType: "blob" }); const blob = response.data as Blob; const url = URL.createObjectURL(blob); const a = document.createElement("a"); a.href = url; a.download = path.split("/").pop() || "image.png"; document.body.appendChild(a); a.click(); document.body.removeChild(a); URL.revokeObjectURL(url); } export async function fetchImageTags() { return httpRequest<{ tags: string[] }>("/api/images/tags"); } export async function setImageTags(path: string, tags: string[]) { return httpRequest<{ ok: boolean; tags: string[] }>("/api/images/tags", { method: "POST", body: { path, tags }, }); } export async function deleteImageTag(tag: string) { return httpRequest<{ ok: boolean; removed_from: number }>(`/api/images/tags/${encodeURIComponent(tag)}`, { method: "DELETE", }); } export async function fetchSystemLogs(filters: { type?: string; start_date?: string; end_date?: string }) { const params = new URLSearchParams(); if (filters.type) params.set("type", filters.type); if (filters.start_date) params.set("start_date", filters.start_date); if (filters.end_date) params.set("end_date", filters.end_date); return httpRequest<{ items: SystemLog[] }>(`/api/logs${params.toString() ? `?${params.toString()}` : ""}`); } export async function deleteSystemLogs(ids: string[]) { return httpRequest<{ removed: number }>("/api/logs/delete", { method: "POST", body: { ids }, }); } export async function fetchUserKeys() { return httpRequest<{ items: UserKey[] }>("/api/auth/users"); } export async function createUserKey(name: string) { return httpRequest<{ item: UserKey; key: string; items: UserKey[] }>("/api/auth/users", { method: "POST", body: { name }, }); } export async function updateUserKey(keyId: string, updates: { enabled?: boolean; name?: string; key?: string }) { return httpRequest<{ item: UserKey; items: UserKey[] }>(`/api/auth/users/${keyId}`, { method: "POST", body: updates, }); } export async function deleteUserKey(keyId: string) { return httpRequest<{ items: UserKey[] }>(`/api/auth/users/${keyId}`, { method: "DELETE", }); } export async function fetchRegisterConfig() { return httpRequest<{ register: RegisterConfig }>("/api/register"); } export async function updateRegisterConfig(updates: Partial) { return httpRequest<{ register: RegisterConfig }>("/api/register", { method: "POST", body: updates, }); } export async function startRegister() { return httpRequest<{ register: RegisterConfig }>("/api/register/start", { method: "POST" }); } export async function startCodexRegister() { return httpRequest<{ register: RegisterConfig }>("/api/register/codex/start", { method: "POST" }); } export async function stopRegister() { return httpRequest<{ register: RegisterConfig }>("/api/register/stop", { method: "POST" }); } export async function resetRegister() { return httpRequest<{ register: RegisterConfig }>("/api/register/reset", { method: "POST" }); } // ── Official OpenAI API Keys ────────────────────────────────────── export async function fetchOpenAIKeys() { return httpRequest("/api/openai-keys"); } export async function createOpenAIKey(name: string, key: string, check = true) { return httpRequest> & OpenAIKeyMutationResponse>("/api/openai-keys", { method: "POST", body: { name, key, check }, }); } export async function checkOpenAIKey(keyId: string) { return httpRequest> & OpenAIKeyMutationResponse>( `/api/openai-keys/${keyId}/check`, { method: "POST" }, ); } export async function deleteOpenAIKey(keyId: string) { return httpRequest(`/api/openai-keys/${keyId}`, { method: "DELETE", }); } // ── CPA (CLIProxyAPI) ────────────────────────────────────────────── export type CPAPool = { id: string; name: string; base_url: string; import_job?: CPAImportJob | null; }; export type CPARemoteFile = { name: string; email: string; }; export type CPAImportJob = { job_id: string; status: "pending" | "running" | "completed" | "failed"; created_at: string; updated_at: string; total: number; completed: number; added: number; skipped: number; refreshed: number; failed: number; errors: Array<{ name: string; error: string }>; }; export async function fetchCPAPools() { return httpRequest<{ pools: CPAPool[] }>("/api/cpa/pools"); } export async function createCPAPool(pool: { name: string; base_url: string; secret_key: string }) { return httpRequest<{ pool: CPAPool; pools: CPAPool[] }>("/api/cpa/pools", { method: "POST", body: pool, }); } export async function updateCPAPool( poolId: string, updates: { name?: string; base_url?: string; secret_key?: string }, ) { return httpRequest<{ pool: CPAPool; pools: CPAPool[] }>(`/api/cpa/pools/${poolId}`, { method: "POST", body: updates, }); } export async function deleteCPAPool(poolId: string) { return httpRequest<{ pools: CPAPool[] }>(`/api/cpa/pools/${poolId}`, { method: "DELETE", }); } export async function fetchCPAPoolFiles(poolId: string) { return httpRequest<{ pool_id: string; files: CPARemoteFile[] }>(`/api/cpa/pools/${poolId}/files`); } export async function startCPAImport(poolId: string, names: string[]) { return httpRequest<{ import_job: CPAImportJob | null }>(`/api/cpa/pools/${poolId}/import`, { method: "POST", body: { names }, }); } export async function fetchCPAPoolImportJob(poolId: string) { return httpRequest<{ import_job: CPAImportJob | null }>(`/api/cpa/pools/${poolId}/import`); } // ── Sub2API ──────────────────────────────────────────────────────── export type Sub2APIServer = { id: string; name: string; base_url: string; email: string; has_api_key: boolean; group_id: string; import_job?: CPAImportJob | null; }; export type Sub2APIRemoteAccount = { id: string; name: string; email: string; plan_type: string; status: string; expires_at: string; has_refresh_token: boolean; }; export type Sub2APIRemoteGroup = { id: string; name: string; description: string; platform: string; status: string; account_count: number; active_account_count: number; }; export async function fetchSub2APIServers() { return httpRequest<{ servers: Sub2APIServer[] }>("/api/sub2api/servers"); } export async function createSub2APIServer(server: { name: string; base_url: string; email: string; password: string; api_key: string; group_id: string; }) { return httpRequest<{ server: Sub2APIServer; servers: Sub2APIServer[] }>("/api/sub2api/servers", { method: "POST", body: server, }); } export async function updateSub2APIServer( serverId: string, updates: { name?: string; base_url?: string; email?: string; password?: string; api_key?: string; group_id?: string; }, ) { return httpRequest<{ server: Sub2APIServer; servers: Sub2APIServer[] }>(`/api/sub2api/servers/${serverId}`, { method: "POST", body: updates, }); } export async function fetchSub2APIServerGroups(serverId: string) { return httpRequest<{ server_id: string; groups: Sub2APIRemoteGroup[] }>( `/api/sub2api/servers/${serverId}/groups`, ); } export async function deleteSub2APIServer(serverId: string) { return httpRequest<{ servers: Sub2APIServer[] }>(`/api/sub2api/servers/${serverId}`, { method: "DELETE", }); } export async function fetchSub2APIServerAccounts(serverId: string) { return httpRequest<{ server_id: string; accounts: Sub2APIRemoteAccount[] }>( `/api/sub2api/servers/${serverId}/accounts`, ); } export async function startSub2APIImport(serverId: string, accountIds: string[]) { return httpRequest<{ import_job: CPAImportJob | null }>(`/api/sub2api/servers/${serverId}/import`, { method: "POST", body: { account_ids: accountIds }, }); } export async function fetchSub2APIImportJob(serverId: string) { return httpRequest<{ import_job: CPAImportJob | null }>(`/api/sub2api/servers/${serverId}/import`); } // ── Upstream proxy ──────────────────────────────────────────────── export type ProxySettings = { enabled: boolean; url: string; }; export type ProxyTestResult = { ok: boolean; status: number; latency_ms: number; error: string | null; }; export async function fetchProxy() { return httpRequest<{ proxy: ProxySettings }>("/api/proxy"); } export async function updateProxy(updates: { enabled?: boolean; url?: string }) { return httpRequest<{ proxy: ProxySettings }>("/api/proxy", { method: "POST", body: updates, }); } export async function testProxy(url?: string) { return httpRequest<{ result: ProxyTestResult }>("/api/proxy/test", { method: "POST", body: { url: url ?? "" }, }); }