benchscope 1.0.2__tar.gz → 1.0.3__tar.gz

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 (49) hide show
  1. {benchscope-1.0.2 → benchscope-1.0.3}/PKG-INFO +6 -6
  2. {benchscope-1.0.2 → benchscope-1.0.3}/README.md +2 -2
  3. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/__init__.py +1 -1
  4. benchscope-1.0.2/benchscope/webui/assets/LogView-DDQEtmE9.js → benchscope-1.0.3/benchscope/webui/assets/LogView-uBOyk8EU.js +1 -1
  5. benchscope-1.0.2/benchscope/webui/assets/MetricsCharts-nbvzLpID.js → benchscope-1.0.3/benchscope/webui/assets/MetricsCharts-BKjshnuj.js +1 -1
  6. benchscope-1.0.2/benchscope/webui/assets/SettingsView-CTQ-BCjl.js → benchscope-1.0.3/benchscope/webui/assets/SettingsView-D2WEiq-g.js +1 -1
  7. benchscope-1.0.2/benchscope/webui/assets/TestView-CWMIdblB.js → benchscope-1.0.3/benchscope/webui/assets/TestView-BDm6cgl1.js +1 -1
  8. benchscope-1.0.2/benchscope/webui/assets/antd-DWALckI0.js → benchscope-1.0.3/benchscope/webui/assets/antd-CmFZS0N1.js +87 -87
  9. benchscope-1.0.2/benchscope/webui/assets/index-CF7y9dDO.css → benchscope-1.0.3/benchscope/webui/assets/index-C03xBaD-.css +1 -1
  10. benchscope-1.0.3/benchscope/webui/assets/index-CzYL8dyk.js +2 -0
  11. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/index.html +3 -3
  12. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/PKG-INFO +6 -6
  13. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/SOURCES.txt +7 -7
  14. {benchscope-1.0.2 → benchscope-1.0.3}/pyproject.toml +4 -4
  15. benchscope-1.0.2/benchscope/webui/assets/index-DYReb9-e.js +0 -2
  16. {benchscope-1.0.2 → benchscope-1.0.3}/LICENSE +0 -0
  17. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/__main__.py +0 -0
  18. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/benches/__init__.py +0 -0
  19. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/benches/base.py +0 -0
  20. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/benches/runner.py +0 -0
  21. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/benches/sglang_bench.py +0 -0
  22. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/benches/vllm_bench.py +0 -0
  23. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/cli.py +0 -0
  24. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/config.py +0 -0
  25. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/constants.py +0 -0
  26. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/datasets.py +0 -0
  27. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/gpu.py +0 -0
  28. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/parser.py +0 -0
  29. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/__init__.py +0 -0
  30. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/api_config.py +0 -0
  31. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/api_logs.py +0 -0
  32. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/api_test.py +0 -0
  33. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/app.py +0 -0
  34. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/state.py +0 -0
  35. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/status.py +0 -0
  36. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/test_manager.py +0 -0
  37. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/server/ws.py +0 -0
  38. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/summary.py +0 -0
  39. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/LogView-BDFIduo7.css +0 -0
  40. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/MetricsCharts-D1wU0LbK.css +0 -0
  41. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/SettingsView-7uuTFqXU.css +0 -0
  42. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/TestView-BAwcOtR2.css +0 -0
  43. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/echarts-Bb6yjXMn.js +0 -0
  44. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope/webui/assets/vue-Ch4zjUb1.js +0 -0
  45. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/dependency_links.txt +0 -0
  46. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/entry_points.txt +0 -0
  47. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/requires.txt +0 -0
  48. {benchscope-1.0.2 → benchscope-1.0.3}/benchscope.egg-info/top_level.txt +0 -0
  49. {benchscope-1.0.2 → benchscope-1.0.3}/setup.cfg +0 -0
@@ -1,12 +1,12 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: benchscope
3
- Version: 1.0.2
3
+ Version: 1.0.3
4
4
  Summary: vLLM / SGLang 推理服务性能测试 Web 工具 (benchscope)
5
5
  Author-email: benchscope <benchscope@example.com>
6
6
  License-Expression: Apache-2.0
7
- Project-URL: Homepage, https://github.com/benchscope/benchscope
8
- Project-URL: Documentation, https://github.com/benchscope/benchscope#readme
9
- Project-URL: Source, https://github.com/benchscope/benchscope
7
+ Project-URL: Homepage, https://github.com/LABELNET/benchscope
8
+ Project-URL: Documentation, https://github.com/LABELNET/benchscope#readme
9
+ Project-URL: Source, https://github.com/LABELNET/benchscope
10
10
  Keywords: vllm,sglang,benchmark,llm,performance-test,inference,openai-api,web-ui,benchscope
11
11
  Classifier: Development Status :: 5 - Production/Stable
12
12
  Classifier: Intended Audience :: Developers
@@ -82,7 +82,7 @@ Open the page and:
82
82
  - **Admin-console UI** — fixed top nav, fixed left nav (test workflow / test records), and a fixed sub-nav; the content area scrolls internally.
83
83
  - **Status monitoring** — Service & Environment online/offline indicators with live updates.
84
84
 
85
- ## Roadmap / TODO
85
+ ## Roadmap
86
86
 
87
87
  | Version | Status | Scope |
88
88
  | --- | --- | --- |
@@ -127,5 +127,5 @@ cd web && npm install && npm run dev # http://127.0.0.1:5173
127
127
 
128
128
  - **License** — [Apache License 2.0](LICENSE)
129
129
  - **Published on** — [PyPI: benchscope](https://pypi.org/project/benchscope/)
130
- - **Source** — <https://github.com/benchscope/benchscope>
130
+ - **Source** — <https://github.com/LABELNET/benchscope>
131
131
  - **Contributing** — feel free to open issues / pull requests on the source repository.
@@ -48,7 +48,7 @@ Open the page and:
48
48
  - **Admin-console UI** — fixed top nav, fixed left nav (test workflow / test records), and a fixed sub-nav; the content area scrolls internally.
49
49
  - **Status monitoring** — Service & Environment online/offline indicators with live updates.
50
50
 
51
- ## Roadmap / TODO
51
+ ## Roadmap
52
52
 
53
53
  | Version | Status | Scope |
54
54
  | --- | --- | --- |
@@ -93,5 +93,5 @@ cd web && npm install && npm run dev # http://127.0.0.1:5173
93
93
 
94
94
  - **License** — [Apache License 2.0](LICENSE)
95
95
  - **Published on** — [PyPI: benchscope](https://pypi.org/project/benchscope/)
96
- - **Source** — <https://github.com/benchscope/benchscope>
96
+ - **Source** — <https://github.com/LABELNET/benchscope>
97
97
  - **Contributing** — feel free to open issues / pull requests on the source repository.
@@ -1,3 +1,3 @@
1
1
  """benchscope - vLLM / SGLang 推理服务性能测试 Web 工具."""
2
2
 
3
- __version__ = "1.0.2"
3
+ __version__ = "1.0.3"
@@ -1 +1 @@
1
- import{_ as E,b as Z,a as F}from"./index-DYReb9-e.js";import{f as x,w as G,o as ee,S as c,U as b,a6 as S,X as w,V as L,W as a,G as v,_ as i,k as t,Y as te,c as O,F as X,a8 as D,r as Y}from"./vue-Ch4zjUb1.js";import{M as H,_ as ae}from"./MetricsCharts-nbvzLpID.js";import{j as W}from"./antd-DWALckI0.js";import"./echarts-Bb6yjXMn.js";const ne={class:"record-list"},oe={class:"record-head"},le={style:{"font-weight":"600","font-size":"13px"}},se={style:{"font-size":"12px","line-height":"1.6"}},re={__name:"RunRecordList",props:{modelValue:{type:String,default:""},framework:{type:String,default:""}},emits:["update:modelValue"],setup(p,{emit:d}){const u=p,r=d,l=Z(),o=O(()=>u.framework),m=x(u.framework||""),T=x([]),f=x(!1),B=O(()=>{const s=o.value||m.value;if(!s)return T.value;const k=s==="vllm"?"vLLM":"SGLang";return T.value.filter(g=>{var e;return(((e=g.meta)==null?void 0:e.framework)||"")===k})});function j(s){return s==="vllm"?"vLLM":"SGLang"}function K(s){return s==="done"?"green":s==="error"?"red":s==="stopped"?"orange":"blue"}function A(s){return s==="done"?"完成":s==="error"?"失败":s==="stopped"?"已停止":"运行中"}async function M(){f.value=!0;try{const s=await F.listRuns();T.value=s.runs||[]}finally{f.value=!1}}return G(B,s=>{if(!s.length){u.modelValue&&r("update:modelValue","");return}if(!(u.modelValue&&s.some(g=>g.run_id===u.modelValue))){const g=l.lastRunId&&s.some(e=>e.run_id===l.lastRunId)?l.lastRunId:s[0].run_id;r("update:modelValue",g)}},{immediate:!0}),G(()=>l.lastRunId,M),G(m,()=>{}),ee(M),(s,k)=>{const g=c("a-select"),e=c("a-tag"),n=c("a-list-item-meta"),C=c("a-list-item"),$=c("a-list"),R=c("a-spin");return b(),S("div",ne,[w("div",oe,[k[1]||(k[1]=w("span",{class:"record-title"},"测试记录",-1)),o.value?(b(),L(e,{key:1,size:"small",color:"blue"},{default:a(()=>[v(i(j(o.value)),1)]),_:1})):(b(),L(g,{key:0,value:m.value,"onUpdate:value":k[0]||(k[0]=_=>m.value=_),size:"small",style:{width:"110px"},options:[{value:"",label:"全部"},{value:"vllm",label:"vLLM"},{value:"sglang",label:"SGLang"}]},null,8,["value"]))]),t(R,{spinning:f.value},{default:a(()=>[t($,{size:"small",bordered:"","data-source":B.value},{renderItem:a(({item:_})=>[t(C,{style:{cursor:"pointer"},class:te({"record-selected":_.run_id===p.modelValue}),onClick:z=>s.$emit("update:modelValue",_.run_id)},{default:a(()=>[t(n,null,{title:a(()=>{var z;return[w("span",le,i(_.run_id),1),t(e,{size:"small",color:K((z=_.meta)==null?void 0:z.status),style:{"margin-left":"6px"}},{default:a(()=>{var h;return[v(i(A((h=_.meta)==null?void 0:h.status)),1)]}),_:2},1032,["color"])]}),description:a(()=>{var z,h,N;return[w("div",se,[w("div",null,i(((z=_.meta)==null?void 0:z.framework)||"-")+" · "+i(((h=_.meta)==null?void 0:h.model)||"-"),1),w("div",null,i(((N=_.meta)==null?void 0:N.started_at)||"")+" · "+i(_.files.length)+" 文件",1)])]}),_:2},1024)]),_:2},1032,["class","onClick"])]),empty:a(()=>[...k[2]||(k[2]=[w("div",{style:{padding:"12px",color:"#999"}},"暂无日志记录",-1)])]),_:1},8,["data-source"])]),_:1},8,["spinning"])])}}},ue=E(re,[["__scopeId","data-v-85fc4f26"]]),de={__name:"RunSummaryBlock",props:{records:{type:Array,default:()=>[]}},setup(p){const d=p,u=O(()=>d.records.map(l=>({label:l.label,concurrency:l.concurrency,metrics:{output_mean:l.output_mean,total_mean:l.total_mean,ttft_mean:l.ttft_mean,tpot_mean:l.tpot_mean,ttft_p99:l.ttft_p99,tpot_p99:l.tpot_p99}}))),r=[{key:"output_mean",label:"Output 吞吐 (tok/s)"},{key:"total_mean",label:"Total 吞吐 (tok/s)"},{key:"ttft_mean",label:"TTFT mean 耗时 (ms)"},{key:"tpot_mean",label:"TPOT mean 耗时 (ms)"},{key:"ttft_p99",label:"TTFT P99 耗时 (ms)"},{key:"tpot_p99",label:"TPOT P99 耗时 (ms)"}];return(l,o)=>(b(),S("div",null,[t(H,{rows:u.value,"metric-defs":r},null,8,["rows"])]))}},ie={style:{"margin-bottom":"8px",color:"#999","font-size":"12px"}},q={__name:"AnalysisBlock",props:{rows:{type:Array,default:()=>[]},best:{type:Object,default:()=>({})},threshold:{type:[Number,String],default:null}},setup(p){const d=p,u=[{key:"output_mean",label:"Output 吞吐 (tok/s)"},{key:"peakoutput_mean",label:"Peak Output 吞吐 (tok/s)"},{key:"total_mean",label:"Total 吞吐 (tok/s)"},{key:"ttft_mean",label:"TTFT mean 耗时 (ms)"},{key:"itl_mean",label:"ITL mean 耗时 (ms)"},{key:"tpot_mean",label:"TPOT mean 耗时 (ms)"}],r=O(()=>{const l={};for(const o of Object.keys(d.best||{})){const m=d.best[o];m&&m.row&&(l[`${o}-${m.concurrency}`]=!0)}return d.rows.map(o=>({label:o.label,concurrency:o.concurrency,best:!!l[`${o.label}-${o.concurrency}`],metrics:{output_mean:o.output,peakoutput_mean:o.peakoutput,total_mean:o.total,ttft_mean:o.ttft,tpot_mean:o.tpot,itl_mean:o.itl}}))});return(l,o)=>(b(),S("div",null,[w("div",ie,i(p.threshold?`TPOT 阈值 ${p.threshold}ms,金色行为最佳并发`:"未设置 TPOT 阈值"),1),t(ae,{rows:r.value,threshold:p.threshold,pagination:{pageSize:20,showSizeChanger:!0}},null,8,["rows","threshold"]),o[0]||(o[0]=w("div",{style:{"margin-top":"12px","font-weight":"600"}},"曲线(横轴:并发数)",-1)),t(H,{rows:r.value,"metric-defs":u},null,8,["rows"])]))}},ce={class:"run-detail"},me={style:{color:"#999","font-size":"12px","margin-bottom":"6px"}},pe={class:"preview-pre"},_e={__name:"RunDetailPanel",props:{runId:{type:String,default:""}},setup(p){const d=p,u=Y({records:[],records_mean:[],records_p99:[],best_mean:{},best_p99:{},threshold:null}),r=x({}),l=x([]),o=x("summary"),m=x(!1),T=x(""),f=Y({content:"",total_lines:0,truncated:0}),B=[{title:"文件名",dataIndex:"name",key:"name"},{title:"大小",dataIndex:"size",key:"size",width:110,customRender:({text:e})=>K(e)},{title:"操作",key:"actions",width:140}],j=O(()=>{var e;return((e=l.value.find(n=>n.name.endsWith(".xlsx")))==null?void 0:e.name)||""});function K(e){return e==null?"-":e>1024*1024?(e/1024/1024).toFixed(1)+" MB":e>1024?(e/1024).toFixed(1)+" KB":e+" B"}function A(e){return e==="done"?"green":e==="error"?"red":e==="stopped"?"orange":"blue"}function M(e){return e==="done"?"完成":e==="error"?"失败":e==="stopped"?"已停止":"运行中"}async function s(){if(d.runId)try{const[e,n]=await Promise.all([F.runSummary(d.runId),F.getRun(d.runId).catch(()=>null)]);Object.assign(u,e),r.value=e.meta||{},l.value=((n==null?void 0:n.files)||[]).map(C=>({name:C[0],size:C[1]}))}catch(e){W.error(e.message)}}async function k(e){T.value=e,f.content="";try{const n=await F.previewFile(d.runId,e);f.content=n.content,f.total_lines=n.total_lines,f.truncated=n.truncated,m.value=!0}catch(n){W.error(n.message)}}function g(e){if(!e){W.warning("该运行暂无 xlsx 汇总(可能没有成功记录)");return}window.open(F.downloadUrl(d.runId,e),"_blank")}return G(()=>d.runId,()=>s(),{immediate:!0}),(e,n)=>{const C=c("a-empty"),$=c("a-tag"),R=c("a-button"),_=c("a-space"),z=c("a-card"),h=c("a-tab-pane"),N=c("a-table"),J=c("a-modal"),Q=c("a-tabs");return b(),S("div",ce,[p.runId?(b(),S(X,{key:1},[t(z,{size:"small",class:"detail-meta",bordered:!0},{default:a(()=>[t(_,{wrap:""},{default:a(()=>{var I,P,U;return[t($,{color:"blue"},{default:a(()=>{var y,V;return[v(i(((y=u.meta)==null?void 0:y.framework_name)||((V=r.value)==null?void 0:V.framework)||"-"),1)]}),_:1}),t($,null,{default:a(()=>{var y,V;return[v(i(((y=u.meta)==null?void 0:y.model)||((V=r.value)==null?void 0:V.model)||"-"),1)]}),_:1}),(I=r.value)!=null&&I.gpu?(b(),L($,{key:0},{default:a(()=>[v("GPU: "+i(r.value.gpu),1)]),_:1})):D("",!0),(P=r.value)!=null&&P.precision?(b(),L($,{key:1},{default:a(()=>[v("精度: "+i(r.value.precision),1)]),_:1})):D("",!0),t($,null,{default:a(()=>{var y,V;return[v(i(((y=r.value)==null?void 0:y.started_at)||"")+" → "+i(((V=r.value)==null?void 0:V.finished_at)||""),1)]}),_:1}),t($,{color:A((U=r.value)==null?void 0:U.status)},{default:a(()=>{var y;return[v(i(M((y=r.value)==null?void 0:y.status)),1)]}),_:1},8,["color"]),t(R,{size:"small",type:"primary",ghost:"",onClick:n[0]||(n[0]=y=>g(j.value))},{default:a(()=>[...n[3]||(n[3]=[v("下载 xlsx 汇总",-1)])]),_:1}),t(R,{size:"small",onClick:s},{default:a(()=>[...n[4]||(n[4]=[v("刷新",-1)])]),_:1})]}),_:1})]),_:1}),t(Q,{activeKey:o.value,"onUpdate:activeKey":n[2]||(n[2]=I=>o.value=I),class:"detail-tabs"},{default:a(()=>[t(h,{key:"summary",tab:"指标汇总"},{default:a(()=>[t(de,{records:u.records||[]},null,8,["records"])]),_:1}),t(h,{key:"mean",tab:"均值分析 Mean"},{default:a(()=>[t(q,{rows:u.records_mean||[],best:u.best_mean||{},threshold:u.threshold},null,8,["rows","best","threshold"])]),_:1}),t(h,{key:"p99",tab:"P99 分析"},{default:a(()=>[t(q,{rows:u.records_p99||[],best:u.best_p99||{},threshold:u.threshold},null,8,["rows","best","threshold"])]),_:1}),t(h,{key:"files",tab:"日志文件"},{default:a(()=>[t(N,{columns:B,"data-source":l.value,size:"small",pagination:!1,"row-key":"name"},{bodyCell:a(({column:I,record:P})=>[I.key==="actions"?(b(),S(X,{key:0},[t(R,{size:"small",type:"link",onClick:U=>k(P.name)},{default:a(()=>[...n[5]||(n[5]=[v("预览",-1)])]),_:1},8,["onClick"]),t(R,{size:"small",type:"link",onClick:U=>g(P.name)},{default:a(()=>[...n[6]||(n[6]=[v("下载",-1)])]),_:1},8,["onClick"])],64)):D("",!0)]),_:1},8,["data-source"]),t(J,{open:m.value,"onUpdate:open":n[1]||(n[1]=I=>m.value=I),title:`预览:${T.value}`,width:"900px",footer:null},{default:a(()=>[w("div",me," 共 "+i(f.total_lines)+" 行,显示末尾 "+i(f.truncated>0?`(省略前 ${f.truncated} 行)`:"全部"),1),w("pre",pe,i(f.content),1)]),_:1},8,["open","title"])]),_:1})]),_:1},8,["activeKey"])],64)):(b(),L(C,{key:0,description:"请选择左侧测试记录",style:{"padding-top":"80px"}}))])}}},fe=E(_e,[["__scopeId","data-v-53d908f7"]]),ye={__name:"LogView",setup(p){const d=x("");return(u,r)=>{const l=c("a-layout-sider"),o=c("a-layout-content"),m=c("a-layout");return b(),L(m,{class:"page-layout"},{default:a(()=>[t(l,{width:"260",theme:"light",class:"record-sider"},{default:a(()=>[t(ue,{modelValue:d.value,"onUpdate:modelValue":r[0]||(r[0]=T=>d.value=T),framework:""},null,8,["modelValue"])]),_:1}),t(o,{class:"page-content"},{default:a(()=>[t(fe,{"run-id":d.value},null,8,["run-id"])]),_:1})]),_:1})}}},he=E(ye,[["__scopeId","data-v-8fab23f1"]]);export{he as default};
1
+ import{_ as E,b as Z,a as F}from"./index-CzYL8dyk.js";import{f as x,w as G,o as ee,S as c,U as b,a6 as S,X as w,V as L,W as a,G as v,_ as d,k as t,Y as te,c as O,F as X,a8 as D,r as Y}from"./vue-Ch4zjUb1.js";import{M as H,_ as ae}from"./MetricsCharts-BKjshnuj.js";import{i as W}from"./antd-CmFZS0N1.js";import"./echarts-Bb6yjXMn.js";const ne={class:"record-list"},oe={class:"record-head"},le={style:{"font-weight":"600","font-size":"13px"}},se={style:{"font-size":"12px","line-height":"1.6"}},re={__name:"RunRecordList",props:{modelValue:{type:String,default:""},framework:{type:String,default:""}},emits:["update:modelValue"],setup(p,{emit:i}){const u=p,r=i,l=Z(),o=O(()=>u.framework),m=x(u.framework||""),T=x([]),f=x(!1),B=O(()=>{const s=o.value||m.value;if(!s)return T.value;const k=s==="vllm"?"vLLM":"SGLang";return T.value.filter(g=>{var e;return(((e=g.meta)==null?void 0:e.framework)||"")===k})});function K(s){return s==="vllm"?"vLLM":"SGLang"}function j(s){return s==="done"?"green":s==="error"?"red":s==="stopped"?"orange":"blue"}function A(s){return s==="done"?"完成":s==="error"?"失败":s==="stopped"?"已停止":"运行中"}async function M(){f.value=!0;try{const s=await F.listRuns();T.value=s.runs||[]}finally{f.value=!1}}return G(B,s=>{if(!s.length){u.modelValue&&r("update:modelValue","");return}if(!(u.modelValue&&s.some(g=>g.run_id===u.modelValue))){const g=l.lastRunId&&s.some(e=>e.run_id===l.lastRunId)?l.lastRunId:s[0].run_id;r("update:modelValue",g)}},{immediate:!0}),G(()=>l.lastRunId,M),G(m,()=>{}),ee(M),(s,k)=>{const g=c("a-select"),e=c("a-tag"),n=c("a-list-item-meta"),C=c("a-list-item"),$=c("a-list"),R=c("a-spin");return b(),S("div",ne,[w("div",oe,[k[1]||(k[1]=w("span",{class:"record-title"},"测试记录",-1)),o.value?(b(),L(e,{key:1,size:"small",color:"blue"},{default:a(()=>[v(d(K(o.value)),1)]),_:1})):(b(),L(g,{key:0,value:m.value,"onUpdate:value":k[0]||(k[0]=_=>m.value=_),size:"small",style:{width:"110px"},options:[{value:"",label:"全部"},{value:"vllm",label:"vLLM"},{value:"sglang",label:"SGLang"}]},null,8,["value"]))]),t(R,{spinning:f.value},{default:a(()=>[t($,{size:"small",bordered:"","data-source":B.value},{renderItem:a(({item:_})=>[t(C,{style:{cursor:"pointer"},class:te({"record-selected":_.run_id===p.modelValue}),onClick:z=>s.$emit("update:modelValue",_.run_id)},{default:a(()=>[t(n,null,{title:a(()=>{var z;return[w("span",le,d(_.run_id),1),t(e,{size:"small",color:j((z=_.meta)==null?void 0:z.status),style:{"margin-left":"6px"}},{default:a(()=>{var h;return[v(d(A((h=_.meta)==null?void 0:h.status)),1)]}),_:2},1032,["color"])]}),description:a(()=>{var z,h,N;return[w("div",se,[w("div",null,d(((z=_.meta)==null?void 0:z.framework)||"-")+" · "+d(((h=_.meta)==null?void 0:h.model)||"-"),1),w("div",null,d(((N=_.meta)==null?void 0:N.started_at)||"")+" · "+d(_.files.length)+" 文件",1)])]}),_:2},1024)]),_:2},1032,["class","onClick"])]),empty:a(()=>[...k[2]||(k[2]=[w("div",{style:{padding:"12px",color:"#999"}},"暂无日志记录",-1)])]),_:1},8,["data-source"])]),_:1},8,["spinning"])])}}},ue=E(re,[["__scopeId","data-v-85fc4f26"]]),ie={__name:"RunSummaryBlock",props:{records:{type:Array,default:()=>[]}},setup(p){const i=p,u=O(()=>i.records.map(l=>({label:l.label,concurrency:l.concurrency,metrics:{output_mean:l.output_mean,total_mean:l.total_mean,ttft_mean:l.ttft_mean,tpot_mean:l.tpot_mean,ttft_p99:l.ttft_p99,tpot_p99:l.tpot_p99}}))),r=[{key:"output_mean",label:"Output 吞吐 (tok/s)"},{key:"total_mean",label:"Total 吞吐 (tok/s)"},{key:"ttft_mean",label:"TTFT mean 耗时 (ms)"},{key:"tpot_mean",label:"TPOT mean 耗时 (ms)"},{key:"ttft_p99",label:"TTFT P99 耗时 (ms)"},{key:"tpot_p99",label:"TPOT P99 耗时 (ms)"}];return(l,o)=>(b(),S("div",null,[t(H,{rows:u.value,"metric-defs":r},null,8,["rows"])]))}},de={style:{"margin-bottom":"8px",color:"#999","font-size":"12px"}},q={__name:"AnalysisBlock",props:{rows:{type:Array,default:()=>[]},best:{type:Object,default:()=>({})},threshold:{type:[Number,String],default:null}},setup(p){const i=p,u=[{key:"output_mean",label:"Output 吞吐 (tok/s)"},{key:"peakoutput_mean",label:"Peak Output 吞吐 (tok/s)"},{key:"total_mean",label:"Total 吞吐 (tok/s)"},{key:"ttft_mean",label:"TTFT mean 耗时 (ms)"},{key:"itl_mean",label:"ITL mean 耗时 (ms)"},{key:"tpot_mean",label:"TPOT mean 耗时 (ms)"}],r=O(()=>{const l={};for(const o of Object.keys(i.best||{})){const m=i.best[o];m&&m.row&&(l[`${o}-${m.concurrency}`]=!0)}return i.rows.map(o=>({label:o.label,concurrency:o.concurrency,best:!!l[`${o.label}-${o.concurrency}`],metrics:{output_mean:o.output,peakoutput_mean:o.peakoutput,total_mean:o.total,ttft_mean:o.ttft,tpot_mean:o.tpot,itl_mean:o.itl}}))});return(l,o)=>(b(),S("div",null,[w("div",de,d(p.threshold?`TPOT 阈值 ${p.threshold}ms,金色行为最佳并发`:"未设置 TPOT 阈值"),1),t(ae,{rows:r.value,threshold:p.threshold,pagination:{pageSize:20,showSizeChanger:!0}},null,8,["rows","threshold"]),o[0]||(o[0]=w("div",{style:{"margin-top":"12px","font-weight":"600"}},"曲线(横轴:并发数)",-1)),t(H,{rows:r.value,"metric-defs":u},null,8,["rows"])]))}},ce={class:"run-detail"},me={style:{color:"#999","font-size":"12px","margin-bottom":"6px"}},pe={class:"preview-pre"},_e={__name:"RunDetailPanel",props:{runId:{type:String,default:""}},setup(p){const i=p,u=Y({records:[],records_mean:[],records_p99:[],best_mean:{},best_p99:{},threshold:null}),r=x({}),l=x([]),o=x("summary"),m=x(!1),T=x(""),f=Y({content:"",total_lines:0,truncated:0}),B=[{title:"文件名",dataIndex:"name",key:"name"},{title:"大小",dataIndex:"size",key:"size",width:110,customRender:({text:e})=>j(e)},{title:"操作",key:"actions",width:140}],K=O(()=>{var e;return((e=l.value.find(n=>n.name.endsWith(".xlsx")))==null?void 0:e.name)||""});function j(e){return e==null?"-":e>1024*1024?(e/1024/1024).toFixed(1)+" MB":e>1024?(e/1024).toFixed(1)+" KB":e+" B"}function A(e){return e==="done"?"green":e==="error"?"red":e==="stopped"?"orange":"blue"}function M(e){return e==="done"?"完成":e==="error"?"失败":e==="stopped"?"已停止":"运行中"}async function s(){if(i.runId)try{const[e,n]=await Promise.all([F.runSummary(i.runId),F.getRun(i.runId).catch(()=>null)]);Object.assign(u,e),r.value=e.meta||{},l.value=((n==null?void 0:n.files)||[]).map(C=>({name:C[0],size:C[1]}))}catch(e){W.error(e.message)}}async function k(e){T.value=e,f.content="";try{const n=await F.previewFile(i.runId,e);f.content=n.content,f.total_lines=n.total_lines,f.truncated=n.truncated,m.value=!0}catch(n){W.error(n.message)}}function g(e){if(!e){W.warning("该运行暂无 xlsx 汇总(可能没有成功记录)");return}window.open(F.downloadUrl(i.runId,e),"_blank")}return G(()=>i.runId,()=>s(),{immediate:!0}),(e,n)=>{const C=c("a-empty"),$=c("a-tag"),R=c("a-button"),_=c("a-space"),z=c("a-card"),h=c("a-tab-pane"),N=c("a-table"),J=c("a-modal"),Q=c("a-tabs");return b(),S("div",ce,[p.runId?(b(),S(X,{key:1},[t(z,{size:"small",class:"detail-meta",bordered:!0},{default:a(()=>[t(_,{wrap:""},{default:a(()=>{var I,P,U;return[t($,{color:"blue"},{default:a(()=>{var y,V;return[v(d(((y=u.meta)==null?void 0:y.framework_name)||((V=r.value)==null?void 0:V.framework)||"-"),1)]}),_:1}),t($,null,{default:a(()=>{var y,V;return[v(d(((y=u.meta)==null?void 0:y.model)||((V=r.value)==null?void 0:V.model)||"-"),1)]}),_:1}),(I=r.value)!=null&&I.gpu?(b(),L($,{key:0},{default:a(()=>[v("GPU: "+d(r.value.gpu),1)]),_:1})):D("",!0),(P=r.value)!=null&&P.precision?(b(),L($,{key:1},{default:a(()=>[v("精度: "+d(r.value.precision),1)]),_:1})):D("",!0),t($,null,{default:a(()=>{var y,V;return[v(d(((y=r.value)==null?void 0:y.started_at)||"")+" → "+d(((V=r.value)==null?void 0:V.finished_at)||""),1)]}),_:1}),t($,{color:A((U=r.value)==null?void 0:U.status)},{default:a(()=>{var y;return[v(d(M((y=r.value)==null?void 0:y.status)),1)]}),_:1},8,["color"]),t(R,{size:"small",type:"primary",ghost:"",onClick:n[0]||(n[0]=y=>g(K.value))},{default:a(()=>[...n[3]||(n[3]=[v("下载 xlsx 汇总",-1)])]),_:1}),t(R,{size:"small",onClick:s},{default:a(()=>[...n[4]||(n[4]=[v("刷新",-1)])]),_:1})]}),_:1})]),_:1}),t(Q,{activeKey:o.value,"onUpdate:activeKey":n[2]||(n[2]=I=>o.value=I),class:"detail-tabs"},{default:a(()=>[t(h,{key:"summary",tab:"指标汇总"},{default:a(()=>[t(ie,{records:u.records||[]},null,8,["records"])]),_:1}),t(h,{key:"mean",tab:"均值分析 Mean"},{default:a(()=>[t(q,{rows:u.records_mean||[],best:u.best_mean||{},threshold:u.threshold},null,8,["rows","best","threshold"])]),_:1}),t(h,{key:"p99",tab:"P99 分析"},{default:a(()=>[t(q,{rows:u.records_p99||[],best:u.best_p99||{},threshold:u.threshold},null,8,["rows","best","threshold"])]),_:1}),t(h,{key:"files",tab:"日志文件"},{default:a(()=>[t(N,{columns:B,"data-source":l.value,size:"small",pagination:!1,"row-key":"name"},{bodyCell:a(({column:I,record:P})=>[I.key==="actions"?(b(),S(X,{key:0},[t(R,{size:"small",type:"link",onClick:U=>k(P.name)},{default:a(()=>[...n[5]||(n[5]=[v("预览",-1)])]),_:1},8,["onClick"]),t(R,{size:"small",type:"link",onClick:U=>g(P.name)},{default:a(()=>[...n[6]||(n[6]=[v("下载",-1)])]),_:1},8,["onClick"])],64)):D("",!0)]),_:1},8,["data-source"]),t(J,{open:m.value,"onUpdate:open":n[1]||(n[1]=I=>m.value=I),title:`预览:${T.value}`,width:"900px",footer:null},{default:a(()=>[w("div",me," 共 "+d(f.total_lines)+" 行,显示末尾 "+d(f.truncated>0?`(省略前 ${f.truncated} 行)`:"全部"),1),w("pre",pe,d(f.content),1)]),_:1},8,["open","title"])]),_:1})]),_:1},8,["activeKey"])],64)):(b(),L(C,{key:0,description:"请选择左侧测试记录",style:{"padding-top":"80px"}}))])}}},fe=E(_e,[["__scopeId","data-v-53d908f7"]]),ye={__name:"LogView",setup(p){const i=x("");return(u,r)=>{const l=c("a-layout-sider"),o=c("a-layout-content"),m=c("a-layout");return b(),L(m,{class:"page-layout"},{default:a(()=>[t(l,{width:"260",theme:"light",class:"record-sider"},{default:a(()=>[t(ue,{modelValue:i.value,"onUpdate:modelValue":r[0]||(r[0]=T=>i.value=T),framework:""},null,8,["modelValue"])]),_:1}),t(o,{class:"page-content"},{default:a(()=>[t(fe,{"run-id":i.value},null,8,["run-id"])]),_:1})]),_:1})}}},he=E(ye,[["__scopeId","data-v-8fab23f1"]]);export{he as default};
@@ -1 +1 @@
1
- import{S as g,U as a,V as p,W as y,a6 as b,_ as k,F as T,G as x,a8 as v,c as R,w as z,o as C,j as O,a7 as N,X as S,a9 as I}from"./vue-Ch4zjUb1.js";import{i as P}from"./echarts-Bb6yjXMn.js";import{_ as F}from"./index-DYReb9-e.js";const L={key:0,style:{fontWeight:600}},A={key:0,style:{color:"#999","font-size":"12px"}},E={__name:"MetricsTable",props:{rows:{type:Array,default:()=>[]},threshold:{type:Number,default:null},pagination:{type:[Boolean,Object],default:!1}},setup(d){const m=d,c=R(()=>[{title:"用例 Case",key:"label",width:180,fixed:"left"},{title:"并发数 Concurrency",key:"concurrency",width:110,fixed:"left"},{title:"Output 吞吐 Output tok/s",dataIndex:["metrics","output_mean"],key:"output",width:130,customRender:s},{title:"Peak Output 吞吐 Peak tok/s",dataIndex:["metrics","peakoutput_mean"],key:"peak",width:140,customRender:s},{title:"Total 吞吐 Total tok/s",dataIndex:["metrics","total_mean"],key:"total",width:130,customRender:s},{title:"TTFT mean (ms)",dataIndex:["metrics","ttft_mean"],key:"ttft_mean",width:120,customRender:s},{title:"TPOT mean (ms)",dataIndex:["metrics","tpot_mean"],key:"tpot_mean",width:120,customRender:s},{title:"ITL mean (ms)",dataIndex:["metrics","itl_mean"],key:"itl_mean",width:120,customRender:s},{title:"TTFT P99 (ms)",dataIndex:["metrics","ttft_p99"],key:"ttft_p99",width:120,customRender:s},{title:"TPOT P99 (ms)",dataIndex:["metrics","tpot_p99"],key:"tpot_p99",width:120,customRender:s},{title:"ITL P99 (ms)",dataIndex:["metrics","itl_p99"],key:"itl_p99",width:120,customRender:s},{title:"单用户 QPS (1000/TPOT)",key:"single_user",width:150,customRender:w},{title:"状态 Status",key:"status",width:90,fixed:"right"}]);function s({text:n}){return n==null?"-":Number(n).toFixed(2)}function w({record:n}){var o;const e=(o=n.metrics)==null?void 0:o.single_user;return e==null?"-":Number(e).toFixed(2)}function h(n){return`${n.label||n.case||""}-${n.concurrency}`}function r(n){var o;if(n.error)return"row-error";if(n.best)return"row-best";const e=(o=n.metrics)==null?void 0:o.tpot_mean;return e!=null&&m.threshold&&Number(e)<Number(m.threshold)?"row-near-threshold":""}return(n,e)=>{const o=g("a-tag"),u=g("a-table");return a(),p(u,{columns:c.value,"data-source":d.rows,"row-key":h,pagination:d.pagination,size:"small",scroll:{x:1400},"row-class-name":r,bordered:""},{bodyCell:y(({column:i,record:t})=>[i.key==="concurrency"?(a(),b("span",L,k(t.concurrency),1)):i.key==="status"?(a(),b(T,{key:1},[t.error?(a(),p(o,{key:0,color:"red"},{default:y(()=>[...e[0]||(e[0]=[x("失败",-1)])]),_:1})):t.best?(a(),p(o,{key:1,color:"gold"},{default:y(()=>[...e[1]||(e[1]=[x("最佳",-1)])]),_:1})):(a(),p(o,{key:2,color:"green"},{default:y(()=>[...e[2]||(e[2]=[x("成功",-1)])]),_:1}))],64)):i.key==="label"?(a(),b(T,{key:2},[x(k(t.label)+" ",1),t.input_len?(a(),b("span",A," ("+k(t.input_len)+"/"+k(t.output_len)+") ",1)):v("",!0)],64)):v("",!0)]),_:1},8,["columns","data-source","pagination"])}}},B={class:"chart-title"},D="260px",M={__name:"MetricsCharts",props:{rows:{type:Array,default:()=>[]},metricDefs:{type:Array,default:()=>[]},height:{type:String,default:"300px"}},setup(d){const m=d,c={},s=[];function w(r,n){n&&(c[r]||(c[r]=P(n),s.push(new ResizeObserver(()=>c[r]&&c[r].resize())),s[s.length-1].observe(n)))}function h(){for(const r of m.metricDefs){const n=c[r.key];if(!n)continue;const e={};for(const t of m.rows){const l=t.metrics||{},f=r.value?r.value(l):l[r.key];if(f==null)continue;const _=t.label||t.case||"unknown";e[_]||(e[_]=[]),e[_].push({concurrency:t.concurrency,value:Number(f)})}const o=Object.keys(e),u={color:["#1677ff","#52c41a","#faad14","#f5222d","#13c2c2","#722ed1","#eb2f96","#fa8c16"],tooltip:{trigger:"axis",backgroundColor:"rgba(255,255,255,0.96)",borderColor:"#f0f0f0",textStyle:{color:"rgba(0,0,0,0.88)",fontSize:12},valueFormatter:t=>t==null?"-":Number(t).toFixed(2)},legend:o.length>1?{data:o,type:"scroll",top:0,textStyle:{fontSize:12}}:void 0,grid:{left:54,right:16,top:o.length>1?32:20,bottom:28},xAxis:{type:"category",name:"并发数",nameTextStyle:{fontSize:11,color:"rgba(0,0,0,0.45)"},axisLine:{lineStyle:{color:"#d9d9d9"}},axisLabel:{fontSize:11}},yAxis:{type:"value",scale:!0,splitLine:{lineStyle:{type:"dashed",color:"#f0f0f0"}},axisLabel:{fontSize:11}},series:o.map(t=>{const l=e[t].sort((f,_)=>f.concurrency-_.concurrency);return{name:t,type:"line",smooth:!0,symbol:"circle",symbolSize:6,lineStyle:{width:2},data:l.map(f=>f.value),markPoint:{data:[{type:"max",name:"峰值"}],symbolSize:44,label:{fontSize:10}}}})},i=[];for(const t of o)for(const l of e[t])i.includes(l.concurrency)||i.push(l.concurrency);u.xAxis.data=i.sort((t,l)=>t-l),n.setOption(u,!0)}}return z(()=>m.rows,h,{deep:!0}),z(()=>m.metricDefs,h,{deep:!0}),C(h),O(()=>{s.forEach(r=>r.disconnect()),Object.values(c).forEach(r=>r.dispose())}),(r,n)=>{const e=g("a-col"),o=g("a-row");return a(),p(o,{gutter:12},{default:y(()=>[(a(!0),b(T,null,N(d.metricDefs,u=>(a(),p(e,{key:u.key,xs:24,sm:12,lg:8,style:{"margin-bottom":"12px"}},{default:y(()=>[S("div",{style:I({height:d.height,width:"100%"})},[S("div",B,k(u.label),1),S("div",{ref_for:!0,ref:i=>w(u.key,i),style:I({height:D,width:"100%"})},null,4)],4)]),_:2},1024))),128))]),_:1})}}},U=F(M,[["__scopeId","data-v-99455d6f"]]);export{U as M,E as _};
1
+ import{S as g,U as a,V as p,W as y,a6 as b,_ as k,F as T,G as x,a8 as v,c as R,w as z,o as C,j as O,a7 as N,X as S,a9 as I}from"./vue-Ch4zjUb1.js";import{i as P}from"./echarts-Bb6yjXMn.js";import{_ as F}from"./index-CzYL8dyk.js";const L={key:0,style:{fontWeight:600}},A={key:0,style:{color:"#999","font-size":"12px"}},E={__name:"MetricsTable",props:{rows:{type:Array,default:()=>[]},threshold:{type:Number,default:null},pagination:{type:[Boolean,Object],default:!1}},setup(d){const m=d,c=R(()=>[{title:"用例 Case",key:"label",width:180,fixed:"left"},{title:"并发数 Concurrency",key:"concurrency",width:110,fixed:"left"},{title:"Output 吞吐 Output tok/s",dataIndex:["metrics","output_mean"],key:"output",width:130,customRender:s},{title:"Peak Output 吞吐 Peak tok/s",dataIndex:["metrics","peakoutput_mean"],key:"peak",width:140,customRender:s},{title:"Total 吞吐 Total tok/s",dataIndex:["metrics","total_mean"],key:"total",width:130,customRender:s},{title:"TTFT mean (ms)",dataIndex:["metrics","ttft_mean"],key:"ttft_mean",width:120,customRender:s},{title:"TPOT mean (ms)",dataIndex:["metrics","tpot_mean"],key:"tpot_mean",width:120,customRender:s},{title:"ITL mean (ms)",dataIndex:["metrics","itl_mean"],key:"itl_mean",width:120,customRender:s},{title:"TTFT P99 (ms)",dataIndex:["metrics","ttft_p99"],key:"ttft_p99",width:120,customRender:s},{title:"TPOT P99 (ms)",dataIndex:["metrics","tpot_p99"],key:"tpot_p99",width:120,customRender:s},{title:"ITL P99 (ms)",dataIndex:["metrics","itl_p99"],key:"itl_p99",width:120,customRender:s},{title:"单用户 QPS (1000/TPOT)",key:"single_user",width:150,customRender:w},{title:"状态 Status",key:"status",width:90,fixed:"right"}]);function s({text:n}){return n==null?"-":Number(n).toFixed(2)}function w({record:n}){var o;const e=(o=n.metrics)==null?void 0:o.single_user;return e==null?"-":Number(e).toFixed(2)}function h(n){return`${n.label||n.case||""}-${n.concurrency}`}function r(n){var o;if(n.error)return"row-error";if(n.best)return"row-best";const e=(o=n.metrics)==null?void 0:o.tpot_mean;return e!=null&&m.threshold&&Number(e)<Number(m.threshold)?"row-near-threshold":""}return(n,e)=>{const o=g("a-tag"),u=g("a-table");return a(),p(u,{columns:c.value,"data-source":d.rows,"row-key":h,pagination:d.pagination,size:"small",scroll:{x:1400},"row-class-name":r,bordered:""},{bodyCell:y(({column:i,record:t})=>[i.key==="concurrency"?(a(),b("span",L,k(t.concurrency),1)):i.key==="status"?(a(),b(T,{key:1},[t.error?(a(),p(o,{key:0,color:"red"},{default:y(()=>[...e[0]||(e[0]=[x("失败",-1)])]),_:1})):t.best?(a(),p(o,{key:1,color:"gold"},{default:y(()=>[...e[1]||(e[1]=[x("最佳",-1)])]),_:1})):(a(),p(o,{key:2,color:"green"},{default:y(()=>[...e[2]||(e[2]=[x("成功",-1)])]),_:1}))],64)):i.key==="label"?(a(),b(T,{key:2},[x(k(t.label)+" ",1),t.input_len?(a(),b("span",A," ("+k(t.input_len)+"/"+k(t.output_len)+") ",1)):v("",!0)],64)):v("",!0)]),_:1},8,["columns","data-source","pagination"])}}},B={class:"chart-title"},D="260px",M={__name:"MetricsCharts",props:{rows:{type:Array,default:()=>[]},metricDefs:{type:Array,default:()=>[]},height:{type:String,default:"300px"}},setup(d){const m=d,c={},s=[];function w(r,n){n&&(c[r]||(c[r]=P(n),s.push(new ResizeObserver(()=>c[r]&&c[r].resize())),s[s.length-1].observe(n)))}function h(){for(const r of m.metricDefs){const n=c[r.key];if(!n)continue;const e={};for(const t of m.rows){const l=t.metrics||{},f=r.value?r.value(l):l[r.key];if(f==null)continue;const _=t.label||t.case||"unknown";e[_]||(e[_]=[]),e[_].push({concurrency:t.concurrency,value:Number(f)})}const o=Object.keys(e),u={color:["#1677ff","#52c41a","#faad14","#f5222d","#13c2c2","#722ed1","#eb2f96","#fa8c16"],tooltip:{trigger:"axis",backgroundColor:"rgba(255,255,255,0.96)",borderColor:"#f0f0f0",textStyle:{color:"rgba(0,0,0,0.88)",fontSize:12},valueFormatter:t=>t==null?"-":Number(t).toFixed(2)},legend:o.length>1?{data:o,type:"scroll",top:0,textStyle:{fontSize:12}}:void 0,grid:{left:54,right:16,top:o.length>1?32:20,bottom:28},xAxis:{type:"category",name:"并发数",nameTextStyle:{fontSize:11,color:"rgba(0,0,0,0.45)"},axisLine:{lineStyle:{color:"#d9d9d9"}},axisLabel:{fontSize:11}},yAxis:{type:"value",scale:!0,splitLine:{lineStyle:{type:"dashed",color:"#f0f0f0"}},axisLabel:{fontSize:11}},series:o.map(t=>{const l=e[t].sort((f,_)=>f.concurrency-_.concurrency);return{name:t,type:"line",smooth:!0,symbol:"circle",symbolSize:6,lineStyle:{width:2},data:l.map(f=>f.value),markPoint:{data:[{type:"max",name:"峰值"}],symbolSize:44,label:{fontSize:10}}}})},i=[];for(const t of o)for(const l of e[t])i.includes(l.concurrency)||i.push(l.concurrency);u.xAxis.data=i.sort((t,l)=>t-l),n.setOption(u,!0)}}return z(()=>m.rows,h,{deep:!0}),z(()=>m.metricDefs,h,{deep:!0}),C(h),O(()=>{s.forEach(r=>r.disconnect()),Object.values(c).forEach(r=>r.dispose())}),(r,n)=>{const e=g("a-col"),o=g("a-row");return a(),p(o,{gutter:12},{default:y(()=>[(a(!0),b(T,null,N(d.metricDefs,u=>(a(),p(e,{key:u.key,xs:24,sm:12,lg:8,style:{"margin-bottom":"12px"}},{default:y(()=>[S("div",{style:I({height:d.height,width:"100%"})},[S("div",B,k(u.label),1),S("div",{ref_for:!0,ref:i=>w(u.key,i),style:I({height:D,width:"100%"})},null,4)],4)]),_:2},1024))),128))]),_:1})}}},U=F(M,[["__scopeId","data-v-99455d6f"]]);export{U as M,E as _};
@@ -1 +1 @@
1
- import{_ as F,u as H,a as K}from"./index-DYReb9-e.js";import{i as j,t as W,u as Q,v as Y,j as I}from"./antd-DWALckI0.js";import{o as Z,V as ee,W as t,f as k,r as ae,S as r,U as h,k as e,u as w,G as p,a6 as V,_ as x,a8 as E,X as te}from"./vue-Ch4zjUb1.js";const le={key:0,style:{"margin-right":"12px"}},ne={key:0},oe={key:1,style:{color:"#999"}},se={key:0,style:{color:"#999","font-size":"12px","margin-top":"4px"}},ue={__name:"SettingsView",setup(re){const o=H(),A=k(!1),B=k(!1),_=k(null),U=k(null),l=ae({framework:"vllm",api:{base_url:"",endpoint:"/v1/chat/completions",api_key:"",extra_headers:{}},gpu:{auto:!0,name:"",count:8},logs_dir:"./logs",datasets_dir:"./datasets",tpot_threshold_ms:100,request_rate:"inf",bench_commands:{vllm:"vllm bench serve",sglang:"python -m sglang.bench_serving"}}),v=k("{}");Z(async()=>{var d,a,g,m,c,S,s,u,i,f,O,C,N,b,y,q,L,P,G,n,J,z,D,T,M,R;A.value=!0;try{await o.load(),Object.assign(l,{framework:((d=o.config)==null?void 0:d.framework)||"vllm",api:{base_url:((g=(a=o.config)==null?void 0:a.api)==null?void 0:g.base_url)||"",endpoint:((c=(m=o.config)==null?void 0:m.api)==null?void 0:c.endpoint)||"/v1/chat/completions",api_key:((s=(S=o.config)==null?void 0:S.api)==null?void 0:s.api_key)||"",extra_headers:((i=(u=o.config)==null?void 0:u.api)==null?void 0:i.extra_headers)||{}},gpu:{auto:((O=(f=o.config)==null?void 0:f.gpu)==null?void 0:O.auto)??!0,name:((N=(C=o.config)==null?void 0:C.gpu)==null?void 0:N.name)||"",count:((y=(b=o.config)==null?void 0:b.gpu)==null?void 0:y.count)||8},logs_dir:((q=o.config)==null?void 0:q.logs_dir)||"./logs",datasets_dir:((L=o.config)==null?void 0:L.datasets_dir)||"./datasets",tpot_threshold_ms:((P=o.config)==null?void 0:P.tpot_threshold_ms)??100,request_rate:((G=o.config)==null?void 0:G.request_rate)||"inf",bench_commands:{vllm:((J=(n=o.config)==null?void 0:n.bench_commands)==null?void 0:J.vllm)||"vllm bench serve",sglang:((D=(z=o.config)==null?void 0:z.bench_commands)==null?void 0:D.sglang)||"python -m sglang.bench_serving"}}),v.value=JSON.stringify(((M=(T=o.config)==null?void 0:T.api)==null?void 0:M.extra_headers)||{},null,2),(R=o.gpu)!=null&&R.auto_detected&&(U.value=o.gpu.auto_detected)}finally{A.value=!1}});async function X(){B.value=!0,_.value=null;try{let d={};try{d=JSON.parse(v.value||"{}")}catch{I.error("额外请求头不是合法 JSON");return}_.value=await K.testConnection({base_url:l.api.base_url,endpoint:l.api.endpoint,api_key:l.api.api_key,extra_headers:d})}finally{B.value=!1}}async function $(){try{let d={};try{d=JSON.parse(v.value||"{}")}catch{I.error("额外请求头不是合法 JSON");return}const a={framework:l.framework,api:{...l.api,extra_headers:d},gpu:l.gpu,logs_dir:l.logs_dir,datasets_dir:l.datasets_dir,tpot_threshold_ms:l.tpot_threshold_ms,request_rate:l.request_rate,bench_commands:l.bench_commands};await o.save(a),I.success("配置已保存"),o.refreshStatus()}catch(d){I.error(`保存失败:${d.message}`)}}return(d,a)=>{const g=r("a-button"),m=r("a-divider"),c=r("a-radio-button"),S=r("a-radio-group"),s=r("a-form-item"),u=r("a-col"),i=r("a-input"),f=r("a-row"),O=r("a-input-password"),C=r("a-tag"),N=r("a-switch"),b=r("a-input-number"),y=r("a-select-option"),q=r("a-select"),L=r("a-form"),P=r("a-spin"),G=r("a-card");return h(),ee(G,{size:"small",class:"panel",title:"服务设置 Service Settings"},{extra:t(()=>[e(g,{type:"link",size:"small",loading:B.value,onClick:X},{icon:t(()=>[e(w(j))]),default:t(()=>[a[14]||(a[14]=p(" 测试连接 ",-1))]),_:1},8,["loading"])]),default:t(()=>[e(P,{spinning:A.value},{default:t(()=>[e(L,{layout:"vertical"},{default:t(()=>[e(m,{orientation:"left"},{default:t(()=>[e(w(j),{style:{color:"#1677ff"}}),a[15]||(a[15]=p(" 推理服务 API 配置 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"默认框架 Default Framework"},{default:t(()=>[e(S,{value:l.framework,"onUpdate:value":a[0]||(a[0]=n=>l.framework=n),"button-style":"solid"},{default:t(()=>[e(c,{value:"vllm"},{default:t(()=>[...a[16]||(a[16]=[p("vLLM",-1)])]),_:1}),e(c,{value:"sglang"},{default:t(()=>[...a[17]||(a[17]=[p("SGLang",-1)])]),_:1})]),_:1},8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"Base URL(OpenAI 兼容)"},{default:t(()=>[e(i,{value:l.api.base_url,"onUpdate:value":a[1]||(a[1]=n=>l.api.base_url=n),placeholder:"http://192.168.1.67:8000"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"Endpoint"},{default:t(()=>[e(i,{value:l.api.endpoint,"onUpdate:value":a[2]||(a[2]=n=>l.api.endpoint=n),placeholder:"/v1/chat/completions"},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"API Key(可选)"},{default:t(()=>[e(O,{value:l.api.api_key,"onUpdate:value":a[3]||(a[3]=n=>l.api.api_key=n),placeholder:"Bearer token"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:16},{default:t(()=>[e(s,{label:"额外请求头(JSON,可选)"},{default:t(()=>[e(i,{value:v.value,"onUpdate:value":a[4]||(a[4]=n=>v.value=n),placeholder:'{"X-Custom": "value"}'},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(s,null,{default:t(()=>{var n;return[_.value?(h(),V("span",le,[e(C,{color:_.value.ok?"green":"red"},{default:t(()=>[p(x(_.value.ok?"连接成功":"连接失败"),1)]),_:1},8,["color"]),_.value.ok?(h(),V("span",ne,x(((n=_.value.models)==null?void 0:n.length)||0)+" 个模型",1)):(h(),V("span",oe,x(_.value.error),1))])):E("",!0)]}),_:1}),e(m,{orientation:"left"},{default:t(()=>[e(w(W),{style:{color:"#1677ff"}}),a[18]||(a[18]=p(" GPU / 目录 / 阈值 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:6},{default:t(()=>[e(s,{label:"GPU 自动检测"},{default:t(()=>[e(N,{checked:l.gpu.auto,"onUpdate:checked":a[5]||(a[5]=n=>l.gpu.auto=n)},null,8,["checked"]),U.value?(h(),V("div",se," 检测到:"+x(U.value.name)+" × "+x(U.value.count),1)):E("",!0)]),_:1})]),_:1}),e(u,{span:5},{default:t(()=>[e(s,{label:"GPU 型号(回退)"},{default:t(()=>[e(i,{value:l.gpu.name,"onUpdate:value":a[6]||(a[6]=n=>l.gpu.name=n)},null,8,["value"])]),_:1})]),_:1}),e(u,{span:4},{default:t(()=>[e(s,{label:"GPU 数量"},{default:t(()=>[e(b,{value:l.gpu.count,"onUpdate:value":a[7]||(a[7]=n=>l.gpu.count=n),min:1,style:{width:"100%"}},null,8,["value"])]),_:1})]),_:1}),e(u,{span:9},{default:t(()=>[e(s,{label:"TPOT 阈值 (ms)(默认)"},{default:t(()=>[e(b,{value:l.tpot_threshold_ms,"onUpdate:value":a[8]||(a[8]=n=>l.tpot_threshold_ms=n),min:1,style:{width:"100%"}},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"日志目录 logs_dir"},{default:t(()=>[e(i,{value:l.logs_dir,"onUpdate:value":a[9]||(a[9]=n=>l.logs_dir=n),placeholder:"./logs"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"数据集缓存目录 datasets_dir"},{default:t(()=>[e(i,{value:l.datasets_dir,"onUpdate:value":a[10]||(a[10]=n=>l.datasets_dir=n),placeholder:"./datasets"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"请求速率 Request rate(默认)"},{default:t(()=>[e(q,{value:l.request_rate,"onUpdate:value":a[11]||(a[11]=n=>l.request_rate=n)},{default:t(()=>[e(y,{value:"inf"},{default:t(()=>[...a[19]||(a[19]=[p("inf(不限速)",-1)])]),_:1}),e(y,{value:"custom"},{default:t(()=>[...a[20]||(a[20]=[p("自定义",-1)])]),_:1})]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),e(m,{orientation:"left"},{default:t(()=>[e(w(Q),{style:{color:"#1677ff"}}),a[21]||(a[21]=p(" bench 执行命令 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:12},{default:t(()=>[e(s,{label:"vLLM bench 命令模板"},{default:t(()=>[e(i,{value:l.bench_commands.vllm,"onUpdate:value":a[12]||(a[12]=n=>l.bench_commands.vllm=n),placeholder:"vllm bench serve"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:12},{default:t(()=>[e(s,{label:"SGLang bench 命令模板"},{default:t(()=>[e(i,{value:l.bench_commands.sglang,"onUpdate:value":a[13]||(a[13]=n=>l.bench_commands.sglang=n),placeholder:"python -m sglang.bench_serving"},null,8,["value"])]),_:1})]),_:1})]),_:1}),a[23]||(a[23]=te("div",{style:{color:"#999","font-size":"12px","margin-bottom":"12px"}}," 说明:bench 工具在 benchscope 所在机器以子进程运行(需安装 vllm / sglang CLI),推理服务端只需提供 OpenAI 兼容 API,无需安装插件。 ",-1)),e(s,null,{default:t(()=>[e(g,{type:"primary",size:"large",onClick:$},{icon:t(()=>[e(w(Y))]),default:t(()=>[a[22]||(a[22]=p(" 保存配置 ",-1))]),_:1})]),_:1})]),_:1})]),_:1},8,["spinning"])]),_:1})}}},_e=F(ue,[["__scopeId","data-v-a3dbcdbc"]]);export{_e as default};
1
+ import{_ as F,u as H,a as K}from"./index-CzYL8dyk.js";import{h as E,t as W,u as Q,v as Y,i as I}from"./antd-CmFZS0N1.js";import{o as Z,V as ee,W as t,f as k,r as ae,S as r,U as h,k as e,u as w,G as p,a6 as V,_ as x,a8 as X,X as te}from"./vue-Ch4zjUb1.js";const le={key:0,style:{"margin-right":"12px"}},ne={key:0},oe={key:1,style:{color:"#999"}},se={key:0,style:{color:"#999","font-size":"12px","margin-top":"4px"}},ue={__name:"SettingsView",setup(re){const o=H(),A=k(!1),B=k(!1),_=k(null),U=k(null),l=ae({framework:"vllm",api:{base_url:"",endpoint:"/v1/chat/completions",api_key:"",extra_headers:{}},gpu:{auto:!0,name:"",count:8},logs_dir:"./logs",datasets_dir:"./datasets",tpot_threshold_ms:100,request_rate:"inf",bench_commands:{vllm:"vllm bench serve",sglang:"python -m sglang.bench_serving"}}),v=k("{}");Z(async()=>{var d,a,g,m,c,S,s,u,i,f,O,C,N,b,y,q,L,P,G,n,J,z,D,T,M,R;A.value=!0;try{await o.load(),Object.assign(l,{framework:((d=o.config)==null?void 0:d.framework)||"vllm",api:{base_url:((g=(a=o.config)==null?void 0:a.api)==null?void 0:g.base_url)||"",endpoint:((c=(m=o.config)==null?void 0:m.api)==null?void 0:c.endpoint)||"/v1/chat/completions",api_key:((s=(S=o.config)==null?void 0:S.api)==null?void 0:s.api_key)||"",extra_headers:((i=(u=o.config)==null?void 0:u.api)==null?void 0:i.extra_headers)||{}},gpu:{auto:((O=(f=o.config)==null?void 0:f.gpu)==null?void 0:O.auto)??!0,name:((N=(C=o.config)==null?void 0:C.gpu)==null?void 0:N.name)||"",count:((y=(b=o.config)==null?void 0:b.gpu)==null?void 0:y.count)||8},logs_dir:((q=o.config)==null?void 0:q.logs_dir)||"./logs",datasets_dir:((L=o.config)==null?void 0:L.datasets_dir)||"./datasets",tpot_threshold_ms:((P=o.config)==null?void 0:P.tpot_threshold_ms)??100,request_rate:((G=o.config)==null?void 0:G.request_rate)||"inf",bench_commands:{vllm:((J=(n=o.config)==null?void 0:n.bench_commands)==null?void 0:J.vllm)||"vllm bench serve",sglang:((D=(z=o.config)==null?void 0:z.bench_commands)==null?void 0:D.sglang)||"python -m sglang.bench_serving"}}),v.value=JSON.stringify(((M=(T=o.config)==null?void 0:T.api)==null?void 0:M.extra_headers)||{},null,2),(R=o.gpu)!=null&&R.auto_detected&&(U.value=o.gpu.auto_detected)}finally{A.value=!1}});async function $(){B.value=!0,_.value=null;try{let d={};try{d=JSON.parse(v.value||"{}")}catch{I.error("额外请求头不是合法 JSON");return}_.value=await K.testConnection({base_url:l.api.base_url,endpoint:l.api.endpoint,api_key:l.api.api_key,extra_headers:d})}finally{B.value=!1}}async function j(){try{let d={};try{d=JSON.parse(v.value||"{}")}catch{I.error("额外请求头不是合法 JSON");return}const a={framework:l.framework,api:{...l.api,extra_headers:d},gpu:l.gpu,logs_dir:l.logs_dir,datasets_dir:l.datasets_dir,tpot_threshold_ms:l.tpot_threshold_ms,request_rate:l.request_rate,bench_commands:l.bench_commands};await o.save(a),I.success("配置已保存"),o.refreshStatus()}catch(d){I.error(`保存失败:${d.message}`)}}return(d,a)=>{const g=r("a-button"),m=r("a-divider"),c=r("a-radio-button"),S=r("a-radio-group"),s=r("a-form-item"),u=r("a-col"),i=r("a-input"),f=r("a-row"),O=r("a-input-password"),C=r("a-tag"),N=r("a-switch"),b=r("a-input-number"),y=r("a-select-option"),q=r("a-select"),L=r("a-form"),P=r("a-spin"),G=r("a-card");return h(),ee(G,{size:"small",class:"panel",title:"服务设置 Service Settings"},{extra:t(()=>[e(g,{type:"link",size:"small",loading:B.value,onClick:$},{icon:t(()=>[e(w(E))]),default:t(()=>[a[14]||(a[14]=p(" 测试连接 ",-1))]),_:1},8,["loading"])]),default:t(()=>[e(P,{spinning:A.value},{default:t(()=>[e(L,{layout:"vertical"},{default:t(()=>[e(m,{orientation:"left"},{default:t(()=>[e(w(E),{style:{color:"#1677ff"}}),a[15]||(a[15]=p(" 推理服务 API 配置 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"默认框架 Default Framework"},{default:t(()=>[e(S,{value:l.framework,"onUpdate:value":a[0]||(a[0]=n=>l.framework=n),"button-style":"solid"},{default:t(()=>[e(c,{value:"vllm"},{default:t(()=>[...a[16]||(a[16]=[p("vLLM",-1)])]),_:1}),e(c,{value:"sglang"},{default:t(()=>[...a[17]||(a[17]=[p("SGLang",-1)])]),_:1})]),_:1},8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"Base URL(OpenAI 兼容)"},{default:t(()=>[e(i,{value:l.api.base_url,"onUpdate:value":a[1]||(a[1]=n=>l.api.base_url=n),placeholder:"http://192.168.1.67:8000"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"Endpoint"},{default:t(()=>[e(i,{value:l.api.endpoint,"onUpdate:value":a[2]||(a[2]=n=>l.api.endpoint=n),placeholder:"/v1/chat/completions"},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"API Key(可选)"},{default:t(()=>[e(O,{value:l.api.api_key,"onUpdate:value":a[3]||(a[3]=n=>l.api.api_key=n),placeholder:"Bearer token"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:16},{default:t(()=>[e(s,{label:"额外请求头(JSON,可选)"},{default:t(()=>[e(i,{value:v.value,"onUpdate:value":a[4]||(a[4]=n=>v.value=n),placeholder:'{"X-Custom": "value"}'},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(s,null,{default:t(()=>{var n;return[_.value?(h(),V("span",le,[e(C,{color:_.value.ok?"green":"red"},{default:t(()=>[p(x(_.value.ok?"连接成功":"连接失败"),1)]),_:1},8,["color"]),_.value.ok?(h(),V("span",ne,x(((n=_.value.models)==null?void 0:n.length)||0)+" 个模型",1)):(h(),V("span",oe,x(_.value.error),1))])):X("",!0)]}),_:1}),e(m,{orientation:"left"},{default:t(()=>[e(w(W),{style:{color:"#1677ff"}}),a[18]||(a[18]=p(" GPU / 目录 / 阈值 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:6},{default:t(()=>[e(s,{label:"GPU 自动检测"},{default:t(()=>[e(N,{checked:l.gpu.auto,"onUpdate:checked":a[5]||(a[5]=n=>l.gpu.auto=n)},null,8,["checked"]),U.value?(h(),V("div",se," 检测到:"+x(U.value.name)+" × "+x(U.value.count),1)):X("",!0)]),_:1})]),_:1}),e(u,{span:5},{default:t(()=>[e(s,{label:"GPU 型号(回退)"},{default:t(()=>[e(i,{value:l.gpu.name,"onUpdate:value":a[6]||(a[6]=n=>l.gpu.name=n)},null,8,["value"])]),_:1})]),_:1}),e(u,{span:4},{default:t(()=>[e(s,{label:"GPU 数量"},{default:t(()=>[e(b,{value:l.gpu.count,"onUpdate:value":a[7]||(a[7]=n=>l.gpu.count=n),min:1,style:{width:"100%"}},null,8,["value"])]),_:1})]),_:1}),e(u,{span:9},{default:t(()=>[e(s,{label:"TPOT 阈值 (ms)(默认)"},{default:t(()=>[e(b,{value:l.tpot_threshold_ms,"onUpdate:value":a[8]||(a[8]=n=>l.tpot_threshold_ms=n),min:1,style:{width:"100%"}},null,8,["value"])]),_:1})]),_:1})]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:8},{default:t(()=>[e(s,{label:"日志目录 logs_dir"},{default:t(()=>[e(i,{value:l.logs_dir,"onUpdate:value":a[9]||(a[9]=n=>l.logs_dir=n),placeholder:"./logs"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"数据集缓存目录 datasets_dir"},{default:t(()=>[e(i,{value:l.datasets_dir,"onUpdate:value":a[10]||(a[10]=n=>l.datasets_dir=n),placeholder:"./datasets"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:8},{default:t(()=>[e(s,{label:"请求速率 Request rate(默认)"},{default:t(()=>[e(q,{value:l.request_rate,"onUpdate:value":a[11]||(a[11]=n=>l.request_rate=n)},{default:t(()=>[e(y,{value:"inf"},{default:t(()=>[...a[19]||(a[19]=[p("inf(不限速)",-1)])]),_:1}),e(y,{value:"custom"},{default:t(()=>[...a[20]||(a[20]=[p("自定义",-1)])]),_:1})]),_:1},8,["value"])]),_:1})]),_:1})]),_:1}),e(m,{orientation:"left"},{default:t(()=>[e(w(Q),{style:{color:"#1677ff"}}),a[21]||(a[21]=p(" bench 执行命令 ",-1))]),_:1}),e(f,{gutter:16},{default:t(()=>[e(u,{span:12},{default:t(()=>[e(s,{label:"vLLM bench 命令模板"},{default:t(()=>[e(i,{value:l.bench_commands.vllm,"onUpdate:value":a[12]||(a[12]=n=>l.bench_commands.vllm=n),placeholder:"vllm bench serve"},null,8,["value"])]),_:1})]),_:1}),e(u,{span:12},{default:t(()=>[e(s,{label:"SGLang bench 命令模板"},{default:t(()=>[e(i,{value:l.bench_commands.sglang,"onUpdate:value":a[13]||(a[13]=n=>l.bench_commands.sglang=n),placeholder:"python -m sglang.bench_serving"},null,8,["value"])]),_:1})]),_:1})]),_:1}),a[23]||(a[23]=te("div",{style:{color:"#999","font-size":"12px","margin-bottom":"12px"}}," 说明:bench 工具在 benchscope 所在机器以子进程运行(需安装 vllm / sglang CLI),推理服务端只需提供 OpenAI 兼容 API,无需安装插件。 ",-1)),e(s,null,{default:t(()=>[e(g,{type:"primary",size:"large",onClick:j},{icon:t(()=>[e(w(Y))]),default:t(()=>[a[22]||(a[22]=p(" 保存配置 ",-1))]),_:1})]),_:1})]),_:1})]),_:1},8,["spinning"])]),_:1})}}},_e=F(ue,[["__scopeId","data-v-a3dbcdbc"]]);export{_e as default};
@@ -1,4 +1,4 @@
1
- import{_ as le,u as ce,a as te,b as ye}from"./index-DYReb9-e.js";import{U as s,a6 as D,X as c,F as J,a7 as ee,Y as re,V as y,Z as ge,G as f,_ as w,a0 as ze,o as pe,S as r,k as e,W as t,u as o,a8 as Y,c as k,f as F,r as ie,w as de,j as ke,n as Pe}from"./vue-Ch4zjUb1.js";import{E as Se,M as Oe,f as Ve,g as Be,C as Me,a as Ie,h as qe,i as De,S as Ee,j as L,k as Re,D as Fe,U as je,b as Le,l as Ne,m as Ae,n as Ge,e as Ke,o as Ye,p as He,q as he,r as Xe,s as We,B as Ze}from"./antd-DWALckI0.js";import{_ as Je,M as Qe}from"./MetricsCharts-nbvzLpID.js";import"./echarts-Bb6yjXMn.js";const et={class:"subtabs"},tt={class:"group"},at=["onClick"],lt={__name:"SubTabBar",props:{modelValue:{type:String,default:"random"}},emits:["update:modelValue"],setup(p,{emit:h}){const i=[{key:"random",label:"Random",icon:Se},{key:"sharegpt",label:"ShareGPT",icon:Oe},{key:"custom",label:"Custom",icon:Ve}];return(z,a)=>(s(),D("div",et,[c("div",tt,[(s(),D(J,null,ee(i,$=>c("button",{key:$.key,class:re(["subtab",{active:p.modelValue===$.key}]),onClick:S=>z.$emit("update:modelValue",$.key)},[(s(),y(ge($.icon),{class:"subtab-icon"})),f(" "+w($.label),1)],10,at)),64))])]))}},nt=le(lt,[["__scopeId","data-v-5bdf780d"]]),me=ze("testForm",{state:()=>({model:"",tokenizer:"",precision:"",tpot_threshold_ms:100,concurrency_list:[1,4,8,16,32,40,64,128],request_rate:"inf",gpu:{auto:!0,name:"",count:8},force:!1,extra_args:[],curated:{},_initialized:!1}),actions:{initFromConfig(p,h){this._initialized||(p!=null&&p.tpot_threshold_ms&&(this.tpot_threshold_ms=p.tpot_threshold_ms),p!=null&&p.request_rate&&(this.request_rate=p.request_rate),h!=null&&h.config&&(this.gpu.name=h.config.name||"",this.gpu.count=h.config.count||8,this.gpu.auto=h.config.auto??!0),this._initialized=!0)},initCurated(p){if(!Object.keys(this.curated).length)for(const h of p||[])h.default!==void 0&&h.default!==null&&(this.curated[h.key]=h.default)}}}),ot={class:"field-label"},st={class:"env-footer"},ut={__name:"EnvPanel",setup(p){const h=ce(),i=me(),z=k(()=>h.apiBase),a=k(()=>{var M,_;return((_=(M=h.config)==null?void 0:M.api)==null?void 0:_.endpoint)||"/v1/chat/completions"}),$=k(()=>h.status||{}),S=k(()=>$.value.inference==="ready"),x=k(()=>$.value.models||[]),V=k(()=>x.value.length),m=F(!1),v=F(""),T=F(!1),P=F(0);pe(()=>{x.value.length||h.refreshStatus()});async function A(){await h.refreshStatus(),L.success("状态已刷新")}async function U(){var M,_,C,g,R;m.value=!0,v.value="";try{const I=await te.testConnection({base_url:z.value,endpoint:a.value,api_key:((_=(M=h.config)==null?void 0:M.api)==null?void 0:_.api_key)||"",extra_headers:((g=(C=h.config)==null?void 0:C.api)==null?void 0:g.extra_headers)||{}});T.value=I.ok,P.value=((R=I.models)==null?void 0:R.length)||0,v.value=I.ok?"":I.error||"未知错误",I.ok&&await h.refreshStatus()}finally{m.value=!1}}return(M,_)=>{const C=r("a-typography-link"),g=r("a-descriptions-item"),R=r("a-badge"),I=r("a-tag"),W=r("a-descriptions"),K=r("a-col"),H=r("a-select"),N=r("a-input"),u=r("a-row"),b=r("a-alert"),G=r("a-button"),Q=r("a-space");return s(),D("div",null,[e(u,{gutter:16},{default:t(()=>[e(K,{xs:24,md:10},{default:t(()=>[e(W,{size:"small",column:2},{default:t(()=>[e(g,{label:"Base URL",span:2},{default:t(()=>[e(C,{copyable:""},{default:t(()=>[f(w(z.value),1)]),_:1})]),_:1}),e(g,{label:"Endpoint"},{default:t(()=>[f(w(a.value),1)]),_:1}),e(g,{label:"模型数量"},{default:t(()=>[e(R,{count:V.value,"number-style":{backgroundColor:S.value?"#1677ff":"#bbb"}},null,8,["count","number-style"])]),_:1}),e(g,{label:"最近检测"},{default:t(()=>[f(w($.value.last_check||"-"),1)]),_:1}),e(g,{label:"执行方式"},{default:t(()=>[e(I,{color:"geekblue",style:{"margin-left":"0"}},{default:t(()=>[..._[4]||(_[4]=[f("本机子进程执行 bench",-1)])]),_:1})]),_:1})]),_:1})]),_:1}),e(K,{xs:24,md:14},{default:t(()=>[e(u,{gutter:16},{default:t(()=>[e(K,{span:16},{default:t(()=>[c("div",ot,[e(o(Be),{style:{color:"#1677ff"}}),_[5]||(_[5]=f(" 测试模型 Model",-1))]),x.value.length?(s(),y(H,{key:0,value:o(i).model,"onUpdate:value":_[0]||(_[0]=E=>o(i).model=E),options:x.value.map(E=>({value:E,label:E})),"show-search":"",placeholder:"选择模型(来自 /v1/models)",style:{width:"100%"},"allow-clear":!0},null,8,["value","options"])):(s(),y(N,{key:1,value:o(i).model,"onUpdate:value":_[1]||(_[1]=E=>o(i).model=E),placeholder:"推理环境离线,可手动输入模型名(需勾选强制开始)"},null,8,["value"]))]),_:1}),e(K,{span:8},{default:t(()=>[_[6]||(_[6]=c("div",{class:"field-label"},"Tokenizer(可空)",-1)),e(N,{value:o(i).tokenizer,"onUpdate:value":_[2]||(_[2]=E=>o(i).tokenizer=E),placeholder:"默认同模型",size:"middle"},null,8,["value"])]),_:1})]),_:1}),x.value.length?Y("",!0):(s(),y(b,{key:0,type:"warning","show-icon":"",message:`模型列表不可用:${$.value.error||"推理环境离线"}`,style:{"margin-top":"8px","font-size":"12px"}},null,8,["message"]))]),_:1})]),_:1}),c("div",st,[v.value?(s(),D("span",{key:0,class:re(["conn-msg",T.value?"ok":"bad"])},[T.value?(s(),D(J,{key:0},[e(o(Me)),f(" 连接成功("+w(P.value)+" 个模型) ",1)],64)):(s(),D(J,{key:1},[e(o(Ie)),f(" 连接失败:"+w(v.value),1)],64))],2)):Y("",!0),e(Q,null,{default:t(()=>[e(G,{size:"middle",onClick:A},{icon:t(()=>[e(o(qe))]),default:t(()=>[_[7]||(_[7]=f(" 刷新状态 ",-1))]),_:1}),e(G,{size:"middle",type:"primary",loading:m.value,onClick:U},{icon:t(()=>[e(o(De))]),default:t(()=>[_[8]||(_[8]=f(" 测试连接 ",-1))]),_:1},8,["loading"]),e(G,{size:"middle",type:"link",onClick:_[3]||(_[3]=E=>M.$router.push("/settings"))},{icon:t(()=>[e(o(Ee))]),default:t(()=>[_[9]||(_[9]=f(" 服务设置 ",-1))]),_:1})]),_:1})])])}}},rt=le(ut,[["__scopeId","data-v-eb27c687"]]),it={style:{display:"flex","flex-wrap":"wrap",gap:"8px","align-items":"center","margin-bottom":"8px"}},dt={__name:"ConcurrencyEditor",props:{modelValue:{type:Array,default:()=>[]}},emits:["update:modelValue"],setup(p,{emit:h}){const i=p,z=h,a=F("");function $(){const V=String(a.value).trim();if(V==="")return;const m=V.split(/[,,\s]+/).filter(Boolean).map(Number).filter(T=>Number.isInteger(T)&&T>0);if(!m.length)return;const v=[...i.modelValue];for(const T of m)v.includes(T)||v.push(T);v.sort((T,P)=>T-P),z("update:modelValue",v),a.value=""}function S(V){const m=i.modelValue.filter((v,T)=>T!==V);z("update:modelValue",m)}function x(){z("update:modelValue",[1,4,8,16,32,40,64,128])}return(V,m)=>{const v=r("a-tag"),T=r("a-input"),P=r("a-button");return s(),D("div",null,[c("div",it,[(s(!0),D(J,null,ee(p.modelValue,(A,U)=>(s(),y(v,{key:U,closable:"",color:"blue",style:{"font-size":"14px",padding:"2px 10px"},onClose:M=>S(U)},{default:t(()=>[f(w(A),1)]),_:2},1032,["onClose"]))),128)),e(T,{value:a.value,"onUpdate:value":m[0]||(m[0]=A=>a.value=A),placeholder:"添加并发数,回车确认",style:{width:"160px"},onPressEnter:$,onBlur:$},null,8,["value"]),e(P,{size:"small",type:"dashed",onClick:$},{default:t(()=>[...m[1]||(m[1]=[f("添加",-1)])]),_:1}),e(P,{size:"small",onClick:x},{default:t(()=>[...m[2]||(m[2]=[f("恢复默认 1,4,8,16,32,40,64,128",-1)])]),_:1})]),m[3]||(m[3]=c("div",{style:{color:"#999","font-size":"12px"}}," 测试时每个并发数分别执行一次 bench;--max-concurrency 与 --num-prompts 保持一致。 ",-1))])}}},ct={__name:"FreeArgsEditor",props:{modelValue:{type:Array,default:()=>[]}},emits:["update:modelValue"],setup(p,{emit:h}){const i=p,z=h;function a(){z("update:modelValue",[...i.modelValue,{flag:"",value:""}])}function $(S){z("update:modelValue",i.modelValue.filter((x,V)=>V!==S))}return(S,x)=>{const V=r("a-input"),m=r("a-button");return s(),D("div",null,[(s(!0),D(J,null,ee(p.modelValue,(v,T)=>(s(),D("div",{key:T,style:{display:"flex",gap:"8px","margin-bottom":"6px"}},[e(V,{value:v.flag,"onUpdate:value":P=>v.flag=P,placeholder:"参数名,如 --top-p",style:{width:"220px"}},null,8,["value","onUpdate:value"]),e(V,{value:v.value,"onUpdate:value":P=>v.value=P,placeholder:"参数值(布尔开关可留空)",style:{width:"220px"}},null,8,["value","onUpdate:value"]),e(m,{size:"small",danger:"",onClick:P=>$(T)},{default:t(()=>[...x[0]||(x[0]=[f("删除",-1)])]),_:1},8,["onClick"])]))),128)),e(m,{size:"small",type:"dashed",onClick:a},{default:t(()=>[...x[1]||(x[1]=[f("+ 添加其他参数",-1)])]),_:1}),x[2]||(x[2]=c("div",{style:{color:"#999","font-size":"12px","margin-top":"4px"}}," 自由添加 vLLM / SGLang bench 的其他参数,直接拼接到命令末尾。 ",-1))])}}},pt={style:{display:"flex","flex-wrap":"wrap",gap:"8px"}},mt={style:{display:"flex",gap:"8px","margin-top":"8px","align-items":"center"}},ft={style:{color:"#999","font-size":"12px","margin-top":"4px"}},vt={style:{display:"flex","align-items":"center",gap:"12px","flex-wrap":"wrap"}},_t={key:0,class:"path-text"},yt={style:{display:"flex",gap:"8px"}},gt={style:{display:"flex",gap:"8px"}},kt={key:1,style:{color:"#999","font-size":"12px","margin-top":"4px"}},ht={style:{color:"#999","font-size":"12px"}},bt={style:{color:"#999","font-size":"12px"}},wt={style:{display:"flex",gap:"12px","align-items":"center","justify-content":"flex-end"}},xt={style:{"max-height":"480px",overflow:"auto",background:"#f6f8fa",padding:"12px","font-size":"12px","white-space":"pre-wrap"}},$t={__name:"TestConfigPanel",props:{framework:{type:String,default:"vllm"},datasetType:{type:String,default:"random"}},setup(p,{expose:h}){const i=p,z=ce(),a=me(),$=k(()=>i.framework==="vllm"?"vLLM":"SGLang"),S=k(()=>{var d;return((d=z.status)==null?void 0:d.models)||[]}),x=k(()=>{var d;return(d=z.gpu)!=null&&d.auto_detected?z.gpu.auto_detected:null}),V=[{label:"3K1K",input:3072,output:1024},{label:"1K1K",input:1024,output:1024},{label:"256X256",input:256,output:256}],m=ie({type:i.datasetType,length_pairs:[...V],path:""}),v=ie({input:1024,output:512}),T=F(""),P=F([]),A=F([]),U=ie({state:"idle",path:null,error:null}),M=F(!1),_=F(""),C=F(100),g=k(()=>m.length_pairs.filter(d=>d.checked!==!1)),R=k(()=>P.value.filter(d=>!d.advanced)),I=k(()=>P.value.filter(d=>d.advanced));function W(d){return m.length_pairs.some(n=>n.label===d.label)}function K(d){const n=m.length_pairs.findIndex(O=>O.label===d.label);n>=0?m.length_pairs.splice(n,1):m.length_pairs.push({...d,checked:!0})}function H(){if(!v.input||!v.output){L.warning("请输入输入/输出长度");return}const d=`${v.input}X${v.output}`;if(m.length_pairs.some(n=>n.label===d)){L.warning("该长度组合已存在");return}m.length_pairs.push({label:d,input:v.input,output:v.output,checked:!0})}function N(d){d==="custom"?a.request_rate=String(C.value):a.request_rate="inf"}async function u(){try{await te.sharegptDownload(),U.state="downloading",b()}catch(d){L.error(d.message)}}async function b(){try{const d=await te.sharegptStatus();U.state=d.state,U.path=d.path,U.error=d.error,d.state==="downloading"&&setTimeout(b,2e3)}catch{}}const G=k(()=>U.state==="done"?"已就绪":U.state==="downloading"?"下载中…":U.state==="error"?`下载失败:${U.error}`:"未下载");function Q(d){const n=L.loading(`上传 ${d.name} 中…`,0);return te.uploadDataset(d).then(async O=>{L.success("上传成功"),await E(),m.path=O.path}).catch(O=>L.error(O.message)).finally(()=>n()),!1}async function E(){try{const d=await te.listDatasets();A.value=d.datasets||[]}catch{A.value=[]}}async function ne(){var q,X;if(!a.model)return L.warning("请选择测试模型(推理服务面板或此处)"),null;const d={type:i.datasetType};if(i.datasetType==="random"){if(!g.value.length)return L.warning("请至少选择一个输入/输出长度组合"),null;d.length_pairs=g.value.map(j=>[j.input,j.output,j.label])}else if(i.datasetType==="custom"){const j=m.path||T.value;if(!j)return L.warning("请选择或填写自定义数据集路径"),null;d.path=j}if(!a.concurrency_list.length)return L.warning("请至少添加一个并发数"),null;if(!a.force&&!S.value.length)return L.warning("推理服务离线,请确认服务可用或勾选“强制开始”"),null;const n={auto:a.gpu.auto,name:a.gpu.name||((q=x.value)==null?void 0:q.name)||"",count:a.gpu.count||((X=x.value)==null?void 0:X.count)||8},O={};for(const[j,Z]of Object.entries(a.curated))Z!=null&&Z!==""&&(O[j]=Z);return{framework:i.framework,model:a.model,tokenizer:a.tokenizer,dataset:d,concurrency_list:a.concurrency_list,gpu:n,request_rate:a.request_rate==="inf"?"inf":Number(a.request_rate),tpot_threshold_ms:a.tpot_threshold_ms,precision:a.precision,curated:O,extra_args:a.extra_args.filter(j=>j.flag),force:a.force}}async function oe(){const d=await ne();if(d)try{const O=(await te.previewTest(d)).commands||[];_.value=O.map(q=>`[${q.case} | 并发=${q.concurrency}]
1
+ import{_ as le,u as ce,a as te,b as ye}from"./index-CzYL8dyk.js";import{U as s,a6 as D,X as c,F as J,a7 as ee,Y as re,V as y,Z as ge,G as f,_ as w,a0 as ze,o as pe,S as r,k as e,W as t,u as o,a8 as Y,c as k,f as F,r as ie,w as de,j as ke,n as Pe}from"./vue-Ch4zjUb1.js";import{E as Se,M as Oe,e as Ve,f as Be,C as Me,a as Ie,g as qe,h as De,S as Ee,i as L,j as Re,D as Fe,U as je,b as Le,k as Ne,l as Ae,m as Ge,d as Ke,n as Ye,o as He,p as he,q as Xe,s as We,B as Ze}from"./antd-CmFZS0N1.js";import{_ as Je,M as Qe}from"./MetricsCharts-BKjshnuj.js";import"./echarts-Bb6yjXMn.js";const et={class:"subtabs"},tt={class:"group"},at=["onClick"],lt={__name:"SubTabBar",props:{modelValue:{type:String,default:"random"}},emits:["update:modelValue"],setup(p,{emit:h}){const i=[{key:"random",label:"Random",icon:Se},{key:"sharegpt",label:"ShareGPT",icon:Oe},{key:"custom",label:"Custom",icon:Ve}];return(z,a)=>(s(),D("div",et,[c("div",tt,[(s(),D(J,null,ee(i,$=>c("button",{key:$.key,class:re(["subtab",{active:p.modelValue===$.key}]),onClick:S=>z.$emit("update:modelValue",$.key)},[(s(),y(ge($.icon),{class:"subtab-icon"})),f(" "+w($.label),1)],10,at)),64))])]))}},nt=le(lt,[["__scopeId","data-v-5bdf780d"]]),me=ze("testForm",{state:()=>({model:"",tokenizer:"",precision:"",tpot_threshold_ms:100,concurrency_list:[1,4,8,16,32,40,64,128],request_rate:"inf",gpu:{auto:!0,name:"",count:8},force:!1,extra_args:[],curated:{},_initialized:!1}),actions:{initFromConfig(p,h){this._initialized||(p!=null&&p.tpot_threshold_ms&&(this.tpot_threshold_ms=p.tpot_threshold_ms),p!=null&&p.request_rate&&(this.request_rate=p.request_rate),h!=null&&h.config&&(this.gpu.name=h.config.name||"",this.gpu.count=h.config.count||8,this.gpu.auto=h.config.auto??!0),this._initialized=!0)},initCurated(p){if(!Object.keys(this.curated).length)for(const h of p||[])h.default!==void 0&&h.default!==null&&(this.curated[h.key]=h.default)}}}),ot={class:"field-label"},st={class:"env-footer"},ut={__name:"EnvPanel",setup(p){const h=ce(),i=me(),z=k(()=>h.apiBase),a=k(()=>{var M,_;return((_=(M=h.config)==null?void 0:M.api)==null?void 0:_.endpoint)||"/v1/chat/completions"}),$=k(()=>h.status||{}),S=k(()=>$.value.inference==="ready"),x=k(()=>$.value.models||[]),V=k(()=>x.value.length),m=F(!1),v=F(""),T=F(!1),P=F(0);pe(()=>{x.value.length||h.refreshStatus()});async function A(){await h.refreshStatus(),L.success("状态已刷新")}async function U(){var M,_,C,g,R;m.value=!0,v.value="";try{const I=await te.testConnection({base_url:z.value,endpoint:a.value,api_key:((_=(M=h.config)==null?void 0:M.api)==null?void 0:_.api_key)||"",extra_headers:((g=(C=h.config)==null?void 0:C.api)==null?void 0:g.extra_headers)||{}});T.value=I.ok,P.value=((R=I.models)==null?void 0:R.length)||0,v.value=I.ok?"":I.error||"未知错误",I.ok&&await h.refreshStatus()}finally{m.value=!1}}return(M,_)=>{const C=r("a-typography-link"),g=r("a-descriptions-item"),R=r("a-badge"),I=r("a-tag"),W=r("a-descriptions"),K=r("a-col"),H=r("a-select"),N=r("a-input"),u=r("a-row"),b=r("a-alert"),G=r("a-button"),Q=r("a-space");return s(),D("div",null,[e(u,{gutter:16},{default:t(()=>[e(K,{xs:24,md:10},{default:t(()=>[e(W,{size:"small",column:2},{default:t(()=>[e(g,{label:"Base URL",span:2},{default:t(()=>[e(C,{copyable:""},{default:t(()=>[f(w(z.value),1)]),_:1})]),_:1}),e(g,{label:"Endpoint"},{default:t(()=>[f(w(a.value),1)]),_:1}),e(g,{label:"模型数量"},{default:t(()=>[e(R,{count:V.value,"number-style":{backgroundColor:S.value?"#1677ff":"#bbb"}},null,8,["count","number-style"])]),_:1}),e(g,{label:"最近检测"},{default:t(()=>[f(w($.value.last_check||"-"),1)]),_:1}),e(g,{label:"执行方式"},{default:t(()=>[e(I,{color:"geekblue",style:{"margin-left":"0"}},{default:t(()=>[..._[4]||(_[4]=[f("本机子进程执行 bench",-1)])]),_:1})]),_:1})]),_:1})]),_:1}),e(K,{xs:24,md:14},{default:t(()=>[e(u,{gutter:16},{default:t(()=>[e(K,{span:16},{default:t(()=>[c("div",ot,[e(o(Be),{style:{color:"#1677ff"}}),_[5]||(_[5]=f(" 测试模型 Model",-1))]),x.value.length?(s(),y(H,{key:0,value:o(i).model,"onUpdate:value":_[0]||(_[0]=E=>o(i).model=E),options:x.value.map(E=>({value:E,label:E})),"show-search":"",placeholder:"选择模型(来自 /v1/models)",style:{width:"100%"},"allow-clear":!0},null,8,["value","options"])):(s(),y(N,{key:1,value:o(i).model,"onUpdate:value":_[1]||(_[1]=E=>o(i).model=E),placeholder:"推理环境离线,可手动输入模型名(需勾选强制开始)"},null,8,["value"]))]),_:1}),e(K,{span:8},{default:t(()=>[_[6]||(_[6]=c("div",{class:"field-label"},"Tokenizer(可空)",-1)),e(N,{value:o(i).tokenizer,"onUpdate:value":_[2]||(_[2]=E=>o(i).tokenizer=E),placeholder:"默认同模型",size:"middle"},null,8,["value"])]),_:1})]),_:1}),x.value.length?Y("",!0):(s(),y(b,{key:0,type:"warning","show-icon":"",message:`模型列表不可用:${$.value.error||"推理环境离线"}`,style:{"margin-top":"8px","font-size":"12px"}},null,8,["message"]))]),_:1})]),_:1}),c("div",st,[v.value?(s(),D("span",{key:0,class:re(["conn-msg",T.value?"ok":"bad"])},[T.value?(s(),D(J,{key:0},[e(o(Me)),f(" 连接成功("+w(P.value)+" 个模型) ",1)],64)):(s(),D(J,{key:1},[e(o(Ie)),f(" 连接失败:"+w(v.value),1)],64))],2)):Y("",!0),e(Q,null,{default:t(()=>[e(G,{size:"middle",onClick:A},{icon:t(()=>[e(o(qe))]),default:t(()=>[_[7]||(_[7]=f(" 刷新状态 ",-1))]),_:1}),e(G,{size:"middle",type:"primary",loading:m.value,onClick:U},{icon:t(()=>[e(o(De))]),default:t(()=>[_[8]||(_[8]=f(" 测试连接 ",-1))]),_:1},8,["loading"]),e(G,{size:"middle",type:"link",onClick:_[3]||(_[3]=E=>M.$router.push("/settings"))},{icon:t(()=>[e(o(Ee))]),default:t(()=>[_[9]||(_[9]=f(" 服务设置 ",-1))]),_:1})]),_:1})])])}}},rt=le(ut,[["__scopeId","data-v-eb27c687"]]),it={style:{display:"flex","flex-wrap":"wrap",gap:"8px","align-items":"center","margin-bottom":"8px"}},dt={__name:"ConcurrencyEditor",props:{modelValue:{type:Array,default:()=>[]}},emits:["update:modelValue"],setup(p,{emit:h}){const i=p,z=h,a=F("");function $(){const V=String(a.value).trim();if(V==="")return;const m=V.split(/[,,\s]+/).filter(Boolean).map(Number).filter(T=>Number.isInteger(T)&&T>0);if(!m.length)return;const v=[...i.modelValue];for(const T of m)v.includes(T)||v.push(T);v.sort((T,P)=>T-P),z("update:modelValue",v),a.value=""}function S(V){const m=i.modelValue.filter((v,T)=>T!==V);z("update:modelValue",m)}function x(){z("update:modelValue",[1,4,8,16,32,40,64,128])}return(V,m)=>{const v=r("a-tag"),T=r("a-input"),P=r("a-button");return s(),D("div",null,[c("div",it,[(s(!0),D(J,null,ee(p.modelValue,(A,U)=>(s(),y(v,{key:U,closable:"",color:"blue",style:{"font-size":"14px",padding:"2px 10px"},onClose:M=>S(U)},{default:t(()=>[f(w(A),1)]),_:2},1032,["onClose"]))),128)),e(T,{value:a.value,"onUpdate:value":m[0]||(m[0]=A=>a.value=A),placeholder:"添加并发数,回车确认",style:{width:"160px"},onPressEnter:$,onBlur:$},null,8,["value"]),e(P,{size:"small",type:"dashed",onClick:$},{default:t(()=>[...m[1]||(m[1]=[f("添加",-1)])]),_:1}),e(P,{size:"small",onClick:x},{default:t(()=>[...m[2]||(m[2]=[f("恢复默认 1,4,8,16,32,40,64,128",-1)])]),_:1})]),m[3]||(m[3]=c("div",{style:{color:"#999","font-size":"12px"}}," 测试时每个并发数分别执行一次 bench;--max-concurrency 与 --num-prompts 保持一致。 ",-1))])}}},ct={__name:"FreeArgsEditor",props:{modelValue:{type:Array,default:()=>[]}},emits:["update:modelValue"],setup(p,{emit:h}){const i=p,z=h;function a(){z("update:modelValue",[...i.modelValue,{flag:"",value:""}])}function $(S){z("update:modelValue",i.modelValue.filter((x,V)=>V!==S))}return(S,x)=>{const V=r("a-input"),m=r("a-button");return s(),D("div",null,[(s(!0),D(J,null,ee(p.modelValue,(v,T)=>(s(),D("div",{key:T,style:{display:"flex",gap:"8px","margin-bottom":"6px"}},[e(V,{value:v.flag,"onUpdate:value":P=>v.flag=P,placeholder:"参数名,如 --top-p",style:{width:"220px"}},null,8,["value","onUpdate:value"]),e(V,{value:v.value,"onUpdate:value":P=>v.value=P,placeholder:"参数值(布尔开关可留空)",style:{width:"220px"}},null,8,["value","onUpdate:value"]),e(m,{size:"small",danger:"",onClick:P=>$(T)},{default:t(()=>[...x[0]||(x[0]=[f("删除",-1)])]),_:1},8,["onClick"])]))),128)),e(m,{size:"small",type:"dashed",onClick:a},{default:t(()=>[...x[1]||(x[1]=[f("+ 添加其他参数",-1)])]),_:1}),x[2]||(x[2]=c("div",{style:{color:"#999","font-size":"12px","margin-top":"4px"}}," 自由添加 vLLM / SGLang bench 的其他参数,直接拼接到命令末尾。 ",-1))])}}},pt={style:{display:"flex","flex-wrap":"wrap",gap:"8px"}},mt={style:{display:"flex",gap:"8px","margin-top":"8px","align-items":"center"}},ft={style:{color:"#999","font-size":"12px","margin-top":"4px"}},vt={style:{display:"flex","align-items":"center",gap:"12px","flex-wrap":"wrap"}},_t={key:0,class:"path-text"},yt={style:{display:"flex",gap:"8px"}},gt={style:{display:"flex",gap:"8px"}},kt={key:1,style:{color:"#999","font-size":"12px","margin-top":"4px"}},ht={style:{color:"#999","font-size":"12px"}},bt={style:{color:"#999","font-size":"12px"}},wt={style:{display:"flex",gap:"12px","align-items":"center","justify-content":"flex-end"}},xt={style:{"max-height":"480px",overflow:"auto",background:"#f6f8fa",padding:"12px","font-size":"12px","white-space":"pre-wrap"}},$t={__name:"TestConfigPanel",props:{framework:{type:String,default:"vllm"},datasetType:{type:String,default:"random"}},setup(p,{expose:h}){const i=p,z=ce(),a=me(),$=k(()=>i.framework==="vllm"?"vLLM":"SGLang"),S=k(()=>{var d;return((d=z.status)==null?void 0:d.models)||[]}),x=k(()=>{var d;return(d=z.gpu)!=null&&d.auto_detected?z.gpu.auto_detected:null}),V=[{label:"3K1K",input:3072,output:1024},{label:"1K1K",input:1024,output:1024},{label:"256X256",input:256,output:256}],m=ie({type:i.datasetType,length_pairs:[...V],path:""}),v=ie({input:1024,output:512}),T=F(""),P=F([]),A=F([]),U=ie({state:"idle",path:null,error:null}),M=F(!1),_=F(""),C=F(100),g=k(()=>m.length_pairs.filter(d=>d.checked!==!1)),R=k(()=>P.value.filter(d=>!d.advanced)),I=k(()=>P.value.filter(d=>d.advanced));function W(d){return m.length_pairs.some(n=>n.label===d.label)}function K(d){const n=m.length_pairs.findIndex(O=>O.label===d.label);n>=0?m.length_pairs.splice(n,1):m.length_pairs.push({...d,checked:!0})}function H(){if(!v.input||!v.output){L.warning("请输入输入/输出长度");return}const d=`${v.input}X${v.output}`;if(m.length_pairs.some(n=>n.label===d)){L.warning("该长度组合已存在");return}m.length_pairs.push({label:d,input:v.input,output:v.output,checked:!0})}function N(d){d==="custom"?a.request_rate=String(C.value):a.request_rate="inf"}async function u(){try{await te.sharegptDownload(),U.state="downloading",b()}catch(d){L.error(d.message)}}async function b(){try{const d=await te.sharegptStatus();U.state=d.state,U.path=d.path,U.error=d.error,d.state==="downloading"&&setTimeout(b,2e3)}catch{}}const G=k(()=>U.state==="done"?"已就绪":U.state==="downloading"?"下载中…":U.state==="error"?`下载失败:${U.error}`:"未下载");function Q(d){const n=L.loading(`上传 ${d.name} 中…`,0);return te.uploadDataset(d).then(async O=>{L.success("上传成功"),await E(),m.path=O.path}).catch(O=>L.error(O.message)).finally(()=>n()),!1}async function E(){try{const d=await te.listDatasets();A.value=d.datasets||[]}catch{A.value=[]}}async function ne(){var q,X;if(!a.model)return L.warning("请选择测试模型(推理服务面板或此处)"),null;const d={type:i.datasetType};if(i.datasetType==="random"){if(!g.value.length)return L.warning("请至少选择一个输入/输出长度组合"),null;d.length_pairs=g.value.map(j=>[j.input,j.output,j.label])}else if(i.datasetType==="custom"){const j=m.path||T.value;if(!j)return L.warning("请选择或填写自定义数据集路径"),null;d.path=j}if(!a.concurrency_list.length)return L.warning("请至少添加一个并发数"),null;if(!a.force&&!S.value.length)return L.warning("推理服务离线,请确认服务可用或勾选“强制开始”"),null;const n={auto:a.gpu.auto,name:a.gpu.name||((q=x.value)==null?void 0:q.name)||"",count:a.gpu.count||((X=x.value)==null?void 0:X.count)||8},O={};for(const[j,Z]of Object.entries(a.curated))Z!=null&&Z!==""&&(O[j]=Z);return{framework:i.framework,model:a.model,tokenizer:a.tokenizer,dataset:d,concurrency_list:a.concurrency_list,gpu:n,request_rate:a.request_rate==="inf"?"inf":Number(a.request_rate),tpot_threshold_ms:a.tpot_threshold_ms,precision:a.precision,curated:O,extra_args:a.extra_args.filter(j=>j.flag),force:a.force}}async function oe(){const d=await ne();if(d)try{const O=(await te.previewTest(d)).commands||[];_.value=O.map(q=>`[${q.case} | 并发=${q.concurrency}]
2
2
  ${q.cmd}`).join(`
3
3
 
4
4
  `),M.value=!0}catch(n){L.error(n.message)}}async function ae(){await z.loadParams(i.framework),P.value=z.params[i.framework],a.initCurated(P.value)}return pe(async()=>{a.initFromConfig(z.config,z.gpu),await ae(),E(),b()}),de(()=>i.framework,async()=>{for(const d of Object.keys(a.curated))delete a.curated[d];await ae()}),h({buildPayload:ne,preview:oe}),(d,n)=>{const O=r("a-input"),q=r("a-form-item"),X=r("a-col"),j=r("a-input-number"),Z=r("a-row"),be=r("a-checkable-tag"),se=r("a-button"),we=r("a-badge"),ue=r("a-select"),xe=r("a-upload"),fe=r("a-select-option"),$e=r("a-tag"),ve=r("a-switch"),_e=r("a-collapse-panel"),Ce=r("a-collapse"),Te=r("a-modal"),Ue=r("a-form");return s(),y(Ue,{layout:"vertical"},{default:t(()=>[e(Z,{gutter:16},{default:t(()=>[e(X,{span:6},{default:t(()=>[e(q,{label:"模型精度 Precision"},{default:t(()=>[e(O,{value:o(a).precision,"onUpdate:value":n[0]||(n[0]=l=>o(a).precision=l),placeholder:"如 W8A8(可空)"},null,8,["value"])]),_:1})]),_:1}),e(X,{span:6},{default:t(()=>[e(q,{label:"TPOT 阈值 (ms)"},{default:t(()=>[e(j,{value:o(a).tpot_threshold_ms,"onUpdate:value":n[1]||(n[1]=l=>o(a).tpot_threshold_ms=l),min:1,style:{width:"100%"}},null,8,["value"]),n[14]||(n[14]=c("div",{style:{color:"#999","font-size":"12px"}},"接近该阈值的行高亮",-1))]),_:1})]),_:1}),e(X,{span:12},{default:t(()=>[e(q,{label:"测试模型 Model"},{default:t(()=>[e(O,{value:o(a).model,disabled:"",placeholder:"在「① 推理服务」面板选择模型","addon-after":"去选择",onClick:n[2]||(n[2]=l=>d.$emit("pick-model"))},null,8,["value"]),n[15]||(n[15]=c("div",{style:{color:"#999","font-size":"12px"}}," 模型与 Tokenizer 在「① 推理服务」面板选择;服务地址等配置在「服务设置」中维护 ",-1))]),_:1})]),_:1})]),_:1}),p.datasetType==="random"?(s(),y(q,{key:0,label:"输入/输出长度组合(random 数据集)"},{default:t(()=>[c("div",pt,[(s(),D(J,null,ee(V,l=>e(be,{key:l.label,checked:W(l),onChange:B=>K(l)},{default:t(()=>[f(w(l.label)+"("+w(l.input)+"/"+w(l.output)+") ",1)]),_:2},1032,["checked","onChange"])),64))]),c("div",mt,[n[17]||(n[17]=c("span",null,"自定义:",-1)),e(j,{value:v.input,"onUpdate:value":n[3]||(n[3]=l=>v.input=l),min:1,placeholder:"输入长度",style:{width:"140px"}},null,8,["value"]),n[18]||(n[18]=c("span",null,"/",-1)),e(j,{value:v.output,"onUpdate:value":n[4]||(n[4]=l=>v.output=l),min:1,placeholder:"输出长度",style:{width:"140px"}},null,8,["value"]),e(se,{size:"small",type:"dashed",onClick:H},{icon:t(()=>[e(o(Re))]),default:t(()=>[n[16]||(n[16]=f(" 添加 ",-1))]),_:1})]),c("div",ft," 已选:"+w(g.value.map(l=>l.label).join("、")||"(未选择,无法开始)"),1)]),_:1})):p.datasetType==="sharegpt"?(s(),y(q,{key:1,label:"ShareGPT 数据集"},{default:t(()=>[c("div",vt,[e(we,{status:U.state==="done"?"success":U.state==="downloading"?"processing":U.state==="error"?"error":"default",text:G.value},null,8,["status","text"]),e(se,{size:"small",loading:U.state==="downloading",onClick:u},{icon:t(()=>[e(o(Fe))]),default:t(()=>[n[19]||(n[19]=f(" 下载 / 检查(modelscope) ",-1))]),_:1},8,["loading"]),U.path?(s(),D("span",_t,w(U.path),1)):Y("",!0)]),n[20]||(n[20]=c("div",{style:{color:"#999","font-size":"12px","margin-top":"4px"}}," 来源:https://www.modelscope.cn/datasets/gliang1001/ShareGPT_V3_unfiltered_cleaned_split ,未指定路径时测试开始前自动下载。 ",-1))]),_:1})):(s(),y(q,{key:2,label:"自定义数据集(与 sharegpt 功能一致)"},{default:t(()=>[e(ue,{value:m.path,"onUpdate:value":n[5]||(n[5]=l=>m.path=l),placeholder:"选择已上传的数据集,或填写服务器本地路径",style:{"margin-bottom":"8px",width:"100%"},options:A.value.map(l=>({value:l.path,label:`${l.name}(${l.path})`})),"allow-clear":""},null,8,["value","options"]),c("div",yt,[e(O,{value:T.value,"onUpdate:value":n[6]||(n[6]=l=>T.value=l),placeholder:"服务器本地 jsonl 路径,如 /data/sharegpt.jsonl"},null,8,["value"]),e(xe,{"before-upload":Q,"show-upload-list":!1},{default:t(()=>[e(se,{size:"small"},{icon:t(()=>[e(o(je))]),default:t(()=>[n[21]||(n[21]=f(" 上传文件 ",-1))]),_:1})]),_:1})])]),_:1})),e(Z,{gutter:16},{default:t(()=>[e(X,{span:12},{default:t(()=>[e(q,{label:"测试请求并发数(--max-concurrency = --num-prompts)"},{default:t(()=>[e(dt,{value:o(a).concurrency_list,"onUpdate:value":n[7]||(n[7]=l=>o(a).concurrency_list=l)},null,8,["value"])]),_:1})]),_:1}),e(X,{span:6},{default:t(()=>[e(q,{label:"请求速率 Request rate"},{default:t(()=>[e(ue,{value:o(a).request_rate,"onUpdate:value":n[8]||(n[8]=l=>o(a).request_rate=l),onChange:N},{default:t(()=>[e(fe,{value:"inf"},{default:t(()=>[...n[22]||(n[22]=[f("inf(不限速,推荐)",-1)])]),_:1}),e(fe,{value:"custom"},{default:t(()=>[...n[23]||(n[23]=[f("自定义(req/s)",-1)])]),_:1})]),_:1},8,["value"]),o(a).request_rate==="custom"?(s(),y(j,{key:0,value:C.value,"onUpdate:value":n[9]||(n[9]=l=>C.value=l),min:.01,style:{width:"100%","margin-top":"6px"}},null,8,["value"])):Y("",!0)]),_:1})]),_:1}),e(X,{span:6},{default:t(()=>[e(q,{label:"GPU(部署信息)"},{default:t(()=>[c("div",gt,[e(O,{value:o(a).gpu.name,"onUpdate:value":n[10]||(n[10]=l=>o(a).gpu.name=l),placeholder:"型号(自动获取优先)"},null,8,["value"]),e(j,{value:o(a).gpu.count,"onUpdate:value":n[11]||(n[11]=l=>o(a).gpu.count=l),min:1,style:{width:"90px"}},null,8,["value"])]),x.value?(s(),y($e,{key:0,color:"green",style:{"margin-top":"4px"}},{icon:t(()=>[e(o(Le))]),default:t(()=>[f(" 自动检测:"+w(x.value.name)+" × "+w(x.value.count),1)]),_:1})):(s(),D("div",kt,"未检测到 nvidia-smi,请手动填写"))]),_:1})]),_:1})]),_:1}),e(q,{label:`框架参数(${$.value} bench)`},{default:t(()=>[e(Ce,{ghost:"",bordered:!1},{default:t(()=>[e(_e,{key:"common",header:"常用参数"},{default:t(()=>[e(Z,{gutter:16},{default:t(()=>[(s(!0),D(J,null,ee(R.value,l=>(s(),y(X,{key:l.key,span:6},{default:t(()=>[e(q,{label:l.label},{default:t(()=>[l.type==="bool"?(s(),y(ve,{key:0,checked:o(a).curated[l.key],"onUpdate:checked":B=>o(a).curated[l.key]=B,"checked-children":"开","un-checked-children":"关"},null,8,["checked","onUpdate:checked"])):l.type==="select"?(s(),y(ue,{key:1,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B,options:l.options.map(B=>({value:B,label:B})),style:{width:"100%"}},null,8,["value","onUpdate:value","options"])):l.type==="int"||l.type==="float"?(s(),y(j,{key:2,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B,step:l.type==="float"?.1:1,style:{width:"100%"}},null,8,["value","onUpdate:value","step"])):(s(),y(O,{key:3,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B},null,8,["value","onUpdate:value"])),c("div",ht,w(l.help),1)]),_:2},1032,["label"])]),_:2},1024))),128))]),_:1})]),_:1}),e(_e,{key:"advanced",header:"高级参数"},{default:t(()=>[e(Z,{gutter:16},{default:t(()=>[(s(!0),D(J,null,ee(I.value,l=>(s(),y(X,{key:l.key,span:6},{default:t(()=>[e(q,{label:l.label},{default:t(()=>[l.type==="bool"?(s(),y(ve,{key:0,checked:o(a).curated[l.key],"onUpdate:checked":B=>o(a).curated[l.key]=B,"checked-children":"开","un-checked-children":"关"},null,8,["checked","onUpdate:checked"])):l.type==="select"?(s(),y(ue,{key:1,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B,options:l.options.map(B=>({value:B,label:B})),style:{width:"100%"}},null,8,["value","onUpdate:value","options"])):l.type==="int"||l.type==="float"?(s(),y(j,{key:2,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B,step:l.type==="float"?.1:1,style:{width:"100%"}},null,8,["value","onUpdate:value","step"])):(s(),y(O,{key:3,value:o(a).curated[l.key],"onUpdate:value":B=>o(a).curated[l.key]=B},null,8,["value","onUpdate:value"])),c("div",bt,w(l.help),1)]),_:2},1032,["label"])]),_:2},1024))),128))]),_:1})]),_:1})]),_:1})]),_:1},8,["label"]),e(q,{label:"其他参数(自由添加)"},{default:t(()=>[e(ct,{value:o(a).extra_args,"onUpdate:value":n[12]||(n[12]=l=>o(a).extra_args=l)},null,8,["value"])]),_:1}),e(q,null,{default:t(()=>[c("div",wt,[n[25]||(n[25]=c("span",{style:{color:"#999","font-size":"12px","margin-right":"auto"}},"开始 / 取消测试请在「测试进度」面板操作",-1)),e(se,{type:"primary",ghost:"",onClick:oe},{icon:t(()=>[e(o(Ne))]),default:t(()=>[n[24]||(n[24]=f(" 命令预览 ",-1))]),_:1})])]),_:1}),e(Te,{open:M.value,"onUpdate:open":n[13]||(n[13]=l=>M.value=l),title:"命令预览(首个用例)",width:"860px",footer:null},{default:t(()=>[c("pre",xt,w(_.value),1)]),_:1},8,["open"])]),_:1})}}},Ct=le($t,[["__scopeId","data-v-01937508"]]),Tt={class:"progress-row"},Ut={class:"progress-info"},zt={class:"progress-stats"},Pt={key:0},St={class:"progress-actions"},Ot={__name:"TestProgressPanel",props:{starting:{type:Boolean,default:!1}},emits:["start","stop"],setup(p,{emit:h}){const i=ye(),z=me(),a=F(null),$=F(["log"]),S=k(()=>i.running),x=k(()=>{var u;return((u=i.run)==null?void 0:u.status)||"idle"}),V=k(()=>{var u;return i.lastRunId||((u=i.run)==null?void 0:u.run_id)||""}),m=k(()=>{var u;return((u=i.run)==null?void 0:u.model)||""}),v=k(()=>{var u;return((u=i.run)==null?void 0:u.framework_name)||""}),T=k(()=>{var b;const u=(b=i.run)==null?void 0:b.gpu;return u?u.name?`${u.name}×${u.count}`:`×${u.count}`:""}),P=k(()=>{var u;return((u=i.run)==null?void 0:u.cases)||[]}),A=k(()=>{var u;return((u=i.run)==null?void 0:u.concurrency_list)||[]}),U=k(()=>P.value.length*A.value.length),M=k(()=>i.rows.filter(u=>u.metrics||u.error).length),_=k(()=>U.value?Math.round(M.value/U.value*100):0),C=k(()=>i.currentCase||""),g=k(()=>i.currentConc??null),R=k(()=>{const u=P.value.find(b=>b.label===C.value);return u?u.input_len?`${u.label}(${u.input_len}/${u.output_len})`:u.label:C.value||"-"}),I=k(()=>i.logLines.slice(-120)),W=k(()=>{var b;const u=(b=i.run)==null?void 0:b.summary;return u!=null&&u.xlsx?`共 ${u.rows} 条结果,汇总文件:${u.xlsx}`:M.value?`共 ${M.value} 条结果(无 xlsx 汇总,可能全部失败)`:"未产生结果"}),K=F(Date.now());let H=null;de(S,u=>{H&&clearInterval(H),u&&(K.value=Date.now(),H=setInterval(()=>K.value=Date.now(),1e3))},{immediate:!0}),ke(()=>{H&&clearInterval(H)});const N=k(()=>{var E;const u=(E=i.run)==null?void 0:E.started_at;if(!u)return"-";const b=Ke(u,"YYYY-MM-DD HH:mm:ss"),G=Math.max(0,K.value-b.valueOf()),Q=Math.floor(G/1e3);return`${Math.floor(Q/60)}分${Q%60}秒`});return de(()=>i.logLines.length,async()=>{await Pe(),a.value&&(a.value.scrollTop=a.value.scrollHeight)}),(u,b)=>{const G=r("a-alert"),Q=r("a-progress"),E=r("a-tag"),ne=r("a-space"),oe=r("a-checkbox"),ae=r("a-button"),d=r("a-collapse-panel"),n=r("a-collapse");return s(),D("div",null,[S.value?(s(),y(G,{key:0,type:"info","show-icon":"",message:`测试进行中:${R.value}(并发 ${g.value??"-"})`,description:`已出结果 ${M.value}/${U.value},运行 ${N.value},请勿关闭页面`,style:{"margin-bottom":"12px"}},null,8,["message","description"])):x.value==="done"?(s(),y(G,{key:1,type:"success","show-icon":"",message:"测试完成",description:W.value,style:{"margin-bottom":"12px"}},null,8,["description"])):x.value==="stopped"?(s(),y(G,{key:2,type:"warning","show-icon":"",message:"测试已取消",description:`已出结果 ${M.value}/${U.value}`,style:{"margin-bottom":"12px"}},null,8,["description"])):x.value==="error"?(s(),y(G,{key:3,type:"error","show-icon":"",message:"测试执行出错",description:o(i).error,style:{"margin-bottom":"12px"}},null,8,["description"])):(s(),y(G,{key:4,type:"info","show-icon":"",message:"等待开始测试",description:"配置好测试参数后,点击「开始测试」执行性能压测",style:{"margin-bottom":"12px"}})),c("div",Tt,[U.value>0?(s(),y(Q,{key:0,type:"circle",size:64,percent:_.value,status:_.value>=100?"success":S.value?"active":"normal"},null,8,["percent","status"])):Y("",!0),c("div",Ut,[e(ne,{wrap:""},{default:t(()=>[V.value?(s(),y(E,{key:0,color:"blue"},{default:t(()=>[f("Run "+w(V.value),1)]),_:1})):Y("",!0),m.value?(s(),y(E,{key:1},{default:t(()=>[f(w(m.value),1)]),_:1})):Y("",!0),v.value?(s(),y(E,{key:2,color:"purple"},{default:t(()=>[f(w(v.value),1)]),_:1})):Y("",!0),T.value?(s(),y(E,{key:3},{default:t(()=>[f("GPU: "+w(T.value),1)]),_:1})):Y("",!0)]),_:1}),c("div",zt,[c("span",null,[b[4]||(b[4]=f("进度:",-1)),c("b",null,w(M.value),1),f(" / "+w(U.value),1)]),S.value?(s(),D("span",Pt,"当前:"+w(R.value)+" @ 并发 "+w(g.value??"-"),1)):Y("",!0)])]),c("div",St,[e(oe,{checked:o(z).force,"onUpdate:checked":b[0]||(b[0]=O=>o(z).force=O),style:{"margin-right":"4px"}},{default:t(()=>[...b[5]||(b[5]=[f("离线强制开始",-1)])]),_:1},8,["checked"]),e(ae,{type:"primary",size:"large",loading:p.starting,disabled:S.value,onClick:b[1]||(b[1]=O=>u.$emit("start"))},{icon:t(()=>[e(o(Ae))]),default:t(()=>[b[6]||(b[6]=f(" 开始测试 ",-1))]),_:1},8,["loading","disabled"]),e(ae,{size:"large",danger:"",disabled:!S.value,onClick:b[2]||(b[2]=O=>u.$emit("stop"))},{icon:t(()=>[e(o(Ge))]),default:t(()=>[b[7]||(b[7]=f(" 取消测试 ",-1))]),_:1},8,["disabled"])])]),I.value.length?(s(),y(n,{key:5,ghost:"",style:{"margin-top":"12px"},activeKey:$.value,"onUpdate:activeKey":b[3]||(b[3]=O=>$.value=O)},{default:t(()=>[e(d,{key:"log",header:`实时输出(${I.value.length} 行,仅尾部)`},{default:t(()=>[c("pre",{class:"log-console",ref_key:"logBox",ref:a},w(I.value.join("")),513)]),_:1},8,["header"])]),_:1},8,["activeKey"])):Y("",!0)])}}},Vt=le(Ot,[["__scopeId","data-v-866c7da1"]]),Bt={key:0,style:{color:"#999","font-size":"12px"}},Mt={__name:"RealtimeResultPanel",props:{rows:{type:Array,default:()=>[]},threshold:{type:Number,default:null},running:{type:Boolean,default:!1}},setup(p){const h=p,i=[{key:"output_mean",label:"Output 吞吐 (tok/s)"},{key:"total_mean",label:"Total 吞吐 (tok/s)"},{key:"ttft_mean",label:"TTFT mean 耗时 (ms)"},{key:"tpot_mean",label:"TPOT mean 耗时 (ms)"},{key:"ttft_p99",label:"TTFT P99 耗时 (ms)"},{key:"tpot_p99",label:"TPOT P99 耗时 (ms)"}],z=k(()=>new Set(h.rows.map($=>$.label||$.case)).size);return(a,$)=>{const S=r("a-tag"),x=r("a-space"),V=r("a-divider");return s(),D("div",null,[e(x,{style:{"margin-bottom":"8px"},wrap:""},{default:t(()=>[e(S,{color:"blue"},{icon:t(()=>[e(o(Ye))]),default:t(()=>[f("用例 "+w(z.value)+" 个",1)]),_:1}),e(S,{color:"green"},{icon:t(()=>[e(o(He))]),default:t(()=>[f("已出结果 "+w(p.rows.length)+" 条",1)]),_:1}),e(S,{color:p.running?"processing":"default"},{icon:t(()=>[e(o(he),{spin:p.running},null,8,["spin"])]),default:t(()=>[f(" "+w(p.running?"测试进行中…":"空闲"),1)]),_:1},8,["color"]),p.threshold?(s(),D("span",Bt," TPOT 阈值 "+w(p.threshold)+"ms:绿色=低于阈值,金色=最佳并发 ",1)):Y("",!0)]),_:1}),e(Je,{rows:p.rows,threshold:p.threshold,pagination:{pageSize:20,showSizeChanger:!0}},null,8,["rows","threshold"]),e(V,{style:{margin:"12px 0"}},{default:t(()=>[...$[0]||($[0]=[f("实时曲线(横轴:并发数)",-1)])]),_:1}),e(Qe,{rows:p.rows,"metric-defs":i},null,8,["rows"])])}}},It=["onClick"],qt={class:"blocks-wrap"},Dt={id:"env",class:"block"},Et={id:"config",class:"block"},Rt={id:"progress",class:"block"},Ft={id:"result",class:"block"},jt={__name:"TestView",props:{framework:{type:String,default:"vllm"}},setup(p){const h=p,i=ye(),z=ce(),a=F("random"),$=F(null),S=F(!1),x=F(null),V=k(()=>{var C;return((C=z.config)==null?void 0:C.tpot_threshold_ms)??null}),m=k(()=>{var C;return((C=z.status)==null?void 0:C.inference)==="ready"}),v=[{id:"env",label:"测试环境",icon:Xe},{id:"config",label:"测试配置",icon:We},{id:"progress",label:"测试进度",icon:he},{id:"result",label:"测试结果",icon:Ze}],T=F("env");let P=null;function A(){var g;const C=((g=x.value)==null?void 0:g.$el)||x.value;if(!(!C||typeof C.getBoundingClientRect!="function")){P=new IntersectionObserver(R=>{for(const I of R)I.isIntersecting&&(T.value=I.target.id)},{root:C,rootMargin:"0px 0px -70% 0px",threshold:0});for(const R of v){const I=document.getElementById(R.id);I&&P.observe(I)}}}function U(C){var g;(g=document.getElementById(C))==null||g.scrollIntoView({behavior:"smooth",block:"start"}),T.value=C}pe(()=>{setTimeout(A,100)}),ke(()=>{P&&P.disconnect()});async function M(){var g;const C=await((g=$.value)==null?void 0:g.buildPayload());if(C){S.value=!0;try{const R=await i.start({...C,framework:h.framework});L.success(`测试已启动:${R.run_id}`)}catch(R){L.error(`启动失败:${R.message}`)}finally{S.value=!1}}}async function _(){try{await i.stop(),L.info("已发送取消请求")}catch(C){L.error(C.message)}}return(C,g)=>{const R=r("a-layout-sider"),I=r("a-tag"),W=r("a-card"),K=r("a-layout-content"),H=r("a-layout");return s(),y(H,{class:"page-layout"},{default:t(()=>[e(R,{width:"200",theme:"light",class:"workflow-sider"},{default:t(()=>[g[3]||(g[3]=c("div",{class:"sider-title"},"测试流程",-1)),(s(),D(J,null,ee(v,N=>c("a",{key:N.id,class:re(["side-item",{active:T.value===N.id}]),onClick:u=>U(N.id)},[(s(),y(ge(N.icon))),g[2]||(g[2]=f()),c("span",null,w(N.label),1)],10,It)),64))]),_:1}),e(K,{ref_key:"contentEl",ref:x,class:"page-content"},{default:t(()=>[e(nt,{modelValue:a.value,"onUpdate:modelValue":g[0]||(g[0]=N=>a.value=N),class:"subnav"},null,8,["modelValue"]),c("div",qt,[c("section",Dt,[e(W,{size:"small",class:"panel",title:"测试环境"},{extra:t(()=>[e(I,{color:m.value?"green":"red"},{default:t(()=>[c("span",{class:re(["dot",m.value?"ok":"bad"])},null,2),f(" "+w(m.value?"在线":"离线"),1)]),_:1},8,["color"])]),default:t(()=>[e(rt)]),_:1})]),c("section",Et,[e(W,{size:"small",class:"panel",title:"测试配置"},{default:t(()=>[e(Ct,{ref_key:"configPanel",ref:$,framework:p.framework,"dataset-type":a.value,onPickModel:g[1]||(g[1]=N=>U("env"))},null,8,["framework","dataset-type"])]),_:1})]),c("section",Rt,[e(W,{size:"small",class:"panel",title:"测试进度"},{default:t(()=>[e(Vt,{starting:S.value,onStart:M,onStop:_},null,8,["starting"])]),_:1})]),c("section",Ft,[e(W,{size:"small",class:"panel",title:"测试结果"},{default:t(()=>[e(Mt,{rows:o(i).rows,threshold:V.value,running:o(i).running},null,8,["rows","threshold","running"])]),_:1})])])]),_:1},512)]),_:1})}}},Yt=le(jt,[["__scopeId","data-v-a6a85fbb"]]);export{Yt as default};