ezllm 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +57 -0
- package/bin/ellm-proxy.js +3 -0
- package/dist/cli.js +27667 -0
- package/dist/package.json +1 -0
- package/dist/server.js +42403 -0
- package/dist/web-ui/assets/DashboardView-DwlQExQv.css +1 -0
- package/dist/web-ui/assets/DashboardView-fRDkGq0g.js +1 -0
- package/dist/web-ui/assets/LayoutView-CK_MaWN7.js +1 -0
- package/dist/web-ui/assets/LayoutView-kZ2yGen8.css +1 -0
- package/dist/web-ui/assets/LoginView-B1naaT8E.js +1 -0
- package/dist/web-ui/assets/LoginView-CSfb59pE.css +1 -0
- package/dist/web-ui/assets/LogsView-CCjJTjvZ.css +1 -0
- package/dist/web-ui/assets/LogsView-YtH8gJPU.js +9 -0
- package/dist/web-ui/assets/ProvidersView-Caqpg_0F.css +1 -0
- package/dist/web-ui/assets/ProvidersView-DWtS_e7t.js +31 -0
- package/dist/web-ui/assets/ServiceStatusView-D3ybS2T-.js +39 -0
- package/dist/web-ui/assets/ServiceStatusView-DrPoYMN-.css +1 -0
- package/dist/web-ui/assets/SettingsView-D1kbH5Ev.css +1 -0
- package/dist/web-ui/assets/SettingsView-DepOaZYg.js +1 -0
- package/dist/web-ui/assets/SetupView-BwDwokAd.js +1 -0
- package/dist/web-ui/assets/SetupView-pS9nSnLg.css +1 -0
- package/dist/web-ui/assets/clipboard-aCBIMfw7.js +1 -0
- package/dist/web-ui/assets/config-CdOq1p3C.js +1 -0
- package/dist/web-ui/assets/format-kTdM4RVv.js +1 -0
- package/dist/web-ui/assets/index-BecfPmag.css +1 -0
- package/dist/web-ui/assets/index-CgzCvxTY.js +96 -0
- package/dist/web-ui/assets/providers-i7t_wEzk.js +1 -0
- package/dist/web-ui/assets/useLoadError-UA3r7sR9.js +1 -0
- package/dist/web-ui/assets/useManagerApi-CBQNomtR.js +1 -0
- package/dist/web-ui/assets/useToast-DNMhOOeI.js +1 -0
- package/dist/web-ui/assets/version-BKHjE_LF.js +1 -0
- package/dist/web-ui/config.js +7 -0
- package/dist/web-ui/index.html +15 -0
- package/docs/DESIGN.md +90 -0
- package/ezllm.config.example.json +33 -0
- package/package.json +55 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
@charset "UTF-8";.service-status-page[data-v-8dcb74ec]{height:calc(100vh - 124px);display:flex;flex-direction:column;overflow:hidden}.main-card[data-v-8dcb74ec]{flex:1;min-height:0;overflow:hidden;display:flex;flex-direction:column}.main-card[data-v-8dcb74ec] .el-card__body{height:100%;display:flex;flex-direction:column;overflow:hidden}.view-switch[data-v-8dcb74ec]{margin-right:4px}.chart-wrap[data-v-8dcb74ec]{position:relative;flex:1;min-height:0;padding-top:8px}.chart-dom[data-v-8dcb74ec]{height:100%;width:100%}.chart-empty[data-v-8dcb74ec]{height:100%;display:flex;align-items:center;justify-content:center;color:#909399;font-size:13px}.hint[data-v-8dcb74ec]{margin-bottom:12px;flex-shrink:0}.table-wrap[data-v-8dcb74ec]{flex:1;min-height:0}.copy-text[data-v-8dcb74ec]{color:#409eff;cursor:pointer}.copy-text[data-v-8dcb74ec]:hover{text-decoration:underline}.model-name[data-v-8dcb74ec]{display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.error-text[data-v-8dcb74ec]{color:#f56c6c}.latency-cell[data-v-8dcb74ec]{display:block;margin:0 -14px;padding:10px 14px;border-radius:2px}.nowrap-cell[data-v-8dcb74ec] .cell{white-space:nowrap}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.switch-row[data-v-5084d579]{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:4px 0}.switch-title[data-v-5084d579]{display:flex;align-items:center;gap:8px;font-weight:600;margin-bottom:4px}.switch-desc[data-v-5084d579]{color:var(--el-text-color-secondary);font-size:13px;line-height:1.6}.switch-desc code[data-v-5084d579]{background:var(--el-fill-color-light);padding:1px 6px;border-radius:4px;font-size:12px}.switch-divider[data-v-5084d579]{margin:16px 0}.mb-16[data-v-d51cfdf5]{margin-bottom:16px}.mt-8[data-v-d51cfdf5]{margin-top:8px}.switch-row[data-v-d51cfdf5]{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:4px 0}.switch-title[data-v-d51cfdf5]{display:flex;align-items:center;gap:8px;font-weight:600;margin-bottom:4px}.switch-desc[data-v-d51cfdf5]{color:var(--el-text-color-secondary);font-size:13px;line-height:1.6}.switch-desc code[data-v-d51cfdf5]{background:var(--el-fill-color-light);padding:1px 6px;border-radius:4px;font-size:12px}.version-row[data-v-d51cfdf5]{display:flex;align-items:center;gap:8px;margin-bottom:8px}.version-label[data-v-d51cfdf5]{color:var(--el-text-color-secondary);font-size:13px}.version-actions[data-v-d51cfdf5]{margin-top:12px;display:flex;gap:8px}.settings-tabs[data-v-4c888be1] .el-tabs__content{overflow:visible}.save-bar[data-v-4c888be1]{position:sticky;bottom:0;display:flex;justify-content:center;padding:8px 0}.login-row[data-v-4c888be1]{display:flex;gap:8px;flex-wrap:wrap}.monitor-row[data-v-4c888be1]{display:flex;align-items:center;justify-content:space-between;gap:24px}.monitor-title[data-v-4c888be1]{font-weight:600;margin-bottom:4px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{u as Z}from"./useToast-DNMhOOeI.js";import{u as re}from"./useLoadError-UA3r7sR9.js";import{d as ee,l as le,b as te,o as d,c as A,w as n,e as b,f as s,t as V,j as T,g as i,h as o,F as I,r as v,E as q,a as c,k as se,_ as ae,y as de,p as j,A as ve,i as Q,z as ce}from"./index-CgzCvxTY.js";import{u as pe}from"./config-CdOq1p3C.js";import{c as me}from"./clipboard-aCBIMfw7.js";import{m as L,w as fe}from"./useManagerApi-CBQNomtR.js";import{u as _e,i as ye}from"./version-BKHjE_LF.js";const we={class:"flex-between"},ge={class:"muted-sm mb-8"},be={class:"switch-row"},ke={class:"switch-info"},Ce={class:"switch-title"},$e={class:"switch-row"},Ve={class:"switch-info"},xe={class:"switch-title"},he={class:"switch-row"},Te={class:"switch-info"},Ae={class:"switch-title"},Se=ee({__name:"HarnessSwitches",setup(ne){const{toast:y}=Z(),x=v(!0),z=v(!1),p=v(null),S=v(null),u=v(null),P=v(null),k=v("success"),h=async g=>{g||(p.value?z.value=!0:x.value=!0);try{p.value=await L.harness(),S.value=null}catch(a){g||(S.value=a.message)}finally{g||(x.value=!1,z.value=!1)}};le(()=>h(!1));const B={claudeCode:{label:"Claude Code",file:"~/.claude/settings.json",toggle:L.setClaudeCode},codex:{label:"Codex CLI",file:"~/.codex/config.toml",toggle:L.setCodex},dsh:{label:"DeepSeek Harness",file:"~/.dsh/settings.yaml",toggle:L.setDsh}},C=async(g,a)=>{if(!p.value||u.value)return;const $=B[g],N=a?`确定开启 ${$.label} 代理?将改写 ${$.file}(开启前自动备份,关闭时从备份还原)。`:`确定关闭 ${$.label} 代理?将从备份还原 ${$.file}(无备份时移除代理相关配置)。`;try{await q.confirm(N,a?"开启确认":"关闭确认",{confirmButtonText:a?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}u.value=g;try{const f=await $.toggle(a);P.value=f.note??null,k.value=a?"success":"info",y(a?"已开启代理":"已关闭代理","success")}catch(f){y(f.message||"操作失败","error")}finally{u.value=null,await h(!0)}};return(g,a)=>{const $=c("el-button"),N=c("el-alert"),f=c("el-tag"),E=c("el-switch"),M=c("el-divider"),K=c("el-empty"),F=c("el-card"),R=se("loading");return te((d(),A(F,{shadow:"never"},{header:n(()=>[s("div",we,[a[7]||(a[7]=s("span",{class:"fw-600"},"代理开关",-1)),o($,{loading:z.value,onClick:a[0]||(a[0]=U=>h(!1))},{default:n(()=>[...a[6]||(a[6]=[i("刷新",-1)])]),_:1},8,["loading"])])]),default:n(()=>[p.value?(d(),b(I,{key:0},[s("div",ge," 将本机 CLI 工具的流量一键指向本机网关("+V(p.value.gatewayBase)+")。 开启前自动备份原配置为 *.ellm-bak(保留最早的原始备份),关闭时从备份还原。 ",1),P.value?(d(),A(N,{key:0,title:P.value,type:k.value,"show-icon":"",class:"mb-8",onClose:a[1]||(a[1]=U=>P.value=null)},null,8,["title","type"])):T("",!0),s("div",be,[s("div",ke,[s("div",Ce,[a[8]||(a[8]=i(" Claude Code ",-1)),o(f,{type:p.value.claudeCode?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(p.value.claudeCode?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[9]||(a[9]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.claude/settings.json"),i(" 的 env.ANTHROPIC_BASE_URL / ANTHROPIC_AUTH_TOKEN, 鉴权取网关配置的 masterKey(未设置将开启失败);其余字段原样保留,重启 Claude Code 会话后生效。 ")],-1))]),o(E,{"model-value":p.value.claudeCode,loading:u.value==="claudeCode",onChange:a[2]||(a[2]=U=>C("claudeCode",!!U))},null,8,["model-value","loading"])]),o(M,{class:"switch-divider"}),s("div",$e,[s("div",Ve,[s("div",xe,[a[10]||(a[10]=i(" Codex CLI ",-1)),o(f,{type:p.value.codex?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(p.value.codex?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[11]||(a[11]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.codex/config.toml"),i(" 的 model_provider 与 [model_providers.ellm-proxy] 段 (保留用户注释与排版);开启后需按提示设置环境变量 ELLM_PROXY_API_KEY 供 Codex 鉴权。 ")],-1))]),o(E,{"model-value":p.value.codex,loading:u.value==="codex",onChange:a[3]||(a[3]=U=>C("codex",!!U))},null,8,["model-value","loading"])]),o(M,{class:"switch-divider"}),s("div",he,[s("div",Te,[s("div",Ae,[a[12]||(a[12]=i(" DeepSeek Harness ",-1)),o(f,{type:p.value.dsh?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(p.value.dsh?"已开启":"未开启"),1)]),_:1},8,["type"])]),a[13]||(a[13]=s("div",{class:"switch-desc"},[i(" 写入 "),s("code",null,"~/.dsh/settings.yaml"),i(" 的 llm-deepseek.baseURL 与 "),s("code",null,"~/.dsh/.credentials.yaml"),i(" 的 DEEPSEEK_API_KEY(取网关 masterKey,未设置则写占位值);模型请在 dsh 内选择与网关部署名一致的模型。 dsh 为 developer preview,配置格式可能随版本变化。 ")],-1))]),o(E,{"model-value":p.value.dsh,loading:u.value==="dsh",onChange:a[4]||(a[4]=U=>C("dsh",!!U))},null,8,["model-value","loading"])])],64)):(d(),A(K,{key:1,description:S.value||"暂无开关状态"},{default:n(()=>[o($,{type:"primary",onClick:a[5]||(a[5]=U=>h(!1))},{default:n(()=>[...a[14]||(a[14]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1})),[[R,x.value]])}}}),Ee=ae(Se,[["__scopeId","data-v-5084d579"]]),Ue={class:"service-settings"},ze={class:"flex-between"},Be={key:0,class:"switch-row"},Le={class:"switch-info"},Ie={class:"switch-title"},Pe={key:0,class:"switch-row"},He={class:"switch-info"},Ke={class:"switch-title"},De={class:"switch-desc"},Ne={key:0,class:"version-block"},Oe={class:"version-row"},je={class:"muted-sm"},Me={key:0,class:"muted-sm"},Re={key:1,class:"muted-sm"},Fe={class:"muted-sm"},Ye={class:"version-actions"},We=ee({__name:"ServiceUpdateSettings",setup(ne){const{toast:y}=Z(),x=v(!0),z=v(!1),p=v(null),S=v(null),u=v(null),P=v(null),k=v(null),h=v(!1),B=v(!1),C=v(null);let g=null;de(()=>g==null?void 0:g.abort());const a=async l=>{var e,r;if(!l){if(z.value)return;z.value=!0}try{const[_,m]=await Promise.allSettled([L.autostart(),L.update()]);p.value=_.status==="fulfilled"?_.value:null,S.value=_.status==="rejected"?(e=_.reason)==null?void 0:e.message:null,u.value=m.status==="fulfilled"?m.value:null,P.value=m.status==="rejected"?(r=m.reason)==null?void 0:r.message:null}finally{x.value=!1,z.value=!1}};le(()=>a(!1));const $=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.currentVersion)??null}),N=j(()=>ye($.value)),f=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.latestVersion)??null}),E=j(()=>{var l,e;return((e=(l=u.value)==null?void 0:l.lastCheck)==null?void 0:e.hasUpdate)===!0}),M=j(()=>{var e,r;const l=(r=(e=u.value)==null?void 0:e.lastCheck)==null?void 0:r.checkedAt;return l?new Date(l).toLocaleString():null}),K=j(()=>{var r;const l=(r=u.value)==null?void 0:r.lastApply;if(!l)return null;const e=l.appliedAt?new Date(l.appliedAt).toLocaleString():"";return`${l.fromVersion} → ${l.toVersion}${e?`(${e})`:""}`}),F=l=>l?new Date(l).toLocaleString():"",R=async l=>{if(!p.value||k.value)return;const e=l?"确定开启开机自启?将注册登录触发的自启项(登录时自动恢复服务)。":"确定关闭开机自启?将移除自启项,且此后首次启动不再自动注册。";try{await q.confirm(e,l?"开启确认":"关闭确认",{confirmButtonText:l?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}k.value="autostart";try{const r=await L.setAutostart(l);r.note?y(r.note,"success"):y(l?"开机自启已开启":"开机自启已关闭","success")}catch(r){y(r.message||"操作失败","error")}finally{k.value=null,await a(!0)}},U=async l=>{if(!u.value||k.value)return;const e=l?"确定开启自动更新?将每小时检查 npm 源,发现新版本自动安装并重启服务。":"确定关闭自动更新?不再自动检查(手动检查更新不受影响)。";try{await q.confirm(e,l?"开启确认":"关闭确认",{confirmButtonText:l?"开启":"关闭",cancelButtonText:"取消",type:"warning"})}catch{return}k.value="updateEnabled";try{const r=await L.setUpdateEnabled(l);r.note&&y(r.note,"success")}catch(r){y(r.message||"操作失败","error")}finally{k.value=null,await a(!0)}},D=async()=>{h.value=!0;try{const l=await L.checkUpdate();C.value=l.hasUpdate?`发现新版本 ${l.latestVersion}(当前 ${l.currentVersion}):点击「立即更新」即可安装(服务自动重启,期间管理台短暂不可访问)`:`已是最新版本 ${l.currentVersion}(检查于 ${F(l.checkedAt)})`,await a(!0)}catch(l){y(l.message||"检查更新失败","error")}finally{h.value=!1}},t=async()=>{var e;try{await q.confirm(`确定更新到 ${f.value}?服务会自动重启并在启动时安装新版本:重启期间管理台短暂不可访问(预计 1~3 分钟),更新完成后自动恢复。`,"更新确认",{confirmButtonText:"立即更新",cancelButtonText:"取消",type:"warning"})}catch{return}B.value=!0;const l=new AbortController;g=l;try{const r=await L.update(),_=await L.applyUpdate();if(!_.updated){C.value=`已是最新版本 ${_.toVersion}`;return}C.value=`正在重启服务并安装 ${_.toVersion}(预计 1~3 分钟):重启期间管理台短暂不可访问,完成后这里会自动显示结果。`;const m=await fe({targetVersion:_.toVersion,sinceAppliedAt:((e=r.lastApply)==null?void 0:e.appliedAt)??null,signal:l.signal});if(l.signal.aborted)return;m&&!m.error?(y(`已更新到 ${m.toVersion}`,"success"),C.value=`已更新 ${m.fromVersion} → ${m.toVersion},服务已在新版本上运行。`):m!=null&&m.error?(y(`更新失败:${m.error}`,"error"),C.value=_e(m.error)):C.value="更新仍在进行(安装耗时较长):稍后刷新页面查看最新状态。"}catch(r){y(r.message||"更新失败","error")}finally{B.value=!1,g===l&&(g=null),l.signal.aborted||await a(!0)}};return(l,e)=>{const r=c("el-button"),_=c("el-tag"),m=c("el-switch"),Y=c("el-empty"),O=c("el-card"),W=c("el-link"),X=c("el-alert"),G=se("loading");return te((d(),b("div",Ue,[o(O,{shadow:"never",class:"mb-16"},{header:n(()=>[s("div",ze,[e[7]||(e[7]=s("span",{class:"fw-600"},"开机自启",-1)),o(r,{loading:z.value,onClick:e[0]||(e[0]=H=>a(!1))},{default:n(()=>[...e[6]||(e[6]=[i("刷新",-1)])]),_:1},8,["loading"])])]),default:n(()=>[p.value?(d(),b("div",Be,[s("div",Le,[s("div",Ie,[e[8]||(e[8]=i(" 登录时自动启动服务 ",-1)),o(_,{type:p.value.enabled?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(p.value.enabled?"已开启":"未开启"),1)]),_:1},8,["type"])]),e[9]||(e[9]=s("div",{class:"switch-desc"},[i(" 登录操作系统时自动启动服务(无需管理员权限)。 关闭后首次启动 "),s("code",null,"ezllm"),i(" 也不会再自动注册,重新开启即可解除。 ")],-1))]),o(m,{"model-value":p.value.enabled,loading:k.value==="autostart",onChange:e[1]||(e[1]=H=>R(!!H))},null,8,["model-value","loading"])])):(d(),A(Y,{key:1,description:S.value||"暂无自启状态"},{default:n(()=>[o(r,{type:"primary",onClick:e[2]||(e[2]=H=>a(!1))},{default:n(()=>[...e[10]||(e[10]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1}),o(O,{shadow:"never",class:"mb-16"},{header:n(()=>[...e[11]||(e[11]=[s("div",{class:"flex-between"},[s("span",{class:"fw-600"},"自动更新")],-1)])]),default:n(()=>[u.value?(d(),b("div",Pe,[s("div",He,[s("div",Ke,[e[12]||(e[12]=i(" 自动检查并安装新版本 ",-1)),o(_,{type:u.value.enabled?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(u.value.enabled?"已开启":"未开启"),1)]),_:1},8,["type"])]),s("div",De,[u.value.supported?(d(),b(I,{key:1},[i(" 每小时检查 npm 源,发现新版本自动重启服务并在启动时安装(更新期间服务短暂中断); 关闭后仍可在下方手动检查与更新。 ")],64)):(d(),b(I,{key:0},[i(" 当前为源码运行模式,更新功能不可用(仅 npm 全局安装的包支持自动更新)。 ")],64))])]),u.value.supported?(d(),A(m,{key:0,"model-value":u.value.enabled,loading:k.value==="updateEnabled",onChange:e[3]||(e[3]=H=>U(!!H))},null,8,["model-value","loading"])):T("",!0)])):(d(),A(Y,{key:1,description:P.value||"暂无更新状态"},{default:n(()=>[o(r,{type:"primary",onClick:e[4]||(e[4]=H=>a(!1))},{default:n(()=>[...e[13]||(e[13]=[i("重试",-1)])]),_:1})]),_:1},8,["description"]))]),_:1}),o(O,{shadow:"never"},{header:n(()=>[...e[14]||(e[14]=[s("div",{class:"flex-between"},[s("span",{class:"fw-600"},"版本信息")],-1)])]),default:n(()=>[u.value?(d(),b("div",Ne,[s("div",Oe,[e[18]||(e[18]=s("span",{class:"version-label"},"当前版本",-1)),o(_,{size:"small"},{default:n(()=>[i(V($.value||"未知"),1)]),_:1}),N.value?(d(),A(_,{key:0,type:"warning",size:"small","disable-transitions":""},{default:n(()=>[...e[15]||(e[15]=[i("本地构建",-1)])]),_:1})):T("",!0),f.value?(d(),b(I,{key:1},[e[17]||(e[17]=s("span",{class:"version-label"},"最新版本",-1)),o(_,{type:E.value?"warning":"success",size:"small","disable-transitions":""},{default:n(()=>[i(V(f.value),1)]),_:1},8,["type"]),E.value?(d(),A(_,{key:0,type:"warning",size:"small","disable-transitions":""},{default:n(()=>[...e[16]||(e[16]=[i("发现新版本",-1)])]),_:1})):T("",!0)],64)):T("",!0)]),s("div",je,[i(" 上次检查:"+V(M.value||"尚未检查")+" ",1),u.value.updating?(d(),b(I,{key:0},[i(" · 更新执行中...")],64)):T("",!0)]),u.value.supported?T("",!0):(d(),b("div",Me," 源码运行模式:手动检查与更新不可用。 ")),K.value?(d(),b("div",Re," 上次更新:"+V(K.value),1)):T("",!0),s("div",Fe,[e[20]||(e[20]=i(" npm 包主页:",-1)),o(W,{type:"primary",href:"https://www.npmjs.com/package/ezllm",target:"_blank"},{default:n(()=>[...e[19]||(e[19]=[i("npmjs.com/package/ezllm",-1)])]),_:1})]),s("div",Ye,[o(r,{loading:h.value,disabled:!u.value.supported||u.value.updating,onClick:D},{default:n(()=>[i(V(h.value?"检查中...":"检查更新"),1)]),_:1},8,["loading","disabled"]),E.value&&u.value.supported?(d(),A(r,{key:0,type:"primary",loading:B.value,disabled:u.value.updating,onClick:t},{default:n(()=>[i(V(B.value?"更新中...":`立即更新到 ${f.value}`),1)]),_:1},8,["loading","disabled"])):T("",!0)]),C.value?(d(),A(X,{key:2,title:C.value,type:"info","show-icon":"",class:"mt-8",onClose:e[5]||(e[5]=H=>C.value=null)},null,8,["title"])):T("",!0)])):(d(),A(Y,{key:1,description:"更新状态不可用"}))]),_:1})])),[[G,x.value]])}}}),Xe=ae(We,[["__scopeId","data-v-d51cfdf5"]]),qe={class:"flex-col-gap"},Ge={class:"flex-between"},Je={class:"muted-sm"},Qe={key:0},Ze={class:"login-row"},el={class:"muted-sm"},ll={class:"flex-between"},tl={class:"monitor-row"},sl={class:"save-bar"},al=ee({__name:"SettingsView",setup(ne){const{toast:y}=Z(),x=pe(),z=v("basic"),p=v(!0),S=v(!1),u=v(""),P=async()=>{if(!u.value)return;await me(u.value)?y("已复制到剪贴板","success"):y("复制失败","error")},k=v(29770),h=v(null),B=v(!0),C=v(null),g=v(null),a=v(""),$=v(""),N=j(()=>u.value.trim()!==""||a.value!==""&&$.value!==""),f=v(!1),E=v(60),M=[{label:"10分钟",value:10},{label:"30分钟",value:30},{label:"1小时",value:60},{label:"2小时",value:120},{label:"5小时",value:300},{label:"8小时",value:480},{label:"12小时",value:720},{label:"24小时",value:1440}],{loadError:K,run:F}=re("设置加载失败,请重试"),R=()=>F(async()=>{var D;try{await x.load(),u.value=x.config.masterKey||"",k.value=x.config.port??29770;const t=(D=x.config["web-ui"])==null?void 0:D["login-account"];a.value=(t==null?void 0:t.username)||"",$.value=(t==null?void 0:t.password)||"",B.value=x.config.allowLan!==!1;const l=x.config.latencyTest;f.value=(l==null?void 0:l.enabled)===!0,E.value=(l==null?void 0:l.intervalMinutes)??60;try{const e=await ve.get("/api/status");h.value=e.listenPort,C.value=e.listenHost??null,g.value=e.listenSource??null}catch{h.value=null,C.value=null,g.value=null}}finally{p.value=!1}}),U=async()=>{var t;S.value=!0;const D=f.value&&((t=x.config.latencyTest)==null?void 0:t.enabled)!==!0;try{const l=await x.update(e=>{var r;e.masterKey=u.value.trim(),e.port=k.value,e.allowLan=B.value,e.latencyTest={enabled:f.value,intervalMinutes:E.value},e["web-ui"]??(e["web-ui"]={}),(r=e["web-ui"])["login-account"]??(r["login-account"]={}),e["web-ui"]["login-account"].username=a.value.trim(),e["web-ui"]["login-account"].password=$.value});y("设置已保存并生效","success"),D&&y("已开启自动测试:服务将定期直连所有上游发送探测请求,有少量 token 消耗","warning"),l.restartHint&&y(l.restartHint,"warning")}catch(l){y(l.message,"error")}finally{S.value=!1}};return le(R),(D,t)=>{const l=c("el-button"),e=c("el-alert"),r=c("el-tag"),_=c("el-input"),m=c("el-form-item"),Y=c("el-input-number"),O=c("el-form"),W=c("el-card"),X=c("el-switch"),G=c("el-divider"),H=c("el-option"),oe=c("el-select"),J=c("el-tab-pane"),ie=c("el-tabs"),ue=se("loading");return d(),A(ie,{modelValue:z.value,"onUpdate:modelValue":t[7]||(t[7]=w=>z.value=w),class:"settings-tabs"},{default:n(()=>[o(J,{label:"基本设置",name:"basic"},{default:n(()=>[te((d(),b("div",qe,[Q(K)?(d(),A(e,{key:0,title:Q(K),type:"error","show-icon":"",closable:!1},{default:n(()=>[o(l,{size:"small",onClick:R},{default:n(()=>[...t[8]||(t[8]=[i("重试",-1)])]),_:1})]),_:1},8,["title"])):T("",!0),o(W,{shadow:"never"},{header:n(()=>[s("div",Ge,[t[10]||(t[10]=s("span",{class:"fw-600"},"网关访问",-1)),o(r,{type:"success"},{default:n(()=>[...t[9]||(t[9]=[i("运行中",-1)])]),_:1})])]),default:n(()=>[o(O,{"label-position":"top"},{default:n(()=>[o(m,{label:"API 密钥 (masterKey)"},{default:n(()=>[o(_,{modelValue:u.value,"onUpdate:modelValue":t[0]||(t[0]=w=>u.value=w),placeholder:"sk-1234",clearable:""},{append:n(()=>[o(l,{onClick:P},{default:n(()=>[...t[11]||(t[11]=[i("复制",-1)])]),_:1})]),_:1},8,["modelValue"]),t[12]||(t[12]=s("div",{class:"muted-sm"}," 客户端请求 /v1/* 时的认证密钥(Bearer <masterKey>;留空 = 本地放行) ",-1))]),_:1}),o(m,{label:"监听端口 (port)"},{default:n(()=>[o(Y,{modelValue:k.value,"onUpdate:modelValue":t[1]||(t[1]=w=>k.value=w),min:1,max:65535,step:1,style:{width:"220px"}},null,8,["modelValue"]),s("div",Je,[t[14]||(t[14]=i(" 网关与管理台 API 的监听端口,保存后重启生效 ",-1)),h.value!==null?(d(),b(I,{key:0},[t[13]||(t[13]=i(" ;当前实际监听 ",-1)),s("b",null,V(h.value),1),h.value!==k.value?(d(),b("span",Qe,"(由 PORT 环境变量覆盖,此配置值不生效)")):T("",!0)],64)):T("",!0)])]),_:1})]),_:1})]),_:1}),o(W,{shadow:"never"},{header:n(()=>[...t[15]||(t[15]=[s("span",{class:"fw-600"},"安全与登录",-1)])]),default:n(()=>[o(O,{"label-position":"top"},{default:n(()=>[o(m,{label:"管理台登录账号"},{default:n(()=>[s("div",Ze,[o(_,{modelValue:a.value,"onUpdate:modelValue":t[2]||(t[2]=w=>a.value=w),placeholder:"用户名",style:{width:"200px"}},null,8,["modelValue"]),o(_,{modelValue:$.value,"onUpdate:modelValue":t[3]||(t[3]=w=>$.value=w),type:"password",placeholder:"密码(至少 6 位)","show-password":"",style:{width:"200px"}},null,8,["modelValue"])]),t[16]||(t[16]=s("div",{class:"muted-sm"}," 管理台登录凭证;留空 = 免登录直接访问(仅本机使用时推荐)。 修改后立即生效,需用新账号重新登录 ",-1))]),_:1}),o(m,{label:"允许局域网访问 (allowLan)"},{default:n(()=>[o(X,{modelValue:B.value,"onUpdate:modelValue":t[4]||(t[4]=w=>B.value=w)},null,8,["modelValue"]),s("div",el,[t[19]||(t[19]=i(" 开启 = 绑定全部网卡,局域网内设备可访问;关闭 = 仅本机 127.0.0.1。保存后需重启生效 ",-1)),g.value==="env"?(d(),b(I,{key:0},[t[17]||(t[17]=i(" ;当前实际监听 ",-1)),s("b",null,V(C.value),1),t[18]||(t[18]=i("(由 HOST 环境变量覆盖,此开关不生效) ",-1))],64)):N.value?T("",!0):(d(),b(I,{key:1},[i(" ;未设置任何凭据(密钥与登录账号皆无)时始终仅绑本机 ")],64))])]),_:1})]),_:1})]),_:1}),o(W,{shadow:"never"},{header:n(()=>[s("div",ll,[t[20]||(t[20]=s("span",{class:"fw-600"},"模型服务监控",-1)),o(r,{type:f.value?"success":"info",size:"small","disable-transitions":""},{default:n(()=>[i(V(f.value?"已开启":"未开启"),1)]),_:1},8,["type"])])]),default:n(()=>[s("div",tl,[t[21]||(t[21]=s("div",{class:"monitor-info"},[s("div",{class:"monitor-title"},"自动测试模型服务状态"),s("div",{class:"muted-sm"}," 按设定间隔自动直连所有上游模型发送极小探测请求(max_tokens: 1,有少量 token 消耗); 测试结果展示在「服务状态」页面 ")],-1)),o(X,{modelValue:f.value,"onUpdate:modelValue":t[5]||(t[5]=w=>f.value=w)},null,8,["modelValue"])]),f.value?(d(),b(I,{key:0},[o(G,{style:{margin:"12px 0"}}),o(O,{"label-position":"top"},{default:n(()=>[o(m,{label:"测试间隔",style:{"margin-bottom":"0"}},{default:n(()=>[o(oe,{modelValue:E.value,"onUpdate:modelValue":t[6]||(t[6]=w=>E.value=w),style:{width:"220px"}},{default:n(()=>[(d(),b(I,null,ce(M,w=>o(H,{key:w.value,label:w.label,value:w.value},null,8,["label","value"])),64))]),_:1},8,["modelValue"]),t[22]||(t[22]=s("div",{class:"muted-sm"}," 自动测试的执行间隔,保存后即时生效(无需重启) ",-1))]),_:1})]),_:1})],64)):T("",!0)]),_:1}),s("div",sl,[o(l,{type:"primary",size:"large",loading:S.value,disabled:S.value||Q(K)!==null,onClick:U},{default:n(()=>[i(V(S.value?"保存中...":"保存设置"),1)]),_:1},8,["loading","disabled"])])])),[[ue,p.value]])]),_:1}),o(J,{label:"代理开关",name:"harness",lazy:""},{default:n(()=>[o(Ee)]),_:1}),o(J,{label:"服务与更新",name:"service",lazy:""},{default:n(()=>[o(Xe)]),_:1})]),_:1},8,["modelValue"])}}}),cl=ae(al,[["__scopeId","data-v-4c888be1"]]);export{cl as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{d as E,l as H,m as I,a6 as T,e as j,h as a,w as t,r as m,a as p,o as k,f as _,g as f,c as S,j as h,a3 as G,ah as w,A as K,aj as L,s as P,_ as R}from"./index-CgzCvxTY.js";import{c as Z}from"./clipboard-aCBIMfw7.js";const $={class:"setup-wrap"},q={class:"account-row"},z=E({__name:"SetupView",setup(D){const A=P(),o=m(!1),n=m("");let b=!1;const v=m(""),d=m(""),V=m(!1),u=m("");H(async()=>{!(await I()).masterKeySet&&o.value&&g()});function g(){n.value=B(),b=!0}T(o,l=>{l?n.value.trim()===""&&g():b&&(n.value="",b=!1)});function B(){const l=new Uint8Array(32);crypto.getRandomValues(l);let e="";for(const s of l)e+=String.fromCharCode(s);return btoa(e).replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"")}async function U(){await Z(n.value)?w.success("已复制到剪贴板"):w.error("复制失败,请手动选择复制")}async function C(){u.value="";const l=o.value?"server":"local",e=n.value.trim(),s=v.value.trim()!==""||d.value!=="";if(o.value&&e===""){u.value="服务器部署必须设置主密钥,防止 /v1 网关被他人盗用";return}if(o.value&&!s){u.value="服务器部署必须设置登录账号密码,防止管理台被陌生人登录";return}if(s){if(v.value.trim()===""||d.value===""){u.value="用户名和密码需同时填写";return}if(d.value.length<6){u.value="密码至少 6 位";return}}V.value=!0;try{const r=e!==""?await K.post("/api/setup/master-key",{mode:"custom",masterKey:e}):null,y=await K.post("/api/setup/finish",{deployment:l,...s?{username:v.value.trim(),password:d.value}:{}});L(l,s),w.success(s?"初始化完成,请使用新账号登录":"初始化完成,免登录进入管理台");const c=(r==null?void 0:r.restartHint)??y.restartHint;c&&w({message:c,type:"warning",duration:8e3}),await A.push(s?"/login":"/")}catch(r){u.value=r.message||"保存失败"}finally{V.value=!1}}return(l,e)=>{const s=p("el-checkbox"),r=p("el-alert"),y=p("el-button"),c=p("el-input"),x=p("el-form-item"),M=p("el-form"),N=p("el-card");return k(),j("div",$,[a(N,{shadow:"hover",class:"setup-card"},{default:t(()=>[e[10]||(e[10]=_("h2",{class:"setup-title"},"初始化 EZLLM",-1)),a(s,{modelValue:o.value,"onUpdate:modelValue":e[0]||(e[0]=i=>o.value=i),class:"mb-16"},{default:t(()=>[...e[4]||(e[4]=[f(" 允许其他设备访问本服务(局域网 / 公网部署) ",-1)])]),_:1},8,["modelValue"]),o.value?(k(),S(r,{key:0,type:"warning","show-icon":"",closable:!1,title:"服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号",class:"mb-16"})):h("",!0),a(M,{"label-position":"top",onSubmit:G(C,["prevent"])},{default:t(()=>[a(x,null,{label:t(()=>[...e[5]||(e[5]=[f(" API 主密钥(本地部署可留空) ",-1),_("span",{class:"label-hint"},"调用 /v1/* 时的 Bearer Token;留空 = 不启用鉴权,且未设登录账号时服务仅本机可访问",-1)])]),default:t(()=>[a(c,{modelValue:n.value,"onUpdate:modelValue":e[1]||(e[1]=i=>n.value=i),placeholder:"已设置主密钥,留空保持不变",clearable:""},{append:t(()=>[a(y,{onClick:g},{default:t(()=>[...e[6]||(e[6]=[f("生成",-1)])]),_:1}),a(y,{disabled:!n.value,onClick:U},{default:t(()=>[...e[7]||(e[7]=[f("复制",-1)])]),_:1},8,["disabled"])]),_:1},8,["modelValue"])]),_:1}),a(x,null,{label:t(()=>[...e[8]||(e[8]=[f(" 管理台登录(可选) ",-1),_("span",{class:"label-hint"},"不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写",-1)])]),default:t(()=>[_("div",q,[a(c,{modelValue:v.value,"onUpdate:modelValue":e[2]||(e[2]=i=>v.value=i),placeholder:"用户名",clearable:""},null,8,["modelValue"]),a(c,{modelValue:d.value,"onUpdate:modelValue":e[3]||(e[3]=i=>d.value=i),type:"password","show-password":"",placeholder:"密码(至少 6 位)"},null,8,["modelValue"])])]),_:1}),u.value?(k(),S(r,{key:0,title:u.value,type:"error","show-icon":"",closable:!1,class:"mb-16"},null,8,["title"])):h("",!0),a(y,{type:"primary",class:"full-width",loading:V.value,onClick:C},{default:t(()=>[...e[9]||(e[9]=[f(" 完成初始化 ",-1)])]),_:1},8,["loading"])]),_:1})]),_:1})])}}}),O=R(z,[["__scopeId","data-v-52af652f"]]);export{O as default};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
.setup-wrap[data-v-52af652f]{min-height:100vh;display:flex;align-items:center;justify-content:center;background:#f5f7fa}.setup-card[data-v-52af652f]{width:520px;max-width:92vw}.setup-title[data-v-52af652f]{text-align:center;margin-bottom:20px;color:#3b82f6}.account-row[data-v-52af652f]{display:flex;gap:12px;width:100%}.label-hint[data-v-52af652f]{display:block;font-size:12px;font-weight:400;color:#909399;line-height:1.4}.full-width[data-v-52af652f]{width:100%}.mb-16[data-v-52af652f]{margin-bottom:16px}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
async function c(t){try{if(navigator.clipboard&&window.isSecureContext)return await navigator.clipboard.writeText(t),!0}catch{}try{const e=document.createElement("textarea");e.value=t,e.style.position="fixed",e.style.opacity="0",document.body.appendChild(e),e.select();const o=document.execCommand("copy");return document.body.removeChild(e),o}catch{return!1}}export{c};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a1 as p,r as s,p as n,A as i}from"./index-CgzCvxTY.js";const y=p("config",()=>{const a=s({}),e=s(!1),o=n(()=>Array.isArray(a.value.providers)?a.value.providers:[]),l=n(()=>o.value.length),c=n(()=>o.value.reduce((t,d)=>{var u;return t+(((u=d.models)==null?void 0:u.length)??0)},0));async function f(){e.value=!0;try{a.value=await i.get("/api/config")}finally{e.value=!1}}async function r(){return await i.put("/api/config",a.value)}async function v(t){return t(a.value),await r()}return{config:a,loading:e,providers:o,providerCount:l,totalModelCount:c,load:f,save:r,update:v}});export{y as u};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function u(){let t=0;return()=>{const e=++t;return()=>e===t}}const i=t=>{if(!t)return"-";const e=new Date(t);if(Number.isNaN(e.getTime()))return"-";const r=n=>String(n).padStart(2,"0");return`${e.getFullYear()}-${r(e.getMonth()+1)}-${r(e.getDate())} ${r(e.getHours())}:${r(e.getMinutes())}:${r(e.getSeconds())}`},o=t=>t?typeof t=="string"?t:JSON.stringify(t,null,2):"-",s=t=>{if(!t)return"-";try{return JSON.stringify(JSON.parse(t),null,2)}catch{return t}},c=t=>(t??0).toLocaleString(),a=t=>t?t>=1024**3?(t/1024**3).toFixed(1)+"G":t>=1024**2?(t/1024**2).toFixed(1)+"M":t>=1024?(t/1024).toFixed(1)+"K":`${t}B`:"-",f=({protocol:t,hostname:e,port:r})=>`${t==="https:"?"https:":"http:"}//${e}${r?`:${r}`:""}`,g=t=>t==null||t<=0?"-":t>=1e3?(t/1e3).toFixed(2)+"s":Math.round(t)+"ms",h=t=>{const e=t.input_tokens||0,r=t.cache_read_tokens||0;return e<=0?"-":(r/e*100).toFixed(1)+"%"};export{g as a,a as b,u as c,f as d,i as e,c as f,h as g,o as h,s as i};
|