@z-qinghui/migpt-claw 1.0.0

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 (111) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +690 -0
  3. package/dist/index.d.ts +23 -0
  4. package/dist/index.js +33 -0
  5. package/dist/index.js.map +1 -0
  6. package/dist/setup-entry.d.ts +3 -0
  7. package/dist/setup-entry.js +7 -0
  8. package/dist/setup-entry.js.map +1 -0
  9. package/dist/src/channel.d.ts +10 -0
  10. package/dist/src/channel.js +444 -0
  11. package/dist/src/channel.js.map +1 -0
  12. package/dist/src/config.d.ts +125 -0
  13. package/dist/src/config.js +146 -0
  14. package/dist/src/config.js.map +1 -0
  15. package/dist/src/message.d.ts +51 -0
  16. package/dist/src/message.js +145 -0
  17. package/dist/src/message.js.map +1 -0
  18. package/dist/src/mi/account.d.ts +5 -0
  19. package/dist/src/mi/account.js +162 -0
  20. package/dist/src/mi/account.js.map +1 -0
  21. package/dist/src/mi/common.d.ts +15 -0
  22. package/dist/src/mi/common.js +80 -0
  23. package/dist/src/mi/common.js.map +1 -0
  24. package/dist/src/mi/index.d.ts +4 -0
  25. package/dist/src/mi/index.js +10 -0
  26. package/dist/src/mi/index.js.map +1 -0
  27. package/dist/src/mi/mina.d.ts +66 -0
  28. package/dist/src/mi/mina.js +225 -0
  29. package/dist/src/mi/mina.js.map +1 -0
  30. package/dist/src/mi/miot.d.ts +35 -0
  31. package/dist/src/mi/miot.js +168 -0
  32. package/dist/src/mi/miot.js.map +1 -0
  33. package/dist/src/mi/typing.d.ts +90 -0
  34. package/dist/src/mi/typing.js +1 -0
  35. package/dist/src/mi/typing.js.map +1 -0
  36. package/dist/src/onboarding.d.ts +5 -0
  37. package/dist/src/onboarding.js +118 -0
  38. package/dist/src/onboarding.js.map +1 -0
  39. package/dist/src/openclaw-plugin-sdk.d.d.ts +185 -0
  40. package/dist/src/openclaw-plugin-sdk.d.js +1 -0
  41. package/dist/src/openclaw-plugin-sdk.d.js.map +1 -0
  42. package/dist/src/outbound.d.ts +5 -0
  43. package/dist/src/outbound.js +108 -0
  44. package/dist/src/outbound.js.map +1 -0
  45. package/dist/src/runtime.d.ts +6 -0
  46. package/dist/src/runtime.js +15 -0
  47. package/dist/src/runtime.js.map +1 -0
  48. package/dist/src/service.d.ts +70 -0
  49. package/dist/src/service.js +200 -0
  50. package/dist/src/service.js.map +1 -0
  51. package/dist/src/speaker.d.ts +62 -0
  52. package/dist/src/speaker.js +211 -0
  53. package/dist/src/speaker.js.map +1 -0
  54. package/dist/src/tts/mimo.d.ts +50 -0
  55. package/dist/src/tts/mimo.js +214 -0
  56. package/dist/src/tts/mimo.js.map +1 -0
  57. package/dist/src/types.d.ts +30 -0
  58. package/dist/src/types.js +1 -0
  59. package/dist/src/types.js.map +1 -0
  60. package/dist/src/utils/codec.d.ts +31 -0
  61. package/dist/src/utils/codec.js +144 -0
  62. package/dist/src/utils/codec.js.map +1 -0
  63. package/dist/src/utils/debug.d.ts +10 -0
  64. package/dist/src/utils/debug.js +15 -0
  65. package/dist/src/utils/debug.js.map +1 -0
  66. package/dist/src/utils/hash.d.ts +40 -0
  67. package/dist/src/utils/hash.js +75 -0
  68. package/dist/src/utils/hash.js.map +1 -0
  69. package/dist/src/utils/http.d.ts +24 -0
  70. package/dist/src/utils/http.js +151 -0
  71. package/dist/src/utils/http.js.map +1 -0
  72. package/dist/src/utils/index.d.ts +6 -0
  73. package/dist/src/utils/index.js +10 -0
  74. package/dist/src/utils/index.js.map +1 -0
  75. package/dist/src/utils/io.d.ts +26 -0
  76. package/dist/src/utils/io.js +53 -0
  77. package/dist/src/utils/io.js.map +1 -0
  78. package/dist/src/utils/parse.d.ts +26 -0
  79. package/dist/src/utils/parse.js +51 -0
  80. package/dist/src/utils/parse.js.map +1 -0
  81. package/index.ts +26 -0
  82. package/openclaw.plugin.json +344 -0
  83. package/package.json +106 -0
  84. package/setup-entry.ts +12 -0
  85. package/skills/migpt-volume/SKILL.md +182 -0
  86. package/skills/migpt-volume/index.ts +50 -0
  87. package/src/channel.ts +519 -0
  88. package/src/config.ts +299 -0
  89. package/src/message.ts +186 -0
  90. package/src/mi/account.ts +184 -0
  91. package/src/mi/common.ts +105 -0
  92. package/src/mi/index.ts +4 -0
  93. package/src/mi/mina.ts +261 -0
  94. package/src/mi/miot.ts +193 -0
  95. package/src/mi/typing.ts +93 -0
  96. package/src/onboarding.ts +136 -0
  97. package/src/openclaw-plugin-sdk.d.ts +185 -0
  98. package/src/outbound.ts +137 -0
  99. package/src/runtime.ts +14 -0
  100. package/src/service.ts +246 -0
  101. package/src/speaker.ts +264 -0
  102. package/src/tts/mimo.ts +300 -0
  103. package/src/types.ts +34 -0
  104. package/src/utils/codec.ts +206 -0
  105. package/src/utils/debug.ts +16 -0
  106. package/src/utils/hash.ts +104 -0
  107. package/src/utils/http.ts +193 -0
  108. package/src/utils/index.ts +5 -0
  109. package/src/utils/io.ts +68 -0
  110. package/src/utils/parse.ts +64 -0
  111. package/tsconfig.json +25 -0
package/src/service.ts ADDED
@@ -0,0 +1,246 @@
1
+ import { MiNA } from './mi/mina.js';
2
+ import { MIoT } from './mi/miot.js';
3
+ import { getMiService } from './mi/common.js';
4
+ import { assert, sleep } from './utils/parse.js';
5
+ import { Debugger } from './utils/debug.js';
6
+
7
+ export interface MiServiceConfig {
8
+ /** 小米 ID(数字) */
9
+ userId?: string;
10
+ /** 密码 */
11
+ password?: string;
12
+ /** 登录凭证 */
13
+ passToken?: string;
14
+ /** 是否开启调试模式 */
15
+ debug?: boolean;
16
+ /** 网络请求超时时长(毫秒) */
17
+ timeout?: number;
18
+ /** 音箱控制方式:mina/miot */
19
+ speakerControl?: 'mina' | 'miot';
20
+ }
21
+
22
+ class _MiService {
23
+ MiNA?: MiNA;
24
+ MiOT?: MIoT;
25
+ private _initialized = false;
26
+ private _initializing = false;
27
+ private _speakerControl: 'mina' | 'miot' = 'mina';
28
+
29
+ /**
30
+ * 使用 MIoT 发送 TTS 播报
31
+ */
32
+ async playWithMiot(text: string): Promise<boolean> {
33
+ if (!this.MiOT) {
34
+ console.warn('⚠️ MIoT 服务不可用');
35
+ return false;
36
+ }
37
+ try {
38
+ // 使用 MIoT spec 调用 TTS 动作 (siid=5, aiid=1 是常见的 TTS 动作)
39
+ // 不同设备可能不同,需要根据设备 spec 调整
40
+ const result = await this.MiOT.doAction(5, 1, [text]);
41
+ return result;
42
+ } catch (e: any) {
43
+ console.error('❌ MIoT TTS 失败:', e?.message || e);
44
+ return false;
45
+ }
46
+ }
47
+
48
+ /**
49
+ * 使用 MiNA 发送 TTS 播报
50
+ */
51
+ async playWithMina(text: string): Promise<boolean> {
52
+ if (!this.MiNA) {
53
+ console.warn('⚠️ MiNA 服务不可用');
54
+ return false;
55
+ }
56
+ try {
57
+ const result = await this.MiNA.play({ text });
58
+ return result;
59
+ } catch (e: any) {
60
+ console.error('❌ MiNA TTS 失败:', e?.message || e);
61
+ return false;
62
+ }
63
+ }
64
+
65
+ /**
66
+ * 发送 TTS 播报(根据配置选择 MiNA 或 MIoT)
67
+ */
68
+ async play(text: string): Promise<boolean> {
69
+ if (this._speakerControl === 'miot') {
70
+ return this.playWithMiot(text);
71
+ } else {
72
+ return this.playWithMina(text);
73
+ }
74
+ }
75
+
76
+ /**
77
+ * 初始化服务
78
+ */
79
+ async init(config: MiServiceConfig & {
80
+ announceOnStart?: boolean;
81
+ startupMessage?: string;
82
+ }, did: string): Promise<boolean> {
83
+ if (this._initialized) {
84
+ console.log('✅ MiService 已初始化,跳过');
85
+ return true;
86
+ }
87
+
88
+ if (this._initializing) {
89
+ // 等待初始化完成
90
+ let waitCount = 0;
91
+ while (this._initializing && waitCount < 30) {
92
+ await sleep(100);
93
+ waitCount++;
94
+ }
95
+ return this._initialized;
96
+ }
97
+
98
+ this._initializing = true;
99
+
100
+ try {
101
+ console.log('🚀 开始初始化 MiService...');
102
+ console.log('📋 配置信息:', {
103
+ did,
104
+ userId: config.userId,
105
+ hasPassword: !!config.password,
106
+ hasPassToken: !!config.passToken,
107
+ debug: config.debug,
108
+ timeout: config.timeout,
109
+ speakerControl:config.speakerControl
110
+ });
111
+
112
+ assert(!!did, '❌ Speaker 缺少 did 参数');
113
+ assert(
114
+ !!config.passToken || (!!config.userId && !!config.password),
115
+ '❌ Speaker 缺少 passToken 或 userId 和 password',
116
+ );
117
+
118
+ Debugger.debug = config.debug ?? false;
119
+ this._speakerControl = config.speakerControl ?? 'mina';
120
+
121
+ const serviceConfig = {
122
+ ...config,
123
+ did,
124
+ timeout: Math.max(1000, config.timeout ?? 5000),
125
+ };
126
+
127
+ console.log('🔌 正在连接 MiNA 服务...');
128
+ this.MiNA = (await getMiService({ ...serviceConfig, service: 'mina' })) as MiNA | undefined;
129
+ console.log('🔌 查询 MiNA 服务结果:', { mina: !!this.MiNA });
130
+
131
+ // MiOT 对于音箱设备是可选的,只记录警告不阻断
132
+ console.log('🔌 正在连接 MIoT 服务...');
133
+ this.MiOT = (await getMiService({ ...serviceConfig, service: 'miot' })) as MIoT | undefined;
134
+ console.log('🔌 查询 MIoT 服务结果:', { miot: !!this.MiOT });
135
+
136
+ // 对于音箱设备,MiNA 是必需的,MiOT 是可选的
137
+ assert(!!this.MiNA, '❌ 初始化 MiNA 服务失败');
138
+ if (!this.MiOT) {
139
+ console.warn('⚠️ MIoT 服务初始化失败,部分设备控制功能可能不可用');
140
+ }
141
+
142
+ if (Debugger.debug) {
143
+ const device: any = this.MiNA?.account?.device;
144
+ console.debug(
145
+ '🐛 设备信息:',
146
+ JSON.stringify(
147
+ {
148
+ name: device?.name,
149
+ desc: device?.desc,
150
+ model: device?.model,
151
+ rom: device?.extra?.fw_version,
152
+ },
153
+ null,
154
+ 2,
155
+ ),
156
+ );
157
+ }
158
+
159
+ this._initialized = true;
160
+ console.log('✅ MiService 初始化成功');
161
+ console.log(`🔊 音箱控制方式:${this._speakerControl}`);
162
+
163
+ // 初始化成功后发送 TTS 播报(如果启用了启动播报)
164
+ const announceOnStart = config.announceOnStart ?? true;
165
+ if (announceOnStart) {
166
+ const startupMessage = config.startupMessage ?? '您的小龙虾已上线,随时为您服务';
167
+ try {
168
+ console.log('🔊 正在发送启动播报:', startupMessage);
169
+ await this.play(startupMessage);
170
+ console.log('✅ 启动播报发送成功');
171
+ } catch (e: any) {
172
+ console.warn('⚠️ 启动播报发送失败:', e?.message || e);
173
+ }
174
+ }
175
+
176
+ return true;
177
+ } catch (err: any) {
178
+ console.error('❌ 初始化失败:',{err:err,message: err.message});
179
+ return false;
180
+ } finally {
181
+ this._initializing = false;
182
+ }
183
+ }
184
+
185
+ /**
186
+ * 获取设备列表
187
+ */
188
+ async getDevices(config: MiServiceConfig): Promise<Array<{ did: string; name: string; model?: string }>> {
189
+ try {
190
+ // 临时初始化以获取设备列表
191
+ const tempService = await getMiService({ ...config, service: 'mina', relogin: false });
192
+ if (!tempService) {
193
+ return [];
194
+ }
195
+
196
+ const devices = await (tempService as MiNA).getDevices();
197
+ return (devices || []).map((d: any) => ({
198
+ did: d.name || d.alias || d.deviceID,
199
+ name: d.alias || d.name,
200
+ model: d.model,
201
+ }));
202
+ } catch (err) {
203
+ console.error('❌ 获取设备列表失败:', err);
204
+ return [];
205
+ }
206
+ }
207
+
208
+ /**
209
+ * 重新登录
210
+ */
211
+ async relogin(config: MiServiceConfig, did: string): Promise<boolean> {
212
+ this._initialized = false;
213
+ return this.init(config, did);
214
+ }
215
+
216
+ /**
217
+ * 唤醒小爱音箱(进入监听状态)
218
+ * 使用 MIoT spec 调用唤醒动作 (siid=5, aiid=3)
219
+ * 基于 mi-gpt 项目的实现
220
+ */
221
+ async wakeUp(): Promise<boolean> {
222
+ if (!this.MiOT) {
223
+ console.warn('⚠️ MIoT 服务不可用,无法唤醒音箱');
224
+ return false;
225
+ }
226
+ try {
227
+ const result = await this.MiOT.doAction(5, 3, []);
228
+ return result;
229
+ } catch (e: any) {
230
+ console.warn('⚠️ 唤醒音箱失败:', e?.message || e);
231
+ return false;
232
+ }
233
+ }
234
+
235
+ /**
236
+ * 退出监听状态(取消唤醒)
237
+ * 使用 MiNA 暂停使小爱退出监听
238
+ */
239
+ async unWakeUp(): Promise<void> {
240
+ if (this.MiNA) {
241
+ await this.MiNA.pause().catch(() => {});
242
+ }
243
+ }
244
+ }
245
+
246
+ export const MiService = new _MiService();
package/src/speaker.ts ADDED
@@ -0,0 +1,264 @@
1
+ import { networkInterfaces } from 'node:os';
2
+ import { MiService } from './service.js';
3
+ import type { MiMoTTS } from './tts/mimo.js';
4
+
5
+ /**
6
+ * 获取小爱音箱可访问的主机 IP
7
+ * 优先使用环境变量 MIMO_TTS_HOST_IP,否则自动检测
8
+ */
9
+ function getHostLANIP(): string {
10
+ // 优先使用环境变量(适用于云服务器场景)
11
+ const envIP = process.env.MIMO_TTS_HOST_IP;
12
+ if (envIP) return envIP;
13
+
14
+ const nets = networkInterfaces();
15
+ for (const name of Object.keys(nets)) {
16
+ for (const net of nets[name] ?? []) {
17
+ if (net.internal || net.family !== 'IPv4') continue;
18
+ if (net.address.startsWith('172.17.')) continue;
19
+ if (
20
+ net.address.startsWith('192.168.') ||
21
+ net.address.startsWith('10.') ||
22
+ net.address.startsWith('172.16.') ||
23
+ net.address.startsWith('172.18.') ||
24
+ net.address.startsWith('172.19.') ||
25
+ net.address.startsWith('172.2') ||
26
+ net.address.startsWith('172.3')
27
+ ) {
28
+ return net.address;
29
+ }
30
+ }
31
+ }
32
+ for (const name of Object.keys(nets)) {
33
+ for (const net of nets[name] ?? []) {
34
+ if (!net.internal && net.family === 'IPv4') return net.address;
35
+ }
36
+ }
37
+ return '127.0.0.1';
38
+ }
39
+
40
+ export interface IPlayOptions {
41
+ text?: string;
42
+ url?: string;
43
+ duration?: number;
44
+ }
45
+
46
+ export interface IPlayResult {
47
+ success: boolean;
48
+ error?: string;
49
+ duration?: number;
50
+ }
51
+
52
+ class _MiSpeaker {
53
+ /** MiMo TTS 实例(延迟注入) */
54
+ private _mimoTTS: MiMoTTS | null = null;
55
+
56
+ /**
57
+ * 注入 MiMo TTS 提供者(自动清理旧实例,防止端口泄漏)
58
+ */
59
+ async setMiMoTTS(tts: MiMoTTS) {
60
+ // 清理旧实例,释放端口
61
+ if (this._mimoTTS) {
62
+ console.log('🔊 清理旧 MiMo TTS 实例...');
63
+ await this._mimoTTS.destroy().catch(() => {});
64
+ }
65
+ this._mimoTTS = tts;
66
+ }
67
+
68
+ /**
69
+ * 清理 MiMo TTS 资源(释放端口和临时文件)
70
+ */
71
+ async cleanupMiMoTTS() {
72
+ if (this._mimoTTS) {
73
+ console.log('🔊 清理 MiMo TTS 资源...');
74
+ await this._mimoTTS.destroy().catch(() => {});
75
+ this._mimoTTS = null;
76
+ }
77
+ }
78
+
79
+ /**
80
+ * 播放文字、音频链接
81
+ * 优先使用 MiMo TTS(如果已配置),否则回退到小米原生 TTS
82
+ */
83
+ async play(options: IPlayOptions): Promise<IPlayResult> {
84
+ const { text, url } = options;
85
+
86
+ console.log(`🔊 Speaker.play called: text=${text?.slice(0, 50)}..., url=${url}`);
87
+
88
+ if (!MiService.MiNA && !MiService.MiOT) {
89
+ console.error('❌ Speaker.play failed: MiNA/MiOT service not initialized');
90
+ return { success: false, error: 'MiNA/MiOT service not initialized' };
91
+ }
92
+
93
+ try {
94
+ let result: boolean;
95
+ if (url) {
96
+ // URL 播放只支持 MiNA
97
+ if (!MiService.MiNA) {
98
+ return { success: false, error: 'MiNA service not initialized for URL playback' };
99
+ }
100
+ console.log(`🔊 Playing URL: ${url}`);
101
+ result = await MiService.MiNA.play({ url });
102
+ } else if (text) {
103
+ // 优先使用 MiMo TTS
104
+ if (this._mimoTTS) {
105
+ console.log(`🔊 Using MiMo TTS for: ${text.slice(0, 30)}...`);
106
+ const ttsResult = await this._mimoTTS.synthesize(text);
107
+ if (ttsResult.success && ttsResult.url) {
108
+ await this._suppressBeforeCustomTTS();
109
+ const hostIP = getHostLANIP();
110
+ const externalUrl = ttsResult.url.replace(/0\.0\.0\.0|127\.0\.0\.1|localhost/g, hostIP);
111
+ console.log(`🔊 MiMo TTS 播放: ${externalUrl} (时长: ${ttsResult.duration?.toFixed(1)}s)`);
112
+ const duration = ttsResult.duration; // 保存 duration
113
+ result = await MiService.MiNA!.play({ url: externalUrl });
114
+ console.log(`🔊 MiMo TTS play result: ${result}`);
115
+ // 无论播放是否成功,都返回 duration
116
+ return { success: result, duration };
117
+ } else {
118
+ console.warn('⚠️ MiMo TTS 失败,回退到原生 TTS:', ttsResult.error);
119
+ result = await MiService.play(text);
120
+ }
121
+ } else {
122
+ // 文字播报使用配置的播放方式
123
+ console.log(`🔊 Using native TTS for: ${text.slice(0, 30)}...`);
124
+ result = await MiService.play(text);
125
+ }
126
+ } else {
127
+ return { success: false, error: 'text or url is required' };
128
+ }
129
+
130
+ if (result) {
131
+ return { success: true, duration: options.duration };
132
+ } else {
133
+ return { success: false, error: 'Playback failed' };
134
+ }
135
+ } catch (err: any) {
136
+ return { success: false, error: err.message };
137
+ }
138
+ }
139
+
140
+ /**
141
+ * 自定义 TTS 播放前的抑制处理
142
+ * 暂停当前播放,防止小爱将 TTS 音频误识别为用户语音指令
143
+ */
144
+ private async _suppressBeforeCustomTTS() {
145
+ if (MiService.MiNA) {
146
+ await MiService.MiNA.pause().catch(() => {});
147
+ }
148
+ }
149
+
150
+ /**
151
+ * 设置音量
152
+ */
153
+ async setVolume(volume: number): Promise<IPlayResult> {
154
+ if (!MiService.MiNA && !MiService.MiOT) {
155
+ return { success: false, error: 'MiNA/MiOT service not initialized' };
156
+ }
157
+
158
+ try {
159
+ // 音量控制只支持 MiNA
160
+ if (MiService.MiNA) {
161
+ const result = await MiService.MiNA.setVolume(volume);
162
+ if (result) {
163
+ return { success: true };
164
+ } else {
165
+ return { success: false, error: 'Failed to set volume' };
166
+ }
167
+ } else {
168
+ return { success: false, error: 'MiNA service required for volume control' };
169
+ }
170
+ } catch (err: any) {
171
+ return { success: false, error: err.message };
172
+ }
173
+ }
174
+
175
+ /**
176
+ * 获取音量
177
+ */
178
+ async getVolume(): Promise<number | undefined> {
179
+ if (!MiService.MiNA) {
180
+ return undefined;
181
+ }
182
+
183
+ try {
184
+ return await MiService.MiNA.getVolume();
185
+ } catch {
186
+ return undefined;
187
+ }
188
+ }
189
+
190
+ /**
191
+ * 暂停播放
192
+ */
193
+ async pause(): Promise<IPlayResult> {
194
+ if (!MiService.MiNA && !MiService.MiOT) {
195
+ return { success: false, error: 'MiNA/MiOT service not initialized' };
196
+ }
197
+
198
+ try {
199
+ // 暂停只支持 MiNA
200
+ if (MiService.MiNA) {
201
+ const result = await MiService.MiNA.pause();
202
+ return { success: result };
203
+ } else {
204
+ return { success: false, error: 'MiNA service required for pause' };
205
+ }
206
+ } catch (err: any) {
207
+ return { success: false, error: err.message };
208
+ }
209
+ }
210
+
211
+ /**
212
+ * 停止播放
213
+ */
214
+ async stop(): Promise<IPlayResult> {
215
+ if (!MiService.MiNA && !MiService.MiOT) {
216
+ return { success: false, error: 'MiNA/MiOT service not initialized' };
217
+ }
218
+
219
+ try {
220
+ // 停止只支持 MiNA
221
+ if (MiService.MiNA) {
222
+ const result = await MiService.MiNA.stop();
223
+ return { success: result };
224
+ } else {
225
+ return { success: false, error: 'MiNA service required for stop' };
226
+ }
227
+ } catch (err: any) {
228
+ return { success: false, error: err.message };
229
+ }
230
+ }
231
+
232
+ /**
233
+ * 播放或暂停
234
+ */
235
+ async playOrPause(): Promise<IPlayResult> {
236
+ if (!MiService.MiNA && !MiService.MiOT) {
237
+ return { success: false, error: 'MiNA/MiOT service not initialized' };
238
+ }
239
+
240
+ try {
241
+ // 播放或暂停只支持 MiNA
242
+ if (MiService.MiNA) {
243
+ const result = await MiService.MiNA.playOrPause();
244
+ return { success: result };
245
+ } else {
246
+ return { success: false, error: 'MiNA service required for playOrPause' };
247
+ }
248
+ } catch (err: any) {
249
+ return { success: false, error: err.message };
250
+ }
251
+ }
252
+
253
+ /**
254
+ * 中断小爱音箱的运行(重启设备)
255
+ * 注意:重启需要大约 1-2s 的时间,在此期间无法使用小爱音箱自带的 TTS 服务
256
+ */
257
+ async abortXiaoAI(): Promise<boolean> {
258
+ // 无法通过 MiOT 中断小爱运行
259
+ // 可以通过 MiOT 重启设备,但这会影响所有功能
260
+ return false;
261
+ }
262
+ }
263
+
264
+ export const MiSpeaker = new _MiSpeaker();