fix: harden workflow smoke issues
This commit is contained in:
@@ -421,7 +421,7 @@ export BOOSAPI_SERVER__PORT=4000
|
|||||||
export BOOSAPI_AUTH__AUTH_TOKEN=your-admin-token
|
export BOOSAPI_AUTH__AUTH_TOKEN=your-admin-token
|
||||||
export BOOSAPI_AUTH__PROXY_TOKEN=sk-your-proxy-token
|
export BOOSAPI_AUTH__PROXY_TOKEN=sk-your-proxy-token
|
||||||
export BOOSAPI_UPSTREAM_BASE=https://api.boos.lat/v1
|
export BOOSAPI_UPSTREAM_BASE=https://api.boos.lat/v1
|
||||||
export BOOSAPI_UPSTREAM_KEY=sk-boos4721
|
export BOOSAPI_UPSTREAM_KEY=sk-your-upstream-key
|
||||||
```
|
```
|
||||||
|
|
||||||
### 前端(React SPA)
|
### 前端(React SPA)
|
||||||
|
|||||||
@@ -359,6 +359,7 @@ mod tests {
|
|||||||
site_id INTEGER NOT NULL,
|
site_id INTEGER NOT NULL,
|
||||||
access_token TEXT NOT NULL,
|
access_token TEXT NOT NULL,
|
||||||
api_token TEXT,
|
api_token TEXT,
|
||||||
|
unit_cost REAL,
|
||||||
status TEXT NOT NULL DEFAULT 'active'
|
status TEXT NOT NULL DEFAULT 'active'
|
||||||
)",
|
)",
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -368,6 +368,8 @@ async fn status_handler(
|
|||||||
"keyName": key_name,
|
"keyName": key_name,
|
||||||
"userId": auth.user_id,
|
"userId": auth.user_id,
|
||||||
"role": auth.role,
|
"role": auth.role,
|
||||||
|
"apiBase": upstream_base,
|
||||||
|
"upstreamBase": upstream_base,
|
||||||
"upstreamLabel": upstream_label,
|
"upstreamLabel": upstream_label,
|
||||||
"comfyui": state.comfyui.status_response().await,
|
"comfyui": state.comfyui.status_response().await,
|
||||||
})))
|
})))
|
||||||
|
|||||||
@@ -1570,6 +1570,7 @@ mod tests {
|
|||||||
site_id INTEGER NOT NULL,
|
site_id INTEGER NOT NULL,
|
||||||
access_token TEXT NOT NULL,
|
access_token TEXT NOT NULL,
|
||||||
api_token TEXT,
|
api_token TEXT,
|
||||||
|
unit_cost REAL,
|
||||||
status TEXT NOT NULL DEFAULT 'active'
|
status TEXT NOT NULL DEFAULT 'active'
|
||||||
)",
|
)",
|
||||||
)
|
)
|
||||||
|
|||||||
+20
-45
@@ -5183,55 +5183,30 @@ async fn workflow_context(state: &AppState, caller: &WorkflowCaller) -> AppResul
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn inject_bootstrap(html: String, config: &crate::config::ComfyUIConfig) -> String {
|
fn inject_bootstrap(html: String, config: &crate::config::ComfyUIConfig) -> String {
|
||||||
let cloud_api_key = workflow_cloud_api_key(config);
|
|
||||||
if config.uses_native_backend() && !config.uses_cloud_backend() {
|
if config.uses_native_backend() && !config.uses_cloud_backend() {
|
||||||
return inject_external_bootstrap(html, cloud_api_key);
|
return inject_external_bootstrap(html);
|
||||||
}
|
}
|
||||||
inject_enhanced_bootstrap(html, cloud_api_key)
|
inject_enhanced_bootstrap(html)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn workflow_api_key_bootstrap(api_key: Option<&str>) -> String {
|
fn workflow_secret_cleanup_bootstrap() -> &'static str {
|
||||||
let Some(api_key) = api_key else {
|
|
||||||
return String::new();
|
|
||||||
};
|
|
||||||
let api_key = serde_json::to_string(api_key).unwrap_or_else(|_| "null".to_string());
|
|
||||||
format!(
|
|
||||||
r#"<script>
|
r#"<script>
|
||||||
(function () {{
|
(function () {
|
||||||
const apiKey = {api_key};
|
const clearLeakedComfyApiKey = () => {
|
||||||
if (!apiKey) return;
|
try {
|
||||||
const installComfyApiKey = () => {{
|
localStorage.removeItem('comfy_api_key');
|
||||||
try {{
|
sessionStorage.removeItem('comfy_api_key');
|
||||||
localStorage.setItem('comfy_api_key', apiKey);
|
document.cookie = 'comfy_api_key=; Path=/workflow-ui; Max-Age=0; SameSite=Lax';
|
||||||
sessionStorage.setItem('comfy_api_key', apiKey);
|
} catch (err) {}
|
||||||
for (const api of [window.app?.api, window.comfyAPI?.api, window.api]) {{
|
};
|
||||||
if (api) {{
|
clearLeakedComfyApiKey();
|
||||||
api.apiKey = api.apiKey || apiKey;
|
window.addEventListener('DOMContentLoaded', clearLeakedComfyApiKey);
|
||||||
if (!api.__boosapiCloudApiKeyQueuePatch && typeof api.queuePrompt === 'function') {{
|
})();
|
||||||
const originalQueuePrompt = api.queuePrompt.bind(api);
|
|
||||||
api.queuePrompt = function() {{
|
|
||||||
if (!this.apiKey) this.apiKey = apiKey;
|
|
||||||
return originalQueuePrompt(...arguments);
|
|
||||||
}};
|
|
||||||
api.__boosapiCloudApiKeyQueuePatch = true;
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
}}
|
|
||||||
document.cookie = 'comfy_api_key=' + encodeURIComponent(apiKey) + '; Path=/workflow-ui; SameSite=Lax';
|
|
||||||
}} catch (err) {{}}
|
|
||||||
}};
|
|
||||||
installComfyApiKey();
|
|
||||||
window.addEventListener('DOMContentLoaded', installComfyApiKey);
|
|
||||||
window.setTimeout(installComfyApiKey, 300);
|
|
||||||
window.setTimeout(installComfyApiKey, 1200);
|
|
||||||
window.setInterval(installComfyApiKey, 5000);
|
|
||||||
}})();
|
|
||||||
</script>"#
|
</script>"#
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_external_bootstrap(html: String, cloud_api_key: Option<&str>) -> String {
|
fn inject_external_bootstrap(html: String) -> String {
|
||||||
let api_key_bootstrap = workflow_api_key_bootstrap(cloud_api_key);
|
let secret_cleanup_bootstrap = workflow_secret_cleanup_bootstrap();
|
||||||
let shell = r#"<script>
|
let shell = r#"<script>
|
||||||
(function () {
|
(function () {
|
||||||
const renameComfyUiBrand = () => {
|
const renameComfyUiBrand = () => {
|
||||||
@@ -5310,12 +5285,12 @@ fn inject_external_bootstrap(html: String, cloud_api_key: Option<&str>) -> Strin
|
|||||||
window.setTimeout(installWorkflowValidationButton, 1800);
|
window.setTimeout(installWorkflowValidationButton, 1800);
|
||||||
})();
|
})();
|
||||||
</script>"#;
|
</script>"#;
|
||||||
let bootstrap = format!("{api_key_bootstrap}{shell}");
|
let bootstrap = format!("{secret_cleanup_bootstrap}{shell}");
|
||||||
html.replace("</head>", &format!("{bootstrap}\n</head>"))
|
html.replace("</head>", &format!("{bootstrap}\n</head>"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn inject_enhanced_bootstrap(html: String, cloud_api_key: Option<&str>) -> String {
|
fn inject_enhanced_bootstrap(html: String) -> String {
|
||||||
let api_key_bootstrap = workflow_api_key_bootstrap(cloud_api_key);
|
let secret_cleanup_bootstrap = workflow_secret_cleanup_bootstrap();
|
||||||
let shell = r#"<style id="boosapi-workflow-shell-style">
|
let shell = r#"<style id="boosapi-workflow-shell-style">
|
||||||
</style>
|
</style>
|
||||||
<script>
|
<script>
|
||||||
@@ -5713,7 +5688,7 @@ fn inject_enhanced_bootstrap(html: String, cloud_api_key: Option<&str>) -> Strin
|
|||||||
window.setTimeout(patchWorkflowShell, 1200);
|
window.setTimeout(patchWorkflowShell, 1200);
|
||||||
})();
|
})();
|
||||||
</script>"#;
|
</script>"#;
|
||||||
let bootstrap = format!("{api_key_bootstrap}{shell}");
|
let bootstrap = format!("{secret_cleanup_bootstrap}{shell}");
|
||||||
html.replace("</head>", &format!("{bootstrap}\n</head>"))
|
html.replace("</head>", &format!("{bootstrap}\n</head>"))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,7 +37,7 @@ describe('Login surface', () => {
|
|||||||
));
|
));
|
||||||
|
|
||||||
expect(pageText).toContain('BoosAPI');
|
expect(pageText).toContain('BoosAPI');
|
||||||
expect(pageText).toContain('中转站的中转站');
|
expect(pageText).toContain('AI 应用平台');
|
||||||
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');
|
||||||
expect(pageText).toContain('统一代理网关');
|
expect(pageText).toContain('统一代理网关');
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ const zhToEn: Record<string, string> = {
|
|||||||
'仅校验本地服务访问权限,不会把令牌发送到第三方。': 'Only checks local service access and never sends the token to a third party.',
|
'仅校验本地服务访问权限,不会把令牌发送到第三方。': 'Only checks local service access and never sends the token to a third party.',
|
||||||
'验证中...': 'Verifying...',
|
'验证中...': 'Verifying...',
|
||||||
'登录': 'Sign In',
|
'登录': 'Sign In',
|
||||||
|
'AI 应用平台': 'AI Application Platform',
|
||||||
|
'聚合多模型、多模态、工作流与智能路由,把对话、生图、视频和数字人生产放进一个统一平台。': 'Unify multi-model routing, multimodal creation, workflows, chat, image generation, video, and digital human production in one platform.',
|
||||||
'中转站的中转站': 'The Hub of Hubs',
|
'中转站的中转站': 'The Hub of Hubs',
|
||||||
'把分散的 New API / One API / OneHub 等站点聚合成统一网关,自动发现模型、智能路由、成本更优。': 'Turn fragmented New API / One API / OneHub sites into one unified gateway with auto model discovery, smart routing, and better cost control.',
|
'把分散的 New API / One API / OneHub 等站点聚合成统一网关,自动发现模型、智能路由、成本更优。': 'Turn fragmented New API / One API / OneHub sites into one unified gateway with auto model discovery, smart routing, and better cost control.',
|
||||||
'兼容 New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API': 'Compatible with New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API',
|
'兼容 New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API': 'Compatible with New API / One API / OneHub / DoneHub / Veloera / AnyRouter / Sub2API',
|
||||||
|
|||||||
+1
-1
@@ -3,7 +3,7 @@
|
|||||||
<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 应用平台" />
|
||||||
<title>BoosAPI</title>
|
<title>BoosAPI</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" />
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ export default function LoginShell({
|
|||||||
>
|
>
|
||||||
<div className="login-brand-name">BoosAPI</div>
|
<div className="login-brand-name">BoosAPI</div>
|
||||||
<div className="login-brand-kicker">
|
<div className="login-brand-kicker">
|
||||||
{variant === 'user' ? t('用户登录') : t('中转站的中转站')}
|
{variant === 'user' ? t('用户登录') : t('AI 应用平台')}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -62,7 +62,7 @@ export default function LoginShell({
|
|||||||
<>
|
<>
|
||||||
<div className="login-brand-copy-block">
|
<div className="login-brand-copy-block">
|
||||||
<p className="login-brand-copy">
|
<p className="login-brand-copy">
|
||||||
{t('把分散的 New API / One API / OneHub 等站点聚合成统一网关,自动发现模型、智能路由、成本更优。')}
|
{t('聚合多模型、多模态、工作流与智能路由,把对话、生图、视频和数字人生产放进一个统一平台。')}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="login-compat-line">
|
<div className="login-compat-line">
|
||||||
|
|||||||
Reference in New Issue
Block a user