rvis-aiui-kit 1.1.0 → 1.1.1
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/README.md +706 -9
- package/package.json +1 -1
- package/sdk/README.md +41 -3
- package/sdk/index.js +4 -0
- package/sdk/modules/openapi/client.js +517 -0
- package/sdk/modules/openapi/index.js +21 -0
- package/sdk/modules/openapi/readme.md +83 -0
package/README.md
CHANGED
|
@@ -1,22 +1,719 @@
|
|
|
1
1
|
# rvis-aiui-kit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
面向 Rokid AIUI / JSUI 应用的组件库与 Glass3 扩展 SDK。包内包含 7 个 Ink UI 组件、9 组 Host RPC 能力,以及一个 Rokid OpenAPI HTTPS/SSE 客户端。
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## 文档导航
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
- [安装与运行环境](#安装与运行环境)
|
|
8
|
+
- [快速接入](#快速接入)
|
|
9
|
+
- [Glass3 SDK API](#glass3-sdk-api)
|
|
10
|
+
- [API 总览](#api-总览)
|
|
11
|
+
- [Device Context](#device-context)
|
|
12
|
+
- [Screen](#screen)
|
|
13
|
+
- [Notification](#notification)
|
|
14
|
+
- [TTS](#tts)
|
|
15
|
+
- [Offline Command](#offline-command)
|
|
16
|
+
- [Audio](#audio)
|
|
17
|
+
- [Camera](#camera)
|
|
18
|
+
- [Face](#face)
|
|
19
|
+
- [Motion](#motion)
|
|
20
|
+
- [OpenAPI](#openapi)
|
|
21
|
+
- [错误处理](#错误处理)
|
|
22
|
+
- [页面卸载与资源清理](#页面卸载与资源清理)
|
|
23
|
+
- [组件 API](#组件-api)
|
|
24
|
+
- [Image](#image)
|
|
25
|
+
- [List](#list)
|
|
26
|
+
- [Markdown](#markdown)
|
|
27
|
+
- [Model List](#model-list)
|
|
28
|
+
- [Paragraph](#paragraph)
|
|
29
|
+
- [Status Bar](#status-bar)
|
|
30
|
+
- [Table](#table)
|
|
31
|
+
|
|
32
|
+
## 安装与运行环境
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
npm install rvis-aiui-kit
|
|
9
36
|
```
|
|
10
37
|
|
|
11
|
-
|
|
38
|
+
`rvis-aiui-kit` 运行在 AIUI Ink 页面环境中,SDK 依赖宿主提供的 `wx`、Host RPC 和设备能力,不能直接在普通浏览器或 Node.js 中运行。
|
|
39
|
+
|
|
40
|
+
包提供以下入口:
|
|
41
|
+
|
|
42
|
+
| 入口 | 内容 |
|
|
43
|
+
| --- | --- |
|
|
44
|
+
| `rvis-aiui-kit` | 默认导出 `glass3`,并命名导出 `glass3`、`API_MAP`、`Glass3Error` |
|
|
45
|
+
| `rvis-aiui-kit/sdk` | 与包根入口相同 |
|
|
46
|
+
| `rvis-aiui-kit/api-map` | Host RPC API 映射 |
|
|
47
|
+
| `rvis-aiui-kit/<component>` | Ink 组件注册路径 |
|
|
48
|
+
|
|
49
|
+
## 快速接入
|
|
12
50
|
|
|
13
|
-
|
|
51
|
+
### 1. 注册组件
|
|
52
|
+
|
|
53
|
+
在 `.ink` 页面的 `<script def>` 中配置 `usingComponents`:
|
|
54
|
+
|
|
55
|
+
```html
|
|
56
|
+
<script def>
|
|
14
57
|
{
|
|
58
|
+
"navigationBarTitleText": "巡检",
|
|
59
|
+
"description": "显示巡检结果并提供 Glass3 设备能力。",
|
|
60
|
+
"schema": {
|
|
61
|
+
"data": {
|
|
62
|
+
"type": "object",
|
|
63
|
+
"properties": {}
|
|
64
|
+
}
|
|
65
|
+
},
|
|
15
66
|
"usingComponents": {
|
|
16
|
-
"rvis-
|
|
17
|
-
"rvis-
|
|
67
|
+
"rvis-status-bar": "rvis-aiui-kit/status-bar",
|
|
68
|
+
"rvis-paragraph": "rvis-aiui-kit/paragraph",
|
|
69
|
+
"rvis-table": "rvis-aiui-kit/table"
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
</script>
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
### 2. 引入 SDK 并转发 Host 消息
|
|
76
|
+
|
|
77
|
+
```html
|
|
78
|
+
<script setup>
|
|
79
|
+
import glass3 from 'rvis-aiui-kit';
|
|
80
|
+
|
|
81
|
+
export default {
|
|
82
|
+
data: {
|
|
83
|
+
resultText: '准备就绪'
|
|
84
|
+
},
|
|
85
|
+
|
|
86
|
+
onMessage(messageEvent) {
|
|
87
|
+
// Host RPC 的 Promise 和流式 onEvent 都依赖这一步。
|
|
88
|
+
glass3.handleMessage(messageEvent);
|
|
89
|
+
},
|
|
90
|
+
|
|
91
|
+
async takePhoto() {
|
|
92
|
+
try {
|
|
93
|
+
const photo = await glass3.camera.takePhoto();
|
|
94
|
+
this.setData({
|
|
95
|
+
resultText: `照片尺寸:${photo.width} × ${photo.height}`
|
|
96
|
+
});
|
|
97
|
+
} catch (error) {
|
|
98
|
+
this.setData({ resultText: `${error.code}: ${error.message}` });
|
|
99
|
+
}
|
|
100
|
+
},
|
|
101
|
+
|
|
102
|
+
onUnload() {
|
|
103
|
+
// 先停止页面启动的长任务,再释放 SDK 本地监听和等待中的请求。
|
|
104
|
+
glass3.dispose();
|
|
105
|
+
}
|
|
106
|
+
};
|
|
107
|
+
</script>
|
|
108
|
+
|
|
109
|
+
<page>
|
|
110
|
+
<view class="page">
|
|
111
|
+
<rvis-status-bar title="巡检"></rvis-status-bar>
|
|
112
|
+
<view class="content">
|
|
113
|
+
<rvis-paragraph text="{{ resultText }}" width="424px"></rvis-paragraph>
|
|
114
|
+
</view>
|
|
115
|
+
</view>
|
|
116
|
+
</page>
|
|
117
|
+
|
|
118
|
+
<style>
|
|
119
|
+
.page {
|
|
120
|
+
position: absolute;
|
|
121
|
+
top: 0;
|
|
122
|
+
left: 0;
|
|
123
|
+
width: 480px;
|
|
124
|
+
height: 640px;
|
|
125
|
+
background-color: #000000;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.content {
|
|
129
|
+
position: absolute;
|
|
130
|
+
top: 40px;
|
|
131
|
+
left: 28px;
|
|
132
|
+
width: 424px;
|
|
133
|
+
}
|
|
134
|
+
</style>
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
> `glass3.openapi` 不依赖 Host RPC 消息转发,但页面卸载时仍应调用 `glass3.dispose()`,关闭未完成的 SSE 请求。
|
|
138
|
+
|
|
139
|
+
## Glass3 SDK API
|
|
140
|
+
|
|
141
|
+
### 导入
|
|
142
|
+
|
|
143
|
+
```js
|
|
144
|
+
import glass3, {
|
|
145
|
+
glass3 as namedGlass3,
|
|
146
|
+
API_MAP,
|
|
147
|
+
Glass3Error
|
|
148
|
+
} from 'rvis-aiui-kit';
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
- `glass3`:默认客户端单例及全部公开模块;
|
|
152
|
+
- `API_MAP`:公开 JavaScript API 到 Host RPC 的映射;
|
|
153
|
+
- `Glass3Error`:统一 SDK 错误类型。
|
|
154
|
+
|
|
155
|
+
### 通用调用约定
|
|
156
|
+
|
|
157
|
+
- 每个业务方法都返回 Promise;Promise 完成的时点以各 API 说明为准。
|
|
158
|
+
- 长任务通过第二个参数 `{ onEvent(result) {} }` 持续返回事件。
|
|
159
|
+
- Native response 不进入 `onEvent`,`onEvent` 只接收匹配的 event result。
|
|
160
|
+
- `start*`、`observe`、`register` 等返回的 `requestId` 是对应 stop/unregister 调用的目标 ID,必须保存。
|
|
161
|
+
- stop/unregister 自己会生成新的 `requestId`,其返回值中的 ID 不是原任务 ID。
|
|
162
|
+
- 除明确记录的字段外,大多数参数按闭合对象校验,不要传未记录字段或 `snake_case` 字段。
|
|
163
|
+
- Native 下划线字段通常会递归转换为驼峰字段,具体以对应 API 为准。
|
|
164
|
+
|
|
165
|
+
### API 总览
|
|
166
|
+
|
|
167
|
+
| 模块 | 方法 | 用途 |
|
|
168
|
+
| --- | --- | --- |
|
|
169
|
+
| `deviceContext` | `get(options?)` | 获取设备上下文原子快照 |
|
|
170
|
+
| `deviceContext` | `observe(options?, callOptions?)` | 订阅设备上下文快照和变化 |
|
|
171
|
+
| `deviceContext` | `stopObserve({ requestId })` | 停止设备上下文订阅 |
|
|
172
|
+
| `screen` | `turnOff()` / `turnOn()` | 息屏 / 亮屏 |
|
|
173
|
+
| `notification` | `show(options)` / `hide({ requestId })` | 显示 / 隐藏原生通知 |
|
|
174
|
+
| `tts` | `speak(options, callOptions?)` / `stop({ requestId })` | TTS 播报 / 停止 |
|
|
175
|
+
| `offlineCommand` | `register(options, callOptions?)` / `unregister({ requestId })` | 注册 / 注销离线指令 |
|
|
176
|
+
| `audio` | `startRecord(options?, callOptions?)` / `stopRecord({ requestId })` | 录音、转写、保存或上传 |
|
|
177
|
+
| `camera` | `startPreview(options?)` / `stopPreview({ requestId })` | 相机预览 |
|
|
178
|
+
| `camera` | `takePhoto(options?)` | 拍照 |
|
|
179
|
+
| `camera` | `startTakeVideo(options?, callOptions?)` / `stopTakeVideo({ requestId })` | 分段录像 |
|
|
180
|
+
| `face` | `startRecognize({}, callOptions?)` / `stopRecognize({ requestId })` | 持续人脸识别 |
|
|
181
|
+
| `motion` | `startDetect({}, callOptions?)` / `stopDetect({ requestId })` | 持续运动状态检测 |
|
|
182
|
+
| `openapi` | `setConfig(options)` / `visionExtract(params, callOptions?)` | 配置并调用 Rokid OpenAPI 图片识别 |
|
|
183
|
+
|
|
184
|
+
客户端级方法:
|
|
185
|
+
|
|
186
|
+
| 方法 | 返回值 | 说明 |
|
|
187
|
+
| --- | --- | --- |
|
|
188
|
+
| `glass3.handleMessage(messageEvent)` | 匹配结果或 `null` | 将 Page 收到的 Host 消息交给 SDK |
|
|
189
|
+
| `glass3.dispose()` | `undefined` | 释放监听,以 `CALL_DISPOSED` 结束等待中的 RPC,并关闭未完成的 OpenAPI 请求 |
|
|
190
|
+
|
|
191
|
+
### Device Context
|
|
192
|
+
|
|
193
|
+
```js
|
|
194
|
+
const context = await glass3.deviceContext.get({
|
|
195
|
+
domains: ['environment', 'power', 'network', 'interaction']
|
|
196
|
+
});
|
|
197
|
+
|
|
198
|
+
const observer = await glass3.deviceContext.observe(
|
|
199
|
+
{ domains: ['power', 'network'] },
|
|
200
|
+
{
|
|
201
|
+
onEvent(result) {
|
|
202
|
+
if (result.eventType === 'snapshot') {
|
|
203
|
+
// result.snapshot
|
|
204
|
+
} else if (result.eventType === 'changed') {
|
|
205
|
+
// 按 epoch、baseRevision 合并 patch
|
|
206
|
+
} else if (result.eventType === 'invalidated') {
|
|
207
|
+
// 清除旧账号/环境上下文并重新加载
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
);
|
|
212
|
+
|
|
213
|
+
await glass3.deviceContext.stopObserve({ requestId: observer.requestId });
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
`domains` 可选值:`identity`、`software`、`account`、`environment`、`power`、`network`、`interaction`。省略参数或传 `{}` 表示全部;显式传入时必须是非空数组。
|
|
217
|
+
|
|
218
|
+
`get()` 等待 `snapshot` 事件后完成,返回 `{ requestId, ok, eventType: 'snapshot', snapshot }`。`observe()` 在订阅启动后返回 `{ requestId, ok, state: 'started' }`;首个业务事件为 `snapshot`,后续为 `changed` 或 `invalidated`。SDK 不自动合并 patch。
|
|
219
|
+
|
|
220
|
+
### Screen
|
|
221
|
+
|
|
222
|
+
```js
|
|
223
|
+
const offResult = await glass3.screen.turnOff();
|
|
224
|
+
const onResult = await glass3.screen.turnOn();
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
返回 `{ requestId, ok, changed, screen: 'off' | 'on' }`。`changed: false` 表示调用前已经处于目标状态,仍属于成功。
|
|
228
|
+
|
|
229
|
+
普通电源键行为由 Host 管理时,不要在按键回调中调用这两个方法。系统亮屏/息屏通过 Page 收到的原始 `rokid.device / screenStateChanged` 消息通知;先转发给 `glass3.handleMessage()`,再读取 `messageEvent.data.data.state`。
|
|
230
|
+
|
|
231
|
+
### Notification
|
|
232
|
+
|
|
233
|
+
```js
|
|
234
|
+
const notice = await glass3.notification.show({
|
|
235
|
+
text: '思考中',
|
|
236
|
+
level: 'active',
|
|
237
|
+
position: 'topCenter',
|
|
238
|
+
durationMs: 8000,
|
|
239
|
+
animation: 'thinking',
|
|
240
|
+
resident: true
|
|
241
|
+
});
|
|
242
|
+
|
|
243
|
+
await glass3.notification.hide({ requestId: notice.requestId });
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
| 字段 | 类型 | 必填/默认值 | 说明 |
|
|
247
|
+
| --- | --- | --- | --- |
|
|
248
|
+
| `title` | `string` | 与 `text` 至少一个 | 标题,可显式传空字符串 |
|
|
249
|
+
| `text` | `string` | 与 `title` 至少一个 | 正文,可显式传空字符串 |
|
|
250
|
+
| `level` | `string` | `'active'` | `active` 或 `critical`;非法值警告后回退到 `active` |
|
|
251
|
+
| `position` | `string` | Native 默认值 | `topLeft`、`topCenter`、`topRight`、`bottomLeft`、`bottomCenter`、`bottomRight` |
|
|
252
|
+
| `durationMs` | `number` | Native 默认值 | 大于 0 的整数,单位毫秒 |
|
|
253
|
+
| `animation` | `string` | `'idle'` | 通知动效 |
|
|
254
|
+
| `resident` | `boolean` | Native 默认值 | 是否常驻 |
|
|
255
|
+
|
|
256
|
+
`animation` 可选值:`idle`、`blink`、`thinking`、`calm`、`nod`、`bow`、`salute`、`photo`、`face`、`scan`、`success`、`listening`、`speaking`、`enter`、`exit`。
|
|
257
|
+
|
|
258
|
+
`show()` 和 `hide()` 都返回 `{ requestId, ok: true }`。Native 通知优先级高于息屏状态;若息屏后不应保留通知,应先调用 `hide()`。
|
|
259
|
+
|
|
260
|
+
### TTS
|
|
261
|
+
|
|
262
|
+
```js
|
|
263
|
+
const playback = await glass3.tts.speak(
|
|
264
|
+
{ text: '你好,这是一段播报。', queueMode: 'flush' },
|
|
265
|
+
{
|
|
266
|
+
onEvent(result) {
|
|
267
|
+
// state: started | finished | canceled
|
|
268
|
+
}
|
|
18
269
|
}
|
|
270
|
+
);
|
|
271
|
+
|
|
272
|
+
await glass3.tts.stop({ requestId: playback.requestId });
|
|
273
|
+
```
|
|
274
|
+
|
|
275
|
+
`speak()` 在请求被 Native 接受后返回 `{ requestId, ok: true }`,不等待播放结束。`stop()` 返回 `{ requestId, ok: true, state: 'stopped' }`。
|
|
276
|
+
|
|
277
|
+
### Offline Command
|
|
278
|
+
|
|
279
|
+
```js
|
|
280
|
+
const registration = await glass3.offlineCommand.register(
|
|
281
|
+
{
|
|
282
|
+
language: 'ZH_CN',
|
|
283
|
+
commands: [
|
|
284
|
+
{
|
|
285
|
+
id: 'next_step',
|
|
286
|
+
phrases: [
|
|
287
|
+
{ text: '下一步', pinyin: 'xia yi bu' },
|
|
288
|
+
{ text: '继续', pinyin: 'ji xu' }
|
|
289
|
+
]
|
|
290
|
+
}
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
onEvent(result) {
|
|
295
|
+
if (result.commandId === 'next_step') {
|
|
296
|
+
// 处理命中
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
);
|
|
301
|
+
|
|
302
|
+
await glass3.offlineCommand.unregister({
|
|
303
|
+
requestId: registration.requestId
|
|
304
|
+
});
|
|
305
|
+
```
|
|
306
|
+
|
|
307
|
+
`commands` 必须是非空数组;每项包含非空 `id` 和非空 `phrases`。每个 phrase 必须提供非空 `text`,应用开发时同时提供非空 `pinyin`。命中事件通过注册调用的 `onEvent` 返回 `{ ok, commandId, phrase, timestamp }`,不要用 `onVoiceWakeup` 接收 SDK 离线指令。
|
|
308
|
+
|
|
309
|
+
### Audio
|
|
310
|
+
|
|
311
|
+
```js
|
|
312
|
+
const recording = await glass3.audio.startRecord(
|
|
313
|
+
{
|
|
314
|
+
maxMinutes: 10,
|
|
315
|
+
needText: true,
|
|
316
|
+
needMp3: false,
|
|
317
|
+
showCard: true,
|
|
318
|
+
upload: false
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
onEvent(result) {
|
|
322
|
+
// finished、canceled 或异步错误
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
);
|
|
326
|
+
|
|
327
|
+
const audioResult = await glass3.audio.stopRecord({
|
|
328
|
+
requestId: recording.requestId
|
|
329
|
+
});
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
333
|
+
| --- | --- | --- | --- |
|
|
334
|
+
| `maxMinutes` | `number` | `10` | 1~120 的整数 |
|
|
335
|
+
| `needText` | `boolean` | `true` | 返回整段 ASR 文本 |
|
|
336
|
+
| `needMp3` | `boolean` | `false` | 保留并返回音频文件 |
|
|
337
|
+
| `showCard` | `boolean` | `true` | 显示 Native 录音卡片 |
|
|
338
|
+
| `upload` | `boolean` | `false` | 上传结果;成功时返回 `fileUrl` |
|
|
339
|
+
|
|
340
|
+
`startRecord()` 返回 `{ requestId, ok, state: 'started' }`。结束结果包含 `state`、`reason`、`durationMs`,并按选项提供 `text`、`filePath`、`fileUrl`、`sizeBytes`、`sampleRate`。`stopRecord()` 直接返回停止状态和录音成果。
|
|
341
|
+
|
|
342
|
+
### Camera
|
|
343
|
+
|
|
344
|
+
#### 预览
|
|
345
|
+
|
|
346
|
+
```js
|
|
347
|
+
const preview = await glass3.camera.startPreview();
|
|
348
|
+
await glass3.camera.stopPreview({ requestId: preview.requestId });
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
默认预览参数:
|
|
352
|
+
|
|
353
|
+
```js
|
|
354
|
+
{
|
|
355
|
+
left: 0,
|
|
356
|
+
top: 40,
|
|
357
|
+
width: 168,
|
|
358
|
+
height: 104,
|
|
359
|
+
cornerRadius: 2,
|
|
360
|
+
outline: true
|
|
19
361
|
}
|
|
20
362
|
```
|
|
21
363
|
|
|
22
|
-
|
|
364
|
+
自定义区域时,`left`、`top`、`width`、`height`、`cornerRadius` 必须一起提供;`outline` 可以单独设置。启动返回 `{ requestId, ok, state: 'started' }`,停止返回 `{ requestId, ok, state: 'cancel' }`。
|
|
365
|
+
|
|
366
|
+
#### 拍照
|
|
367
|
+
|
|
368
|
+
```js
|
|
369
|
+
const photo = await glass3.camera.takePhoto({
|
|
370
|
+
returnBase64: true,
|
|
371
|
+
upload: false,
|
|
372
|
+
timeout: 5000
|
|
373
|
+
});
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
| 字段 | 类型 | 默认值 | 说明 |
|
|
377
|
+
| --- | --- | --- | --- |
|
|
378
|
+
| `returnBase64` | `boolean` | `true` | 返回 `photoMime` 和 `photoBase64` |
|
|
379
|
+
| `upload` | `boolean` | `false` | 上传照片 |
|
|
380
|
+
| `timeout` | `number` | `5000` | JS 等待超时,正整数毫秒,不发送给 Native |
|
|
381
|
+
|
|
382
|
+
结果包含 `{ requestId, ok, photoSize, filePath, width, height }`,并按选项提供 `photoMime`、`photoBase64`、`fileUrl`、`inspectionResultId` 或 `uploadError`。超时抛出 `CALL_TIMEOUT`;这只会停止 JS 等待,不保证 Native 操作已取消。
|
|
383
|
+
|
|
384
|
+
#### 录像
|
|
385
|
+
|
|
386
|
+
```js
|
|
387
|
+
const video = await glass3.camera.startTakeVideo(
|
|
388
|
+
{ enableAudio: true, segmentMinutes: 20 },
|
|
389
|
+
{
|
|
390
|
+
onEvent(result) {
|
|
391
|
+
// started、分段文件、canceled 或失败事件
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
);
|
|
395
|
+
|
|
396
|
+
await glass3.camera.stopTakeVideo({ requestId: video.requestId });
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
`enableAudio` 默认 `true`;`segmentMinutes` 默认 `20`,必须是正整数。分段事件包含 `filePath`、`startTime`、`endTime`、`hasMore`。`hasMore: false` 是最后一段。
|
|
400
|
+
|
|
401
|
+
### Face
|
|
402
|
+
|
|
403
|
+
```js
|
|
404
|
+
const recognition = await glass3.face.startRecognize({}, {
|
|
405
|
+
onEvent(result) {
|
|
406
|
+
// personId、personName、similarity、faceModel 等
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
|
|
410
|
+
await glass3.face.stopRecognize({ requestId: recognition.requestId });
|
|
411
|
+
```
|
|
412
|
+
|
|
413
|
+
`startRecognize()` 不接收业务参数;需要传 `onEvent` 时,第一个参数必须是空对象。启动返回 `{ requestId, ok: true }`,停止返回 `{ requestId, ok: true, state: 'stopped' }`。
|
|
414
|
+
|
|
415
|
+
### Motion
|
|
416
|
+
|
|
417
|
+
```js
|
|
418
|
+
const detection = await glass3.motion.startDetect({}, {
|
|
419
|
+
onEvent(result) {
|
|
420
|
+
// { ok, motionState, previous, moving, timestamp }
|
|
421
|
+
}
|
|
422
|
+
});
|
|
423
|
+
|
|
424
|
+
await glass3.motion.stopDetect({ requestId: detection.requestId });
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
`motionState` 可选值:`still`、`walk`、`run`、`headTurnLeft`、`headTurnRight`。Native 仅在状态变化时上报;首个事件的 `previous` 为 `unknown`。
|
|
428
|
+
|
|
429
|
+
### OpenAPI
|
|
430
|
+
|
|
431
|
+
`glass3.openapi` 使用 HTTPS/SSE,不经过 Host RPC。
|
|
432
|
+
|
|
433
|
+
```js
|
|
434
|
+
glass3.openapi.setConfig({
|
|
435
|
+
apiKey: '<AK>'
|
|
436
|
+
});
|
|
437
|
+
|
|
438
|
+
const result = await glass3.openapi.visionExtract(
|
|
439
|
+
{
|
|
440
|
+
image: 'data:image/jpeg;base64,...',
|
|
441
|
+
prompt: '图中有什么安全隐患',
|
|
442
|
+
uiType: 'table',
|
|
443
|
+
fields: [
|
|
444
|
+
{ name: 'hazard', title: '隐患', type: 'string' },
|
|
445
|
+
{ name: 'suggestion', title: '修改建议', type: 'string' }
|
|
446
|
+
]
|
|
447
|
+
},
|
|
448
|
+
{
|
|
449
|
+
onEvent(event) {
|
|
450
|
+
// type: start | snapshot | discard | result | error
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
);
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
配置:
|
|
457
|
+
|
|
458
|
+
| 字段 | 类型 | 必填/默认值 | 说明 |
|
|
459
|
+
| --- | --- | --- | --- |
|
|
460
|
+
| `apiKey` | `string` | 必填 | Rokid OpenAPI AK |
|
|
461
|
+
| `baseUrl` | `string` | `https://api.rokid.com` | 测试环境使用 `https://api-test.rokid.com` |
|
|
462
|
+
|
|
463
|
+
`visionExtract()` 参数:
|
|
464
|
+
|
|
465
|
+
| 字段 | 类型 | 说明 |
|
|
466
|
+
| --- | --- | --- |
|
|
467
|
+
| `image` | `string` | 必填;纯 Base64 或 Data URL,原图最大 10MB |
|
|
468
|
+
| `prompt` | `string` | 必填;最长 8192 字符 |
|
|
469
|
+
| `uiType` | `string` | 必填;`text` 或 `table` |
|
|
470
|
+
| `fields` | `array` | `table` 必填 1~8 项;`text` 时省略或传空数组 |
|
|
471
|
+
|
|
472
|
+
`fields[]` 包含稳定的英文 `name`、展示名 `title`,以及 `string`、`number` 或 `boolean` 类型。Promise 在收到 `[DONE]` 后返回最终 `result`;`result.success === false` 属于已完成的业务失败,仍然 resolve。HTTP、网络、SSE、协议、超时及 `event:error` 会 reject。
|
|
473
|
+
|
|
474
|
+
不要把 API Key 放入页面渲染数据或日志。SDK 日志会脱敏 `apiKey`、`Authorization` 和图片 Base64。
|
|
475
|
+
|
|
476
|
+
## 错误处理
|
|
477
|
+
|
|
478
|
+
```js
|
|
479
|
+
import glass3, { Glass3Error } from 'rvis-aiui-kit';
|
|
480
|
+
|
|
481
|
+
try {
|
|
482
|
+
await glass3.camera.takePhoto({ timeout: 5000 });
|
|
483
|
+
} catch (error) {
|
|
484
|
+
if (error instanceof Glass3Error) {
|
|
485
|
+
console.error(error.code, error.stage, error.requestId);
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
`Glass3Error` 提供 `name`、`message`、`code`、`stage`、`requestId`、`namespace`、`method`、`details` 和 `cause`。
|
|
491
|
+
|
|
492
|
+
常见错误码:
|
|
493
|
+
|
|
494
|
+
| 错误码 | 说明 |
|
|
495
|
+
| --- | --- |
|
|
496
|
+
| `INVALID_PARAMS` | 参数缺失、类型或枚举错误、存在未支持字段 |
|
|
497
|
+
| `TRANSPORT_REJECTED` | Host RPC 传输层返回非成功状态 |
|
|
498
|
+
| `NATIVE_REQUEST_ERROR` | 请求发送或响应阶段异常 |
|
|
499
|
+
| `NATIVE_REQUEST_NOT_ACCEPTED` | Native 响应未通过协议校验或未受理 |
|
|
500
|
+
| `NATIVE_EVENT_ERROR` | 匹配的 Native event 返回失败 |
|
|
501
|
+
| `CALL_TIMEOUT` | JS 等待超时 |
|
|
502
|
+
| `CALL_DISPOSED` | 请求等待期间调用了 `glass3.dispose()` |
|
|
503
|
+
| `OPENAPI_NOT_CONFIGURED` | OpenAPI 尚未配置 |
|
|
504
|
+
| `OPENAPI_HTTP_ERROR` | OpenAPI 返回非成功 HTTP 状态 |
|
|
505
|
+
| `OPENAPI_STREAM_ERROR` | SSE 连接或传输失败 |
|
|
506
|
+
| `OPENAPI_PROTOCOL_ERROR` | SSE 结果或结束帧不符合协议 |
|
|
507
|
+
| `OPENAPI_SERVICE_ERROR` | OpenAPI 返回 `event:error` |
|
|
508
|
+
|
|
509
|
+
Native 也可能返回自己的错误码。恢复逻辑应判断 `error.code`,不要匹配 `message` 文本。
|
|
510
|
+
|
|
511
|
+
## 页面卸载与资源清理
|
|
512
|
+
|
|
513
|
+
以下长任务应保存启动 `requestId`,并在页面卸载前调用对应 stop/unregister:
|
|
514
|
+
|
|
515
|
+
- `deviceContext.observe()`;
|
|
516
|
+
- `tts.speak()`;
|
|
517
|
+
- `offlineCommand.register()`;
|
|
518
|
+
- `audio.startRecord()`;
|
|
519
|
+
- `camera.startPreview()`;
|
|
520
|
+
- `camera.startTakeVideo()`;
|
|
521
|
+
- `face.startRecognize()`;
|
|
522
|
+
- `motion.startDetect()`。
|
|
523
|
+
|
|
524
|
+
最后调用 `glass3.dispose()`。`dispose()` 只清理 SDK 本地监听、等待中的 Promise 和 OpenAPI SSE,不等价于所有 Native 长任务的业务 stop 操作。
|
|
525
|
+
|
|
526
|
+
## 组件 API
|
|
527
|
+
|
|
528
|
+
所有组件都通过 `rvis-aiui-kit/<组件名>` 注册。数组或对象类属性使用 JSON 字符串传递,调用方需要先执行 `JSON.stringify()`。
|
|
529
|
+
|
|
530
|
+
### Image
|
|
531
|
+
|
|
532
|
+
注册路径:`rvis-aiui-kit/image`
|
|
533
|
+
|
|
534
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
535
|
+
| --- | --- | --- | --- |
|
|
536
|
+
| `src` | `String` | `''` | 网络地址、本地路径或 Base64 Data URL |
|
|
537
|
+
| `width` | `String` | `'168px'` | 图片宽度 |
|
|
538
|
+
| `height` | `String` | `'104px'` | 图片高度 |
|
|
539
|
+
| `objectFit` | `String` | `'fill'` | `contain`、`cover` 或 `fill` |
|
|
540
|
+
|
|
541
|
+
组件固定使用 `2px` 圆角。默认尺寸与 `glass3.camera.startPreview()` 的默认预览区域一致。
|
|
542
|
+
|
|
543
|
+
```html
|
|
544
|
+
<rvis-image src="{{ imageSrc }}" objectFit="cover"></rvis-image>
|
|
545
|
+
```
|
|
546
|
+
|
|
547
|
+
Base64 拍照结果可转换为 Data URL:
|
|
548
|
+
|
|
549
|
+
```js
|
|
550
|
+
const imageSrc = `data:${photo.photoMime || 'image/jpeg'};base64,${photo.photoBase64}`;
|
|
551
|
+
```
|
|
552
|
+
|
|
553
|
+
### List
|
|
554
|
+
|
|
555
|
+
注册路径:`rvis-aiui-kit/list`
|
|
556
|
+
|
|
557
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
558
|
+
| --- | --- | --- | --- |
|
|
559
|
+
| `title` | `String` | `''` | 列表标题 |
|
|
560
|
+
| `description` | `String` | `''` | 标题后的补充说明 |
|
|
561
|
+
| `items` | `String` | `'[]'` | Item 数组序列化后的 JSON 字符串 |
|
|
562
|
+
|
|
563
|
+
Item 结构:
|
|
564
|
+
|
|
565
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
566
|
+
| --- | --- | --- | --- |
|
|
567
|
+
| `id` | `String` | 是 | 稳定且唯一的列表项 ID |
|
|
568
|
+
| `text` | `String` | 是 | 列表项文案 |
|
|
569
|
+
| `completed` | `Boolean` | 是 | 是否显示完成标记 |
|
|
570
|
+
|
|
571
|
+
```js
|
|
572
|
+
data: {
|
|
573
|
+
items: JSON.stringify([
|
|
574
|
+
{ id: 'camera', text: '检查相机', completed: true },
|
|
575
|
+
{ id: 'network', text: '检查网络', completed: false }
|
|
576
|
+
])
|
|
577
|
+
}
|
|
578
|
+
```
|
|
579
|
+
|
|
580
|
+
```html
|
|
581
|
+
<rvis-list title="检查清单" items="{{ items }}"></rvis-list>
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
组件不提供事件或插槽。动态隐藏时保持组件挂载,并使用定位将其移出屏幕;不要用 `ink:if` 反复卸载,也不要用 `display` 隐藏。
|
|
585
|
+
|
|
586
|
+
### Markdown
|
|
587
|
+
|
|
588
|
+
注册路径:`rvis-aiui-kit/markdown`
|
|
589
|
+
|
|
590
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
591
|
+
| --- | --- | --- | --- |
|
|
592
|
+
| `content` | `String` | `''` | 原始 Markdown 字符串 |
|
|
593
|
+
|
|
594
|
+
```html
|
|
595
|
+
<rvis-markdown content="{{ markdownContent }}"></rvis-markdown>
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
支持范围:
|
|
599
|
+
|
|
600
|
+
- 独占一行的 Markdown 图片;
|
|
601
|
+
- 普通段落与段内 `**粗体**`;
|
|
602
|
+
- 管道表格;
|
|
603
|
+
- `1. 内容` 形式的编号列表。
|
|
604
|
+
|
|
605
|
+
不支持标题、嵌套列表、斜体、代码、公式、HTML 和可点击链接。组件宽度为 `424px`,不内置滚动容器;长内容应由页面放入 `scroll-view`。当前版本针对完整文档展示,不保证逐 token 流式更新时布局稳定。
|
|
606
|
+
|
|
607
|
+
### Model List
|
|
608
|
+
|
|
609
|
+
注册路径:`rvis-aiui-kit/model-list`
|
|
610
|
+
|
|
611
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
612
|
+
| --- | --- | --- | --- |
|
|
613
|
+
| `items` | `String` | `'[]'` | Item 数组序列化后的 JSON 字符串 |
|
|
614
|
+
| `selectedId` | `String` | `''` | 当前选中项 ID |
|
|
615
|
+
| `showIndex` | `Boolean` | `true` | 是否显示序号 |
|
|
616
|
+
| `visible` | `Boolean` | `true` | 是否显示在屏幕内 |
|
|
617
|
+
|
|
618
|
+
Item 结构:
|
|
619
|
+
|
|
620
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
621
|
+
| --- | --- | --- | --- |
|
|
622
|
+
| `id` | `String` | 是 | 唯一 ID |
|
|
623
|
+
| `title` | `String` | 是 | 标题 |
|
|
624
|
+
| `description` | `String` | 否 | 右侧说明 |
|
|
625
|
+
| `indexText` | `String` | 否 | 自定义序号 |
|
|
626
|
+
|
|
627
|
+
```html
|
|
628
|
+
<rvis-model-list
|
|
629
|
+
items="{{ modelItems }}"
|
|
630
|
+
selectedId="{{ selectedModelId }}"
|
|
631
|
+
visible="{{ showModelList }}"
|
|
632
|
+
style="position: fixed; top: 0; left: 0; right: 0; bottom: 0; z-index: 1000;"
|
|
633
|
+
></rvis-model-list>
|
|
634
|
+
```
|
|
635
|
+
|
|
636
|
+
组件不提供选择事件,页面通过设备按键或业务逻辑更新 `selectedId`。调用方必须按示例为组件宿主设置全屏固定定位,否则自定义组件宿主可能裁剪遮罩。
|
|
637
|
+
|
|
638
|
+
### Paragraph
|
|
639
|
+
|
|
640
|
+
注册路径:`rvis-aiui-kit/paragraph`
|
|
641
|
+
|
|
642
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
643
|
+
| --- | --- | --- | --- |
|
|
644
|
+
| `text` | `String` | `''` | 普通段落文本 |
|
|
645
|
+
| `width` | `String` | `'380px'` | 段落宽度 |
|
|
646
|
+
| `segments` | `String` | `'[]'` | `{ text, bold }` 数组序列化后的 JSON 字符串;非空时优先于 `text` |
|
|
647
|
+
|
|
648
|
+
```js
|
|
649
|
+
data: {
|
|
650
|
+
segments: JSON.stringify([
|
|
651
|
+
{ text: '状态:' },
|
|
652
|
+
{ text: '正常', bold: true }
|
|
653
|
+
])
|
|
654
|
+
}
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
```html
|
|
658
|
+
<rvis-paragraph text="{{ text }}" width="424px" segments="{{ segments }}"></rvis-paragraph>
|
|
659
|
+
```
|
|
660
|
+
|
|
661
|
+
### Status Bar
|
|
662
|
+
|
|
663
|
+
注册路径:`rvis-aiui-kit/status-bar`
|
|
664
|
+
|
|
665
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
666
|
+
| --- | --- | --- | --- |
|
|
667
|
+
| `title` | `String` | `''` | 左侧应用标题 |
|
|
668
|
+
|
|
669
|
+
```html
|
|
670
|
+
<rvis-status-bar title="应用名称"></rvis-status-bar>
|
|
671
|
+
```
|
|
672
|
+
|
|
673
|
+
组件尺寸固定为 `480px × 20px`,显示应用标题、本地日期时间和实时电量。页面应将其放在全屏绘制区域的 `(0, 0)`。组件自动管理时钟和 `power` 订阅,但 Page 必须把 `onMessage` 转发给共享的 `glass3` 实例。
|
|
674
|
+
|
|
675
|
+
### Table
|
|
676
|
+
|
|
677
|
+
注册路径:`rvis-aiui-kit/table`
|
|
678
|
+
|
|
679
|
+
| 属性 | 类型 | 默认值 | 说明 |
|
|
680
|
+
| --- | --- | --- | --- |
|
|
681
|
+
| `header` | `String` | `''` | 表格标题;空白时不渲染标题区 |
|
|
682
|
+
| `column` | `String` | `'[]'` | Column 数组序列化后的 JSON 字符串 |
|
|
683
|
+
| `data` | `String` | `'[]'` | 数据数组序列化后的 JSON 字符串 |
|
|
684
|
+
| `direction` | `String` | `'horizontal'` | `horizontal` 或 `vertical` |
|
|
685
|
+
| `compact` | `Boolean` | `false` | 横向表格是否使用紧凑内边距 |
|
|
686
|
+
| `columnWidths` | `String` | `''` | 横向列宽,例如 `'120px 156px 144px'`;空值表示等分 |
|
|
687
|
+
|
|
688
|
+
Column 结构:
|
|
689
|
+
|
|
690
|
+
| 字段 | 类型 | 必填 | 说明 |
|
|
691
|
+
| --- | --- | --- | --- |
|
|
692
|
+
| `title` | `String` | 是 | 字段标题 |
|
|
693
|
+
| `dataIndex` | `String` | 是 | 数据字段名 |
|
|
694
|
+
| `align` | `String` | 否 | `left`、`center` 或 `right` |
|
|
695
|
+
|
|
696
|
+
每条数据应提供稳定且唯一的 `key`。
|
|
697
|
+
|
|
698
|
+
```js
|
|
699
|
+
data: {
|
|
700
|
+
columns: JSON.stringify([
|
|
701
|
+
{ title: '名称', dataIndex: 'name' },
|
|
702
|
+
{ title: '状态', dataIndex: 'status', align: 'right' }
|
|
703
|
+
]),
|
|
704
|
+
rows: JSON.stringify([
|
|
705
|
+
{ key: 'camera', name: '相机', status: '正常' }
|
|
706
|
+
])
|
|
707
|
+
}
|
|
708
|
+
```
|
|
709
|
+
|
|
710
|
+
```html
|
|
711
|
+
<rvis-table
|
|
712
|
+
header="设备状态"
|
|
713
|
+
column="{{ columns }}"
|
|
714
|
+
data="{{ rows }}"
|
|
715
|
+
direction="horizontal"
|
|
716
|
+
></rvis-table>
|
|
717
|
+
```
|
|
718
|
+
|
|
719
|
+
表格宽度为 `424px`。放在纵向 Flex 容器中时,父容器应设置 `align-items: flex-start`。
|