@ray-js/t-agent-plugin-aistream 0.2.3-beta-2 → 0.2.3-beta-4
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/dist/AIStreamTypes.d.ts +91 -1
- package/dist/AIStreamTypes.js +8 -0
- package/dist/asr/AsrAgent.d.ts +59 -0
- package/dist/asr/AsrAgent.js +235 -0
- package/dist/asr/createAsrAgent.d.ts +31 -0
- package/dist/asr/createAsrAgent.js +35 -0
- package/dist/asr/index.d.ts +3 -0
- package/dist/asr/index.js +3 -0
- package/dist/buildIn/withBuildIn.js +22 -23
- package/dist/index.d.ts +1 -0
- package/dist/index.js +2 -1
- package/dist/utils/AIStream.d.ts +4 -2
- package/dist/utils/AIStream.js +9 -3
- package/dist/utils/defaultMock.js +19 -3
- package/dist/utils/index.d.ts +0 -1
- package/dist/utils/index.js +0 -1
- package/dist/utils/ttt.d.ts +5 -5
- package/dist/utils/ttt.js +3 -1
- package/dist/withAIStream.js +23 -10
- package/package.json +2 -2
- package/dist/utils/createAsrAgent.d.ts +0 -79
- package/dist/utils/createAsrAgent.js +0 -198
package/dist/AIStreamTypes.d.ts
CHANGED
|
@@ -791,6 +791,18 @@ export type StartPlayAudioParams = {
|
|
|
791
791
|
}) => void;
|
|
792
792
|
complete?: () => void;
|
|
793
793
|
};
|
|
794
|
+
export type StopPlayAudioParams = {
|
|
795
|
+
success?: (params: null) => void;
|
|
796
|
+
fail?: (params: {
|
|
797
|
+
errorMsg: string;
|
|
798
|
+
errorCode: string | number;
|
|
799
|
+
innerError: {
|
|
800
|
+
errorCode: string | number;
|
|
801
|
+
errorMsg: string;
|
|
802
|
+
};
|
|
803
|
+
}) => void;
|
|
804
|
+
complete?: () => void;
|
|
805
|
+
};
|
|
794
806
|
export type Attribute = {
|
|
795
807
|
/** Attribute 类型 */
|
|
796
808
|
type: AIStreamAttributeType;
|
|
@@ -862,6 +874,67 @@ export type AudioBody = {
|
|
|
862
874
|
*/
|
|
863
875
|
bitDepth?: number;
|
|
864
876
|
};
|
|
877
|
+
export declare enum AudioPlayChangedState {
|
|
878
|
+
/** 播放开始 */
|
|
879
|
+
START = 1,
|
|
880
|
+
/** 缓冲中 */
|
|
881
|
+
BUFFERING = 2,
|
|
882
|
+
/** 缓存完成继续播放 */
|
|
883
|
+
BUFFERED = 3,
|
|
884
|
+
/** 播放完成 */
|
|
885
|
+
COMPLETED = 4,
|
|
886
|
+
/** 播放异常 */
|
|
887
|
+
ERROR = 5
|
|
888
|
+
}
|
|
889
|
+
export type AudioPlayChangedBody = {
|
|
890
|
+
path: string;
|
|
891
|
+
/** 播放状态: 1-播放开始, 2-缓冲中, 3-缓存完成 继续播放, 4-播放完成, 5-播放异常 */
|
|
892
|
+
state: AudioPlayChangedState;
|
|
893
|
+
/** 播放异常码: 1-主动停止播放, 2-播放被异常中断, ... */
|
|
894
|
+
code?: number;
|
|
895
|
+
};
|
|
896
|
+
export interface AIStreamAudioFile {
|
|
897
|
+
/** 音频缓存路径 */
|
|
898
|
+
path: string;
|
|
899
|
+
/**
|
|
900
|
+
* 音频编码类型,表示音频数据的编码格式
|
|
901
|
+
* - 100: ADPCM
|
|
902
|
+
* - 101: PCM
|
|
903
|
+
* - 102: AACRaw
|
|
904
|
+
* - 103: AACADTS
|
|
905
|
+
* - 104: AACLATM
|
|
906
|
+
* - 105: G711U
|
|
907
|
+
* - 106: G711A
|
|
908
|
+
* - 107: G726
|
|
909
|
+
* - 108: SPEEX
|
|
910
|
+
* - 109: MP3
|
|
911
|
+
* - 110: G722
|
|
912
|
+
* - 111: Opus
|
|
913
|
+
*/
|
|
914
|
+
codecType: number;
|
|
915
|
+
/**
|
|
916
|
+
* 音频采样率,单位Hz
|
|
917
|
+
* 表示每秒采样次数,常见值:8000, 16000, 44100等
|
|
918
|
+
*/
|
|
919
|
+
sampleRate: number;
|
|
920
|
+
/**
|
|
921
|
+
* 音频位深,表示每个采样点的位数
|
|
922
|
+
* 常见值:8, 16, 24, 32等
|
|
923
|
+
*/
|
|
924
|
+
bitDepth: number;
|
|
925
|
+
/**
|
|
926
|
+
* 音频通道数
|
|
927
|
+
* - 0: 单声道
|
|
928
|
+
* - 1: 立体声
|
|
929
|
+
*/
|
|
930
|
+
channels: number;
|
|
931
|
+
}
|
|
932
|
+
export type RecordAndSendAudioFailBody = {
|
|
933
|
+
/**
|
|
934
|
+
* 录制发送异常: 1-发送数据异常, 2-录制音频异常
|
|
935
|
+
*/
|
|
936
|
+
code: 0 | 1;
|
|
937
|
+
};
|
|
865
938
|
export type VideoBody = {
|
|
866
939
|
/** 接收数据通道 */
|
|
867
940
|
dataChannel: string;
|
|
@@ -1217,6 +1290,10 @@ export type SendEventChatBreakParams = {
|
|
|
1217
1290
|
*@description 开始录制并发送音频数据
|
|
1218
1291
|
*/
|
|
1219
1292
|
export type StartRecordAndSendAudioDataParams = {
|
|
1293
|
+
saveFile?: boolean;
|
|
1294
|
+
recordInitParams?: {
|
|
1295
|
+
sampleRate?: number;
|
|
1296
|
+
};
|
|
1220
1297
|
/** 会话 id */
|
|
1221
1298
|
sessionId: string;
|
|
1222
1299
|
/** 下发数据通道,当音频只有单路的时候,可以不传 */
|
|
@@ -1241,7 +1318,7 @@ export type StopRecordAndSendAudioDataParams = {
|
|
|
1241
1318
|
dataChannel?: string;
|
|
1242
1319
|
/** 扩展属性 */
|
|
1243
1320
|
userData?: Attribute[];
|
|
1244
|
-
success?: (params: null) => void;
|
|
1321
|
+
success?: (params: AIStreamAudioFile | null) => void;
|
|
1245
1322
|
fail?: (params: {
|
|
1246
1323
|
errorMsg: string;
|
|
1247
1324
|
errorCode: string | number;
|
|
@@ -1342,6 +1419,19 @@ export type SendTextDataParams = {
|
|
|
1342
1419
|
}) => void;
|
|
1343
1420
|
complete?: () => void;
|
|
1344
1421
|
};
|
|
1422
|
+
export type InitAudioRecorderParams = {
|
|
1423
|
+
sampleRate?: number;
|
|
1424
|
+
success?: (params: null) => void;
|
|
1425
|
+
fail?: (params: {
|
|
1426
|
+
errorMsg: string;
|
|
1427
|
+
errorCode: string | number;
|
|
1428
|
+
innerError: {
|
|
1429
|
+
errorCode: string | number;
|
|
1430
|
+
errorMsg: string;
|
|
1431
|
+
};
|
|
1432
|
+
}) => void;
|
|
1433
|
+
complete?: () => void;
|
|
1434
|
+
};
|
|
1345
1435
|
export type SendFileDataParams = {
|
|
1346
1436
|
/** 会话 id */
|
|
1347
1437
|
sessionId: string;
|
package/dist/AIStreamTypes.js
CHANGED
|
@@ -187,6 +187,14 @@ export let AIStreamAttributePayloadType = /*#__PURE__*/function (AIStreamAttribu
|
|
|
187
187
|
AIStreamAttributePayloadType[AIStreamAttributePayloadType["STRING"] = 6] = "STRING";
|
|
188
188
|
return AIStreamAttributePayloadType;
|
|
189
189
|
}({});
|
|
190
|
+
export let AudioPlayChangedState = /*#__PURE__*/function (AudioPlayChangedState) {
|
|
191
|
+
AudioPlayChangedState[AudioPlayChangedState["START"] = 1] = "START";
|
|
192
|
+
AudioPlayChangedState[AudioPlayChangedState["BUFFERING"] = 2] = "BUFFERING";
|
|
193
|
+
AudioPlayChangedState[AudioPlayChangedState["BUFFERED"] = 3] = "BUFFERED";
|
|
194
|
+
AudioPlayChangedState[AudioPlayChangedState["COMPLETED"] = 4] = "COMPLETED";
|
|
195
|
+
AudioPlayChangedState[AudioPlayChangedState["ERROR"] = 5] = "ERROR";
|
|
196
|
+
return AudioPlayChangedState;
|
|
197
|
+
}({});
|
|
190
198
|
export let NetworkType = /*#__PURE__*/function (NetworkType) {
|
|
191
199
|
NetworkType["NONE"] = "none";
|
|
192
200
|
NetworkType["CELL_2G"] = "2g";
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AIStreamAudioFile, ConnectClientType } from '../AIStreamTypes';
|
|
2
|
+
export interface AsrAgentOptions {
|
|
3
|
+
agentId: string;
|
|
4
|
+
/** 获取 agent token 的参数 */
|
|
5
|
+
tokenOptions?: {
|
|
6
|
+
api: string;
|
|
7
|
+
version: string;
|
|
8
|
+
extParams?: Record<string, any>;
|
|
9
|
+
};
|
|
10
|
+
/** 是否在构造时就初始化连接和录音参数 */
|
|
11
|
+
earlyStart?: boolean;
|
|
12
|
+
homeId?: number;
|
|
13
|
+
clientType?: ConnectClientType;
|
|
14
|
+
deviceId?: string;
|
|
15
|
+
onMessage?: (message: {
|
|
16
|
+
type: 'text';
|
|
17
|
+
text: string;
|
|
18
|
+
} | {
|
|
19
|
+
type: 'file';
|
|
20
|
+
file: AIStreamAudioFile;
|
|
21
|
+
}) => void;
|
|
22
|
+
onFinish?: () => void;
|
|
23
|
+
onError?: (error: any) => void;
|
|
24
|
+
/** 主动中断或者超过录制时长,会调用onAbort */
|
|
25
|
+
onAbort?: () => void;
|
|
26
|
+
recordingOptions?: {
|
|
27
|
+
/** 是否需要保存音频 */
|
|
28
|
+
saveFile?: boolean;
|
|
29
|
+
/** 保存的音频采样率,单位:hz */
|
|
30
|
+
sampleRate?: number;
|
|
31
|
+
/** 最长录制时长,单位:毫秒 */
|
|
32
|
+
maxDuration?: number;
|
|
33
|
+
};
|
|
34
|
+
enableLog?: boolean;
|
|
35
|
+
}
|
|
36
|
+
export declare class AsrAgent {
|
|
37
|
+
/** 数据链接,一个agent保持一个链接就可以 */
|
|
38
|
+
private streamConn;
|
|
39
|
+
/** 当前请求的session */
|
|
40
|
+
private activeSession;
|
|
41
|
+
private activeEvent;
|
|
42
|
+
/** 音频流监听 */
|
|
43
|
+
private audioStream;
|
|
44
|
+
options: AsrAgentOptions;
|
|
45
|
+
/** 录音时长定时器 */
|
|
46
|
+
private recordDurationTimer;
|
|
47
|
+
constructor(options: AsrAgentOptions);
|
|
48
|
+
/** 获取录音权限 */
|
|
49
|
+
getRecordScope(): Promise<boolean>;
|
|
50
|
+
/** 获取数据链接,一般只有一个链接就可以 */
|
|
51
|
+
private getConnection;
|
|
52
|
+
private createSession;
|
|
53
|
+
/** 开始录音时长监听 */
|
|
54
|
+
private startRecordTimer;
|
|
55
|
+
start(): Promise<void>;
|
|
56
|
+
stop(isAbort?: boolean): Promise<void>;
|
|
57
|
+
abort(): Promise<void>;
|
|
58
|
+
dispose(): void;
|
|
59
|
+
}
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
|
|
2
|
+
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
3
|
+
import "core-js/modules/es.json.stringify.js";
|
|
4
|
+
import { authorize, getCurrentHomeInfo, initAudioRecorder } from '../utils';
|
|
5
|
+
import { AIStreamAttributePayloadType, AIStreamAttributeType, ConnectClientType, ConnectState, ReceivedTextPacketType, SessionState } from '../AIStreamTypes';
|
|
6
|
+
import { DEFAULT_TOKEN_API, DEFAULT_TOKEN_API_VERSION, globalAIStreamClient } from '../global';
|
|
7
|
+
import { Logger, safeParseJSON } from '@ray-js/t-agent';
|
|
8
|
+
import logger from '../utils/logger';
|
|
9
|
+
export class AsrAgent {
|
|
10
|
+
constructor(options) {
|
|
11
|
+
/** 数据链接,一个agent保持一个链接就可以 */
|
|
12
|
+
/** 当前请求的session */
|
|
13
|
+
/** 音频流监听 */
|
|
14
|
+
/** 录音时长定时器 */
|
|
15
|
+
_defineProperty(this, "recordDurationTimer", null);
|
|
16
|
+
this.options = options;
|
|
17
|
+
if (options.earlyStart) {
|
|
18
|
+
const {
|
|
19
|
+
recordingOptions
|
|
20
|
+
} = options;
|
|
21
|
+
const sampleRate = recordingOptions === null || recordingOptions === void 0 ? void 0 : recordingOptions.sampleRate;
|
|
22
|
+
// 如果需要提前启动,直接初始化和创建连接
|
|
23
|
+
this.createSession().then(() => initAudioRecorder(sampleRate ? {
|
|
24
|
+
sampleRate
|
|
25
|
+
} : {})).catch(error => {
|
|
26
|
+
logger.error('EarlyStart Failed to create ASR session:', error);
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
if (this.options.enableLog) {
|
|
30
|
+
Logger.setLogLevel('debug');
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** 获取录音权限 */
|
|
35
|
+
getRecordScope() {
|
|
36
|
+
return authorize({
|
|
37
|
+
scope: 'scope.record'
|
|
38
|
+
}).then(() => true, () => false);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/** 获取数据链接,一般只有一个链接就可以 */
|
|
42
|
+
getConnection(clientType, deviceId) {
|
|
43
|
+
if (this.streamConn) {
|
|
44
|
+
return this.streamConn;
|
|
45
|
+
}
|
|
46
|
+
// 创建 activeSession
|
|
47
|
+
this.streamConn = globalAIStreamClient.getConnection({
|
|
48
|
+
clientType: clientType || ConnectClientType.APP,
|
|
49
|
+
deviceId: deviceId
|
|
50
|
+
});
|
|
51
|
+
return this.streamConn;
|
|
52
|
+
}
|
|
53
|
+
async createSession() {
|
|
54
|
+
var _this$activeSession;
|
|
55
|
+
// 如果有激活的 Session,直接返回
|
|
56
|
+
if ((_this$activeSession = this.activeSession) !== null && _this$activeSession !== void 0 && _this$activeSession.sessionId) {
|
|
57
|
+
return this.activeSession;
|
|
58
|
+
}
|
|
59
|
+
const {
|
|
60
|
+
clientType,
|
|
61
|
+
deviceId,
|
|
62
|
+
tokenOptions,
|
|
63
|
+
agentId
|
|
64
|
+
} = this.options;
|
|
65
|
+
const streamConn = this.getConnection(clientType, deviceId);
|
|
66
|
+
let homeId = this.options.homeId;
|
|
67
|
+
if (!homeId) {
|
|
68
|
+
const info = await getCurrentHomeInfo();
|
|
69
|
+
homeId = +info.homeId;
|
|
70
|
+
}
|
|
71
|
+
this.activeSession = streamConn.createSession({
|
|
72
|
+
ownerId: clientType === ConnectClientType.DEVICE ? deviceId : "".concat(homeId),
|
|
73
|
+
api: (tokenOptions === null || tokenOptions === void 0 ? void 0 : tokenOptions.api) || DEFAULT_TOKEN_API,
|
|
74
|
+
apiVersion: (tokenOptions === null || tokenOptions === void 0 ? void 0 : tokenOptions.version) || DEFAULT_TOKEN_API_VERSION,
|
|
75
|
+
solutionCode: agentId,
|
|
76
|
+
extParams: _objectSpread({
|
|
77
|
+
onlyAsr: true
|
|
78
|
+
}, tokenOptions === null || tokenOptions === void 0 ? void 0 : tokenOptions.extParams)
|
|
79
|
+
});
|
|
80
|
+
return this.activeSession;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** 开始录音时长监听 */
|
|
84
|
+
startRecordTimer() {
|
|
85
|
+
const {
|
|
86
|
+
maxDuration
|
|
87
|
+
} = this.options.recordingOptions || {};
|
|
88
|
+
if (maxDuration) {
|
|
89
|
+
if (this.recordDurationTimer) {
|
|
90
|
+
clearTimeout(this.recordDurationTimer);
|
|
91
|
+
}
|
|
92
|
+
this.recordDurationTimer = setTimeout(() => {
|
|
93
|
+
this.stop(true);
|
|
94
|
+
}, maxDuration);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
async start() {
|
|
98
|
+
const hasScope = await this.getRecordScope();
|
|
99
|
+
if (!hasScope) {
|
|
100
|
+
throw new Error('authorize failed');
|
|
101
|
+
}
|
|
102
|
+
const {
|
|
103
|
+
onMessage,
|
|
104
|
+
onFinish,
|
|
105
|
+
onError
|
|
106
|
+
} = this.options || {};
|
|
107
|
+
const activeSession = await this.createSession();
|
|
108
|
+
const activeEvent = await activeSession.startEvent({
|
|
109
|
+
userData: [{
|
|
110
|
+
type: AIStreamAttributeType.AI_CHAT,
|
|
111
|
+
payloadType: AIStreamAttributePayloadType.STRING,
|
|
112
|
+
value: JSON.stringify({
|
|
113
|
+
'processing.interrupt': 'false',
|
|
114
|
+
'asr.enableVad': 'false'
|
|
115
|
+
})
|
|
116
|
+
}]
|
|
117
|
+
});
|
|
118
|
+
this.activeEvent = activeEvent;
|
|
119
|
+
const {
|
|
120
|
+
recordingOptions
|
|
121
|
+
} = this.options || {};
|
|
122
|
+
const {
|
|
123
|
+
sampleRate,
|
|
124
|
+
saveFile
|
|
125
|
+
} = recordingOptions || {};
|
|
126
|
+
const audioStream = activeEvent.stream({
|
|
127
|
+
type: 'audio',
|
|
128
|
+
sampleRate,
|
|
129
|
+
saveFile
|
|
130
|
+
});
|
|
131
|
+
this.audioStream = audioStream;
|
|
132
|
+
activeEvent.on('data', entry => {
|
|
133
|
+
if (entry.type === 'text') {
|
|
134
|
+
const packet = safeParseJSON(entry.body.text);
|
|
135
|
+
if (!packet || !packet.data) {
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
if (packet.bizType !== ReceivedTextPacketType.ASR) {
|
|
139
|
+
return;
|
|
140
|
+
}
|
|
141
|
+
typeof onMessage === 'function' && onMessage({
|
|
142
|
+
type: 'text',
|
|
143
|
+
text: packet.data.text
|
|
144
|
+
});
|
|
145
|
+
} else if (entry.type === 'connectionState') {
|
|
146
|
+
if (entry.body.connectState === ConnectState.DISCONNECTED || entry.body.connectState === ConnectState.CLOSED) {
|
|
147
|
+
this.stop();
|
|
148
|
+
typeof onError === 'function' && onError(new Error('Connection closed'));
|
|
149
|
+
}
|
|
150
|
+
} else if (entry.type === 'sessionState') {
|
|
151
|
+
if (entry.body.sessionState === SessionState.CLOSED || entry.body.sessionState === SessionState.CREATE_FAILED) {
|
|
152
|
+
this.stop();
|
|
153
|
+
typeof onError === 'function' && onError(new Error('Session closed'));
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
let finished = false;
|
|
158
|
+
activeEvent.on('finish', () => {
|
|
159
|
+
if (finished) {
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
this.stop();
|
|
163
|
+
typeof onFinish === 'function' && onFinish();
|
|
164
|
+
finished = true;
|
|
165
|
+
});
|
|
166
|
+
activeEvent.on('close', () => {
|
|
167
|
+
if (finished) {
|
|
168
|
+
return;
|
|
169
|
+
}
|
|
170
|
+
this.stop();
|
|
171
|
+
typeof onFinish === 'function' && onFinish();
|
|
172
|
+
finished = true;
|
|
173
|
+
});
|
|
174
|
+
activeEvent.on('error', error => {
|
|
175
|
+
typeof onError === 'function' && onError(error);
|
|
176
|
+
});
|
|
177
|
+
await audioStream.start();
|
|
178
|
+
this.startRecordTimer();
|
|
179
|
+
}
|
|
180
|
+
async stop(isAbort) {
|
|
181
|
+
if (this.recordDurationTimer) {
|
|
182
|
+
clearTimeout(this.recordDurationTimer);
|
|
183
|
+
this.recordDurationTimer = null;
|
|
184
|
+
}
|
|
185
|
+
if (this.audioStream) {
|
|
186
|
+
const file = await this.audioStream.stop();
|
|
187
|
+
console.log('Audio file result:', file);
|
|
188
|
+
if (file !== null && file !== void 0 && file.path) {
|
|
189
|
+
this.options.onMessage({
|
|
190
|
+
type: 'file',
|
|
191
|
+
file
|
|
192
|
+
});
|
|
193
|
+
}
|
|
194
|
+
this.audioStream = null;
|
|
195
|
+
}
|
|
196
|
+
if (this.activeEvent) {
|
|
197
|
+
if (isAbort) {
|
|
198
|
+
await this.activeEvent.abort();
|
|
199
|
+
} else {
|
|
200
|
+
await this.activeEvent.end();
|
|
201
|
+
}
|
|
202
|
+
this.activeEvent = null;
|
|
203
|
+
}
|
|
204
|
+
if (isAbort) {
|
|
205
|
+
const {
|
|
206
|
+
onAbort
|
|
207
|
+
} = this.options || {};
|
|
208
|
+
typeof onAbort === 'function' && onAbort();
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async abort() {
|
|
212
|
+
await this.stop(true);
|
|
213
|
+
}
|
|
214
|
+
dispose() {
|
|
215
|
+
if (this.recordDurationTimer) {
|
|
216
|
+
clearTimeout(this.recordDurationTimer);
|
|
217
|
+
this.recordDurationTimer = null;
|
|
218
|
+
}
|
|
219
|
+
if (this.audioStream && this.audioStream.started) {
|
|
220
|
+
this.audioStream.stop();
|
|
221
|
+
}
|
|
222
|
+
this.audioStream = null;
|
|
223
|
+
if (this.activeEvent) {
|
|
224
|
+
this.activeEvent.abort();
|
|
225
|
+
this.activeEvent = null;
|
|
226
|
+
}
|
|
227
|
+
if (this.activeSession) {
|
|
228
|
+
this.activeSession.close();
|
|
229
|
+
this.activeSession = null;
|
|
230
|
+
}
|
|
231
|
+
if (this.streamConn) {
|
|
232
|
+
this.streamConn = null;
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { AsrAgent, AsrAgentOptions } from './AsrAgent';
|
|
2
|
+
/**
|
|
3
|
+
* 创建一个AsrAgent实例,用于语音转文本
|
|
4
|
+
* @example
|
|
5
|
+
* const asrAgent = createAsrAgent({
|
|
6
|
+
* agentId: 'your_agent_id',
|
|
7
|
+
* clientType: ConnectClientType.APP,
|
|
8
|
+
* deviceId: 'deviceId',
|
|
9
|
+
* maxDuration: 60,
|
|
10
|
+
* onMessage: (message) => {
|
|
11
|
+
* console.log('onMessage', message);
|
|
12
|
+
* },
|
|
13
|
+
* onFinish: () => {
|
|
14
|
+
* console.log('onFinish');
|
|
15
|
+
* },
|
|
16
|
+
* onError: (error) => {
|
|
17
|
+
* console.log('onError', error);
|
|
18
|
+
* },
|
|
19
|
+
* onAbort: () => {
|
|
20
|
+
* console.log('onAbort');
|
|
21
|
+
* },
|
|
22
|
+
* });
|
|
23
|
+
* // 开始录音
|
|
24
|
+
* asrAgent.start()
|
|
25
|
+
* // 停止录音
|
|
26
|
+
* asrAgent.stop()
|
|
27
|
+
* // 中断录音
|
|
28
|
+
* asrAgent.abort()
|
|
29
|
+
* @returns
|
|
30
|
+
*/
|
|
31
|
+
export declare function createAsrAgent(options: AsrAgentOptions): AsrAgent;
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { AsrAgent } from './AsrAgent';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* 创建一个AsrAgent实例,用于语音转文本
|
|
5
|
+
* @example
|
|
6
|
+
* const asrAgent = createAsrAgent({
|
|
7
|
+
* agentId: 'your_agent_id',
|
|
8
|
+
* clientType: ConnectClientType.APP,
|
|
9
|
+
* deviceId: 'deviceId',
|
|
10
|
+
* maxDuration: 60,
|
|
11
|
+
* onMessage: (message) => {
|
|
12
|
+
* console.log('onMessage', message);
|
|
13
|
+
* },
|
|
14
|
+
* onFinish: () => {
|
|
15
|
+
* console.log('onFinish');
|
|
16
|
+
* },
|
|
17
|
+
* onError: (error) => {
|
|
18
|
+
* console.log('onError', error);
|
|
19
|
+
* },
|
|
20
|
+
* onAbort: () => {
|
|
21
|
+
* console.log('onAbort');
|
|
22
|
+
* },
|
|
23
|
+
* });
|
|
24
|
+
* // 开始录音
|
|
25
|
+
* asrAgent.start()
|
|
26
|
+
* // 停止录音
|
|
27
|
+
* asrAgent.stop()
|
|
28
|
+
* // 中断录音
|
|
29
|
+
* asrAgent.abort()
|
|
30
|
+
* @returns
|
|
31
|
+
*/
|
|
32
|
+
export function createAsrAgent(options) {
|
|
33
|
+
const asrAgent = new AsrAgent(options);
|
|
34
|
+
return asrAgent;
|
|
35
|
+
}
|
|
@@ -1,6 +1,4 @@
|
|
|
1
1
|
import "core-js/modules/web.dom-collections.iterator.js";
|
|
2
|
-
import { getMiniAppConfig } from '../utils';
|
|
3
|
-
import logger from '../utils/logger';
|
|
4
2
|
import { BuildInSkillCode, ReceivedSmartHomeSkillAction } from '../AIStreamTypes';
|
|
5
3
|
export function withBuildIn() {
|
|
6
4
|
return _agent => {
|
|
@@ -17,27 +15,28 @@ export function withBuildIn() {
|
|
|
17
15
|
const {
|
|
18
16
|
onSkillsEnd
|
|
19
17
|
} = agent.plugins.aiStream;
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
18
|
+
|
|
19
|
+
// onAgentStart(async () => {
|
|
20
|
+
// const agentId = session.get('AIStream.agentId');
|
|
21
|
+
// if (agentId) {
|
|
22
|
+
// const _conf = session.get('AIStream.projectConfig');
|
|
23
|
+
// if (!_conf) {
|
|
24
|
+
// try {
|
|
25
|
+
// const config: Record<string, ProjectConfig> = (await getMiniAppConfig({})).config || {};
|
|
26
|
+
// const projectConfig = config[agentId];
|
|
27
|
+
// if (projectConfig) {
|
|
28
|
+
// logger.debug('getMiniAppConfig projectConfig', {
|
|
29
|
+
// agentId,
|
|
30
|
+
// projectConfig,
|
|
31
|
+
// });
|
|
32
|
+
// await session.set('AIAssistant.projectConfig', projectConfig);
|
|
33
|
+
// }
|
|
34
|
+
// } catch (error) {
|
|
35
|
+
// logger.warn('getMiniAppConfig error', error);
|
|
36
|
+
// }
|
|
37
|
+
// }
|
|
38
|
+
// }
|
|
39
|
+
// });
|
|
41
40
|
|
|
42
41
|
// 关联文档
|
|
43
42
|
|
package/dist/index.d.ts
CHANGED
package/dist/index.js
CHANGED
package/dist/utils/AIStream.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
|
|
1
|
+
import { AIStreamAudioFile, Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
|
|
2
2
|
import { AIStreamDataEntry, AIStreamObserverPool } from './observer';
|
|
3
3
|
import { AIStreamError } from './errors';
|
|
4
4
|
interface AIStreamConnectionOptions {
|
|
@@ -87,6 +87,8 @@ type AIStreamEventSource = {
|
|
|
87
87
|
type: 'audio';
|
|
88
88
|
dataChannel?: string;
|
|
89
89
|
userData?: Attribute[];
|
|
90
|
+
saveFile?: boolean;
|
|
91
|
+
sampleRate?: number;
|
|
90
92
|
} | {
|
|
91
93
|
type: 'video';
|
|
92
94
|
dataChannel?: string;
|
|
@@ -98,7 +100,7 @@ export interface AIStreamEventStream {
|
|
|
98
100
|
dataChannel: string;
|
|
99
101
|
started: boolean;
|
|
100
102
|
start: () => Promise<void>;
|
|
101
|
-
stop: () => Promise<
|
|
103
|
+
stop: () => Promise<AIStreamAudioFile | null>;
|
|
102
104
|
}
|
|
103
105
|
export declare class AIStreamEvent {
|
|
104
106
|
readonly eventId: string;
|
package/dist/utils/AIStream.js
CHANGED
|
@@ -459,7 +459,11 @@ export class AIStreamEvent {
|
|
|
459
459
|
startPromise = startRecordAndSendAudioData({
|
|
460
460
|
sessionId: this.sessionId,
|
|
461
461
|
dataChannel,
|
|
462
|
-
userData: source.userData
|
|
462
|
+
userData: source.userData,
|
|
463
|
+
recordInitParams: source.sampleRate ? {
|
|
464
|
+
sampleRate: source.sampleRate
|
|
465
|
+
} : undefined,
|
|
466
|
+
saveFile: source.saveFile
|
|
463
467
|
});
|
|
464
468
|
await startPromise;
|
|
465
469
|
} else if (source.type === 'video') {
|
|
@@ -473,15 +477,16 @@ export class AIStreamEvent {
|
|
|
473
477
|
},
|
|
474
478
|
stop: async () => {
|
|
475
479
|
if (!stream.started || this.closed) {
|
|
476
|
-
return;
|
|
480
|
+
return null;
|
|
477
481
|
}
|
|
478
482
|
// 一定要等录音开始,才能结束
|
|
479
483
|
if (startPromise) {
|
|
480
484
|
await tryCatchTTT(() => startPromise);
|
|
481
485
|
startPromise = null;
|
|
482
486
|
}
|
|
487
|
+
let file = null;
|
|
483
488
|
if (source.type === 'audio') {
|
|
484
|
-
stopRecordAndSendAudioData({
|
|
489
|
+
file = await stopRecordAndSendAudioData({
|
|
485
490
|
sessionId: this.sessionId,
|
|
486
491
|
dataChannel,
|
|
487
492
|
userData: source.userData
|
|
@@ -502,6 +507,7 @@ export class AIStreamEvent {
|
|
|
502
507
|
});
|
|
503
508
|
delete this.streams[dataChannel];
|
|
504
509
|
stream.started = false;
|
|
510
|
+
return file;
|
|
505
511
|
}
|
|
506
512
|
};
|
|
507
513
|
this.streams[dataChannel] = stream;
|
|
@@ -16,6 +16,7 @@ function splitString(input) {
|
|
|
16
16
|
return input.match(/[a-zA-Z0-9]+\s*|[\u4e00-\u9fff]+\s*|[^\w\s\u4e00-\u9fff]+\s*|[\s]+/g) || [];
|
|
17
17
|
}
|
|
18
18
|
mock.data.set('sessionMap', new Map());
|
|
19
|
+
mock.data.set('tokenMap', new Map());
|
|
19
20
|
const getSession = (sessionId, eventId) => {
|
|
20
21
|
const connection = getCurrentConnection();
|
|
21
22
|
if (!connection) {
|
|
@@ -94,8 +95,15 @@ mock.hooks.hook('disconnect', context => {
|
|
|
94
95
|
mock.data.set('sessionMap', new Map());
|
|
95
96
|
});
|
|
96
97
|
mock.hooks.hook('queryAgentToken', context => {
|
|
98
|
+
var _context$options$extP, _context$options$extP2;
|
|
99
|
+
const agentToken = generateId();
|
|
100
|
+
const map = mock.data.get('tokenMap');
|
|
101
|
+
map.set(agentToken, {
|
|
102
|
+
onlyAsr: ((_context$options$extP = context.options.extParams) === null || _context$options$extP === void 0 ? void 0 : _context$options$extP.onlyAsr) || false,
|
|
103
|
+
needTts: ((_context$options$extP2 = context.options.extParams) === null || _context$options$extP2 === void 0 ? void 0 : _context$options$extP2.needTts) || false
|
|
104
|
+
});
|
|
97
105
|
context.result = {
|
|
98
|
-
agentToken
|
|
106
|
+
agentToken,
|
|
99
107
|
bizConfig: {
|
|
100
108
|
bizCode: BizCode.CHAT,
|
|
101
109
|
sendData: ['audio', 'video', 'text', 'image'],
|
|
@@ -114,12 +122,15 @@ mock.hooks.hook('createSession', context => {
|
|
|
114
122
|
throw new TTTError('not connect', AIStreamAppErrorCode.CONNECTION_INVALID);
|
|
115
123
|
}
|
|
116
124
|
const map = mock.data.get('sessionMap');
|
|
125
|
+
const tokenMap = mock.data.get('tokenMap');
|
|
126
|
+
const tokenConfig = tokenMap.get(context.options.agentToken);
|
|
117
127
|
const session = {
|
|
118
128
|
closed: false,
|
|
119
129
|
sessionId: generateId(),
|
|
120
130
|
sendDataChannels: ['audio', 'video', 'text', 'image'],
|
|
121
131
|
revDataChannels: ['text', 'audio'],
|
|
122
|
-
currentEvent: null
|
|
132
|
+
currentEvent: null,
|
|
133
|
+
tokenConfig
|
|
123
134
|
};
|
|
124
135
|
map.set(session.sessionId, session);
|
|
125
136
|
context.result = {
|
|
@@ -238,6 +249,11 @@ mock.hooks.hook('sendEventEnd', async context => {
|
|
|
238
249
|
(async () => {
|
|
239
250
|
var _ctx$responseSkills;
|
|
240
251
|
await event.asr.promise;
|
|
252
|
+
if (session.tokenConfig.onlyAsr) {
|
|
253
|
+
event.replyEvent(EventType.EVENT_END);
|
|
254
|
+
session.currentEvent = null;
|
|
255
|
+
return;
|
|
256
|
+
}
|
|
241
257
|
const ctx = {
|
|
242
258
|
data: event.data,
|
|
243
259
|
responseText: ''
|
|
@@ -454,7 +470,7 @@ mock.hooks.hook('stopRecordAndSendAudioData', async context => {
|
|
|
454
470
|
throw new TTTError('stopRecordAndSendAudioData event not exists', AIStreamAppErrorCode.SESSION_ID_INVALID);
|
|
455
471
|
}
|
|
456
472
|
session.currentEvent.asr.finishController.abort(new Error('stopRecordAndSendAudioData'));
|
|
457
|
-
context.result =
|
|
473
|
+
context.result = null;
|
|
458
474
|
await mock.sleep(100);
|
|
459
475
|
});
|
|
460
476
|
mock.hooks.hook('startRecordAndSendVideoData', context => {
|
package/dist/utils/index.d.ts
CHANGED
package/dist/utils/index.js
CHANGED
package/dist/utils/ttt.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiRequestByAtopParams, ApiRequestByHighwayParams, AudioBody, AuthorizeParams, AuthorizePolicyStatusParams, CanIUseRouterParams, CloseSessionParams, ConnectParams, ConnectStateBody, CreateSessionParams, DeleteRecordListParams, DisconnectParams, EventBody, EventChannelMessageParams, GetAppInfoParams, GetCurrentHomeInfoParams, GetMiniAppConfigParams, GetAccountInfoParams, ImageBody, InsertRecordParams, NavigateToMiniProgramParams, OpenInnerH5Params, OpenMiniWidgetParams, QueryAgentTokenParams, QueryRecordListParams, RecordAmplitudesBody, RegisterChannelParams, RouterParams, SendEventChatBreakParams, SendEventEndParams, SendEventPayloadEndParams, SendEventStartParams, SendImageDataParams, SendTextDataParams, SessionStateBody, StartRecordAndSendAudioDataParams, StopRecordAndSendAudioDataParams, TextBody, UpdateRecordParams, IsConnectedParams, GetNetworkTypeParams, StartPlayAudioParams } from '../AIStreamTypes';
|
|
1
|
+
import { ApiRequestByAtopParams, ApiRequestByHighwayParams, AudioBody, AuthorizeParams, AuthorizePolicyStatusParams, CanIUseRouterParams, CloseSessionParams, ConnectParams, ConnectStateBody, CreateSessionParams, DeleteRecordListParams, DisconnectParams, EventBody, EventChannelMessageParams, GetAppInfoParams, GetCurrentHomeInfoParams, GetMiniAppConfigParams, GetAccountInfoParams, ImageBody, InsertRecordParams, NavigateToMiniProgramParams, OpenInnerH5Params, OpenMiniWidgetParams, QueryAgentTokenParams, QueryRecordListParams, RecordAmplitudesBody, RegisterChannelParams, RouterParams, SendEventChatBreakParams, SendEventEndParams, SendEventPayloadEndParams, SendEventStartParams, SendImageDataParams, SendTextDataParams, SessionStateBody, StartRecordAndSendAudioDataParams, StopRecordAndSendAudioDataParams, TextBody, UpdateRecordParams, IsConnectedParams, GetNetworkTypeParams, StartPlayAudioParams, InitAudioRecorderParams, StopPlayAudioParams, AudioPlayChangedBody } from '../AIStreamTypes';
|
|
2
2
|
export declare const getMiniAppConfig: (options?: Omit<GetMiniAppConfigParams, "success" | "fail"> | undefined) => Promise<{
|
|
3
3
|
config: any;
|
|
4
4
|
}>;
|
|
@@ -79,18 +79,18 @@ export declare const sendEventPayloadEnd: (options?: Omit<SendEventPayloadEndPar
|
|
|
79
79
|
export declare const sendEventEnd: (options?: Omit<SendEventEndParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
80
80
|
export declare const sendEventChatBreak: (options?: Omit<SendEventChatBreakParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
81
81
|
export declare const startRecordAndSendAudioData: (options?: Omit<StartRecordAndSendAudioDataParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
82
|
-
export declare const stopRecordAndSendAudioData: (options?: Omit<StopRecordAndSendAudioDataParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
82
|
+
export declare const stopRecordAndSendAudioData: (options?: Omit<StopRecordAndSendAudioDataParams, "success" | "fail"> | undefined) => Promise<import("../AIStreamTypes").AIStreamAudioFile | null>;
|
|
83
83
|
export declare const sendImageData: (options?: Omit<SendImageDataParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
84
84
|
export declare const sendTextData: (options?: Omit<SendTextDataParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
85
85
|
export declare const registerRecordAmplitudes: (options?: Omit<{
|
|
86
86
|
count: number;
|
|
87
87
|
}, "success" | "fail"> | undefined) => Promise<never>;
|
|
88
88
|
export declare const unregisterVoiceAmplitudes: (options?: Omit<any, "success" | "fail"> | undefined) => Promise<unknown>;
|
|
89
|
+
export declare const initAudioRecorder: (options?: Omit<InitAudioRecorderParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
89
90
|
export declare const startPlayAudio: (options?: Omit<StartPlayAudioParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
91
|
+
export declare const stopPlayAudio: (options?: Omit<StopPlayAudioParams, "success" | "fail"> | undefined) => Promise<null>;
|
|
90
92
|
export declare const listenEventReceived: (listener: (params: EventBody) => void) => () => void;
|
|
91
|
-
export declare const
|
|
92
|
-
path: string;
|
|
93
|
-
}) => void) => () => void;
|
|
93
|
+
export declare const listenAudioPlayChanged: (listener: (params: AudioPlayChangedBody) => void) => () => void;
|
|
94
94
|
export declare const listenAudioReceived: (listener: (params: AudioBody) => void) => () => void;
|
|
95
95
|
export declare const listenTextReceived: (listener: (params: TextBody) => void) => () => void;
|
|
96
96
|
export declare const listenImageReceived: (listener: (params: ImageBody) => void) => () => void;
|
package/dist/utils/ttt.js
CHANGED
|
@@ -56,12 +56,14 @@ export const sendImageData = promisify(ty.aistream.sendImageData, true);
|
|
|
56
56
|
export const sendTextData = promisify(ty.aistream.sendTextData, true);
|
|
57
57
|
export const registerRecordAmplitudes = promisify(ty.aistream.registerRecordAmplitudes, true);
|
|
58
58
|
export const unregisterVoiceAmplitudes = promisify(ty.aistream.unregisterVoiceAmplitudes, true);
|
|
59
|
+
export const initAudioRecorder = promisify(ty.aistream.initAudioRecorder, true);
|
|
59
60
|
export const startPlayAudio = promisify(ty.aistream.startPlayAudio, true);
|
|
61
|
+
export const stopPlayAudio = promisify(ty.aistream.stopPlayAudio, true);
|
|
60
62
|
|
|
61
63
|
// export const sendFileData = promisify<SendFileDataParams>(ty.aistream.sendFileData);
|
|
62
64
|
|
|
63
65
|
export const listenEventReceived = listening(ty.aistream.onEventReceived, ty.aistream.offEventReceived, true);
|
|
64
|
-
export const
|
|
66
|
+
export const listenAudioPlayChanged = listening(ty.aistream.onAudioPlayChanged, ty.aistream.onAudioPlayChanged, true);
|
|
65
67
|
export const listenAudioReceived = listening(ty.aistream.onAudioReceived, ty.aistream.offAudioReceived, true);
|
|
66
68
|
|
|
67
69
|
// export const listenVideoReceived = listening<VideoBody>(
|
package/dist/withAIStream.js
CHANGED
|
@@ -190,6 +190,28 @@ export function withAIStream() {
|
|
|
190
190
|
await removeMessage(message);
|
|
191
191
|
}
|
|
192
192
|
});
|
|
193
|
+
const clearAllMessages = async () => {
|
|
194
|
+
// 删除内存中的消息
|
|
195
|
+
const messages = agent.session.messages.values();
|
|
196
|
+
await Promise.all(Array.from(messages).map(message => message.remove()));
|
|
197
|
+
// 清空缓存的数据
|
|
198
|
+
const historyStore = getHistoryStore();
|
|
199
|
+
if (historyStore) {
|
|
200
|
+
await historyStore.removeAll();
|
|
201
|
+
}
|
|
202
|
+
};
|
|
203
|
+
ui.hook('onClearHistory', async context => {
|
|
204
|
+
try {
|
|
205
|
+
await clearAllMessages();
|
|
206
|
+
context.result = {
|
|
207
|
+
success: true
|
|
208
|
+
};
|
|
209
|
+
} catch (e) {
|
|
210
|
+
context.result = {
|
|
211
|
+
success: false
|
|
212
|
+
};
|
|
213
|
+
}
|
|
214
|
+
});
|
|
193
215
|
const send = (blocks, signal, extraOptions) => {
|
|
194
216
|
const streamSession = session.get('AIStream.streamSession');
|
|
195
217
|
const result = sendBlocksToAIStream({
|
|
@@ -517,16 +539,7 @@ export function withAIStream() {
|
|
|
517
539
|
chat,
|
|
518
540
|
options,
|
|
519
541
|
removeMessage,
|
|
520
|
-
clearAllMessages
|
|
521
|
-
// 删除内存中的消息
|
|
522
|
-
const messages = agent.session.messages.values();
|
|
523
|
-
await Promise.all(Array.from(messages).map(message => message.remove()));
|
|
524
|
-
// 清空缓存的数据
|
|
525
|
-
const historyStore = getHistoryStore();
|
|
526
|
-
if (historyStore) {
|
|
527
|
-
await historyStore.removeAll();
|
|
528
|
-
}
|
|
529
|
-
},
|
|
542
|
+
clearAllMessages,
|
|
530
543
|
feedback,
|
|
531
544
|
onSkillCompose: fn => {
|
|
532
545
|
return hooks.hook('onSkillCompose', fn);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ray-js/t-agent-plugin-aistream",
|
|
3
|
-
"version": "0.2.3-beta-
|
|
3
|
+
"version": "0.2.3-beta-4",
|
|
4
4
|
"author": "Tuya.inc",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"private": false,
|
|
@@ -35,5 +35,5 @@
|
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@types/url-parse": "^1.4.11"
|
|
37
37
|
},
|
|
38
|
-
"gitHead": "
|
|
38
|
+
"gitHead": "952d287025737224227ead3ecf6dd4c432fec6a2"
|
|
39
39
|
}
|
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
import { ConnectClientType } from '../AIStreamTypes';
|
|
2
|
-
export interface AsrAgentOptions {
|
|
3
|
-
agentId: string;
|
|
4
|
-
tokenApi?: string;
|
|
5
|
-
tokenApiVersion?: string;
|
|
6
|
-
clientType?: ConnectClientType;
|
|
7
|
-
deviceId?: string;
|
|
8
|
-
/** 最长录制时长,单位:秒 */
|
|
9
|
-
maxDuration?: number;
|
|
10
|
-
onMessage?: (message: {
|
|
11
|
-
text: string;
|
|
12
|
-
}) => void;
|
|
13
|
-
onFinish?: () => void;
|
|
14
|
-
onError?: (error: any) => void;
|
|
15
|
-
/** 主动中断或者超过录制时长,会调用onAbort */
|
|
16
|
-
onAbort?: () => void;
|
|
17
|
-
}
|
|
18
|
-
declare class AsrAgent {
|
|
19
|
-
/** 数据链接,一个agent保持一个链接就可以 */
|
|
20
|
-
private streamConn;
|
|
21
|
-
/** 当前请求的session,每次请求都需要是一个新的session */
|
|
22
|
-
private activeSession;
|
|
23
|
-
private activeEvent;
|
|
24
|
-
/** 音频流监听 */
|
|
25
|
-
private audioStream;
|
|
26
|
-
options: AsrAgentOptions;
|
|
27
|
-
/** 录音时长定时器 */
|
|
28
|
-
private recordDurationTimer;
|
|
29
|
-
constructor(options: any);
|
|
30
|
-
/** 获取录音权限 */
|
|
31
|
-
getRecordScope(): Promise<boolean>;
|
|
32
|
-
/** 获取数据链接,一般只有一个链接就可以 */
|
|
33
|
-
private getConnection;
|
|
34
|
-
private createSession;
|
|
35
|
-
/** 开始录音时长监听 */
|
|
36
|
-
private startRecordTimer;
|
|
37
|
-
start(): Promise<void>;
|
|
38
|
-
stop(isAbort?: boolean): Promise<void>;
|
|
39
|
-
abort(): Promise<void>;
|
|
40
|
-
}
|
|
41
|
-
/**
|
|
42
|
-
* 创建一个AsrAgent实例,用于语音转文本
|
|
43
|
-
* @param options AsrAgentOptions
|
|
44
|
-
* @param options.agentId 必填 语音转文本的agentId
|
|
45
|
-
* @param options.tokenApi 语音转文本的tokenApi
|
|
46
|
-
* @param options.tokenApiVersion 语音转文本的tokenApiVersion
|
|
47
|
-
* @param options.clientType 语音转文本的clientType
|
|
48
|
-
* @param options.deviceId 语音转文本的deviceId
|
|
49
|
-
* @example
|
|
50
|
-
* const asrAgent = createAsrAgent({
|
|
51
|
-
* agentId: 'asr-agent',
|
|
52
|
-
* tokenApi: 'xxxx',
|
|
53
|
-
* tokenApiVersion: '1.0',
|
|
54
|
-
* clientType: ConnectClientType.APP,
|
|
55
|
-
* deviceId: 'deviceId',
|
|
56
|
-
* maxDuration: 60,
|
|
57
|
-
* onMessage: (message) => {
|
|
58
|
-
* console.log('onMessage', message);
|
|
59
|
-
* },
|
|
60
|
-
* onFinish: () => {
|
|
61
|
-
* console.log('onFinish');
|
|
62
|
-
* },
|
|
63
|
-
* onError: (error) => {
|
|
64
|
-
* console.log('onError', error);
|
|
65
|
-
* },
|
|
66
|
-
* onAbort: () => {
|
|
67
|
-
* console.log('onAbort');
|
|
68
|
-
* },
|
|
69
|
-
* });
|
|
70
|
-
* // 开始录音
|
|
71
|
-
* asrAgent.start()
|
|
72
|
-
* // 停止录音
|
|
73
|
-
* asrAgent.stop()
|
|
74
|
-
* // 中断录音
|
|
75
|
-
* asrAgent.abort()
|
|
76
|
-
* @returns
|
|
77
|
-
*/
|
|
78
|
-
export declare function createAsrAgent(options: AsrAgentOptions): AsrAgent;
|
|
79
|
-
export {};
|
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
|
|
2
|
-
import "core-js/modules/es.json.stringify.js";
|
|
3
|
-
import { authorize } from './ttt';
|
|
4
|
-
import { DEFAULT_TOKEN_API, DEFAULT_TOKEN_API_VERSION, globalAIStreamClient } from '../global';
|
|
5
|
-
import { ConnectClientType, AIStreamAttributePayloadType, AIStreamAttributeType } from '../AIStreamTypes';
|
|
6
|
-
import logger from './logger';
|
|
7
|
-
class AsrAgent {
|
|
8
|
-
constructor(options) {
|
|
9
|
-
/** 数据链接,一个agent保持一个链接就可以 */
|
|
10
|
-
/** 当前请求的session,每次请求都需要是一个新的session */
|
|
11
|
-
/** 音频流监听 */
|
|
12
|
-
/** 录音时长定时器 */
|
|
13
|
-
_defineProperty(this, "recordDurationTimer", null);
|
|
14
|
-
this.options = options;
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
/** 获取录音权限 */
|
|
18
|
-
getRecordScope() {
|
|
19
|
-
return authorize({
|
|
20
|
-
scope: 'scope.record'
|
|
21
|
-
}).then(() => true, () => false);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
/** 获取数据链接,一般只有一个链接就可以 */
|
|
25
|
-
getConnection(clientType, deviceId) {
|
|
26
|
-
if (this.streamConn) {
|
|
27
|
-
return this.streamConn;
|
|
28
|
-
}
|
|
29
|
-
// 创建 activeSession
|
|
30
|
-
this.streamConn = globalAIStreamClient.getConnection({
|
|
31
|
-
clientType: clientType || ConnectClientType.APP,
|
|
32
|
-
deviceId: deviceId
|
|
33
|
-
});
|
|
34
|
-
return this.streamConn;
|
|
35
|
-
}
|
|
36
|
-
createSession() {
|
|
37
|
-
var _this$activeSession;
|
|
38
|
-
// 每次新的请求,都需要重新创建一个Session
|
|
39
|
-
const {
|
|
40
|
-
clientType,
|
|
41
|
-
deviceId,
|
|
42
|
-
tokenApi,
|
|
43
|
-
tokenApiVersion,
|
|
44
|
-
agentId
|
|
45
|
-
} = this.options;
|
|
46
|
-
const streamConn = this.getConnection(clientType, deviceId);
|
|
47
|
-
// 如果有激活的,需要释放
|
|
48
|
-
if ((_this$activeSession = this.activeSession) !== null && _this$activeSession !== void 0 && _this$activeSession.sessionId) {
|
|
49
|
-
this.activeSession.close();
|
|
50
|
-
}
|
|
51
|
-
const activeSession = streamConn.createSession({
|
|
52
|
-
api: tokenApi || DEFAULT_TOKEN_API,
|
|
53
|
-
apiVersion: tokenApiVersion || DEFAULT_TOKEN_API_VERSION,
|
|
54
|
-
solutionCode: agentId,
|
|
55
|
-
extParams: {
|
|
56
|
-
onlyAsr: true
|
|
57
|
-
}
|
|
58
|
-
});
|
|
59
|
-
this.activeSession = activeSession;
|
|
60
|
-
return this.activeSession;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
/** 开始录音时长监听 */
|
|
64
|
-
startRecordTimer() {
|
|
65
|
-
const {
|
|
66
|
-
maxDuration
|
|
67
|
-
} = this.options;
|
|
68
|
-
if (maxDuration) {
|
|
69
|
-
if (this.recordDurationTimer) {
|
|
70
|
-
clearTimeout(this.recordDurationTimer);
|
|
71
|
-
}
|
|
72
|
-
this.recordDurationTimer = setTimeout(() => {
|
|
73
|
-
this.stop(true);
|
|
74
|
-
}, maxDuration * 1000);
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
async start() {
|
|
78
|
-
const hasScope = await this.getRecordScope();
|
|
79
|
-
if (!hasScope) {
|
|
80
|
-
throw new Error('authorize failed');
|
|
81
|
-
}
|
|
82
|
-
const {
|
|
83
|
-
onMessage,
|
|
84
|
-
onFinish,
|
|
85
|
-
onError
|
|
86
|
-
} = this.options || {};
|
|
87
|
-
const activeSession = this.createSession();
|
|
88
|
-
const activeEvent = await activeSession.startEvent({
|
|
89
|
-
userData: [{
|
|
90
|
-
type: AIStreamAttributeType.AI_CHAT,
|
|
91
|
-
payloadType: AIStreamAttributePayloadType.STRING,
|
|
92
|
-
value: JSON.stringify({
|
|
93
|
-
'processing.interrupt': 'false',
|
|
94
|
-
'asr.enableVad': 'false'
|
|
95
|
-
})
|
|
96
|
-
}]
|
|
97
|
-
});
|
|
98
|
-
this.activeEvent = activeEvent;
|
|
99
|
-
const audioStream = activeEvent.stream({
|
|
100
|
-
type: 'audio'
|
|
101
|
-
});
|
|
102
|
-
this.audioStream = audioStream;
|
|
103
|
-
await audioStream.start();
|
|
104
|
-
this.startRecordTimer();
|
|
105
|
-
activeEvent.on('data', entry => {
|
|
106
|
-
if (entry.type === 'text') {
|
|
107
|
-
console.log('text', entry, JSON.parse(entry.body.text));
|
|
108
|
-
let data = {
|
|
109
|
-
text: ''
|
|
110
|
-
};
|
|
111
|
-
try {
|
|
112
|
-
data = JSON.parse(entry.body.text) || {};
|
|
113
|
-
} catch (error) {
|
|
114
|
-
logger.error('JSON.parse error', error);
|
|
115
|
-
}
|
|
116
|
-
typeof onMessage === 'function' && onMessage(data);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
activeEvent.on('finish', () => {
|
|
120
|
-
this.stop();
|
|
121
|
-
typeof onFinish === 'function' && onFinish();
|
|
122
|
-
});
|
|
123
|
-
activeEvent.on('error', error => {
|
|
124
|
-
typeof onError === 'function' && onError(error);
|
|
125
|
-
});
|
|
126
|
-
}
|
|
127
|
-
async stop(isAbort) {
|
|
128
|
-
var _this$activeSession2;
|
|
129
|
-
if (this.recordDurationTimer) {
|
|
130
|
-
clearTimeout(this.recordDurationTimer);
|
|
131
|
-
this.recordDurationTimer = null;
|
|
132
|
-
}
|
|
133
|
-
if (this.audioStream) {
|
|
134
|
-
await this.audioStream.stop();
|
|
135
|
-
this.audioStream = null;
|
|
136
|
-
}
|
|
137
|
-
if (this.activeEvent) {
|
|
138
|
-
if (isAbort) {
|
|
139
|
-
await this.activeEvent.abort();
|
|
140
|
-
} else {
|
|
141
|
-
await this.activeEvent.end();
|
|
142
|
-
}
|
|
143
|
-
this.activeEvent = null;
|
|
144
|
-
}
|
|
145
|
-
if (isAbort) {
|
|
146
|
-
const {
|
|
147
|
-
onAbort
|
|
148
|
-
} = this.options || {};
|
|
149
|
-
typeof onAbort === 'function' && onAbort();
|
|
150
|
-
}
|
|
151
|
-
await ((_this$activeSession2 = this.activeSession) === null || _this$activeSession2 === void 0 ? void 0 : _this$activeSession2.close());
|
|
152
|
-
}
|
|
153
|
-
async abort() {
|
|
154
|
-
await this.stop(true);
|
|
155
|
-
}
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* 创建一个AsrAgent实例,用于语音转文本
|
|
160
|
-
* @param options AsrAgentOptions
|
|
161
|
-
* @param options.agentId 必填 语音转文本的agentId
|
|
162
|
-
* @param options.tokenApi 语音转文本的tokenApi
|
|
163
|
-
* @param options.tokenApiVersion 语音转文本的tokenApiVersion
|
|
164
|
-
* @param options.clientType 语音转文本的clientType
|
|
165
|
-
* @param options.deviceId 语音转文本的deviceId
|
|
166
|
-
* @example
|
|
167
|
-
* const asrAgent = createAsrAgent({
|
|
168
|
-
* agentId: 'asr-agent',
|
|
169
|
-
* tokenApi: 'xxxx',
|
|
170
|
-
* tokenApiVersion: '1.0',
|
|
171
|
-
* clientType: ConnectClientType.APP,
|
|
172
|
-
* deviceId: 'deviceId',
|
|
173
|
-
* maxDuration: 60,
|
|
174
|
-
* onMessage: (message) => {
|
|
175
|
-
* console.log('onMessage', message);
|
|
176
|
-
* },
|
|
177
|
-
* onFinish: () => {
|
|
178
|
-
* console.log('onFinish');
|
|
179
|
-
* },
|
|
180
|
-
* onError: (error) => {
|
|
181
|
-
* console.log('onError', error);
|
|
182
|
-
* },
|
|
183
|
-
* onAbort: () => {
|
|
184
|
-
* console.log('onAbort');
|
|
185
|
-
* },
|
|
186
|
-
* });
|
|
187
|
-
* // 开始录音
|
|
188
|
-
* asrAgent.start()
|
|
189
|
-
* // 停止录音
|
|
190
|
-
* asrAgent.stop()
|
|
191
|
-
* // 中断录音
|
|
192
|
-
* asrAgent.abort()
|
|
193
|
-
* @returns
|
|
194
|
-
*/
|
|
195
|
-
export function createAsrAgent(options) {
|
|
196
|
-
const asrAgent = new AsrAgent(options);
|
|
197
|
-
return asrAgent;
|
|
198
|
-
}
|