Selaa lähdekoodia

chore: 删除走不到的卡片引导链;asr 移出 three-libs(用户要求)

用户要求:① 判断 initToken() / openid_to_token / VITE_APP_KEY 删了是否影响现用功能,无影响就删;
② 把 ASR 文件夹移出来,然后删除 three-libs 文件夹。

① 影响评估(先查再删):
- index.html 的结构是 if (isKnowledgeApi) { 写死「政策解读」cardInfo } else { initToken(); },
  而两个环境(development / production)都是 VITE_USE_KNOWLEDGE_API=true —— else 永远走不到;
- 就算走到:initToken 的产物 globalThis.token 与 initCardInfo 的产物 globalThis.cardInfo
  全仓库没有任何读者(只 grep 到赋值);hasSequence 与 dataLoaded/sequenceLoaded 两个事件
  在 if 分支里同样会发;
- 顺带发现那段本身就是坏的:initCardInfo 里调用 globalThis.changeLoadingText /
  globalThis.showReloadView,而这两个函数从未挂到 globalThis → 一旦走到就 TypeError;
- ⇒ 删掉不影响现用功能。
删除内容:initToken / initCardInfo / else 分支 + 随之孤儿的 randomString / changeLoadingText /
showReloadView + 两份 env 的 VITE_APP_KEY。产物核对:app_key / openid_to_token 0 命中。

② asr 搬家:git mv src/three-libs/asr src/asr,删除 src/three-libs/(目录名有误导性,
清理后只剩 asr 一个子目录)。同步改两个壳组件的 import(@/asr/nls)、nls-protocol.ts 的自引用注释、
harness/tools/_entry-nls.ts 的入口路径,验证脚本新增两条断言(three-libs 已删、asr 在 src/asr)。

验证:npm run build 通过;dist/redirect.html 的 redirectMap 仍有值;
verify-nls-realtime 43 → 44/44;附件 57/57、toast 27/27、DMS 字段契约 19/19、
DMS 端到端 89/89、validate-harness 通过;vue-tsc 除既有 webpack-env 外无错误。
文档同步:architecture(目录树 + 搬家沿革)、asr-nls、current-api-call-sites、asr-realtime
(历史文档里指向已删文件的链接改为纯文本)。

Co-Authored-By: Claude Code <noreply@anthropic.com>
gongtianxiao 1 kuukausi sitten
vanhempi
sitoutus
446b03a8f8

+ 0 - 1
.env.development

@@ -3,7 +3,6 @@ VITE_VERSION=${npm_package_version}
 # VITE_API="//human-card-mini.metamaker.cn"
 # VITE_API="//fifth-hospital.test.metamaker.cn"
 VITE_API="//qingpu-data-api.metamaker.cn"
-VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
 VITE_MODEL_SERVER="https://qingpu-data-api.metamaker.cn/llms/qingpu"
 
 # VITE_API="/api"

+ 0 - 1
.env.production

@@ -2,7 +2,6 @@ VITE_VERSION=${npm_package_version}
 VITE_API="//qingpu-data-api.metamaker.cn"
 # 政策库来源顺序:false = 远端优先、本地兜底(见 index.html)
 VITE_POLICY_LOCAL_FIRST="false"
-VITE_APP_KEY="e61a4f61170a4b2f8f88ee946e2e635b"
 VITE_PARENT_ORIGIN = 'https://aixq.shqp.gov.cn/'
 VITE_MODEL_SERVER="https://qingpu-data-api.metamaker.cn/llms/qingpu"
 VITE_USE_KNOWLEDGE_API=true

+ 9 - 1
README.md

@@ -422,6 +422,14 @@
     `harness/tools/get-nls-token.mjs` 与 dev 端点共用;带 5 分钟提前刷新 + 并发去重
   - 验证:端点 200;**拿端点发的 token 真调通一次识别**(`status:20000000 SUCCESS`);
     `npm run build` 后**产物里搜三个凭据值 0 命中**
+- **删掉走不到的卡片引导链 + asr 搬家**(用户 2026-09-24):
+  - `index.html` 的 `initToken()` / `initCardInfo()` / `else` 分支:**两个环境都走不到**
+    (`isKnowledgeApi` 恒 true),且它们的产物(`globalThis.token` / `cardInfo`)**全仓库无读者**;
+    那段本身还是坏的(调用从未挂到 globalThis 的 `changeLoadingText`/`showReloadView`,走到会抛)。
+    一并删掉随之孤儿的 `randomString` / `changeLoadingText` / `showReloadView` 与
+    `VITE_APP_KEY`(产物核对:`app_key` / `openid_to_token` 0 命中)
+  - `src/three-libs/asr/` → **`src/asr/`**,`three-libs/` 目录删除(名字有误导性,且只剩 asr 一个子目录);
+    import 同步为 `@/asr/nls`,验证脚本新增断言钉住新位置
 - **环境只保留开发与生产**(用户 2026-09-24):删掉 qingpu / test 两个构建模式 ——
   `.env.qingpu` / `.env.test` 删除前,先把它俩**独有的配置合并进 `.env.production`**:
   `VITE_DOWNLOAD_URL="/api/download/"` 与 **`VITE_REDIRECT_MAP`**(后者 production 原本没有,
@@ -444,7 +452,7 @@
   - 教训记档:删文件要按**导出的符号名**反查引用(只查 import 路径会漏 ——
     `components/utils.ts` 因此被误删,构建报错才发现,已恢复)
 - **实时语音识别已切到阿里云 NLS**(2026-09-23,接管旧厂商 SDK):
-  - 协议层 `src/three-libs/asr/nls-protocol.ts`(纯函数:帧构建 / 事件折叠 / 16k PCM 编码)
+  - 协议层 `src/asr/nls-protocol.ts`(纯函数:帧构建 / 事件折叠 / 16k PCM 编码)
     + 类 `src/three-libs/asr/nls.ts`,**对外契约与旧 SDK 一致** → 两个壳组件只改了 import
     与一处构造参数(去掉硬编码 appKey),其余一行没动
   - **协议是实测出来的**:`StartTranscription`→`TranscriptionStarted`→二进制音频帧→

+ 5 - 5
harness/docs/architecture.md

@@ -16,12 +16,12 @@
   `src/components/api-chat-coordinator.ts` 翻译成既有渲染组件可识别的内容标记。
   详见 [`reference/api-chat.md`](reference/api-chat.md)。
 - **没有 3D 虚拟人渲染**。`three` 仅用于粒子背景(`business-assistant-particle.ts`);
-  **`src/three-libs/` 下有且只有一个模块:`asr/`(2026-09-24 起只剩 NLS 实现 `nls.ts` / `nls-protocol.ts`)**
-  (PC 与移动端都 `import ASR from '@/three-libs/asr/index'`,点麦克风就走它)。
+  语音识别在 **`src/asr/`**(`nls.ts` 采集与连接 + `nls-protocol.ts` 纯函数协议层),
+  PC 与移动端都 `import ASR from '@/asr/nls'`,点麦克风就走它。
   现行实现(**阿里云 NLS 直连**,2026-09-23 起)见 [`reference/asr-nls.md`](reference/asr-nls.md);
   换之前那套(厂商 `asr_hub` 中转)的记录见 [`reference/asr-realtime.md`](reference/asr-realtime.md)。
-  > 注:本文曾写「`src/three-libs/metamaker` 是未被引用的 SDK 包」——**那个目录不存在**,
-  > 2026-09-18 核查时已更正。目录名 `three-libs` 有误导性:它与 three.js 无关。
+  > 目录沿革:原先在 `src/three-libs/asr/`。**2026-09-24 用户要求把 asr 移出来、删掉 `three-libs/`**
+  > —— 那个目录名有误导性(与 three.js 无关),且 2026-09-24 清理后它只剩 asr 一个子目录。
 - **没有状态管理库**(无 Vuex / Pinia)。对话状态在 `useBusinessAssistantChat` 组合式函数内,
   会话与消息持久化到 `localStorage`。
 - **没有 `src/hooks/` 目录**;也**没有** `stream-message-coordinator-v2.ts`。
@@ -58,7 +58,7 @@ src/
 ├── network/api/                 接口封装(chat-sessions、enterprise、assistant-statistics、card)
 ├── types/                       TypeScript 类型定义
 ├── utils/                       工具(runtime-config、stream-xml-filter、scope-record-rows…)
-└── three-libs/asr/              语音识别
+└── asr/                         语音识别(NLS:nls.ts + nls-protocol.ts)
 ```
 
 ## 核心系统

+ 3 - 3
harness/docs/reference/asr-nls.md

@@ -30,8 +30,8 @@ token 由**后端网关**签发(2026-09-24 起,用户指定):
 | 件 | 在哪 |
 |---|---|
 | 前端取 token(带缓存) | [`src/network/api/nls-token.ts`](../../../src/network/api/nls-token.ts) |
-| 协议层(**纯函数**,可被 harness 测) | [`src/three-libs/asr/nls-protocol.ts`](../../../src/three-libs/asr/nls-protocol.ts) |
-| 采集与连接(**对外契约与旧 SDK 一致**) | [`src/three-libs/asr/nls.ts`](../../../src/three-libs/asr/nls.ts) |
+| 协议层(**纯函数**,可被 harness 测) | [`src/asr/nls-protocol.ts`](../../../src/asr/nls-protocol.ts) |
+| 采集与连接(**对外契约与旧 SDK 一致**) | [`src/asr/nls.ts`](../../../src/asr/nls.ts) |
 | 取 token 的三种来源(工具侧统一入口) | [`harness/tools/nls-token.mjs`](../../tools/nls-token.mjs):显式 `NLS_TOKEN` → **网关** → AK/SK 自签(退路) |
 | 验证脚本 | [`harness/tools/verify-nls-realtime.mjs`](../../tools/verify-nls-realtime.mjs)(42 项,含真实识别) |
 | 探针(读原始帧用) | [`harness/tools/probe-nls-realtime.mjs`](../../tools/probe-nls-realtime.mjs) |
@@ -161,7 +161,7 @@ node harness/tools/probe-nls-realtime.mjs --say="青浦区高新技术企业奖
 
 - ✅ 协议层、类、token 通路都已实现并**打真实网关验证通过**(39/39,含真实识别)
 - ✅ **两个壳组件已切过来**(2026-09-23):`BusinessAssistantPC.vue` / `BusinessAssistantMobile.vue`
-  改为 `import ASR from '@/three-libs/asr/nls'`,并把构造函数里的硬编码 appKey 去掉
+  改为 `import ASR from '@/asr/nls'`(2026-09-24 前是 `@/three-libs/asr/nls`),并把构造函数里的硬编码 appKey 去掉
   (appkey 由端点下发)。契约一致,所以除了 import 与那一处构造参数,**其余一行没改**
   —— 有源码级断言守着(`verify-nls-realtime.mjs` 的【4】)
 - ⏳ **需要用户在浏览器实测一次**:点麦克风说一句 → 输入框应边说边出字;再点一次停止 →

+ 3 - 3
harness/docs/reference/asr-realtime.md

@@ -27,7 +27,7 @@
 
 | 是什么 | 在哪 |
 |---|---|
-| SDK(全部实现,含协议细节) | [`src/three-libs/asr/index.ts`](../../../src/three-libs/asr/index.ts) |
+| SDK(全部实现,含协议细节) | `src/three-libs/asr/index.ts`(已删) |
 | 事件基类(mitt 封装) | [`src/utils/base-event.ts`](../../../src/utils/base-event.ts) |
 | 移动端调用点 | `BusinessAssistantMobile.vue` 的 `toggleVoiceInput` / `stopVoiceInput` / `releaseVoiceInputInstance` |
 | 桌面端调用点 | `BusinessAssistantPC.vue` 的同名三函数 + `drawWave`(波形) |
@@ -152,8 +152,8 @@ token 由 `POST {VITE_XF_ASR}/api/human_asr/v2/asr/gen_auth {app_key}` 换取。
 
 1. `getUserMedia` 拿到麦克风流 → `MediaStreamAudioSourceNode` → `ScriptProcessorNode`
    (`createScriptProcessor(0, 1, 1)`,bufferSize 传 0 让浏览器自选;**该 API 已废弃**)。
-2. 每个回调把 `Float32` 采样 → [`to16kHZ()`](../../../src/three-libs/asr/index.ts)(线性插值重采样)
-   → [`to16BitPCM()`](../../../src/three-libs/asr/index.ts)(钳到 ±1 后转 int16 小端)→ 推入 `audioData`。
+2. 每个回调把 `Float32` 采样 → `to16kHZ()`(原 asr/index.ts,已删)(线性插值重采样)
+   → `to16BitPCM()`(同上,已删)(钳到 ±1 后转 int16 小端)→ 推入 `audioData`。
 3. 定时器每 **80ms** 检查一次:非讯飞分支**攒够 5120 字节(= 2560 采样 = 160ms 音频)才发一帧**,
    作为二进制帧发出。也就是说端到端延迟由"满 160ms"决定,不是每 80ms 都发。
    - 5120 = `1280 × 4`;讯飞分支的发帧间隔是 40ms、块大小 1280 字节。

+ 5 - 4
harness/docs/reference/current-api-call-sites.md

@@ -17,7 +17,7 @@
 | 3 | `{VITE_DMS_API}/content/*` | DMS 读写(1886/1887/1888/1889 会话·问答·反馈·企业信息) | `src/network/api/dms/client.ts` |
 | 4 | `POST {VITE_DMS_API}/file/uploadFile` | 附件上传到 DMS 文件服务 | `src/network/api/dms/file-upload.ts` |
 | 5 | `GET {VITE_NLS_TOKEN_API}`(→ `http://121.43.55.7:10011/proxy/verify/getALYToken`) | 语音识别的 token(后端网关签发) | `src/network/api/nls-token.ts` |
-| 6 | `wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1` | 实时语音识别(阿里云 NLS) | `src/three-libs/asr/nls.ts` |
+| 6 | `wss://nls-gateway-cn-shanghai.aliyuncs.com/ws/v1` | 实时语音识别(阿里云 NLS) | `src/asr/nls.ts` |
 | 7 | `GET {VITE_IP_API}/proxy/verify/getIPByBrowser`(→ 同上 10011) | 取本机 IP(DMS 访客归属) | `src/utils/client-ip.ts` |
 | 8 | `POST {VITE_API}/enterprise/login`、`GET {VITE_API}/fta_ent_policy/enterprise_info` | 企业登录换码 / 拉企业信息(**老接口**) | `src/network/api/enterprise.ts` |
 | 9 | `POST {modelServer}/open/openid_to_token`(带 `app_key=VITE_APP_KEY`)+ 助手卡片信息 | 免登引导、卡片配置 | `index.html`(脚本段) |
@@ -141,7 +141,8 @@ gitignored)+ `.env.production`。`qingpu` / `test` 两个模式已删除,脚
 ### 3. 语音输入 —— ~~在用~~ **2026-09-23 起换成阿里云 NLS,见 [`asr-nls.md`](asr-nls.md)**
 
 > 下面这段是**换之前**的实现记录(厂商 `asr_hub` 中转)。旧实现代码仍在
-> `src/three-libs/asr/index.ts`(切回去的退路),所以细节保留;但它已不在链路上。
+> ~~`src/three-libs/asr/index.ts`(切回去的退路)~~ —— **该文件已于 2026-09-24 删除**
+> (连同 `three-libs/` 目录),本节只是历史记录;它已不在链路上。
 
 - 触发:点输入框的麦克风
 **实际只依赖 1 个接口:**
@@ -153,7 +154,7 @@ wss://qingpu-data-api.metamaker.cn/common/asr_hub
 ```
 
 - host 取自 `VITE_ASR`;**引擎是 `aliyun_dashscope`(阿里云百炼),不是讯飞**
-- **鉴权不需要调接口**:token 硬编码在 [asr/index.ts](../../../src/three-libs/asr/index.ts) 里
+- **鉴权不需要调接口**:token 硬编码在 asr/index.ts(已删) 里
   (JWT `iss: human-large-screen`,**exp 2034-12-29**)—— 所以 ASR 没有 DMS 那种每天换 token 的问题
 - 调用方还硬编码传了一个 `appKey`(`new ASR("<key>", {audio:true,video:false})`),
   但它在当前分支用不到(只在讯飞分支的 `gen_auth` 里用)
@@ -167,7 +168,7 @@ wss://{VITE_XF_ASR}/api/human_asr/v2/asr?Authorization=...
 
 与对话协议无关,历次迁移没碰它。
 
-#### 📋 ASR 协议契约(从 [asr/index.ts](../../../src/three-libs/asr/index.ts) 反推,供「换成自建服务」时照做)
+#### 📋 ASR 协议契约(从 asr/index.ts(已删) 反推,供「换成自建服务」时照做)
 
 **连接**:`wss://<host>/common/asr_hub?project=qingpu&engine=aliyun_dashscope&is_long_connection=true&heartbeat=true`
 

+ 36 - 1
harness/progress.md

@@ -4245,7 +4245,42 @@ payload 里含模型里**不存在**的列时,`addContent` 会忽略该列照
 `initCardInfo()` 拉回的卡片之间的关系(`isKnowledgeApi` 分支里是写死的「政策解读」卡片)。
 已记进 [`docs/reference/current-api-call-sites.md`](docs/reference/current-api-call-sites.md) §6。
 
-**🔴 部署必配(已写进技术债 #10 与 asr-nls.md)**:
+### 续 39:删掉走不到的卡片引导链 + 把 asr 移出 three-libs(用户要求)
+
+**用户要求**:①「判断删除后是否会对现用功能造成影响,没有影响就删掉」(指 `initToken()` /
+`openid_to_token` / `VITE_APP_KEY`);②「将 ASR 文件夹移出来,然后删除 three-libs 文件夹」。
+
+**① 影响评估(先查再删)**:
+- `index.html` 的结构是 `if (globalThis.isKnowledgeApi) { 写死「政策解读」cardInfo … } else { initToken(); }`
+  —— **两个环境(dev / production)都是 `VITE_USE_KNOWLEDGE_API=true`**,else 永远走不到
+- 就算走到:`initToken()` 的产物 `globalThis.token`、`initCardInfo()` 的产物 `globalThis.cardInfo`
+  **全仓库没有任何读者**(只 grep 到赋值);`hasSequence` 与 `dataLoaded`/`sequenceLoaded`
+  两个事件在 if 分支里**同样会发**
+- 顺带发现那段本身就是坏的:`initCardInfo()` 里调用 `globalThis.changeLoadingText(...)` /
+  `globalThis.showReloadView(...)`,而这两个函数**从未挂到 globalThis** → 一旦走到就会
+  `TypeError`(也就是"失败时才走的那几个分支"从来没生效过)
+- ⇒ **删掉不影响现用功能**,且去掉一处会抛错的死代码
+
+**删了什么**:`initToken()`、`initCardInfo()`、`else { initToken(); }` 分支,以及随之孤儿的
+`randomString()` / `changeLoadingText()` / `showReloadView()`;两份 env 里的 `VITE_APP_KEY`
+(`index.html` 里的 `app_key` 占位也随之消失 —— 产物核对:`app_key` / `openid_to_token` 0 命中)。
+
+**② asr 搬家**:`git mv src/three-libs/asr src/asr` → 删 `src/three-libs/`(目录名有误导性,
+且清理后只剩 asr 一个子目录)。同步改:两个壳组件的 import(`@/asr/nls`)、
+`nls-protocol.ts` 注释里的自引用、`harness/tools/_entry-nls.ts` 的入口路径、
+验证脚本的断言(新增两条:**three-libs 已删、asr 现在在 src/asr**;旧的「不再 import 旧 SDK」
+断言也覆盖了新路径)。
+
+**运行过的验证**:
+- `npm run build` 通过;产物核对:`dist/index.html` 里 `app_key` / `openid_to_token` **已无**,
+  `dist/redirect.html` 的 `redirectMap` 仍有值(上一轮的成果没被碰坏)
+- `verify-nls-realtime.mjs` 43 → **44/44**(含新增的目录位置断言)
+- 附件 57/57、toast 27/27、DMS 字段契约 19/19、DMS 端到端 89/89、`validate-harness` 通过
+- 文档同步:`architecture.md`(目录树/ASR 段落 + 搬家沿革)、`asr-nls.md`(代码位置表、
+  切换说明)、`current-api-call-sites.md`(§0 A 表第 6 行、§三 的旧路径标注为已删)、
+  `asr-realtime.md`(历史文档里指向已删文件的**链接**改成纯文本,避免 404 链接)
+
+**⚠️ 部署必配(已写进技术债 #10 与 asr-nls.md)**:
 ① nginx 要把 `/aly-api/` 转发到 `http://121.43.55.7:10011/`(去掉前缀);
 ② **`.env.production` / `.env.qingpu` / `.env.test` 都没有 `VITE_NLS_APPKEY`** ——
 实测生产构建的包里 appkey 为空,上线会因空 appkey 失败。**需用户决定**:由部署侧注入,

+ 1 - 1
harness/tools/_entry-nls.ts

@@ -17,4 +17,4 @@ export {
   createNlsTranscriptState,
   reduceNlsTranscript,
   encodePcm16kMono,
-} from '../../src/three-libs/asr/nls-protocol';
+} from '../../src/asr/nls-protocol';

+ 10 - 6
harness/tools/verify-nls-realtime.mjs

@@ -4,7 +4,7 @@
  * 分两段:
  *   【1】纯协议(不需要网络/凭据):帧结构、事件折叠、16k PCM 编码
  *   【2】真实端到端(需要凭据 + Windows TTS):说一句话 → 看识别结果
- *        —— 用的是**前端同一份协议代码**(`src/three-libs/asr/nls-protocol.ts`),
+ *        —— 用的是**前端同一份协议代码**(`src/asr/nls-protocol.ts`),
  *        所以它绿了就意味着前端那套帧真的被网关接受
  *
  * 怎么跑(先打包协议层):
@@ -262,10 +262,11 @@ console.log('\n【4】两个壳组件已切到 NLS 实现(源码级断言)')
     'src/components/BusinessAssistantMobile.vue',
   ]) {
     const source = readFileSync(file, 'utf8');
-    check(`${file}:import 的是 NLS 实现`,
-      /import ASR from '@\/three-libs\/asr\/nls';/.test(source));
+    check(`${file}:import 的是 NLS 实现(2026-09-24 起在 @/asr/nls)`,
+      /import ASR from '@\/asr\/nls';/.test(source));
     check(`${file}:不再 import 旧的厂商 SDK`,
-      !/import ASR from '@\/three-libs\/asr\/index';/.test(source));
+      !/import ASR from '@\/three-libs\/asr\/index';/.test(source) &&
+        !/import ASR from '@\/asr\/index';/.test(source));
     check(`${file}:不再硬编码 appKey(改由端点下发)`,
       !/new ASR\("/.test(source) && /new ASR\(undefined/.test(source));
     // 契约没变:这几个调用点必须还在(换了实现就得跟着改)
@@ -275,8 +276,11 @@ console.log('\n【4】两个壳组件已切到 NLS 实现(源码级断言)')
         /\.close\(\)/.test(source) && /\.clear\(\)/.test(source));
   }
   // 2026-09-24 用户要求「B 全部删掉」:旧厂商 SDK 连同 VITE_ASR / VITE_XF_ASR / /asr 代理一起删了
-  // —— 所以这条断言从「旧实现仍在」反过来:**确认它已经不在**(免得哪天有人误加回来)
-  check('旧的厂商 SDK 已删除(2026-09-24 用户要求)', !existsSync('src/three-libs/asr/index.ts'));
+  // —— 所以这条断言从「旧实现仍在」反过来:**确认它已经不在**(免得哪天有人误加回来)。
+  // 同日又按用户要求把 asr 目录移出 three-libs(`src/asr/`)并删掉 three-libs —— 一并钉住。
+  check('旧的厂商 SDK 已删除(2026-09-24 用户要求)',
+    !existsSync('src/three-libs/asr/index.ts') && !existsSync('src/asr/index.ts'));
+  check('three-libs 目录已删除,asr 现在在 src/asr/', !existsSync('src/three-libs') && existsSync('src/asr/nls.ts'));
   check('旧 ASR 的 env 也删干净了(VITE_ASR / VITE_XF_ASR)',
     !readFileSync('.env.development', 'utf8').includes('VITE_ASR') &&
       !readFileSync('.env.development', 'utf8').includes('VITE_XF_ASR'));

+ 0 - 131
index.html

@@ -64,29 +64,6 @@
         return resObj.hasOwnProperty(querykey) ? resObj[querykey] : null;
       }
 
-      function changeLoadingText(text) {
-        document.querySelector("#loading-cover").classList.add("blur-effect");
-        setTimeout(function () {
-          var loadingCover = document.querySelector("#result-text");
-          loadingCover.innerText = text;
-
-          var circle = document.querySelector("#circle");
-          if (circle) {
-            circle.style.display = "none";
-          }
-        }, 500);
-      }
-
-      function showReloadView(text) {
-        document.getElementById("error-info").style.display = "flex";
-        document.querySelector("#error-tips").innerText = text;
-        setTimeout(function () {
-          document.getElementById("error-info").style.opacity = 1;
-          document.getElementById("error-reload").addEventListener("click", function () {
-            location.reload();
-          });
-        }, 100);
-      }
 
       function addVersionInfo() {
         var version = "%VITE_VERSION%";
@@ -101,113 +78,7 @@
         }
       }
 
-      function randomString() {
-        var chars = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
-        var length = 32;
-        var result = "";
-        for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
-        return result;
-      }
-
-      function initToken() {
-        var openId = localStorage.getItem("openId") || randomString();
-        localStorage.setItem("openId", openId);
-        var requestOptions = {
-          method: "POST",
-          headers: {
-            "Content-Type": "application/json",
-          },
-          body: JSON.stringify({
-            openid: openId,
-            mobile: "17",
-            nickname: globalThis.orgTitle,
-            app_key: "%VITE_APP_KEY%",
-          }),
-        };
-
-        var url = globalThis.modelServer + "/open/openid_to_token";
-
-        fetch(url, requestOptions)
-          .then((response) => response.json())
-          .then((result) => {
-            console.log(result.ret.token);
-            globalThis.token = result.ret.token;
-            // globalThis.token =
-            //  "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyaWQiOjMxNjA1MSwiZXhwIjoxNzM2NDE1MDAyLCJpYXQiOjE3MzU1NTEwMDIsImlzcyI6ImFpLWh1bWFuLW1pbmkiLCJzY29wZSI6IiJ9.jYvLswI5NQaeL8W6Q0TQm7sdz4EtqyLRNVjuuKFtdO0";
-
-            // globalThis.mini_id = 10156;
-            initCardInfo();
-          })
-          .catch((error) => console.log("error", error));
-      }
-
-      function initCardInfo() {
-        var token = globalThis.token;
-        var mini = globalThis.mini_id;
-        var card_id = globalThis.card_id;
-
-        // if (!token || (!card_id && !mini)) {
-        //   return;
-        // } else {
-        //   sessionStorage.setItem("token", token);
-        // }
-
-        var url = cardURL + "/mini/info";
-
-        let params = [];
-        if (mini) {
-          params.push("mini=" + mini);
-        }
 
-        if (card_id) {
-          params.push("card=" + card_id);
-        }
-
-        url += "?" + params.join("&");
-
-        fetch(url, {
-          method: "get",
-          headers: {
-            "Content-Type": "application/x-www-form-urlencoded",
-            Authorization: token,
-          },
-        })
-          .then(function (response) {
-            return response.json();
-          })
-          .then(function (result) {
-            if (result.err_code === -1) {
-              globalThis.showReloadView(result.err_msg);
-              return;
-            }
-
-            if (result.err_code !== 0) {
-              globalThis.changeLoadingText(result.err_msg);
-              return;
-            }
-
-            if (result.ret.hasOwnProperty("card_id") && result.ret.card_id === 0) {
-              globalThis.changeLoadingText("助手不存在,请在管理后台中创建");
-              return;
-            }
-
-            globalThis.cardInfo = result.ret;
-            globalThis.cardInfo.tts_args = {
-              speed: 30,
-              volume: 100,
-              voice_name: "S_x8pOUDlm1",
-            };
-            globalThis.hasSequence = true;
-            // globalThis.token = data.ret;
-            document.dispatchEvent(new CustomEvent("dataLoaded"));
-            document.dispatchEvent(new CustomEvent("sequenceLoaded"));
-            addVersionInfo();
-          })
-          .catch(function (err) {
-            console.warn(err);
-            addVersionInfo();
-            globalThis.changeLoadingText(err);
-          });
       }
 
       function initMessageChannel() {
@@ -401,8 +272,6 @@
           document.dispatchEvent(new CustomEvent("dataLoaded"));
           document.dispatchEvent(new CustomEvent("sequenceLoaded"));
           addVersionInfo();
-        } else {
-          initToken();
         }
       })();
 

+ 1 - 1
src/three-libs/asr/nls-protocol.ts → src/asr/nls-protocol.ts

@@ -3,7 +3,7 @@
  *
  * 单独抽出来的原因:① 帧结构与事件映射是这个改造里唯一"错了就静默不工作"的部分,
  * 抽成纯函数就能被 harness 直接测(`harness/tools/verify-nls-realtime.mjs`);
- * ② `src/three-libs/asr/nls.ts` 只负责音频采集与连接,读起来更清楚。
+ * ② `src/asr/nls.ts` 只负责音频采集与连接,读起来更清楚。
  *
  * 契约来源:**实测**(`harness/tools/probe-nls-realtime.mjs` 打真实网关,
  * 逐帧看过原始载荷;文档侧要点见 progress.md 续 33)。两条踩过的坑:

+ 0 - 0
src/three-libs/asr/nls.ts → src/asr/nls.ts


+ 1 - 1
src/components/BusinessAssistantMobile.vue

@@ -407,7 +407,7 @@ import { scrollBusinessAssistantListToBottom } from './business-assistant/scroll
 // 实时语音识别:**阿里云 NLS 直连**(2026-09-23 换)。
 // 对外契约与旧厂商 SDK(`@/three-libs/asr/index`)一致,所以这里只有这一行变了;
 // 切回旧实现也只改这一行。详见 harness/docs/reference/asr-nls.md
-import ASR from '@/three-libs/asr/nls';
+import ASR from '@/asr/nls';
 import AccountInfo from "./Chat/AccountInfo.vue";
 import { useEnterpriseAuth } from '@/components/useEnterpriseAuth';
 import { createModalMutex, MODAL_MUTEX_KEY } from './business-assistant/modal-mutex';

+ 1 - 1
src/components/BusinessAssistantPC.vue

@@ -349,7 +349,7 @@ import ScrollList from './Common/ScrollList.vue';
 // 实时语音识别:**阿里云 NLS 直连**(2026-09-23 换)。
 // 对外契约与旧厂商 SDK(`@/three-libs/asr/index`)一致,所以这里只有这一行变了;
 // 切回旧实现也只改这一行。详见 harness/docs/reference/asr-nls.md
-import ASR from '@/three-libs/asr/nls';
+import ASR from '@/asr/nls';
 import ParticleBackground from "./Common/ParticleBackground.vue";
 import { useBusinessAssistantChat } from './business-assistant/useBusinessAssistantChat';
 import { useBusinessAssistantUpload } from './business-assistant/useBusinessAssistantUpload';