chore: rename frontend brand to BossAI

This commit is contained in:
boos
2026-05-25 21:27:50 +08:00
parent a1f3400af3
commit 294d227eba
23 changed files with 70 additions and 70 deletions
+9 -9
View File
@@ -1,6 +1,6 @@
<div align="center"> <div align="center">
# BoosAPI # BossAI
**AI 聚合网关 + Workflow Studio — 将分散的中转站整合为一个统一入口** **AI 聚合网关 + Workflow Studio — 将分散的中转站整合为一个统一入口**
@@ -36,7 +36,7 @@
现在 AI 生态里出现了越来越多基于 New API / One API 系列的聚合中转站,要管理多个站点的余额、模型列表和 API 密钥,往往既分散又费时。 现在 AI 生态里出现了越来越多基于 New API / One API 系列的聚合中转站,要管理多个站点的余额、模型列表和 API 密钥,往往既分散又费时。
**BoosAPI** 作为中转站之上的**元聚合层**,把多个站点统一到 **一个入口**——下游所有工具即可无感接入全部模型。 **BossAI** 作为中转站之上的**元聚合层**,把多个站点统一到 **一个入口**——下游所有工具即可无感接入全部模型。
支持的上游范围: 支持的上游范围:
@@ -45,7 +45,7 @@
- **官方预设**:阿里云、智谱、豆包 Coding Plan、DeepSeek、Moonshot、MiniMax、ModelScope - **官方预设**:阿里云、智谱、豆包 Coding Plan、DeepSeek、Moonshot、MiniMax、ModelScope
- **OAuth 连接**:Codex、Claude、Gemini CLI、Antigravity - **OAuth 连接**:Codex、Claude、Gemini CLI、Antigravity
| 痛点 | BoosAPI 怎么解决 | | 痛点 | BossAI 怎么解决 |
|------|-----------------| |------|-----------------|
| 🔑 每个站点一个 Key,下游配置一堆 | **统一代理入口 + 多下游 Key 策略**,模型自动聚合 | | 🔑 每个站点一个 Key,下游配置一堆 | **统一代理入口 + 多下游 Key 策略**,模型自动聚合 |
| 💸 不知道哪个站点最便宜 | **智能路由** 按成本、余额、使用率选最优通道 | | 💸 不知道哪个站点最便宜 | **智能路由** 按成本、余额、使用率选最优通道 |
@@ -53,7 +53,7 @@
| 📊 余额分散各处 | **集中看板** 一目了然,余额不足自动告警 | | 📊 余额分散各处 | **集中看板** 一目了然,余额不足自动告警 |
| ✅ 每天签到领额度 | **自动签到** 定时执行,奖励自动追踪 | | ✅ 每天签到领额度 | **自动签到** 定时执行,奖励自动追踪 |
| 🤷 不知道各站有什么模型 | **自动模型发现**,上游新增模型零配置 | | 🤷 不知道各站有什么模型 | **自动模型发现**,上游新增模型零配置 |
| 🎨 想编排图像/视频流程但不想跑本地模型 | **Workflow Studio + 对话助手**,直接复用 BoosAPI 模型路由 | | 🎨 想编排图像/视频流程但不想跑本地模型 | **Workflow Studio + 对话助手**,直接复用 BossAI 模型路由 |
| 👥 多人协作管理中转站 | **组织管理**,成员邀请,角色权限控制 | | 👥 多人协作管理中转站 | **组织管理**,成员邀请,角色权限控制 |
| 📋 不同团队需要不同配额 | **套餐系统**,Free/Pro/Enterprise 三级限制 | | 📋 不同团队需要不同配额 | **套餐系统**,Free/Pro/Enterprise 三级限制 |
@@ -63,7 +63,7 @@
![Workflow Studio 画布执行](docs/screenshots/workflow-canvas.png) ![Workflow Studio 画布执行](docs/screenshots/workflow-canvas.png)
![Workflow 中的 BoosAPI 模型](docs/screenshots/workflow-boosapi-models.png) ![Workflow 中的 BossAI 模型](docs/screenshots/workflow-boosapi-models.png)
--- ---
@@ -165,13 +165,13 @@
## 🖥️ 硬件配置建议 ## 🖥️ 硬件配置建议
BoosAPI 本身是 Rust 网关与管理后台,不在本地跑大模型推理时不需要 GPU。实际硬件主要取决于你是否把图像/视频生成放在本机 ComfyUI 上执行。 BossAI 本身是 Rust 网关与管理后台,不在本地跑大模型推理时不需要 GPU。实际硬件主要取决于你是否把图像/视频生成放在本机 ComfyUI 上执行。
| 使用模式 | CPU | 内存 | 磁盘 | GPU | | 使用模式 | CPU | 内存 | 磁盘 | GPU |
|----------|-----|------|------|-----| |----------|-----|------|------|-----|
| 仅网关 / 管理后台 / `/v1/*` 代理 | 2 核起步,4 核推荐 | 2GB 起步,4GB 推荐 | 10GB+ | 不需要 | | 仅网关 / 管理后台 / `/v1/*` 代理 | 2 核起步,4 核推荐 | 2GB 起步,4GB 推荐 | 10GB+ | 不需要 |
| BoosAPI + Workflow UI + 远程模型 API / Comfy Cloud / RunningHub | 4 核推荐 | 4GB 起步,8GB 推荐 | 20-50GB | 不需要 | | BossAI + Workflow UI + 远程模型 API / Comfy Cloud / RunningHub | 4 核推荐 | 4GB 起步,8GB 推荐 | 20-50GB | 不需要 |
| 外部独立 ComfyUI 代理 | 4 核推荐 | 8GB 推荐 | 50GB+ | BoosAPI 机器不需要;ComfyUI 机器按模型需求配置 | | 外部独立 ComfyUI 代理 | 4 核推荐 | 8GB 推荐 | 50GB+ | BossAI 机器不需要;ComfyUI 机器按模型需求配置 |
| 本机 Docker / 本地 ComfyUI 轻量文生图 | 4-8 核 | 16GB+ | 100GB+ | NVIDIA 8GB VRAM 勉强,12GB+ 推荐 | | 本机 Docker / 本地 ComfyUI 轻量文生图 | 4-8 核 | 16GB+ | 100GB+ | NVIDIA 8GB VRAM 勉强,12GB+ 推荐 |
| 本机视频生成 / 数字人 / 大工作流 | 8 核+ | 32GB 起步,64GB 推荐 | 200GB-1TB | NVIDIA 24GB VRAM 起步,48GB+ 更稳 | | 本机视频生成 / 数字人 / 大工作流 | 8 核+ | 32GB 起步,64GB 推荐 | 200GB-1TB | NVIDIA 24GB VRAM 起步,48GB+ 更稳 |
@@ -184,7 +184,7 @@ BoosAPI 本身是 Rust 网关与管理后台,不在本地跑大模型推理时
无需 GPU 无需 GPU
``` ```
如果图像、视频、语音能力走 BoosAPI 上游路由、Comfy Cloud、RunningHub 或其他远程 API,本机只负责网关、数据库、Workflow UI 代理、日志和 Workspace 归档,上面这档配置通常足够。只有把 ComfyUI 模型和视频生成放在本机运行时,才需要高显存 NVIDIA GPU。 如果图像、视频、语音能力走 BossAI 上游路由、Comfy Cloud、RunningHub 或其他远程 API,本机只负责网关、数据库、Workflow UI 代理、日志和 Workspace 归档,上面这档配置通常足够。只有把 ComfyUI 模型和视频生成放在本机运行时,才需要高显存 NVIDIA GPU。
## 🚀 快速开始 ## 🚀 快速开始
+13 -13
View File
@@ -1050,7 +1050,7 @@ async fn workflow_ui_index() -> Html<String> {
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>BoosAPI Workflow Studio</title> <title>BossAI Workflow Studio</title>
<style> <style>
html, body { margin: 0; width: 100%; height: 100%; background: #111827; color: #e5e7eb; font-family: system-ui, sans-serif; } html, body { margin: 0; width: 100%; height: 100%; background: #111827; color: #e5e7eb; font-family: system-ui, sans-serif; }
.wrap { display: grid; place-items: center; height: 100%; padding: 24px; text-align: center; } .wrap { display: grid; place-items: center; height: 100%; padding: 24px; text-align: center; }
@@ -1616,7 +1616,7 @@ async fn queue_prompt(
if graph.nodes.is_empty() { if graph.nodes.is_empty() {
return Ok(prompt_error_response( return Ok(prompt_error_response(
"画布里还没有可执行节点", "画布里还没有可执行节点",
"请先从左侧节点库添加 BoosAPI 节点并连接后再执行。", "请先从左侧节点库添加 BossAI 节点并连接后再执行。",
)); ));
} }
let name = payload let name = payload
@@ -2234,7 +2234,7 @@ fn run_status_messages(run: &crate::workflow::models::WorkflowRunSummary) -> Vec
"node_type": failed_node.map(|node| node.node_type.as_str()).unwrap_or("Workflow"), "node_type": failed_node.map(|node| node.node_type.as_str()).unwrap_or("Workflow"),
"executed": run.node_runs.iter().filter(|node| node.status == "completed").map(|node| node.node_id.clone()).collect::<Vec<_>>(), "executed": run.node_runs.iter().filter(|node| node.status == "completed").map(|node| node.node_id.clone()).collect::<Vec<_>>(),
"exception_message": run.error_message.clone().unwrap_or_else(|| "Workflow execution failed".to_string()), "exception_message": run.error_message.clone().unwrap_or_else(|| "Workflow execution failed".to_string()),
"exception_type": "BoosAPIWorkflowError", "exception_type": "BossAIWorkflowError",
"traceback": [], "traceback": [],
"current_inputs": failed_node.map(|node| node.inputs.clone()).unwrap_or_else(|| json!({})), "current_inputs": failed_node.map(|node| node.inputs.clone()).unwrap_or_else(|| json!({})),
"current_outputs": failed_node.and_then(|node| node.outputs.clone()).unwrap_or_else(|| json!({})), "current_outputs": failed_node.and_then(|node| node.outputs.clone()).unwrap_or_else(|| json!({})),
@@ -2356,7 +2356,7 @@ fn workflow_run_to_prompt_tuple(run: &crate::workflow::models::WorkflowRunSummar
.workflow_name .workflow_name
.as_deref() .as_deref()
.or(run.workflow_public_id.as_deref()) .or(run.workflow_public_id.as_deref())
.unwrap_or("BoosAPI workflow"); .unwrap_or("BossAI workflow");
let workflow = json!({ "name": workflow_name, "nodes": [], "links": [] }); let workflow = json!({ "name": workflow_name, "nodes": [], "links": [] });
let prompt = run let prompt = run
.node_runs .node_runs
@@ -2560,7 +2560,7 @@ fn workflow_progress_callback_with_run_sender(
"node_id": "workflow", "node_id": "workflow",
"node_type": "Workflow", "node_type": "Workflow",
"exception_message": error.unwrap_or_else(|| "Workflow execution failed".to_string()), "exception_message": error.unwrap_or_else(|| "Workflow execution failed".to_string()),
"exception_type": "BoosAPIWorkflowError", "exception_type": "BossAIWorkflowError",
"traceback": [], "traceback": [],
}) })
}, },
@@ -2638,7 +2638,7 @@ fn publish_run_events(
"node_id": run.node_runs.last().map(|node| node.node_id.as_str()).unwrap_or("workflow"), "node_id": run.node_runs.last().map(|node| node.node_id.as_str()).unwrap_or("workflow"),
"node_type": run.node_runs.last().map(|node| node.node_type.as_str()).unwrap_or("Workflow"), "node_type": run.node_runs.last().map(|node| node.node_type.as_str()).unwrap_or("Workflow"),
"exception_message": run.error_message.clone().unwrap_or_else(|| "Workflow execution failed".to_string()), "exception_message": run.error_message.clone().unwrap_or_else(|| "Workflow execution failed".to_string()),
"exception_type": "BoosAPIWorkflowError", "exception_type": "BossAIWorkflowError",
"traceback": [], "traceback": [],
}) })
} else { } else {
@@ -3139,16 +3139,16 @@ fn inject_bootstrap(html: String) -> String {
'CLIP': 'CLIP', 'CLIP': 'CLIP',
'VAE': 'VAE', 'VAE': 'VAE',
'CONDITIONING': '条件', 'CONDITIONING': '条件',
'BoosAPI': 'BoosAPI', 'BossAI': 'BossAI',
'boosapi.image_to_video': 'BoosAPI 图生视频', 'boosapi.image_to_video': 'BossAI 图生视频',
'boosapi.text_to_video': 'BoosAPI 文生视频', 'boosapi.text_to_video': 'BossAI 文生视频',
'boosapi.video_status': '查询视频任务', 'boosapi.video_status': '查询视频任务',
'output.preview_video': '输出:预览视频', 'output.preview_video': '输出:预览视频',
'output.preview_image': '输出:预览图像', 'output.preview_image': '输出:预览图像',
'input.text': '输入:文本', 'input.text': '输入:文本',
'boosapi.chat_completion': 'BoosAPI 对话', 'boosapi.chat_completion': 'BossAI 对话',
'boosapi.prompt_rewrite': 'BoosAPI 提示词改写', 'boosapi.prompt_rewrite': 'BossAI 提示词改写',
'boosapi.text_to_image': 'BoosAPI 文生图', 'boosapi.text_to_image': 'BossAI 文生图',
'output.save_file': '输出:保存文件' 'output.save_file': '输出:保存文件'
})); }));
const translateWorkflowText = (text) => { const translateWorkflowText = (text) => {
@@ -3350,7 +3350,7 @@ fn inject_bootstrap(html: String) -> String {
const graph = app?.graph || window.LGraphCanvas?.active_canvas?.graph; const graph = app?.graph || window.LGraphCanvas?.active_canvas?.graph;
const canvas = app?.canvas || window.LGraphCanvas?.active_canvas; const canvas = app?.canvas || window.LGraphCanvas?.active_canvas;
if (!graph) return false; if (!graph) return false;
const node = window.LiteGraph.createNode('boosapi.text_to_video', 'BoosAPI 文生视频'); const node = window.LiteGraph.createNode('boosapi.text_to_video', 'BossAI 文生视频');
if (!node) return false; if (!node) return false;
const area = canvas?.ds?.visible_area; const area = canvas?.ds?.visible_area;
node.pos = Array.isArray(area) ? [area[0] + area[2] / 2 - 190, area[1] + area[3] / 2 - 120] : [160, 160]; node.pos = Array.isArray(area) ? [area[0] + area[2] / 2 - 190, area[1] + area[3] / 2 - 120] : [160, 160];
+1 -1
View File
@@ -36,7 +36,7 @@ describe('Login surface', () => {
&& node.props.className.includes('brand-mark-canvas') && node.props.className.includes('brand-mark-canvas')
)); ));
expect(pageText).toContain('BoosAPI'); expect(pageText).toContain('BossAI');
expect(pageText).toContain('中转站的中转站'); expect(pageText).toContain('中转站的中转站');
expect(pageText).not.toContain('一个 API Key,一个入口'); expect(pageText).not.toContain('一个 API Key,一个入口');
expect(pageText).toContain('兼容 New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API'); expect(pageText).toContain('兼容 New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API');
+4 -4
View File
@@ -696,8 +696,8 @@ function AppShell() {
</button> </button>
)} )}
<div className="topbar-logo"> <div className="topbar-logo">
<img src="/logo.png" alt="BoosAPI" style={{ width: 28, height: 28, borderRadius: 6 }} /> <img src="/logo.png" alt="BossAI" style={{ width: 28, height: 28, borderRadius: 6 }} />
<span className="topbar-logo-text">BoosAPI</span> <span className="topbar-logo-text">BossAI</span>
</div> </div>
<nav className="topbar-nav"> <nav className="topbar-nav">
{currentTopNavItems.map((item) => ( {currentTopNavItems.map((item) => (
@@ -829,8 +829,8 @@ function AppShell() {
closeLabel={t('关闭导航')} closeLabel={t('关闭导航')}
> >
<div className="mobile-drawer-header"> <div className="mobile-drawer-header">
<img src="/logo.png" alt="BoosAPI" /> <img src="/logo.png" alt="BossAI" />
<span>BoosAPI</span> <span>BossAI</span>
</div> </div>
<nav className="mobile-nav"> <nav className="mobile-nav">
{currentSidebarGroups.map((group) => ( {currentSidebarGroups.map((group) => (
+3 -3
View File
@@ -191,7 +191,7 @@ export const zhToEnSupplemental: Record<string, string> = {
'共 ${models.length} 个模型': 'Total ${models.length} models', '共 ${models.length} 个模型': 'Total ${models.length} models',
'关闭': 'closure', '关闭': 'closure',
'关于': 'about', '关于': 'about',
'关于 BoosAPI': 'About BoosAPI', '关于 BossAI': 'About BossAI',
'管理端 IP 白名单': 'Management IP whitelist', '管理端 IP 白名单': 'Management IP whitelist',
'管理员': 'administrator', '管理员': 'administrator',
'管理员登录 Token 已被修改,请使用新 Token 登录。': 'The administrator login token has been modified, please use the new token to log in.', '管理员登录 Token 已被修改,请使用新 Token 登录。': 'The administrator login token has been modified, please use the new token to log in.',
@@ -259,7 +259,7 @@ export const zhToEnSupplemental: Record<string, string> = {
'拉取分组失败': 'Failed to pull group', '拉取分组失败': 'Failed to pull group',
'拉取分组失败,已回退 default': 'Failed to pull the group and has fallen back to default', '拉取分组失败,已回退 default': 'Failed to pull the group and has fallen back to default',
'冷却中': 'Cooling down', '冷却中': 'Cooling down',
'例如 BoosAPI': 'For example BoosAPI', '例如 BossAI': 'For example BossAI',
'例如: admin@example.com': 'For example: admin@example.com', '例如: admin@example.com': 'For example: admin@example.com',
'例如: smtp.qq.com': 'For example: smtp.qq.com', '例如: smtp.qq.com': 'For example: smtp.qq.com',
'例如: target@example.com': 'For example: target@example.com', '例如: target@example.com': 'For example: target@example.com',
@@ -770,7 +770,7 @@ export const zhToEnSupplemental: Record<string, string> = {
'LDOH Cookie 已更新': 'LDOH Cookie updated', 'LDOH Cookie 已更新': 'LDOH Cookie updated',
'LDOH Cookie 已清空': 'LDOH Cookie Cleared', 'LDOH Cookie 已清空': 'LDOH Cookie Cleared',
'LinuxDo 可用性监控': 'LinuxDo availability monitoring', 'LinuxDo 可用性监控': 'LinuxDo availability monitoring',
'BoosAPI 完全自托管,所有数据(账号、令牌、路由、日志)均存储在本地 SQLite 数据库中,不会向任何第三方发送数据。代理请求仅在你的服务器与上游站点之间直连传输。': 'boosapi is completely self-hosted, all data (accounts, tokens, routes, logs) is stored in a local SQLite database and no data is sent to any third party. Proxy requests only travel directly between your server and the upstream site.', 'BossAI 完全自托管,所有数据(账号、令牌、路由、日志)均存储在本地 SQLite 数据库中,不会向任何第三方发送数据。代理请求仅在你的服务器与上游站点之间直连传输。': 'BossAI is completely self-hosted, all data (accounts, tokens, routes, logs) is stored in a local SQLite database and no data is sent to any third party. Proxy requests only travel directly between your server and the upstream site.',
'model 不能为空': 'model cannot be empty', 'model 不能为空': 'model cannot be empty',
'modelLimitsEnabled 参数无效': 'modelLimitsEnabled parameter is invalid', 'modelLimitsEnabled 参数无效': 'modelLimitsEnabled parameter is invalid',
'models 必须是非空数组': 'models must be a non-empty array', 'models 必须是非空数组': 'models must be a non-empty array',
+3 -3
View File
@@ -84,7 +84,7 @@ const zhToEn: Record<string, string> = {
'模型操练场': 'Model Playground', '模型操练场': 'Model Playground',
'模型测试': 'Model Testing', '模型测试': 'Model Testing',
'关于': 'About', '关于': 'About',
'关于 BoosAPI': 'About BoosAPI', '关于 BossAI': 'About BossAI',
'站点文档': 'Site Docs', '站点文档': 'Site Docs',
'任务状态已更新': 'Task status updated', '任务状态已更新': 'Task status updated',
'会话已过期,请重新登录': 'Session expired, please sign in again', '会话已过期,请重新登录': 'Session expired, please sign in again',
@@ -221,7 +221,7 @@ const zhToEn: Record<string, string> = {
'代理端点': 'Proxy Endpoints', '代理端点': 'Proxy Endpoints',
'路由行为': 'Routing Behavior', '路由行为': 'Routing Behavior',
'指标口径': 'Metric Notes', '指标口径': 'Metric Notes',
'BoosAPI 将多个上游兼容供应商聚合为统一的 OpenAI / Claude 下游兼容入口。': 'BoosAPI aggregates multiple upstream compatible providers into a unified OpenAI / Claude compatible downstream endpoint.', 'BossAI 将多个上游兼容供应商聚合为统一的 OpenAI / Claude 下游兼容入口。': 'BossAI aggregates multiple upstream compatible providers into a unified OpenAI / Claude compatible downstream endpoint.',
'核心目标:自动签到、自动模型发现、自动路由重建、统一代理可观测性。': 'Core goals: auto check-in, auto model discovery, auto route rebuild, and unified proxy observability.', '核心目标:自动签到、自动模型发现、自动路由重建、统一代理可观测性。': 'Core goals: auto check-in, auto model discovery, auto route rebuild, and unified proxy observability.',
'1. 路由根据模型可用性自动生成。': '1. Routes are auto-generated based on model availability.', '1. 路由根据模型可用性自动生成。': '1. Routes are auto-generated based on model availability.',
'2. 当模型或账号发生变更时,路由通道会自动重建。': '2. Route channels are auto-rebuilt when models or accounts change.', '2. 当模型或账号发生变更时,路由通道会自动重建。': '2. Route channels are auto-rebuilt when models or accounts change.',
@@ -322,7 +322,7 @@ const zhToEn: Record<string, string> = {
'零配置嵌入式数据库': 'Zero-config embedded database', '零配置嵌入式数据库': 'Zero-config embedded database',
'项目链接': 'Project Links', '项目链接': 'Project Links',
'数据与隐私': 'Data & Privacy', '数据与隐私': 'Data & Privacy',
'BoosAPI 完全自托管,所有数据(账号、令牌、路由、日志)均存储在本地 SQLite 数据库中,不会向任何第三方发送数据。代理请求仅在你的服务器与上游站点之间直连传输。': 'BoosAPI is fully self-hosted. All data (accounts, tokens, routes, logs) is stored in a local SQLite database and never sent to any third party. Proxy requests travel directly between your server and upstream sites.', 'BossAI 完全自托管,所有数据(账号、令牌、路由、日志)均存储在本地 SQLite 数据库中,不会向任何第三方发送数据。代理请求仅在你的服务器与上游站点之间直连传输。': 'BossAI is fully self-hosted. All data (accounts, tokens, routes, logs) is stored in a local SQLite database and never sent to any third party. Proxy requests travel directly between your server and upstream sites.',
// User SaaS translations // User SaaS translations
'用户登录': 'User Login', '用户登录': 'User Login',
+2 -2
View File
@@ -3,8 +3,8 @@
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta name="description" content="BoosAPI - 中转站的中转站,聚合多个 AI API 中转站为统一网关" /> <meta name="description" content="BossAI - 中转站的中转站,聚合多个 AI API 中转站为统一网关" />
<title>BoosAPI</title> <title>BossAI</title>
<link rel="icon" type="image/png" href="/favicon.png" /> <link rel="icon" type="image/png" href="/favicon.png" />
<link rel="preconnect" href="https://fonts.googleapis.com" /> <link rel="preconnect" href="https://fonts.googleapis.com" />
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin /> <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+8 -8
View File
@@ -7,10 +7,10 @@ const FEATURES = [
{ icon: 'RT', title: '模型路由与容灾', desc: '按模型、账号、站点和通道优先级调度,失败后自动冷却并切换到可用通道。' }, { icon: 'RT', title: '模型路由与容灾', desc: '按模型、账号、站点和通道优先级调度,失败后自动冷却并切换到可用通道。' },
{ icon: 'AC', title: '站点与账号管理', desc: '集中维护站点、账号、API Key、OAuth、下游 Key 和普通用户可用模型。' }, { icon: 'AC', title: '站点与账号管理', desc: '集中维护站点、账号、API Key、OAuth、下游 Key 和普通用户可用模型。' },
{ icon: 'MD', title: '模型广场', desc: '聚合各站点模型可用性、账号覆盖、绑定令牌与路由状态,便于快速修路由。' }, { icon: 'MD', title: '模型广场', desc: '聚合各站点模型可用性、账号覆盖、绑定令牌与路由状态,便于快速修路由。' },
{ icon: 'WF', title: '工作流画布', desc: '沿用 ComfyUI 节点画布体验,后续接入 BoosAPI 模型路由、图像、视频、音频和工具节点。' }, { icon: 'WF', title: '工作流画布', desc: '沿用 ComfyUI 节点画布体验,后续接入 BossAI 模型路由、图像、视频、音频和工具节点。' },
{ icon: 'AG', title: '视频助手', desc: '面向工作流创作的对话助手,支持附件、多会话、用户 API Key 和模型路由选择。' }, { icon: 'AG', title: '视频助手', desc: '面向工作流创作的对话助手,支持附件、多会话、用户 API Key 和模型路由选择。' },
{ icon: 'PI', title: '生图助手', desc: '提供提示词模板、比例尺寸控制和图像模型调用,管理员与普通用户均可使用。' }, { icon: 'PI', title: '生图助手', desc: '提供提示词模板、比例尺寸控制和图像模型调用,管理员与普通用户均可使用。' },
{ icon: 'VD', title: '视频任务模板', desc: '支持火山方舟 Step1 创建视频任务、Step2 查询任务结果,并可复用 BoosAPI 模型路由。' }, { icon: 'VD', title: '视频任务模板', desc: '支持火山方舟 Step1 创建视频任务、Step2 查询任务结果,并可复用 BossAI 模型路由。' },
{ icon: 'CK', title: '签到与余额刷新', desc: '按站点/账号执行签到、余额刷新、健康检查和连接状态追踪。' }, { icon: 'CK', title: '签到与余额刷新', desc: '按站点/账号执行签到、余额刷新、健康检查和连接状态追踪。' },
{ icon: 'NT', title: '通知与审计', desc: 'Webhook / Bark / Server酱 / Telegram / SMTP 告警,配合代理日志和程序事件排障。' }, { icon: 'NT', title: '通知与审计', desc: 'Webhook / Bark / Server酱 / Telegram / SMTP 告警,配合代理日志和程序事件排障。' },
]; ];
@@ -21,7 +21,7 @@ const TECH_STACK = [
{ name: 'SQLx', desc: '类型化数据库访问与迁移管理。' }, { name: 'SQLx', desc: '类型化数据库访问与迁移管理。' },
{ name: 'SQLite', desc: '默认嵌入式数据库,适合单机部署和低运维成本场景。' }, { name: 'SQLite', desc: '默认嵌入式数据库,适合单机部署和低运维成本场景。' },
{ name: 'React / Vite', desc: '管理后台、普通用户面板、模型测试器和 Agent 界面。' }, { name: 'React / Vite', desc: '管理后台、普通用户面板、模型测试器和 Agent 界面。' },
{ name: 'External ComfyUI', desc: '可选外部 ComfyUI 代理;BoosAPI 不再内置 Docker 工作台。' }, { name: 'External ComfyUI', desc: '可选外部 ComfyUI 代理;BossAI 不再内置 Docker 工作台。' },
]; ];
const ENDPOINTS = [ const ENDPOINTS = [
@@ -39,7 +39,7 @@ export default function About() {
<div className="animate-fade-in" style={{ maxWidth: 860 }}> <div className="animate-fade-in" style={{ maxWidth: 860 }}>
{/* Header */} {/* Header */}
<div className="page-header" style={{ marginBottom: 14 }}> <div className="page-header" style={{ marginBottom: 14 }}>
<h2 className="page-title">{tr('关于 BoosAPI')}</h2> <h2 className="page-title">{tr('关于 BossAI')}</h2>
</div> </div>
{/* Hero card */} {/* Hero card */}
@@ -47,16 +47,16 @@ export default function About() {
<div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 14 }}> <div style={{ display: 'flex', alignItems: 'center', gap: 14, marginBottom: 14 }}>
<img <img
src="/logo.png" src="/logo.png"
alt="BoosAPI" alt="BossAI"
style={{ width: 48, height: 48, borderRadius: 12, flexShrink: 0 }} style={{ width: 48, height: 48, borderRadius: 12, flexShrink: 0 }}
/> />
<div> <div>
<div style={{ fontSize: 18, fontWeight: 700 }}>BoosAPI</div> <div style={{ fontSize: 18, fontWeight: 700 }}>BossAI</div>
<div style={{ fontSize: 12, color: 'var(--color-text-tertiary)', marginTop: 2 }}>v{VERSION}</div> <div style={{ fontSize: 12, color: 'var(--color-text-tertiary)', marginTop: 2 }}>v{VERSION}</div>
</div> </div>
</div> </div>
<div style={{ fontSize: 14, color: 'var(--color-text-secondary)', lineHeight: 1.8 }}> <div style={{ fontSize: 14, color: 'var(--color-text-secondary)', lineHeight: 1.8 }}>
{tr('BoosAPI 是一个自托管 AI 模型网关与工作台。它把多站点账号、下游 Key、模型路由、图像生成、视频任务、ComfyUI 风格工作流和普通用户面板收束到同一个 Rust 服务中,让前端、Agent 和工作流节点都能使用后台已经配置好的模型。')} {tr('BossAI 是一个自托管 AI 模型网关与工作台。它把多站点账号、下游 Key、模型路由、图像生成、视频任务、ComfyUI 风格工作流和普通用户面板收束到同一个 Rust 服务中,让前端、Agent 和工作流节点都能使用后台已经配置好的模型。')}
</div> </div>
<div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 14 }}> <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap', marginTop: 14 }}>
{['Rust Backend', 'OpenAI Compatible', 'ComfyUI Canvas', 'Picture Agent', 'Volcengine Video'].map((tag) => ( {['Rust Backend', 'OpenAI Compatible', 'ComfyUI Canvas', 'Picture Agent', 'Volcengine Video'].map((tag) => (
@@ -171,7 +171,7 @@ export default function About() {
<div className="card animate-slide-up stagger-5" style={{ padding: 22 }}> <div className="card animate-slide-up stagger-5" style={{ padding: 22 }}>
<h3 style={{ fontSize: 15, fontWeight: 600, marginBottom: 10 }}>{tr('数据与隐私')}</h3> <h3 style={{ fontSize: 15, fontWeight: 600, marginBottom: 10 }}>{tr('数据与隐私')}</h3>
<div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.8 }}> <div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.8 }}>
{tr('BoosAPI 完全自托管,账号、令牌、路由、日志、普通用户和工作台状态均保存在你的运行环境中。代理请求只在你的服务器、可选外部 ComfyUI 与已配置上游之间流转;内置系统 Key 会被保护,后台列表中只展示脱敏值。')} {tr('BossAI 完全自托管,账号、令牌、路由、日志、普通用户和工作台状态均保存在你的运行环境中。代理请求只在你的服务器、可选外部 ComfyUI 与已配置上游之间流转;内置系统 Key 会被保护,后台列表中只展示脱敏值。')}
</div> </div>
</div> </div>
</div> </div>
+1 -1
View File
@@ -46,7 +46,7 @@ describe('About page', () => {
await flushMicrotasks(); await flushMicrotasks();
const text = collectText(root.root); const text = collectText(root.root);
expect(text).toContain('关于 BoosAPI'); expect(text).toContain('关于 BossAI');
expect(text).toContain('核心特色'); expect(text).toContain('核心特色');
expect(text).toContain('兼容入口'); expect(text).toContain('兼容入口');
expect(text).not.toContain('更新提醒'); expect(text).not.toContain('更新提醒');
+1 -1
View File
@@ -1910,7 +1910,7 @@ export default function Accounts() {
color: "var(--color-text-muted)", color: "var(--color-text-muted)",
}} }}
> >
配置 refresh_token 后,BoosAPI 会在 JWT 临近过期或 配置 refresh_token 后,BossAI 会在 JWT 临近过期或
401 时自动续期并回写新 token。 401 时自动续期并回写新 token。
</div> </div>
</div> </div>
+1 -1
View File
@@ -952,7 +952,7 @@ export default function ComfyUIAgent() {
const exportWorkflow = () => { const exportWorkflow = () => {
const workflow = latestWorkflow || { const workflow = latestWorkflow || {
name: 'BoosAPI Video Agent Project', name: 'BossAI Video Agent Project',
version: 1, version: 1,
messages: messages messages: messages
.filter((message) => message.role !== 'system') .filter((message) => message.role !== 'system')
+3 -3
View File
@@ -51,8 +51,8 @@ export default function DigitalHuman() {
const audience: SessionAudience = location.pathname.startsWith('/user/') ? 'user' : 'admin'; const audience: SessionAudience = location.pathname.startsWith('/user/') ? 'user' : 'admin';
const [mode, setMode] = useState<Mode>('audio'); const [mode, setMode] = useState<Mode>('audio');
const [model, setModel] = useState(MODEL_PRESETS[0]); const [model, setModel] = useState(MODEL_PRESETS[0]);
const [prompt, setPrompt] = useState('一位专业中文数字人主播,坐在简洁演播室中,面向镜头自然讲解 BoosAPI 的模型路由和工作流能力。'); const [prompt, setPrompt] = useState('一位专业中文数字人主播,坐在简洁演播室中,面向镜头自然讲解 BossAI 的模型路由和工作流能力。');
const [script, setScript] = useState('大家好,欢迎使用 BoosAPI。今天我们演示如何用统一模型路由生成数字人口播视频。'); const [script, setScript] = useState('大家好,欢迎使用 BossAI。今天我们演示如何用统一模型路由生成数字人口播视频。');
const [imageUrl, setImageUrl] = useState(''); const [imageUrl, setImageUrl] = useState('');
const [audioUrl, setAudioUrl] = useState(''); const [audioUrl, setAudioUrl] = useState('');
const [voiceStyle, setVoiceStyle] = useState(VOICE_STYLE_OPTIONS[0]); const [voiceStyle, setVoiceStyle] = useState(VOICE_STYLE_OPTIONS[0]);
@@ -112,7 +112,7 @@ export default function DigitalHuman() {
<div className="page-header"> <div className="page-header">
<div> <div>
<h1 className="page-title">数字人</h1> <h1 className="page-title">数字人</h1>
<p className="page-subtitle">参考 LongCat-Video Avatar 的任务形态:人物图、音频、台词、分段和多人数字人编排,底层走 BoosAPI 视频模型路由。</p> <p className="page-subtitle">参考 LongCat-Video Avatar 的任务形态:人物图、音频、台词、分段和多人数字人编排,底层走 BossAI 视频模型路由。</p>
</div> </div>
<div className="page-actions"> <div className="page-actions">
<button type="button" className="btn btn-primary" onClick={submit} disabled={submitting}> <button type="button" className="btn btn-primary" onClick={submit} disabled={submitting}>
+1 -1
View File
@@ -108,7 +108,7 @@ export default function Monitors() {
<div> <div>
<h2 className="page-title">{tr('监控内嵌')}</h2> <h2 className="page-title">{tr('监控内嵌')}</h2>
<div style={{ marginTop: 6, fontSize: 13, color: 'var(--color-text-muted)' }}> <div style={{ marginTop: 6, fontSize: 13, color: 'var(--color-text-muted)' }}>
在 BoosAPI 内查看外部站点监控页面。 在 BossAI 内查看外部站点监控页面。
</div> </div>
</div> </div>
<div style={{ display: 'flex', gap: 8 }}> <div style={{ display: 'flex', gap: 8 }}>
+3 -3
View File
@@ -2313,16 +2313,16 @@ export default function OAuthManagement() {
{renderGuideCard( {renderGuideCard(
'本地部署', '本地部署',
'BoosAPI 和浏览器在同一台机器时,不需要 SSH 隧道。直接点击“连接”,在弹窗里完成授权即可。', 'BossAI 和浏览器在同一台机器时,不需要 SSH 隧道。直接点击“连接”,在弹窗里完成授权即可。',
<div className="oauth-guide-copy"> <div className="oauth-guide-copy">
如果浏览器能直接访问上面的 localhost 回调地址,授权完成后会自动回到 BoosAPI。 如果浏览器能直接访问上面的 localhost 回调地址,授权完成后会自动回到 BossAI。
</div>, </div>,
)} )}
{activeSession.instructions.sshTunnelCommand {activeSession.instructions.sshTunnelCommand
? renderGuideCard( ? renderGuideCard(
'云端部署', '云端部署',
'BoosAPI 部署在 VPS、容器或远程主机时,浏览器访问到的是你自己电脑的 localhost。先在本地开 SSH 隧道,再继续登录。', 'BossAI 部署在 VPS、容器或远程主机时,浏览器访问到的是你自己电脑的 localhost。先在本地开 SSH 隧道,再继续登录。',
<div className="oauth-guide-block-list"> <div className="oauth-guide-block-list">
<div className="oauth-guide-block-label">常规 SSH 隧道</div> <div className="oauth-guide-block-label">常规 SSH 隧道</div>
{renderCodeBlock(activeSession.instructions.sshTunnelCommand)} {renderCodeBlock(activeSession.instructions.sshTunnelCommand)}
+1 -1
View File
@@ -720,7 +720,7 @@ export default function PictureAgent() {
<div> <div>
<h1 className="page-title">生图助手</h1> <h1 className="page-title">生图助手</h1>
<p className="page-subtitle"> <p className="page-subtitle">
{modeLabel} · {status?.upstreamLabel || 'BoosAPI 本地图片路由'} · {status?.keyName || '加载密钥中'} {modeLabel} · {status?.upstreamLabel || 'BossAI 本地图片路由'} · {status?.keyName || '加载密钥中'}
</p> </p>
</div> </div>
<div className="page-actions"> <div className="page-actions">
+5 -5
View File
@@ -1799,7 +1799,7 @@ export default function Settings() {
<div style={settingsModernTitleBlockStyle}> <div style={settingsModernTitleBlockStyle}>
<div style={settingsModernTitleStyle}>Codex 上游传输与会话并发</div> <div style={settingsModernTitleStyle}>Codex 上游传输与会话并发</div>
<div style={settingsModernDescriptionStyle}> <div style={settingsModernDescriptionStyle}>
默认采用 HTTP 优先。只有这里开启后,BoosAPI 才会在 Codex 请求上尝试把上游升级为 WebSocket。下游 Codex 客户端也必须同时启用 `/v1/responses` websocket,单开这里不会生效。 默认采用 HTTP 优先。只有这里开启后,BossAI 才会在 Codex 请求上尝试把上游升级为 WebSocket。下游 Codex 客户端也必须同时启用 `/v1/responses` websocket,单开这里不会生效。
</div> </div>
</div> </div>
<div style={settingsModernPillRowStyle}> <div style={settingsModernPillRowStyle}>
@@ -1813,7 +1813,7 @@ export default function Settings() {
</div> </div>
<label style={settingsModernToggleStyle}> <label style={settingsModernToggleStyle}>
<div style={settingsModernToggleCopyStyle}> <div style={settingsModernToggleCopyStyle}>
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text-secondary)' }}>允许 BoosAPI 到 Codex 上游使用 WebSocket</span> <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text-secondary)' }}>允许 BossAI 到 Codex 上游使用 WebSocket</span>
<span style={{ fontSize: 12, lineHeight: 1.7, color: 'var(--color-text-muted)' }}> <span style={{ fontSize: 12, lineHeight: 1.7, color: 'var(--color-text-muted)' }}>
仅在下游 Codex 客户端已同步开启 `/v1/responses` websocket 时启用;否则仍按 HTTP 优先执行。 仅在下游 Codex 客户端已同步开启 `/v1/responses` websocket 时启用;否则仍按 HTTP 优先执行。
</span> </span>
@@ -1896,7 +1896,7 @@ export default function Settings() {
<div style={settingsModernTitleBlockStyle}> <div style={settingsModernTitleBlockStyle}>
<div style={{ ...settingsModernTitleStyle, color: 'var(--color-danger)' }}>批量测活</div> <div style={{ ...settingsModernTitleStyle, color: 'var(--color-danger)' }}>批量测活</div>
<div style={settingsModernDescriptionStyle}> <div style={settingsModernDescriptionStyle}>
默认关闭。开启后,BoosAPI 会在后台定时对活跃账号模型发送最小化探测请求,用来校正“/models 能看到但实际不可用”的假阳性。 默认关闭。开启后,BossAI 会在后台定时对活跃账号模型发送最小化探测请求,用来校正“/models 能看到但实际不可用”的假阳性。
</div> </div>
</div> </div>
<div style={settingsModernPillRowStyle}> <div style={settingsModernPillRowStyle}>
@@ -1922,7 +1922,7 @@ export default function Settings() {
</div> </div>
<label style={settingsModernToggleStyle}> <label style={settingsModernToggleStyle}>
<div style={settingsModernToggleCopyStyle}> <div style={settingsModernToggleCopyStyle}>
<span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text-secondary)' }}>允许 BoosAPI 后台主动批量测活</span> <span style={{ fontSize: 13, fontWeight: 600, color: 'var(--color-text-secondary)' }}>允许 BossAI 后台主动批量测活</span>
<span style={{ fontSize: 12, lineHeight: 1.7, color: 'var(--color-text-muted)' }}> <span style={{ fontSize: 12, lineHeight: 1.7, color: 'var(--color-text-muted)' }}>
首次从关闭切换到开启时,需要手动输入确认语句;关闭时可直接保存。 首次从关闭切换到开启时,需要手动输入确认语句;关闭时可直接保存。
</span> </span>
@@ -2599,7 +2599,7 @@ export default function Settings() {
<div className="card animate-slide-up stagger-7" style={{ padding: 20, border: '1px solid color-mix(in srgb, var(--color-danger) 30%, var(--color-border))' }}> <div className="card animate-slide-up stagger-7" style={{ padding: 20, border: '1px solid color-mix(in srgb, var(--color-danger) 30%, var(--color-border))' }}>
<div style={{ fontWeight: 600, fontSize: 14, marginBottom: 10, color: 'var(--color-danger)' }}>危险操作</div> <div style={{ fontWeight: 600, fontSize: 14, marginBottom: 10, color: 'var(--color-danger)' }}>危险操作</div>
<div style={{ fontSize: 12, color: 'var(--color-text-muted)', lineHeight: 1.8, marginBottom: 12 }}> <div style={{ fontSize: 12, color: 'var(--color-text-muted)', lineHeight: 1.8, marginBottom: 12 }}>
重新初始化系统会清空当前 BoosAPI 使用中的全部数据库内容;若当前运行在外部 MySQL/Postgres,也会先清空该外部库中的 BoosAPI 数据,然后切回默认 SQLite。 重新初始化系统会清空当前 BossAI 使用中的全部数据库内容;若当前运行在外部 MySQL/Postgres,也会先清空该外部库中的 BossAI 数据,然后切回默认 SQLite。
</div> </div>
<div style={{ fontSize: 12, color: 'var(--color-text-muted)', lineHeight: 1.8, marginBottom: 14 }}> <div style={{ fontSize: 12, color: 'var(--color-text-muted)', lineHeight: 1.8, marginBottom: 14 }}>
完成后管理员 Token 会重置为 <code style={{ fontFamily: 'var(--font-mono)' }}>{FACTORY_RESET_ADMIN_TOKEN}</code>,当前会话会立即退出并刷新页面。 完成后管理员 Token 会重置为 <code style={{ fontFamily: 'var(--font-mono)' }}>{FACTORY_RESET_ADMIN_TOKEN}</code>,当前会话会立即退出并刷新页面。
+1 -1
View File
@@ -1,6 +1,6 @@
/** /**
* @Author: 橘子 * @Author: 橘子
* @Project_description: BoosAPI 站点管理页 * @Project_description: BossAI 站点管理页
* @Description: 代码是我抄的,不会也是真的 * @Description: 代码是我抄的,不会也是真的
*/ */
import { useEffect, useMemo, useRef, useState } from 'react'; import { useEffect, useMemo, useRef, useState } from 'react';
+1 -1
View File
@@ -1099,7 +1099,7 @@ export function TokensPanel({ embedded = false, onEmbeddedActionsChange }: Token
<input <input
value={form.name} value={form.name}
onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))} onChange={(e) => setForm((prev) => ({ ...prev, name: e.target.value }))}
placeholder="例如 BoosAPI" placeholder="例如 BossAI"
style={inputStyle} style={inputStyle}
/> />
</div> </div>
+1 -1
View File
@@ -131,7 +131,7 @@ export default function UserDashboard({ onLogout }: { onLogout?: () => void }) {
<div className="page-container" style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}> <div className="page-container" style={{ padding: '24px', maxWidth: '1200px', margin: '0 auto' }}>
<header style={{ marginBottom: '24px' }}> <header style={{ marginBottom: '24px' }}>
<h1 style={{ fontSize: '24px', fontWeight: 700, margin: '0 0 8px 0' }}>你好, {profile.username}</h1> <h1 style={{ fontSize: '24px', fontWeight: 700, margin: '0 0 8px 0' }}>你好, {profile.username}</h1>
<p style={{ color: 'var(--color-text-muted)', margin: 0 }}>欢迎回到 BoosAPI 用户中心。</p> <p style={{ color: 'var(--color-text-muted)', margin: 0 }}>欢迎回到 BossAI 用户中心。</p>
</header> </header>
{/* Summary Cards */} {/* Summary Cards */}
+2 -2
View File
@@ -44,14 +44,14 @@ export default function LoginShell({
> >
<div className="brand-mark-frame brand-mark-frame-hero"> <div className="brand-mark-frame brand-mark-frame-hero">
<div className="brand-mark-canvas"> <div className="brand-mark-canvas">
<img src="/logo.png" alt="BoosAPI" className="login-brand-logo" /> <img src="/logo.png" alt="BossAI" className="login-brand-logo" />
</div> </div>
</div> </div>
<div <div
className="login-brand-summary" className="login-brand-summary"
style={variant === 'user' ? { textAlign: 'center' } : undefined} style={variant === 'user' ? { textAlign: 'center' } : undefined}
> >
<div className="login-brand-name">BoosAPI</div> <div className="login-brand-name">BossAI</div>
<div className="login-brand-kicker"> <div className="login-brand-kicker">
{variant === 'user' ? t('用户登录') : t('中转站的中转站')} {variant === 'user' ? t('用户登录') : t('中转站的中转站')}
</div> </div>
@@ -29,7 +29,7 @@ export function normalizeVerifyFailureMessage(message: unknown): string {
if (!text) return '验证失败'; if (!text) return '验证失败';
const lowered = text.toLowerCase(); const lowered = text.toLowerCase();
if (isNetworkFailureMessage(text)) { if (isNetworkFailureMessage(text)) {
return '无法连接到 BoosAPI 服务端,请检查服务状态或网络连接'; return '无法连接到 BossAI 服务端,请检查服务状态或网络连接';
} }
if (lowered.includes('user id mismatch') || lowered.includes('does not match this token')) { if (lowered.includes('user id mismatch') || lowered.includes('does not match this token')) {
return '填写的用户 ID 与当前 Token / Cookie 不匹配'; return '填写的用户 ID 与当前 Token / Cookie 不匹配';
@@ -43,7 +43,7 @@ export function buildVerifyFailureHint(result: VerifyResultLike): string | null
return '这不是 Token 错误判断。请检查填写的用户 ID 是否与当前 Token / Cookie 属于同一账号。'; return '这不是 Token 错误判断。请检查填写的用户 ID 是否与当前 Token / Cookie 属于同一账号。';
} }
if (isNetworkFailureMessage(result.message)) { if (isNetworkFailureMessage(result.message)) {
return '这不是 Token 错误判断。请检查 BoosAPI 服务是否在线,以及目标站点或代理是否可达。'; return '这不是 Token 错误判断。请检查 BossAI 服务是否在线,以及目标站点或代理是否可达。';
} }
if (isTimeoutFailureMessage(result.message)) { if (isTimeoutFailureMessage(result.message)) {
return '这不是 Token 错误判断。目标站点响应超时,请稍后重试或检查代理/网络。'; return '这不是 Token 错误判断。目标站点响应超时,请稍后重试或检查代理/网络。';
@@ -63,7 +63,7 @@ export function buildAddAccountPrereqHint(result: VerifyResultLike): string {
return '请先修正用户 ID 并重新验证,验证成功后才能添加账号。'; return '请先修正用户 ID 并重新验证,验证成功后才能添加账号。';
} }
if (isNetworkFailureMessage(result.message)) { if (isNetworkFailureMessage(result.message)) {
return '验证请求未成功完成,请先检查 BoosAPI 服务、站点网络或代理配置。'; return '验证请求未成功完成,请先检查 BossAI 服务、站点网络或代理配置。';
} }
if (isTimeoutFailureMessage(result.message)) { if (isTimeoutFailureMessage(result.message)) {
return '验证请求超时,请先检查站点或代理连通性后再添加账号。'; return '验证请求超时,请先检查站点或代理连通性后再添加账号。';
+2 -2
View File
@@ -43,10 +43,10 @@ export default function FactoryResetModal({
<div className="modal-header" style={{ color: 'var(--color-danger)' }}>确认重新初始化系统</div> <div className="modal-header" style={{ color: 'var(--color-danger)' }}>确认重新初始化系统</div>
<div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}> <div className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ padding: 12, borderRadius: 'var(--radius-sm)', background: 'var(--color-danger-bg)', color: 'var(--color-danger)', fontSize: 12, lineHeight: 1.8 }}> <div style={{ padding: 12, borderRadius: 'var(--radius-sm)', background: 'var(--color-danger-bg)', color: 'var(--color-danger)', fontSize: 12, lineHeight: 1.8 }}>
这是不可逆操作。系统会清空当前 BoosAPI 使用中的全部数据库内容,并在成功后立即退出当前登录状态。 这是不可逆操作。系统会清空当前 BossAI 使用中的全部数据库内容,并在成功后立即退出当前登录状态。
</div> </div>
<div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.9 }}> <div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.9 }}>
<div>• 当前若使用外部 MySQL/Postgres,也会先清空该外部库中的 BoosAPI 数据。</div> <div>• 当前若使用外部 MySQL/Postgres,也会先清空该外部库中的 BossAI 数据。</div>
<div>• 系统随后会强制切回默认 SQLite。</div> <div>• 系统随后会强制切回默认 SQLite。</div>
<div>• 管理员 Token 将重置为 <code style={{ fontFamily: 'var(--font-mono)' }}>{adminToken}</code>。</div> <div>• 管理员 Token 将重置为 <code style={{ fontFamily: 'var(--font-mono)' }}>{adminToken}</code>。</div>
<div>• 完成后会立即退出登录并刷新页面,回到当前首装初始状态。</div> <div>• 完成后会立即退出登录并刷新页面,回到当前首装初始状态。</div>
@@ -52,7 +52,7 @@ export default function ModelAvailabilityProbeConfirmModal({
<div id={titleId} className="modal-header" style={{ color: 'var(--color-danger)' }}>确认开启批量测活</div> <div id={titleId} className="modal-header" style={{ color: 'var(--color-danger)' }}>确认开启批量测活</div>
<div id={descriptionId} className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}> <div id={descriptionId} className="modal-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
<div style={{ padding: 12, borderRadius: 'var(--radius-sm)', background: 'var(--color-danger-bg)', color: 'var(--color-danger)', fontSize: 12, lineHeight: 1.8 }}> <div style={{ padding: 12, borderRadius: 'var(--radius-sm)', background: 'var(--color-danger-bg)', color: 'var(--color-danger)', fontSize: 12, lineHeight: 1.8 }}>
开启后,BoosAPI 会在后台对活跃账号模型做最小化探测请求。这可能被部分中转站视为批量测活或异常行为,请务必先确认你的中转站明确允许此类探测。 开启后,BossAI 会在后台对活跃账号模型做最小化探测请求。这可能被部分中转站视为批量测活或异常行为,请务必先确认你的中转站明确允许此类探测。
</div> </div>
<div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.9 }}> <div style={{ fontSize: 13, color: 'var(--color-text-secondary)', lineHeight: 1.9 }}>
请手动输入以下整句后再开启: 请手动输入以下整句后再开启: