UNPKG

@coze/uniapp-api

Version:

Official Coze UniApp SDK for seamless AI integration into your applications | 扣子官方 UniApp SDK,助您轻松集成 AI 能力到应用中

299 lines (298 loc) 11.3 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.BaseWsChatClient = void 0; const api_1 = require("@coze/api"); const pcm_stream_player_1 = __importDefault(require("../pcm-stream-player")); const api_2 = require("../../api"); const event_names_1 = require("./event-names"); /** * Base class for WebSocket-based chat client for WeChat Mini Program */ class BaseWsChatClient { constructor(config) { var _a; Object.defineProperty(this, "ws", { enumerable: true, configurable: true, writable: true, value: null }); Object.defineProperty(this, "listeners", { enumerable: true, configurable: true, writable: true, value: new Map() }); Object.defineProperty(this, "wavStreamPlayer", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "trackId", { enumerable: true, configurable: true, writable: true, value: 'default' }); Object.defineProperty(this, "api", { enumerable: true, configurable: true, writable: true, value: void 0 }); Object.defineProperty(this, "audioDeltaList", { enumerable: true, configurable: true, writable: true, value: [] }); Object.defineProperty(this, "config", { enumerable: true, configurable: true, writable: true, value: void 0 }); /** * Handle incoming audio messages from the server */ Object.defineProperty(this, "handleAudioMessage", { enumerable: true, configurable: true, writable: true, value: () => { if (this.audioDeltaList.length === 0) { return; } const message = this.audioDeltaList[0]; try { this.wavStreamPlayer.addBase64PCM(message, this.trackId); this.audioDeltaList.shift(); if (this.audioDeltaList.length > 0) { this.handleAudioMessage(); } } catch (error) { this.warn('wavStreamPlayer error', error); } } }); this.api = new api_2.CozeAPI(Object.assign(Object.assign({ baseWsURL: api_1.COZE_CN_BASE_WS_URL }, config), { debug: false })); this.config = config; this.wavStreamPlayer = new pcm_stream_player_1.default({ sampleRate: 8000, defaultFormat: 'g711a', volume: (_a = this.config.playbackVolumeDefault) !== null && _a !== void 0 ? _a : 1.0, }); } /** * Initialize WebSocket connection and setup event handlers * @returns {Promise<WebSocketAPI>} The WebSocket API instance */ init() { return __awaiter(this, void 0, void 0, function* () { if (this.ws) { return this.ws; } const ws = yield this.api.websockets.chat.create({ bot_id: this.config.botId, workflow_id: this.config.workflowId, }, this.config.websocketOptions); this.ws = ws; // 标记 websocket 是否已 resolve or reject let isResolved = false; this.trackId = `my-track-id-${Date.now()}`; return new Promise((resolve, reject) => { ws.onopen = () => { this.log('ws open'); }; ws.onmessage = data => { // Trigger all registered event listeners this.emit(`server.${data.event_type}`, data); switch (data.event_type) { case api_1.WebsocketsEventType.ERROR: this.closeWs(); if (isResolved) { return; } isResolved = true; reject(new api_1.APIError(data.data.code, { code: data.data.code, msg: data.data.msg, detail: data.detail, }, undefined, undefined)); return; case api_1.WebsocketsEventType.CHAT_CREATED: resolve(ws); isResolved = true; break; case api_1.WebsocketsEventType.CONVERSATION_AUDIO_DELTA: this.audioDeltaList.push(data.data.content); if (this.audioDeltaList.length === 1) { this.handleAudioMessage(); } break; case api_1.WebsocketsEventType.INPUT_AUDIO_BUFFER_SPEECH_STARTED: this.clear(); break; case api_1.WebsocketsEventType.CONVERSATION_AUDIO_COMPLETED: // this.closeWs(); break; case api_1.WebsocketsEventType.CONVERSATION_CHAT_CANCELED: this.clear(); break; default: break; } }; ws.onerror = (error, event) => { this.warn('ws error', error, event); this.emit(`server.${api_1.WebsocketsEventType.ERROR}`, error); this.closeWs(); if (isResolved) { return; } isResolved = true; reject(new api_1.APIError(error.data.code, error, error.data.msg, undefined)); }; ws.onclose = () => { this.log('ws close'); }; }); }); } /** * Send a message to the chat server * @param {CreateChatWsReq} data - The message data to send */ sendMessage(data) { var _a; (_a = this.ws) === null || _a === void 0 ? void 0 : _a.send(data); this.log('sendMessage', data); } /** * Send a text message to the chat server * @param {string} text - The text message to send */ sendTextMessage(text) { this.sendMessage({ id: Date.now().toString(), event_type: api_1.WebsocketsEventType.CONVERSATION_MESSAGE_CREATE, data: { role: api_1.RoleType.User, content_type: 'text', content: text, }, }); } /** * Add event listener(s) * @param {string | string[]} event - Event name or array of event names * @param {WsChatCallbackHandler} callback - Event callback function */ on(event, callback) { const events = Array.isArray(event) ? event : [event]; events.forEach(eventName => { var _a; if (!this.listeners.has(eventName)) { this.listeners.set(eventName, new Set()); } (_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.add(callback); this.log('on', eventName); }); } /** * Remove event listener(s) * @param {string | string[]} event - Event name or array of event names * @param {WsChatCallbackHandler} callback - Event callback function to remove */ off(event, callback) { const events = Array.isArray(event) ? event : [event]; events.forEach(eventName => { var _a; (_a = this.listeners.get(eventName)) === null || _a === void 0 ? void 0 : _a.delete(callback); }); } /** * Close the WebSocket connection */ closeWs() { var _a, _b; if (((_a = this.ws) === null || _a === void 0 ? void 0 : _a.readyState) === 1) { (_b = this.ws) === null || _b === void 0 ? void 0 : _b.close(); } this.ws = null; } /** * Clear audio buffers and interrupt current playback */ clear() { this.log('clear'); this.audioDeltaList.length = 0; this.wavStreamPlayer.interrupt(); this.trackId = `my-track-id-${Date.now()}`; } /** * Set playback volume level * @param {number} volume - Volume level from 0.0 (muted) to 1.0 (full volume) */ setPlaybackVolume(volume) { this.wavStreamPlayer.setVolume(volume); } /** * Get current playback volume level * @returns {number} Current volume level from 0.0 (muted) to 1.0 (full volume) */ getPlaybackVolume() { return this.wavStreamPlayer.getVolume(); } /** * Emit an event to all registered listeners * @param {string} eventName - The name of the event * @param {WsChatEventData} event - The event data */ emit(eventName, event) { var _a, _b; (_a = this.listeners .get(eventName)) === null || _a === void 0 ? void 0 : _a.forEach(callback => callback(eventName, event)); (_b = this.listeners .get(event_names_1.WsChatEventNames.ALL)) === null || _b === void 0 ? void 0 : _b.forEach(callback => callback(eventName, event)); this.log('dispatch', eventName, event); } /** * Log a message if debug is enabled * @param {...any} args - The arguments to log */ // eslint-disable-next-line @typescript-eslint/no-explicit-any log(...args) { if (this.config.debug) { console.log('[WsChatClient]', ...args); } return true; } /** * Log a warning message if debug is enabled * @param {...any} args - The arguments to log */ // eslint-disable-next-line @typescript-eslint/no-explicit-any warn(...args) { if (this.config.debug) { console.warn('[WsChatClient]', ...args); } return true; } } exports.BaseWsChatClient = BaseWsChatClient; exports.default = BaseWsChatClient;