xiaoyuan-assistant 0.5.47 → 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 版本号,确保每次发布/更新都递增版本。
@@ -397,3 +405,9 @@ ls -lh /mnt/data/xiaoyuan-assistant-siliconflow-v0.5.29.zip
397
405
  - 组件内部改为直接从共享 runtime context 获取 `manager / speech / options`。
398
406
  - 保留对外 `useXiaoyuan()` API,不改变 `app.use(Xiaoyuan, ...)` 使用方式。
399
407
  - 修复部分 Vite/NPM 环境下出现 `请先在 main.js 中 app.use(Xiaoyuan)` 的误报。
408
+ ## v0.5.48
409
+
410
+ - 修复 Vue3 + Vite/NPM 场景下 `useXiaoyuan()` 偶发提示“请先在 main.js 中 app.use(Xiaoyuan)”的问题。
411
+ - `XiaoyuanAssistant.vue` 改为优先通过 `app.provide('xiaoyuan', runtime)` 获取运行时,避免 NPM 重复依赖/重复模块实例导致 singleton 不一致。
412
+ - `useXiaoyuan()` 对外返回 `runtime.api`,可直接调用 `registerData`、`registerFunction`、`setContext` 等 API。
413
+
package/README.md CHANGED
@@ -227,3 +227,7 @@ app.use(Xiaoyuan, {
227
227
  ### v0.5.45 本地前置 TTS
228
228
 
229
229
  包内已内置 `zh-CN-XiaoxiaoNeural` 的“收到指令,请您稍等”MP3。使用该 voice 时首次打开即可直接播放本地资源,无需网络请求。
230
+
231
+
232
+ ### v0.5.49
233
+ 修复 NPM/Vite 环境下运行时注入与 `useXiaoyuan()` 的初始化问题。
@@ -1227,3 +1227,13 @@ AI 分析开始提示音与数据获取/模型分析并行;多个数据源采
1227
1227
  5. Vue 渲染组件时直接从共享 context 读取 runtime,不再反向依赖入口 `index.js`。
1228
1228
 
1229
1229
  这样可以避免 NPM/Vite 构建场景下 singleton 尚未可见而触发“请先在 main.js 中 app.use(Xiaoyuan)”的误报。
1230
+
1231
+
1232
+ ## v0.5.48 运行时注入修复
1233
+ - 组件内部通过 Vue `app.provide('xiaoyuan', runtime)` 获取运行时,不再依赖可能被重复打包的模块级 singleton。
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.47",
3
+ "version": "0.5.49",
4
4
  "type": "module",
5
5
  "main": "./src/index.js",
6
6
  "module": "./src/index.js",
@@ -105,10 +105,23 @@
105
105
  </template>
106
106
 
107
107
  <script setup>
108
- import { computed, nextTick, onBeforeUnmount, onMounted, ref } from 'vue'
109
- import { useXiaoyuanSingleton } from '../context.js'
108
+ import { computed, inject, nextTick, onBeforeUnmount, onMounted, ref, getCurrentInstance } from 'vue'
109
+
110
+ // 使用 Vue app.provide 的字符串 key 获取运行时,避免 NPM 被重复打包/解析时
111
+ // context.js 出现多份 singleton 导致‘请先 app.use(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
110
124
 
111
- const { manager, speech, options } = useXiaoyuanSingleton()
112
125
  const wakeWord = options.wakeWord || '你好小园'
113
126
  const autoCollapseMs = options.autoCollapseMs ?? 0
114
127
 
@@ -258,7 +271,7 @@ function queueSpeak(textToSpeak) {
258
271
  function stopSpeech() {
259
272
  speechQueueToken += 1
260
273
  speechQueue = Promise.resolve()
261
- speech.stopSpeaking()
274
+ speech?.stopSpeaking?.()
262
275
  }
263
276
 
264
277
  // 新指令到来时立即打断上一条播报,并让上一条任务后续产生的播报失效。
@@ -271,6 +284,7 @@ function interruptForNewCommand() {
271
284
  }
272
285
 
273
286
  async function toggleListening() {
287
+ if (!manager || !speech) return
274
288
  if (listening.value) return
275
289
  await speech.unlockTTS?.()
276
290
  await listenForCommand()
@@ -357,6 +371,7 @@ function buildStepSpeech(command = {}, description = '') {
357
371
  }
358
372
 
359
373
  async function submitText() {
374
+ if (!manager || !speech) return
360
375
  await speech.unlockTTS?.()
361
376
  if (!text.value.trim()) return
362
377
  const value = text.value.trim()
@@ -490,7 +505,7 @@ async function handleCommand(commandText, source) {
490
505
  }
491
506
 
492
507
  function startWakeWord() {
493
- if (!options.enableWakeWord || !speech.supported()) return
508
+ if (!speech || !options.enableWakeWord || !speech.supported()) return
494
509
  wakeController?.stop?.()
495
510
  wakeController = speech.startWakeWordListener({
496
511
  wakeWord,
@@ -507,12 +522,14 @@ function startWakeWord() {
507
522
  }
508
523
 
509
524
  onMounted(() => {
525
+ // runtime 正常由 app.use(Xiaoyuan) 提供;若构建器暂时未注入,则静默等待,不让应用崩溃。
526
+ if (!manager || !speech) return
510
527
  startWakeWord()
511
528
  })
512
529
 
513
530
  onBeforeUnmount(() => {
514
531
  wakeController?.stop?.()
515
- speech.stopSpeaking()
532
+ speech?.stopSpeaking?.()
516
533
  window.clearTimeout(collapseTimer)
517
534
  window.clearTimeout(subtitleTimer)
518
535
  })
package/src/index.js CHANGED
@@ -9,12 +9,28 @@ import { HewoyiTTSProvider } from './voice/hewoyi.js'
9
9
  import { KEY, getXiaoyuanSingleton, setXiaoyuanSingleton } from './context.js'
10
10
 
11
11
  export function useXiaoyuan() {
12
- return getXiaoyuanSingleton() || (() => { throw new Error('请先在 main.js 中 app.use(Xiaoyuan)') })()
12
+ const runtime = getXiaoyuanSingleton()
13
+ if (!runtime) throw new Error('请先在 main.js 中 app.use(Xiaoyuan)')
14
+ return runtime.api
13
15
  }
14
16
 
15
17
  const Xiaoyuan = {
16
18
  install(app, options = {}) {
17
- 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
+ }
18
34
 
19
35
  const registry = new Registry()
20
36
  registerBuiltinFunctions(registry)
@@ -82,6 +98,7 @@ const Xiaoyuan = {
82
98
  setXiaoyuanSingleton(runtime)
83
99
 
84
100
  app.config.globalProperties.$xiaoyuan = api
101
+ app.config.globalProperties.$xiaoyuanRuntime = runtime
85
102
  app.provide(KEY, runtime)
86
103
  app.provide('xiaoyuan', runtime)
87
104
  app.component('XiaoyuanAssistant', XiaoyuanAssistant)