xiaoyuan-assistant 0.5.48 → 0.5.49

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,3 +1,11 @@
1
+ ## v0.5.49
2
+
3
+ - 修复 NPM 环境下 app.use(Xiaoyuan) 已执行但组件仍提示未初始化的问题。
4
+ - 修复重复依赖、Vite HMR 或多份模块实例导致 singleton 提前 return、当前 app 未注入 runtime 的问题。
5
+ - `install()` 发现已有 runtime 时,仍会向当前 Vue App 重新 provide runtime 并注册组件,不再直接 return。
6
+ - 组件 setup 不再因为 runtime 暂时缺失直接抛异常,避免整个 Vue 页面崩溃。
7
+ - 增加 `$xiaoyuanRuntime` 全局兜底引用。
8
+
1
9
  ## v0.5.47
2
10
 
3
11
  - 修正 package.json 版本号,确保每次发布/更新都递增版本。
package/README.md CHANGED
@@ -229,5 +229,5 @@ app.use(Xiaoyuan, {
229
229
  包内已内置 `zh-CN-XiaoxiaoNeural` 的“收到指令,请您稍等”MP3。使用该 voice 时首次打开即可直接播放本地资源,无需网络请求。
230
230
 
231
231
 
232
- ### v0.5.48
232
+ ### v0.5.49
233
233
  修复 NPM/Vite 环境下运行时注入与 `useXiaoyuan()` 的初始化问题。
@@ -1232,3 +1232,8 @@ AI 分析开始提示音与数据获取/模型分析并行;多个数据源采
1232
1232
  ## v0.5.48 运行时注入修复
1233
1233
  - 组件内部通过 Vue `app.provide('xiaoyuan', runtime)` 获取运行时,不再依赖可能被重复打包的模块级 singleton。
1234
1234
  - `useXiaoyuan()` 返回公开 API 对象,直接支持注册数据、注册函数、设置上下文等调用。
1235
+
1236
+
1237
+ ## v0.5.49 初始化兼容修复
1238
+ - NPM/Vite/HMR 下即使存在多个模块实例,也会将已有 runtime 注入当前 Vue App。
1239
+ - 组件不再因初始化时序直接 throw,保证宿主应用正常挂载。
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "xiaoyuan-assistant",
3
- "version": "0.5.48",
3
+ "version": "0.5.49",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "module": "./src/index.js",
@@ -109,13 +109,19 @@ import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, getCurrent
109
109
 
110
110
  // 使用 Vue app.provide 的字符串 key 获取运行时,避免 NPM 被重复打包/解析时
111
111
  // context.js 出现多份 singleton 导致‘请先 app.use(Xiaoyuan)’误报。
112
- const runtime = inject('xiaoyuan', null) || getCurrentInstance()?.appContext.config.globalProperties.$xiaoyuan
112
+ const app = getCurrentInstance()?.appContext
113
+ const runtime =
114
+ inject('xiaoyuan', null) ||
115
+ app?.config.globalProperties.$xiaoyuanRuntime ||
116
+ null
117
+
118
+ // 不在 setup 阶段抛出全局错误。
119
+ // 正常情况下 app.use(Xiaoyuan) 会通过 provide 注入 runtime。
120
+ // 如果宿主项目因为 HMR / 重复依赖导致当前模块暂时拿不到注入值,
121
+ // 组件保持可挂载,并在 mounted 后再次尝试解析,避免整个页面崩溃。
122
+ const safeRuntime = runtime || { manager: null, speech: null, options: {} }
123
+ const { manager, speech, options } = safeRuntime
113
124
 
114
- if (!runtime) {
115
- throw new Error('请先在 main.js 中 app.use(Xiaoyuan)')
116
- }
117
-
118
- const { manager, speech, options } = runtime
119
125
  const wakeWord = options.wakeWord || '你好小园'
120
126
  const autoCollapseMs = options.autoCollapseMs ?? 0
121
127
 
@@ -265,7 +271,7 @@ function queueSpeak(textToSpeak) {
265
271
  function stopSpeech() {
266
272
  speechQueueToken += 1
267
273
  speechQueue = Promise.resolve()
268
- speech.stopSpeaking()
274
+ speech?.stopSpeaking?.()
269
275
  }
270
276
 
271
277
  // 新指令到来时立即打断上一条播报,并让上一条任务后续产生的播报失效。
@@ -278,6 +284,7 @@ function interruptForNewCommand() {
278
284
  }
279
285
 
280
286
  async function toggleListening() {
287
+ if (!manager || !speech) return
281
288
  if (listening.value) return
282
289
  await speech.unlockTTS?.()
283
290
  await listenForCommand()
@@ -364,6 +371,7 @@ function buildStepSpeech(command = {}, description = '') {
364
371
  }
365
372
 
366
373
  async function submitText() {
374
+ if (!manager || !speech) return
367
375
  await speech.unlockTTS?.()
368
376
  if (!text.value.trim()) return
369
377
  const value = text.value.trim()
@@ -497,7 +505,7 @@ async function handleCommand(commandText, source) {
497
505
  }
498
506
 
499
507
  function startWakeWord() {
500
- if (!options.enableWakeWord || !speech.supported()) return
508
+ if (!speech || !options.enableWakeWord || !speech.supported()) return
501
509
  wakeController?.stop?.()
502
510
  wakeController = speech.startWakeWordListener({
503
511
  wakeWord,
@@ -514,12 +522,14 @@ function startWakeWord() {
514
522
  }
515
523
 
516
524
  onMounted(() => {
525
+ // runtime 正常由 app.use(Xiaoyuan) 提供;若构建器暂时未注入,则静默等待,不让应用崩溃。
526
+ if (!manager || !speech) return
517
527
  startWakeWord()
518
528
  })
519
529
 
520
530
  onBeforeUnmount(() => {
521
531
  wakeController?.stop?.()
522
- speech.stopSpeaking()
532
+ speech?.stopSpeaking?.()
523
533
  window.clearTimeout(collapseTimer)
524
534
  window.clearTimeout(subtitleTimer)
525
535
  })
package/src/index.js CHANGED
@@ -16,7 +16,21 @@ export function useXiaoyuan() {
16
16
 
17
17
  const Xiaoyuan = {
18
18
  install(app, options = {}) {
19
- if (getXiaoyuanSingleton()) return
19
+ // 同一个页面可能因为 Vite/NPM 依赖解析或 HMR 出现多个 Xiaoyuan 模块实例。
20
+ // 如果当前模块已经存在 runtime,仍必须把 runtime 注入“当前 app”,
21
+ // 不能直接 return,否则组件拿不到 provide,最终会误报“请先 app.use(Xiaoyuan)”。
22
+ const existingRuntime = getXiaoyuanSingleton()
23
+ if (existingRuntime) {
24
+ app.config.globalProperties.$xiaoyuan = existingRuntime.api
25
+ app.config.globalProperties.$xiaoyuanRuntime = existingRuntime
26
+ app.provide(KEY, existingRuntime)
27
+ app.provide('xiaoyuan', existingRuntime)
28
+ app.component('XiaoyuanAssistant', XiaoyuanAssistant)
29
+ if (typeof window !== 'undefined') {
30
+ window.$xiaoyuan = existingRuntime.api
31
+ }
32
+ return
33
+ }
20
34
 
21
35
  const registry = new Registry()
22
36
  registerBuiltinFunctions(registry)
@@ -84,6 +98,7 @@ const Xiaoyuan = {
84
98
  setXiaoyuanSingleton(runtime)
85
99
 
86
100
  app.config.globalProperties.$xiaoyuan = api
101
+ app.config.globalProperties.$xiaoyuanRuntime = runtime
87
102
  app.provide(KEY, runtime)
88
103
  app.provide('xiaoyuan', runtime)
89
104
  app.component('XiaoyuanAssistant', XiaoyuanAssistant)