chatgpt2api / web /src /lib /api.ts
tx1538's picture
Upload 179 files
9d7ddb9 verified
Raw
History Blame
21.6 kB
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<string, unknown> | 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<string, unknown>;
[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<Record<string, unknown>>;
};
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<LoginResponse>("/auth/login", {
method: "POST",
body: {},
headers: {
Authorization: `Bearer ${normalizedAuthKey}`,
},
redirectOnUnauthorized: false,
});
}
export async function fetchAccounts() {
return httpRequest<AccountListResponse>("/api/accounts");
}
export async function createAccounts(tokens: string[]) {
return httpRequest<AccountMutationResponse>("/api/accounts", {
method: "POST",
body: { tokens },
});
}
export async function deleteAccounts(tokens: string[]) {
return httpRequest<AccountMutationResponse>("/api/accounts", {
method: "DELETE",
body: { tokens },
});
}
export async function refreshAccounts(accessTokens: string[]) {
return httpRequest<AccountRefreshResponse>("/api/accounts/refresh", {
method: "POST",
body: { access_tokens: accessTokens },
});
}
export async function updateAccount(
accessToken: string,
updates: {
type?: AccountType;
status?: AccountStatus;
quota?: number;
},
) {
return httpRequest<AccountUpdateResponse>("/api/accounts/update", {
method: "POST",
body: {
access_token: accessToken,
...updates,
},
});
}
export async function generateImage(prompt: string, model?: ImageModel, size?: string) {
return httpRequest<ImageResponse>(
"/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<ImageResponse>(
"/v1/images/edits",
{
method: "POST",
body: formData,
},
);
}
export async function createImageGenerationTask(clientTaskId: string, prompt: string, model?: ImageModel, size?: string) {
return httpRequest<ImageTask>("/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<ImageTask>("/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<ImageTaskListResponse>(`/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<RegisterConfig>) {
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<OpenAIKeyListResponse>("/api/openai-keys");
}
export async function createOpenAIKey(name: string, key: string, check = true) {
return httpRequest<Required<Pick<OpenAIKeyMutationResponse, "item">> & OpenAIKeyMutationResponse>("/api/openai-keys", {
method: "POST",
body: { name, key, check },
});
}
export async function checkOpenAIKey(keyId: string) {
return httpRequest<Required<Pick<OpenAIKeyMutationResponse, "item">> & OpenAIKeyMutationResponse>(
`/api/openai-keys/${keyId}/check`,
{ method: "POST" },
);
}
export async function deleteOpenAIKey(keyId: string) {
return httpRequest<OpenAIKeyListResponse>(`/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 ?? "" },
});
}