mirror of
https://github.com/foxhui/WebAI2API.git
synced 2026-06-16 21:03:59 +08:00
feat: 部分适配器支持视频生成
This commit is contained in:
@@ -26,19 +26,20 @@
|
||||
|
||||
### 📋 支持列表
|
||||
|
||||
| 网站名称 | 文本支持 | 图片支持 |
|
||||
| :--- | :---: | :---: |
|
||||
| [**LMArena**](https://lmarena.ai/) | ✅ | ✅ |
|
||||
| [**Gemini Enterprise Business**](https://business.gemini.google/) | ✅ | ✅ |
|
||||
| [**Nano Banana Free**](https://nanobananafree.ai/) | ❌ | ✅ |
|
||||
| [**zAI**](https://zai.is/) | ❌ | ✅ |
|
||||
| [**Google Gemini**](https://gemini.google.com/) | ✅ | ✅ |
|
||||
| [**ZenMux**](https://zenmux.ai/) | ✅ | ❌ |
|
||||
| 网站名称 | 文本生成 | 图片生成 | 视频生成 |
|
||||
| :--- | :---: | :---: | :---: |
|
||||
| [**LMArena**](https://lmarena.ai/) | ✅ | ✅ | 🚫 |
|
||||
| [**Gemini Enterprise Business**](https://business.gemini.google/) | ✅ | ✅ | ✅ |
|
||||
| [**Nano Banana Free**](https://nanobananafree.ai/) | 🚫 | ✅ | 🚫 |
|
||||
| [**zAI**](https://zai.is/) | ❌ | ✅ | 🚫 |
|
||||
| [**Google Gemini**](https://gemini.google.com/) | ✅ | ✅ | ✅ |
|
||||
| [**ZenMux**](https://zenmux.ai/) | ✅ | ❌ | 🚫 |
|
||||
| 待续... | - | - | - |
|
||||
|
||||
> [!NOTE]
|
||||
> **获取完整模型列表**: 通过 `GET /v1/models` 接口查看当前配置下所有可用模型及其详细信息。
|
||||
>
|
||||
> 未来可能会支持更多网站...
|
||||
> ✅目前支持;❌目前不支持,但未来可能会支持;🚫网站不支持,是否在支持看网站具体情况;
|
||||
|
||||
---
|
||||
|
||||
|
||||
@@ -71,16 +71,33 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
await fillPrompt(page, inputLocator, prompt, meta);
|
||||
await sleep(500, 1000);
|
||||
|
||||
// 4. 点击 Tools 按钮启用图片生成
|
||||
// 4. 点击 Tools 按钮启用图片/视频生成
|
||||
logger.debug('适配器', '点击 Tools 按钮...', meta);
|
||||
const toolsBtn = page.getByRole('button', { name: 'Tools' });
|
||||
await safeClick(page, toolsBtn, { bias: 'button' });
|
||||
await sleep(500, 1000);
|
||||
|
||||
// 5. 点击 Create images 按钮
|
||||
logger.debug('适配器', '点击 Create images 按钮...', meta);
|
||||
const createImagesBtn = page.getByRole('button', { name: 'Create images' });
|
||||
await safeClick(page, createImagesBtn, { bias: 'button' });
|
||||
// 检测是否是视频模型
|
||||
const isVideoModel = modelId && modelId.startsWith('veo-');
|
||||
|
||||
// 5. 点击 Create images / Create videos 按钮
|
||||
if (isVideoModel) {
|
||||
logger.debug('适配器', '点击 Create videos 按钮...', meta);
|
||||
const createVideosBtn = page.getByRole('button', { name: /^Create videos/ });
|
||||
|
||||
// 检查按钮是否存在(有些账号可能没有视频生成功能)
|
||||
const btnCount = await createVideosBtn.count();
|
||||
if (btnCount === 0) {
|
||||
logger.error('适配器', '未找到 Create videos 按钮,该账号可能不支持视频生成', meta);
|
||||
return { error: '该账号不支持视频生成功能 (未找到 Create videos 按钮)' };
|
||||
}
|
||||
|
||||
await safeClick(page, createVideosBtn, { bias: 'button' });
|
||||
} else {
|
||||
logger.debug('适配器', '点击 Create images 按钮...', meta);
|
||||
const createImagesBtn = page.getByRole('button', { name: 'Create images' });
|
||||
await safeClick(page, createImagesBtn, { bias: 'button' });
|
||||
}
|
||||
await sleep(500, 1000);
|
||||
|
||||
// 6. 点击发送
|
||||
@@ -111,33 +128,64 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
return { error: `API 返回错误: ${httpError.error}` };
|
||||
}
|
||||
|
||||
logger.info('适配器', '生成请求成功,等待图片...', meta);
|
||||
// 8. 等待图片/视频响应
|
||||
if (isVideoModel) {
|
||||
// 视频模式:等待视频下载链接
|
||||
logger.info('适配器', '生成请求成功,等待视频...', meta);
|
||||
|
||||
// 8. 等待图片响应
|
||||
let imageResponse;
|
||||
try {
|
||||
imageResponse = await waitApiResponse(page, {
|
||||
urlMatch: 'googleusercontent.com/rd-gg-dl',
|
||||
urlContains: '=s1024-rj',
|
||||
method: 'GET',
|
||||
timeout: 60000,
|
||||
meta
|
||||
});
|
||||
} catch (e) {
|
||||
const pageError = normalizePageError(e, meta);
|
||||
if (pageError) return pageError;
|
||||
throw e;
|
||||
let videoResponse;
|
||||
try {
|
||||
videoResponse = await waitApiResponse(page, {
|
||||
urlMatch: 'contribution.usercontent.google.com/download',
|
||||
urlContains: 'filename=video.mp4',
|
||||
method: 'GET',
|
||||
timeout: 180000, // 视频生成可能更慢
|
||||
meta
|
||||
});
|
||||
} catch (e) {
|
||||
const pageError = normalizePageError(e, meta);
|
||||
if (pageError) return pageError;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 获取视频数据
|
||||
const buffer = await videoResponse.body();
|
||||
const base64 = buffer.toString('base64');
|
||||
const contentType = videoResponse.headers()['content-type'] || 'video/mp4';
|
||||
const videoData = `data:${contentType};base64,${base64}`;
|
||||
|
||||
logger.info('适配器', '已获取视频,任务完成', meta);
|
||||
return { image: videoData };
|
||||
|
||||
} else {
|
||||
// 图片模式
|
||||
logger.info('适配器', '生成请求成功,等待图片...', meta);
|
||||
|
||||
let imageResponse;
|
||||
try {
|
||||
imageResponse = await waitApiResponse(page, {
|
||||
urlMatch: 'googleusercontent.com/rd-gg-dl',
|
||||
urlContains: '=s1024-rj',
|
||||
method: 'GET',
|
||||
timeout: 60000,
|
||||
meta
|
||||
});
|
||||
} catch (e) {
|
||||
const pageError = normalizePageError(e, meta);
|
||||
if (pageError) return pageError;
|
||||
throw e;
|
||||
}
|
||||
|
||||
// 获取图片数据
|
||||
const buffer = await imageResponse.body();
|
||||
const base64 = buffer.toString('base64');
|
||||
const contentType = imageResponse.headers()['content-type'] || 'image/jpeg';
|
||||
const imageData = `data:${contentType};base64,${base64}`;
|
||||
|
||||
logger.info('适配器', '已获取图片,任务完成', meta);
|
||||
return { image: imageData };
|
||||
}
|
||||
|
||||
// 获取图片数据
|
||||
const buffer = await imageResponse.body();
|
||||
const base64 = buffer.toString('base64');
|
||||
const contentType = imageResponse.headers()['content-type'] || 'image/jpeg';
|
||||
const imageData = `data:${contentType};base64,${base64}`;
|
||||
|
||||
logger.info('适配器', '已获取图片,任务完成', meta);
|
||||
return { image: imageData };
|
||||
|
||||
} catch (err) {
|
||||
// 顶层错误处理
|
||||
const pageError = normalizePageError(err, meta);
|
||||
@@ -156,7 +204,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'gemini',
|
||||
displayName: 'Gemini (Consumer)',
|
||||
displayName: 'Google Gemini (图片、视频生成)',
|
||||
|
||||
// 入口 URL
|
||||
getTargetUrl(config, workerConfig) {
|
||||
@@ -165,7 +213,8 @@ export const manifest = {
|
||||
|
||||
// 模型列表
|
||||
models: [
|
||||
{ id: 'gemini-3-pro-image-preview', imagePolicy: 'optional' }
|
||||
{ id: 'gemini-3-pro-image-preview', imagePolicy: 'optional' },
|
||||
{ id: 'veo-3.1-generate-preview', imagePolicy: 'optional' }
|
||||
],
|
||||
|
||||
// 无需导航处理器
|
||||
|
||||
@@ -171,9 +171,16 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
logger.debug('适配器', '已拦截请求,正在修改...', meta);
|
||||
if (!postData.streamAssistRequest) postData.streamAssistRequest = {};
|
||||
if (!postData.streamAssistRequest.assistGenerationConfig) postData.streamAssistRequest.assistGenerationConfig = {};
|
||||
postData.streamAssistRequest.toolsSpec = { imageGenerationSpec: {} };
|
||||
|
||||
logger.info('适配器', '已拦截请求,强制使用 Nano Banana Pro', meta);
|
||||
// 根据模型 ID 选择 toolsSpec
|
||||
if (modelId && modelId.startsWith('veo-')) {
|
||||
postData.streamAssistRequest.toolsSpec = { videoGenerationSpec: {} };
|
||||
logger.info('适配器', '已拦截请求,使用视频生成规格', meta);
|
||||
} else {
|
||||
postData.streamAssistRequest.toolsSpec = { imageGenerationSpec: {} };
|
||||
logger.info('适配器', '已拦截请求,使用图片生成规格', meta);
|
||||
}
|
||||
|
||||
await route.continue({ postData: JSON.stringify(postData) });
|
||||
return;
|
||||
}
|
||||
@@ -239,8 +246,12 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
|
||||
|
||||
const base64 = await imageResponse.text();
|
||||
logger.info('适配器', '已下载图片,任务完成', meta);
|
||||
const dataUri = `data:image/png;base64,${base64}`;
|
||||
|
||||
// 从响应头获取内容类型
|
||||
const contentType = imageResponse.headers()['x-goog-safety-content-type'] || 'image/png';
|
||||
logger.info('适配器', `已下载内容,类型: ${contentType}`, meta);
|
||||
|
||||
const dataUri = `data:${contentType};base64,${base64}`;
|
||||
return { image: dataUri };
|
||||
|
||||
|
||||
@@ -264,7 +275,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'gemini_biz',
|
||||
displayName: 'Gemini Business',
|
||||
displayName: 'Gemini Business (图片、视频生成)',
|
||||
|
||||
// 配置表单定义
|
||||
configSchema: [
|
||||
@@ -284,7 +295,8 @@ export const manifest = {
|
||||
|
||||
// 模型列表
|
||||
models: [
|
||||
{ id: 'gemini-3-pro-image-preview', imagePolicy: 'optional' }
|
||||
{ id: 'gemini-3-pro-image-preview', imagePolicy: 'optional' },
|
||||
{ id: 'veo-3.1-generate-preview', imagePolicy: 'optional' },
|
||||
],
|
||||
|
||||
// 导航处理器
|
||||
|
||||
@@ -307,7 +307,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'gemini_biz_text',
|
||||
displayName: 'Gemini Business (Text)',
|
||||
displayName: 'Gemini Business (文本生成)',
|
||||
|
||||
// 配置表单定义(与 gemini_biz 共享配置)
|
||||
configSchema: [
|
||||
|
||||
@@ -215,7 +215,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'gemini_text',
|
||||
displayName: 'Gemini Text (Consumer)',
|
||||
displayName: 'Google Gemini (文本生成)',
|
||||
|
||||
getTargetUrl(config, workerConfig) {
|
||||
return TARGET_URL;
|
||||
|
||||
@@ -179,7 +179,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'lmarena',
|
||||
displayName: 'LMArena',
|
||||
displayName: 'LMArena (图片生成)',
|
||||
|
||||
// 配置项模式
|
||||
configSchema: [
|
||||
|
||||
@@ -170,7 +170,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'lmarena_text',
|
||||
displayName: 'LMArena Text',
|
||||
displayName: 'LMArena (文本生成)',
|
||||
|
||||
// 入口 URL
|
||||
getTargetUrl(config, workerConfig) {
|
||||
|
||||
@@ -135,7 +135,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'nanobananafree_ai',
|
||||
displayName: 'NanoBananaFree AI',
|
||||
displayName: 'NanoBananaFree (图片生成)',
|
||||
|
||||
// 入口 URL
|
||||
getTargetUrl(config, workerConfig) {
|
||||
|
||||
@@ -196,7 +196,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'turnstile_test',
|
||||
displayName: 'Cloudflare Turnstile Test',
|
||||
displayName: 'Cloudflare Turnstile Test (CF人机验证码测试)',
|
||||
|
||||
getTargetUrl(config, workerConfig) {
|
||||
return TARGET_URL;
|
||||
|
||||
@@ -348,7 +348,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'zai_is',
|
||||
displayName: 'zAI (zai.is)',
|
||||
displayName: 'zAI (图片生成)',
|
||||
|
||||
// 入口 URL
|
||||
getTargetUrl(config, workerConfig) {
|
||||
|
||||
@@ -238,7 +238,7 @@ async function generate(context, prompt, imgPaths, modelId, meta = {}) {
|
||||
*/
|
||||
export const manifest = {
|
||||
id: 'zenmux_ai',
|
||||
displayName: 'Zenmux AI',
|
||||
displayName: 'Zenmux AI (文本生成)',
|
||||
|
||||
// 无需额外配置
|
||||
configSchema: [],
|
||||
|
||||
+7
-2
@@ -131,11 +131,16 @@ export function createQueueManager(queueConfig, callbacks) {
|
||||
// 生成成功
|
||||
let finalContent = '';
|
||||
if (result.image) {
|
||||
finalContent = ``;
|
||||
logger.info('服务器', '图片已准备就绪 (Base64)', { id });
|
||||
// 只有图片格式才使用 markdown,视频等其他格式直接返回 data URI
|
||||
if (result.image.startsWith('data:image/')) {
|
||||
finalContent = ``;
|
||||
} else {
|
||||
finalContent = result.image;
|
||||
}
|
||||
} else {
|
||||
finalContent = result.text || '生成失败';
|
||||
}
|
||||
logger.info('服务器', '结果已准备就绪', { id });
|
||||
|
||||
// 发送成功响应
|
||||
logger.info('服务器', '准备发送响应...', { id, isStreaming, contentLength: finalContent.length });
|
||||
|
||||
Vendored
+1
-1
@@ -1 +1 @@
|
||||
import{c as i,I as u}from"./index-UseUKVwr.js";var l={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 140H96c-17.7 0-32 14.3-32 32v496c0 17.7 14.3 32 32 32h380v112H304c-8.8 0-16 7.2-16 16v48c0 4.4 3.6 8 8 8h432c4.4 0 8-3.6 8-8v-48c0-8.8-7.2-16-16-16H548V700h380c17.7 0 32-14.3 32-32V172c0-17.7-14.3-32-32-32zm-40 488H136V212h752v416z"}}]},name:"desktop",theme:"outlined"};function c(r){for(var t=1;t<arguments.length;t++){var e=arguments[t]!=null?Object(arguments[t]):{},n=Object.keys(e);typeof Object.getOwnPropertySymbols=="function"&&(n=n.concat(Object.getOwnPropertySymbols(e).filter(function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.forEach(function(a){s(r,a,e[a])})}return r}function s(r,t,e){return t in r?Object.defineProperty(r,t,{value:e,enumerable:!0,configurable:!0,writable:!0}):r[t]=e,r}var o=function(t,e){var n=c({},t,e.attrs);return i(u,c({},n,{icon:l}),null)};o.displayName="DesktopOutlined";o.inheritAttrs=!1;export{o as D};
|
||||
import{c as i,I as u}from"./index-SQeV-w6F.js";var l={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M928 140H96c-17.7 0-32 14.3-32 32v496c0 17.7 14.3 32 32 32h380v112H304c-8.8 0-16 7.2-16 16v48c0 4.4 3.6 8 8 8h432c4.4 0 8-3.6 8-8v-48c0-8.8-7.2-16-16-16H548V700h380c17.7 0 32-14.3 32-32V172c0-17.7-14.3-32-32-32zm-40 488H136V212h752v416z"}}]},name:"desktop",theme:"outlined"};function c(r){for(var t=1;t<arguments.length;t++){var e=arguments[t]!=null?Object(arguments[t]):{},n=Object.keys(e);typeof Object.getOwnPropertySymbols=="function"&&(n=n.concat(Object.getOwnPropertySymbols(e).filter(function(a){return Object.getOwnPropertyDescriptor(e,a).enumerable}))),n.forEach(function(a){s(r,a,e[a])})}return r}function s(r,t,e){return t in r?Object.defineProperty(r,t,{value:e,enumerable:!0,configurable:!0,writable:!0}):r[t]=e,r}var o=function(t,e){var n=c({},t,e.attrs);return i(u,c({},n,{icon:l}),null)};o.displayName="DesktopOutlined";o.inheritAttrs=!1;export{o as D};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{c as l,I as q,j as I,r as b,k as D,o as F,l as T,b as _,d as u,w as s,e as v,f as c,g as y,u as h,t as w,S as L,h as g,i as f,m as G,F as J}from"./index-UseUKVwr.js";var Q={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"};function S(p){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?Object(arguments[n]):{},o=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(o=o.concat(Object.getOwnPropertySymbols(a).filter(function(t){return Object.getOwnPropertyDescriptor(a,t).enumerable}))),o.forEach(function(t){R(p,t,a[t])})}return p}function R(p,n,a){return n in p?Object.defineProperty(p,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):p[n]=a,p}var k=function(n,a){var o=S({},n,a.attrs);return l(q,S({},o,{icon:Q}),null)};k.displayName="AppstoreOutlined";k.inheritAttrs=!1;const W={style:{display:"flex","align-items":"center","justify-content":"space-between",gap:"8px"}},X={style:{display:"flex","align-items":"center","min-width":"0",flex:"1"}},Y={style:{"font-weight":"600","font-size":"14px",overflow:"hidden","text-overflow":"ellipsis","white-space":"nowrap"}},Z={key:0},K={key:2},ee={key:4,style:{"font-size":"12px",color:"#8c8c8c","margin-top":"4px"}},te={style:{"text-align":"right"}},ae={__name:"adapters",setup(p){const n=I(),a=b(!1),o=b(null),t=D({});F(async()=>{await Promise.all([n.fetchAdaptersMeta(),n.fetchAdapterConfig()])});const O=T(()=>n.adaptersMeta),C=m=>{o.value=m;const r=n.adapterConfig[m.id]||{};Object.keys(t).forEach(i=>delete t[i]),m.configSchema&&m.configSchema.forEach(i=>{r[i.key]!==void 0?t[i.key]=r[i.key]:t[i.key]=i.default}),a.value=!0},V=async()=>{if(!o.value)return;const m={[o.value.id]:{...t}};await n.saveAdapterConfig(m)&&(a.value=!1)};return(m,r)=>{const i=c("a-button"),x=c("a-card"),z=c("a-list-item"),A=c("a-list"),U=c("a-empty"),H=c("a-input"),j=c("a-input-number"),M=c("a-switch"),P=c("a-select"),B=c("a-form-item"),E=c("a-form"),N=c("a-drawer"),$=c("a-layout");return u(),_($,{style:{background:"transparent"}},{default:s(()=>[l(x,{title:"适配器管理",bordered:!1},{extra:s(()=>[l(i,{type:"link",onClick:h(n).fetchAdaptersMeta},{default:s(()=>[...r[2]||(r[2]=[g("刷新列表",-1)])]),_:1},8,["onClick"])]),default:s(()=>[l(A,{grid:{gutter:16,xs:1,sm:2,md:3,lg:3,xl:4,xxl:4},"data-source":O.value},{renderItem:s(({item:e})=>[l(z,null,{default:s(()=>[l(x,{hoverable:"",onClick:d=>C(e),bodyStyle:{padding:"12px 16px"}},{default:s(()=>[y("div",W,[y("div",X,[l(h(k),{style:{"font-size":"18px",color:"#1890ff","margin-right":"8px","flex-shrink":"0"}}),y("span",Y,w(e.id),1)]),l(h(L),{style:{"font-size":"16px",color:"#8c8c8c","flex-shrink":"0"}})])]),_:2},1032,["onClick"])]),_:2},1024)]),_:1},8,["data-source"])]),_:1}),o.value?(u(),_(N,{key:0,open:a.value,"onUpdate:open":r[1]||(r[1]=e=>a.value=e),title:`配置适配器 - ${o.value.id}`,width:"500",placement:"right"},{footer:s(()=>[y("div",te,[l(i,{style:{"margin-right":"8px"},onClick:r[0]||(r[0]=e=>a.value=!1)},{default:s(()=>[...r[3]||(r[3]=[g("取消",-1)])]),_:1}),l(i,{type:"primary",onClick:V},{default:s(()=>[...r[4]||(r[4]=[g("保存配置",-1)])]),_:1})])]),default:s(()=>[!o.value.configSchema||o.value.configSchema.length===0?(u(),f("div",Z,[l(U,{description:"该适配器没有可配置项"})])):(u(),_(E,{key:1,layout:"vertical"},{default:s(()=>[(u(!0),f(J,null,G(o.value.configSchema,e=>(u(),_(B,{key:e.key,label:e.label,required:e.required},{default:s(()=>[e.type==="string"?(u(),_(H,{key:0,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,placeholder:e.placeholder},null,8,["value","onUpdate:value","placeholder"])):v("",!0),e.type==="number"?(u(),_(j,{key:1,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,min:e.min,max:e.max,style:{width:"100%"}},null,8,["value","onUpdate:value","min","max"])):v("",!0),e.type==="boolean"?(u(),f("div",K,[l(M,{checked:t[e.key],"onUpdate:checked":d=>t[e.key]=d},null,8,["checked","onUpdate:checked"])])):v("",!0),e.type==="select"?(u(),_(P,{key:3,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,options:e.options},null,8,["value","onUpdate:value","options"])):v("",!0),e.note?(u(),f("div",ee,w(e.note),1)):v("",!0)]),_:2},1032,["label","required"]))),128))]),_:1}))]),_:1},8,["open","title"])):v("",!0)]),_:1})}}};export{ae as default};
|
||||
import{c as l,I as q,j as I,r as b,k as D,o as F,l as T,b as _,d as u,w as s,e as v,f as c,g as y,u as h,t as w,S as L,h as g,i as f,m as G,F as J}from"./index-SQeV-w6F.js";var Q={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 144H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H212V212h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V160c0-8.8-7.2-16-16-16zm-52 268H612V212h200v200zM464 544H160c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H212V612h200v200zm452-268H560c-8.8 0-16 7.2-16 16v304c0 8.8 7.2 16 16 16h304c8.8 0 16-7.2 16-16V560c0-8.8-7.2-16-16-16zm-52 268H612V612h200v200z"}}]},name:"appstore",theme:"outlined"};function S(p){for(var n=1;n<arguments.length;n++){var a=arguments[n]!=null?Object(arguments[n]):{},o=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(o=o.concat(Object.getOwnPropertySymbols(a).filter(function(t){return Object.getOwnPropertyDescriptor(a,t).enumerable}))),o.forEach(function(t){R(p,t,a[t])})}return p}function R(p,n,a){return n in p?Object.defineProperty(p,n,{value:a,enumerable:!0,configurable:!0,writable:!0}):p[n]=a,p}var k=function(n,a){var o=S({},n,a.attrs);return l(q,S({},o,{icon:Q}),null)};k.displayName="AppstoreOutlined";k.inheritAttrs=!1;const W={style:{display:"flex","align-items":"center","justify-content":"space-between",gap:"8px"}},X={style:{display:"flex","align-items":"center","min-width":"0",flex:"1"}},Y={style:{"font-weight":"600","font-size":"14px",overflow:"hidden","text-overflow":"ellipsis","white-space":"nowrap"}},Z={key:0},K={key:2},ee={key:4,style:{"font-size":"12px",color:"#8c8c8c","margin-top":"4px"}},te={style:{"text-align":"right"}},ae={__name:"adapters",setup(p){const n=I(),a=b(!1),o=b(null),t=D({});F(async()=>{await Promise.all([n.fetchAdaptersMeta(),n.fetchAdapterConfig()])});const O=T(()=>n.adaptersMeta),C=m=>{o.value=m;const r=n.adapterConfig[m.id]||{};Object.keys(t).forEach(i=>delete t[i]),m.configSchema&&m.configSchema.forEach(i=>{r[i.key]!==void 0?t[i.key]=r[i.key]:t[i.key]=i.default}),a.value=!0},V=async()=>{if(!o.value)return;const m={[o.value.id]:{...t}};await n.saveAdapterConfig(m)&&(a.value=!1)};return(m,r)=>{const i=c("a-button"),x=c("a-card"),z=c("a-list-item"),A=c("a-list"),U=c("a-empty"),H=c("a-input"),j=c("a-input-number"),M=c("a-switch"),P=c("a-select"),B=c("a-form-item"),E=c("a-form"),N=c("a-drawer"),$=c("a-layout");return u(),_($,{style:{background:"transparent"}},{default:s(()=>[l(x,{title:"适配器管理",bordered:!1},{extra:s(()=>[l(i,{type:"link",onClick:h(n).fetchAdaptersMeta},{default:s(()=>[...r[2]||(r[2]=[g("刷新列表",-1)])]),_:1},8,["onClick"])]),default:s(()=>[l(A,{grid:{gutter:16,xs:1,sm:2,md:3,lg:3,xl:4,xxl:4},"data-source":O.value},{renderItem:s(({item:e})=>[l(z,null,{default:s(()=>[l(x,{hoverable:"",onClick:d=>C(e),bodyStyle:{padding:"12px 16px"}},{default:s(()=>[y("div",W,[y("div",X,[l(h(k),{style:{"font-size":"18px",color:"#1890ff","margin-right":"8px","flex-shrink":"0"}}),y("span",Y,w(e.id),1)]),l(h(L),{style:{"font-size":"16px",color:"#8c8c8c","flex-shrink":"0"}})])]),_:2},1032,["onClick"])]),_:2},1024)]),_:1},8,["data-source"])]),_:1}),o.value?(u(),_(N,{key:0,open:a.value,"onUpdate:open":r[1]||(r[1]=e=>a.value=e),title:`配置适配器 - ${o.value.id}`,width:"500",placement:"right"},{footer:s(()=>[y("div",te,[l(i,{style:{"margin-right":"8px"},onClick:r[0]||(r[0]=e=>a.value=!1)},{default:s(()=>[...r[3]||(r[3]=[g("取消",-1)])]),_:1}),l(i,{type:"primary",onClick:V},{default:s(()=>[...r[4]||(r[4]=[g("保存配置",-1)])]),_:1})])]),default:s(()=>[!o.value.configSchema||o.value.configSchema.length===0?(u(),f("div",Z,[l(U,{description:"该适配器没有可配置项"})])):(u(),_(E,{key:1,layout:"vertical"},{default:s(()=>[(u(!0),f(J,null,G(o.value.configSchema,e=>(u(),_(B,{key:e.key,label:e.label,required:e.required},{default:s(()=>[e.type==="string"?(u(),_(H,{key:0,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,placeholder:e.placeholder},null,8,["value","onUpdate:value","placeholder"])):v("",!0),e.type==="number"?(u(),_(j,{key:1,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,min:e.min,max:e.max,style:{width:"100%"}},null,8,["value","onUpdate:value","min","max"])):v("",!0),e.type==="boolean"?(u(),f("div",K,[l(M,{checked:t[e.key],"onUpdate:checked":d=>t[e.key]=d},null,8,["checked","onUpdate:checked"])])):v("",!0),e.type==="select"?(u(),_(P,{key:3,value:t[e.key],"onUpdate:value":d=>t[e.key]=d,options:e.options},null,8,["value","onUpdate:value","options"])):v("",!0),e.note?(u(),f("div",ee,w(e.note),1)):v("",!0)]),_:2},1032,["label","required"]))),128))]),_:1}))]),_:1},8,["open","title"])):v("",!0)]),_:1})}}};export{ae as default};
|
||||
+1
-1
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+1
-1
File diff suppressed because one or more lines are too long
+1
-1
@@ -1 +1 @@
|
||||
[data-v-dbebb88a]::-webkit-scrollbar{width:6px;height:6px}[data-v-dbebb88a]::-webkit-scrollbar-thumb{background:#ccc;border-radius:3px}[data-v-dbebb88a]::-webkit-scrollbar-track{background:#f1f1f1}html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
||||
[data-v-5ef25f71]::-webkit-scrollbar{width:6px;height:6px}[data-v-5ef25f71]::-webkit-scrollbar-thumb{background:#ccc;border-radius:3px}[data-v-5ef25f71]::-webkit-scrollbar-track{background:#f1f1f1}html,body{width:100%;height:100%}input::-ms-clear,input::-ms-reveal{display:none}*,*:before,*:after{box-sizing:border-box}html{font-family:sans-serif;line-height:1.15;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%;-ms-overflow-style:scrollbar;-webkit-tap-highlight-color:rgba(0,0,0,0)}@-ms-viewport{width:device-width}body{margin:0}[tabindex="-1"]:focus{outline:none}hr{box-sizing:content-box;height:0;overflow:visible}h1,h2,h3,h4,h5,h6{margin-top:0;margin-bottom:.5em;font-weight:500}p{margin-top:0;margin-bottom:1em}abbr[title],abbr[data-original-title]{-webkit-text-decoration:underline dotted;text-decoration:underline;text-decoration:underline dotted;border-bottom:0;cursor:help}address{margin-bottom:1em;font-style:normal;line-height:inherit}input[type=text],input[type=password],input[type=number],textarea{-webkit-appearance:none}ol,ul,dl{margin-top:0;margin-bottom:1em}ol ol,ul ul,ol ul,ul ol{margin-bottom:0}dt{font-weight:500}dd{margin-bottom:.5em;margin-left:0}blockquote{margin:0 0 1em}dfn{font-style:italic}b,strong{font-weight:bolder}small{font-size:80%}sub,sup{position:relative;font-size:75%;line-height:0;vertical-align:baseline}sub{bottom:-.25em}sup{top:-.5em}pre,code,kbd,samp{font-size:1em;font-family:SFMono-Regular,Consolas,Liberation Mono,Menlo,Courier,monospace}pre{margin-top:0;margin-bottom:1em;overflow:auto}figure{margin:0 0 1em}img{vertical-align:middle;border-style:none}a,area,button,[role=button],input:not([type=range]),label,select,summary,textarea{touch-action:manipulation}table{border-collapse:collapse}caption{padding-top:.75em;padding-bottom:.3em;text-align:left;caption-side:bottom}input,button,select,optgroup,textarea{margin:0;color:inherit;font-size:inherit;font-family:inherit;line-height:inherit}button,input{overflow:visible}button,select{text-transform:none}button,html [type=button],[type=reset],[type=submit]{-webkit-appearance:button}button::-moz-focus-inner,[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner{padding:0;border-style:none}input[type=radio],input[type=checkbox]{box-sizing:border-box;padding:0}input[type=date],input[type=time],input[type=datetime-local],input[type=month]{-webkit-appearance:listbox}textarea{overflow:auto;resize:vertical}fieldset{min-width:0;margin:0;padding:0;border:0}legend{display:block;width:100%;max-width:100%;margin-bottom:.5em;padding:0;color:inherit;font-size:1.5em;line-height:inherit;white-space:normal}progress{vertical-align:baseline}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{outline-offset:-2px;-webkit-appearance:none}[type=search]::-webkit-search-cancel-button,[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{font:inherit;-webkit-appearance:button}output{display:inline-block}summary{display:list-item}template{display:none}[hidden]{display:none!important}mark{padding:.2em;background-color:#feffe6}
|
||||
+67
-67
File diff suppressed because one or more lines are too long
@@ -1,2 +1,2 @@
|
||||
import{c as l,I as P,_ as q,j as J,r as p,l as Q,o as X,a as Y,b as N,d as b,w as s,g as v,f,h as m,u as C,R as k,y as Z,D as K,i as L,e as S,t as _,m as ee,F as te,s as R,M as ae,z as le,A as ne,B as oe}from"./index-UseUKVwr.js";var se={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1a184.31 184.31 0 00-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9a184.31 184.31 0 00-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8a63 63 0 01-63 63H232a63 63 0 01-63-63c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5.2 13 .7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7a273 273 0 0022.7 49c24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2a281.38 281.38 0 00123.2-149.5A120 120 0 01836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7.4-6.4.7-12.8.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3C584 874.3 548.8 884 512 884s-72-9.7-102.9-27.8c-30.3-17.7-55.6-43-73.3-73.3A202.75 202.75 0 01308 680V412h408v268z"}}]},name:"bug",theme:"outlined"};function D(n){for(var t=1;t<arguments.length;t++){var a=arguments[t]!=null?Object(arguments[t]):{},r=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(r=r.concat(Object.getOwnPropertySymbols(a).filter(function(c){return Object.getOwnPropertyDescriptor(a,c).enumerable}))),r.forEach(function(c){re(n,c,a[c])})}return n}function re(n,t,a){return t in n?Object.defineProperty(n,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):n[t]=a,n}var j=function(t,a){var r=D({},t,a.attrs);return l(P,D({},r,{icon:se}),null)};j.displayName="BugOutlined";j.inheritAttrs=!1;var ce={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8zm475.7 440l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zm-783.5-27.9L512 239.9l339.8 588.2H172.2z"}}]},name:"warning",theme:"outlined"};function E(n){for(var t=1;t<arguments.length;t++){var a=arguments[t]!=null?Object(arguments[t]):{},r=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(r=r.concat(Object.getOwnPropertySymbols(a).filter(function(c){return Object.getOwnPropertyDescriptor(a,c).enumerable}))),r.forEach(function(c){ie(n,c,a[c])})}return n}function ie(n,t,a){return t in n?Object.defineProperty(n,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):n[t]=a,n}var I=function(t,a){var r=E({},t,a.attrs);return l(P,E({},r,{icon:ce}),null)};I.displayName="WarningOutlined";I.inheritAttrs=!1;const ue={class:"toolbar"},de={class:"toolbar-row"},fe={class:"toolbar-row"},ve={style:{"margin-bottom":"12px",color:"#8c8c8c","font-size":"12px"}},me={key:0,style:{color:"#1890ff","margin-left":"8px"}},pe={class:"log-container"},ge={class:"log-time"},_e={class:"log-module"},he={class:"log-message"},Oe={__name:"logs",setup(n){const t=J(),a=p([]),r=p(!1),c=p(0),h=p(!1),g=p(null),y=p(""),w=p("all"),U={INFO:{color:"#1890ff",icon:oe},WARN:{color:"#faad14",icon:I},ERRO:{color:"#ff4d4f",icon:ne},DBUG:{color:"#722ed1",icon:j}},z=async()=>{r.value=!0;try{const o=await fetch("/admin/logs?lines=500",{headers:t.getHeaders()});if(o.ok){const e=await o.json();a.value=A(e.logs||[]),c.value=e.total||0}}catch{R.error("获取日志失败")}finally{r.value=!1}},A=o=>o.map((e,u)=>{const d=e.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \[(\w+)\] \[([^\]]+)\] (.*)$/);return d?{id:u,time:d[1],level:d[2],module:d[3],message:d[4],raw:e}:{id:u,raw:e,level:"INFO",time:"",module:"",message:e}}),x=Q(()=>a.value.filter(o=>{if(w.value!=="all"&&o.level!==w.value)return!1;if(y.value){const e=y.value.toLowerCase();return o.raw.toLowerCase().includes(e)}return!0})),F=()=>{ae.confirm({title:"确认清除日志",content:"此操作将删除所有系统日志文件,是否继续?",okText:"确认清除",okType:"danger",cancelText:"取消",async onOk(){try{(await fetch("/admin/logs",{method:"DELETE",headers:t.getHeaders()})).ok?(R.success("日志已清除"),a.value=[],c.value=0):R.error("清除失败")}catch{R.error("请求失败")}}})},M=()=>{const o=a.value.map(O=>O.raw).join(`
|
||||
import{c as l,I as P,_ as q,j as J,r as p,l as Q,o as X,a as Y,b as N,d as b,w as s,g as v,f,h as m,u as C,R as k,y as Z,D as K,i as L,e as S,t as _,m as ee,F as te,s as R,M as ae,z as le,A as ne,B as oe}from"./index-SQeV-w6F.js";var se={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M304 280h56c4.4 0 8-3.6 8-8 0-28.3 5.9-53.2 17.1-73.5 10.6-19.4 26-34.8 45.4-45.4C450.9 142 475.7 136 504 136h16c28.3 0 53.2 5.9 73.5 17.1 19.4 10.6 34.8 26 45.4 45.4C650 218.9 656 243.7 656 272c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-40-8.8-76.7-25.9-108.1a184.31 184.31 0 00-74-74C596.7 72.8 560 64 520 64h-16c-40 0-76.7 8.8-108.1 25.9a184.31 184.31 0 00-74 74C304.8 195.3 296 232 296 272c0 4.4 3.6 8 8 8z"}},{tag:"path",attrs:{d:"M940 512H792V412c76.8 0 139-62.2 139-139 0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8a63 63 0 01-63 63H232a63 63 0 01-63-63c0-4.4-3.6-8-8-8h-60c-4.4 0-8 3.6-8 8 0 76.8 62.2 139 139 139v100H84c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h148v96c0 6.5.2 13 .7 19.3C164.1 728.6 116 796.7 116 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-44.2 23.9-82.9 59.6-103.7a273 273 0 0022.7 49c24.3 41.5 59 76.2 100.5 100.5S460.5 960 512 960s99.8-13.9 141.3-38.2a281.38 281.38 0 00123.2-149.5A120 120 0 01836 876c0 4.4 3.6 8 8 8h56c4.4 0 8-3.6 8-8 0-79.3-48.1-147.4-116.7-176.7.4-6.4.7-12.8.7-19.3v-96h148c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM716 680c0 36.8-9.7 72-27.8 102.9-17.7 30.3-43 55.6-73.3 73.3C584 874.3 548.8 884 512 884s-72-9.7-102.9-27.8c-30.3-17.7-55.6-43-73.3-73.3A202.75 202.75 0 01308 680V412h408v268z"}}]},name:"bug",theme:"outlined"};function D(n){for(var t=1;t<arguments.length;t++){var a=arguments[t]!=null?Object(arguments[t]):{},r=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(r=r.concat(Object.getOwnPropertySymbols(a).filter(function(c){return Object.getOwnPropertyDescriptor(a,c).enumerable}))),r.forEach(function(c){re(n,c,a[c])})}return n}function re(n,t,a){return t in n?Object.defineProperty(n,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):n[t]=a,n}var j=function(t,a){var r=D({},t,a.attrs);return l(P,D({},r,{icon:se}),null)};j.displayName="BugOutlined";j.inheritAttrs=!1;var ce={icon:{tag:"svg",attrs:{viewBox:"64 64 896 896",focusable:"false"},children:[{tag:"path",attrs:{d:"M464 720a48 48 0 1096 0 48 48 0 10-96 0zm16-304v184c0 4.4 3.6 8 8 8h48c4.4 0 8-3.6 8-8V416c0-4.4-3.6-8-8-8h-48c-4.4 0-8 3.6-8 8zm475.7 440l-416-720c-6.2-10.7-16.9-16-27.7-16s-21.6 5.3-27.7 16l-416 720C56 877.4 71.4 904 96 904h832c24.6 0 40-26.6 27.7-48zm-783.5-27.9L512 239.9l339.8 588.2H172.2z"}}]},name:"warning",theme:"outlined"};function E(n){for(var t=1;t<arguments.length;t++){var a=arguments[t]!=null?Object(arguments[t]):{},r=Object.keys(a);typeof Object.getOwnPropertySymbols=="function"&&(r=r.concat(Object.getOwnPropertySymbols(a).filter(function(c){return Object.getOwnPropertyDescriptor(a,c).enumerable}))),r.forEach(function(c){ie(n,c,a[c])})}return n}function ie(n,t,a){return t in n?Object.defineProperty(n,t,{value:a,enumerable:!0,configurable:!0,writable:!0}):n[t]=a,n}var I=function(t,a){var r=E({},t,a.attrs);return l(P,E({},r,{icon:ce}),null)};I.displayName="WarningOutlined";I.inheritAttrs=!1;const ue={class:"toolbar"},de={class:"toolbar-row"},fe={class:"toolbar-row"},ve={style:{"margin-bottom":"12px",color:"#8c8c8c","font-size":"12px"}},me={key:0,style:{color:"#1890ff","margin-left":"8px"}},pe={class:"log-container"},ge={class:"log-time"},_e={class:"log-module"},he={class:"log-message"},Oe={__name:"logs",setup(n){const t=J(),a=p([]),r=p(!1),c=p(0),h=p(!1),g=p(null),y=p(""),w=p("all"),U={INFO:{color:"#1890ff",icon:oe},WARN:{color:"#faad14",icon:I},ERRO:{color:"#ff4d4f",icon:ne},DBUG:{color:"#722ed1",icon:j}},z=async()=>{r.value=!0;try{const o=await fetch("/admin/logs?lines=500",{headers:t.getHeaders()});if(o.ok){const e=await o.json();a.value=A(e.logs||[]),c.value=e.total||0}}catch{R.error("获取日志失败")}finally{r.value=!1}},A=o=>o.map((e,u)=>{const d=e.match(/^(\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}\.\d{3}) \[(\w+)\] \[([^\]]+)\] (.*)$/);return d?{id:u,time:d[1],level:d[2],module:d[3],message:d[4],raw:e}:{id:u,raw:e,level:"INFO",time:"",module:"",message:e}}),x=Q(()=>a.value.filter(o=>{if(w.value!=="all"&&o.level!==w.value)return!1;if(y.value){const e=y.value.toLowerCase();return o.raw.toLowerCase().includes(e)}return!0})),F=()=>{ae.confirm({title:"确认清除日志",content:"此操作将删除所有系统日志文件,是否继续?",okText:"确认清除",okType:"danger",cancelText:"取消",async onOk(){try{(await fetch("/admin/logs",{method:"DELETE",headers:t.getHeaders()})).ok?(R.success("日志已清除"),a.value=[],c.value=0):R.error("清除失败")}catch{R.error("请求失败")}}})},M=()=>{const o=a.value.map(O=>O.raw).join(`
|
||||
`),e=new Blob([o],{type:"text/plain"}),u=URL.createObjectURL(e),d=document.createElement("a");d.href=u,d.download=`system-${new Date().toISOString().split("T")[0]}.log`,d.click(),URL.revokeObjectURL(u)},T=o=>{h.value=o,o?(z(),g.value=setInterval(z,5e3)):g.value&&(clearInterval(g.value),g.value=null)};return X(()=>{z()}),Y(()=>{g.value&&clearInterval(g.value)}),(o,e)=>{const u=f("a-select-option"),d=f("a-select"),O=f("a-button"),B=f("a-tooltip"),V=f("a-space"),W=f("a-input-search"),$=f("a-tag"),H=f("a-empty"),G=f("a-card");return b(),N(G,{title:"系统日志",bordered:!1},{default:s(()=>[v("div",ue,[v("div",de,[l(d,{value:w.value,"onUpdate:value":e[0]||(e[0]=i=>w.value=i),style:{width:"90px"},size:"small"},{default:s(()=>[l(u,{value:"all"},{default:s(()=>[...e[3]||(e[3]=[m("全部",-1)])]),_:1}),l(u,{value:"INFO"},{default:s(()=>[...e[4]||(e[4]=[m("INFO",-1)])]),_:1}),l(u,{value:"WARN"},{default:s(()=>[...e[5]||(e[5]=[m("WARN",-1)])]),_:1}),l(u,{value:"ERRO"},{default:s(()=>[...e[6]||(e[6]=[m("ERROR",-1)])]),_:1}),l(u,{value:"DBUG"},{default:s(()=>[...e[7]||(e[7]=[m("DEBUG",-1)])]),_:1})]),_:1},8,["value"]),l(V,{size:4},{default:s(()=>[l(B,{title:h.value?"关闭自动刷新":"开启自动刷新"},{default:s(()=>[l(O,{size:"small",type:h.value?"primary":"default",onClick:e[1]||(e[1]=i=>T(!h.value))},{icon:s(()=>[l(C(k))]),_:1},8,["type"])]),_:1},8,["title"]),l(B,{title:"导出日志"},{default:s(()=>[l(O,{size:"small",onClick:M},{icon:s(()=>[l(C(Z))]),_:1})]),_:1}),l(B,{title:"清除日志"},{default:s(()=>[l(O,{size:"small",danger:"",onClick:F},{icon:s(()=>[l(C(K))]),_:1})]),_:1})]),_:1})]),v("div",fe,[l(W,{value:y.value,"onUpdate:value":e[2]||(e[2]=i=>y.value=i),placeholder:"搜索日志",size:"small","enter-button":"","allow-clear":"",style:{width:"100%"}},null,8,["value"])])]),v("div",ve,[m(" 共 "+_(c.value)+" 条日志,当前显示 "+_(x.value.length)+" 条 ",1),h.value?(b(),L("span",me,[l(C(k),{spin:!0}),e[8]||(e[8]=m(" 自动刷新中 ",-1))])):S("",!0)]),v("div",pe,[(b(!0),L(te,null,ee(x.value,i=>(b(),L("div",{key:i.id,class:le(["log-line","level-"+i.level.toLowerCase()])},[v("span",ge,_(i.time),1),l($,{color:U[i.level]?.color||"#8c8c8c",size:"small",style:{margin:"0 8px"}},{default:s(()=>[m(_(i.level),1)]),_:2},1032,["color"]),v("span",_e,"["+_(i.module)+"]",1),v("span",he,_(i.message),1)],2))),128)),x.value.length===0?(b(),N(H,{key:0,description:"暂无日志"})):S("",!0)])]),_:1})}}},ye=q(Oe,[["__scopeId","data-v-a8b1f18a"]]);export{ye as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{_ as b,j as w,k,o as c,b as C,d as S,w as n,c as o,g as e,f as a,h as i}from"./index-UseUKVwr.js";const B={style:{"margin-bottom":"8px"}},T={style:{"margin-bottom":"8px"}},z={style:{"margin-bottom":"8px"}},U={style:{display:"flex","justify-content":"flex-end","margin-top":"24px"}},j={style:{"margin-bottom":"8px"}},M={style:{"margin-bottom":"8px"}},q={style:{display:"flex","justify-content":"flex-end","margin-top":"24px"}},L={__name:"server",setup(N){const d=w(),s=k({port:5173,authToken:"",keepaliveMode:"comment",queueBuffer:2,imageLimit:5});c(async()=>{await d.fetchServerConfig(),Object.assign(s,d.serverConfig)});const m=async()=>{await d.saveServerConfig(s)};return(V,t)=>{const p=a("a-input-number"),r=a("a-col"),y=a("a-input-password"),u=a("a-select-option"),g=a("a-select"),f=a("a-row"),v=a("a-button"),x=a("a-card"),_=a("a-layout");return S(),C(_,{style:{background:"transparent"}},{default:n(()=>[o(x,{title:"服务器设置",bordered:!1,style:{width:"100%"}},{default:n(()=>[o(f,{gutter:[16,16]},{default:n(()=>[o(r,{xs:24,md:12},{default:n(()=>[e("div",B,[t[5]||(t[5]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"监听端口",-1)),t[6]||(t[6]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 设置服务器监听的端口号,默认为 5173 ",-1)),o(p,{value:s.port,"onUpdate:value":t[0]||(t[0]=l=>s.port=l),min:1,max:65535,placeholder:"请输入端口号",style:{width:"100%"}},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",T,[t[7]||(t[7]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"鉴权 Token",-1)),t[8]||(t[8]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 用于 API 请求鉴权的密钥,留空则不启用鉴权 ",-1)),o(y,{value:s.authToken,"onUpdate:value":t[1]||(t[1]=l=>s.authToken=l),placeholder:"请输入 Token",type:"password"},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",z,[t[11]||(t[11]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"心跳包类型",-1)),t[12]||(t[12]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 选择 SSE 流式响应的心跳包格式 ",-1)),o(g,{value:s.keepaliveMode,"onUpdate:value":t[2]||(t[2]=l=>s.keepaliveMode=l),style:{width:"100%"},placeholder:"请选择心跳包类型"},{default:n(()=>[o(u,{value:"comment"},{default:n(()=>[...t[9]||(t[9]=[i("Comment - 注释格式",-1)])]),_:1}),o(u,{value:"content"},{default:n(()=>[...t[10]||(t[10]=[i("Content - 内容格式",-1)])]),_:1})]),_:1},8,["value"])])]),_:1})]),_:1}),e("div",U,[o(v,{type:"primary",onClick:m},{default:n(()=>[...t[13]||(t[13]=[i(" 保存设置 ",-1)])]),_:1})])]),_:1}),o(x,{title:"队列设置",bordered:!1,style:{width:"100%","margin-top":"10px"}},{default:n(()=>[o(f,{gutter:[16,16]},{default:n(()=>[o(r,{xs:24,md:12},{default:n(()=>[e("div",j,[t[14]||(t[14]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"队列缓冲区大小",-1)),t[15]||(t[15]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}},[i(" 非流式请求的额外排队数(设为 0 则不限制非流式请求数量)"),e("br"),i(" 实际队列上限 = Workers数量 + 缓冲区大小 ")],-1)),o(p,{value:s.queueBuffer,"onUpdate:value":t[3]||(t[3]=l=>s.queueBuffer=l),min:0,max:100,placeholder:"默认为 2",style:{width:"100%"}},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",M,[t[16]||(t[16]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"图片数量上限",-1)),t[17]||(t[17]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}},[i(" 单次请求最多支持的图片附件数量"),e("br"),i(" 网页最多支持10个附件,超出会被丢弃 ")],-1)),o(p,{value:s.imageLimit,"onUpdate:value":t[4]||(t[4]=l=>s.imageLimit=l),min:1,max:10,placeholder:"默认为 5",style:{width:"100%"}},null,8,["value"])])]),_:1})]),_:1}),e("div",q,[o(v,{type:"primary",onClick:m},{default:n(()=>[...t[18]||(t[18]=[i(" 保存设置 ",-1)])]),_:1})])]),_:1})]),_:1})}}},A=b(L,[["__scopeId","data-v-bd32923f"]]);export{A as default};
|
||||
import{_ as b,j as w,k,o as c,b as C,d as S,w as n,c as o,g as e,f as a,h as i}from"./index-SQeV-w6F.js";const B={style:{"margin-bottom":"8px"}},T={style:{"margin-bottom":"8px"}},z={style:{"margin-bottom":"8px"}},U={style:{display:"flex","justify-content":"flex-end","margin-top":"24px"}},j={style:{"margin-bottom":"8px"}},M={style:{"margin-bottom":"8px"}},q={style:{display:"flex","justify-content":"flex-end","margin-top":"24px"}},L={__name:"server",setup(N){const d=w(),s=k({port:5173,authToken:"",keepaliveMode:"comment",queueBuffer:2,imageLimit:5});c(async()=>{await d.fetchServerConfig(),Object.assign(s,d.serverConfig)});const m=async()=>{await d.saveServerConfig(s)};return(V,t)=>{const p=a("a-input-number"),r=a("a-col"),y=a("a-input-password"),u=a("a-select-option"),g=a("a-select"),f=a("a-row"),v=a("a-button"),x=a("a-card"),_=a("a-layout");return S(),C(_,{style:{background:"transparent"}},{default:n(()=>[o(x,{title:"服务器设置",bordered:!1,style:{width:"100%"}},{default:n(()=>[o(f,{gutter:[16,16]},{default:n(()=>[o(r,{xs:24,md:12},{default:n(()=>[e("div",B,[t[5]||(t[5]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"监听端口",-1)),t[6]||(t[6]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 设置服务器监听的端口号,默认为 5173 ",-1)),o(p,{value:s.port,"onUpdate:value":t[0]||(t[0]=l=>s.port=l),min:1,max:65535,placeholder:"请输入端口号",style:{width:"100%"}},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",T,[t[7]||(t[7]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"鉴权 Token",-1)),t[8]||(t[8]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 用于 API 请求鉴权的密钥,留空则不启用鉴权 ",-1)),o(y,{value:s.authToken,"onUpdate:value":t[1]||(t[1]=l=>s.authToken=l),placeholder:"请输入 Token",type:"password"},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",z,[t[11]||(t[11]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"心跳包类型",-1)),t[12]||(t[12]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}}," 选择 SSE 流式响应的心跳包格式 ",-1)),o(g,{value:s.keepaliveMode,"onUpdate:value":t[2]||(t[2]=l=>s.keepaliveMode=l),style:{width:"100%"},placeholder:"请选择心跳包类型"},{default:n(()=>[o(u,{value:"comment"},{default:n(()=>[...t[9]||(t[9]=[i("Comment - 注释格式",-1)])]),_:1}),o(u,{value:"content"},{default:n(()=>[...t[10]||(t[10]=[i("Content - 内容格式",-1)])]),_:1})]),_:1},8,["value"])])]),_:1})]),_:1}),e("div",U,[o(v,{type:"primary",onClick:m},{default:n(()=>[...t[13]||(t[13]=[i(" 保存设置 ",-1)])]),_:1})])]),_:1}),o(x,{title:"队列设置",bordered:!1,style:{width:"100%","margin-top":"10px"}},{default:n(()=>[o(f,{gutter:[16,16]},{default:n(()=>[o(r,{xs:24,md:12},{default:n(()=>[e("div",j,[t[14]||(t[14]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"队列缓冲区大小",-1)),t[15]||(t[15]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}},[i(" 非流式请求的额外排队数(设为 0 则不限制非流式请求数量)"),e("br"),i(" 实际队列上限 = Workers数量 + 缓冲区大小 ")],-1)),o(p,{value:s.queueBuffer,"onUpdate:value":t[3]||(t[3]=l=>s.queueBuffer=l),min:0,max:100,placeholder:"默认为 2",style:{width:"100%"}},null,8,["value"])])]),_:1}),o(r,{xs:24,md:12},{default:n(()=>[e("div",M,[t[16]||(t[16]=e("div",{style:{"font-weight":"600","margin-bottom":"4px"}},"图片数量上限",-1)),t[17]||(t[17]=e("div",{style:{"font-size":"12px",color:"#8c8c8c","margin-bottom":"8px"}},[i(" 单次请求最多支持的图片附件数量"),e("br"),i(" 网页最多支持10个附件,超出会被丢弃 ")],-1)),o(p,{value:s.imageLimit,"onUpdate:value":t[4]||(t[4]=l=>s.imageLimit=l),min:1,max:10,placeholder:"默认为 5",style:{width:"100%"}},null,8,["value"])])]),_:1})]),_:1}),e("div",q,[o(v,{type:"primary",onClick:m},{default:n(()=>[...t[18]||(t[18]=[i(" 保存设置 ",-1)])]),_:1})])]),_:1})]),_:1})}}},A=b(L,[["__scopeId","data-v-bd32923f"]]);export{A as default};
|
||||
+1
-1
@@ -1 +1 @@
|
||||
import{x as i,j as a,s as r}from"./index-UseUKVwr.js";const u=i("system",{state:()=>({status:"",version:"1.0.0",systemVersion:"",uptime:0,cpuUsage:0,memoryUsage:{total:0,used:0,free:0},safeMode:{enabled:!1,reason:null},stats:{totalRequests:0,successRate:0,activeWorkers:0,totalWorkers:0,avgResponseTime:0}}),actions:{async fetchStatus(){const t=a();try{const e=await fetch("/admin/status",{headers:t.getHeaders()});if(e.ok){const s=await e.json();this.$patch(s)}}catch(e){console.error("Failed to fetch system status:",e)}},async fetchStats(){const t=a();try{const e=await fetch("/admin/stats",{headers:t.getHeaders()});if(e.ok){const s=await e.json();this.stats=s}}catch(e){console.error("Failed to fetch stats:",e)}},async restartService(t={}){const e=a(),{loginMode:s,workerName:n}=t;try{const o=await(await fetch("/admin/restart",{method:"POST",headers:{...e.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({loginMode:s,workerName:n})})).json();return o.success?(r.success(o.message||"服务重启中..."),!0):(r.error("重启失败"),!1)}catch{return r.error("重启请求失败"),!1}},async stopService(){const t=a();try{const s=await(await fetch("/admin/stop",{method:"POST",headers:t.getHeaders()})).json();return s.success?(r.success(s.message||"服务停止中..."),!0):(r.error("停止失败"),!1)}catch{return r.error("停止请求失败"),!1}}}});export{u};
|
||||
import{x as i,j as a,s as r}from"./index-SQeV-w6F.js";const u=i("system",{state:()=>({status:"",version:"1.0.0",systemVersion:"",uptime:0,cpuUsage:0,memoryUsage:{total:0,used:0,free:0},safeMode:{enabled:!1,reason:null},stats:{totalRequests:0,successRate:0,activeWorkers:0,totalWorkers:0,avgResponseTime:0}}),actions:{async fetchStatus(){const t=a();try{const e=await fetch("/admin/status",{headers:t.getHeaders()});if(e.ok){const s=await e.json();this.$patch(s)}}catch(e){console.error("Failed to fetch system status:",e)}},async fetchStats(){const t=a();try{const e=await fetch("/admin/stats",{headers:t.getHeaders()});if(e.ok){const s=await e.json();this.stats=s}}catch(e){console.error("Failed to fetch stats:",e)}},async restartService(t={}){const e=a(),{loginMode:s,workerName:n}=t;try{const o=await(await fetch("/admin/restart",{method:"POST",headers:{...e.getHeaders(),"Content-Type":"application/json"},body:JSON.stringify({loginMode:s,workerName:n})})).json();return o.success?(r.success(o.message||"服务重启中..."),!0):(r.error("重启失败"),!1)}catch{return r.error("重启请求失败"),!1}},async stopService(){const t=a();try{const s=await(await fetch("/admin/stop",{method:"POST",headers:t.getHeaders()})).json();return s.success?(r.success(s.message||"服务停止中..."),!0):(r.error("停止失败"),!1)}catch{return r.error("停止请求失败"),!1}}}});export{u};
|
||||
-1
File diff suppressed because one or more lines are too long
+1
File diff suppressed because one or more lines are too long
Vendored
+2
-2
@@ -6,8 +6,8 @@
|
||||
<link rel="icon" type="image/png" href="/favicon.png">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>WebAI2API</title>
|
||||
<script type="module" crossorigin src="/assets/index-UseUKVwr.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-D7WjNDz2.css">
|
||||
<script type="module" crossorigin src="/assets/index-SQeV-w6F.js"></script>
|
||||
<link rel="stylesheet" crossorigin href="/assets/index-BVr8U7Bl.css">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
+75
-41
@@ -108,9 +108,37 @@ const handleImageChange = async (info) => {
|
||||
}
|
||||
};
|
||||
|
||||
// 解析 Markdown 图片
|
||||
// 将 base64 转换为 blob URL
|
||||
const base64ToBlob = (dataUri) => {
|
||||
const arr = dataUri.split(',');
|
||||
const mime = arr[0].match(/:(.*?);/)[1];
|
||||
const bstr = atob(arr[1]);
|
||||
let n = bstr.length;
|
||||
const u8arr = new Uint8Array(n);
|
||||
while (n--) {
|
||||
u8arr[n] = bstr.charCodeAt(n);
|
||||
}
|
||||
return URL.createObjectURL(new Blob([u8arr], { type: mime }));
|
||||
};
|
||||
|
||||
// 解析内容中的 Markdown 图片和直接的视频 data URI
|
||||
const parseMarkdownImages = (content) => {
|
||||
if (!content) return { text: '', images: [] };
|
||||
if (!content) return { text: '', images: [], videos: [] };
|
||||
|
||||
// 检测是否是直接的 data:video/ 内容(非 markdown 格式)
|
||||
if (content.trim().startsWith('data:video/')) {
|
||||
try {
|
||||
const blobUrl = base64ToBlob(content.trim());
|
||||
return {
|
||||
text: '',
|
||||
images: [],
|
||||
videos: [{ src: blobUrl, type: 'video/mp4' }]
|
||||
};
|
||||
} catch (e) {
|
||||
console.error('视频转换失败', e);
|
||||
return { text: content, images: [], videos: [] };
|
||||
}
|
||||
}
|
||||
|
||||
const imageRegex = /!\[([^\]]*)\]\(([^)]+)\)/g;
|
||||
const images = [];
|
||||
@@ -127,11 +155,10 @@ const parseMarkdownImages = (content) => {
|
||||
// 添加图片
|
||||
images.push({
|
||||
alt: match[1] || '图片',
|
||||
src: match[2]
|
||||
src: match[2],
|
||||
type: 'image'
|
||||
});
|
||||
|
||||
// 不添加占位符,直接跳过图片的 markdown 语法
|
||||
|
||||
lastIndex = imageRegex.lastIndex;
|
||||
}
|
||||
|
||||
@@ -142,7 +169,8 @@ const parseMarkdownImages = (content) => {
|
||||
|
||||
return {
|
||||
text: textParts.join('').trim(),
|
||||
images
|
||||
images,
|
||||
videos: []
|
||||
};
|
||||
};
|
||||
|
||||
@@ -544,49 +572,59 @@ onMounted(async () => {
|
||||
</div>
|
||||
|
||||
<!-- 测试结果 -->
|
||||
<!-- 流式模式:实时显示内容 -->
|
||||
<div v-if="chatStreamMode && apiTestResults.chat.status === 'loading'"
|
||||
style="background: #fafafa; padding: 12px; border-radius: 4px; font-size: 12px; max-height: 400px; overflow-y: auto;">
|
||||
<div style="color: #1890ff; margin-bottom: 8px;">
|
||||
<LoadingOutlined /> 正在接收流式响应...
|
||||
<!-- 加载中或成功:统一显示内容 -->
|
||||
<div v-if="apiTestResults.chat.status === 'loading' || apiTestResults.chat.status === 'success'">
|
||||
<!-- 状态标签 -->
|
||||
<div style="margin-bottom: 8px;">
|
||||
<a-tag v-if="apiTestResults.chat.status === 'loading'" color="processing">
|
||||
<LoadingOutlined /> {{ chatStreamMode ? '正在接收流式响应...' : '请求中,可能需要较长时间...' }}
|
||||
</a-tag>
|
||||
<a-tag v-else color="success">
|
||||
<CheckCircleOutlined /> 成功
|
||||
</a-tag>
|
||||
</div>
|
||||
<!-- 文本内容 -->
|
||||
<pre v-if="parseMarkdownImages(chatStreamContent).text"
|
||||
style="white-space: pre-wrap; word-break: break-all; margin: 0 0 8px 0; min-height: 50px;">{{
|
||||
parseMarkdownImages(chatStreamContent).text || '等待内容...' }}</pre>
|
||||
<!-- 图片展示 -->
|
||||
<div v-if="parseMarkdownImages(chatStreamContent).images.length > 0"
|
||||
style="display: flex; flex-direction: column; gap: 8px;">
|
||||
<div v-for="(img, index) in parseMarkdownImages(chatStreamContent).images" :key="index"
|
||||
style="border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px; background: white;">
|
||||
<div style="font-size: 11px; color: #8c8c8c; margin-bottom: 4px;">{{ img.alt }}</div>
|
||||
<img :src="img.src" :alt="img.alt"
|
||||
style="max-width: 100%; height: auto; display: block; border-radius: 2px;" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="apiTestResults.chat.status === 'success'">
|
||||
<a-tag color="success">
|
||||
<CheckCircleOutlined /> 成功
|
||||
</a-tag>
|
||||
<div
|
||||
style="margin-top: 8px; font-size: 12px; max-height: 400px; overflow-y: auto; background: #fafafa; padding: 8px; border-radius: 4px;">
|
||||
|
||||
<!-- 内容显示容器(流式用 chatStreamContent,成功后用 data.content) -->
|
||||
<div v-if="chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content"
|
||||
style="font-size: 12px; max-height: 400px; overflow-y: auto; background: #fafafa; padding: 8px; border-radius: 4px;">
|
||||
<!-- 文本内容 -->
|
||||
<pre v-if="parseMarkdownImages(apiTestResults.chat.data?.content).text"
|
||||
<pre
|
||||
v-if="parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).text"
|
||||
style="white-space: pre-wrap; word-break: break-all; margin: 0 0 8px 0;">{{
|
||||
parseMarkdownImages(apiTestResults.chat.data?.content).text }}</pre>
|
||||
parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).text }}</pre>
|
||||
|
||||
<!-- 图片展示 -->
|
||||
<div v-if="parseMarkdownImages(apiTestResults.chat.data?.content).images.length > 0"
|
||||
<div
|
||||
v-if="parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).images.length > 0"
|
||||
style="display: flex; flex-direction: column; gap: 8px;">
|
||||
<div v-for="(img, index) in parseMarkdownImages(apiTestResults.chat.data?.content).images" :key="index"
|
||||
style="border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px; background: white;">
|
||||
<div
|
||||
v-for="(img, index) in parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).images"
|
||||
:key="index" style="border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px; background: white;">
|
||||
<div style="font-size: 11px; color: #8c8c8c; margin-bottom: 4px;">{{ img.alt }}</div>
|
||||
<img :src="img.src" :alt="img.alt"
|
||||
style="max-width: 100%; height: auto; display: block; border-radius: 2px;" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 视频展示 -->
|
||||
<div
|
||||
v-if="parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).videos.length > 0"
|
||||
style="display: flex; flex-direction: column; gap: 8px;">
|
||||
<div
|
||||
v-for="(video, index) in parseMarkdownImages(chatStreamMode ? chatStreamContent : apiTestResults.chat.data?.content).videos"
|
||||
:key="'video-' + index"
|
||||
style="border: 1px solid #d9d9d9; border-radius: 4px; padding: 4px; background: white;">
|
||||
<div style="font-size: 11px; color: #8c8c8c; margin-bottom: 4px;">生成的视频</div>
|
||||
<video :src="video.src" controls
|
||||
style="max-width: 100%; height: auto; display: block; border-radius: 2px;">
|
||||
您的浏览器不支持视频播放。
|
||||
</video>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 错误状态 -->
|
||||
<div v-else-if="apiTestResults.chat.status === 'error'">
|
||||
<a-tag color="error">
|
||||
<CloseCircleOutlined /> 失败
|
||||
@@ -595,10 +633,6 @@ onMounted(async () => {
|
||||
{{ apiTestResults.chat.error }}
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="apiTestResults.chat.status === 'loading' && !chatStreamMode"
|
||||
style="color: #1890ff; font-size: 12px;">
|
||||
<LoadingOutlined /> 请求中,可能需要较长时间...
|
||||
</div>
|
||||
</a-card>
|
||||
</a-space>
|
||||
</a-drawer>
|
||||
|
||||
@@ -59,13 +59,13 @@ const handleLogin = async () => {
|
||||
WebAI2API 管理面板
|
||||
</div>
|
||||
<div style="color: #8c8c8c; margin-top: 8px;">
|
||||
请输入访问 Token 以继续
|
||||
请输入访问 API Token 以继续
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<a-form layout="vertical">
|
||||
<a-form-item label="Access Token">
|
||||
<a-input-password v-model:value="token" placeholder="请输入 Token" size="large"
|
||||
<a-input-password v-model:value="token" placeholder="请输入 API Token" size="large"
|
||||
@pressEnter="handleLogin">
|
||||
<template #prefix>
|
||||
<LockOutlined style="color: rgba(0,0,0,.25)" />
|
||||
|
||||
@@ -22,19 +22,36 @@ onMounted(async () => {
|
||||
]);
|
||||
});
|
||||
|
||||
// 计算属性:适配器选项
|
||||
// 计算属性:适配器选项(包含 merge)
|
||||
const adapterOptions = computed(() => {
|
||||
const options = settingsStore.adaptersMeta.map(a => ({
|
||||
label: a.name,
|
||||
label: a.displayName || a.id,
|
||||
value: a.id
|
||||
}));
|
||||
// 手动添加 Merge 选项(如果没有在元数据中返回)
|
||||
// 将 Merge 选项放在第一个位置
|
||||
if (!options.find(o => o.value === 'merge')) {
|
||||
options.push({ label: 'Merge(聚合模式)', value: 'merge' });
|
||||
options.unshift({ label: 'Merge(聚合模式)', value: 'merge' });
|
||||
}
|
||||
return options;
|
||||
});
|
||||
|
||||
// 计算属性:可聚合的适配器选项(不包含 merge,避免套娃)
|
||||
const mergeableAdapterOptions = computed(() => {
|
||||
return settingsStore.adaptersMeta
|
||||
.filter(a => a.id !== 'merge')
|
||||
.map(a => ({
|
||||
label: a.displayName || a.id,
|
||||
value: a.id
|
||||
}));
|
||||
});
|
||||
|
||||
// 辅助函数:根据适配器 ID 获取 displayName
|
||||
const getAdapterDisplayName = (id) => {
|
||||
if (id === 'merge') return 'Merge(聚合模式)';
|
||||
const adapter = settingsStore.adaptersMeta.find(a => a.id === id);
|
||||
return adapter?.displayName || id;
|
||||
};
|
||||
|
||||
// 实例列表表格列定义
|
||||
const columns = [
|
||||
{
|
||||
@@ -419,11 +436,11 @@ const handleRemoveWorker = (index) => {
|
||||
<div>
|
||||
<div style="font-weight: 600;">{{ item.name }}</div>
|
||||
<div style="font-size: 12px; color: #8c8c8c;">
|
||||
类型: {{ item.type }}
|
||||
类型: {{ getAdapterDisplayName(item.type) }}
|
||||
<span v-if="item.type === 'merge'">
|
||||
| 聚合: {{ item.mergeTypes?.join(', ') || '无' }}
|
||||
| 聚合: {{ item.mergeTypes?.map(getAdapterDisplayName).join(', ') || '无' }}
|
||||
<span v-if="item.mergeMonitor">
|
||||
| 监控: {{ item.mergeMonitor }}
|
||||
| 监控: {{ getAdapterDisplayName(item.mergeMonitor) }}
|
||||
</span>
|
||||
</span>
|
||||
</div>
|
||||
@@ -467,7 +484,7 @@ const handleRemoveWorker = (index) => {
|
||||
选择要聚合的后端适配器(可多选)
|
||||
</div>
|
||||
<a-select v-model:value="workerForm.mergeTypes" mode="multiple" style="width: 100%"
|
||||
placeholder="选择要聚合的适配器" :options="adapterOptions">
|
||||
placeholder="选择要聚合的适配器" :options="mergeableAdapterOptions">
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
@@ -480,7 +497,7 @@ const handleRemoveWorker = (index) => {
|
||||
allow-clear>
|
||||
<a-select-option value="">无</a-select-option>
|
||||
<a-select-option v-for="type in workerForm.mergeTypes" :key="type" :value="type">
|
||||
{{ type }}
|
||||
{{ getAdapterDisplayName(type) }}
|
||||
</a-select-option>
|
||||
</a-select>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user