rvis-aiui-kit 1.1.0 → 1.2.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 +70 -5
- package/sdk/api-map.js +2 -0
- package/sdk/core/client.js +52 -15
- package/sdk/core/constants.js +1 -0
- package/sdk/core/transport.js +21 -2
- 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/sdk/modules/status-bar/index.js +78 -0
- package/sdk/modules/status-bar/readme.md +66 -0
package/package.json
CHANGED
package/sdk/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Glass3 扩展 SDK API 文档
|
|
2
2
|
|
|
3
|
-
本文档汇总 `sdk/` 目录当前公开的 JavaScript API
|
|
4
|
-
[`api-map.js`](./api-map.js)
|
|
5
|
-
|
|
3
|
+
本文档汇总 `sdk/` 目录当前公开的 JavaScript API。Host RPC 接口以
|
|
4
|
+
[`api-map.js`](./api-map.js) 为准;`glass3.openapi` 是独立的 HTTPS/SSE 客户端。
|
|
5
|
+
各模块的 `readme.md` 提供更完整的协议、事件时序与返回示例。
|
|
6
6
|
|
|
7
7
|
> 适用范围:项目内的 Host RPC 扩展能力。若 `glass3` 已提供对应能力,应优先使用
|
|
8
8
|
> 本 SDK;只有 SDK 未覆盖的能力才使用基础 AIUI 运行时 API。
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
- [API 总览](#api-总览)
|
|
14
14
|
- [通用调用约定](#通用调用约定)
|
|
15
15
|
- [Device Context 设备上下文](#device-context-设备上下文)
|
|
16
|
+
- [Status Bar 原生状态栏](#status-bar-原生状态栏)
|
|
16
17
|
- [Screen 屏幕控制](#screen-屏幕控制)
|
|
17
18
|
- [Notification 原生通知](#notification-原生通知)
|
|
18
19
|
- [TTS 语音播报](#tts-语音播报)
|
|
@@ -21,6 +22,7 @@
|
|
|
21
22
|
- [Camera 相机](#camera-相机)
|
|
22
23
|
- [Face 人脸识别](#face-人脸识别)
|
|
23
24
|
- [Motion 运动状态检测](#motion-运动状态检测)
|
|
25
|
+
- [OpenAPI](#openapi)
|
|
24
26
|
- [错误处理](#错误处理)
|
|
25
27
|
- [页面卸载清理](#页面卸载清理)
|
|
26
28
|
- [Native 映射](#native-映射)
|
|
@@ -64,6 +66,8 @@ import glass3, {
|
|
|
64
66
|
|
|
65
67
|
| 模块 | 方法 | 用途 |
|
|
66
68
|
| --- | --- | --- |
|
|
69
|
+
| `statusBar` | `setTitle({ title })` | 设置或清理当前 AIX 页面的状态栏标题。 |
|
|
70
|
+
| `statusBar` | `setVisible({ visible })` | 显示或重新隐藏 Native 状态栏。 |
|
|
67
71
|
| `deviceContext` | `get(options?)` | 一次性获取设备上下文原子快照。 |
|
|
68
72
|
| `deviceContext` | `observe(options?, callOptions?)` | 订阅设备上下文快照和增量变化。 |
|
|
69
73
|
| `deviceContext` | `stopObserve({ requestId })` | 停止指定的设备上下文订阅。 |
|
|
@@ -86,6 +90,8 @@ import glass3, {
|
|
|
86
90
|
| `face` | `stopRecognize({ requestId })` | 停止指定人脸识别。 |
|
|
87
91
|
| `motion` | `startDetect({}, callOptions?)` | 开始持续运动状态检测。 |
|
|
88
92
|
| `motion` | `stopDetect({ requestId })` | 停止指定运动检测。 |
|
|
93
|
+
| `openapi` | `setConfig({ baseUrl?, apiKey })` | 配置全局 OpenAPI 客户端。 |
|
|
94
|
+
| `openapi` | `visionExtract(params, callOptions?)` | 通过 POST SSE 识别图片。 |
|
|
89
95
|
|
|
90
96
|
客户端级方法:
|
|
91
97
|
|
|
@@ -215,6 +221,25 @@ const result = await glass3.deviceContext.stopObserve({
|
|
|
215
221
|
|
|
216
222
|
详见 [`modules/device-context/readme.md`](./modules/device-context/readme.md)。
|
|
217
223
|
|
|
224
|
+
## Status Bar 原生状态栏
|
|
225
|
+
|
|
226
|
+
状态栏是 Host 管理的系统 UI,可在屏幕顶部显示标题、时间、网络和电量。该能力只在
|
|
227
|
+
通过 `OPEN_AIX_INK` 外部入口打开的 AIX 页面中注册,页面创建后默认隐藏。
|
|
228
|
+
|
|
229
|
+
建议先设置标题,再显示:
|
|
230
|
+
|
|
231
|
+
```js
|
|
232
|
+
await glass3.statusBar.setTitle({ title: '设备巡检' });
|
|
233
|
+
const result = await glass3.statusBar.setVisible({ visible: true });
|
|
234
|
+
// { updated: true, visible: true }
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
`title` 必须是字符串;空字符串或全空白字符串用于清理标题。`visible` 必须是
|
|
238
|
+
Boolean。两个方法直接解析 Host RPC HTTP response body,不依赖 `onMessage`,并有
|
|
239
|
+
5 秒本地等待上限。
|
|
240
|
+
|
|
241
|
+
详见 [`modules/status-bar/readme.md`](./modules/status-bar/readme.md)。
|
|
242
|
+
|
|
218
243
|
## Screen 屏幕控制
|
|
219
244
|
|
|
220
245
|
### `glass3.screen.turnOff()`
|
|
@@ -851,6 +876,36 @@ const result = await glass3.motion.stopDetect({
|
|
|
851
876
|
|
|
852
877
|
详见 [`modules/motion/readme.md`](./modules/motion/readme.md)。
|
|
853
878
|
|
|
879
|
+
## OpenAPI
|
|
880
|
+
|
|
881
|
+
`glass3.openapi` 是全局 HTTPS/SSE 客户端,不经过 Host RPC:
|
|
882
|
+
|
|
883
|
+
```js
|
|
884
|
+
glass3.openapi.setConfig({
|
|
885
|
+
apiKey: '<AK>'
|
|
886
|
+
});
|
|
887
|
+
|
|
888
|
+
const result = await glass3.openapi.visionExtract(
|
|
889
|
+
{
|
|
890
|
+
image: 'data:image/jpeg;base64,...',
|
|
891
|
+
prompt: '图中有什么安全隐患',
|
|
892
|
+
uiType: 'table',
|
|
893
|
+
fields: [
|
|
894
|
+
{ name: 'hazard', title: '隐患', type: 'string' }
|
|
895
|
+
]
|
|
896
|
+
},
|
|
897
|
+
{
|
|
898
|
+
onEvent(event) {
|
|
899
|
+
console.log(event.type, JSON.stringify(event.data));
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
);
|
|
903
|
+
```
|
|
904
|
+
|
|
905
|
+
`baseUrl` 默认是 `https://api.rokid.com`;测试环境需要显式配置。
|
|
906
|
+
Promise 在收到 `[DONE]` 后返回最终 `result`。`glass3.dispose()` 会关闭并拒绝尚未
|
|
907
|
+
完成的 OpenAPI 请求。详见 [`modules/openapi/readme.md`](./modules/openapi/readme.md)。
|
|
908
|
+
|
|
854
909
|
## 错误处理
|
|
855
910
|
|
|
856
911
|
所有 SDK 错误都使用 `Glass3Error`:
|
|
@@ -889,6 +944,11 @@ try {
|
|
|
889
944
|
| `NATIVE_EVENT_ERROR` | 匹配的 Native event 返回失败。 |
|
|
890
945
|
| `CALL_TIMEOUT` | JS 等待超时;当前用于 `camera.takePhoto()`。 |
|
|
891
946
|
| `CALL_DISPOSED` | 调用尚未完成时执行了 `glass3.dispose()`。 |
|
|
947
|
+
| `OPENAPI_NOT_CONFIGURED` | 调用 OpenAPI 前没有执行 `setConfig()`。 |
|
|
948
|
+
| `OPENAPI_HTTP_ERROR` | OpenAPI 返回非成功 HTTP 状态。 |
|
|
949
|
+
| `OPENAPI_STREAM_ERROR` | SSE 连接或传输失败。 |
|
|
950
|
+
| `OPENAPI_PROTOCOL_ERROR` | SSE 未按约定返回结果或结束标记。 |
|
|
951
|
+
| `OPENAPI_SERVICE_ERROR` | OpenAPI 返回 `event:error`。 |
|
|
892
952
|
| `GLASS3_ERROR` | 未提供更具体错误码时的默认值。 |
|
|
893
953
|
|
|
894
954
|
Native 也可能直接返回自己的错误码。需要恢复策略时,应按 `error.code` 判断,不要
|
|
@@ -948,8 +1008,8 @@ export default {
|
|
|
948
1008
|
|
|
949
1009
|
## Native 映射
|
|
950
1010
|
|
|
951
|
-
|
|
952
|
-
`method: "invoke"`。
|
|
1011
|
+
除 `statusBar` 外的 Host RPC 业务调用使用 `version: "2.0.0"`、
|
|
1012
|
+
`namespace: "rokid.tools"`、`method: "invoke"`。
|
|
953
1013
|
|
|
954
1014
|
| JavaScript API | `toolName` | `toolAction` |
|
|
955
1015
|
| --- | --- | --- |
|
|
@@ -976,12 +1036,16 @@ export default {
|
|
|
976
1036
|
| `motion.startDetect` | `motionDetect` | `start` |
|
|
977
1037
|
| `motion.stopDetect` | `motionDetect` | `stop` |
|
|
978
1038
|
|
|
1039
|
+
`statusBar.setTitle` 和 `statusBar.setVisible` 使用 `namespace: "rokid.statusBar"`,
|
|
1040
|
+
Native method 分别为 `setTitle` 和 `setVisible`,业务参数直接放在 `params` 中。
|
|
1041
|
+
|
|
979
1042
|
业务代码应调用公开 JavaScript API,不要直接依赖这张 Native 映射表发 RPC。
|
|
980
1043
|
|
|
981
1044
|
## 详细文档与 Demo
|
|
982
1045
|
|
|
983
1046
|
### 模块文档
|
|
984
1047
|
|
|
1048
|
+
- [Status Bar](./modules/status-bar/readme.md)
|
|
985
1049
|
- [Device Context](./modules/device-context/readme.md)
|
|
986
1050
|
- [Screen](./modules/screen/readme.md)
|
|
987
1051
|
- [Notification](./modules/notification/readme.md)
|
|
@@ -994,6 +1058,7 @@ export default {
|
|
|
994
1058
|
|
|
995
1059
|
### 示例页面
|
|
996
1060
|
|
|
1061
|
+
- [Status Bar Demo](../pages/sdk-demo/status-bar/index.ink)
|
|
997
1062
|
- [Device Context Demo](../pages/sdk-demo/device-context/index.ink)
|
|
998
1063
|
- [Screen Demo](../pages/sdk-demo/screen/index.ink)
|
|
999
1064
|
- [Notification Demo Suite](../pages/sdk-demo/notification/index.ink)
|
package/sdk/api-map.js
CHANGED
|
@@ -6,11 +6,13 @@ import motion from './modules/motion/index.js';
|
|
|
6
6
|
import notification from './modules/notification/index.js';
|
|
7
7
|
import offlineCommand from './modules/offline-command/index.js';
|
|
8
8
|
import screen from './modules/screen/index.js';
|
|
9
|
+
import statusBar from './modules/status-bar/index.js';
|
|
9
10
|
import tts from './modules/tts/index.js';
|
|
10
11
|
|
|
11
12
|
// This map is the only mapping between the public JavaScript API and Host RPC.
|
|
12
13
|
// Public names are never inferred from the native namespace or method strings.
|
|
13
14
|
export const API_MAP = [].concat(
|
|
15
|
+
statusBar,
|
|
14
16
|
deviceContext,
|
|
15
17
|
notification,
|
|
16
18
|
screen,
|
package/sdk/core/client.js
CHANGED
|
@@ -43,12 +43,14 @@ export class Glass3Client {
|
|
|
43
43
|
requestId,
|
|
44
44
|
namespace: definition.namespace,
|
|
45
45
|
method: definition.method,
|
|
46
|
-
params:
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
46
|
+
params: typeof definition.buildRequestParams === 'function'
|
|
47
|
+
? definition.buildRequestParams(nativeArgs)
|
|
48
|
+
: {
|
|
49
|
+
toolName: definition.toolName,
|
|
50
|
+
toolAction: definition.toolAction,
|
|
51
|
+
args: nativeArgs,
|
|
52
|
+
extra: {}
|
|
53
|
+
}
|
|
52
54
|
};
|
|
53
55
|
|
|
54
56
|
if (definition.completion === COMPLETION_EVENT) {
|
|
@@ -59,7 +61,12 @@ export class Glass3Client {
|
|
|
59
61
|
return this.invokeUntilReadyEventStream(definition, request, callOptions);
|
|
60
62
|
}
|
|
61
63
|
|
|
62
|
-
return this.invokeUntilAccepted(
|
|
64
|
+
return this.invokeUntilAccepted(
|
|
65
|
+
definition,
|
|
66
|
+
request,
|
|
67
|
+
callOptions,
|
|
68
|
+
timeoutMs
|
|
69
|
+
);
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
sendRequest(definition, request) {
|
|
@@ -104,7 +111,7 @@ export class Glass3Client {
|
|
|
104
111
|
return true;
|
|
105
112
|
}
|
|
106
113
|
|
|
107
|
-
invokeUntilAccepted(definition, request, callOptions) {
|
|
114
|
+
invokeUntilAccepted(definition, request, callOptions, timeoutMs) {
|
|
108
115
|
if (typeof callOptions.onEvent === 'function') {
|
|
109
116
|
this.activeInvocations.set(request.requestId, {
|
|
110
117
|
requestId: request.requestId,
|
|
@@ -113,13 +120,37 @@ export class Glass3Client {
|
|
|
113
120
|
});
|
|
114
121
|
}
|
|
115
122
|
|
|
116
|
-
|
|
123
|
+
let timeoutId = null;
|
|
124
|
+
const responsePromise = this.sendRequest(definition, request);
|
|
125
|
+
|
|
126
|
+
if (timeoutMs !== undefined) {
|
|
127
|
+
timeoutId = setTimeout(() => {
|
|
128
|
+
this.rejectPendingResponse(request.requestId, new Glass3Error(
|
|
129
|
+
`Glass3 call timed out after ${timeoutMs}ms: ${definition.publicModule}.${definition.publicMethod}`,
|
|
130
|
+
{
|
|
131
|
+
code: 'CALL_TIMEOUT',
|
|
132
|
+
stage: 'timeout',
|
|
133
|
+
requestId: request.requestId,
|
|
134
|
+
namespace: definition.namespace,
|
|
135
|
+
method: definition.method,
|
|
136
|
+
details: { timeout: timeoutMs }
|
|
137
|
+
}
|
|
138
|
+
));
|
|
139
|
+
}, timeoutMs);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
return responsePromise.then(response => {
|
|
143
|
+
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
117
144
|
this.validateAcceptedResponse(definition, request.requestId, response);
|
|
145
|
+
if (typeof definition.selectAcceptedResult === 'function') {
|
|
146
|
+
return definition.selectAcceptedResult(response);
|
|
147
|
+
}
|
|
118
148
|
return {
|
|
119
149
|
requestId: response.requestId,
|
|
120
150
|
ok: response.ok
|
|
121
151
|
};
|
|
122
152
|
}).catch(error => {
|
|
153
|
+
if (timeoutId !== null) clearTimeout(timeoutId);
|
|
123
154
|
this.activeInvocations.delete(request.requestId);
|
|
124
155
|
throw this.normalizeInvocationError(error, definition, request.requestId);
|
|
125
156
|
});
|
|
@@ -235,22 +266,28 @@ export class Glass3Client {
|
|
|
235
266
|
acceptedResult.toolName === definition.toolName &&
|
|
236
267
|
acceptedResult.toolAction === definition.toolAction
|
|
237
268
|
);
|
|
238
|
-
const
|
|
269
|
+
const validChannel = !definition.responseChannel || (
|
|
270
|
+
response && response.channel === definition.responseChannel
|
|
271
|
+
);
|
|
272
|
+
const validEnvelope = response &&
|
|
273
|
+
validChannel &&
|
|
239
274
|
response.version === RPC_VERSION &&
|
|
240
275
|
response.kind === 'response' &&
|
|
241
|
-
response.requestId === requestId
|
|
242
|
-
|
|
243
|
-
validAcceptedResult;
|
|
276
|
+
response.requestId === requestId;
|
|
277
|
+
const validResponse = validEnvelope &&
|
|
278
|
+
response.ok === true && validAcceptedResult;
|
|
244
279
|
|
|
245
280
|
if (validResponse) return;
|
|
246
281
|
|
|
247
|
-
const nativeError =
|
|
282
|
+
const nativeError = validEnvelope && response.ok === false
|
|
283
|
+
? response.error
|
|
284
|
+
: null;
|
|
248
285
|
throw new Glass3Error(
|
|
249
286
|
nativeError && nativeError.message
|
|
250
287
|
? nativeError.message
|
|
251
288
|
: `Native request was not accepted: ${definition.publicModule}.${definition.publicMethod}`,
|
|
252
289
|
{
|
|
253
|
-
code: nativeError && nativeError.code
|
|
290
|
+
code: nativeError && nativeError.code !== undefined
|
|
254
291
|
? nativeError.code
|
|
255
292
|
: 'NATIVE_REQUEST_NOT_ACCEPTED',
|
|
256
293
|
stage: 'response',
|
package/sdk/core/constants.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
export const RPC_URL = 'https://ink-host-rpc.invalid/rpc';
|
|
2
2
|
export const RPC_ORIGIN = 'rokid://host-rpc';
|
|
3
3
|
export const RPC_VERSION = '2.0.0';
|
|
4
|
+
export const RPC_CHANNEL = 'rokid.host.rpc';
|
|
4
5
|
|
|
5
6
|
export const RPC_SUCCESS_STATUS_MIN = 200;
|
|
6
7
|
export const RPC_SUCCESS_STATUS_MAX = 299;
|
package/sdk/core/transport.js
CHANGED
|
@@ -22,10 +22,20 @@ export class HostRpcTransport {
|
|
|
22
22
|
JSON.stringify(redactSensitiveDataForLog(request))
|
|
23
23
|
);
|
|
24
24
|
|
|
25
|
-
return requestFetch(this.url, {
|
|
25
|
+
return Promise.resolve().then(() => requestFetch(this.url, {
|
|
26
26
|
method: 'POST',
|
|
27
27
|
headers: { 'content-type': 'application/json' },
|
|
28
28
|
body: requestBody
|
|
29
|
+
})).catch(error => {
|
|
30
|
+
if (error instanceof Glass3Error) throw error;
|
|
31
|
+
throw new Glass3Error('Host RPC transport failed', {
|
|
32
|
+
code: 'TRANSPORT_ERROR',
|
|
33
|
+
stage: 'transport',
|
|
34
|
+
requestId: request.requestId,
|
|
35
|
+
namespace: request.namespace,
|
|
36
|
+
method: request.method,
|
|
37
|
+
cause: error
|
|
38
|
+
});
|
|
29
39
|
}).then(response => {
|
|
30
40
|
if (
|
|
31
41
|
response.status < RPC_SUCCESS_STATUS_MIN ||
|
|
@@ -43,7 +53,16 @@ export class HostRpcTransport {
|
|
|
43
53
|
);
|
|
44
54
|
}
|
|
45
55
|
|
|
46
|
-
return response.json()
|
|
56
|
+
return Promise.resolve().then(() => response.json()).catch(error => {
|
|
57
|
+
throw new Glass3Error('Host RPC response is not valid JSON', {
|
|
58
|
+
code: 'TRANSPORT_INVALID_RESPONSE',
|
|
59
|
+
stage: 'transport',
|
|
60
|
+
requestId: request.requestId,
|
|
61
|
+
namespace: request.namespace,
|
|
62
|
+
method: request.method,
|
|
63
|
+
cause: error
|
|
64
|
+
});
|
|
65
|
+
});
|
|
47
66
|
}).then(result => {
|
|
48
67
|
console.log(
|
|
49
68
|
'[glass3] Native fetch response:',
|
package/sdk/index.js
CHANGED
|
@@ -1,16 +1,20 @@
|
|
|
1
1
|
import API_MAP from './api-map.js';
|
|
2
2
|
import { Glass3Client } from './core/client.js';
|
|
3
|
+
import openapi, { openApiClient } from './modules/openapi/index.js';
|
|
3
4
|
import { createApiNamespaces } from './utils/api-builder.js';
|
|
4
5
|
|
|
5
6
|
const client = new Glass3Client();
|
|
6
7
|
const glass3 = createApiNamespaces(client, API_MAP);
|
|
7
8
|
|
|
9
|
+
glass3.openapi = openapi;
|
|
10
|
+
|
|
8
11
|
glass3.handleMessage = function handleMessage(messageEvent) {
|
|
9
12
|
return client.handleMessage(messageEvent);
|
|
10
13
|
};
|
|
11
14
|
|
|
12
15
|
glass3.dispose = function dispose() {
|
|
13
16
|
client.dispose();
|
|
17
|
+
openApiClient.dispose();
|
|
14
18
|
};
|
|
15
19
|
|
|
16
20
|
export { API_MAP } from './api-map.js';
|