agent-assistant-sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,167 @@
1
+ # 坐席辅助SDK (Agent Assistant SDK)
2
+
3
+ 一个用于坐席辅助功能的JavaScript SDK,支持音频协商和SSE连接功能。
4
+
5
+ ## 功能特性
6
+
7
+ - 音频协商 API
8
+ - SSE (Server-Sent Events) 连接
9
+ - 自动认证头生成
10
+ - 模块化设计,支持多种环境
11
+
12
+ ## 安装
13
+
14
+ ```bash
15
+ npm install @xinyao/agent-assistant-sdk
16
+ # 或
17
+ pnpm add @xinyao/agent-assistant-sdk
18
+ ```
19
+
20
+ ## 使用方法
21
+
22
+ ### ES6 模块
23
+
24
+ ```javascript
25
+ import AgentAssistantSDK from '@xinyao/agent-assistant-sdk';
26
+
27
+ const vm = new AgentAssistantSDK({
28
+ // 配置项...
29
+ });
30
+ ```
31
+
32
+ ### CommonJS
33
+
34
+ ```javascript
35
+ // 在支持ES模块的环境中(当package.json包含"type": "module"时)
36
+ import AgentAssistantSDK from '@xinyao/agent-assistant-sdk/dist/agent-assistant-sdk.js';
37
+
38
+ // 或者使用动态导入
39
+ const { default: AgentAssistantSDK } = await import('@xinyao/agent-assistant-sdk/dist/agent-assistant-sdk.js');
40
+ ```
41
+
42
+ ```javascript
43
+ import AgentAssistantSDK from '@xinyao/agent-assistant-sdk';
44
+
45
+ const vm = new AgentAssistantSDK({
46
+ url: 'https://dev.xinyaoai.com',
47
+ app_key: 'your_app_key',
48
+ app_secret: 'your_app_secret',
49
+ onMessage: (data) => {
50
+ console.log('服务器消息', data.data || data);
51
+ },
52
+ onError: (error) => {
53
+ console.log('SSE连接错误:', error.message || error);
54
+ },
55
+ onOpen: () => {
56
+ console.log('SSE连接已建立');
57
+ },
58
+ onAudioData: (audioData) => {
59
+ console.log('收到音频数据:', audioData);
60
+ }
61
+ });
62
+ ```
63
+
64
+ ### CommonJS
65
+
66
+ ```javascript
67
+ const AgentAssistantSDK = require('@xinyao/agent-assistant-sdk');
68
+
69
+ const vm = new AgentAssistantSDK({
70
+ // 配置项...
71
+ });
72
+ ```
73
+
74
+ ### 浏览器中使用
75
+
76
+ ```html
77
+ <script src="https://unpkg.com/@xinyao/agent-assistant-sdk/dist/agent-assistant-sdk.umd.js"></script>
78
+ <script>
79
+ const vm = new AgentAssistantSDK({
80
+ // 配置项...
81
+ });
82
+ </script>
83
+ ```
84
+
85
+ 注意:在UMD构建中,构造函数直接导出为`AgentAssistantSDK`,不需要使用`.default`属性。
86
+
87
+ ## API
88
+
89
+ ### 构造函数选项
90
+
91
+ - `url`: API服务器地址
92
+ - `app_key`: 应用密钥
93
+ - `app_secret`: 应用密钥
94
+ - `onMessage`: 服务器消息回调
95
+ - `onError`: 错误回调
96
+ - `onOpen`: 连接建立回调
97
+ - `onAudioData`: 音频数据回调
98
+ - `onAudioNegotiationSuccess`: 音频协商成功回调
99
+ - `onConnectSSE`: 连接SSE回调
100
+
101
+ ### 方法
102
+
103
+ #### `post(endpoint, data)`
104
+
105
+ 通用POST请求方法,可用于向指定端点发送数据。
106
+
107
+ 参数:
108
+ - `endpoint` (string): API端点路径
109
+ - `data` (object): 要发送的数据
110
+
111
+ #### `audioNegotiation(data)`
112
+
113
+ 执行音频协商请求(内部使用post方法)。
114
+
115
+ #### `connectSSEWithNegotiationResult()`
116
+
117
+ 根据音频协商结果连接SSE。此方法需要在音频协商成功后手动调用,会使用协商结果中的sse_addr和client_id来建立SSE连接。
118
+
119
+ #### `connectSSEWithURL(sseUrl)`
120
+
121
+ 使用指定URL连接SSE(辅助方法)。
122
+
123
+ 参数:
124
+ - `sseUrl` (string): SSE连接的完整URL
125
+
126
+ 参数:
127
+ - `data` (object):
128
+ - `app_id` (string, required): 租户ID
129
+ - `audio_format` (string, required): 音频格式
130
+ - `audio_sample` (string, required): 音频采样率 (8k/16k)
131
+ - `user_agent` (string, required): 客户端标识
132
+
133
+ #### `connectSSE()`
134
+
135
+ 建立SSE连接。注意:SDK会自动在请求头中添加认证信息。
136
+
137
+ #### `disconnectSSE()`
138
+
139
+ 断开SSE连接。
140
+
141
+ ## 认证
142
+
143
+ SDK会自动在每个请求中添加认证头,格式为: `Authorization: {app_key}:{timestamp}:{md5(app_secret:timestamp)}`
144
+
145
+ ## 开发
146
+
147
+ ```bash
148
+ # 安装依赖
149
+ pnpm install
150
+
151
+ # 构建
152
+ pnpm run build
153
+
154
+ # 开发模式(监听文件变化)
155
+ pnpm run dev
156
+
157
+ # 运行测试
158
+ pnpm run test
159
+ ```
160
+
161
+ 项目使用 Vite 进行构建,支持多格式输出 (ESM, CJS, UMD)。
162
+
163
+ ## 发布到npm
164
+
165
+ ```bash
166
+ npm publish
167
+ ```
@@ -0,0 +1 @@
1
+ "use strict";const t=require("event-source-polyfill");function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var n,o,r={exports:{}},s={exports:{}};n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o={rotl:function(t,e){return t<<e|t>>>32-e},rotr:function(t,e){return t<<32-e|t>>>e},endian:function(t){if(t.constructor==Number)return 16711935&o.rotl(t,8)|4278255360&o.rotl(t,24);for(var e=0;e<t.length;e++)t[e]=o.endian(t[e]);return t},randomBytes:function(t){for(var e=[];t>0;t--)e.push(Math.floor(256*Math.random()));return e},bytesToWords:function(t){for(var e=[],n=0,o=0;n<t.length;n++,o+=8)e[o>>>5]|=t[n]<<24-o%32;return e},wordsToBytes:function(t){for(var e=[],n=0;n<32*t.length;n+=8)e.push(t[n>>>5]>>>24-n%32&255);return e},bytesToHex:function(t){for(var e=[],n=0;n<t.length;n++)e.push((t[n]>>>4).toString(16)),e.push((15&t[n]).toString(16));return e.join("")},hexToBytes:function(t){for(var e=[],n=0;n<t.length;n+=2)e.push(parseInt(t.substr(n,2),16));return e},bytesToBase64:function(t){for(var e=[],o=0;o<t.length;o+=3)for(var r=t[o]<<16|t[o+1]<<8|t[o+2],s=0;s<4;s++)8*o+6*s<=8*t.length?e.push(n.charAt(r>>>6*(3-s)&63)):e.push("=");return e.join("")},base64ToBytes:function(t){t=t.replace(/[^A-Z0-9+\/]/gi,"");for(var e=[],o=0,r=0;o<t.length;r=++o%4)0!=r&&e.push((n.indexOf(t.charAt(o-1))&Math.pow(2,-2*r+8)-1)<<2*r|n.indexOf(t.charAt(o))>>>6-2*r);return e}},s.exports=o;var i,u,a,c,h,l=s.exports,f={utf8:{stringToBytes:function(t){return f.bin.stringToBytes(unescape(encodeURIComponent(t)))},bytesToString:function(t){return decodeURIComponent(escape(f.bin.bytesToString(t)))}},bin:{stringToBytes:function(t){for(var e=[],n=0;n<t.length;n++)e.push(255&t.charCodeAt(n));return e},bytesToString:function(t){for(var e=[],n=0;n<t.length;n++)e.push(String.fromCharCode(t[n]));return e.join("")}}},g=f,p=function(t){return null!=t&&(S(t)||function(t){return"function"==typeof t.readFloatLE&&"function"==typeof t.slice&&S(t.slice(0,0))}(t)||!!t._isBuffer)};function S(t){return!!t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)}i=l,u=g.utf8,a=p,c=g.bin,(h=function(t,e){t.constructor==String?t=e&&"binary"===e.encoding?c.stringToBytes(t):u.stringToBytes(t):a(t)?t=Array.prototype.slice.call(t,0):Array.isArray(t)||t.constructor===Uint8Array||(t=t.toString());for(var n=i.bytesToWords(t),o=8*t.length,r=1732584193,s=-271733879,l=-1732584194,f=271733878,g=0;g<n.length;g++)n[g]=16711935&(n[g]<<8|n[g]>>>24)|4278255360&(n[g]<<24|n[g]>>>8);n[o>>>5]|=128<<o%32,n[14+(o+64>>>9<<4)]=o;var p=h._ff,S=h._gg,d=h._hh,y=h._ii;for(g=0;g<n.length;g+=16){var v=r,T=s,_=l,A=f;r=p(r,s,l,f,n[g+0],7,-680876936),f=p(f,r,s,l,n[g+1],12,-389564586),l=p(l,f,r,s,n[g+2],17,606105819),s=p(s,l,f,r,n[g+3],22,-1044525330),r=p(r,s,l,f,n[g+4],7,-176418897),f=p(f,r,s,l,n[g+5],12,1200080426),l=p(l,f,r,s,n[g+6],17,-1473231341),s=p(s,l,f,r,n[g+7],22,-45705983),r=p(r,s,l,f,n[g+8],7,1770035416),f=p(f,r,s,l,n[g+9],12,-1958414417),l=p(l,f,r,s,n[g+10],17,-42063),s=p(s,l,f,r,n[g+11],22,-1990404162),r=p(r,s,l,f,n[g+12],7,1804603682),f=p(f,r,s,l,n[g+13],12,-40341101),l=p(l,f,r,s,n[g+14],17,-1502002290),r=S(r,s=p(s,l,f,r,n[g+15],22,1236535329),l,f,n[g+1],5,-165796510),f=S(f,r,s,l,n[g+6],9,-1069501632),l=S(l,f,r,s,n[g+11],14,643717713),s=S(s,l,f,r,n[g+0],20,-373897302),r=S(r,s,l,f,n[g+5],5,-701558691),f=S(f,r,s,l,n[g+10],9,38016083),l=S(l,f,r,s,n[g+15],14,-660478335),s=S(s,l,f,r,n[g+4],20,-405537848),r=S(r,s,l,f,n[g+9],5,568446438),f=S(f,r,s,l,n[g+14],9,-1019803690),l=S(l,f,r,s,n[g+3],14,-187363961),s=S(s,l,f,r,n[g+8],20,1163531501),r=S(r,s,l,f,n[g+13],5,-1444681467),f=S(f,r,s,l,n[g+2],9,-51403784),l=S(l,f,r,s,n[g+7],14,1735328473),r=d(r,s=S(s,l,f,r,n[g+12],20,-1926607734),l,f,n[g+5],4,-378558),f=d(f,r,s,l,n[g+8],11,-2022574463),l=d(l,f,r,s,n[g+11],16,1839030562),s=d(s,l,f,r,n[g+14],23,-35309556),r=d(r,s,l,f,n[g+1],4,-1530992060),f=d(f,r,s,l,n[g+4],11,1272893353),l=d(l,f,r,s,n[g+7],16,-155497632),s=d(s,l,f,r,n[g+10],23,-1094730640),r=d(r,s,l,f,n[g+13],4,681279174),f=d(f,r,s,l,n[g+0],11,-358537222),l=d(l,f,r,s,n[g+3],16,-722521979),s=d(s,l,f,r,n[g+6],23,76029189),r=d(r,s,l,f,n[g+9],4,-640364487),f=d(f,r,s,l,n[g+12],11,-421815835),l=d(l,f,r,s,n[g+15],16,530742520),r=y(r,s=d(s,l,f,r,n[g+2],23,-995338651),l,f,n[g+0],6,-198630844),f=y(f,r,s,l,n[g+7],10,1126891415),l=y(l,f,r,s,n[g+14],15,-1416354905),s=y(s,l,f,r,n[g+5],21,-57434055),r=y(r,s,l,f,n[g+12],6,1700485571),f=y(f,r,s,l,n[g+3],10,-1894986606),l=y(l,f,r,s,n[g+10],15,-1051523),s=y(s,l,f,r,n[g+1],21,-2054922799),r=y(r,s,l,f,n[g+8],6,1873313359),f=y(f,r,s,l,n[g+15],10,-30611744),l=y(l,f,r,s,n[g+6],15,-1560198380),s=y(s,l,f,r,n[g+13],21,1309151649),r=y(r,s,l,f,n[g+4],6,-145523070),f=y(f,r,s,l,n[g+11],10,-1120210379),l=y(l,f,r,s,n[g+2],15,718787259),s=y(s,l,f,r,n[g+9],21,-343485551),r=r+v>>>0,s=s+T>>>0,l=l+_>>>0,f=f+A>>>0}return i.endian([r,s,l,f])})._ff=function(t,e,n,o,r,s,i){var u=t+(e&n|~e&o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._gg=function(t,e,n,o,r,s,i){var u=t+(e&o|n&~o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._hh=function(t,e,n,o,r,s,i){var u=t+(e^n^o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._ii=function(t,e,n,o,r,s,i){var u=t+(n^(e|~o))+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._blocksize=16,h._digestsize=16,r.exports=function(t,e){if(null==t)throw new Error("Illegal argument "+t);var n=i.wordsToBytes(h(t,e));return e&&e.asBytes?n:e&&e.asString?c.bytesToString(n):i.bytesToHex(n)};const d=e(r.exports);module.exports=class{constructor(t={}){this.url=t.url,this.app_key=t.app_key,this.app_secret=t.app_secret,this.onMessage=t.onMessage||(()=>{}),this.onError=t.onError||(()=>{}),this.onOpen=t.onOpen||(()=>{}),this.onAudioData=t.onAudioData||(()=>{}),this.onAudioNegotiationSuccess=t.onAudioNegotiationSuccess||(()=>{}),this.onConnectSSE=t.onConnectSSE||(()=>{}),this.eventSource=null,this.negotiationResult=null}generateAuthToken(){const t=Math.floor(Date.now()/1e3);return`${this.app_key}:${t}:${d(`${this.app_secret}:${t}`)}`}getAuthHeaders(){return{Authorization:`${this.generateAuthToken()}`,"Content-Type":"application/json"}}async post(t,e){const n=this.generateAuthToken(),o=await fetch(`${this.url}${t}`,{method:"POST",headers:{Authorization:`${n}`,"Content-Type":"application/json","User-Agent":"XY-ASSIST-SDK"},body:JSON.stringify(e)});if(!o.ok){const t=await o.text();throw new Error(`HTTP error! status: ${o.status}, message: ${t}`)}return await o.json()}async audioNegotiation(t){const e=await this.post("/api/v1/agent/ccms/assist/audio-nego",t);return this.negotiationResult=e,this.onAudioNegotiationSuccess&&this.onAudioNegotiationSuccess(e),e}connectSSEWithNegotiationResult(){if(!this.negotiationResult||!this.negotiationResult.result)throw new Error("没有有效的协商结果,请先执行音频协商");const{sse_addr:t,client_id:e}=this.negotiationResult.result;if(!t||!e)throw new Error("协商结果中缺少sse_addr或client_id");const n=`http://${t}/sse?client_id=${e}`;this.connectSSEWithURL(n),this.onConnectSSE&&this.onConnectSSE({sseUrl:n,client_id:e,sse_addr:t})}connectSSEWithURL(e){this.eventSource=new t(e),this.eventSource.onmessage=t=>{const e=JSON.parse(t.data);this.onMessage(e)},this.eventSource.onerror=t=>{this.onError(t)},this.eventSource.onopen=()=>{this.onOpen()}}connectSSE(e=!0){if(e&&this.negotiationResult&&this.negotiationResult.result&&this.negotiationResult.result.sse_addr)this.connectSSEWithNegotiationResult();else{const e=this.generateAuthToken(),n=`${this.url}/api/v1/agent/sse?auth=${e}`;this.eventSource=new t(n),this.eventSource.onmessage=t=>{const e=JSON.parse(t.data);this.onMessage(e)},this.eventSource.onerror=t=>{this.onError(t)},this.eventSource.onopen=()=>{this.onOpen()}}}disconnectSSE(){this.eventSource&&(this.eventSource.close(),this.eventSource=null)}};
@@ -0,0 +1,366 @@
1
+ import EventSource from "event-source-polyfill";
2
+ function getDefaultExportFromCjs(x) {
3
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
4
+ }
5
+ var md5$1 = { exports: {} };
6
+ var crypt = { exports: {} };
7
+ (function() {
8
+ var base64map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", crypt$1 = {
9
+ // Bit-wise rotation left
10
+ rotl: function(n, b) {
11
+ return n << b | n >>> 32 - b;
12
+ },
13
+ // Bit-wise rotation right
14
+ rotr: function(n, b) {
15
+ return n << 32 - b | n >>> b;
16
+ },
17
+ // Swap big-endian to little-endian and vice versa
18
+ endian: function(n) {
19
+ if (n.constructor == Number) {
20
+ return crypt$1.rotl(n, 8) & 16711935 | crypt$1.rotl(n, 24) & 4278255360;
21
+ }
22
+ for (var i = 0; i < n.length; i++)
23
+ n[i] = crypt$1.endian(n[i]);
24
+ return n;
25
+ },
26
+ // Generate an array of any length of random bytes
27
+ randomBytes: function(n) {
28
+ for (var bytes = []; n > 0; n--)
29
+ bytes.push(Math.floor(Math.random() * 256));
30
+ return bytes;
31
+ },
32
+ // Convert a byte array to big-endian 32-bit words
33
+ bytesToWords: function(bytes) {
34
+ for (var words = [], i = 0, b = 0; i < bytes.length; i++, b += 8)
35
+ words[b >>> 5] |= bytes[i] << 24 - b % 32;
36
+ return words;
37
+ },
38
+ // Convert big-endian 32-bit words to a byte array
39
+ wordsToBytes: function(words) {
40
+ for (var bytes = [], b = 0; b < words.length * 32; b += 8)
41
+ bytes.push(words[b >>> 5] >>> 24 - b % 32 & 255);
42
+ return bytes;
43
+ },
44
+ // Convert a byte array to a hex string
45
+ bytesToHex: function(bytes) {
46
+ for (var hex = [], i = 0; i < bytes.length; i++) {
47
+ hex.push((bytes[i] >>> 4).toString(16));
48
+ hex.push((bytes[i] & 15).toString(16));
49
+ }
50
+ return hex.join("");
51
+ },
52
+ // Convert a hex string to a byte array
53
+ hexToBytes: function(hex) {
54
+ for (var bytes = [], c = 0; c < hex.length; c += 2)
55
+ bytes.push(parseInt(hex.substr(c, 2), 16));
56
+ return bytes;
57
+ },
58
+ // Convert a byte array to a base-64 string
59
+ bytesToBase64: function(bytes) {
60
+ for (var base64 = [], i = 0; i < bytes.length; i += 3) {
61
+ var triplet = bytes[i] << 16 | bytes[i + 1] << 8 | bytes[i + 2];
62
+ for (var j = 0; j < 4; j++)
63
+ if (i * 8 + j * 6 <= bytes.length * 8)
64
+ base64.push(base64map.charAt(triplet >>> 6 * (3 - j) & 63));
65
+ else
66
+ base64.push("=");
67
+ }
68
+ return base64.join("");
69
+ },
70
+ // Convert a base-64 string to a byte array
71
+ base64ToBytes: function(base64) {
72
+ base64 = base64.replace(/[^A-Z0-9+\/]/ig, "");
73
+ for (var bytes = [], i = 0, imod4 = 0; i < base64.length; imod4 = ++i % 4) {
74
+ if (imod4 == 0) continue;
75
+ bytes.push((base64map.indexOf(base64.charAt(i - 1)) & Math.pow(2, -2 * imod4 + 8) - 1) << imod4 * 2 | base64map.indexOf(base64.charAt(i)) >>> 6 - imod4 * 2);
76
+ }
77
+ return bytes;
78
+ }
79
+ };
80
+ crypt.exports = crypt$1;
81
+ })();
82
+ var cryptExports = crypt.exports;
83
+ var charenc = {
84
+ // UTF-8 encoding
85
+ utf8: {
86
+ // Convert a string to a byte array
87
+ stringToBytes: function(str) {
88
+ return charenc.bin.stringToBytes(unescape(encodeURIComponent(str)));
89
+ },
90
+ // Convert a byte array to a string
91
+ bytesToString: function(bytes) {
92
+ return decodeURIComponent(escape(charenc.bin.bytesToString(bytes)));
93
+ }
94
+ },
95
+ // Binary encoding
96
+ bin: {
97
+ // Convert a string to a byte array
98
+ stringToBytes: function(str) {
99
+ for (var bytes = [], i = 0; i < str.length; i++)
100
+ bytes.push(str.charCodeAt(i) & 255);
101
+ return bytes;
102
+ },
103
+ // Convert a byte array to a string
104
+ bytesToString: function(bytes) {
105
+ for (var str = [], i = 0; i < bytes.length; i++)
106
+ str.push(String.fromCharCode(bytes[i]));
107
+ return str.join("");
108
+ }
109
+ }
110
+ };
111
+ var charenc_1 = charenc;
112
+ /*!
113
+ * Determine if an object is a Buffer
114
+ *
115
+ * @author Feross Aboukhadijeh <https://feross.org>
116
+ * @license MIT
117
+ */
118
+ var isBuffer_1 = function(obj) {
119
+ return obj != null && (isBuffer(obj) || isSlowBuffer(obj) || !!obj._isBuffer);
120
+ };
121
+ function isBuffer(obj) {
122
+ return !!obj.constructor && typeof obj.constructor.isBuffer === "function" && obj.constructor.isBuffer(obj);
123
+ }
124
+ function isSlowBuffer(obj) {
125
+ return typeof obj.readFloatLE === "function" && typeof obj.slice === "function" && isBuffer(obj.slice(0, 0));
126
+ }
127
+ (function() {
128
+ var crypt2 = cryptExports, utf8 = charenc_1.utf8, isBuffer2 = isBuffer_1, bin = charenc_1.bin, md52 = function(message, options) {
129
+ if (message.constructor == String)
130
+ if (options && options.encoding === "binary")
131
+ message = bin.stringToBytes(message);
132
+ else
133
+ message = utf8.stringToBytes(message);
134
+ else if (isBuffer2(message))
135
+ message = Array.prototype.slice.call(message, 0);
136
+ else if (!Array.isArray(message) && message.constructor !== Uint8Array)
137
+ message = message.toString();
138
+ var m = crypt2.bytesToWords(message), l = message.length * 8, a = 1732584193, b = -271733879, c = -1732584194, d = 271733878;
139
+ for (var i = 0; i < m.length; i++) {
140
+ m[i] = (m[i] << 8 | m[i] >>> 24) & 16711935 | (m[i] << 24 | m[i] >>> 8) & 4278255360;
141
+ }
142
+ m[l >>> 5] |= 128 << l % 32;
143
+ m[(l + 64 >>> 9 << 4) + 14] = l;
144
+ var FF = md52._ff, GG = md52._gg, HH = md52._hh, II = md52._ii;
145
+ for (var i = 0; i < m.length; i += 16) {
146
+ var aa = a, bb = b, cc = c, dd = d;
147
+ a = FF(a, b, c, d, m[i + 0], 7, -680876936);
148
+ d = FF(d, a, b, c, m[i + 1], 12, -389564586);
149
+ c = FF(c, d, a, b, m[i + 2], 17, 606105819);
150
+ b = FF(b, c, d, a, m[i + 3], 22, -1044525330);
151
+ a = FF(a, b, c, d, m[i + 4], 7, -176418897);
152
+ d = FF(d, a, b, c, m[i + 5], 12, 1200080426);
153
+ c = FF(c, d, a, b, m[i + 6], 17, -1473231341);
154
+ b = FF(b, c, d, a, m[i + 7], 22, -45705983);
155
+ a = FF(a, b, c, d, m[i + 8], 7, 1770035416);
156
+ d = FF(d, a, b, c, m[i + 9], 12, -1958414417);
157
+ c = FF(c, d, a, b, m[i + 10], 17, -42063);
158
+ b = FF(b, c, d, a, m[i + 11], 22, -1990404162);
159
+ a = FF(a, b, c, d, m[i + 12], 7, 1804603682);
160
+ d = FF(d, a, b, c, m[i + 13], 12, -40341101);
161
+ c = FF(c, d, a, b, m[i + 14], 17, -1502002290);
162
+ b = FF(b, c, d, a, m[i + 15], 22, 1236535329);
163
+ a = GG(a, b, c, d, m[i + 1], 5, -165796510);
164
+ d = GG(d, a, b, c, m[i + 6], 9, -1069501632);
165
+ c = GG(c, d, a, b, m[i + 11], 14, 643717713);
166
+ b = GG(b, c, d, a, m[i + 0], 20, -373897302);
167
+ a = GG(a, b, c, d, m[i + 5], 5, -701558691);
168
+ d = GG(d, a, b, c, m[i + 10], 9, 38016083);
169
+ c = GG(c, d, a, b, m[i + 15], 14, -660478335);
170
+ b = GG(b, c, d, a, m[i + 4], 20, -405537848);
171
+ a = GG(a, b, c, d, m[i + 9], 5, 568446438);
172
+ d = GG(d, a, b, c, m[i + 14], 9, -1019803690);
173
+ c = GG(c, d, a, b, m[i + 3], 14, -187363961);
174
+ b = GG(b, c, d, a, m[i + 8], 20, 1163531501);
175
+ a = GG(a, b, c, d, m[i + 13], 5, -1444681467);
176
+ d = GG(d, a, b, c, m[i + 2], 9, -51403784);
177
+ c = GG(c, d, a, b, m[i + 7], 14, 1735328473);
178
+ b = GG(b, c, d, a, m[i + 12], 20, -1926607734);
179
+ a = HH(a, b, c, d, m[i + 5], 4, -378558);
180
+ d = HH(d, a, b, c, m[i + 8], 11, -2022574463);
181
+ c = HH(c, d, a, b, m[i + 11], 16, 1839030562);
182
+ b = HH(b, c, d, a, m[i + 14], 23, -35309556);
183
+ a = HH(a, b, c, d, m[i + 1], 4, -1530992060);
184
+ d = HH(d, a, b, c, m[i + 4], 11, 1272893353);
185
+ c = HH(c, d, a, b, m[i + 7], 16, -155497632);
186
+ b = HH(b, c, d, a, m[i + 10], 23, -1094730640);
187
+ a = HH(a, b, c, d, m[i + 13], 4, 681279174);
188
+ d = HH(d, a, b, c, m[i + 0], 11, -358537222);
189
+ c = HH(c, d, a, b, m[i + 3], 16, -722521979);
190
+ b = HH(b, c, d, a, m[i + 6], 23, 76029189);
191
+ a = HH(a, b, c, d, m[i + 9], 4, -640364487);
192
+ d = HH(d, a, b, c, m[i + 12], 11, -421815835);
193
+ c = HH(c, d, a, b, m[i + 15], 16, 530742520);
194
+ b = HH(b, c, d, a, m[i + 2], 23, -995338651);
195
+ a = II(a, b, c, d, m[i + 0], 6, -198630844);
196
+ d = II(d, a, b, c, m[i + 7], 10, 1126891415);
197
+ c = II(c, d, a, b, m[i + 14], 15, -1416354905);
198
+ b = II(b, c, d, a, m[i + 5], 21, -57434055);
199
+ a = II(a, b, c, d, m[i + 12], 6, 1700485571);
200
+ d = II(d, a, b, c, m[i + 3], 10, -1894986606);
201
+ c = II(c, d, a, b, m[i + 10], 15, -1051523);
202
+ b = II(b, c, d, a, m[i + 1], 21, -2054922799);
203
+ a = II(a, b, c, d, m[i + 8], 6, 1873313359);
204
+ d = II(d, a, b, c, m[i + 15], 10, -30611744);
205
+ c = II(c, d, a, b, m[i + 6], 15, -1560198380);
206
+ b = II(b, c, d, a, m[i + 13], 21, 1309151649);
207
+ a = II(a, b, c, d, m[i + 4], 6, -145523070);
208
+ d = II(d, a, b, c, m[i + 11], 10, -1120210379);
209
+ c = II(c, d, a, b, m[i + 2], 15, 718787259);
210
+ b = II(b, c, d, a, m[i + 9], 21, -343485551);
211
+ a = a + aa >>> 0;
212
+ b = b + bb >>> 0;
213
+ c = c + cc >>> 0;
214
+ d = d + dd >>> 0;
215
+ }
216
+ return crypt2.endian([a, b, c, d]);
217
+ };
218
+ md52._ff = function(a, b, c, d, x, s, t) {
219
+ var n = a + (b & c | ~b & d) + (x >>> 0) + t;
220
+ return (n << s | n >>> 32 - s) + b;
221
+ };
222
+ md52._gg = function(a, b, c, d, x, s, t) {
223
+ var n = a + (b & d | c & ~d) + (x >>> 0) + t;
224
+ return (n << s | n >>> 32 - s) + b;
225
+ };
226
+ md52._hh = function(a, b, c, d, x, s, t) {
227
+ var n = a + (b ^ c ^ d) + (x >>> 0) + t;
228
+ return (n << s | n >>> 32 - s) + b;
229
+ };
230
+ md52._ii = function(a, b, c, d, x, s, t) {
231
+ var n = a + (c ^ (b | ~d)) + (x >>> 0) + t;
232
+ return (n << s | n >>> 32 - s) + b;
233
+ };
234
+ md52._blocksize = 16;
235
+ md52._digestsize = 16;
236
+ md5$1.exports = function(message, options) {
237
+ if (message === void 0 || message === null)
238
+ throw new Error("Illegal argument " + message);
239
+ var digestbytes = crypt2.wordsToBytes(md52(message, options));
240
+ return options && options.asBytes ? digestbytes : options && options.asString ? bin.bytesToString(digestbytes) : crypt2.bytesToHex(digestbytes);
241
+ };
242
+ })();
243
+ var md5Exports = md5$1.exports;
244
+ const md5 = /* @__PURE__ */ getDefaultExportFromCjs(md5Exports);
245
+ class AgentAssistantSDK {
246
+ constructor(options = {}) {
247
+ this.url = options.url;
248
+ this.app_key = options.app_key;
249
+ this.app_secret = options.app_secret;
250
+ this.onMessage = options.onMessage || (() => {
251
+ });
252
+ this.onError = options.onError || (() => {
253
+ });
254
+ this.onOpen = options.onOpen || (() => {
255
+ });
256
+ this.onAudioData = options.onAudioData || (() => {
257
+ });
258
+ this.onAudioNegotiationSuccess = options.onAudioNegotiationSuccess || (() => {
259
+ });
260
+ this.onConnectSSE = options.onConnectSSE || (() => {
261
+ });
262
+ this.eventSource = null;
263
+ this.negotiationResult = null;
264
+ }
265
+ // 生成认证字符串: app_key:timestamp:md5(app_secret:timestamp)
266
+ generateAuthToken() {
267
+ const timestamp = Math.floor(Date.now() / 1e3);
268
+ const authString = `${this.app_key}:${timestamp}:${md5(`${this.app_secret}:${timestamp}`)}`;
269
+ return authString;
270
+ }
271
+ // 获取认证头
272
+ getAuthHeaders() {
273
+ return {
274
+ "Authorization": `${this.generateAuthToken()}`,
275
+ "Content-Type": "application/json"
276
+ };
277
+ }
278
+ // 通用POST请求方法
279
+ async post(endpoint, data) {
280
+ const authToken = this.generateAuthToken();
281
+ const response = await fetch(`${this.url}${endpoint}`, {
282
+ method: "POST",
283
+ headers: {
284
+ "Authorization": `${authToken}`,
285
+ "Content-Type": "application/json",
286
+ "User-Agent": "XY-ASSIST-SDK"
287
+ },
288
+ body: JSON.stringify(data)
289
+ });
290
+ if (!response.ok) {
291
+ const errorData = await response.text();
292
+ throw new Error(`HTTP error! status: ${response.status}, message: ${errorData}`);
293
+ }
294
+ return await response.json();
295
+ }
296
+ // 音频协商API
297
+ async audioNegotiation(data) {
298
+ const result = await this.post("/api/v1/agent/ccms/assist/audio-nego", data);
299
+ this.negotiationResult = result;
300
+ if (this.onAudioNegotiationSuccess) {
301
+ this.onAudioNegotiationSuccess(result);
302
+ }
303
+ return result;
304
+ }
305
+ // 根据协商结果连接SSE
306
+ // 用户需要在音频协商成功后手动调用此方法
307
+ connectSSEWithNegotiationResult() {
308
+ if (!this.negotiationResult || !this.negotiationResult.result) {
309
+ throw new Error("没有有效的协商结果,请先执行音频协商");
310
+ }
311
+ const { sse_addr, client_id } = this.negotiationResult.result;
312
+ if (!sse_addr || !client_id) {
313
+ throw new Error("协商结果中缺少sse_addr或client_id");
314
+ }
315
+ const sseUrl = `http://${sse_addr}/sse?client_id=${client_id}`;
316
+ this.connectSSEWithURL(sseUrl);
317
+ if (this.onConnectSSE) {
318
+ this.onConnectSSE({ sseUrl, client_id, sse_addr });
319
+ }
320
+ }
321
+ // 使用指定URL连接SSE(辅助方法)
322
+ connectSSEWithURL(sseUrl) {
323
+ this.eventSource = new EventSource(sseUrl);
324
+ this.eventSource.onmessage = (event) => {
325
+ const data = JSON.parse(event.data);
326
+ this.onMessage(data);
327
+ };
328
+ this.eventSource.onerror = (error) => {
329
+ this.onError(error);
330
+ };
331
+ this.eventSource.onopen = () => {
332
+ this.onOpen();
333
+ };
334
+ }
335
+ // 建立SSE连接
336
+ // 如果有协商结果,则使用协商结果中的SSE地址,否则使用默认端点
337
+ connectSSE(useNegotiationResult = true) {
338
+ if (useNegotiationResult && this.negotiationResult && this.negotiationResult.result && this.negotiationResult.result.sse_addr) {
339
+ this.connectSSEWithNegotiationResult();
340
+ } else {
341
+ const authToken = this.generateAuthToken();
342
+ const sseUrl = `${this.url}/api/v1/agent/sse?auth=${authToken}`;
343
+ this.eventSource = new EventSource(sseUrl);
344
+ this.eventSource.onmessage = (event) => {
345
+ const data = JSON.parse(event.data);
346
+ this.onMessage(data);
347
+ };
348
+ this.eventSource.onerror = (error) => {
349
+ this.onError(error);
350
+ };
351
+ this.eventSource.onopen = () => {
352
+ this.onOpen();
353
+ };
354
+ }
355
+ }
356
+ // 关闭SSE连接
357
+ disconnectSSE() {
358
+ if (this.eventSource) {
359
+ this.eventSource.close();
360
+ this.eventSource = null;
361
+ }
362
+ }
363
+ }
364
+ export {
365
+ AgentAssistantSDK as default
366
+ };
@@ -0,0 +1 @@
1
+ !function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("event-source-polyfill")):"function"==typeof define&&define.amd?define(["event-source-polyfill"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).AgentAssistantSDK=e(t.EventSource)}(this,function(t){"use strict";function e(t){return t&&t.__esModule&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t}var n,o,r={exports:{}},s={exports:{}};n="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/",o={rotl:function(t,e){return t<<e|t>>>32-e},rotr:function(t,e){return t<<32-e|t>>>e},endian:function(t){if(t.constructor==Number)return 16711935&o.rotl(t,8)|4278255360&o.rotl(t,24);for(var e=0;e<t.length;e++)t[e]=o.endian(t[e]);return t},randomBytes:function(t){for(var e=[];t>0;t--)e.push(Math.floor(256*Math.random()));return e},bytesToWords:function(t){for(var e=[],n=0,o=0;n<t.length;n++,o+=8)e[o>>>5]|=t[n]<<24-o%32;return e},wordsToBytes:function(t){for(var e=[],n=0;n<32*t.length;n+=8)e.push(t[n>>>5]>>>24-n%32&255);return e},bytesToHex:function(t){for(var e=[],n=0;n<t.length;n++)e.push((t[n]>>>4).toString(16)),e.push((15&t[n]).toString(16));return e.join("")},hexToBytes:function(t){for(var e=[],n=0;n<t.length;n+=2)e.push(parseInt(t.substr(n,2),16));return e},bytesToBase64:function(t){for(var e=[],o=0;o<t.length;o+=3)for(var r=t[o]<<16|t[o+1]<<8|t[o+2],s=0;s<4;s++)8*o+6*s<=8*t.length?e.push(n.charAt(r>>>6*(3-s)&63)):e.push("=");return e.join("")},base64ToBytes:function(t){t=t.replace(/[^A-Z0-9+\/]/gi,"");for(var e=[],o=0,r=0;o<t.length;r=++o%4)0!=r&&e.push((n.indexOf(t.charAt(o-1))&Math.pow(2,-2*r+8)-1)<<2*r|n.indexOf(t.charAt(o))>>>6-2*r);return e}},s.exports=o;var i,u,a,c,h,f=s.exports,l={utf8:{stringToBytes:function(t){return l.bin.stringToBytes(unescape(encodeURIComponent(t)))},bytesToString:function(t){return decodeURIComponent(escape(l.bin.bytesToString(t)))}},bin:{stringToBytes:function(t){for(var e=[],n=0;n<t.length;n++)e.push(255&t.charCodeAt(n));return e},bytesToString:function(t){for(var e=[],n=0;n<t.length;n++)e.push(String.fromCharCode(t[n]));return e.join("")}}},g=l,p=function(t){return null!=t&&(d(t)||function(t){return"function"==typeof t.readFloatLE&&"function"==typeof t.slice&&d(t.slice(0,0))}(t)||!!t._isBuffer)};function d(t){return!!t.constructor&&"function"==typeof t.constructor.isBuffer&&t.constructor.isBuffer(t)}i=f,u=g.utf8,a=p,c=g.bin,(h=function(t,e){t.constructor==String?t=e&&"binary"===e.encoding?c.stringToBytes(t):u.stringToBytes(t):a(t)?t=Array.prototype.slice.call(t,0):Array.isArray(t)||t.constructor===Uint8Array||(t=t.toString());for(var n=i.bytesToWords(t),o=8*t.length,r=1732584193,s=-271733879,f=-1732584194,l=271733878,g=0;g<n.length;g++)n[g]=16711935&(n[g]<<8|n[g]>>>24)|4278255360&(n[g]<<24|n[g]>>>8);n[o>>>5]|=128<<o%32,n[14+(o+64>>>9<<4)]=o;var p=h._ff,d=h._gg,S=h._hh,y=h._ii;for(g=0;g<n.length;g+=16){var v=r,T=s,A=f,_=l;r=p(r,s,f,l,n[g+0],7,-680876936),l=p(l,r,s,f,n[g+1],12,-389564586),f=p(f,l,r,s,n[g+2],17,606105819),s=p(s,f,l,r,n[g+3],22,-1044525330),r=p(r,s,f,l,n[g+4],7,-176418897),l=p(l,r,s,f,n[g+5],12,1200080426),f=p(f,l,r,s,n[g+6],17,-1473231341),s=p(s,f,l,r,n[g+7],22,-45705983),r=p(r,s,f,l,n[g+8],7,1770035416),l=p(l,r,s,f,n[g+9],12,-1958414417),f=p(f,l,r,s,n[g+10],17,-42063),s=p(s,f,l,r,n[g+11],22,-1990404162),r=p(r,s,f,l,n[g+12],7,1804603682),l=p(l,r,s,f,n[g+13],12,-40341101),f=p(f,l,r,s,n[g+14],17,-1502002290),r=d(r,s=p(s,f,l,r,n[g+15],22,1236535329),f,l,n[g+1],5,-165796510),l=d(l,r,s,f,n[g+6],9,-1069501632),f=d(f,l,r,s,n[g+11],14,643717713),s=d(s,f,l,r,n[g+0],20,-373897302),r=d(r,s,f,l,n[g+5],5,-701558691),l=d(l,r,s,f,n[g+10],9,38016083),f=d(f,l,r,s,n[g+15],14,-660478335),s=d(s,f,l,r,n[g+4],20,-405537848),r=d(r,s,f,l,n[g+9],5,568446438),l=d(l,r,s,f,n[g+14],9,-1019803690),f=d(f,l,r,s,n[g+3],14,-187363961),s=d(s,f,l,r,n[g+8],20,1163531501),r=d(r,s,f,l,n[g+13],5,-1444681467),l=d(l,r,s,f,n[g+2],9,-51403784),f=d(f,l,r,s,n[g+7],14,1735328473),r=S(r,s=d(s,f,l,r,n[g+12],20,-1926607734),f,l,n[g+5],4,-378558),l=S(l,r,s,f,n[g+8],11,-2022574463),f=S(f,l,r,s,n[g+11],16,1839030562),s=S(s,f,l,r,n[g+14],23,-35309556),r=S(r,s,f,l,n[g+1],4,-1530992060),l=S(l,r,s,f,n[g+4],11,1272893353),f=S(f,l,r,s,n[g+7],16,-155497632),s=S(s,f,l,r,n[g+10],23,-1094730640),r=S(r,s,f,l,n[g+13],4,681279174),l=S(l,r,s,f,n[g+0],11,-358537222),f=S(f,l,r,s,n[g+3],16,-722521979),s=S(s,f,l,r,n[g+6],23,76029189),r=S(r,s,f,l,n[g+9],4,-640364487),l=S(l,r,s,f,n[g+12],11,-421815835),f=S(f,l,r,s,n[g+15],16,530742520),r=y(r,s=S(s,f,l,r,n[g+2],23,-995338651),f,l,n[g+0],6,-198630844),l=y(l,r,s,f,n[g+7],10,1126891415),f=y(f,l,r,s,n[g+14],15,-1416354905),s=y(s,f,l,r,n[g+5],21,-57434055),r=y(r,s,f,l,n[g+12],6,1700485571),l=y(l,r,s,f,n[g+3],10,-1894986606),f=y(f,l,r,s,n[g+10],15,-1051523),s=y(s,f,l,r,n[g+1],21,-2054922799),r=y(r,s,f,l,n[g+8],6,1873313359),l=y(l,r,s,f,n[g+15],10,-30611744),f=y(f,l,r,s,n[g+6],15,-1560198380),s=y(s,f,l,r,n[g+13],21,1309151649),r=y(r,s,f,l,n[g+4],6,-145523070),l=y(l,r,s,f,n[g+11],10,-1120210379),f=y(f,l,r,s,n[g+2],15,718787259),s=y(s,f,l,r,n[g+9],21,-343485551),r=r+v>>>0,s=s+T>>>0,f=f+A>>>0,l=l+_>>>0}return i.endian([r,s,f,l])})._ff=function(t,e,n,o,r,s,i){var u=t+(e&n|~e&o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._gg=function(t,e,n,o,r,s,i){var u=t+(e&o|n&~o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._hh=function(t,e,n,o,r,s,i){var u=t+(e^n^o)+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._ii=function(t,e,n,o,r,s,i){var u=t+(n^(e|~o))+(r>>>0)+i;return(u<<s|u>>>32-s)+e},h._blocksize=16,h._digestsize=16,r.exports=function(t,e){if(null==t)throw new Error("Illegal argument "+t);var n=i.wordsToBytes(h(t,e));return e&&e.asBytes?n:e&&e.asString?c.bytesToString(n):i.bytesToHex(n)};const S=e(r.exports);return class{constructor(t={}){this.url=t.url,this.app_key=t.app_key,this.app_secret=t.app_secret,this.onMessage=t.onMessage||(()=>{}),this.onError=t.onError||(()=>{}),this.onOpen=t.onOpen||(()=>{}),this.onAudioData=t.onAudioData||(()=>{}),this.onAudioNegotiationSuccess=t.onAudioNegotiationSuccess||(()=>{}),this.onConnectSSE=t.onConnectSSE||(()=>{}),this.eventSource=null,this.negotiationResult=null}generateAuthToken(){const t=Math.floor(Date.now()/1e3);return`${this.app_key}:${t}:${S(`${this.app_secret}:${t}`)}`}getAuthHeaders(){return{Authorization:`${this.generateAuthToken()}`,"Content-Type":"application/json"}}async post(t,e){const n=this.generateAuthToken(),o=await fetch(`${this.url}${t}`,{method:"POST",headers:{Authorization:`${n}`,"Content-Type":"application/json","User-Agent":"XY-ASSIST-SDK"},body:JSON.stringify(e)});if(!o.ok){const t=await o.text();throw new Error(`HTTP error! status: ${o.status}, message: ${t}`)}return await o.json()}async audioNegotiation(t){const e=await this.post("/api/v1/agent/ccms/assist/audio-nego",t);return this.negotiationResult=e,this.onAudioNegotiationSuccess&&this.onAudioNegotiationSuccess(e),e}connectSSEWithNegotiationResult(){if(!this.negotiationResult||!this.negotiationResult.result)throw new Error("没有有效的协商结果,请先执行音频协商");const{sse_addr:t,client_id:e}=this.negotiationResult.result;if(!t||!e)throw new Error("协商结果中缺少sse_addr或client_id");const n=`http://${t}/sse?client_id=${e}`;this.connectSSEWithURL(n),this.onConnectSSE&&this.onConnectSSE({sseUrl:n,client_id:e,sse_addr:t})}connectSSEWithURL(e){this.eventSource=new t(e),this.eventSource.onmessage=t=>{const e=JSON.parse(t.data);this.onMessage(e)},this.eventSource.onerror=t=>{this.onError(t)},this.eventSource.onopen=()=>{this.onOpen()}}connectSSE(e=!0){if(e&&this.negotiationResult&&this.negotiationResult.result&&this.negotiationResult.result.sse_addr)this.connectSSEWithNegotiationResult();else{const e=this.generateAuthToken(),n=`${this.url}/api/v1/agent/sse?auth=${e}`;this.eventSource=new t(n),this.eventSource.onmessage=t=>{const e=JSON.parse(t.data);this.onMessage(e)},this.eventSource.onerror=t=>{this.onError(t)},this.eventSource.onopen=()=>{this.onOpen()}}}disconnectSSE(){this.eventSource&&(this.eventSource.close(),this.eventSource=null)}}});
package/package.json ADDED
@@ -0,0 +1,46 @@
1
+ {
2
+ "name": "agent-assistant-sdk",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "description": "坐席辅助SDK - 提供音频协商和SSE连接功能",
6
+ "main": "./dist/agent-assistant-sdk.cjs.js",
7
+ "module": "./dist/agent-assistant-sdk.es.js",
8
+ "browser": "./dist/agent-assistant-sdk.umd.js",
9
+ "scripts": {
10
+ "build": "vite build",
11
+ "dev": "vite build --watch",
12
+ "test": "node --experimental-vm-modules ./node_modules/.bin/jest",
13
+ "prepublishOnly": "npm run build"
14
+ },
15
+ "keywords": [
16
+ "customer-service",
17
+ "assistant",
18
+ "sdk",
19
+ "audio",
20
+ "negotiation"
21
+ ],
22
+ "author": "Xinyao AI",
23
+ "license": "MIT",
24
+ "dependencies": {
25
+ "event-source-polyfill": "^1.0.31",
26
+ "md5": "^2.3.0"
27
+ },
28
+ "devDependencies": {
29
+ "jest": "^29.7.0",
30
+ "vite": "^5.4.21"
31
+ },
32
+ "files": [
33
+ "dist/",
34
+ "src/",
35
+ "README.md",
36
+ "LICENSE"
37
+ ],
38
+ "repository": {
39
+ "type": "git",
40
+ "url": "https://github.com/xinyao/agent-assistant-sdk.git"
41
+ },
42
+ "bugs": {
43
+ "url": "https://github.com/xinyao/agent-assistant-sdk/issues"
44
+ },
45
+ "homepage": "https://github.com/xinyao/agent-assistant-sdk#readme"
46
+ }
@@ -0,0 +1,153 @@
1
+ import EventSource from 'event-source-polyfill';
2
+ import md5 from 'md5';
3
+
4
+ class AgentAssistantSDK {
5
+ constructor(options = {}) {
6
+ this.url = options.url;
7
+ this.app_key = options.app_key;
8
+ this.app_secret = options.app_secret;
9
+ this.onMessage = options.onMessage || (() => {});
10
+ this.onError = options.onError || (() => {});
11
+ this.onOpen = options.onOpen || (() => {});
12
+ this.onAudioData = options.onAudioData || (() => {});
13
+ this.onAudioNegotiationSuccess = options.onAudioNegotiationSuccess || (() => {});
14
+ this.onConnectSSE = options.onConnectSSE || (() => {});
15
+ this.eventSource = null;
16
+ // 存储协商结果
17
+ this.negotiationResult = null;
18
+ }
19
+
20
+ // 生成认证字符串: app_key:timestamp:md5(app_secret:timestamp)
21
+ generateAuthToken() {
22
+ const timestamp = Math.floor(Date.now() / 1000);
23
+ const authString = `${this.app_key}:${timestamp}:${md5(`${this.app_secret}:${timestamp}`)}`;
24
+ return authString;
25
+ }
26
+
27
+ // 获取认证头
28
+ getAuthHeaders() {
29
+ return {
30
+ 'Authorization': `${this.generateAuthToken()}`,
31
+ 'Content-Type': 'application/json'
32
+ };
33
+ }
34
+
35
+ // 通用POST请求方法
36
+ async post(endpoint, data) {
37
+ const authToken = this.generateAuthToken();
38
+
39
+ const response = await fetch(`${this.url}${endpoint}`, {
40
+ method: 'POST',
41
+ headers: {
42
+ 'Authorization': `${authToken}`,
43
+ 'Content-Type': 'application/json',
44
+ 'User-Agent': 'XY-ASSIST-SDK'
45
+ },
46
+ body: JSON.stringify(data)
47
+ });
48
+
49
+ if (!response.ok) {
50
+ const errorData = await response.text();
51
+ throw new Error(`HTTP error! status: ${response.status}, message: ${errorData}`);
52
+ }
53
+
54
+ return await response.json();
55
+ }
56
+
57
+ // 音频协商API
58
+ async audioNegotiation(data) {
59
+ const result = await this.post('/api/v1/agent/ccms/assist/audio-nego', data);
60
+
61
+ // 存储协商结果
62
+ this.negotiationResult = result;
63
+
64
+ // 触发音频协商成功的回调
65
+ if (this.onAudioNegotiationSuccess) {
66
+ this.onAudioNegotiationSuccess(result);
67
+ }
68
+
69
+ return result;
70
+ }
71
+
72
+ // 根据协商结果连接SSE
73
+ // 用户需要在音频协商成功后手动调用此方法
74
+ connectSSEWithNegotiationResult() {
75
+ if (!this.negotiationResult || !this.negotiationResult.result) {
76
+ throw new Error('没有有效的协商结果,请先执行音频协商');
77
+ }
78
+
79
+ const { sse_addr, client_id } = this.negotiationResult.result;
80
+
81
+ if (!sse_addr || !client_id) {
82
+ throw new Error('协商结果中缺少sse_addr或client_id');
83
+ }
84
+
85
+ // 构建SSE URL
86
+ const sseUrl = `http://${sse_addr}/sse?client_id=${client_id}`;
87
+
88
+ // 连接SSE
89
+ this.connectSSEWithURL(sseUrl);
90
+
91
+ // 触发连接SSE的回调
92
+ if (this.onConnectSSE) {
93
+ this.onConnectSSE({ sseUrl, client_id, sse_addr });
94
+ }
95
+ }
96
+
97
+ // 使用指定URL连接SSE(辅助方法)
98
+ connectSSEWithURL(sseUrl) {
99
+ this.eventSource = new EventSource(sseUrl);
100
+
101
+ this.eventSource.onmessage = (event) => {
102
+ const data = JSON.parse(event.data);
103
+ this.onMessage(data);
104
+ };
105
+
106
+ this.eventSource.onerror = (error) => {
107
+ this.onError(error);
108
+ };
109
+
110
+ this.eventSource.onopen = () => {
111
+ this.onOpen();
112
+ };
113
+ }
114
+
115
+ // 建立SSE连接
116
+ // 如果有协商结果,则使用协商结果中的SSE地址,否则使用默认端点
117
+ connectSSE(useNegotiationResult = true) {
118
+ // 如果明确要求使用协商结果,且存在协商结果,则使用协商结果连接
119
+ if (useNegotiationResult && this.negotiationResult && this.negotiationResult.result && this.negotiationResult.result.sse_addr) {
120
+ this.connectSSEWithNegotiationResult();
121
+ } else {
122
+ // 如果没有协商结果或明确要求不使用协商结果,使用默认的SSE端点
123
+ const authToken = this.generateAuthToken();
124
+ // 根据您提供的代码片段,使用正确的SSE端点
125
+ const sseUrl = `${this.url}/api/v1/agent/sse?auth=${authToken}`;
126
+
127
+ this.eventSource = new EventSource(sseUrl);
128
+
129
+ this.eventSource.onmessage = (event) => {
130
+ const data = JSON.parse(event.data);
131
+ this.onMessage(data);
132
+ };
133
+
134
+ this.eventSource.onerror = (error) => {
135
+ this.onError(error);
136
+ };
137
+
138
+ this.eventSource.onopen = () => {
139
+ this.onOpen();
140
+ };
141
+ }
142
+ }
143
+
144
+ // 关闭SSE连接
145
+ disconnectSSE() {
146
+ if (this.eventSource) {
147
+ this.eventSource.close();
148
+ this.eventSource = null;
149
+ }
150
+ }
151
+ }
152
+
153
+ export default AgentAssistantSDK;