From 07a537a69d5d05957453887a2307428338fb6740 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=8A=A0=E9=B9=8F?= Date: Tue, 8 Sep 2026 18:04:33 +0800 Subject: [PATCH 1/4] =?UTF-8?q?1.=20web=E7=95=8C=E9=9D=A2=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0=E5=9F=BA=E7=A1=80=E4=BF=A1=E6=81=AF=E6=98=BE=E7=A4=BA?= =?UTF-8?q?=EF=BC=88kylinbot=E7=89=88=E6=9C=AC=E3=80=81python=E3=80=81?= =?UTF-8?q?=E4=BD=BF=E7=94=A8=E7=9A=84=E6=A8=A1=E5=9E=8B=EF=BC=89=202.=20?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=87=AA=E5=8A=A8=E8=8E=B7=E5=8F=96token?= =?UTF-8?q?=E5=B9=B6=E4=BF=9D=E5=AD=98=E5=88=B0=E6=9C=AC=E5=9C=B0=EF=BC=8C?= =?UTF-8?q?=E8=8B=A5token=E5=A4=B1=E6=95=88=E5=88=99=E9=87=8D=E6=96=B0?= =?UTF-8?q?=E8=8E=B7=E5=8F=96token?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kylinbot-auto-test.zip | Bin 0 -> 61192 bytes kylinbot-auto-test/.gitignore | 1 + kylinbot-auto-test/README.md | 151 +++++--- .../batch_run_ws_chat.cpython-39.pyc | Bin 0 -> 14834 bytes .../collect_batch_summary.cpython-39.pyc | Bin 0 -> 3438 bytes .../__pycache__/get_ws_token.cpython-39.pyc | Bin 0 -> 9826 bytes kylinbot-auto-test/batch_run_ws_chat.py | 85 ++++- kylinbot-auto-test/collect_batch_summary.py | 19 +- kylinbot-auto-test/get_ws_token.py | 355 ++++++++++++++++++ .../__pycache__/environment.cpython-39.pyc | Bin 0 -> 5792 bytes kylinbot-auto-test/utils/environment.py | 186 +++++++++ kylinbot-auto-test/web/app.js | 40 ++ .../web/data/batch_summary.json | 16 + kylinbot-auto-test/web/index.html | 7 + kylinbot-auto-test/web/styles.css | 19 + 15 files changed, 819 insertions(+), 60 deletions(-) create mode 100644 kylinbot-auto-test.zip create mode 100644 kylinbot-auto-test/.gitignore create mode 100644 kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc create mode 100644 kylinbot-auto-test/__pycache__/collect_batch_summary.cpython-39.pyc create mode 100644 kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc create mode 100644 kylinbot-auto-test/get_ws_token.py create mode 100644 kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc create mode 100644 kylinbot-auto-test/utils/environment.py diff --git a/kylinbot-auto-test.zip b/kylinbot-auto-test.zip new file mode 100644 index 0000000000000000000000000000000000000000..63721c9165f64bf2f2a584b231e33e0070b786b5 GIT binary patch literal 61192 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

+2>GIud2|N%hKHK~@b*E(&CX^zNw#mMqT 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 literal 0 HcmV?d00001 diff --git a/kylinbot-auto-test/.gitignore b/kylinbot-auto-test/.gitignore new file mode 100644 index 0000000..32a6a1c --- /dev/null +++ b/kylinbot-auto-test/.gitignore @@ -0,0 +1 @@ +.ws_token diff --git a/kylinbot-auto-test/README.md b/kylinbot-auto-test/README.md index 4aaa990..84d226e 100644 --- a/kylinbot-auto-test/README.md +++ b/kylinbot-auto-test/README.md @@ -1,18 +1,20 @@ # KylinBot 自动化测试脚本 -面向 **麒麟 Linux**的 WebSocket 对话批量测试工具:按用例驱动模型执行任务,用期望产物文件判断是否通过,汇总结果并生成可离线打开的 HTML 报告;可选调用通义大模型写文字总结。 +面向 **麒麟 Linux** 的 WebSocket 对话批量测试工具:按用例驱动模型执行任务,用期望产物文件判断是否通过,汇总结果并生成可离线打开的 HTML 报告;可选调用通义大模型写文字总结。也支持在 Windows 上做本地调试。 ## 目录结构 ``` -自动化测试脚本/ +kylinbot-auto-test/ ├── batch_run_ws_chat.py # 批量入口(推荐从这里跑) ├── ws_chat_benchmark_lib.py # 单次 WebSocket 压测 / 对话执行 +├── get_ws_token.py # 网关 Token 自动获取 / 缓存 / 探活 ├── collect_batch_summary.py # 扫描 run_summary.json → batch_summary.json ├── check_file.py # 期望产物路径展开与存在性检查 ├── test_cases.json # 测试用例 ├── requirement.txt # Python 依赖 ├── utils/ +│ ├── environment.py # 采集运行环境(系统 / 包版本 / Gateway 状态) │ └── summary.py # 大模型总结 batch_summary.json └── web/ # HTML 报告模板(跑完后会复制到 batch 目录) ├── index.html @@ -25,12 +27,12 @@ - Python 3.12+ - 可访问的 KylinBot Gateway(默认 `ws://127.0.0.1:42617/ws/chat`) -- 网关 Token +- 网关 Token(须以 `zc` 开头;未手动提供时可自动配对获取) ### 安装依赖 ```bash -cd /path/to/自动化测试脚本 +cd /path/to/kylinbot-auto-test python3 -m pip install -r requirement.txt ``` @@ -41,22 +43,26 @@ python3 -m pip install -r requirement.txt ### 环境变量 -| 变量 | 用途 | -|------|------| -| `KYLINBOT_WS_TOKEN` 或 `KYLINBOT_GATEWAY_TOKEN` | 网关 Token(也可用 `--token`) | -| `DASHSCOPE_API_KEY` 或 `OPENAI_API_KEY` | 大模型总结 API Key(可选) | -| `DASHSCOPE_BASE_URL` | 默认 `https://dashscope.aliyuncs.com/compatible-mode/v1` | -| `DASHSCOPE_MODEL` | 默认 `qwen3.7-max`,可选 | +| 变量 | 用途 | +| --------------------------------------------------- | ----------------------------------------------------------------------- | +| `KYLINBOT_WS_TOKEN` 或 `KYLINBOT_GATEWAY_TOKEN` | 网关 Token(也可用`--token`) | +| `KYLINBOT_WS_TOKEN_FILE` | 本地明文 Token 缓存路径(默认项目根目录`.ws_token`) | +| `KYLINBOT_GATEWAY_URL` | 自动取 Token 时的 Gateway HTTP 根地址(默认`http://127.0.0.1:42617`) | +| `DASHSCOPE_API_KEY` 或 `OPENAI_API_KEY` | 大模型总结 API Key(可选) | +| `DASHSCOPE_BASE_URL` | 默认`https://dashscope.aliyuncs.com/compatible-mode/v1` | +| `DASHSCOPE_MODEL` | 默认`qwen3.7-max` | 在麒麟上写入 `~/.bashrc`: ```bash -export KYLINBOT_WS_TOKEN="你的网关token" +export KYLINBOT_WS_TOKEN="zc_你的网关token" export DASHSCOPE_API_KEY="sk-xxx" ``` 然后执行 `source ~/.bashrc`,用 `echo "$DASHSCOPE_API_KEY"` 确认已生效。 +> `.ws_token` 已在 `.gitignore` 中忽略,请勿把真实 Token / API Key 提交进仓库。 + ## 测试用例 `test_cases.json` 每条用例示例: @@ -75,32 +81,50 @@ export DASHSCOPE_API_KEY="sk-xxx" ] ``` -| 字段 | 说明 | -|------|------| -| `id` / `name` | 用例标识与显示名 | -| `enabled` | 是否默认执行 | -| `count` | 该用例重复次数 | -| `mode` | `agentic` / `direct` | -| `message` | 发给模型的测试命令 | -| `output` | 期望产物路径;跑完后检查是否存在,作为 **通过判定** | +### 字段说明 + +| 字段 | 必填 | 说明 | +|------|------|------| +| `id` | 建议 | 用例唯一标识;`--only` / `--skip` 按此过滤 | +| `name` | 可选 | 展示名称,缺省时用 `id` | +| `message` | 是 | 发给 Agent 的完整 Prompt | +| `output` | 是 | 模型对话产出文件,用于判断模型是否正确执行 | +| `enabled` | 否 | 默认 `true`;为 `false` 时除非 `--only` 指定否则跳过 | +| `count` | 否 | 该用例重复跑几次,默认 `1` | +| `mode` | 否 | `agentic` 或 `direct`,默认 `agentic`(见下方说明) | +| `timeout` | 否 | 单次超时秒数;不写则用命令行 `--timeout`(默认 `180`) | +| `model` | 否 | 覆盖模型 | +| `approval_decision` | 否 | `approve` / `deny` / `always` | +| `note` | 否 | 备注,运行时打印 | +| `extra_args` | 否 | 额外透传给 bench 脚本的参数列表 | + +另支持(可选):`token_saving`、`subordinate_agent`。 + +### `mode` 说明 -可选字段:`model`、`timeout`、`token_saving`、`approval_decision`、`subordinate_agent`、`note`、`extra_args`。 +- **`agentic`**(默认):Agent 模式,可走工具调用 / 多步执行,适合文件读写、文档处理等任务类用例。 +- **`direct`**:直连对话模式,不走 Agent 工具链,适合纯问答类场景。 -路径支持 `~/桌面` 与 `~/Desktop`,脚本会映射到系统真实桌面目录(`xdg-user-dir DESKTOP` / `桌面` / `Desktop`)。 +命令行 `--mode` 会覆盖用例里的 `mode`。 + +路径支持 `~/桌面` 与 `~/Desktop`,脚本会映射到系统真实桌面目录(`xdg-user-dir DESKTOP` / `桌面` / `Desktop`)。跑完后检查 `output` 是否存在,作为通过判定。 ## 快速开始 ```bash -cd /path/to/自动化测试脚本 +cd /path/to/kylinbot-auto-test # 干跑:只打印命令 -python3 batch_run_ws_chat.py --token "$KYLINBOT_WS_TOKEN" --dry-run +python3 batch_run_ws_chat.py --dry-run + +# 正式跑(未传 --token 时自动读缓存 / 探活 / 必要时重新配对) +python3 batch_run_ws_chat.py -v -# 正式跑(推荐加 -v 看流式输出) +# 手动指定 Token python3 batch_run_ws_chat.py --token "$KYLINBOT_WS_TOKEN" -v # 指定用例 / 次数 / 输出根目录 -python3 batch_run_ws_chat.py --token "$KYLINBOT_WS_TOKEN" \ +python3 batch_run_ws_chat.py \ --cases test_cases.json \ --only 文档校对 \ --count 1 \ @@ -110,17 +134,20 @@ python3 batch_run_ws_chat.py --token "$KYLINBOT_WS_TOKEN" \ ### 常用参数 -| 参数 | 说明 | -|------|------| -| `--token` | 网关 Token | -| `--url` | WebSocket 地址,默认 `ws://127.0.0.1:42617/ws/chat` | -| `--cases` | 用例 JSON,默认 `test_cases.json` | -| `--only` / `--skip` | 按 `id` 白名单 / 黑名单 | -| `--count` | 覆盖所有用例的采样次数 | -| `--save-root` | 相对路径 → `<桌面>//batch_时间戳`;也可传绝对路径 | -| `--fail-fast` | 一失败即停 | -| `--dry-run` | 只打印命令 | -| `-v` | 打印 thinking / 回复 / 工具调用 | +| 参数 | 说明 | +| ----------------------- | -------------------------------------------------------------- | +| `--token` | 网关 Token(须以`zc` 开头) | +| `--token-file` | 本地 Token 缓存路径 | +| `--refresh-token` | 忽略本地缓存,强制重新配对 | +| `--gateway-url` | 自动取 Token 时的 HTTP 根地址 | +| `--url` | WebSocket 地址,默认`ws://127.0.0.1:42617/ws/chat` | +| `--cases` | 用例 JSON,默认`test_cases.json` | +| `--only` / `--skip` | 按`id` 白名单 / 黑名单 | +| `--count` | 覆盖所有用例的采样次数 | +| `--save-root` | 相对路径 →`<桌面>//batch_时间戳`;也可传绝对路径 | +| `--fail-fast` | 一失败即停 | +| `--dry-run` | 只打印命令 | +| `-v` | 打印 thinking / 回复 / 工具调用 | ## 执行流程 @@ -129,6 +156,8 @@ test_cases.json │ ▼ batch_run_ws_chat.py + │ 未提供 token → get_ws_token 缓存/配对 + │ 采集 environment.json │ 对每条用例调用 ▼ ws_chat_benchmark_lib.py ──WebSocket──► KylinBot Gateway @@ -136,9 +165,10 @@ ws_chat_benchmark_lib.py ──WebSocket──► KylinBot Gateway │ 判定:ws_ok(收到 done)+ ok(output 文件存在) ▼ batch_时间戳/ + ├── environment.json ├── 001_/run_*/run_summary.json ├── batch_index.json / .md - ├── batch_summary.json ← 汇总(含各 run 关键字段) + ├── batch_summary.json ← 汇总(含 environment + 各 run 关键字段) ├── batch_llm_summary.md ← 可选大模型总结 └── web/index.html ← 离线报告(内嵌数据,直接打开) ``` @@ -149,6 +179,22 @@ batch_时间戳/ - `ok`:期望 `output` 文件存在(未配置 `output` 时不因文件检查失败) - 页面「结果」列优先看 sample 的 `ok` +## Token 自动获取 + +未传 `--token` / 环境变量时,`batch_run_ws_chat.py` 会调用 `get_ws_token.py` 逻辑: + +1. 本地无有效 `zc` 明文 → `POST /admin/paircode/new` + `POST /pair` → 写入 `.ws_token` +2. 本地有明文 → 先使用 +3. `GET /api/status` 探活;不可用则重新 pair 并覆盖缓存 + +也可单独使用: + +```bash +python3 get_ws_token.py +python3 get_ws_token.py --refresh +eval "$(python3 get_ws_token.py --export)" +``` + ## 结果与报告 默认输出目录示例: @@ -159,12 +205,13 @@ batch_时间戳/ 重要文件: -| 文件 | 内容 | -|------|------| -| `batch_summary.json` | 各 run 的 `timestamp` / `url` / `message` / `output` / `samples`,以及可选 `summary` | -| `web/index.html` | 可视化报告:通过率、耗时柱状图、用例表、大模型总结 | -| `web/data.js` | 内嵌 JSON,支持 `file://` 直接打开 | -| `*/run_*/sample_*.md` | 单次对话详情(thinking、工具、回复) | +| 文件 | 内容 | +| ----------------------- | ------------------------------------------------------------------------------------------------------------------ | +| `environment.json` | 运行环境(OS、Python、`kylin-bot` 包版本、Gateway status 等) | +| `batch_summary.json` | 各 run 的`timestamp` / `url` / `message` / `output` / `samples`,以及 `environment` 与可选 `summary` | +| `web/index.html` | 可视化报告:运行环境、通过率、耗时柱状图、用例表、大模型总结 | +| `web/data.js` | 内嵌 JSON,支持`file://` 直接打开 | +| `*/run_*/sample_*.md` | 单次对话详情(thinking、工具、回复) | 在麒麟上双击或用浏览器打开: @@ -209,14 +256,14 @@ python3 check_file.py ## 判定与指标说明(简要) -| 字段 | 含义 | -|------|------| -| `send_message_total_ms` | 发 `message` → 收到 `done` | -| `first_thinking_ms` | 发 `message` → 首次 `thinking` 帧 | -| `first_visible_text_ms` | 发 `message` → 首次 `chunk` | -| `queue_to_first_frame_ms` | 发 `message` → 任意首帧 | -| `ws_ok` | 会话是否正常结束 | -| `ok` / `output_ok` | 期望产物是否存在 | +| 字段 | 含义 | +| --------------------------- | ------------------------------------- | +| `send_message_total_ms` | 发`message` → 收到 `done` | +| `first_thinking_ms` | 发`message` → 首次 `thinking` 帧 | +| `first_visible_text_ms` | 发`message` → 首次 `chunk` | +| `queue_to_first_frame_ms` | 发`message` → 任意首帧 | +| `ws_ok` | 会话是否正常结束 | +| `ok` / `output_ok` | 期望产物是否存在 | HTML 报告中耗时以 **秒** 显示。 @@ -225,4 +272,4 @@ HTML 报告中耗时以 **秒** 显示。 1. 跑前若期望产物已存在,可能被误判为成功;脚本会打印警告。 2. 大模型总结依赖外网访问 DashScope;无 Key 时会跳过总结,不影响测试退出码逻辑(汇总/网页仍会尽量生成)。 3. IDE 里运行可能读不到 `~/.bashrc` 里的环境变量,请在终端执行或在 IDE 中配置环境变量。 -4. 请勿把真实 Token / API Key 提交进仓库。 +4. Token 须以 `zc` 开头;请勿把真实 Token / API Key 提交进仓库。 diff --git a/kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc b/kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..5f46ca3b09889b8da2da8c0deeca24d4c63d22a1 GIT binary patch literal 14834 zcmcJ0Yj7Obm0ovGPtOB`Hwc0tNH*UD#Q{j_X_%zNr%8zdxg=$pEpbPKxea1~dGU4+ zNOXFl6pyO4_A`f>R%~afXMw3r;=2% zL3yow=iVM*K+;jAl8}Yl_kGWOoqNuA&SaaLlM4QAe&_A+OD7cNSCnY{XCU#UqNvWB zs-iH(QkcrLf?CupO{I9G5V0cSt6RGGMy;s$8kQlxF)Jp%aVsvq2`hoGUPu;`R#Nm4 zEi@HVR!YQ;LUXajYEczCWw%~dr`u+f@ph}j?qIQ%iq(m49N#W{6ZkH(yX}t4svRF+ zKB@8_(s#OtsWNv)QkX2PDE3;t#g*2|VxQF~MrkUnDz3Ixi+HNArf6DbajmtsxXxNv zTyL!}Zm>3pvgX3Z;wEcTakI6#xW(FnycX8V+HPp9oprpZTm5V+>ttPQ8FISW@)x7l zR+M+)ujfXDtzf;V^AOT2(XNH{u~j#sY&Bbh+->Y3v@}J_wQL<)rbV3=wjM1vu#KoQ zz_y{zCQ)ZI+k!fS_IB1kpgalKWDo` z=F?M!e90U%kLF9&i{_SW!6};;%6!5x%O&%4zQoEG(7w#gLOGW$n9Lrjp6f^ZgBP>K zO2HmVnr3Cn9V?d}Hb;o442a5vM1hP?DK^t-Nug^yZbn20#vP1|{BpJAnmf$&?R ze|mGbJYkp2UE;IHG|lzqM<2XB`}(c9uYG;?m3Ke7Jw5x0Io-m_3%&+j?_ zLF9rx(jN&r?2DCbiDk-Fw^DU86?7IfhY9;)-f^9vliN7-2aPZLHXOEuB?Av?tVCLBqM}v-f&Z%Qh9~{mcI&$=2ux!kAD`@N3 z89IG*B&xg+v~l}MJTI4ucF7HT za1@I;?hSc3@Fm*`x+S%Z1$5N8jurO03Yh3~ET40qb6md7#8RF;+ph(>SPp~RZk3mE zxL6DS5{Px;Z$I(GNtC$CwCXG48hDy^Rh?05svGfDSHG95W%gZ1?TxnU|?o;2@5t-E*JU}oNgI9%3?Qq z5Vevey5fbrXR|=f2Re9AQB1{((N<;hOw8#$h3`W3`QNjLo}ZvcY@`hC#>?Z+XRB^G zO?*=3r%~XH*@ePFwe(_*2fbNAlIAR5qen4>vk!rycBs8-68{aYMbp)8#M%(*2sa?E zYZ_vj+NHLr@q7Na{1^Qbql523FJ7DAL|BQlrf&|HOSad6eXC@-V-F1D1UZ##&L+-; z+)3VrCQI0ohKv~g1Y7#If-Q}!k|ottUj=)LxDhZ82wtu}9wkP@qE{oTBFYSu87PZ2 zc zrbRlIvmOXdi|Jmsi761C`mX9BrK=!5DQpch7jhsxvGrFW>WP_ba8qm}M5e_S5S&Bqv^JnlA+w_pvPXz1-TYzVbK zi`w-W>_U2XL+d?Af36|@B-_jOvHfzbrdxewMg_Y&FzkJ9-=_C%_-c8P$FCu1esig z+$$pe`u5j;b?GZ}H@-Xf`n8XK_SW1V|Mbs)WcKGT-TBU!QS&{=iV^$-mjVXDp=`^=T zA^METWebvyTZUNV@~T~Z9F=B&{?m`Y`EA+pk}iLJ`_Ffze)C1M zzDb8qojPvLO@Dx8pS^hrODd=J@f$yYz>fa02k*|_x(yQNu3R@s0vs9~+_CfVf$jLe zW9X5ckL`H;zKy6aIw+Zsif+8V3(oxwA<_?$NbfbDwnt8ua}%~}QX4wo^sIVM9hs z2b(U5czg3X=)I6+bFODD3{3QyR86Q%3uB_YSZ=JG&)H5xk04x#0N%!9;-*5q5^1ws zpT`oy`&CIu0>@H{4Cg?cqFfq%(pw&0Vlyl;9XnSpF~@64rx%nXuX%}5RQ&-O3tnSN zLB%8uYQQ{U7odntVioDm|MIKfFn1l0dcmH-T??J<8I(^aU9&&_(cG24G`EDc%*lM# zyvWX_vAjHuC8E12lrluZI{gFY-Vx{=RkvXn)Q6%hmb5U{uuV&-_OK76tnpQ#-rK&v z40SE-*myv}NSN43GtV5HVw2S4EoFDi=8ox1TQ5mNa6XO`>64!aD2pl>Te6;bqOqJ*~`yCW-YnLNg(4vD$5wj z)gq6RFc>t~mEHYNe@_ZQdogd{!QuUf1Fh_k&@Z%BzJmrzQOgLnC5VnfxP-{;OgSXC z(@v6d5F~{NC}nt!e~#)KB8v+#R|dPOud@iA$Di{H1PTOD?Gqz{P&L%#KN?XP)52J{ zrv1i9P+psw3iC9zUYcAeUCcvFMH_?K)Z;A>entAh^%whXY`K^l##+Rp`2&^Q%UP!@{h>!&QB1wi&(n$?J0KlxKF+I%H8ge60x}ky} zP|ohEMg1s?u27sqzUCY{|A?>gFCxcSq4*kL#xEjArXrIHA4N)^hFUI^Q^X;y#fI+_ z&WWs(gc*?XHKzE=*)9^yr+<^z?K~Qb9eq#bkD=asTA&SV57dkI>~)aX<=8H` zKxNOrN45WoKgCQ>oASFu%;`A{j{{v;& z6bQYN6wZD<(1}Sw$*UBg`{~3&ISDfThS*A;q58y2c^-ikug@aTiFw{LOwdv<6aR*GXgp?d*5(E+I_RjAYq;0=L9l_x|QPGaQ=1~^Bg zaB@WJ6ZKSy>P7(GDC2r%ROA}yEhb_yw4Fpr6wr(^Zn!Z3Map07POP_yV{&*HKHLmuCL=eqy?XbyEDC zM(5j)0rb&CE_65og2H^7F|;|9ZV;v2C`HZ++_#1r0DD+Z6>t`R617?xz#dg8^@@2> zS+6LwL>Yh|j7K077d`f&M?g(sZ_0QZN?sH-SBaW16Cmfh$XOlcbRg$lk+VkR5S6B& z^52L)*9t1ld#GF|Ag8|rKS;Wre$wr_Oo01uM2q!o1Ncdj_z3k_>T;K{jrEmen6TT6p$j~;k|4?iPAz+6(G+kucfZeNQCK-*Pc$7 z0F;p8MGrYpCw`nddWM2w3XV}g021jdz>&drLK*}}bRUx;?ZzSI*Nq5RUkgA|aOKPD z7Zd<`01mNUD)4Rbl0JyNfZ-A7ezC&$z4I!Wnq5|Pmp_l;ViUbGw)DugkxbdI#E(5g;Jo_oI zTZj($1M-D*9N+pM$}}qL*1A+q&#<@Lt->hu90Z+h5;Bk&*V!c}g&qw8w#4f_3^WU8 zgx+h_6$lnMTx3R>)&Xm4A}89A6Y;faV@7d~0_;|OjqoiuKAr$1Pewoh#(=S@ydZ$~ z$OFpN@#Hnt*#cRiDg360e>>mvTHI#jwty1-v{LHU6}NTjyDCnus<>@6{ftu5wkzm2 zD&TnICZPNJ$X>78?&EnM@4#Ot@U{3=q%ukL^Az=SO`Y1LDz&Hzl?6Qj!e2@m@{)_a zomS4^ovB5?1e3zaFt%OUPVxYw+!KH~6aG?sxc|m-QOnT4sjhul3t7+PZ~t*VoTxi|i+u1%1BouF1gg=k=n^C$+zV~5ITaeSgm?P?M74@&7{zL92ly9ZCv0=X3SbBQ1 z4`a?{+JTTNu|E<1AN|&8>Jzg;2uiS11CTR_4)p8x``8gScmooQSp8r49gX{0uXj!7 zaT;5;x~!66skY2tMlur09`Tn=Z^fxW4C8P2ml1V~XU=_S`XO+LZg<;w+V67v-2sfb z}k4#>?rIA&rttid>Czx$urB2BmR3~d>1>xPM%BDR^zs{)^FR{8{)35@z>xi zoq~MX3i;CDzt5hnnc!~q+?dF9*%y$jv(q)xUp>8reNo)AGyWQRI~ii=Wh2`)Lv+cM zh1+8A?=cJe@SMms7s{RwYn~PDem_iQZnlaQHO@bYm3Vbq6dX(D_#-B-{wR4@%%zg6sggL$rB! z)j$V8x_^1;JBI*&CPfb!fuuJB*38+N5dRLMa0r0?J&yW!-}sX|w{8uYRZ=zYy!Jle zXxZ_{(_bDGJ(#oa{NT=y;7jr9?E62wd+E~b%ReEs8Rmhn{rR1lSLgof>vwK_6A*K? z13i2Uoc#NLICtY~bKkror%*kB?71J#AWwK_P#XZ;vf149`yc)6>zKpbpIw@J``cz{ zwgqY_Ax9A*y_Nv{=8b1I7B{lY#={$**?7{Dl6vM8H2D}{8z4vy%+=&xktt6Aurj3o z1LqjuY7sDRrVjH4O$|;9o@Sa}+%zw6SawaXxnU!Rkd*sn(m#VpMJ-2-J*JCfX!=8>+tpMK*tU_y41R^XhZ+>Y%5cHLFn!Y5wxk8>X~JlXclM z$Yc%L6QL?JWG>pNy;iAYgn%?^=@4~?=2eqJ8vx$2Xxs+KHW4I4#|<*4$AF!Z^HI<& z`v@Iggiu|50K{o#?l{Eol zuK@1O0H+redJ*()X~&+nbQ;4;nTu1~?Ip~x{%$Wauwyh(0qlolpx@mR3s0d3X1fF> zW8pS0pwB}lOiPstd4pv~fe3>uaM%H-tAHLtP5@P-?9NVm8r7g)IPk z_rkpT0iorvPE5|j+jt8VkVl9>E;%75R-{zE5X9jdGD^J!2>~XMQO;@tUD?oJ#uKO;M2iyy|FlsL z8!4a%kGE4%q+pl$Ba|eaTpA#tWy8s4yqqry#6lt+-x8T(EC8V+aGntdJ3?GEd2;`W zBgao=4jehb>1mdHE6PcbuoAS>88U4F?3~>6!=AMzt6ur8gcq4DoF=Oq5lN z6{mllFl`9TqkhN8%xERW!zR2F`83s!*cWrsA4qr0tZcz~2=|iz8Ol&udYWQof`p9I zTKoZ(!AERTIyu523GSQUKqeoefS}(7h^0!ko5Ht3&=3<2VemTAX(eF6kvv))fBp)! z7Od^Fhy_t`l;IskzK8q|sjs?IrM!9KV&21WU{eN%TZcpG6c8u?QaS{r(gips4uFQB z83UmPC!&;qX5d)#TSJ%dj7}xLNf~Xz$*4z*qaFYqqzK??feR7=Glqz@AS73%q(<&Y zu)Lrx{=?Ej@J$M%wvZze!WOj;F>+|?p_=Gpn<%eCKXK&fnt^^L6>-)0pZX_ylaAJ_ zF}8+QpfO5wNueL=-%z_Wd_}8zJ2^+=zZ)rnoO)HbL}}f>)jrXqbxI7a7w}XZ{mM1K z+~$qApkDN^q3@LVFDUsRdQ+EJFRU5H)m2mN_yjBTiLNDoOMk{E@n|2du-2jS_p#ov zD*b>qFI7kV$;0h_>rxVR=)MSi3cllb@W^~q1O6huz^SG+U`(4_IK;c5*8CMR^61Fj zgF%mpe1Jzs;9r;ac1t8v(zq{AmPw@71(#eiSztm!~cs4lEiqQ}?JV_YIe!U5En zhTEpEQJooR=jRK4gq-Ao(ohLpHYwLvL>}1^K)WBKa3aG0F02!yIxhUapg$y8k~ImJ z*0?}*n*2CxhKE;*wO-YstF$dwfZ@Ou9$HMZpAfZa1dVm9Bt*BOb;)dc@4pJ@{tqDk*-0H%Ty5K3Cy~)j?JUU8u$t=S+Z~$J-Xa&E&3S1GEXfR$+ z*wPd&8+02^3J3oTf>Yc_*dLis%J*i>EfzfZ*Gv^`XCUV|9(f?*rS>}OKAnO_2c|X% zP92i;Mgkk&?6ZSg&AsGbNcgjGIT)(X4BiJznhKM1eOi-w`vOT|TL+W)!l`~B1OMq$ z`wwSMKKslwdrzFnWX#>>At5?IhWaMW5L-=SuPGgfu;1q=SDm8qSALGv_~ z4p4B5f=4O%3j~mE>C*7OMqtITQq(bhv)Ef5BQg5XkV-Zy;>ql>d+Kz zJboQQO)!C_QdrPlsg3}p9}6ALF~Z*yha{e@fcMaU!NWux{AwYuBLYr_6d-7=L({aj z-)a%0i*BgL&3Vj34gx@#3y#+Wdz#eh&r{gn99Sp#@hiKeu%G5uEBX2{S z#P1mSBWBbvZhh2Ja&gpasz-k3$wH!-tQnxyAk$zi<~B{Iz?Pcf0Gg6a!G}SPHSZ#3 z)#5gdw;~0zqT2>|Ru{D-GXQ%as231XY`T3$VI5!{)CWpIVP`m>uJ9YC2~-v3FgDib zh}z3&rCB$b*|4@`5?oxL<%{cs)ff`1p-#lOE|<%8FcPDg*Q_cUZaQ`~zgzHfumj`-OEgm(E$5;HvCfu}QV{>G#yq}r{WdfRRQ=w4Igp@C`Jt&ECGLk{@pAeZ{lDvinfD!ncMAw(8ys2So zUc6et^#_ae+RQCsXHZ1#0$j4XL&+GWOXy!0=8IgZx-PU7su!lS48zygukPdpjl4s= z_xv^yL-(EkQv^Zc;KiIR7G4PU{B0^BMqwFQ`guy;Y9_Ym4Ad9kUs44UUmLh1@x(aTh1_1)`iMc2)lOLbAWFtj zTK7+HQQJg|4%8pO-&T$PE&2`OnGB7T$p~XD?6t%FJA+szgWpGGGFCE^8Li^?GIl1z zL5spqP#{+6G{t^K!MhZY_Qe030#a}2C2+^^>olQ-1qS>p$>bcRB8*7TAbJ$f8hJjE zuKZnU`z!@tpx{Fa#KY8y7-`fv(=POgF*`RQb#;>4q`pF0lC`Y<8=@swNgN3)gU z-JS7gy0iW)cB=Ywd<_5EOOucD`U~5i=M(sD;QI`p#P?Y~#iw5~NN4cOzO?uppMT-{ z3*6&p`2s(OndkY17mk09UxwtOmR#cBf#kfnz(06m{?3qZ#6@v_*VtvhhOX;I^U82- zy&WcA=xv0mz3uTxindDSz}rlvC;Lf|^}F3r4qBZo#k7QbT_LxG7bPk!*PNQs`j)KS zWW{)xB&iBjlqT64zNu5>h+c1=%!r6LAoQP zjJOy!c+^(E%9Q-r!wnwe3Y9}G3s(x&mq{DZ@%Bf3t9)2Cjm~e3O@^2-UsRQ`3|qpE z*6`{*A$ndWV%Se`Z!;1x&%8~Uc41s-;vE_C)ZQkxbMeejOfH}k8M*Oza>R1>TVvnI z*#Y~#`P5!FUXf9)EunB*v$a@QPsHFAlN9Z;j^_2x#pjQn4B{x+NLA32Y3EVcSLrnc z6P5C77|6Co9KW4*?RZ8zjp^cnj)J!y?G1|B5*e$Vc6+xj;+TKpF@_(B=Sqf{eyCGW zYTH_h({>nVw_3-GaO?4VD=YVd)w?S{TV9uwSg$W!_NMSz%>VE0&SNYi0~w~ALo01G zP=BnvBtlh=LvqTVRR~CUhwQlo&*iYeeujcmW!B}T`olopBwSX~}S8@j4aS+vKhAXQPARor@`&`gZxR8ew z0AFZs*yu+wrk5PSyGMEv=|%_fEiWN9KoFvxCOm60 zzp6>3C)!O%&eK@^5D9_@p(>m-0Ja5C)iIM~9(Kyjg*=Q8c9dXF9 z7b1~;fJxacG=^DcRn{-4a zlAmISRgj7Ev>ypo*c)jYH?8uvpJD7Y6%b_;TadPz3VwmkNh(k#g+E}9q<_H}S-I7* zl-+T1lbhU9F1PmpXzuPIS?4T!peh`2=hbtd4L+7zAP)cyW0XW|!!PcX{CR@tp}U5} zGZ`sy43kgZ5Ac>ei`%V!OH|ji{JKc8z7#>2wWA0D1(+cOD_m@b{a8t2MR@_uu=X}o zJxOLB&b<%PYqvc3^a`!{kQy?hU(-(8<$5Xo9#ctUwn$q)CW|N2CxVFs}nEV3r;ba_TIuSqia&Ik7#Be&4TfIb;pTf>Z)jMwY*lVb?E-< zi`PF}ym@^wxW4#<#p|CoNk=v40j@~Uy{1!CkL*x1Zp*Dc)kOEnEV8JF9Mp6u(@N#@ItVx{NX45%WK;g_i#Rb{#!lSn&U;q)K!_g@(5C19TLy z1oW_BLuoq`5|HF>BFR~UHKaG7X6Pwf0Z&LWZl}T-AxS4RjD7=@t)u*=9;Gy0irQ2r z+Em=hn>a%fh7r4TWgRVLKz^4#m#ERvYGnh|d6_~glAr^vJ4H(-e@JuQp(wi>MoAk3 zSp$s$t}($d4KNZS@*X5bH3(=<5HuOCv(~&+RDyt~?I7@LL9p3JaVUa75>(}FY6w5_ zr__*@3P43|$I(XV7#BW8qLLJ(v^6P*)gRI)c?e$hYwLHuzI*>cuzdGxt&*l)f<2tA z{HeZ*;;eNd|Hxw+CvcV2POvVGq|J4t3ZN!PX}oym_D8q@XZT8;e|V}_gL literal 0 HcmV?d00001 diff --git a/kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc b/kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e67f0308e2cd1651ec2b75f86d97c758e81f7003 GIT binary patch literal 9826 zcmaJ{U364cmcIX0sT4&K0z^c;A_CQtAJA4it+pVbw5-68*hr~UUF2Lyg-TU%?!7>2 zRaj_5(I!AE{sNlVqT-BVk2WGid6|b)vTIS#jlps#IK&z#jlYx#BV4W62IYOgZPbzUoG1>5KTtK7m5!T3}rxiAb#a`5sEo?4}pO)D? z)`Z+GY(75Cs9nGoBEMMV7a`xmZbAN5rn1HCR^+MO5_TKAo!xO-XC}MzMI*W7rrM>V z_Aa&zwYQ-MeeXW4vgK?AM!Q{%LS-vYYb?Qjg0eeA**%zH6>CM_WNoaSbs)c*twH`y z`5tDEyckL@ zqk3zRXmLOL1ms=~?<9n17GOt*n(UsQn zVQEap&a2&0;tBUZap03Le_DR^lgVRWmyf?`wwn{$dcyws)s`wmi9^>-+In{&eVtNTl+I=O;e- z&G+N)Moe>cn^`&i*X7e+RNfjji@hnc^7gUHn=hOH_R?$S)-ByVW_y|qWOD6=bcXll znbn@N_M7(vRa7WimS1|OeE6(CkiS3-y{0zw=~wDTEgwE|_1h~GCqF@xd)v&%H_#k~ zOuOx*9oIH1$3Cchb@}`8Q&%sJl#icByYi8Drd}SYy!nMm^L;;lwEWG5$&X%|IQ8ZY z6GqUq^5q*7A6~lpUGQ>+L8mXDyVu-pIjQ}2%At*ED-2@dAE_~0Te-E1TXrAXSo_jh zbLp~`Ki<|lP{?y9v9xZ$ooT1HFU8#)P1xI)b}*l5ns;HBKfO9WiV4Ij%*tCAf`k3T z7kG`SLzgGN`)y>3)IK45jp%eDq=Y4DLU;RK*DfSi{+Nv+^8Tp<4R<#!X-2}4N&p&1?pHGMF%nM+;;D3b+OAC2N~oS*;F+A`srDcSv>j$~ zo{)JMJX^t_bFx@duNz6E-ve1Ys`z^vjiv}m;gokCcia6o^2DEFupI)9|;sXP^6>f z4}V{I<48@5rVfvk&wm3fNXW@XX4$Hw^wyjpkRkFDT9*?i>*|2@>j?`1z zHoGPkP{o@kdV02+mCL12e0Sjl&?+xW=wv4zWm*bbxTpjQeG)GVC>9* zm3N&9l;H1?N5#8{cbL3z7|J;D@oSYgzL@TNZwIYX^)zR&VDWkA!<+D+p#p^PBDRy~ zR?6Y7<#wR1eC6ATH*Nqy+J^B<<=AoZS?`gy&t1Ze)oF$ z)#xED<`mO`y4^OU^pg{<7Z4A1906?*8!*KgRk z_NmQ1sda0+H;`CB?H%qlRf~nG5vS#8IcTA$@5<)Wju#P%Nh8}pFGJ+G00;ju7mMXf z@mPtk{RAG8tjWrCL&Z~$%8~yubV|kLXpmBnQ+_ZED#d5IbUG#K#i;yt42UgPA>KYB z5Xx2mC{5BL5P{fONg4&>jmZM%uF37RWRCaD6aXlMJ2O`9HRbYrAf3$=trTfd3e#*s zvno8TK$;F5Xguoz2ySZ&cp4dk++lf0F3AK<`y{@QDLDYskb)A$ZgW(om84VB8D&_0 zfm$g;DxMnuWl04H>6AvTic*EZi%QQBs|Xc;vfqZa=*!zqC)uy|{dPN9Dzo(wGq5DJ zx`dKc_uICoQ-#e*{gN7`-Q`GvGr;0ry?m^WeLx`0$&Y_mdGEy4iFLj#NnoIvUwVnCUnmjus|-DFAME7B4L0pS;8bCN52NXQGA7D{R#;>*pggQ zN}%i`+Ox`#Hl&v{rtH!AHV0(Bgk$rM7Ef6mrOwwoO21mtnE?w#Vi3k*hDWtAhzJf} z$FVka@ivT}IRQ~F>H^uW$)+bqHlCA{Q7dP=z^b&}o5^?*mhbObznuqB$vAx}pM7z- zA9zJ7_H^bB6mass&>MUWs%E?`*?J;v*p#%Bo_Q<{;#kBK=qh-G6jJ2y^@tjVzBbFv z*TdH}jX#XqV%%{HS?d|Fh*c)-@N>QOo7jjZbMO_LXrhJ;c0V)$Td5S{8K~-rI;0hQ zL^-w)o2!f{$J?;AI&D+G4v#`(`iL@QIEKHG!|G6IJE)9?&oIn-F1}i_pY4!j@!5gr zcIkwiGc}qm)E_<}55hkh3d>UQrIOhEx=|a7i%Sio4Pz4j$cc0rb4!t3%67=p4y<`7 zd@$S{{B~gdVuf+6uq#;MGG`uZ5aL69n;2|{ieQ=YTpj2xTIvzo5P3sK)kzA_wHT(yJPhK4n|*tmBmUS2=-jUFFZ-eV z*8ksJ)!jLv*ew`mp3_{449oos(9g%g5bYAwp{XmO_##WXc}^DEc};hnU9As#A#N42 zf*XQK66VCORYTZ8ZGp_baDQ`3-z-PK4p} z_om)C+-W8jdInG|o7tJfa`(C*%E{2SY63O+f|c_$4*2p6W|42^g9?hL`pW$ zoB~pLC-VG3JUkt?nAyp>w5s)@muTTdGIk~hZO-*td^I)HXvAa~aPAKwkO9s@ny?|- zifD!xPNfLTQ>jGbY*3L@@e)Za*DiS4&O93wJMO90f!<`;;yfkF9-?)Uzu-Rv zC3pbYz4+Sn5>jX(prZ+&4gg3K(u;xXx62U_gxgWF3i#fpDDo0fcl&ikQU13@i=u|p zI3RT4s&$?Puf+s-5CITS^G76vkjiJ2A*I;lNK6581Em2sDpb1@;w=yU3Zf0JUR(+7piE|SO7Km5;h*j=U@tT#+5dnQ#Y*}qB~TBt6mx|m@ngk_^aQPN4~7QdUopMJ5z@afs8^rA=49=Kc2Y!S!Lt{Q*duY6t2ymB}f3D72yN^ z2zJojhKKLC_!M|z^m%^{bcQxfjD1d?!%ZQL^4EV;K5-tw4>9pc@P6{xg($p^VKkyE9HA#Q%cY2=*a}sZgS=R7MUX@1e(y zI_1sXWl@-d79n=)Ewr&|$0Q{p^ecuZKG!wqk9J+rlpk7*h}?pY20|XxUDx!e9ESdJ z;x!3PEW~T5jasK+Dvcfdk>^dUNN89e5;YA|g?_2vKyn5QiD@I+kXF)0Wv2UjVm~W# zFffJ9A_e^^Y!=)|V`0`HbV6g1I-P)aL8lDiLpOF^(?ukU6FDr#o^IXhi%jcdBr?RG zJY7h&ziR}efz&KQQgo$2P9PnkCC)44pO-i)0$FiD{_&C1Ax^G(Oxvko##!y4ve}L) z26XI8=XS%%q|nuuXlK(b67Wu(0r)IAKoK}f{>k7hlBkF66N8G#$4oz`7Wr6*mL;ix z5b>xqCQ;-AMio&I!6~It#Zkv(`w`-#j(Q5Gffx`Ri^Iw-67U3c0?d;l6GoR%HkVkg zSf_dQ;-!gmm)v-*pnT=<)Y#>#m(QBQKANO6AAUvF?%UVPuZ-Z|#Q333b1F=0*L+bI z1_wTNnmaa8R2Ur!Vy3ok+puxd)9}K?8_p2yIGM@}m@Yz@Vl97*5p7zC1Ph@-T50DN zUe{Fqmnh>Tm&G|X#!oySURp$SO;IG`W>=9swVHu=8yRvH0ku&IiWQp?J_;h7le_JZARmkG6C z1T0n^#^~L|{gZTy4cMh>aD+f>nlDW5{VDkKB#FG6miVxzZ567J* zUypiD5|aoK#E3oc8i-}29P5B1j>ZdZ>8>LM5xbDhI0)@ow%Al0Uql@?9|;(Qe8!%^UUAK1e( zJQ>-~GY*uSHkMx7(|h{{^32o7t@1+MsZHCS>fR<2+mYamhEnR@eddnZ>3!A>JNmEa zVN)yG(YPQ*Epk-hM5s2NQv?!ux`-ALEz4)&qziK*luO{0jixudwZitIMr`swBH_m? zAk{>b;D6aBL5ZM202Cqjh+e?a#a0vJKZ8&*Al?uzus&p9lkdYOtAqQXCn2<7f(S>5 z`~;#drBI+D;i1sM5Hv*m3JuX&1IW?|%y<+t!W%$%x)Bwh_6Iy4y6Qv zGDJXD849CE9P~(H^Gf7W1JuwvM*f3KNIm=I1ljm2?|}+kz4)qGWdakYz5;uwym|_B z2^{Laj@9k=b=+%CeD=!Z$1ed8Yu6d*U2Lqo@o?$npQ(> z;F+Sh6DWq(S&%qx3X|oMj``Onz8WKn8F(%}Q3{smU;j+=t!gBR+p;XB|IX&Q!^SLArpl65WcXNKnP(;A%w~qK)NhB3Pp&9DWIp= zPoP#6!8@TwwYHky7J(BOlM-+Y;S4QMB5m*}lt>p!MCt|s7fPhpd=dSiE_@OEk`g)a zSAdW(NcIPqAw;VvX;6c(O8`1?@=J)#GWst}M>Zh5uIA%fS1X7X;&Xlv}{7#5pE)}SsZ{p@cDr{nf zQi!A}u0$YBG5k_sJ0>qjtdeAm??a1oz9IENdd{vq@3m6Fi|el4joz>VjyaFHMkBSjv(C ze^`S(rNFZR*wyTQA~+;Ldk-LY06A^CPc9mift6zfg93P>KZ0>isHB%d!(^E?$f1Uy zb#1Ov2+|mGH(}-V^d-0jquXj90sZUfD~BgPdLFkrv);S-eIR`9T^MbKSol}dJ~#3k zLex0gxn#^|H1-<+baB51Etqw-;I`_`m#<#FAcE#I#t7;WNyjbu8%L^hx)h|I(X@8; z1po2od!^Y1CuqOvYF>Dl0%(c-dJ$YJrE|>1-H#wwKKv4{2_Y0z0WPT!{aK{T(+Utm z&+vKNtfYJaqCWX7n8^*Aa1Uw1N=zd)gh5FJvI_i-0FVXH%l(st6JH zQm^VC33Lrwk0Rqp!*FJb;2(6AD@dNy59g&H;@S^qXG9mQoY+RF#>$sCVG8Y3MLUR+ zf`!xn#Hi!rQhx(K1U4Qa9y11rb{hS=6&3(;F6?YEs6p2*aWcRhtP_Gf7B1b zzl0Y`rC7cX4HB5=d;=B5f}$Yw zNfg`ZLoif$Y@UHzS$H#?&c4>$zfq(sCQi{+{u~~(GIHav9PE^kLcWJOMY - python3 batch_run_ws_chat.py --token --cases test_cases.json --count 1 -v - python3 batch_run_ws_chat.py --token --save-root ~/桌面/ws-chat-batch - python3 batch_run_ws_chat.py --token --only doc-summary,ppt-generate + python3 batch_run_ws_chat.py + python3 batch_run_ws_chat.py --cases test_cases.json --count 1 -v + python3 batch_run_ws_chat.py --save-root ~/桌面/ws-chat-batch + python3 batch_run_ws_chat.py --only doc-summary,ppt-generate + python3 batch_run_ws_chat.py --token # 也可手动传入;须以 zc 开头 """ from __future__ import annotations @@ -35,6 +36,18 @@ if str(SCRIPT_DIR) not in sys.path: from check_file import expand_output_path, output_exists, resolve_desktop_dir # noqa: E402 from collect_batch_summary import write_batch_summary # noqa: E402 +from get_ws_token import ( # noqa: E402 + DEFAULT_BASE_URL, + DEFAULT_TOKEN_FILE, + http_base_from_ws_url, + require_zc_token, + resolve_gateway_token, +) +from utils.environment import ( # noqa: E402 + collect_environment, + format_environment_lines, + write_environment_file, +) def load_cases(path: Path) -> list[dict[str, Any]]: @@ -93,7 +106,30 @@ def parse_args(argv: list[str] | None = None) -> argparse.Namespace: parser.add_argument( "--token", default=os.environ.get("KYLINBOT_WS_TOKEN") or os.environ.get("KYLINBOT_GATEWAY_TOKEN"), - help="Gateway token. Env: KYLINBOT_WS_TOKEN / KYLINBOT_GATEWAY_TOKEN", + help=( + "Gateway token(须以 zc 开头)。" + "未提供时自动读本地缓存 / 探活 / 必要时重新配对。" + "Env: KYLINBOT_WS_TOKEN / KYLINBOT_GATEWAY_TOKEN" + ), + ) + parser.add_argument( + "--token-file", + default=os.environ.get("KYLINBOT_WS_TOKEN_FILE", str(DEFAULT_TOKEN_FILE)), + help=f"本地明文 token 缓存路径(默认 {DEFAULT_TOKEN_FILE.name})", + ) + parser.add_argument( + "--refresh-token", + action="store_true", + help="忽略本地 token 缓存,强制重新配对并覆盖", + ) + parser.add_argument( + "--gateway-url", + default=os.environ.get("KYLINBOT_GATEWAY_URL"), + help=( + "自动取 token 时使用的 Gateway HTTP 根地址。" + "默认由 --url 推导,或 http://127.0.0.1:42617。" + "Env: KYLINBOT_GATEWAY_URL" + ), ) parser.add_argument( "--url", @@ -262,10 +298,36 @@ def task(argv: list[str] | None = None) -> tuple[int, Path | None]: print(f"bench script not found: {bench_path}", file=sys.stderr) return 2, None if not args.token and not args.dry_run: + gateway_url = args.gateway_url + if not gateway_url: + try: + gateway_url = http_base_from_ws_url(args.url) + except RuntimeError: + gateway_url = DEFAULT_BASE_URL print( - "缺少 --token(或环境变量 KYLINBOT_WS_TOKEN / KYLINBOT_GATEWAY_TOKEN)", + f"未提供 token,使用本地缓存/自动配对(gateway={gateway_url})…", file=sys.stderr, ) + try: + args.token = resolve_gateway_token( + gateway_url, + token_file=args.token_file, + force_refresh=args.refresh_token, + quiet=False, + ) + except RuntimeError as exc: + print(f"错误: {exc}", file=sys.stderr) + print("获取配对码/token 失败,已退出,未执行测试。", file=sys.stderr) + return 2, None + + if args.token: + try: + args.token = require_zc_token(args.token) + except RuntimeError as exc: + print(f"错误: {exc}", file=sys.stderr) + return 2, None + elif not args.dry_run: + print("缺少有效 token", file=sys.stderr) return 2, None cases = load_cases(cases_path) @@ -284,6 +346,17 @@ def task(argv: list[str] | None = None) -> tuple[int, Path | None]: batch_dir = batch_root / f"batch_{stamp}" if not args.dry_run: batch_dir.mkdir(parents=True, exist_ok=True) + environment = collect_environment( + ws_url=args.url, + token=args.token, + model_override=args.model, + ) + env_path = write_environment_file(batch_dir, environment) + print("environment") + for line in format_environment_lines(environment): + print(f" {line}") + print(f" wrote {env_path}") + print() print(f"cases file : {cases_path}") print(f"bench : {bench_path}") diff --git a/kylinbot-auto-test/collect_batch_summary.py b/kylinbot-auto-test/collect_batch_summary.py index 6d162c3..0e51cbf 100644 --- a/kylinbot-auto-test/collect_batch_summary.py +++ b/kylinbot-auto-test/collect_batch_summary.py @@ -10,12 +10,21 @@ from datetime import datetime from pathlib import Path from typing import Any +SCRIPT_DIR = Path(__file__).resolve().parent +if str(SCRIPT_DIR) not in sys.path: + sys.path.insert(0, str(SCRIPT_DIR)) + +from utils.environment import ( # noqa: E402 + enrich_environment_with_runs, + load_environment_file, +) + # Fields kept from each run_summary.json -KEEP_FIELDS = ("timestamp", "url", "message", "samples", "output") +KEEP_FIELDS = ("timestamp", "url", "message", "samples", "output", "model_override") def extract_summary_fields(summary: dict[str, Any]) -> dict[str, Any]: - """Keep only timestamp / url / message / samples from a run summary.""" + """Keep selected fields from a run summary.""" return {key: summary.get(key) for key in KEEP_FIELDS} @@ -47,10 +56,16 @@ def collect_run_summaries(batch_dir: Path) -> dict[str, Any]: entry["path"] = rel runs.append(entry) + environment = enrich_environment_with_runs( + load_environment_file(batch_dir), + runs, + ) + return { "batch_dir": str(batch_dir), "collected_at": datetime.now().isoformat(timespec="seconds"), "count": len(runs), + "environment": environment, "runs": runs, } diff --git a/kylinbot-auto-test/get_ws_token.py b/kylinbot-auto-test/get_ws_token.py new file mode 100644 index 0000000..47698de --- /dev/null +++ b/kylinbot-auto-test/get_ws_token.py @@ -0,0 +1,355 @@ +#!/usr/bin/env python3 +"""自动获取 / 缓存 KylinBot Gateway WebSocket Token(KYLINBOT_WS_TOKEN)。 + +流程: + 1. 本地无 zc_ 明文 → POST /admin/paircode/new + POST /pair → 写入本地缓存 + 2. 本地有明文 → 先使用 + 3. GET /api/status 探活;不可用则重新 pair,并覆盖本地缓存 + +用法示例: + python3 get_ws_token.py + python3 get_ws_token.py --refresh + eval "$(python3 get_ws_token.py --export)" + python3 batch_run_ws_chat.py # 未传 --token 时自动走本逻辑 +""" + +from __future__ import annotations + +import argparse +import json +import os +import stat +import sys +import urllib.error +import urllib.request +from pathlib import Path +from typing import Optional +from urllib.parse import urlparse + + +DEFAULT_BASE_URL = "http://127.0.0.1:42617" +TOKEN_PREFIX = "zc" +SCRIPT_DIR = Path(__file__).resolve().parent +DEFAULT_TOKEN_FILE = SCRIPT_DIR / ".ws_token" + + +def eprint(*args: object) -> None: + print(*args, file=sys.stderr) + + +def parse_args() -> argparse.Namespace: + parser = argparse.ArgumentParser( + description="获取并缓存 KYLINBOT_WS_TOKEN(本地探活,失效则重新配对)", + ) + parser.add_argument( + "--base-url", + default=os.environ.get("KYLINBOT_GATEWAY_URL", DEFAULT_BASE_URL), + help=f"Gateway HTTP 根地址(默认 {DEFAULT_BASE_URL},可用 KYLINBOT_GATEWAY_URL)", + ) + parser.add_argument( + "--token-file", + default=os.environ.get("KYLINBOT_WS_TOKEN_FILE", str(DEFAULT_TOKEN_FILE)), + help=f"本地明文 token 缓存路径(默认 {DEFAULT_TOKEN_FILE.name})", + ) + parser.add_argument( + "--timeout", + type=float, + default=30.0, + help="HTTP 超时秒数(默认 30)", + ) + parser.add_argument( + "--refresh", + action="store_true", + help="忽略本地缓存,强制重新配对并覆盖", + ) + parser.add_argument( + "--export", + action="store_true", + help="输出可 eval 的 export KYLINBOT_WS_TOKEN=... 语句", + ) + parser.add_argument( + "-q", + "--quiet", + action="store_true", + help="减少 stderr 日志", + ) + return parser.parse_args() + + +def normalize_base_url(url: str) -> str: + return url.rstrip("/") + + +def http_base_from_ws_url(ws_url: str) -> str: + """ws://host:port/ws/chat -> http://host:port""" + parsed = urlparse(ws_url) + scheme = "https" if parsed.scheme in ("wss", "https") else "http" + if not parsed.hostname: + raise RuntimeError(f"无法从 WebSocket URL 解析主机: {ws_url}") + netloc = parsed.hostname + if parsed.port: + netloc = f"{netloc}:{parsed.port}" + return f"{scheme}://{netloc}" + + +def http_json( + method: str, + url: str, + *, + headers: Optional[dict[str, str]] = None, + timeout: float = 30.0, +) -> dict: + status, data = http_json_with_status( + method, url, headers=headers, timeout=timeout + ) + if status >= 400: + raise RuntimeError( + f"HTTP {status} {method} {url}\n" + f"{json.dumps(data, ensure_ascii=False) if data else ''}".strip() + ) + return data + + +def http_json_with_status( + method: str, + url: str, + *, + headers: Optional[dict[str, str]] = None, + timeout: float = 30.0, +) -> tuple[int, dict]: + req = urllib.request.Request(url, method=method, headers=headers or {}) + try: + with urllib.request.urlopen(req, timeout=timeout) as resp: + body = resp.read().decode("utf-8", errors="replace") + status = getattr(resp, "status", 200) + except urllib.error.HTTPError as exc: + err_body = exc.read().decode("utf-8", errors="replace") + try: + data = json.loads(err_body) if err_body.strip() else {} + except json.JSONDecodeError: + data = {"error": err_body.strip()} if err_body.strip() else {} + if not isinstance(data, dict): + data = {"error": err_body.strip()} + return exc.code, data + except urllib.error.URLError as exc: + raise RuntimeError(f"无法连接 {url}: {exc.reason}") from exc + except TimeoutError as exc: + raise RuntimeError(f"请求超时 {url} (timeout={timeout}s)") from exc + + try: + data = json.loads(body) if body.strip() else {} + except json.JSONDecodeError as exc: + raise RuntimeError( + f"响应不是 JSON (HTTP {status} {method} {url}):\n{body.strip()}" + ) from exc + + if not isinstance(data, dict): + raise RuntimeError(f"期望 JSON object,实际: {type(data).__name__}") + return status, data + + +def fetch_pair_code(base_url: str, timeout: float) -> str: + """POST /admin/paircode/new;失败立即报错退出,不继续换 token。""" + url = f"{base_url}/admin/paircode/new" + try: + data = http_json("POST", url, timeout=timeout) + except RuntimeError as exc: + raise RuntimeError( + "获取配对码失败。请确认 KylinBot Gateway 已启动," + f"且本机可访问 {url}\n" + f"原因: {exc}" + ) from exc + + code = data.get("pairing_code") + if code is None or str(code).strip() == "": + message = data.get("message") or data.get("error") or json.dumps( + data, ensure_ascii=False + ) + raise RuntimeError( + "获取配对码失败:接口未返回 pairing_code。" + f"请确认 gateway 已开启 pairing。详情: {message}" + ) + + code = str(code).strip() + if not code.isdigit(): + raise RuntimeError(f"获取配对码失败:pairing_code 格式异常: {code!r}") + return code + + +def exchange_token(base_url: str, pair_code: str, timeout: float) -> str: + url = f"{base_url}/pair" + data = http_json( + "POST", + url, + headers={"X-Pairing-Code": pair_code}, + timeout=timeout, + ) + token = data.get("token") + if not token: + message = data.get("message") or data.get("error") or json.dumps( + data, ensure_ascii=False + ) + raise RuntimeError(f"/pair 未返回 token: {message}") + return str(token).strip() + + +def require_zc_token(token: str) -> str: + token = (token or "").strip() + if not token: + raise RuntimeError("token 为空") + if not token.startswith(TOKEN_PREFIX): + raise RuntimeError( + f"token 必须以 {TOKEN_PREFIX!r} 开头,当前前缀: {token[:8]!r}" + ) + return token + + +def load_cached_token(token_file: Path) -> Optional[str]: + if not token_file.is_file(): + return None + try: + raw = token_file.read_text(encoding="utf-8").strip() + except OSError as exc: + raise RuntimeError(f"读取本地 token 失败: {token_file}: {exc}") from exc + if not raw: + return None + # 只取第一行,避免误粘贴多行 + first = raw.splitlines()[0].strip() + try: + return require_zc_token(first) + except RuntimeError: + return None + + +def save_cached_token(token_file: Path, token: str) -> None: + token = require_zc_token(token) + token_file.parent.mkdir(parents=True, exist_ok=True) + token_file.write_text(token + "\n", encoding="utf-8") + try: + os.chmod(token_file, stat.S_IRUSR | stat.S_IWUSR) + except OSError: + # Windows 等平台可能不支持 chmod,忽略 + pass + + +def token_is_alive( + base_url: str, + token: str, + *, + timeout: float = 30.0, + quiet: bool = False, +) -> bool: + """GET /api/status 探活。连不上 gateway 直接抛错;401/403 等视为不可用。""" + url = f"{normalize_base_url(base_url)}/api/status" + if not quiet: + eprint(f"[get_ws_token] 探活 GET {url}") + try: + status, data = http_json_with_status( + "GET", + url, + headers={"Authorization": f"Bearer {token}"}, + timeout=timeout, + ) + except RuntimeError as exc: + raise RuntimeError( + f"探活失败(无法访问 gateway)。请确认 Gateway 已启动。\n原因: {exc}" + ) from exc + + if status == 200: + if not quiet: + eprint("[get_ws_token] 本地 token 可用") + return True + + if not quiet: + detail = data.get("error") or data.get("message") or json.dumps( + data, ensure_ascii=False + ) + eprint(f"[get_ws_token] 本地 token 不可用 (HTTP {status}): {detail}") + return False + + +def obtain_gateway_token( + base_url: str = DEFAULT_BASE_URL, + *, + timeout: float = 30.0, + quiet: bool = False, +) -> str: + """申请配对码并换取 token,校验后返回。配对码获取失败则直接抛错。""" + base_url = normalize_base_url(base_url) + if not quiet: + eprint(f"[get_ws_token] POST {base_url}/admin/paircode/new") + + pair_code = fetch_pair_code(base_url, timeout) + + if not quiet: + eprint(f"[get_ws_token] 配对码: {pair_code}") + eprint(f"[get_ws_token] POST {base_url}/pair") + + try: + token = exchange_token(base_url, pair_code, timeout) + except RuntimeError as exc: + raise RuntimeError(f"用配对码换取 token 失败: {exc}") from exc + + token = require_zc_token(token) + if not quiet: + eprint("[get_ws_token] 成功获取 token") + return token + + +def resolve_gateway_token( + base_url: str = DEFAULT_BASE_URL, + *, + token_file: Path | str = DEFAULT_TOKEN_FILE, + timeout: float = 30.0, + force_refresh: bool = False, + quiet: bool = False, +) -> str: + """读取本地缓存 → 探活 → 必要时重新配对并覆盖缓存。""" + base_url = normalize_base_url(base_url) + path = Path(token_file).expanduser() + + if not force_refresh: + cached = load_cached_token(path) + if cached: + if not quiet: + eprint(f"[get_ws_token] 使用本地缓存: {path}") + if token_is_alive(base_url, cached, timeout=timeout, quiet=quiet): + return cached + if not quiet: + eprint("[get_ws_token] 缓存失效,重新配对并覆盖本地文件") + elif not quiet: + eprint(f"[get_ws_token] 本地无有效缓存: {path}") + elif not quiet: + eprint("[get_ws_token] --refresh:强制重新配对") + + token = obtain_gateway_token(base_url, timeout=timeout, quiet=quiet) + save_cached_token(path, token) + if not quiet: + eprint(f"[get_ws_token] 已写入本地缓存: {path}") + return token + + +def main() -> int: + args = parse_args() + try: + token = resolve_gateway_token( + args.base_url, + token_file=args.token_file, + timeout=args.timeout, + force_refresh=args.refresh, + quiet=args.quiet, + ) + except RuntimeError as exc: + eprint(f"错误: {exc}") + return 1 + + if args.export: + safe = token.replace("'", "'\"'\"'") + print(f"export KYLINBOT_WS_TOKEN='{safe}'") + else: + print(token) + return 0 + + +if __name__ == "__main__": + sys.exit(main()) diff --git a/kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc b/kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc new file mode 100644 index 0000000000000000000000000000000000000000..040fb07cf770618ce4581791c9ca0b1ee722d21b GIT binary patch literal 5792 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 aOjJtxe;uLbYyJ5U`RE({l{rT+q0FcU}s literal 0 HcmV?d00001 diff --git a/kylinbot-auto-test/utils/environment.py b/kylinbot-auto-test/utils/environment.py new file mode 100644 index 0000000..f2e9a64 --- /dev/null +++ b/kylinbot-auto-test/utils/environment.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python3 +"""采集批次运行环境信息(写入 batch_summary.environment / Web 展示)。""" + +from __future__ import annotations + +import json +import platform +import re +import subprocess +import sys +from datetime import datetime +from pathlib import Path +from typing import Any, Optional +from urllib.error import HTTPError, URLError +from urllib.parse import urlparse +from urllib.request import Request, urlopen + + +ENV_FILENAME = "environment.json" + + +def _ws_to_http_origin(ws_url: str) -> str: + parsed = urlparse(ws_url) + scheme = "https" if parsed.scheme in ("wss", "https") else "http" + if not parsed.hostname: + raise ValueError(f"invalid WebSocket URL: {ws_url}") + netloc = parsed.hostname + if parsed.port: + netloc = f"{netloc}:{parsed.port}" + return f"{scheme}://{netloc}" + + +def get_kylin_bot_dpkg_version() -> Optional[str]: + """通过 `dpkg -s kylin-bot` 解析 Version 字段。""" + try: + completed = subprocess.run( + ["dpkg", "-s", "kylin-bot"], + check=False, + capture_output=True, + text=True, + timeout=10, + ) + except (OSError, subprocess.TimeoutExpired): + return None + + text = (completed.stdout or "") + "\n" + (completed.stderr or "") + for line in text.splitlines(): + if line.lower().startswith("version:"): + return line.split(":", 1)[1].strip() or None + # 兼容 grep Version 风格的单行输出 + match = re.search(r"(?im)^Version:\s*(.+)$", text) + if match: + return match.group(1).strip() or None + return None + + +def get_python_version() -> str: + return ( + f"{sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro} " + f"({platform.python_implementation()})" + ) + + +def fetch_gateway_status( + ws_url: str, + token: Optional[str], + *, + timeout: float = 15.0, +) -> dict[str, Any]: + origin = _ws_to_http_origin(ws_url) + url = f"{origin}/api/status" + headers = {"Accept": "application/json"} + if token: + headers["Authorization"] = f"Bearer {token.strip()}" + req = Request(url, headers=headers, method="GET") + try: + with urlopen(req, timeout=timeout) as resp: + body = resp.read().decode("utf-8", errors="replace") + data = json.loads(body) + return data if isinstance(data, dict) else {"raw": data} + except HTTPError as exc: + detail = exc.read().decode("utf-8", errors="replace")[:300] + return {"error": f"HTTP {exc.code}", "detail": detail} + except (URLError, TimeoutError, json.JSONDecodeError, OSError, ValueError) as exc: + return {"error": str(exc)} + + +def collect_environment( + *, + ws_url: str, + token: Optional[str] = None, + model_override: Optional[str] = None, + gateway_status: Optional[dict[str, Any]] = None, +) -> dict[str, Any]: + """采集环境基础信息。""" + status = gateway_status if gateway_status is not None else fetch_gateway_status( + ws_url, token + ) + status_ok = isinstance(status, dict) and "error" not in status + + env: dict[str, Any] = { + "collected_at": datetime.now().isoformat(timespec="seconds"), + "kylinbot_version": get_kylin_bot_dpkg_version(), + "kylinbot_version_source": "dpkg -s kylin-bot | grep Version", + "python_version": get_python_version(), + "provider": status.get("provider") if status_ok else None, + "model": status.get("model") if status_ok else None, + "temperature": status.get("temperature") if status_ok else None, + "model_override": (model_override or None), + "gateway_status_error": None if status_ok else status.get("error") or status, + "ws_url": ws_url, + } + return env + + +def derive_actual_models(runs: list[dict[str, Any]]) -> dict[str, Any]: + """从 runs/samples 汇总实际用到的 provider / model。""" + providers: set[str] = set() + models: set[str] = set() + for run in runs: + samples = run.get("samples") if isinstance(run, dict) else None + if not isinstance(samples, list): + continue + for sample in samples: + if not isinstance(sample, dict): + continue + if sample.get("provider"): + providers.add(str(sample["provider"])) + if sample.get("model"): + models.add(str(sample["model"])) + return { + "actual_providers": sorted(providers), + "actual_models": sorted(models), + } + + +def enrich_environment_with_runs( + environment: dict[str, Any] | None, + runs: list[dict[str, Any]], +) -> dict[str, Any]: + env = dict(environment or {}) + env.update(derive_actual_models(runs)) + return env + + +def write_environment_file(batch_dir: Path, environment: dict[str, Any]) -> Path: + path = batch_dir / ENV_FILENAME + path.write_text( + json.dumps(environment, ensure_ascii=False, indent=2, default=str), + encoding="utf-8", + ) + return path + + +def load_environment_file(batch_dir: Path) -> Optional[dict[str, Any]]: + path = batch_dir / ENV_FILENAME + if not path.is_file(): + return None + try: + data = json.loads(path.read_text(encoding="utf-8")) + except (OSError, json.JSONDecodeError): + return None + return data if isinstance(data, dict) else None + + +def format_environment_lines(environment: dict[str, Any]) -> list[str]: + """终端打印用的多行摘要。""" + override = environment.get("model_override") + actual_models = environment.get("actual_models") or [] + actual_providers = environment.get("actual_providers") or [] + lines = [ + f"kylinbot 版本 : {environment.get('kylinbot_version') or 'unknown'}", + f"Python 版本 : {environment.get('python_version') or 'unknown'}", + f"默认 provider : {environment.get('provider') or 'unknown'}", + f"默认 model : {environment.get('model') or 'unknown'}", + f"temperature : {environment.get('temperature') if environment.get('temperature') is not None else 'unknown'}", + ] + if override: + lines.append(f"model override: {override}") + if actual_models: + lines.append(f"实际 models : {', '.join(actual_models)}") + if actual_providers: + lines.append(f"实际 providers: {', '.join(actual_providers)}") + if environment.get("gateway_status_error"): + lines.append(f"gateway status: error ({environment['gateway_status_error']})") + return lines diff --git a/kylinbot-auto-test/web/app.js b/kylinbot-auto-test/web/app.js index 6d6d74b..493feca 100644 --- a/kylinbot-auto-test/web/app.js +++ b/kylinbot-auto-test/web/app.js @@ -7,6 +7,7 @@ collectedAt: $("collectedAt"), batchDir: $("batchDir"), runCount: $("runCount"), + envSummary: $("envSummary"), statPass: $("statPass"), statFail: $("statFail"), statSamples: $("statSamples"), @@ -78,6 +79,44 @@ return rows; } + function displayValue(value) { + if (value == null || value === "") return "未知"; + if (Array.isArray(value)) { + return value.length ? value.join("、") : "未知"; + } + return String(value); + } + + function pickUsedModel(env) { + if (env.model_override) return env.model_override; + if (Array.isArray(env.actual_models) && env.actual_models.length) { + return env.actual_models.join("、"); + } + return env.model; + } + + function renderEnvironment(data) { + const el = els.envSummary; + if (!el) return; + const env = data?.environment && typeof data.environment === "object" + ? data.environment + : null; + if (!env) { + el.textContent = "暂无运行环境信息。"; + return; + } + const version = displayValue(env.kylinbot_version); + const python = displayValue(env.python_version); + const model = displayValue(pickUsedModel(env)); + const temperature = + env.temperature == null || env.temperature === "" + ? "未知" + : String(env.temperature); + el.textContent = + `本次测试环境:kylinbot 版本 ${version},Python 版本 ${python},` + + `使用模型 ${model},temperature ${temperature}。`; + } + function renderMeta(data) { els.collectedAt.textContent = fmtTime(data.collected_at); els.batchDir.textContent = data.batch_dir || "—"; @@ -201,6 +240,7 @@ function render(data, source) { const rows = flattenRows(data); renderMeta(data); + renderEnvironment(data); renderStats(rows); renderChart(rows); renderTable(rows); diff --git a/kylinbot-auto-test/web/data/batch_summary.json b/kylinbot-auto-test/web/data/batch_summary.json index 877c3b1..4ef7fe5 100644 --- a/kylinbot-auto-test/web/data/batch_summary.json +++ b/kylinbot-auto-test/web/data/batch_summary.json @@ -2,6 +2,22 @@ "batch_dir": "/home/greatwall/桌面/ws-chat-batch/batch_20260821_150645", "collected_at": "2026-08-21T15:15:29", "count": 2, + "environment": { + "collected_at": "2026-08-21T15:06:45", + "kylinbot_version": "1.0.0-1", + "kylinbot_version_source": "dpkg -s kylin-bot | grep Version", + "python_version": "3.12.3 (CPython)", + "provider": "custom:https://dashscope.aliyuncs.com/compatible-mode/v1", + "model": "qwen3.7-plus", + "temperature": 0.7, + "model_override": null, + "gateway_status_error": null, + "ws_url": "ws://127.0.0.1:42617/ws/chat", + "actual_providers": [ + "custom:https://dashscope.aliyuncs.com/compatible-mode/v1" + ], + "actual_models": ["qwen3.7-plus"] + }, "runs": [ { "timestamp": "2026-08-21T15:12:20+08:00", diff --git a/kylinbot-auto-test/web/index.html b/kylinbot-auto-test/web/index.html index 385aa80..1f7c1ae 100644 --- a/kylinbot-auto-test/web/index.html +++ b/kylinbot-auto-test/web/index.html @@ -29,6 +29,13 @@

+
+
+

运行环境

+
+

—

+
+
采集时间 diff --git a/kylinbot-auto-test/web/styles.css b/kylinbot-auto-test/web/styles.css index f4577f1..0af2aad 100644 --- a/kylinbot-auto-test/web/styles.css +++ b/kylinbot-auto-test/web/styles.css @@ -179,6 +179,25 @@ h1 { overflow: hidden; } +.env-panel { + margin-bottom: 1rem; + padding: 0; + overflow: hidden; + animation: rise 0.5s ease both; +} + +.env-panel .panel-head { + padding: 1.1rem 1.2rem 0.2rem; +} + +.env-summary { + margin: 0; + padding: 0.35rem 1.2rem 1.15rem; + color: var(--ink); + font-size: 0.98rem; + line-height: 1.7; +} + .stats { display: grid; grid-template-columns: repeat(4, minmax(0, 1fr)); -- Gitee From ce74d5bac7aa056a298d44adfc725b1a0e71106a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=8A=A0=E9=B9=8F?= Date: Tue, 8 Sep 2026 18:09:47 +0800 Subject: [PATCH 2/4] =?UTF-8?q?1.=20=E5=88=A0=E9=99=A4=E5=8E=8B=E7=BC=A9?= =?UTF-8?q?=E5=8C=85=202.=20README.md=E7=A7=BB=E5=8A=A8=E5=88=B0=E9=A1=B9?= =?UTF-8?q?=E7=9B=AE=E6=A0=B9=E7=9B=AE=E5=BD=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kylinbot-auto-test/README.md => README.md | 0 kylinbot-auto-test.zip | Bin 61192 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) rename kylinbot-auto-test/README.md => README.md (100%) delete mode 100644 kylinbot-auto-test.zip diff --git a/kylinbot-auto-test/README.md b/README.md similarity index 100% rename from kylinbot-auto-test/README.md rename to README.md diff --git a/kylinbot-auto-test.zip b/kylinbot-auto-test.zip deleted file mode 100644 index 63721c9165f64bf2f2a584b231e33e0070b786b5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 61192 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

+2>GIud2|N%hKHK~@b*E(&CX^zNw#mMqT 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 -- Gitee From d8c6c277e69674dc51b2e0bb7f880cb4f32eabc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=99=88=E5=8A=A0=E9=B9=8F?= Date: Tue, 8 Sep 2026 20:08:56 +0800 Subject: [PATCH 3/4] =?UTF-8?q?1.=E5=88=A0=E9=99=A4python=E4=B8=AD?= =?UTF-8?q?=E9=97=B4=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- kylinbot-auto-test/.gitignore | 29 ++++++++++++++++++ .../batch_run_ws_chat.cpython-39.pyc | Bin 14834 -> 0 bytes .../collect_batch_summary.cpython-39.pyc | Bin 3438 -> 0 bytes .../__pycache__/get_ws_token.cpython-39.pyc | Bin 9826 -> 0 bytes 4 files changed, 29 insertions(+) delete mode 100644 kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc delete mode 100644 kylinbot-auto-test/__pycache__/collect_batch_summary.cpython-39.pyc delete mode 100644 kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc diff --git a/kylinbot-auto-test/.gitignore b/kylinbot-auto-test/.gitignore index 32a6a1c..d20a88e 100644 --- a/kylinbot-auto-test/.gitignore +++ b/kylinbot-auto-test/.gitignore @@ -1 +1,30 @@ .ws_token + +# Python +__pycache__/ +*.py[cod] +*$py.class +*.so +.Python +*.egg-info/ +.eggs/ +dist/ +build/ +*.egg + +# Virtual environments +.venv/ +venv/ +env/ + +# Testing / coverage / type check caches +.pytest_cache/ +.mypy_cache/ +.ruff_cache/ +.coverage +htmlcov/ +.tox/ +.cache/ + +# Jupyter +.ipynb_checkpoints/ diff --git a/kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc b/kylinbot-auto-test/__pycache__/batch_run_ws_chat.cpython-39.pyc deleted file mode 100644 index 5f46ca3b09889b8da2da8c0deeca24d4c63d22a1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14834 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 diff --git a/kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc b/kylinbot-auto-test/__pycache__/get_ws_token.cpython-39.pyc deleted file mode 100644 index e67f0308e2cd1651ec2b75f86d97c758e81f7003..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9826 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 Date: Tue, 8 Sep 2026 20:10:44 +0800 Subject: [PATCH 4/4] =?UTF-8?q?1.=E5=88=A0=E9=99=A4python=E4=B8=AD?= =?UTF-8?q?=E9=97=B4=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../utils/__pycache__/environment.cpython-39.pyc | Bin 5792 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc diff --git a/kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc b/kylinbot-auto-test/utils/__pycache__/environment.cpython-39.pyc deleted file mode 100644 index 040fb07cf770618ce4581791c9ca0b1ee722d21b..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5792 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 aOjJtxe;uLbYyJ5U`RE({l{rT+q0FcU}s -- Gitee