ezllm 0.0.36 → 0.0.37

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.
Files changed (34) hide show
  1. package/README.md +16 -11
  2. package/dist/server.js +60 -54
  3. package/dist/web-ui/assets/DashboardView-BzKKC4LZ.js +1 -0
  4. package/dist/web-ui/assets/{LayoutView-DjpChErJ.js → LayoutView-BzBSYjz8.js} +1 -1
  5. package/dist/web-ui/assets/{LoginView-Dh-JvmGC.js → LoginView-Bzngu7qF.js} +1 -1
  6. package/dist/web-ui/assets/LogsView-C2cZgB5T.js +5 -0
  7. package/dist/web-ui/assets/LogsView-u-0B5Xpc.css +1 -0
  8. package/dist/web-ui/assets/{ManagedServicesView-C5ZROVtT.js → ManagedServicesView-5QT_g-5a.js} +2 -2
  9. package/dist/web-ui/assets/ProvidersView-BPOzev6x.js +14 -0
  10. package/dist/web-ui/assets/ServiceStatusView--D1wfNAZ.js +2 -0
  11. package/dist/web-ui/assets/{SettingsView-MrcC_nr9.js → SettingsView-XXHJh2h8.js} +1 -1
  12. package/dist/web-ui/assets/SetupView-CSBKlfcJ.css +1 -0
  13. package/dist/web-ui/assets/SetupView-DcThD5bd.js +1 -0
  14. package/dist/web-ui/assets/{config-DXHhKDw-.js → config-B8sfBKCc.js} +1 -1
  15. package/dist/web-ui/assets/format-CO5kjbrg.js +1 -0
  16. package/dist/web-ui/assets/{index-BKnCp9qM.js → index-CZeCUjra.js} +1 -1
  17. package/dist/web-ui/assets/{index-wQvjidwN.css → index-s_h6GEbv.css} +1 -1
  18. package/dist/web-ui/assets/{message-C1fkA9sE.js → message-sILMvZIb.js} +1 -1
  19. package/dist/web-ui/assets/{providers-BHK2eZZc.js → providers-dvoMyAle.js} +1 -1
  20. package/dist/web-ui/assets/{router-DI9ZLaCn.js → router-BUuAm5No.js} +2 -2
  21. package/dist/web-ui/assets/{useManagerApi-l9V9LoLa.js → useManagerApi-XPGaswMw.js} +1 -1
  22. package/dist/web-ui/assets/{useQuickRangeFilter-Crb6MDvU.js → useQuickRangeFilter-Bg2q_vMO.js} +1 -1
  23. package/dist/web-ui/assets/useToast-BscapoHF.js +1 -0
  24. package/dist/web-ui/index.html +4 -4
  25. package/package.json +1 -1
  26. package/dist/web-ui/assets/DashboardView-4pju0xUn.js +0 -1
  27. package/dist/web-ui/assets/LogsView-BLOCTdb6.js +0 -5
  28. package/dist/web-ui/assets/LogsView-D7FTeaYQ.css +0 -1
  29. package/dist/web-ui/assets/ProvidersView-Dwc7I6G0.js +0 -14
  30. package/dist/web-ui/assets/ServiceStatusView-fiaEQZNp.js +0 -2
  31. package/dist/web-ui/assets/SetupView-BLl-ZFOA.css +0 -1
  32. package/dist/web-ui/assets/SetupView-vTCaewVk.js +0 -1
  33. package/dist/web-ui/assets/format-DbT9vkcP.js +0 -1
  34. package/dist/web-ui/assets/useToast-PFDoTWpf.js +0 -1
@@ -1,2 +0,0 @@
1
- import{A as e,F as t,I as n,M as r,O as i,P as a,Pt as o,Q as s,Tt as c,V as l,Wt as u,Z as d,a as f,at as ee,et as p,fn as m,ht as h,it as g,j as _,k as v,ln as te,mt as y,nt as b,sn as ne,vt as x,w as S}from"./router-DI9ZLaCn.js";import{t as C}from"./index-BKnCp9qM.js";import{p as w,s as T,u as re,v as ie,y as ae}from"./format-DbT9vkcP.js";import{t as oe}from"./useToast-PFDoTWpf.js";l(),x(),u();var se={class:`service-status-page`},ce={class:`flex-between`},le={class:`flex-gap-8`},E={class:`flex-gap-8`},D={class:`gantt-wrap`},O={key:0,class:`gantt`},ue={class:`gantt-row gantt-head`},de={class:`col-cells`},fe=[`title`],pe={class:`cell-head-date`},me={class:`col-name`},he=[`title`,`onClick`],ge=[`title`],k={class:`col-cells`},A=[`title`],j={key:1,class:`gantt-empty`},M=36e5,N=24,P=`#909399`,F=C(n({__name:`ServiceStatusView`,setup(n){let{toast:l}=oe(),{copyWithToast:u}=ie(),{loadError:x,run:C}=ae(`延迟数据加载失败,请重试`),F=c([]),I=c(!0),L=c(!1),R=c(null),z=c(!1),B=c(!1),V,H,U=c(G()),W=c(new Map);function G(){let e=new Date,t=new Date(e.getFullYear(),e.getMonth(),e.getDate(),e.getHours()).getTime();return Array.from({length:N},(e,n)=>t-(23-n)*M)}let K=e=>{let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${w(t.getMonth()+1)}-${w(t.getDate())} ${w(t.getHours())}:00`},_e=i(()=>U.value.map(e=>{let t=new Date(e),n=w(t.getHours());return{start:e,dateLabel:`${w(t.getMonth()+1)}-${w(t.getDate())}`,hourLabel:n,fullLabel:`${K(e)} - ${n}:59`}})),ve=[103,194,58],q=[230,162,60],ye=[245,108,108],be=i(()=>{let e=[];for(let t of W.value.values())for(let n of t.values())n.avgLatencyMs!==null&&e.push(n.avgLatencyMs);if(e.length===0)return{min:0,max:0};let t=e[0],n=e[0];for(let r of e)r<t&&(t=r),r>n&&(n=r);return{min:t,max:n}}),J=e=>{let{min:t,max:n}=be.value,r=n===t?0:(e-t)/(n-t),[i,a]=r<=.5?[ve,q]:[q,ye],o=r<=.5?r*2:(r-.5)*2,s=i.map((e,t)=>Math.round(e+(a[t]-e)*o));return`rgba(${String(s[0])}, ${String(s[1])}, ${String(s[2])}, 0.9)`},Y=(e,t)=>{let n=`${K(t)} - ${w(new Date(t+M).getHours())}:00`;return e===void 0||e.total===0?`${n}\n无探测数据`:`${n}\n平均延迟 ${T(e.avgLatencyMs)}\n成功 ${String(e.success)} / 失败 ${String(e.failed)}`},X=i(()=>Se.value.map(e=>{let t=W.value.get(e.model),n=U.value.map(e=>{let n=t?.get(e);return n!==void 0&&n.failed>0?{start:e,className:`cell--down`,style:{backgroundColor:P},title:Y(n,e)}:n===void 0||n.avgLatencyMs===null?{start:e,className:`cell--empty`,style:{},title:Y(n,e)}:{start:e,className:``,style:{backgroundColor:J(n.avgLatencyMs)},title:Y(n,e)}});return{model:e.model,avg24h:e.avg24h,statusTitle:[e.avg24h===null?`最近 24 小时无成功探测记录`:`最近 24 小时成功探测平均延迟 ${T(e.avg24h)}`,e.lastLatencyMs==null?`最近一次探测:无成功延迟记录`:`最近一次探测延迟 ${T(e.lastLatencyMs)}`].join(`
2
- `),cells:n}})),xe=(e,t)=>e===null&&t===null?0:e===null?1:t===null?-1:e-t,Se=i(()=>[...F.value].sort((e,t)=>{let n=e.lastOk===!1;if(n!==(t.lastOk===!1))return n?1:-1;let r=xe(e.avg24h,t.avg24h);return r===0?e.model.localeCompare(t.model):r})),Z=async e=>{if(e.length===0){W.value=new Map;return}let t=await Promise.all(e.map(async e=>{try{let t=await f.get(`/api/latency/trend?model=${encodeURIComponent(e)}&granularity=hour`);return[e,new Map((t.buckets??[]).map(e=>[e.bucketStart,e]))]}catch{return[e,new Map]}}));W.value=new Map(t)},Q=async()=>{let e=await f.get(`/api/latency/history`);return F.value=e.models??[],L.value=e.running,R.value=e.lastRunAt,e},$=()=>C(async()=>{try{await Q(),U.value=G(),await Z(F.value.map(e=>e.model))}finally{I.value=!1}}),Ce=()=>$(),we=()=>{B.value?V=window.setInterval(()=>void $(),5e3):V!==void 0&&(window.clearInterval(V),V=void 0)},Te=async()=>{z.value=!0;try{await f.post(`/api/latency/run`)}catch(e){l(e.message,`error`),z.value=!1;return}H=window.setInterval(async()=>{try{(await Q()).running||(window.clearInterval(H),H=void 0,z.value=!1,U.value=G(),await Z(F.value.map(e=>e.model)))}catch{}},2e3)};return d(()=>{$()}),s(()=>{V!==void 0&&window.clearInterval(V),H!==void 0&&window.clearInterval(H)}),(n,i)=>{let s=g(`el-button`),c=g(`el-alert`),l=g(`el-tag`),d=g(`el-checkbox`),f=g(`el-empty`),C=g(`el-card`),w=ee(`loading`);return p(),r(`div`,se,[o(x)?(p(),e(c,{key:0,title:o(x),type:`error`,"show-icon":``,closable:!1,class:`mb-16`},{default:y(()=>[t(s,{size:`small`,onClick:Ce},{default:y(()=>[...i[1]||=[a(`重试`,-1)]]),_:1})]),_:1},8,[`title`])):_(``,!0),t(C,{shadow:`never`,class:`main-card`},{header:y(()=>[v(`div`,ce,[v(`div`,le,[i[3]||=v(`span`,{class:`fw-600`},`服务状态`,-1),L.value?(p(),e(l,{key:0,type:`warning`,size:`small`},{default:y(()=>[...i[2]||=[a(`测试进行中`,-1)]]),_:1})):R.value?(p(),e(l,{key:1,type:`info`,size:`small`},{default:y(()=>[a(` 上次测试 `+m(o(re)(R.value)),1)]),_:1})):_(``,!0)]),v(`div`,E,[t(d,{modelValue:B.value,"onUpdate:modelValue":i[0]||=e=>B.value=e,onChange:we},{default:y(()=>[...i[4]||=[a(` 自动刷新(5s) `,-1)]]),_:1},8,[`modelValue`]),t(s,{loading:z.value,onClick:Te},{default:y(()=>[...i[5]||=[a(` 延迟测试 `,-1)]]),_:1},8,[`loading`])])])]),default:y(()=>[i[9]||=v(`div`,{class:`legend`},[v(`span`,{class:`legend-text`},`延迟`),v(`span`,{class:`legend-text`},`低`),v(`span`,{class:`legend-gradient`}),v(`span`,{class:`legend-text`},`高`),v(`span`,{class:`legend-swatch legend-swatch--down`}),v(`span`,{class:`legend-text`},`该小时有失败探测`),v(`span`,{class:`legend-swatch legend-swatch--empty`}),v(`span`,{class:`legend-text`},`无探测数据`)],-1),h((p(),r(`div`,D,[i[8]||=v(`div`,{class:`muted-sm hint`},` 右侧 24 格为最近 24 小时(每格 1 小时,本地整点对齐,最右格为当前小时)。 格子底色为当小时成功探测的平均延迟,全表统一色标(本期最快→最慢 绿→红); 当小时存在失败探测即视为不可用,显示灰色。 行按 24h 平均延迟升序,最近一次探测失败的模型沉底。 `,-1),X.value.length>0?(p(),r(`div`,O,[v(`div`,ue,[i[6]||=v(`div`,{class:`col-name`},`模型名称`,-1),i[7]||=v(`div`,{class:`col-status`},`状态`,-1),v(`div`,de,[(p(!0),r(S,null,b(_e.value,e=>(p(),r(`div`,{key:e.start,class:`cell cell--head`,title:e.fullLabel},[v(`span`,pe,m(e.dateLabel),1),v(`span`,null,m(e.hourLabel),1)],8,fe))),128))])]),(p(!0),r(S,null,b(X.value,e=>(p(),r(`div`,{key:e.model,class:`gantt-row`},[v(`div`,me,[v(`span`,{class:`copy-text model-name`,title:e.model,onClick:t=>o(u)(e.model)},m(e.model),9,he)]),v(`div`,{class:`col-status`,title:e.statusTitle},m(o(T)(e.avg24h)),9,ge),v(`div`,k,[(p(!0),r(S,null,b(e.cells,e=>(p(),r(`div`,{key:e.start,class:ne([`cell`,e.className]),style:te(e.style),title:e.title},null,14,A))),128))])]))),128))])):(p(),r(`div`,j,[t(f,{description:`暂无延迟数据,点击「延迟测试」开始`,"image-size":80})]))])),[[w,I.value]])]),_:1})])}}}),[[`__scopeId`,`data-v-95ae284d`]]);export{F as default};
@@ -1 +0,0 @@
1
- .setup-wrap[data-v-852bbcb1]{justify-content:center;align-items:center;min-height:100vh;display:flex}.setup-card[data-v-852bbcb1]{border-radius:16px;width:520px;max-width:92vw;box-shadow:0 12px 40px #1f23291a}.setup-brand[data-v-852bbcb1]{justify-content:center;align-items:center;gap:10px;margin-top:8px;display:flex}.setup-title[data-v-852bbcb1]{color:var(--el-text-color-primary);font-size:20px;font-weight:700}.setup-sub[data-v-852bbcb1]{text-align:center;color:var(--el-text-color-secondary);margin:6px 0 24px;font-size:13px}.account-row[data-v-852bbcb1]{gap:12px;width:100%;display:flex}.label-hint[data-v-852bbcb1]{color:#909399;font-size:12px;font-weight:400;line-height:1.4;display:block}.full-width[data-v-852bbcb1]{width:100%}.mb-16[data-v-852bbcb1]{margin-bottom:16px}
@@ -1 +0,0 @@
1
- import{A as e,F as t,I as n,M as r,P as i,S as a,Tt as o,V as s,Z as c,a as l,et as u,ft as d,it as f,j as p,k as m,m as h,mt as g,n as _,r as v,u as y,vt as b}from"./router-DI9ZLaCn.js";import{t as x}from"./message-C1fkA9sE.js";import{t as S}from"./index-BKnCp9qM.js";import{t as C}from"./clipboard-JYWVdyjq.js";s(),h(),b();var w={class:`setup-wrap`},T={class:`account-row`},E=S(n({__name:`SetupView`,setup(n){let s=y(),h=o(!1),b=o(``),S=!1,E=o(``),D=o(``),O=o(!1),k=o(``);c(async()=>{!(await _()).masterKeySet&&h.value&&A()});function A(){b.value=(()=>{let e=new Uint8Array(32);crypto.getRandomValues(e);let t=``;for(let n of e)t+=String.fromCharCode(n);return btoa(t).replace(/\+/g,`-`).replace(/\//g,`_`).replace(/=+$/,``)})(),S=!0}d(h,e=>{e?b.value.trim()===``&&A():S&&=(b.value=``,!1)});async function j(){await C(b.value)?x.success(`已复制到剪贴板`):x.error(`复制失败,请手动选择复制`)}async function M(){k.value=``;let e=h.value?`server`:`local`,t=b.value.trim(),n=E.value.trim()!==``||D.value!==``;if(h.value&&t===``){k.value=`服务器部署必须设置主密钥,防止 /v1 网关被他人盗用`;return}if(h.value&&!n){k.value=`服务器部署必须设置登录账号密码,防止管理台被陌生人登录`;return}if(n){if(E.value.trim()===``||D.value===``){k.value=`用户名和密码需同时填写`;return}if(D.value.length<6){k.value=`密码至少 6 位`;return}}O.value=!0;try{let r=t===``?null:await l.post(`/api/setup/master-key`,{mode:`custom`,masterKey:t}),i=await l.post(`/api/setup/finish`,{deployment:e,...n?{username:E.value.trim(),password:D.value}:{}});v(e,n),x.success(n?`初始化完成,请使用新账号登录`:`初始化完成,免登录进入管理台`);let a=r?.restartHint??i.restartHint;a&&x({message:a,type:`warning`,duration:8e3}),await s.push(n?`/login`:`/`)}catch(e){k.value=e.message||`保存失败`}finally{O.value=!1}}return(n,o)=>{let s=f(`el-checkbox`),c=f(`el-alert`),l=f(`el-button`),d=f(`el-input`),_=f(`el-form-item`),v=f(`el-form`),y=f(`el-card`);return u(),r(`div`,w,[t(y,{shadow:`never`,class:`setup-card`},{default:g(()=>[o[10]||=m(`div`,{class:`setup-brand`},[m(`span`,{class:`brand-mark`},`EZ`),m(`span`,{class:`setup-title`},`初始化 EZLLM`)],-1),o[11]||=m(`p`,{class:`setup-sub`},`首次使用前完成部署形态与访问凭据的配置`,-1),t(s,{modelValue:h.value,"onUpdate:modelValue":o[0]||=e=>h.value=e,class:`mb-16`},{default:g(()=>[...o[4]||=[i(` 允许其他设备访问本服务(局域网 / 公网部署) `,-1)]]),_:1},8,[`modelValue`]),h.value?(u(),e(c,{key:0,type:`warning`,"show-icon":``,closable:!1,title:`服务将对网络中的其他设备可见,请务必保留主密钥并修改默认账号`,class:`mb-16`})):p(``,!0),t(v,{"label-position":`top`,onSubmit:a(M,[`prevent`])},{default:g(()=>[t(_,null,{label:g(()=>[...o[5]||=[i(` API 主密钥(本地部署可留空) `,-1),m(`span`,{class:`label-hint`},`调用 /v1/* 时的 Bearer Token;留空 = 不启用鉴权,且未设登录账号时服务仅本机可访问`,-1)]]),default:g(()=>[t(d,{modelValue:b.value,"onUpdate:modelValue":o[1]||=e=>b.value=e,placeholder:`已设置主密钥,留空保持不变`,clearable:``},{append:g(()=>[t(l,{onClick:A},{default:g(()=>[...o[6]||=[i(`生成`,-1)]]),_:1}),t(l,{disabled:!b.value,onClick:j},{default:g(()=>[...o[7]||=[i(`复制`,-1)]]),_:1},8,[`disabled`])]),_:1},8,[`modelValue`])]),_:1}),t(_,null,{label:g(()=>[...o[8]||=[i(` 管理台登录(可选) `,-1),m(`span`,{class:`label-hint`},`不填 = 免登录直接进管理台(纯本机使用);勾选上方后必须填写`,-1)]]),default:g(()=>[m(`div`,T,[t(d,{modelValue:E.value,"onUpdate:modelValue":o[2]||=e=>E.value=e,placeholder:`用户名`,clearable:``},null,8,[`modelValue`]),t(d,{modelValue:D.value,"onUpdate:modelValue":o[3]||=e=>D.value=e,type:`password`,"show-password":``,placeholder:`密码(至少 6 位)`},null,8,[`modelValue`])])]),_:1}),k.value?(u(),e(c,{key:0,title:k.value,type:`error`,"show-icon":``,closable:!1,class:`mb-16`},null,8,[`title`])):p(``,!0),t(l,{type:`primary`,class:`full-width`,loading:O.value,onClick:M},{default:g(()=>[...o[9]||=[i(` 完成初始化 `,-1)]]),_:1},8,[`loading`])]),_:1})]),_:1})])}}}),[[`__scopeId`,`data-v-852bbcb1`]]);export{E as default};
@@ -1 +0,0 @@
1
- import{Tt as e,vt as t}from"./router-DI9ZLaCn.js";import{t as n}from"./clipboard-JYWVdyjq.js";import{t as r}from"./useToast-PFDoTWpf.js";t();function i(t=`加载失败,请稍后重试`){let n=e(null);async function r(e){n.value=null;try{return await e(),!0}catch(e){return n.value=e?.message||t,!1}}return{loadError:n,run:r}}function a(){let{toast:e}=r();async function t(t,r=`已复制到剪贴板`){let i=await n(t);return i?e(r,`success`):e(`复制失败`,`error`),i}return{copyWithToast:t}}var o=e=>String(e).padStart(2,`0`),s=e=>{let t=e=>`${e.getFullYear()}-${o(e.getMonth()+1)}-${o(e.getDate())}`,n=new Date,r=new Date(n),i=n;if(e!==`today`){if(e===`yesterday`)r.setDate(n.getDate()-1),i=r;else if(e===`beforeYesterday`)r.setDate(n.getDate()-2),i=r;else if(e===`last3days`)r.setDate(n.getDate()-2);else if(e===`week`)r.setDate(n.getDate()-(n.getDay()+6)%7);else if(e===`month`)r.setDate(1);else return null}return[t(r),t(i)]},c=e=>{if(e.name)return e.name;if(e.alias)return e.alias;let t=e.apiKey||``;if(!t)return`-`;if(t.length<=8)return t;let n=Math.min(6,Math.floor(t.length/4));return`${t.substring(0,n)}...${t.substring(t.length-n)}`},l=e=>{if(!e)return`-`;let t=new Date(e);return Number.isNaN(t.getTime())?`-`:`${t.getFullYear()}-${o(t.getMonth()+1)}-${o(t.getDate())} ${o(t.getHours())}:${o(t.getMinutes())}:${o(t.getSeconds())}`},u=e=>e?typeof e==`string`?e:JSON.stringify(e,null,2):`-`,d=e=>{if(!e)return`-`;try{return JSON.stringify(JSON.parse(e),null,2)}catch{return e}},f=e=>{let t=e??0;return(Number.isFinite(t)?t:0).toLocaleString()},p=({protocol:e,hostname:t,port:n})=>`${e===`https:`?`https:`:`http:`}//${t}${n?`:${n}`:``}`,m=e=>e==null||e<=0?`-`:e>=1e3?(e/1e3).toFixed(2)+`s`:Math.round(e)+`ms`,h=e=>e==null?`-`:e<1e3?`${String(e)}ms`:`${(e/1e3).toFixed(1)}s`,g=e=>{let t=e.input_tokens||0,n=e.cache_read_tokens||0;return t<=0?`-`:(n/t*100).toFixed(1)+`%`},_=(e,t=262144)=>{let n=e??``;return n.length<=t?n:`${n.slice(0,t)}\n\n…(已省略 ${(n.length-t).toLocaleString()} 字符以保持流畅,完整内容请点上方「复制」按钮)`},v=e=>{let t=(e||``).trim();return t?t.length>8?`${t.slice(0,8)}…`:t:`-`},y=e=>e.client||e.user_agent||`-`,b=e=>e.user_agent?`${e.user_agent}(点击复制)`:`${e.client??`-`}(点击复制)`,x=e=>{let t=(e||``).split(`,`).map(e=>e.trim()).filter(Boolean).sort();return t.length===0?`-`:t.length<=2?t.join(`, `):`${t.slice(0,2).join(`, `)} +${t.length-2}`},S=e=>x(e),C=e=>x(e);export{_,C as a,f as c,d,S as f,v as g,s as h,b as i,u as l,c as m,g as n,m as o,o as p,y as r,h as s,p as t,l as u,a as v,i as y};
@@ -1 +0,0 @@
1
- import{t as e}from"./message-C1fkA9sE.js";function t(){function t(t,n=`success`){e({message:t,type:n,duration:n===`warning`?8e3:3e3})}return{toast:t}}export{t};