@coze/realtime-api 1.0.3 → 1.0.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/README.md CHANGED
@@ -6,6 +6,8 @@
6
6
  [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
7
  [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/coze-dev/coze-js/pulls)
8
8
 
9
+ English | [简体中文](./README.zh-CN.md)
10
+
9
11
  A powerful real-time communication SDK for voice interactions with Coze AI bots.
10
12
 
11
13
  ## Features
@@ -58,6 +60,10 @@ const client = new RealtimeClient({
58
60
  audioMutedDefault: false, // Optional: Initial audio state (default: false)
59
61
  suppressStationaryNoise: false, // Optional: Enable stationary noise suppression(default: false)
60
62
  suppressNonStationaryNoise: false, // Optional: Enable non-stationary noise suppression(default: false)
63
+ videoConfig: { // Optional: Video configuration
64
+ videoOnDefault: true, // Optional: Whether to turn on video by default, defaults to true
65
+ renderDom: 'local-player' // Optional: The DOM element to render the video stream to
66
+ },
61
67
  });
62
68
 
63
69
  // Essential Setup
@@ -0,0 +1,104 @@
1
+ # Coze 实时语音 API
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@coze/realtime-api.svg)](https://www.npmjs.com/package/@coze/realtime-api)
4
+ [![npm downloads](https://img.shields.io/npm/dm/@coze/realtime-api.svg)](https://www.npmjs.com/package/@coze/realtime-api)
5
+ [![license](https://img.shields.io/npm/l/@coze/realtime-api.svg)](https://github.com/coze-dev/coze-js/blob/main/LICENSE)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-Ready-blue.svg)](https://www.typescriptlang.org/)
7
+ [![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/coze-dev/coze-js/pulls)
8
+
9
+ [English](./README.md) | 简体中文
10
+
11
+ 一个强大的实时语音 SDK,用于与 Coze AI Bot 进行语音交互。
12
+
13
+ ## 特性
14
+ 1. 精准的语音识别:利用大语言模型进行 ASR(自动语音识别),我们的系统提供上下文理解能力。它可以参考之前提到的术语,理解说话风格和引用,并在噪音、专业术语和中英混合语音等挑战性场景下提供更高的识别准确率。
15
+
16
+ 2. 强大的 AI 代理能力:作为 AI 代理开发平台,Coze 提供全面的代理功能,包括:
17
+ - 记忆系统(文件存储、数据库、变量)
18
+ - 知识集成(文本、表格、图像)
19
+ - 技能(插件、触发器)
20
+ - 工作流编排(任务流、图像处理流程)
21
+
22
+ 3. 低延迟:使用 RTC(实时通信)技术实现,最大限度地减少通信管道中的延迟。
23
+
24
+ 4. 自然语音合成:使用由大语言模型驱动的高级 TTS(文本转语音)模型,我们的系统:
25
+ - 智能预测情感语境和语调
26
+ - 生成超自然、高保真、个性化的语音输出
27
+ - 在自然度、音质、韵律、呼吸模式和情感表达方面表现出色
28
+ - 无缝处理中英混合内容
29
+ - 提供类人的语气词和情感细微差别表达
30
+
31
+ ![api-overview](./assets/api-overview.png)
32
+
33
+ ## 安装
34
+
35
+ ```bash
36
+ npm install @coze/realtime-api
37
+ # 或
38
+ yarn add @coze/realtime-api
39
+ ```
40
+
41
+ ## 快速开始
42
+
43
+ ```ts
44
+ import { RealtimeClient, EventNames, RealtimeUtils } from "@coze/realtime-api";
45
+
46
+ // 初始化客户端
47
+ const client = new RealtimeClient({
48
+ baseURL: "https://api.coze.cn",
49
+ accessToken: "your_access_token",
50
+ // 或者
51
+ // accessToken: async () => {
52
+ // // 如果令牌过期则刷新
53
+ // return 'your_oauth_token';
54
+ // },
55
+ botId: "your_bot_id",
56
+ voiceId: "your_voice_id", // 可选:指定音色 ID
57
+ conversationId: "conversation_id", // 可选:用于对话连续性
58
+ debug: true, // 可选:启用调试日志
59
+ allowPersonalAccessTokenInBrowser: true, // 可选:在浏览器中启用 PAT 令牌使用
60
+ audioMutedDefault: false, // 可选:初始音频状态(默认:false)
61
+ suppressStationaryNoise: false, // 可选:启用静态噪声抑制(默认:false)
62
+ suppressNonStationaryNoise: false, // 可选:启用非静态噪声抑制(默认:false)
63
+ });
64
+
65
+ // 基本设置
66
+ async function initializeVoiceChat() {
67
+ // 1. 验证设备权限
68
+ const result = await RealtimeUtils.checkDevicePermission();
69
+ if (!result.audio) {
70
+ throw new Error("需要麦克风访问权限");
71
+ }
72
+
73
+ // 2. 建立连接
74
+ await client.connect();
75
+ }
76
+
77
+ // 核心操作
78
+ const operations = {
79
+ disconnect: () => client.disconnect(),
80
+ interrupt: () => client.interrupt(),
81
+ toggleMicrophone: (enabled: boolean) => client.setAudioEnable(enabled),
82
+ checkConnection: () => client.isConnected
83
+ };
84
+
85
+ // 事件处理
86
+ function setupEventListeners() {
87
+ // 监听所有事件
88
+ client.on(EventNames.EventNames, console.log);
89
+
90
+ // 仅客户端事件
91
+ client.on(EventNames.ALL_CLIENT, console.log);
92
+
93
+ // 仅服务器端事件
94
+ client.on(EventNames.ALL_SERVER, console.log);
95
+
96
+ // 特定事件处理
97
+ client.on(EventNames.CONNECTED, (event) => {
98
+ console.log("连接已建立:", event);
99
+ });
100
+ }
101
+ ```
102
+
103
+ ## 示例
104
+ 查看完整的示例,请参考我们的[实时语音控制台DEMO](../../examples/realtime-console)。
@@ -1,11 +1,11 @@
1
1
  /*! For license information please see index.cjs.LICENSE.txt */
2
2
  "use strict";
3
3
  var __webpack_modules__ = {
4
- "?c628": function() {
4
+ "?e272": function() {
5
5
  /* (ignored) */ },
6
- "?9452": function() {
6
+ "?5742": function() {
7
7
  /* (ignored) */ },
8
- "?e2b1": function() {
8
+ "?9caf": function() {
9
9
  /* (ignored) */ }
10
10
  };
11
11
  /************************************************************************/ // The module cache
@@ -80,7 +80,7 @@ __webpack_require__.d(common_utils_namespaceObject, {
80
80
  hasBrowserEnv: ()=>hasBrowserEnv,
81
81
  hasStandardBrowserEnv: ()=>hasStandardBrowserEnv,
82
82
  hasStandardBrowserWebWorkerEnv: ()=>hasStandardBrowserWebWorkerEnv,
83
- navigator: ()=>_navigator,
83
+ navigator: ()=>utils_navigator,
84
84
  origin: ()=>origin
85
85
  });
86
86
  // NAMESPACE OBJECT: ./src/utils.ts
@@ -90,6 +90,8 @@ __webpack_require__.d(src_utils_namespaceObject, {
90
90
  checkDevicePermission: ()=>checkDevicePermission,
91
91
  checkPermission: ()=>checkPermission,
92
92
  getAudioDevices: ()=>getAudioDevices,
93
+ isScreenShareDevice: ()=>isScreenShareDevice,
94
+ isScreenShareSupported: ()=>isScreenShareSupported,
93
95
  sleep: ()=>utils_sleep
94
96
  });
95
97
  function bind(fn, thisArg) {
@@ -1052,7 +1054,7 @@ class InterceptorManager_InterceptorManager {
1052
1054
  ]
1053
1055
  };
1054
1056
  const hasBrowserEnv = 'undefined' != typeof window && 'undefined' != typeof document;
1055
- const _navigator = 'object' == typeof navigator && navigator || void 0;
1057
+ const utils_navigator = 'object' == typeof navigator && navigator || void 0;
1056
1058
  /**
1057
1059
  * Determine if we're running in a standard browser environment
1058
1060
  *
@@ -1069,11 +1071,11 @@ const _navigator = 'object' == typeof navigator && navigator || void 0;
1069
1071
  * navigator.product -> 'NativeScript' or 'NS'
1070
1072
  *
1071
1073
  * @returns {boolean}
1072
- */ const hasStandardBrowserEnv = hasBrowserEnv && (!_navigator || [
1074
+ */ const hasStandardBrowserEnv = hasBrowserEnv && (!utils_navigator || [
1073
1075
  'ReactNative',
1074
1076
  'NativeScript',
1075
1077
  'NS'
1076
- ].indexOf(_navigator.product) < 0);
1078
+ ].indexOf(utils_navigator.product) < 0);
1077
1079
  /**
1078
1080
  * Determine if we're running in a standard browser webWorker environment
1079
1081
  *
@@ -2858,11 +2860,11 @@ axios.default = axios;
2858
2860
  // so that it can keep same with es module or cjs
2859
2861
  const { Axios: axios_Axios, AxiosError: axios_AxiosError, CanceledError: axios_CanceledError, isCancel: axios_isCancel, CancelToken: axios_CancelToken, VERSION: axios_VERSION, all: axios_all, Cancel, isAxiosError: axios_isAxiosError, spread: axios_spread, toFormData: axios_toFormData, AxiosHeaders: axios_AxiosHeaders, HttpStatusCode: axios_HttpStatusCode, formToJSON, getAdapter, mergeConfig: axios_mergeConfig } = lib_axios;
2860
2862
  // EXTERNAL MODULE: os (ignored)
2861
- var os_ignored_ = __webpack_require__("?e2b1");
2863
+ var os_ignored_ = __webpack_require__("?9caf");
2862
2864
  // EXTERNAL MODULE: crypto (ignored)
2863
- __webpack_require__("?c628");
2865
+ __webpack_require__("?e272");
2864
2866
  // EXTERNAL MODULE: jsonwebtoken (ignored)
2865
- __webpack_require__("?9452");
2867
+ __webpack_require__("?5742");
2866
2868
  class APIResource {
2867
2869
  constructor(client){
2868
2870
  this._client = client;
@@ -3662,9 +3664,9 @@ class documents_Documents extends APIResource {
3662
3664
  * @param params.page - Optional The page number for paginated queries. Default is 1. | 可选 分页查询时的页码。默认为 1。
3663
3665
  * @param params.page_size - Optional The size of pagination. Default is 10. | 可选 分页大小。默认为 10。
3664
3666
  * @returns ListDocumentData | 知识库文件列表
3665
- */ list(params, options) {
3667
+ */ async list(params, options) {
3666
3668
  const apiUrl = '/open_api/knowledge/document/list';
3667
- const response = this._client.get(apiUrl, params, false, esm_mergeConfig(options, {
3669
+ const response = await this._client.get(apiUrl, params, false, esm_mergeConfig(options, {
3668
3670
  headers: documents_documents_headers
3669
3671
  }));
3670
3672
  return response;
@@ -3713,9 +3715,104 @@ class documents_Documents extends APIResource {
3713
3715
  }));
3714
3716
  }
3715
3717
  }
3718
+ class Images extends APIResource {
3719
+ /**
3720
+ * Update the description of an image in the knowledge base | 更新知识库中的图片描述
3721
+ * @docs en: https://www.coze.com/docs/developer_guides/developer_guides/update_image_caption?_lang=en
3722
+ * @docs zh: https://www.coze.cn/docs/developer_guides/developer_guides/update_image_caption?_lang=zh
3723
+ * @param datasetId - The ID of the dataset | 必选 知识库 ID
3724
+ * @param documentId - The ID of the document | 必选 知识库文件 ID
3725
+ * @param params - The parameters for updating the image
3726
+ * @param params.caption - Required. The description of the image | 必选 图片的描述信息
3727
+ * @returns undefined
3728
+ */ // eslint-disable-next-line max-params
3729
+ async update(datasetId, documentId, params, options) {
3730
+ const apiUrl = `/v1/datasets/${datasetId}/images/${documentId}`;
3731
+ await this._client.put(apiUrl, params, false, options);
3732
+ }
3733
+ /**
3734
+ * List images in the knowledge base | 列出知识库中的图片
3735
+ * @docs en: https://www.coze.com/docs/developer_guides/developer_guides/get_images?_lang=en
3736
+ * @docs zh: https://www.coze.cn/docs/developer_guides/developer_guides/get_images?_lang=zh
3737
+ * @param datasetId - The ID of the dataset | 必选 知识库 ID
3738
+ * @param params - The parameters for listing images
3739
+ * @param params.page_num - Optional. Page number for pagination, minimum value is 1, defaults to 1 | 可选 分页查询时的页码。默认为 1。
3740
+ * @param params.page_size - Optional. Number of items per page, range 1-299, defaults to 10 | 可选 分页大小。默认为 10。
3741
+ * @param params.keyword - Optional. Search keyword for image descriptions | 可选 图片描述的搜索关键词。
3742
+ * @param params.has_caption - Optional. Filter for images with/without captions | 可选 是否过滤有/无描述的图片。
3743
+ */ async list(datasetId, params, options) {
3744
+ const apiUrl = `/v1/datasets/${datasetId}/images`;
3745
+ const response = await this._client.get(apiUrl, params, false, options);
3746
+ return response.data;
3747
+ }
3748
+ }
3716
3749
  class Datasets extends APIResource {
3750
+ /**
3751
+ * Creates a new dataset | 创建数据集
3752
+ * @docs en: https://www.coze.com/docs/developer_guides/create_dataset?_lang=en
3753
+ * @docs zh: https://www.coze.cn/docs/developer_guides/create_dataset?_lang=zh
3754
+ * @param params - The parameters for creating a dataset
3755
+ * @param {string} params.name - Required. Dataset name, maximum length of 100 characters | 必选 数据集名称,最大长度为 100 个字符
3756
+ * @param {string} params.space_id - Required. Space ID where the dataset belongs | 必选 数据集所属的空间 ID
3757
+ * @param {number} params.format_type - Required. Dataset type (0: Text type, 2: Image type) | 必选 数据集类型 (0: 文本类型, 2: 图片类型)
3758
+ * @param {string} [params.description] - Optional. Dataset description | 可选 数据集描述
3759
+ * @param {string} [params.file_id] - Optional. Dataset icon file ID from file upload
3760
+ */ async create(params, options) {
3761
+ const apiUrl = '/v1/datasets';
3762
+ const response = await this._client.post(apiUrl, params, false, options);
3763
+ return response.data;
3764
+ }
3765
+ /**
3766
+ * Lists all datasets in a space | 列出空间中的所有数据集
3767
+ * @docs en: https://www.coze.com/docs/developer_guides/list_dataset?_lang=en
3768
+ * @docs zh: https://www.coze.cn/docs/developer_guides/list_dataset?_lang=zh
3769
+ * @param params - The parameters for listing datasets | 列出数据集的参数
3770
+ * @param {string} params.space_id - Required. Space ID where the datasets belong | 必选 数据集所属的空间 ID
3771
+ * @param {string} [params.name] - Optional. Dataset name for fuzzy search | 可选 数据集名称用于模糊搜索
3772
+ * @param {number} [params.format_type] - Optional. Dataset type (0: Text type, 2: Image type) | 可选 数据集类型 (0: 文本类型, 2: 图片类型)
3773
+ * @param {number} [params.page_num] - Optional. Page number for pagination (default: 1) | 可选 分页查询时的页码。默认为 1。
3774
+ * @param {number} [params.page_size] - Optional. Number of items per page (default: 10) | 可选 分页大小。默认为 10。
3775
+ */ async list(params, options) {
3776
+ const apiUrl = '/v1/datasets';
3777
+ const response = await this._client.get(apiUrl, params, false, options);
3778
+ return response.data;
3779
+ }
3780
+ /**
3781
+ * Updates a dataset | 更新数据集
3782
+ * @docs en: https://www.coze.com/docs/developer_guides/update_dataset?_lang=en
3783
+ * @docs zh: https://www.coze.cn/docs/developer_guides/update_dataset?_lang=zh
3784
+ * @param dataset_id - Required. The ID of the dataset to update | 必选 数据集 ID
3785
+ * @param params - Required. The parameters for updating the dataset | 必选 更新数据集的参数
3786
+ * @param params.name - Required. Dataset name, maximum length of 100 characters. | 必选 数据集名称,最大长度为 100 个字符。
3787
+ * @param params.file_id - Optional. Dataset icon, should pass the file_id obtained from the file upload interface. | 可选 数据集图标,应传递从文件上传接口获取的 file_id。
3788
+ * @param params.description - Optional. Dataset description. | 可选 数据集描述。
3789
+ */ async update(dataset_id, params, options) {
3790
+ const apiUrl = `/v1/datasets/${dataset_id}`;
3791
+ await this._client.put(apiUrl, params, false, options);
3792
+ }
3793
+ /**
3794
+ * Deletes a dataset | 删除数据集
3795
+ * @docs en: https://www.coze.com/docs/developer_guides/delete_dataset?_lang=en
3796
+ * @docs zh: https://www.coze.cn/docs/developer_guides/delete_dataset?_lang=zh
3797
+ * @param dataset_id - Required. The ID of the dataset to delete | 必选 数据集 ID
3798
+ */ async delete(dataset_id, options) {
3799
+ const apiUrl = `/v1/datasets/${dataset_id}`;
3800
+ await this._client.delete(apiUrl, false, options);
3801
+ }
3802
+ /**
3803
+ * Views the progress of dataset upload | 查看数据集上传进度
3804
+ * @docs en: https://www.coze.com/docs/developer_guides/get_dataset_progress?_lang=en
3805
+ * @docs zh: https://www.coze.cn/docs/developer_guides/get_dataset_progress?_lang=zh
3806
+ * @param dataset_id - Required. The ID of the dataset to process | 必选 数据集 ID
3807
+ * @param params - Required. The parameters for processing the dataset | 必选 处理数据集的参数
3808
+ * @param params.dataset_ids - Required. List of dataset IDs | 必选 数据集 ID 列表
3809
+ */ async process(dataset_id, params, options) {
3810
+ const apiUrl = `/v1/datasets/${dataset_id}/process`;
3811
+ const response = await this._client.post(apiUrl, params, false, options);
3812
+ return response.data;
3813
+ }
3717
3814
  constructor(...args){
3718
- super(...args), this.documents = new documents_Documents(this._client);
3815
+ super(...args), this.documents = new documents_Documents(this._client), this.images = new Images(this._client);
3719
3816
  }
3720
3817
  }
3721
3818
  class Voices extends APIResource {
@@ -3772,7 +3869,10 @@ class Speech extends APIResource {
3772
3869
  * @returns Speech synthesis data
3773
3870
  */ async create(params, options) {
3774
3871
  const apiUrl = '/v1/audio/speech';
3775
- const response = await this._client.post(apiUrl, params, false, esm_mergeConfig(options, {
3872
+ const response = await this._client.post(apiUrl, {
3873
+ ...params,
3874
+ sample_rate: params.sample_rate || 24000
3875
+ }, false, esm_mergeConfig(options, {
3776
3876
  responseType: 'arraybuffer'
3777
3877
  }));
3778
3878
  return response;
@@ -3790,7 +3890,21 @@ class esm_Audio extends APIResource {
3790
3890
  super(...args), this.rooms = new Rooms(this._client), this.voices = new Voices(this._client), this.speech = new Speech(this._client);
3791
3891
  }
3792
3892
  }
3793
- var package_namespaceObject = JSON.parse('{"name":"@coze/api","version":"1.0.15","description":"Official Coze Node.js SDK for seamless AI integration into your applications | 扣子官方 Node.js SDK,助您轻松集成 AI 能力到应用中","keywords":["coze","ai","nodejs","sdk","chatbot","typescript"],"homepage":"https://github.com/coze-dev/coze-js/tree/main/packages/coze-js","bugs":{"url":"https://github.com/coze-dev/coze-js/issues"},"repository":{"type":"git","url":"https://github.com/coze-dev/coze-js.git","directory":"packages/coze-js"},"license":"MIT","author":"Leeight <leeight@gmail.com>","type":"module","exports":{".":{"require":"./dist/cjs/index.cjs","import":"./dist/esm/index.js","types":"./dist/types/index.d.ts"}},"main":"dist/cjs/index.cjs","module":"dist/esm/index.js","browser":{"crypto":false,"os":false,"jsonwebtoken":false},"types":"dist/types/index.d.ts","files":["dist","LICENSE","README.md","!**/*.tsbuildinfo"],"scripts":{"build":"rm -rf dist && rslib build","format":"prettier --write .","lint":"eslint ./ --cache --quiet","prepublishOnly":"npm run build","start":"rm -rf dist && rslib build -w","test":"vitest","test:cov":"vitest --coverage --run"},"dependencies":{"jsonwebtoken":"^9.0.2"},"devDependencies":{"@coze-infra/eslint-config":"workspace:*","@coze-infra/ts-config":"workspace:*","@coze-infra/vitest-config":"workspace:*","@rslib/core":"0.0.18","@swc/core":"^1.3.14","@types/jsonwebtoken":"^9.0.0","@types/node":"^20","@types/uuid":"^9.0.1","@types/whatwg-fetch":"^0.0.33","@vitest/coverage-v8":"~2.1.4","axios":"^1.7.7","typescript":"^5.5.3","vitest":"~2.1.4"},"peerDependencies":{"axios":"^1.7.1"}}'); // CONCATENATED MODULE: ./src/version.ts
3893
+ class Templates extends APIResource {
3894
+ /**
3895
+ * Duplicate a template. | 复制一个模板。
3896
+ * @param templateId - Required. The ID of the template to duplicate. | 要复制的模板的 ID。
3897
+ * @param params - Optional. The parameters for the duplicate operation. | 可选参数,用于复制操作。
3898
+ * @param params.workspace_id - Required. The ID of the workspace to duplicate the template into. | 要复制到的目标工作空间的 ID。
3899
+ * @param params.name - Optional. The name of the new template. | 新模板的名称。
3900
+ * @returns TemplateDuplicateRes | 复制模板结果
3901
+ */ async duplicate(templateId, params, options) {
3902
+ const apiUrl = `/v1/templates/${templateId}/duplicate`;
3903
+ const response = await this._client.post(apiUrl, params, false, options);
3904
+ return response.data;
3905
+ }
3906
+ }
3907
+ var package_namespaceObject = JSON.parse('{"name":"@coze/api","version":"1.0.16","description":"Official Coze Node.js SDK for seamless AI integration into your applications | 扣子官方 Node.js SDK,助您轻松集成 AI 能力到应用中","keywords":["coze","ai","nodejs","sdk","chatbot","typescript"],"homepage":"https://github.com/coze-dev/coze-js/tree/main/packages/coze-js","bugs":{"url":"https://github.com/coze-dev/coze-js/issues"},"repository":{"type":"git","url":"https://github.com/coze-dev/coze-js.git","directory":"packages/coze-js"},"license":"MIT","author":"Leeight <leeight@gmail.com>","type":"module","exports":{".":{"require":"./dist/cjs/index.cjs","import":"./dist/esm/index.js","types":"./dist/types/index.d.ts"}},"main":"dist/cjs/index.cjs","module":"dist/esm/index.js","browser":{"crypto":false,"os":false,"jsonwebtoken":false},"types":"dist/types/index.d.ts","files":["dist","LICENSE","README.md","README.zh-CN.md"],"scripts":{"build":"rm -rf dist && rslib build","format":"prettier --write .","lint":"eslint ./ --cache --quiet","start":"rm -rf dist && rslib build -w","test":"vitest","test:cov":"vitest --coverage --run"},"dependencies":{"jsonwebtoken":"^9.0.2"},"devDependencies":{"@coze-infra/eslint-config":"workspace:*","@coze-infra/ts-config":"workspace:*","@coze-infra/vitest-config":"workspace:*","@rslib/core":"0.0.18","@swc/core":"^1.3.14","@types/jsonwebtoken":"^9.0.0","@types/node":"^20","@types/uuid":"^9.0.1","@types/whatwg-fetch":"^0.0.33","@vitest/coverage-v8":"~2.1.4","axios":"^1.7.7","typescript":"^5.5.3","vitest":"~2.1.4"},"peerDependencies":{"axios":"^1.7.1"}}'); // CONCATENATED MODULE: ./src/version.ts
3794
3908
  const { version: esm_version } = package_namespaceObject;
3795
3909
  const getEnv = ()=>{
3796
3910
  const nodeVersion = process.version.slice(1); // Remove 'v' prefix
@@ -3840,6 +3954,55 @@ const getNodeClientUserAgent = ()=>{
3840
3954
  };
3841
3955
  return JSON.stringify(ua);
3842
3956
  };
3957
+ const getBrowserClientUserAgent = ()=>{
3958
+ const browserInfo = {
3959
+ name: 'unknown',
3960
+ version: 'unknown'
3961
+ };
3962
+ const osInfo = {
3963
+ name: 'unknown',
3964
+ version: 'unknown'
3965
+ };
3966
+ const { userAgent } = navigator;
3967
+ // 检测操作系统及版本
3968
+ if (userAgent.indexOf('Windows') > -1) {
3969
+ var _userAgent_match;
3970
+ osInfo.name = 'windows';
3971
+ const windowsVersion = (null === (_userAgent_match = userAgent.match(/Windows NT ([0-9.]+)/)) || void 0 === _userAgent_match ? void 0 : _userAgent_match[1]) || 'unknown';
3972
+ osInfo.version = windowsVersion;
3973
+ } else if (userAgent.indexOf('Mac OS X') > -1) {
3974
+ var _userAgent_match1;
3975
+ osInfo.name = 'macos';
3976
+ // 将 10_15_7 格式转换为 10.15.7
3977
+ osInfo.version = ((null === (_userAgent_match1 = userAgent.match(/Mac OS X ([0-9_]+)/)) || void 0 === _userAgent_match1 ? void 0 : _userAgent_match1[1]) || 'unknown').replace(/_/g, '.');
3978
+ } else if (userAgent.indexOf('Linux') > -1) {
3979
+ var _userAgent_match2;
3980
+ osInfo.name = 'linux';
3981
+ osInfo.version = (null === (_userAgent_match2 = userAgent.match(/Linux ([0-9.]+)/)) || void 0 === _userAgent_match2 ? void 0 : _userAgent_match2[1]) || 'unknown';
3982
+ }
3983
+ // 检测浏览器及版本
3984
+ if (userAgent.indexOf('Chrome') > -1) {
3985
+ var _userAgent_match3;
3986
+ browserInfo.name = 'chrome';
3987
+ browserInfo.version = (null === (_userAgent_match3 = userAgent.match(/Chrome\/([0-9.]+)/)) || void 0 === _userAgent_match3 ? void 0 : _userAgent_match3[1]) || 'unknown';
3988
+ } else if (userAgent.indexOf('Firefox') > -1) {
3989
+ var _userAgent_match4;
3990
+ browserInfo.name = 'firefox';
3991
+ browserInfo.version = (null === (_userAgent_match4 = userAgent.match(/Firefox\/([0-9.]+)/)) || void 0 === _userAgent_match4 ? void 0 : _userAgent_match4[1]) || 'unknown';
3992
+ } else if (userAgent.indexOf('Safari') > -1) {
3993
+ var _userAgent_match5;
3994
+ browserInfo.name = 'safari';
3995
+ browserInfo.version = (null === (_userAgent_match5 = userAgent.match(/Version\/([0-9.]+)/)) || void 0 === _userAgent_match5 ? void 0 : _userAgent_match5[1]) || 'unknown';
3996
+ }
3997
+ const ua = {
3998
+ version: esm_version,
3999
+ browser: browserInfo.name,
4000
+ browser_version: browserInfo.version,
4001
+ os_name: osInfo.name,
4002
+ os_version: osInfo.version
4003
+ };
4004
+ return JSON.stringify(ua);
4005
+ };
3843
4006
  /* eslint-disable @typescript-eslint/no-explicit-any */ const esm_handleError = (error)=>{
3844
4007
  if (!error.isAxiosError && (!error.code || !error.message)) return new CozeError(`Unexpected error: ${error.message}`);
3845
4008
  if ('ECONNABORTED' === error.code && error.message.includes('timeout') || 'ETIMEDOUT' === error.code) {
@@ -3937,7 +4100,8 @@ function isAxiosStatic(instance) {
3937
4100
  const headers = {
3938
4101
  authorization: `Bearer ${token}`
3939
4102
  };
3940
- if (!isBrowser()) {
4103
+ if (isBrowser()) headers['X-Coze-Client-User-Agent'] = getBrowserClientUserAgent();
4104
+ else {
3941
4105
  headers['User-Agent'] = getUserAgent();
3942
4106
  headers['X-Coze-Client-User-Agent'] = getNodeClientUserAgent();
3943
4107
  }
@@ -4029,7 +4193,7 @@ class CozeAPI extends APIClient {
4029
4193
  constructor(...args){
4030
4194
  super(...args), this.bots = new Bots(this), this.chat = new Chat(this), this.conversations = new Conversations(this), this.files = new Files(this), /**
4031
4195
  * @deprecated
4032
- */ this.knowledge = new Knowledge(this), this.datasets = new Datasets(this), this.workflows = new Workflows(this), this.workspaces = new WorkSpaces(this), this.audio = new esm_Audio(this);
4196
+ */ this.knowledge = new Knowledge(this), this.datasets = new Datasets(this), this.workflows = new Workflows(this), this.workspaces = new WorkSpaces(this), this.audio = new esm_Audio(this), this.templates = new Templates(this);
4033
4197
  }
4034
4198
  }
4035
4199
  /**
@@ -9261,7 +9425,7 @@ var setPrototypeOf = setPrototypeOf$2, _Object$setPrototypeOf = getDefaultExport
9261
9425
  }, stringPad = {
9262
9426
  start: createMethod(!1),
9263
9427
  end: createMethod(!0)
9264
- }, userAgent = engineUserAgent, stringPadWebkitBug = /Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(userAgent), $$F = _export, $padEnd = stringPad.end, WEBKIT_BUG$1 = stringPadWebkitBug;
9428
+ }, index_esm_min_userAgent = engineUserAgent, stringPadWebkitBug = /Version\/10(?:\.\d+){1,2}(?: [\w./]+)?(?: Mobile\/\w+)? Safari\//.test(index_esm_min_userAgent), $$F = _export, $padEnd = stringPad.end, WEBKIT_BUG$1 = stringPadWebkitBug;
9265
9429
  $$F({
9266
9430
  target: "String",
9267
9431
  proto: !0,
@@ -38434,7 +38598,11 @@ var VERTC = _createClass(function e() {
38434
38598
  return false;
38435
38599
  }
38436
38600
  };
38437
- const checkDevicePermission = async function() {
38601
+ /**
38602
+ * Checks device permissions for audio and video
38603
+ * @param checkVideo Whether to check video permissions (default: false)
38604
+ * @returns Promise that resolves with the device permission status
38605
+ */ const checkDevicePermission = async function() {
38438
38606
  let checkVideo = arguments.length > 0 && void 0 !== arguments[0] && arguments[0];
38439
38607
  return await index_esm_min_index.enableDevices({
38440
38608
  audio: true,
@@ -38447,7 +38615,16 @@ const checkDevicePermission = async function() {
38447
38615
  */ const getAudioDevices = async function() {
38448
38616
  let { video = false } = arguments.length > 0 && void 0 !== arguments[0] ? arguments[0] : {};
38449
38617
  let devices = [];
38450
- devices = video ? await index_esm_min_index.enumerateDevices() : await [
38618
+ if (video) {
38619
+ devices = await index_esm_min_index.enumerateDevices();
38620
+ if (isScreenShareSupported()) // @ts-expect-error - add screenShare device to devices
38621
+ devices.push({
38622
+ deviceId: 'screenShare',
38623
+ kind: 'videoinput',
38624
+ label: 'Screen Share',
38625
+ groupId: 'screenShare'
38626
+ });
38627
+ } else devices = await [
38451
38628
  ...await index_esm_min_index.enumerateAudioCaptureDevices(),
38452
38629
  ...await index_esm_min_index.enumerateAudioPlaybackDevices()
38453
38630
  ];
@@ -38462,6 +38639,14 @@ const checkDevicePermission = async function() {
38462
38639
  videoInputs: devices.filter((i)=>i.deviceId && 'videoinput' === i.kind)
38463
38640
  };
38464
38641
  };
38642
+ const isScreenShareDevice = (deviceId)=>'screenShare' === deviceId;
38643
+ /**
38644
+ * Check if browser supports screen sharing
38645
+ * 检查浏览器是否支持屏幕共享
38646
+ */ function isScreenShareSupported() {
38647
+ var _navigator_mediaDevices, _navigator;
38648
+ return !!(null === (_navigator = navigator) || void 0 === _navigator ? void 0 : null === (_navigator_mediaDevices = _navigator.mediaDevices) || void 0 === _navigator_mediaDevices ? void 0 : _navigator_mediaDevices.getDisplayMedia);
38649
+ }
38465
38650
  var error_RealtimeError = /*#__PURE__*/ function(RealtimeError) {
38466
38651
  RealtimeError["DEVICE_ACCESS_ERROR"] = "DEVICE_ACCESS_ERROR";
38467
38652
  RealtimeError["STREAM_CREATION_ERROR"] = "STREAM_CREATION_ERROR";
@@ -38555,6 +38740,10 @@ var event_handler_EventNames = /*#__PURE__*/ function(EventNames) {
38555
38740
  * zh: 音频输出设备改变
38556
38741
  */ EventNames["AUDIO_OUTPUT_DEVICE_CHANGED"] = "client.output.device.changed";
38557
38742
  /**
38743
+ * en: Video input device changed
38744
+ * zh: 视频输入设备改变
38745
+ */ EventNames["VIDEO_INPUT_DEVICE_CHANGED"] = "client.video.input.device.changed";
38746
+ /**
38558
38747
  * en: Bot joined
38559
38748
  * zh: Bot 加入
38560
38749
  */ EventNames["BOT_JOIN"] = "server.bot.join";
@@ -41972,23 +42161,47 @@ class EngineClient extends RealtimeEventHandler {
41972
42161
  if (-1 === devices.audioOutputs.findIndex((i)=>i.deviceId === deviceId)) throw new RealtimeAPIError(error_RealtimeError.DEVICE_ACCESS_ERROR, `Audio output device not found: ${deviceId}`);
41973
42162
  await this.engine.setAudioPlaybackDevice(deviceId);
41974
42163
  }
42164
+ async setVideoInputDevice(deviceId) {
42165
+ let isAutoCapture = !(arguments.length > 1) || void 0 === arguments[1] || arguments[1];
42166
+ var _this__videoConfig;
42167
+ const devices = await getAudioDevices({
42168
+ video: true
42169
+ });
42170
+ if (-1 === devices.videoInputs.findIndex((i)=>i.deviceId === deviceId)) throw new RealtimeAPIError(error_RealtimeError.DEVICE_ACCESS_ERROR, `Video input device not found: ${deviceId}`);
42171
+ await this.changeVideoState(false);
42172
+ if (isScreenShareDevice(deviceId)) {
42173
+ if (this._streamIndex === StreamIndex$1.STREAM_INDEX_MAIN) this.engine.setLocalVideoPlayer(StreamIndex$1.STREAM_INDEX_MAIN);
42174
+ if (isAutoCapture) {
42175
+ var _this__videoConfig1;
42176
+ this.engine.setVideoSourceType(StreamIndex$1.STREAM_INDEX_SCREEN, VideoSourceType.VIDEO_SOURCE_TYPE_INTERNAL);
42177
+ await this.engine.startScreenCapture(null === (_this__videoConfig1 = this._videoConfig) || void 0 === _this__videoConfig1 ? void 0 : _this__videoConfig1.screenConfig);
42178
+ await this.engine.publishScreen(MediaType$1.VIDEO);
42179
+ }
42180
+ this._streamIndex = StreamIndex$1.STREAM_INDEX_SCREEN;
42181
+ } else {
42182
+ if (this._streamIndex === StreamIndex$1.STREAM_INDEX_SCREEN) this.engine.setLocalVideoPlayer(StreamIndex$1.STREAM_INDEX_SCREEN);
42183
+ if (isAutoCapture) await this.engine.startVideoCapture(deviceId);
42184
+ this._streamIndex = StreamIndex$1.STREAM_INDEX_MAIN;
42185
+ }
42186
+ this.engine.setLocalVideoPlayer(this._streamIndex, {
42187
+ renderDom: (null === (_this__videoConfig = this._videoConfig) || void 0 === _this__videoConfig ? void 0 : _this__videoConfig.renderDom) || 'local-player',
42188
+ userId: this._roomUserId
42189
+ });
42190
+ }
41975
42191
  async createLocalStream(userId, videoConfig) {
42192
+ this._roomUserId = userId;
41976
42193
  const devices = await getAudioDevices({
41977
42194
  video: this._isSupportVideo
41978
42195
  });
41979
42196
  if (!devices.audioInputs.length) throw new RealtimeAPIError(error_RealtimeError.DEVICE_ACCESS_ERROR, 'Failed to get audio devices');
41980
42197
  if (this._isSupportVideo && !devices.videoInputs.length) throw new RealtimeAPIError(error_RealtimeError.DEVICE_ACCESS_ERROR, 'Failed to get video devices');
41981
42198
  await this.engine.startAudioCapture(devices.audioInputs[0].deviceId);
41982
- if (this._isSupportVideo && (null == videoConfig ? void 0 : videoConfig.videoOnDefault)) await this.engine.startVideoCapture(devices.videoInputs[0].deviceId);
41983
- if (this._isSupportVideo) this.engine.setLocalVideoPlayer(StreamIndex$1.STREAM_INDEX_MAIN, {
41984
- renderDom: (null == videoConfig ? void 0 : videoConfig.renderDom) || 'local-player',
41985
- userId
41986
- });
42199
+ if (this._isSupportVideo) this.setVideoInputDevice((null == videoConfig ? void 0 : videoConfig.videoInputDeviceId) || devices.videoInputs[0].deviceId, null == videoConfig ? void 0 : videoConfig.videoOnDefault);
41987
42200
  }
41988
42201
  async disconnect() {
41989
42202
  try {
41990
- if (this._isSupportVideo) await this.engine.stopVideoCapture();
41991
- await this.engine.stopAudioCapture();
42203
+ if (this._isSupportVideo) await this.changeVideoState(false);
42204
+ await this.changeAudioState(false);
41992
42205
  await this.engine.unpublishStream(MediaType$1.AUDIO);
41993
42206
  await this.engine.leaveRoom();
41994
42207
  this.removeEventListener();
@@ -42008,8 +42221,19 @@ class EngineClient extends RealtimeEventHandler {
42008
42221
  }
42009
42222
  async changeVideoState(isVideoOn) {
42010
42223
  try {
42011
- if (isVideoOn) await this.engine.startVideoCapture();
42012
- else await this.engine.stopVideoCapture();
42224
+ if (isVideoOn) {
42225
+ if (this._streamIndex === StreamIndex$1.STREAM_INDEX_MAIN) await this.engine.startVideoCapture();
42226
+ else {
42227
+ var _this__videoConfig;
42228
+ this.engine.setVideoSourceType(StreamIndex$1.STREAM_INDEX_SCREEN, VideoSourceType.VIDEO_SOURCE_TYPE_INTERNAL);
42229
+ await this.engine.startScreenCapture(null === (_this__videoConfig = this._videoConfig) || void 0 === _this__videoConfig ? void 0 : _this__videoConfig.screenConfig);
42230
+ await this.engine.publishScreen(MediaType$1.VIDEO);
42231
+ }
42232
+ } else if (this._streamIndex === StreamIndex$1.STREAM_INDEX_MAIN) await this.engine.stopVideoCapture();
42233
+ else {
42234
+ await this.engine.stopScreenCapture();
42235
+ await this.engine.unpublishScreen(MediaType$1.VIDEO);
42236
+ }
42013
42237
  } catch (e) {
42014
42238
  this.dispatch(event_handler_EventNames.ERROR, e);
42015
42239
  throw e;
@@ -42087,7 +42311,7 @@ class EngineClient extends RealtimeEventHandler {
42087
42311
  }
42088
42312
  }
42089
42313
  // eslint-disable-next-line max-params
42090
- constructor(appId, debug = false, isTestEnv = false, isSupportVideo = false){
42314
+ constructor(appId, debug = false, isTestEnv = false, isSupportVideo = false, videoConfig){
42091
42315
  super(debug), this.joinUserId = '', this._AIAnsExtension = null, this._isSupportVideo = false;
42092
42316
  if (isTestEnv) index_esm_min_index.setParameter('ICE_CONFIG_REQUEST_URLS', [
42093
42317
  'rtc-test.bytedance.com'
@@ -42102,6 +42326,7 @@ class EngineClient extends RealtimeEventHandler {
42102
42326
  this.handleLocalAudioPropertiesReport = this.handleLocalAudioPropertiesReport.bind(this);
42103
42327
  this.handleRemoteAudioPropertiesReport = this.handleRemoteAudioPropertiesReport.bind(this);
42104
42328
  this._isSupportVideo = isSupportVideo;
42329
+ this._videoConfig = videoConfig;
42105
42330
  }
42106
42331
  }
42107
42332
  class RealtimeClient extends RealtimeEventHandler {
@@ -42126,7 +42351,7 @@ class RealtimeClient extends RealtimeEventHandler {
42126
42351
  throw new RealtimeAPIError(error_RealtimeError.CREATE_ROOM_ERROR, error instanceof Error ? error.message : 'Unknown error', error);
42127
42352
  }
42128
42353
  // Step2 create engine
42129
- this._client = new EngineClient(roomInfo.app_id, this._config.debug, this._isTestEnv, this._isSupportVideo);
42354
+ this._client = new EngineClient(roomInfo.app_id, this._config.debug, this._isTestEnv, this._isSupportVideo, this._config.videoConfig);
42130
42355
  // Step3 bind engine events
42131
42356
  this._client.bindEngineEvents();
42132
42357
  this._client.on(event_handler_EventNames.ALL, (eventName, data)=>{
@@ -42262,6 +42487,13 @@ class RealtimeClient extends RealtimeEventHandler {
42262
42487
  deviceId
42263
42488
  });
42264
42489
  }
42490
+ async setVideoInputDevice(deviceId) {
42491
+ var _this__client;
42492
+ await (null === (_this__client = this._client) || void 0 === _this__client ? void 0 : _this__client.setVideoInputDevice(deviceId));
42493
+ this.dispatch(event_handler_EventNames.VIDEO_INPUT_DEVICE_CHANGED, {
42494
+ deviceId
42495
+ });
42496
+ }
42265
42497
  /**
42266
42498
  * Constructor for initializing a RealtimeClient instance.
42267
42499
  *
@@ -42292,6 +42524,16 @@ class RealtimeClient extends RealtimeEventHandler {
42292
42524
  * @param config.suppressNonStationaryNoise - Optional, suppress non-stationary noise, defaults to false. |
42293
42525
  * 可选,默认是否抑制非静态噪声,默认值为 false。
42294
42526
  * @param config.isAutoSubscribeAudio - Optional, whether to automatically subscribe to bot reply audio streams, defaults to true. |
42527
+ * @param config.videoConfig - Optional, Video configuration. |
42528
+ * 可选,视频配置。
42529
+ * @param config.videoConfig.videoOnDefault - Optional, Whether to turn on video by default, defaults to true. |
42530
+ * 可选,默认是否开启视频,默认值为 true。
42531
+ * @param config.videoConfig.renderDom - Optional, The DOM element to render the video stream to. |
42532
+ * 可选,渲染视频流的 DOM 元素。
42533
+ * @param config.videoConfig.videoInputDeviceId - Optional, The device ID of the video input device to use. |
42534
+ * 可选,视频输入设备的设备 ID。
42535
+ * @param config.videoConfig.screenConfig - Optional, Screen share configuration if videoInputDeviceId is 'screenShare' see https://www.volcengine.com/docs/6348/104481#screenconfig for more details. |
42536
+ * 可选,屏幕共享配置,如果 videoInputDeviceId 是 'screenShare',请参考 https://www.volcengine.com/docs/6348/104481#screenconfig 了解更多详情。
42295
42537
  */ constructor(config){
42296
42538
  super(config.debug), this._client = null, this.isConnected = false, this._isTestEnv = false, this._isSupportVideo = false;
42297
42539
  this._config = config;