@ray-js/t-agent-plugin-aistream 0.2.0-beta-1 → 0.2.0-beta-3

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.
@@ -1,5 +1,5 @@
1
1
  import { ChatMessageObject } from '@ray-js/t-agent';
2
- import { QueryRecordListParams } from './AIStreamTypes';
2
+ import { BizCode } from './AIStreamTypes';
3
3
  export interface StoredMessageObject {
4
4
  message: ChatMessageObject;
5
5
  id: number;
@@ -10,28 +10,10 @@ export interface StoredMessageObject {
10
10
  homeId?: number;
11
11
  indexId?: string;
12
12
  }
13
- type Condition = Omit<QueryRecordListParams, 'success' | 'fail' | 'complete' | 'offset' | 'limit' | 'index2'>;
14
- type DeleteCondition = Pick<QueryRecordListParams, 'id' | 'bizCode' | 'devId' | 'homeId' | 'index' | 'index1'>;
15
13
  interface Pagination {
16
14
  sort?: 'asc' | 'desc';
17
- pageSize: number;
18
- pageNo: number;
19
- }
20
- export declare abstract class ChatHistoryStore {
21
- /** 查询消息 */
22
- abstract query(id: number): Promise<StoredMessageObject>;
23
- /** 批量查询 */
24
- abstract queryBy(condition: Condition, pagination: Pagination): Promise<{
25
- total: number;
26
- records: StoredMessageObject[];
27
- }>;
28
- /** 更新消息 */
29
- abstract update(id: number, body: ChatMessageObject): Promise<void>;
30
- abstract remove(id: number): Promise<void>;
31
- abstract removeBy(condition: Condition): Promise<void>;
32
- abstract insert(body: Partial<ChatMessageObject>): Promise<{
33
- id: number;
34
- }>;
15
+ offset: number;
16
+ limit: number;
35
17
  }
36
18
  export interface ChatHistoryStoreOptions {
37
19
  /** 家庭ID */
@@ -42,24 +24,41 @@ export interface ChatHistoryStoreOptions {
42
24
  agentId?: string;
43
25
  deviceId?: string;
44
26
  /** biz Code 大类目 */
45
- bizCode?: number;
27
+ bizCode?: BizCode;
28
+ }
29
+ export interface ChatHistoryStore<Key = number> {
30
+ /** 查询消息 */
31
+ query(id: Key): Promise<StoredMessageObject>;
32
+ /** 批量查询 */
33
+ queryAll(pagination: Pagination): Promise<{
34
+ total: number;
35
+ records: StoredMessageObject[];
36
+ }>;
37
+ /** 更新消息 */
38
+ update(id: Key, body: ChatMessageObject): Promise<void>;
39
+ remove(id: Key): Promise<void>;
40
+ removeAll(): Promise<void>;
41
+ insert(body: ChatMessageObject): Promise<{
42
+ id: Key;
43
+ }>;
46
44
  }
47
45
  export declare class ChatHistoryLocalStore implements ChatHistoryStore {
48
46
  /** 版本号,会作为内部索引的一部分 */
49
47
  private readonly version;
50
- /** 消息的meta数据,新增查询都会以此为条件 */
51
- private messageMeta;
52
- private getAgentIndexId;
48
+ private options;
53
49
  constructor(options: ChatHistoryStoreOptions);
54
- query(id: number): Promise<StoredMessageObject>;
55
- queryBy(condition: Condition, pagination: Pagination): Promise<{
50
+ private itemToMessage;
51
+ private getRecordIndex;
52
+ private getQueryCondition;
53
+ query(id: number): Promise<StoredMessageObject | null>;
54
+ queryAll(pagination: Pagination): Promise<{
56
55
  total: number;
57
56
  records: StoredMessageObject[];
58
57
  }>;
59
58
  update(id: number, body: ChatMessageObject): Promise<void>;
60
59
  remove(id: number): Promise<void>;
61
- removeBy(condition: DeleteCondition): Promise<void>;
62
- insert(body: Partial<ChatMessageObject>): Promise<{
60
+ removeAll(): Promise<void>;
61
+ insert(message: ChatMessageObject): Promise<{
63
62
  id: number;
64
63
  }>;
65
64
  }
@@ -1,160 +1,179 @@
1
+ import _objectWithoutProperties from "@babel/runtime/helpers/esm/objectWithoutProperties";
1
2
  import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
2
3
  import _defineProperty from "@babel/runtime/helpers/esm/defineProperty";
4
+ const _excluded = ["id"];
3
5
  import "core-js/modules/es.array.sort.js";
4
6
  import "core-js/modules/es.json.stringify.js";
5
7
  import "core-js/modules/esnext.iterator.constructor.js";
8
+ import "core-js/modules/esnext.iterator.filter.js";
6
9
  import "core-js/modules/esnext.iterator.map.js";
7
10
  import { safeParseJSON } from '@ray-js/t-agent';
8
- import { insertRecord, deleteRecordList, updateRecord, queryRecordList } from './utils/ttt';
9
- import { safeParseInt } from './utils/parsers';
11
+ import { insertRecord, deleteRecordList, updateRecord, queryRecordList } from './utils';
10
12
  import logger from './utils/logger';
11
- export class ChatHistoryStore {}
12
13
  export class ChatHistoryLocalStore {
13
- getAgentIndexId() {
14
- return "t-agent-".concat(this.version);
15
- }
16
14
  constructor(options) {
17
15
  /** 版本号,会作为内部索引的一部分 */
18
16
  _defineProperty(this, "version", 'v1');
19
- /** 消息的meta数据,新增查询都会以此为条件 */
20
- _defineProperty(this, "messageMeta", {});
21
- this.messageMeta = {
22
- bizCode: options.bizCode,
23
- solutionCode: options.agentId,
24
- // 使用 agentId 填充
25
- agentId: options.agentId,
26
- devId: options.deviceId,
27
- homeId: options.homeId,
28
- index: this.getAgentIndexId(),
29
- index2: options.indexId
17
+ if (!options.agentId) {
18
+ throw new Error('agentId is required');
19
+ }
20
+ if (!options.bizCode) {
21
+ throw new Error('indexId is required');
22
+ }
23
+ this.options = _objectSpread({
24
+ indexId: 'default',
25
+ homeId: 0
26
+ }, options);
27
+ }
28
+ itemToMessage(item) {
29
+ const messageInfo = safeParseJSON(item.data);
30
+ if (!messageInfo) {
31
+ logger.error('ChatHistoryLocalStore failed parse item: ', item);
32
+ return null;
33
+ }
34
+ messageInfo.message.meta.id = item.id;
35
+ return {
36
+ id: item.id,
37
+ indexId: item.index2,
38
+ agentId: item.solutionCode,
39
+ deviceId: item.devId,
40
+ homeId: item.homeId,
41
+ createdAt: messageInfo.createdAt,
42
+ updatedAt: messageInfo.updatedAt,
43
+ message: messageInfo.message
44
+ };
45
+ }
46
+ getRecordIndex() {
47
+ return {
48
+ bizCode: this.options.bizCode,
49
+ solutionCode: this.options.agentId,
50
+ homeId: this.options.homeId,
51
+ index: "t-agent-".concat(this.version),
52
+ index2: this.options.indexId,
53
+ deviceId: this.options.deviceId
30
54
  };
31
55
  }
56
+ getQueryCondition() {
57
+ const indexes = this.getRecordIndex();
58
+ const params = {
59
+ bizCode: [indexes.bizCode],
60
+ solutionCode: [indexes.solutionCode],
61
+ homeId: [indexes.homeId],
62
+ index: [indexes.index],
63
+ index2: [indexes.index2]
64
+ };
65
+ if (indexes.deviceId) {
66
+ params.devId = [indexes.deviceId];
67
+ }
68
+ return params;
69
+ }
32
70
  async query(id) {
33
71
  if (typeof id !== 'number') {
34
- logger.warn('query id is not number', {
72
+ logger.warn('ChatHistoryLocalStore query id is not number', {
35
73
  id
36
74
  });
37
75
  return null;
38
76
  }
39
- const msgList = await this.queryBy({
40
- id: [id]
41
- }, {
42
- pageSize: 1,
43
- pageNo: 0
77
+ const queryCondition = _objectSpread(_objectSpread({}, this.getQueryCondition()), {}, {
78
+ id: [id],
79
+ offset: 0,
80
+ limit: 1,
81
+ sortType: 1
44
82
  });
45
- return msgList.records[0];
83
+ const {
84
+ records
85
+ } = await queryRecordList(queryCondition);
86
+ return records[0] ? this.itemToMessage(records[0]) : null;
46
87
  }
47
- async queryBy(condition, pagination) {
48
- var _msgListRes, _msgListRes2;
49
- const queryCondition = {};
50
- // 参数严格校验,过滤空值和空[]
51
- if (condition && typeof condition === 'object') {
52
- for (const key in condition) {
53
- if (!(condition[key] === undefined || condition[key] === null || Array.isArray(condition[key]) && condition[key].length === 0)) {
54
- queryCondition[key] = condition[key];
55
- }
56
- }
57
- }
58
- // 系统使用index索引,这里使用index2填充业务的index
59
- if (Array.isArray(condition.index) && condition.index.length > 0) {
60
- queryCondition.index2 = condition.index;
61
- }
62
- queryCondition.index = [this.getAgentIndexId()];
63
- let {
64
- pageNo,
65
- pageSize
88
+ async queryAll(pagination) {
89
+ const queryCondition = _objectSpread(_objectSpread({}, this.getQueryCondition()), {}, {
90
+ offset: 0,
91
+ sortType: 1
92
+ });
93
+ const {
94
+ offset,
95
+ limit
66
96
  } = pagination || {};
67
- pageNo = safeParseInt(pageNo, 0);
68
- pageSize = safeParseInt(pageSize, 0);
69
- queryCondition.offset = pageNo * pageSize;
70
- if (pageSize) {
71
- queryCondition.limit = pageSize;
97
+ if (offset) {
98
+ queryCondition.offset = offset;
99
+ }
100
+ if (limit) {
101
+ queryCondition.limit = limit;
72
102
  }
73
103
  queryCondition.sortType = pagination.sort === 'desc' ? 0 : 1;
74
- let msgListRes = null;
75
104
  try {
76
- msgListRes = await queryRecordList(queryCondition);
105
+ const result = await queryRecordList(queryCondition);
106
+ const list = result.records.map(this.itemToMessage).filter(item => !!item);
107
+ return {
108
+ total: result.total,
109
+ records: list
110
+ };
77
111
  } catch (error) {
78
- logger.error('queryRecordList error', error);
79
- msgListRes = {
112
+ logger.error('ChatHistoryLocalStore queryRecordList error', error);
113
+ return {
80
114
  total: 0,
81
115
  records: []
82
116
  };
83
117
  }
84
- const msgList = (((_msgListRes = msgListRes) === null || _msgListRes === void 0 ? void 0 : _msgListRes.records) || []).map(item => {
85
- const messageInfo = safeParseJSON(item.data) || {};
86
- return _objectSpread(_objectSpread({}, item), {}, {
87
- createdAt: messageInfo.createdAt,
88
- updatedAt: messageInfo.updatedAt,
89
- message: messageInfo.message
90
- });
91
- });
92
- return {
93
- total: (_msgListRes2 = msgListRes) === null || _msgListRes2 === void 0 ? void 0 : _msgListRes2.total,
94
- records: msgList
95
- };
96
118
  }
97
119
  async update(id, body) {
98
120
  if (typeof id !== 'number') {
99
- logger.warn('query id is not number', {
100
- id
101
- });
102
- return null;
121
+ throw new Error('query id is not number');
103
122
  }
104
- const messageInfo = await this.query(id);
105
- if (!messageInfo) {
106
- logger.error('query messageInfo is null', {
107
- id
108
- });
109
- return null;
123
+ const stored = await this.query(id);
124
+ if (!stored) {
125
+ throw new Error("could not find message: ".concat(id));
110
126
  }
111
127
  const nowTime = Date.now();
112
128
  const msgObject = {
113
129
  message: body,
114
- createdAt: messageInfo.createdAt,
130
+ createdAt: stored.createdAt,
115
131
  updatedAt: nowTime
116
132
  };
117
- return updateRecord(_objectSpread(_objectSpread({}, this.messageMeta), {}, {
133
+ stored.message.meta.updatedAt = nowTime;
134
+ return updateRecord({
118
135
  id,
119
136
  data: JSON.stringify(msgObject)
120
- }));
137
+ });
121
138
  }
122
139
  async remove(id) {
123
140
  if (typeof id !== 'number') {
124
- logger.warn('query id is not number', {
125
- id
126
- });
127
- return null;
141
+ throw new Error('query id is not number');
128
142
  }
129
- const isExist = await this.query(id);
130
- if (!isExist) {
131
- logger.error('query messageInfo is null', {
143
+ const stored = await this.query(id);
144
+ if (!stored) {
145
+ logger.warn('ChatHistoryLocalStore not find by id', {
132
146
  id
133
147
  });
134
- return null;
135
148
  }
136
- return deleteRecordList({
149
+ await deleteRecordList({
137
150
  id: [id]
138
151
  });
139
152
  }
140
- async removeBy(condition) {
141
- const deleteCondition = _objectSpread(_objectSpread({}, condition), {}, {
142
- index: [this.getAgentIndexId()]
143
- });
144
- // 系统使用index索引,这里使用index2填充业务的index
145
- if (condition.index) {
146
- deleteCondition.index2 = condition.index;
147
- }
148
- return deleteRecordList(condition);
153
+ async removeAll() {
154
+ await deleteRecordList(this.getQueryCondition());
149
155
  }
150
- async insert(body) {
156
+ async insert(message) {
151
157
  const nowTime = Date.now();
152
- return insertRecord(_objectSpread(_objectSpread({}, this.messageMeta), {}, {
153
- data: JSON.stringify({
154
- message: body,
155
- createdAt: nowTime,
156
- updatedAt: nowTime
157
- })
158
+
159
+ // 先把 id 提取出来不存,id 始终是在数据库里自增的
160
+ const _message$meta = message.meta,
161
+ {
162
+ id
163
+ } = _message$meta,
164
+ meta = _objectWithoutProperties(_message$meta, _excluded);
165
+ const msgObject = {
166
+ message: _objectSpread(_objectSpread({}, message), {}, {
167
+ meta: _objectSpread(_objectSpread(_objectSpread({}, meta), this.options), {}, {
168
+ createdAt: nowTime,
169
+ updatedAt: nowTime
170
+ })
171
+ }),
172
+ createdAt: nowTime,
173
+ updatedAt: nowTime
174
+ };
175
+ return insertRecord(_objectSpread(_objectSpread({}, this.getRecordIndex()), {}, {
176
+ data: JSON.stringify(msgObject)
158
177
  }));
159
178
  }
160
179
  }
@@ -1,4 +1,4 @@
1
- import { Attribute, BizTag, ConnectClientType, FileFormat, VideoCameraType } from '../AIStreamTypes';
1
+ import { Attribute, BizTag, ConnectClientType, ConnectState, FileFormat, VideoCameraType } from '../AIStreamTypes';
2
2
  import { AIStreamDataEntry, AIStreamObserverPool } from './observer';
3
3
  interface AIStreamConnectionOptions {
4
4
  /** client 类型: 1-作为设备代理, 2-作为 App */
@@ -15,7 +15,7 @@ export declare class AIStreamConnection {
15
15
  private readonly pool;
16
16
  readonly options: AIStreamConnectionOptions;
17
17
  private connectionId;
18
- private state;
18
+ state: ConnectState;
19
19
  private activeSessions;
20
20
  private promise;
21
21
  private observer;
@@ -55,7 +55,7 @@ export declare class AIStreamSession {
55
55
  private activeObserver?;
56
56
  private promise;
57
57
  constructor(connection: AIStreamConnection, pool: AIStreamObserverPool, options: AIStreamSessionOptions);
58
- private ensureSession;
58
+ ensureSession(): Promise<void>;
59
59
  _onStateChanged: (entry: AIStreamDataEntry) => void;
60
60
  startEvent(options?: AIStreamEventOptions): Promise<AIStreamEvent>;
61
61
  private onDataEntry;
@@ -91,7 +91,7 @@ type AIStreamEventSource = {
91
91
  cameraType?: VideoCameraType;
92
92
  userData?: Attribute[];
93
93
  };
94
- interface AIStreamEventStream {
94
+ export interface AIStreamEventStream {
95
95
  type: 'video' | 'audio';
96
96
  dataChannel: string;
97
97
  started: boolean;
@@ -6,7 +6,7 @@ import "core-js/modules/esnext.iterator.for-each.js";
6
6
  import "core-js/modules/esnext.iterator.map.js";
7
7
  import "core-js/modules/web.dom-collections.iterator.js";
8
8
  import { AIStreamErrorCode, BizTag, ConnectClientType, ConnectState, EventType, SessionState } from '../AIStreamTypes';
9
- import { closeSession, connect, createSession, disconnect, getCurrentHomeInfo, queryAgentToken, registerRecordAmplitudes, sendEventChatBreak, sendEventEnd, sendEventPayloadEnd, sendEventStart, sendImageData, sendTextData, startRecordAndSendAudioData, stopRecordAndSendAudioData, unregisterVoiceAmplitudes } from './ttt';
9
+ import { closeSession, connect, createSession, disconnect, getCurrentHomeInfo, isConnectSync, queryAgentToken, registerRecordAmplitudes, sendEventChatBreak, sendEventEnd, sendEventPayloadEnd, sendEventStart, sendImageData, sendTextData, startRecordAndSendAudioData, stopRecordAndSendAudioData, unregisterVoiceAmplitudes } from './ttt';
10
10
  import { AIStreamObserver, AIStreamObserverPool } from './observer';
11
11
  import { isAbortError } from '@ray-js/t-agent';
12
12
  export class AIStreamClient {
@@ -32,6 +32,7 @@ export class AIStreamConnection {
32
32
  _defineProperty(this, "observer", null);
33
33
  _defineProperty(this, "onStateChanged", entry => {
34
34
  if (entry.type === 'connectionState' && entry.body.connectionId === this.connectionId) {
35
+ this.state = entry.body.connectState;
35
36
  this.activeSessions.forEach(session => {
36
37
  if (session.sessionId) {
37
38
  session._onStateChanged(entry);
@@ -39,7 +40,6 @@ export class AIStreamConnection {
39
40
  });
40
41
  if (entry.body.connectState === ConnectState.DISCONNECTED || entry.body.connectState === ConnectState.CLOSED) {
41
42
  // 事件触发的时候,只做清理
42
- this.state = entry.body.connectState;
43
43
  this.cleanup();
44
44
  }
45
45
  }
@@ -61,16 +61,22 @@ export class AIStreamConnection {
61
61
  if (this.promise) {
62
62
  return this.promise;
63
63
  }
64
- if (this.state === ConnectState.CONNECTED) {
65
- return Promise.resolve();
66
- }
67
- this.promise = (async () => {
68
- // 监听断开事件,重置 state & 清理
64
+ const result = isConnectSync(this.options);
65
+
66
+ // 监听断开事件,重置 state & 清理
67
+ if (!this.observer) {
69
68
  this.observer = new AIStreamObserver(this.onStateChanged, this.pool);
70
69
  this.observer.observe({
71
70
  connectionState: true,
72
71
  sessionState: true
73
72
  });
73
+ }
74
+ if (result.connected) {
75
+ this.state = result.state;
76
+ this.connectionId = result.connectionId;
77
+ return Promise.resolve();
78
+ }
79
+ this.promise = (async () => {
74
80
  // 调用 SDK connect
75
81
  const res = await connect(this.options);
76
82
  this.connectionId = res.connectionId;
@@ -83,6 +89,7 @@ export class AIStreamConnection {
83
89
  var _this$observer;
84
90
  (_this$observer = this.observer) === null || _this$observer === void 0 || _this$observer.disconnect();
85
91
  this.observer = null;
92
+ this.state = ConnectState.CLOSED;
86
93
  this.connectionId = null;
87
94
  this.promise = null;
88
95
  this.activeSessions.forEach(s => s.cleanup());
@@ -190,6 +197,7 @@ export class AIStreamSession {
190
197
  this.sessionId = res.sessionId;
191
198
  this.sendDataChannels = res.sendDataChannels;
192
199
  this.revDataChannels = res.revDataChannels;
200
+ this.promise = null;
193
201
  })();
194
202
  return this.promise;
195
203
  }
@@ -1,4 +1,4 @@
1
- interface ItAgentMessageAppraise {
1
+ interface MessageAppraiseParams {
2
2
  aiPtChannel: string;
3
3
  /** 小程序 ID */
4
4
  miniProgramId: string;
@@ -8,7 +8,7 @@ interface ItAgentMessageAppraise {
8
8
  approveStatus: 1 | 2;
9
9
  }
10
10
  /** 聊天智能体消息的反馈评价 */
11
- export declare const tAgentMessageAppraise: (params: ItAgentMessageAppraise) => Promise<{
11
+ export declare const messageAppraise: (params: MessageAppraiseParams) => Promise<{
12
12
  thingjson?: any;
13
13
  data: string;
14
14
  }>;
@@ -1,7 +1,7 @@
1
1
  import { apiRequestByHighway } from './ttt';
2
2
  import { HighwayMethod } from '../AIStreamTypes';
3
3
  /** 聊天智能体消息的反馈评价 */
4
- export const tAgentMessageAppraise = params => {
4
+ export const messageAppraise = params => {
5
5
  return apiRequestByHighway({
6
6
  api: '/v1.0/m/life/ai/agent/chat-panel-mini/mini/history/appraise',
7
7
  data: params,
@@ -0,0 +1,79 @@
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: 'm.thing.aigc.basic.server.token',
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 {};