fmode-ng 0.0.113 → 0.0.115
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/LICENSE.md +8 -0
- package/README.md +37 -37
- package/esm2022/fmode-ng.mjs +10 -5
- package/esm2022/lib/aigc/agent/fm-agent-task/fm-agent-task.component.mjs +8 -92
- package/esm2022/lib/aigc/agent/index.mjs +10 -3
- package/esm2022/lib/aigc/avatar/avatar.module.mjs +10 -45
- package/esm2022/lib/aigc/avatar/comp-avatar-particle/avatar.role.mjs +10 -2
- package/esm2022/lib/aigc/avatar/comp-avatar-particle/comp-avatar-particle.component.mjs +10 -315
- package/esm2022/lib/aigc/avatar/comp-avatar-particle/index.mjs +10 -3
- package/esm2022/lib/aigc/avatar/comp-avatar-particle/role-points.class.mjs +10 -57
- package/esm2022/lib/aigc/avatar/comp-avatar-role-image/comp-avatar-role-image.component.mjs +10 -98
- package/esm2022/lib/aigc/avatar/comp-avatar-role-video/comp-avatar-role-video.component.mjs +10 -107
- package/esm2022/lib/aigc/avatar/comp-avatar-talk/comp-avatar-talk.component.mjs +10 -113
- package/esm2022/lib/aigc/avatar/index.mjs +10 -8
- package/esm2022/lib/aigc/avatar/interface-avatar-role.mjs +10 -2
- package/esm2022/lib/aigc/avatar/modal-chat-voice-input/modal-chat-voice-input.component.mjs +8 -164
- package/esm2022/lib/aigc/chat/chat-header-area/comp-header-area.component.mjs +10 -49
- package/esm2022/lib/aigc/chat/chat-header-area/index.mjs +10 -2
- package/esm2022/lib/aigc/chat/chat-list/chat-list.component.mjs +8 -155
- package/esm2022/lib/aigc/chat/chat-list/index.mjs +10 -2
- package/esm2022/lib/aigc/chat/chat-message-area/comp-message-area.component.mjs +10 -40
- package/esm2022/lib/aigc/chat/chat-message-area/index.mjs +10 -2
- package/esm2022/lib/aigc/chat/chat-message-card/comp-message-card.component.mjs +10 -140
- package/esm2022/lib/aigc/chat/chat-message-card/duration-str.pipe.mjs +10 -29
- package/esm2022/lib/aigc/chat/chat-message-card/index.mjs +10 -3
- package/esm2022/lib/aigc/chat/chat-modal-input/index.mjs +10 -3
- package/esm2022/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.mjs +8 -193
- package/esm2022/lib/aigc/chat/chat-modal-input/modal-input.component.mjs +10 -331
- package/esm2022/lib/aigc/chat/chat-panel/chat-panel.component.mjs +8 -249
- package/esm2022/lib/aigc/chat/comp-role-prompt/comp-role-prompt.component.mjs +10 -83
- package/esm2022/lib/aigc/chat/comp-role-prompt/index.mjs +10 -2
- package/esm2022/lib/aigc/chat/index.mjs +10 -8
- package/esm2022/lib/aigc/comp-markdown-preview/clipboard.service.mjs +10 -82
- package/esm2022/lib/aigc/comp-markdown-preview/markdown-parse.mjs +8 -367
- package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.component.mjs +10 -51
- package/esm2022/lib/aigc/comp-markdown-preview/markdown-preview.module.mjs +10 -24
- package/esm2022/lib/aigc/comp-markdown-preview/plugins/md-mathjax/index.mjs +10 -115
- package/esm2022/lib/aigc/index.mjs +10 -14
- package/esm2022/lib/aigc/service-fmai/fmai.service.mjs +10 -21
- package/esm2022/lib/aigc/service-fmai/service-chat/chat-class.mjs +10 -2
- package/esm2022/lib/aigc/service-fmai/service-chat/chat.service.mjs +8 -174
- package/esm2022/lib/aigc/service-fmai/service-chat/index.mjs +10 -7
- package/esm2022/lib/aigc/service-fmai/service-chat/mask-list.mjs +9 -194
- package/esm2022/lib/aigc/service-fmai/service-chat/pipes/chat-content.pipe.mjs +10 -27
- package/esm2022/lib/aigc/service-fmai/service-chat/pipes/hidexml.pipe.mjs +10 -27
- package/esm2022/lib/aigc/service-fmai/service-chat/utilnow.pipe.mjs +10 -68
- package/esm2022/lib/aigc/service-fmai/service-imagine/imagine-func.mjs +9 -162
- package/esm2022/lib/aigc/service-fmai/service-imagine/imagine-work.mjs +10 -68
- package/esm2022/lib/aigc/service-fmai/service-imagine/imagine.service.mjs +8 -313
- package/esm2022/lib/aigc/service-fmai/service-imagine/index.mjs +10 -4
- package/esm2022/lib/aigc/story/fm-office-viewer/fm-office-viewer.component.mjs +10 -62
- package/esm2022/lib/aigc/story/fm-story-card/fm-story-card.component.mjs +10 -87
- package/esm2022/lib/aigc/story/fm-story-list/fm-story-list.component.mjs +10 -345
- package/esm2022/lib/aigc/story/fm-story-list/story-preview.mjs +10 -81
- package/esm2022/lib/aigc/story/fm-story-loader/fm-story-loader.component.mjs +10 -152
- package/esm2022/lib/aigc/story/fm-story-splitter/fm-story-splitter.component.mjs +10 -42
- package/esm2022/lib/aigc/story/index.mjs +10 -6
- package/esm2022/lib/aigc/story/modal-chat-story/comp-chat-story-json/comp-chat-story-json.component.mjs +10 -47
- package/esm2022/lib/aigc/story/modal-chat-story/comp-diary-story/comp-diary-story.component.mjs +10 -95
- package/esm2022/lib/aigc/story/modal-chat-story/modal-chat-story.component.mjs +10 -253
- package/esm2022/lib/aigc/story/story.service.mjs +10 -35
- package/esm2022/lib/aigc/voice/fmode-voice.service.mjs +10 -636
- package/esm2022/lib/aigc/voice/index.mjs +10 -7
- package/esm2022/lib/aigc/voice/lib/audio/audio.player.mjs +10 -55
- package/esm2022/lib/aigc/voice/lib/audio/audio.streamer.mjs +10 -2
- package/esm2022/lib/aigc/voice/lib/audio/streamer.microsoft.mjs +10 -96
- package/esm2022/lib/aigc/voice/lib/audio/streamer.pcm.mjs +8 -177
- package/esm2022/lib/aigc/voice/lib/pcm2wav.mjs +10 -38
- package/esm2022/lib/aigc/voice/lib/recorder/extension-waveview.mjs +10 -215
- package/esm2022/lib/aigc/voice/lib/resample.mjs +10 -34
- package/esm2022/lib/aigc/voice/tts/fmode-tts-class.mjs +10 -189
- package/esm2022/lib/aigc/voice/tts/index.mjs +10 -5
- package/esm2022/lib/aigc/voice/tts/int-tts-provider.mjs +10 -2
- package/esm2022/lib/aigc/voice/tts/provider-doubao.mjs +8 -346
- package/esm2022/lib/code/fm-codemirror/fm-codemirror.component.mjs +8 -342
- package/esm2022/lib/code/index.mjs +10 -2
- package/esm2022/lib/core/agent/chat/completion/fmode-completion.mjs +8 -430
- package/esm2022/lib/core/agent/chat/completion/index.mjs +10 -2
- package/esm2022/lib/core/agent/chat/completion/int-gpt-chat-options.mjs +10 -2
- package/esm2022/lib/core/agent/chat/fmode-chat.mjs +8 -617
- package/esm2022/lib/core/agent/chat/index.mjs +10 -4
- package/esm2022/lib/core/agent/chat/interface.mjs +10 -2
- package/esm2022/lib/core/agent/index.mjs +10 -6
- package/esm2022/lib/core/agent/prompt/agent.prompt.mjs +10 -133
- package/esm2022/lib/core/agent/prompt/index.mjs +10 -2
- package/esm2022/lib/core/agent/prompt/prompt-util.mjs +10 -16
- package/esm2022/lib/core/agent/story/agent.story.mjs +10 -64
- package/esm2022/lib/core/agent/story/index.mjs +10 -2
- package/esm2022/lib/core/agent/task/agent.task.mjs +10 -90
- package/esm2022/lib/core/agent/task/index.mjs +10 -2
- package/esm2022/lib/core/agent/waiting/index.mjs +10 -3
- package/esm2022/lib/core/agent/waiting/loading/loading.ctrl.mjs +10 -279
- package/esm2022/lib/core/agent/waiting/tips/tips.ctrl.mjs +8 -190
- package/esm2022/lib/core/index.mjs +10 -4
- package/esm2022/lib/core/parse/datatype/acl.mjs +10 -57
- package/esm2022/lib/core/parse/datatype/file.mjs +10 -69
- package/esm2022/lib/core/parse/datatype/geopoint.mjs +10 -57
- package/esm2022/lib/core/parse/datatype/relation.mjs +10 -56
- package/esm2022/lib/core/parse/fmode.cloud.mjs +10 -0
- package/esm2022/lib/core/parse/fmode.object.mjs +10 -232
- package/esm2022/lib/core/parse/fmode.parse.mjs +10 -84
- package/esm2022/lib/core/parse/fmode.query.mjs +8 -500
- package/esm2022/lib/core/parse/fmode.user.mjs +10 -275
- package/esm2022/lib/core/parse/index.mjs +10 -5
- package/esm2022/lib/core/parse/types.mjs +10 -2
- package/esm2022/lib/core/voice/index.mjs +10 -3
- package/esm2022/lib/core/voice/tts/index.mjs +10 -2
- package/esm2022/lib/icon/filetype/audio.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/avatar.svg.mjs +10 -14
- package/esm2022/lib/icon/filetype/chat.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/docx.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/file.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/filetype.pipe.mjs +10 -57
- package/esm2022/lib/icon/filetype/index.mjs +10 -12
- package/esm2022/lib/icon/filetype/md.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/pdf.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/pptx.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/svgtoblob.mjs +10 -8
- package/esm2022/lib/icon/filetype/video.svg.mjs +10 -3
- package/esm2022/lib/icon/filetype/xlsx.svg.mjs +10 -3
- package/esm2022/lib/icon/index.mjs +10 -2
- package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.component.mjs +10 -209
- package/esm2022/lib/map/comp-poi-picker/comp-poi-picker.module.mjs +10 -33
- package/esm2022/lib/map/index.mjs +10 -4
- package/esm2022/lib/map/map.module.mjs +10 -61
- package/esm2022/lib/map/page-loca-scatter/page-loca-scatter.component.mjs +10 -132
- package/esm2022/lib/map/page-map.start/page-map.start.component.mjs +8 -115
- package/esm2022/lib/map/page-plan-route/page-plan-route.component.mjs +8 -118
- package/esm2022/lib/nova-cloud/index.mjs +10 -3
- package/esm2022/lib/nova-cloud/ncloud-api-func.mjs +10 -91
- package/esm2022/lib/nova-cloud/nova-cloud.service.mjs +10 -53
- package/esm2022/lib/payment/index.mjs +10 -2
- package/esm2022/lib/payment/payment/payment.component.mjs +10 -543
- package/esm2022/lib/payment/payment.service.mjs +10 -202
- package/esm2022/lib/person/comp-person-gender-icon/comp-person-gender-icon.component.mjs +10 -48
- package/esm2022/lib/person/comp-person-item/comp-person-item.component.mjs +10 -29
- package/esm2022/lib/person/comp-person-story/comp-person-story.component.mjs +10 -211
- package/esm2022/lib/person/edit-upload/edit-upload.component.mjs +8 -412
- package/esm2022/lib/person/edit-upload/edit-upload.module.mjs +10 -50
- package/esm2022/lib/person/index.mjs +10 -5
- package/esm2022/lib/person/modal-person-select/modal-person-select.component.mjs +10 -144
- package/esm2022/lib/person/modal-user-verify/secret-text.pipe.mjs +10 -41
- package/esm2022/lib/person/modal-user-verify/user-verify.component.mjs +10 -595
- package/esm2022/lib/person/person-detail/person-detail.component.mjs +10 -172
- package/esm2022/lib/person/person.service.mjs +8 -193
- package/esm2022/lib/platform/cross.service.mjs +10 -62
- package/esm2022/lib/platform/index.mjs +10 -2
- package/esm2022/lib/social/index.mjs +10 -2
- package/esm2022/lib/social/wechat/wechat-jssdk.service.mjs +8 -230
- package/esm2022/lib/storage/comp-hwobs-manager/hwobs-manager.component.mjs +10 -59
- package/esm2022/lib/storage/index.mjs +10 -5
- package/esm2022/lib/storage/service-hwobs/hwobs.service.mjs +8 -131
- package/esm2022/lib/storage/service-hwobs/index.mjs +10 -3
- package/esm2022/lib/storage/service-hwobs/typings/esdk-obs-browser.mjs +1 -1
- package/esm2022/lib/storage/service-upload/index.mjs +10 -2
- package/esm2022/lib/storage/service-upload/nova-upload.service.mjs +8 -513
- package/esm2022/lib/storage/service-upload/util-file-md5.mjs +10 -28
- package/esm2022/lib/storage/service-upload/util-file-metadata.mjs +10 -93
- package/esm2022/lib/storage/storage.module.mjs +10 -42
- package/esm2022/lib/text/fm-article-editor/article-editor-topbar/article-editor-topbar.component.mjs +10 -72
- package/esm2022/lib/text/fm-article-editor/article.service.mjs +10 -237
- package/esm2022/lib/text/fm-article-editor/comp-upload-book-banners/comp-upload-book-banners.component.mjs +8 -72
- package/esm2022/lib/text/fm-article-editor/draft.service.mjs +10 -207
- package/esm2022/lib/text/fm-article-editor/fm-article-aitool/fm-article-aitool.component.mjs +8 -227
- package/esm2022/lib/text/fm-article-editor/fm-article-draft/fm-article-draft.component.mjs +10 -303
- package/esm2022/lib/text/fm-article-editor/fm-article-editor.component.mjs +8 -371
- package/esm2022/lib/text/fm-article-editor/fm-article-outline/fm-article-outline.component.mjs +10 -94
- package/esm2022/lib/text/fm-article-editor/fm-article-outline-leftitem/fm-article-outline-leftitem.component.mjs +10 -36
- package/esm2022/lib/text/fm-article-editor/fm-article-preview/fm-article-preview.component.mjs +10 -281
- package/esm2022/lib/text/fm-article-editor/fm-article-write-options/fm-article-write-options.component.mjs +10 -72
- package/esm2022/lib/text/fm-article-editor/outline-count.pipe.mjs +10 -22
- package/esm2022/lib/text/fm-article-editor/prompt/prompt-insertion-article.mjs +10 -169
- package/esm2022/lib/text/fm-article-editor/task-article-generation.mjs +10 -69
- package/esm2022/lib/text/fm-article-editor/tasks/task-article-draft-create.mjs +10 -65
- package/esm2022/lib/text/fm-article-editor/tasks/task-article-outline-edit.mjs +10 -55
- package/esm2022/lib/text/fm-article-editor/tasks/task-article-outline.mjs +10 -142
- package/esm2022/lib/text/fm-article-editor/tasks/task-article-preview.mjs +10 -35
- package/esm2022/lib/text/fm-article-editor/tasks/task-article-writing-options.mjs +10 -81
- package/esm2022/lib/text/fm-article-editor/tasks/task-document-select.mjs +10 -50
- package/esm2022/lib/text/fm-text-quill/fm-text-quill.component.mjs +10 -145
- package/esm2022/lib/text/index.mjs +10 -4
- package/esm2022/lib/user/account/account.service.mjs +10 -222
- package/esm2022/lib/user/captcha/captcha.component.mjs +10 -135
- package/esm2022/lib/user/comp-user-avatar/comp-user-avatar.component.mjs +10 -66
- package/esm2022/lib/user/index.mjs +10 -17
- package/esm2022/lib/user/login/auth.guard.mjs +10 -28
- package/esm2022/lib/user/login/auth.service.mjs +8 -433
- package/esm2022/lib/user/login/login.component.mjs +10 -916
- package/esm2022/lib/user/modal-user-login/modal-user-login.component.mjs +10 -311
- package/esm2022/lib/user/profile/auth-profile.guard.mjs +10 -27
- package/esm2022/lib/user/profile/auth-profile.service.mjs +10 -122
- package/esm2022/lib/user/profile/profile-bind/profile-bind.component.mjs +10 -164
- package/esm2022/lib/user/profile/profile-bind/profile-confirm-modal.component.mjs +10 -79
- package/esm2022/lib/user/profile/profile.module.mjs +10 -54
- package/esm2022/lib/user/staff/index.mjs +10 -4
- package/esm2022/lib/user/staff/staff.guard.mjs +10 -26
- package/esm2022/lib/user/staff/staff.module.mjs +10 -18
- package/esm2022/lib/user/staff/staff.service.mjs +10 -85
- package/esm2022/lib/user/user-name.pipe.mjs +10 -29
- package/esm2022/lib/user/user.module.mjs +10 -102
- package/esm2022/lib/video/fm-video/fm-video.component.mjs +10 -67
- package/esm2022/lib/video/index.mjs +10 -2
- package/esm2022/public-api.mjs +10 -21
- package/fesm2022/fmode-ng.mjs +7 -19788
- package/fesm2022/fmode-ng.mjs.map +1 -1
- package/lib/aigc/avatar/comp-avatar-role-image/comp-avatar-role-image.component.d.ts +2 -2
- package/lib/aigc/avatar/comp-avatar-role-video/comp-avatar-role-video.component.d.ts +2 -2
- package/lib/aigc/avatar/comp-avatar-talk/comp-avatar-talk.component.d.ts +2 -2
- package/lib/aigc/chat/chat-list/chat-list.component.d.ts +3 -2
- package/lib/aigc/chat/chat-message-card/comp-message-card.component.d.ts +3 -3
- package/lib/aigc/chat/chat-modal-input/modal-audio-message/modal-audio-message.component.d.ts +2 -2
- package/lib/aigc/chat/chat-modal-input/modal-input.component.d.ts +3 -3
- package/lib/aigc/service-fmai/service-imagine/imagine-func.d.ts +3 -3
- package/lib/aigc/service-fmai/service-imagine/imagine-work.d.ts +4 -4
- package/lib/aigc/service-fmai/service-imagine/imagine.service.d.ts +6 -6
- package/lib/aigc/story/fm-office-viewer/fm-office-viewer.component.d.ts +2 -2
- package/lib/aigc/story/fm-story-card/fm-story-card.component.d.ts +2 -1
- package/lib/aigc/story/fm-story-list/fm-story-list.component.d.ts +6 -6
- package/lib/aigc/story/fm-story-list/story-preview.d.ts +4 -4
- package/lib/aigc/story/fm-story-loader/fm-story-loader.component.d.ts +3 -3
- package/lib/aigc/story/fm-story-splitter/fm-story-splitter.component.d.ts +2 -2
- package/lib/aigc/story/modal-chat-story/comp-chat-story-json/comp-chat-story-json.component.d.ts +3 -2
- package/lib/aigc/story/modal-chat-story/comp-diary-story/comp-diary-story.component.d.ts +3 -2
- package/lib/aigc/story/modal-chat-story/modal-chat-story.component.d.ts +6 -6
- package/lib/aigc/story/story.service.d.ts +3 -2
- package/lib/aigc/voice/tts/fmode-tts-class.d.ts +2 -2
- package/lib/core/agent/chat/fmode-chat.d.ts +11 -11
- package/lib/core/agent/story/agent.story.d.ts +8 -8
- package/lib/core/parse/datatype/geopoint.d.ts +5 -1
- package/lib/core/parse/fmode.cloud.d.ts +32 -0
- package/lib/core/parse/fmode.object.d.ts +2 -2
- package/lib/core/parse/fmode.parse.d.ts +15 -9
- package/lib/core/parse/fmode.query.d.ts +41 -2
- package/lib/core/parse/fmode.user.d.ts +1 -0
- package/lib/core/parse/index.d.ts +1 -0
- package/lib/core/parse/types.d.ts +2 -0
- package/lib/map/comp-poi-picker/comp-poi-picker.component.d.ts +5 -5
- package/lib/payment/payment/payment.component.d.ts +3 -3
- package/lib/payment/payment.service.d.ts +4 -4
- package/lib/person/comp-person-gender-icon/comp-person-gender-icon.component.d.ts +2 -1
- package/lib/person/comp-person-item/comp-person-item.component.d.ts +2 -1
- package/lib/person/comp-person-story/comp-person-story.component.d.ts +13 -13
- package/lib/person/edit-upload/edit-upload.component.d.ts +1 -1
- package/lib/person/modal-person-select/modal-person-select.component.d.ts +5 -5
- package/lib/person/modal-user-verify/user-verify.component.d.ts +5 -5
- package/lib/person/person-detail/person-detail.component.d.ts +4 -4
- package/lib/person/person.service.d.ts +7 -7
- package/lib/storage/service-hwobs/hwobs.service.d.ts +4 -5
- package/lib/storage/service-upload/nova-upload.service.d.ts +5 -5
- package/lib/text/fm-article-editor/article-editor-topbar/article-editor-topbar.component.d.ts +2 -1
- package/lib/text/fm-article-editor/article.service.d.ts +12 -12
- package/lib/text/fm-article-editor/draft.service.d.ts +5 -5
- package/lib/text/fm-article-editor/fm-article-aitool/fm-article-aitool.component.d.ts +3 -2
- package/lib/text/fm-article-editor/fm-article-draft/fm-article-draft.component.d.ts +16 -17
- package/lib/text/fm-article-editor/fm-article-editor.component.d.ts +3 -3
- package/lib/text/fm-article-editor/fm-article-outline/fm-article-outline.component.d.ts +11 -10
- package/lib/text/fm-article-editor/fm-article-preview/fm-article-preview.component.d.ts +2 -2
- package/lib/text/fm-article-editor/prompt/prompt-insertion-article.d.ts +3 -3
- package/lib/text/fm-article-editor/task-article-generation.d.ts +5 -4
- package/lib/text/fm-article-editor/tasks/task-article-draft-create.d.ts +3 -3
- package/lib/text/fm-article-editor/tasks/task-article-outline-edit.d.ts +3 -3
- package/lib/text/fm-article-editor/tasks/task-article-outline.d.ts +3 -3
- package/lib/text/fm-article-editor/tasks/task-article-preview.d.ts +2 -1
- package/lib/text/fm-article-editor/tasks/task-article-writing-options.d.ts +3 -3
- package/lib/text/fm-article-editor/tasks/task-document-select.d.ts +3 -3
- package/lib/user/account/account.service.d.ts +2 -2
- package/lib/user/comp-user-avatar/comp-user-avatar.component.d.ts +2 -2
- package/lib/user/login/auth.service.d.ts +5 -5
- package/lib/user/login/login.component.d.ts +3 -3
- package/lib/user/profile/auth-profile.service.d.ts +8 -8
- package/lib/user/profile/profile-bind/profile-bind.component.d.ts +7 -7
- package/lib/user/profile/profile-bind/profile-confirm-modal.component.d.ts +2 -2
- package/lib/user/staff/staff.service.d.ts +3 -3
- package/lib/user/user-name.pipe.d.ts +2 -2
- package/package.json +12 -18
|
@@ -1,348 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
// 前端方案:
|
|
3
|
-
// TTS/ASR使用临时token https://bytedance.larkoffice.com/docx/C4DMdEooSo7s8gxuBvzcNvsonSh
|
|
4
|
-
// 浏览器前端JS方案 https://bytedance.larkoffice.com/docx/WZgsd0NTYo4Hiux6xbIcnml5noe
|
|
5
|
-
import pako from 'pako'; // GZIP压缩库
|
|
6
|
-
import { v4 as uuidv4 } from 'uuid';
|
|
7
|
-
/**
|
|
8
|
-
* ByteDance/Doubao TTS Provider Implementation (Optimized)
|
|
9
|
-
*/
|
|
10
|
-
export class FmodeTTSProviderDoubao {
|
|
11
|
-
constructor() {
|
|
12
|
-
this.ws = null;
|
|
13
|
-
this.audioChunks = [];
|
|
14
|
-
this.isSynthesizing = false;
|
|
15
|
-
this.isStarted = false;
|
|
16
|
-
}
|
|
17
|
-
initialize(config) {
|
|
18
|
-
// console.log("init st",config)
|
|
19
|
-
if (!config.appId || !config.accessToken) {
|
|
20
|
-
throw new Error("appId, accessToken are required for Doubao TTS");
|
|
21
|
-
}
|
|
22
|
-
config.cluster = config.cluster || "volcano_tts";
|
|
23
|
-
this.config = config;
|
|
24
|
-
this.audioStream = config.audioStream;
|
|
25
|
-
}
|
|
26
|
-
synthesize(textOrSSML, onResult, onError, onStart) {
|
|
27
|
-
if (this.isSynthesizing) {
|
|
28
|
-
this.stop();
|
|
29
|
-
}
|
|
30
|
-
this.isSynthesizing = true;
|
|
31
|
-
this.audioChunks = [];
|
|
32
|
-
this.eventMap?.onSpeakBefore?.();
|
|
33
|
-
// Extract plain text if SSML is provided
|
|
34
|
-
const isSSML = textOrSSML?.indexOf("<speak") > -1;
|
|
35
|
-
const text = isSSML ? this.extractTextFromSSML(textOrSSML) : textOrSSML;
|
|
36
|
-
// Connect to WebSocket
|
|
37
|
-
let reqid = uuidv4();
|
|
38
|
-
let token = this.config.stsToken;
|
|
39
|
-
// 构建带认证参数的 WebSocket URL
|
|
40
|
-
const wsUrl = buildFullUrl("wss://openspeech.bytedance.com/api/v1/tts/ws_binary", {
|
|
41
|
-
"api_jwt": token
|
|
42
|
-
});
|
|
43
|
-
// console.log(wsUrl)
|
|
44
|
-
this.ws = new WebSocket(wsUrl);
|
|
45
|
-
this.ws.binaryType = "arraybuffer";
|
|
46
|
-
this.ws.onopen = () => {
|
|
47
|
-
this.eventMap?.onStreamStarted?.();
|
|
48
|
-
// Prepare request payload
|
|
49
|
-
const request = {
|
|
50
|
-
app: {
|
|
51
|
-
appid: this.config.appId,
|
|
52
|
-
token: this.config.accessToken,
|
|
53
|
-
cluster: this.config.cluster,
|
|
54
|
-
},
|
|
55
|
-
user: {
|
|
56
|
-
uid: "user123" // Can be any unique identifier
|
|
57
|
-
},
|
|
58
|
-
audio: {
|
|
59
|
-
voice_type: this.voiceConfig?.voice || "zh_female_shuangkuaisisi_emo_v2_mars_bigtts", // Default voice, can be made configurable
|
|
60
|
-
encoding: "pcm", // Using PCM for streaming
|
|
61
|
-
rate: 24000, // Sample rate
|
|
62
|
-
speed_ratio: 1.0,
|
|
63
|
-
volume_ratio: 1.0,
|
|
64
|
-
pitch_ratio: 1.0,
|
|
65
|
-
language: "cn" // Default to Chinese
|
|
66
|
-
},
|
|
67
|
-
request: {
|
|
68
|
-
reqid: reqid,
|
|
69
|
-
text: text,
|
|
70
|
-
text_type: isSSML ? "ssml" : "plain",
|
|
71
|
-
operation: "submit" // For streaming
|
|
72
|
-
}
|
|
73
|
-
};
|
|
74
|
-
// Send the request
|
|
75
|
-
// console.log('tts req',request)
|
|
76
|
-
const binaryMsg = this.buildBinaryMessage(request);
|
|
77
|
-
this.ws?.send(binaryMsg);
|
|
78
|
-
};
|
|
79
|
-
this.ws.onmessage = async (event) => {
|
|
80
|
-
// console.log("data",event)
|
|
81
|
-
try {
|
|
82
|
-
if (event.data instanceof ArrayBuffer) {
|
|
83
|
-
const data = new Uint8Array(event.data);
|
|
84
|
-
// console.log("parseResponse")
|
|
85
|
-
// this.audioStream.write(data.buffer.slice(0)); // Error 有头部比特
|
|
86
|
-
const parsed = this.parseResponse(data, onStart);
|
|
87
|
-
if (parsed.error) {
|
|
88
|
-
onError(parsed.error);
|
|
89
|
-
this.stop();
|
|
90
|
-
return;
|
|
91
|
-
}
|
|
92
|
-
if (parsed.audio) {
|
|
93
|
-
this.audioChunks.push(parsed.audio);
|
|
94
|
-
// Stream the audio to the output
|
|
95
|
-
if (this.audioStream) {
|
|
96
|
-
// console.log("audioStream",parsed.audio)
|
|
97
|
-
// this.audioStream.write(parsed.audio);
|
|
98
|
-
}
|
|
99
|
-
}
|
|
100
|
-
if (parsed.isLast) {
|
|
101
|
-
this.eventMap?.onAudioCompleted?.();
|
|
102
|
-
// Combine all audio chunks
|
|
103
|
-
// 合并PCM并转换为WAV,同时获取计算出的时长
|
|
104
|
-
const { buffer: audioArrayBuffer, duration: calculatedDuration } = await this.mergePcmToWav(this.audioChunks);
|
|
105
|
-
// const audioBlob = new Blob(this.audioChunks, { type: 'audio/pcm' });
|
|
106
|
-
// const audioArrayBuffer = await this.blobToArrayBuffer(audioBlob);
|
|
107
|
-
onResult({
|
|
108
|
-
audioData: audioArrayBuffer,
|
|
109
|
-
audioDuration: parsed.duration || calculatedDuration || 0
|
|
110
|
-
});
|
|
111
|
-
this.stop();
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
else {
|
|
115
|
-
// Handle text message (shouldn't happen with binary protocol)
|
|
116
|
-
console.warn("Unexpected text message from TTS server:", event.data);
|
|
117
|
-
}
|
|
118
|
-
}
|
|
119
|
-
catch (err) {
|
|
120
|
-
onError(`Error processing TTS response: ${err}`);
|
|
121
|
-
this.stop();
|
|
122
|
-
}
|
|
123
|
-
};
|
|
124
|
-
this.ws.onerror = (error) => {
|
|
125
|
-
onError(`WebSocket error: ${JSON.stringify(error)}`);
|
|
126
|
-
this.stop();
|
|
127
|
-
};
|
|
128
|
-
this.ws.onclose = () => {
|
|
129
|
-
if (this.isSynthesizing) {
|
|
130
|
-
onError("WebSocket connection closed unexpectedly");
|
|
131
|
-
this.stop();
|
|
132
|
-
}
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
|
-
buildBinaryMessage(jsonPayload) {
|
|
136
|
-
// 1. 序列化JSON
|
|
137
|
-
const jsonStr = JSON.stringify(jsonPayload);
|
|
138
|
-
const jsonData = new TextEncoder().encode(jsonStr);
|
|
139
|
-
// 2. GZIP压缩
|
|
140
|
-
const compressed = pako.gzip(jsonData);
|
|
141
|
-
// 3. 创建缓冲区 (4字节头 + 4字节payload长度 + 压缩后的数据)
|
|
142
|
-
const buffer = new ArrayBuffer(4 + 4 + compressed.length);
|
|
143
|
-
const view = new DataView(buffer);
|
|
144
|
-
// 4. 写入协议头 (参考Go实现)
|
|
145
|
-
// 0x11 = 00010001 (protocolVersion=1, headerSize=1)
|
|
146
|
-
// 0x10 = 00010000 (messageType=1, flags=0)
|
|
147
|
-
// 0x11 = 00010001 (serialization=1, compression=1)
|
|
148
|
-
// 0x00 = 00000000 (reserved)
|
|
149
|
-
view.setUint8(0, 0x11); // protocolVersion + headerSize
|
|
150
|
-
view.setUint8(1, 0x10); // messageType + flags
|
|
151
|
-
view.setUint8(2, 0x11); // serialization + compression
|
|
152
|
-
view.setUint8(3, 0x00); // reserved
|
|
153
|
-
// 5. 写入payload长度 (大端序)
|
|
154
|
-
view.setUint32(4, compressed.length, false);
|
|
155
|
-
// 6. 写入压缩后的数据
|
|
156
|
-
const uint8View = new Uint8Array(buffer);
|
|
157
|
-
uint8View.set(compressed, 8);
|
|
158
|
-
return buffer;
|
|
159
|
-
}
|
|
160
|
-
parseResponse(data, onStart) {
|
|
161
|
-
const view = new DataView(data.buffer);
|
|
162
|
-
// 解析头部
|
|
163
|
-
const protocolVersion = data[0] >> 4;
|
|
164
|
-
const headerSize = data[0] & 0x0f;
|
|
165
|
-
const messageType = data[1] >> 4;
|
|
166
|
-
const messageTypeSpecificFlags = data[1] & 0x0f;
|
|
167
|
-
const serializationMethod = data[2] >> 4;
|
|
168
|
-
const messageCompression = data[2] & 0x0f;
|
|
169
|
-
const reserved = data[3];
|
|
170
|
-
// 跳过扩展头 (如果有)
|
|
171
|
-
const payloadOffset = headerSize * 4;
|
|
172
|
-
let payload = data.slice(payloadOffset);
|
|
173
|
-
// console.log("messageType",messageType)
|
|
174
|
-
// console.log("messageTypeSpecificFlags",messageTypeSpecificFlags)
|
|
175
|
-
// console.log("payload",payload)
|
|
176
|
-
// 处理不同类型的消息
|
|
177
|
-
if (messageType == 0xb) { // audio-only server response
|
|
178
|
-
if (messageTypeSpecificFlags === 0) {
|
|
179
|
-
// ACK消息,没有音频数据
|
|
180
|
-
return {};
|
|
181
|
-
}
|
|
182
|
-
else {
|
|
183
|
-
// 音频数据消息
|
|
184
|
-
const sequenceNumber = view.getInt32(payloadOffset, false);
|
|
185
|
-
const payloadSize = view.getInt32(payloadOffset + 4, false);
|
|
186
|
-
const audioData = payload.slice(8); // 0 8 测试
|
|
187
|
-
// playPCM(audioData.buffer.slice(0));
|
|
188
|
-
// console.log("playPCM 666",this.audioStream)
|
|
189
|
-
this.audioStream.write(audioData.buffer.slice(0));
|
|
190
|
-
if (!this.isStarted) {
|
|
191
|
-
onStart?.();
|
|
192
|
-
this.isStarted = true;
|
|
193
|
-
}
|
|
194
|
-
return {
|
|
195
|
-
audio: audioData.buffer,
|
|
196
|
-
isLast: sequenceNumber < 0
|
|
197
|
-
};
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
else if (messageType === 0xf) { // error message
|
|
201
|
-
const code = view.getInt32(payloadOffset, false);
|
|
202
|
-
const msgSize = view.getInt32(payloadOffset + 4, false);
|
|
203
|
-
let errorMsg = payload.slice(8);
|
|
204
|
-
if (messageCompression === 1) {
|
|
205
|
-
errorMsg = pako.ungzip(errorMsg);
|
|
206
|
-
}
|
|
207
|
-
return {
|
|
208
|
-
error: `TTS error (code ${code}): ${new TextDecoder().decode(errorMsg)}`
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
else if (messageType === 0xc) { // frontend server response
|
|
212
|
-
const msgSize = view.getInt32(payloadOffset, false);
|
|
213
|
-
let message = payload.slice(4);
|
|
214
|
-
if (messageCompression === 1) {
|
|
215
|
-
message = pako.ungzip(message);
|
|
216
|
-
}
|
|
217
|
-
// 可以解析返回的元数据,如duration等
|
|
218
|
-
try {
|
|
219
|
-
const meta = JSON.parse(new TextDecoder().decode(message));
|
|
220
|
-
return {
|
|
221
|
-
duration: meta.duration || 0
|
|
222
|
-
};
|
|
223
|
-
}
|
|
224
|
-
catch (err) {
|
|
225
|
-
console.warn("Failed to parse TTS metadata:", err);
|
|
226
|
-
return {};
|
|
227
|
-
}
|
|
228
|
-
}
|
|
229
|
-
else {
|
|
230
|
-
return {
|
|
231
|
-
error: `Unknown message type: ${messageType}`
|
|
232
|
-
};
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
stop() {
|
|
236
|
-
this.isSynthesizing = false;
|
|
237
|
-
if (this.ws) {
|
|
238
|
-
this.ws.close();
|
|
239
|
-
this.ws = null;
|
|
240
|
-
}
|
|
241
|
-
this.audioChunks = [];
|
|
242
|
-
}
|
|
243
|
-
dispose() {
|
|
244
|
-
this.stop();
|
|
245
|
-
}
|
|
246
|
-
extractTextFromSSML(ssml) {
|
|
247
|
-
// Simple SSML to text extraction - can be enhanced as needed
|
|
248
|
-
return ssml.replace(/<[^>]+>/g, '').trim();
|
|
249
|
-
}
|
|
250
|
-
async blobToArrayBuffer(blob) {
|
|
251
|
-
return new Promise((resolve, reject) => {
|
|
252
|
-
const reader = new FileReader();
|
|
253
|
-
reader.onload = () => resolve(reader.result);
|
|
254
|
-
reader.onerror = reject;
|
|
255
|
-
reader.readAsArrayBuffer(blob);
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
async mergePcmToWav(pcmChunks) {
|
|
259
|
-
// 1. 计算总长度和合并所有PCM数据
|
|
260
|
-
let totalLength = 0;
|
|
261
|
-
pcmChunks.forEach(chunk => {
|
|
262
|
-
totalLength += chunk.byteLength;
|
|
263
|
-
});
|
|
264
|
-
// 2. 计算音频时长 (假设是16位单声道PCM,采样率24000)
|
|
265
|
-
const sampleRate = 24000;
|
|
266
|
-
const numChannels = 1;
|
|
267
|
-
const bitsPerSample = 16;
|
|
268
|
-
const duration = 1000 * totalLength / (sampleRate * numChannels * bitsPerSample / 8);
|
|
269
|
-
// 3. 创建合并后的PCM数据缓冲区
|
|
270
|
-
const mergedPcm = new Uint8Array(totalLength);
|
|
271
|
-
let offset = 0;
|
|
272
|
-
pcmChunks.forEach(chunk => {
|
|
273
|
-
mergedPcm.set(new Uint8Array(chunk), offset);
|
|
274
|
-
offset += chunk.byteLength;
|
|
275
|
-
});
|
|
276
|
-
// 4. 创建WAV文件头
|
|
277
|
-
const wavHeader = this.createWavHeader({
|
|
278
|
-
sampleRate,
|
|
279
|
-
numChannels,
|
|
280
|
-
bitsPerSample,
|
|
281
|
-
pcmDataSize: totalLength
|
|
282
|
-
});
|
|
283
|
-
// 5. 合并WAV头和PCM数据
|
|
284
|
-
const wavBuffer = new Uint8Array(wavHeader.byteLength + mergedPcm.byteLength);
|
|
285
|
-
wavBuffer.set(new Uint8Array(wavHeader), 0);
|
|
286
|
-
wavBuffer.set(mergedPcm, wavHeader.byteLength);
|
|
287
|
-
return {
|
|
288
|
-
buffer: wavBuffer.buffer,
|
|
289
|
-
duration
|
|
290
|
-
};
|
|
291
|
-
}
|
|
1
|
+
|
|
292
2
|
/**
|
|
293
|
-
*
|
|
294
|
-
*
|
|
295
|
-
*
|
|
3
|
+
* @copyright © 未来飞马 © 未来全栈 www.fmode.cn
|
|
4
|
+
* 版权所有 © 未来飞马 © 江西脑控科技有限公司 Copyright © Fmode Technology Co., Ltd.
|
|
5
|
+
* 保留所有权利 All Rights Reserved.
|
|
6
|
+
* /home/ryan/workspace/nova/nova-admin/dist/fmode-ng/esm2022/lib/aigc/voice/tts/provider-doubao.mjs
|
|
296
7
|
*/
|
|
297
|
-
createWavHeader(
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
const blockAlign = numChannels * bitsPerSample / 8;
|
|
301
|
-
// WAV头固定44字节
|
|
302
|
-
const buffer = new ArrayBuffer(44);
|
|
303
|
-
const view = new DataView(buffer);
|
|
304
|
-
// RIFF标识
|
|
305
|
-
this.writeString(view, 0, 'RIFF');
|
|
306
|
-
// 文件总长度 (PCM数据长度 + 44 - 8)
|
|
307
|
-
view.setUint32(4, 36 + pcmDataSize, true);
|
|
308
|
-
// WAVE标识
|
|
309
|
-
this.writeString(view, 8, 'WAVE');
|
|
310
|
-
// fmt子块
|
|
311
|
-
this.writeString(view, 12, 'fmt ');
|
|
312
|
-
// fmt块长度 (16 for PCM)
|
|
313
|
-
view.setUint32(16, 16, true);
|
|
314
|
-
// 格式类型 (1 = PCM)
|
|
315
|
-
view.setUint16(20, 1, true);
|
|
316
|
-
// 声道数
|
|
317
|
-
view.setUint16(22, numChannels, true);
|
|
318
|
-
// 采样率
|
|
319
|
-
view.setUint32(24, sampleRate, true);
|
|
320
|
-
// 字节率
|
|
321
|
-
view.setUint32(28, byteRate, true);
|
|
322
|
-
// 块对齐
|
|
323
|
-
view.setUint16(32, blockAlign, true);
|
|
324
|
-
// 位深
|
|
325
|
-
view.setUint16(34, bitsPerSample, true);
|
|
326
|
-
// data标识
|
|
327
|
-
this.writeString(view, 36, 'data');
|
|
328
|
-
// data块长度
|
|
329
|
-
view.setUint32(40, pcmDataSize, true);
|
|
330
|
-
return buffer;
|
|
331
|
-
}
|
|
332
|
-
/**
|
|
333
|
-
* 向DataView写入字符串
|
|
334
|
-
*/
|
|
335
|
-
writeString(view, offset, str) {
|
|
336
|
-
for (let i = 0; i < str.length; i++) {
|
|
337
|
-
view.setUint8(offset + i, str.charCodeAt(i));
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
}
|
|
341
|
-
export function buildFullUrl(url, auth) {
|
|
342
|
-
const arr = [];
|
|
343
|
-
for (const key in auth) {
|
|
344
|
-
arr.push(`${key}=${encodeURIComponent(auth[key])}`);
|
|
345
|
-
}
|
|
346
|
-
return `${url}?${arr.join('&')}`;
|
|
347
|
-
}
|
|
348
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicHJvdmlkZXItZG91YmFvLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvZm1vZGUtbmcvc3JjL2xpYi9haWdjL3ZvaWNlL3R0cy9wcm92aWRlci1kb3ViYW8udHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsOENBQThDO0FBQzlDLFFBQVE7QUFDUixxRkFBcUY7QUFDckYsOEVBQThFO0FBTzlFLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQyxDQUFDLFVBQVU7QUFDbkMsT0FBTyxFQUFFLEVBQUUsSUFBSSxNQUFNLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFjcEM7O0dBRUc7QUFDSCxNQUFNLE9BQU8sc0JBQXNCO0lBUy9CO1FBUlEsT0FBRSxHQUFxQixJQUFJLENBQUM7UUFDNUIsZ0JBQVcsR0FBa0IsRUFBRSxDQUFDO1FBQ2hDLG1CQUFjLEdBQVksS0FBSyxDQUFDO1FBNkx4QyxjQUFTLEdBQVcsS0FBSyxDQUFDO0lBdkxYLENBQUM7SUFHaEIsVUFBVSxDQUFDLE1BS1Y7UUFDRyxnQ0FBZ0M7UUFDaEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLElBQUksQ0FBQyxNQUFNLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDdkMsTUFBTSxJQUFJLEtBQUssQ0FBQyxnREFBZ0QsQ0FBQyxDQUFDO1FBQ3RFLENBQUM7UUFDRCxNQUFNLENBQUMsT0FBTyxHQUFHLE1BQU0sQ0FBQyxPQUFPLElBQUksYUFBYSxDQUFDO1FBQ2pELElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxXQUFXLEdBQUcsTUFBTSxDQUFDLFdBQVcsQ0FBQztJQUMxQyxDQUFDO0lBRUQsVUFBVSxDQUNOLFVBQWtCLEVBQ2xCLFFBQTZFLEVBQzdFLE9BQWdDLEVBQ2hDLE9BQWdCO1FBRWhCLElBQUksSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQ3RCLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQztR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SUFDZixLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxHQUFHLElBQUksa0JBQWtCLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsQ0FBQyxDQUFDO0lBQ3RELENBQUM7SUFDRCxPQUFPLEdBQUcsR0FBRyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztBQUNuQyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLy8gaHR0cHM6Ly93d3cudm9sY2VuZ2luZS5jb20vZG9jcy82NTYxLzc5ODE3IFxyXG4vLyDliY3nq6/mlrnmoYjvvJpcclxuLy8gVFRTL0FTUuS9v+eUqOS4tOaXtnRva2VuIGh0dHBzOi8vYnl0ZWRhbmNlLmxhcmtvZmZpY2UuY29tL2RvY3gvQzRETWRFb29TbzdzOGd4dUJ2emNOdnNvblNoXHJcbi8vIOa1j+iniOWZqOWJjeerr0pT5pa55qGIIGh0dHBzOi8vYnl0ZWRhbmNlLmxhcmtvZmZpY2UuY29tL2RvY3gvV1pnc2QwTlRZbzRIaXV4NnhiSWNubWw1bm9lXHJcblxyXG4vLyDpn7PoibLliJfooajvvJpodHRwczovL3d3dy52b2xjZW5naW5lLmNvbS9kb2NzLzY1NjEvMTI1NzU0NFxyXG4vLyDnlJznvo7moYPlrZAgemhfZmVtYWxlX3RpYW5tZWl0YW96aV9tYXJzX2JpZ3R0c1xyXG4vLyDmmpbpmLPlpbPlo7AgemhfZmVtYWxlX2tlZnVudnNoZW5nX21hcnNfYmlndHRzIOS7heS4reaWh1xyXG5cclxuaW1wb3J0IHsgRm1vZGVUVFNQcm92aWRlciwgRm1vZGVUVFNFdmVudCB9IGZyb20gXCIuL2ludC10dHMtcHJvdmlkZXJcIjtcclxuaW1wb3J0IHBha28gZnJvbSAncGFrbyc7IC8vIEdaSVDljovnvKnlupNcclxuaW1wb3J0IHsgdjQgYXMgdXVpZHY0IH0gZnJvbSAndXVpZCc7XHJcbmltcG9ydCB7IFBDTVN0cmVhbWVyIH0gZnJvbSBcIi4uL2xpYi9hdWRpby9zdHJlYW1lci5wY21cIjtcclxuaW1wb3J0IHsgRm1vZGVDaGF0Vm9pY2VDb25maWcgfSBmcm9tIFwiLi4vLi4vLi4vY29yZS9hZ2VudC9jaGF0L2ludGVyZmFjZVwiO1xyXG5cclxuaW50ZXJmYWNlIFdzSGVhZGVyIHtcclxuICAgIHByb3RvY29sVmVyc2lvbjogbnVtYmVyOyAgLy8gNGJpdCAoMGIwMDAxKVxyXG4gICAgaGVhZGVyU2l6ZTogbnVtYmVyOyAgICAgIC8vIDRiaXQgKDBiMDAwMSA9IDTlrZfoioIpXHJcbiAgICBtZXNzYWdlVHlwZTogbnVtYmVyOyAgICAgLy8gNGJpdCAoMGIwMDAxID0g5a6i5oi356uv6K+35rGCKVxyXG4gICAgZmxhZ3M6IG51bWJlcjsgICAgICAgICAgIC8vIDRiaXQgKDBiMDAwMClcclxuICAgIHNlcmlhbGl6YXRpb246IG51bWJlcjsgICAvLyA0Yml0ICgwYjAwMDEgPSBKU09OKVxyXG4gICAgY29tcHJlc3Npb246IG51bWJlcjsgICAgIC8vIDRiaXQgKDBiMDAwMSA9IEdaSVApXHJcbiAgICByZXNlcnZlZDogbnVtYmVyOyAgICAgICAgLy8gOGJpdCAoMHgwMClcclxufVxyXG5cclxuLyoqXHJcbiAqIEJ5dGVEYW5jZS9Eb3ViYW8gVFRTIFByb3ZpZGVyIEltcGxlbWVudGF0aW9uIChPcHRpbWl6ZWQpXHJcbiAqL1xyXG5leHBvcnQgY2xhc3MgRm1vZGVUVFNQcm92aWRlckRvdWJhbyBpbXBsZW1lbnRzIEZtb2RlVFRTUHJvdmlkZXIge1xyXG4gICAgcHJpdmF0ZSB3czogV2ViU29ja2V0IHwgbnVsbCA9IG51bGw7XHJcbiAgICBwcml2YXRlIGF1ZGlvQ2h1bmtzOiBBcnJheUJ1ZmZlcltdID0gW107XHJcbiAgICBwcml2YXRlIGlzU3ludGhlc2l6aW5nOiBib29sZWFuID0gZmFsc2U7XHJcbiAgICBwcml2YXRlIGF1ZGlvU3RyZWFtOiBQQ01TdHJlYW1lcjtcclxuICAgIHZvaWNlQ29uZmlnOkZtb2RlQ2hhdFZvaWNlQ29uZmlnfHVuZGVmaW5lZFxyXG4gICAgXHJcbiAgICBldmVudE1hcD86IEZtb2RlVFRTRXZlbnQ7XHJcbiAgICBcclxuICAgIGNvbnN0cnVjdG9yKCkge31cclxuICAgIGNvbmZpZzogYW55O1xyXG5cclxuICAgIGluaXRpYWxpemUoY29uZmlnOiB7XHJcbiAgICAgICAgYXBwSWQ6IHN0cmluZyxcclxuICAgICAgICBhY2Nlc3NUb2tlbjogc3RyaW5nLFxyXG4gICAgICAgIGNsdXN0ZXI/OiBzdHJpbmcsXHJcbiAgICAgICAgYXVkaW9TdHJlYW0/OiBQQ01TdHJlYW1lclxyXG4gICAgfSk6IHZvaWQge1xyXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKFwiaW5pdCBzdFwiLGNvbmZpZylcclxuICAgICAgICBpZiAoIWNvbmZpZy5hcHBJZCB8fCAhY29uZmlnLmFjY2Vzc1Rva2VuKSB7XHJcbiAgICAgICAgICAgIHRocm93IG5ldyBFcnJvcihcImFwcElkLCBhY2Nlc3NUb2tlbiBhcmUgcmVxdWlyZWQgZm9yIERvdWJhbyBUVFNcIik7XHJcbiAgICAgICAgfVxyXG4gICAgICAgIGNvbmZpZy5jbHVzdGVyID0gY29uZmlnLmNsdXN0ZXIgfHwgXCJ2b2xjYW5vX3R0c1wiO1xyXG4gICAgICAgIHRoaXMuY29uZmlnID0gY29uZmlnO1xyXG4gICAgICAgIHRoaXMuYXVkaW9TdHJlYW0gPSBjb25maWcuYXVkaW9TdHJlYW07XHJcbiAgICB9XHJcblxyXG4gICAgc3ludGhlc2l6ZShcclxuICAgICAgICB0ZXh0T3JTU01MOiBzdHJpbmcsIFxyXG4gICAgICAgIG9uUmVzdWx0OiAocmVzdWx0OiB7IGF1ZGlvRGF0YTogQXJyYXlCdWZmZXIsIGF1ZGlvRHVyYXRpb246IG51bWJlciB9KSA9PiB2b2lkLCBcclxuICAgICAgICBvbkVycm9yOiAoZXJyb3I6IHN0cmluZykgPT4gdm9pZCxcclxuICAgICAgICBvblN0YXJ0OigpPT52b2lkXHJcbiAgICApOiB2b2lkIHtcclxuICAgICAgICBpZiAodGhpcy5pc1N5bnRoZXNpemluZykge1xyXG4gICAgICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgICAgICB9XHJcbiAgICAgICAgXHJcbiAgICAgICAgdGhpcy5pc1N5bnRoZXNpemluZyA9IHRydWU7XHJcbiAgICAgICAgdGhpcy5hdWRpb0NodW5rcyA9IFtdO1xyXG4gICAgICAgIHRoaXMuZXZlbnRNYXA/Lm9uU3BlYWtCZWZvcmU/LigpO1xyXG5cclxuICAgICAgICAvLyBFeHRyYWN0IHBsYWluIHRleHQgaWYgU1NNTCBpcyBwcm92aWRlZFxyXG4gICAgICAgIGNvbnN0IGlzU1NNTCA9IHRleHRPclNTTUw/LmluZGV4T2YoXCI8c3BlYWtcIikgPiAtMTtcclxuICAgICAgICBjb25zdCB0ZXh0ID0gaXNTU01MID8gdGhpcy5leHRyYWN0VGV4dEZyb21TU01MKHRleHRPclNTTUwpIDogdGV4dE9yU1NNTDtcclxuXHJcbiAgICAgICAgLy8gQ29ubmVjdCB0byBXZWJTb2NrZXRcclxuICAgICAgICBsZXQgcmVxaWQgPSB1dWlkdjQoKTtcclxuICAgICAgICBsZXQgdG9rZW4gPSB0aGlzLmNvbmZpZy5zdHNUb2tlblxyXG4gICAgICAgIC8vIOaehOW7uuW4puiupOivgeWPguaVsOeahCBXZWJTb2NrZXQgVVJMXHJcbiAgICAgICAgY29uc3Qgd3NVcmwgPSBidWlsZEZ1bGxVcmwoXCJ3c3M6Ly9vcGVuc3BlZWNoLmJ5dGVkYW5jZS5jb20vYXBpL3YxL3R0cy93c19iaW5hcnlcIix7XHJcbiAgICAgICAgICAgIFwiYXBpX2p3dFwiOnRva2VuXHJcbiAgICAgICAgfSk7XHJcbiAgICAgXHJcbiAgICAgICAgLy8gY29uc29sZS5sb2cod3NVcmwpXHJcbiAgICAgICAgdGhpcy53cyA9IG5ldyBXZWJTb2NrZXQod3NVcmwpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIHRoaXMud3MuYmluYXJ5VHlwZSA9IFwiYXJyYXlidWZmZXJcIjtcclxuICAgICAgICBcclxuICAgICAgICB0aGlzLndzLm9ub3BlbiA9ICgpID0+IHtcclxuICAgICAgICAgICAgdGhpcy5ldmVudE1hcD8ub25TdHJlYW1TdGFydGVkPy4oKTtcclxuICAgICAgICAgICAgXHJcbiAgICAgICAgICAgIC8vIFByZXBhcmUgcmVxdWVzdCBwYXlsb2FkXHJcbiAgICAgICAgICAgIGNvbnN0IHJlcXVlc3QgPSB7XHJcbiAgICAgICAgICAgICAgICBhcHA6IHtcclxuICAgICAgICAgICAgICAgICAgICBhcHBpZDogdGhpcy5jb25maWcuYXBwSWQsXHJcbiAgICAgICAgICAgICAgICAgICAgdG9rZW46IHRoaXMuY29uZmlnLmFjY2Vzc1Rva2VuLFxyXG4gICAgICAgICAgICAgICAgICAgIGNsdXN0ZXI6IHRoaXMuY29uZmlnLmNsdXN0ZXIsXHJcbiAgICAgICAgICAgICAgICB9LFxyXG4gICAgICAgICAgICAgICAgdXNlcjoge1xyXG4gICAgICAgICAgICAgICAgICAgIHVpZDogXCJ1c2VyMTIzXCIgLy8gQ2FuIGJlIGFueSB1bmlxdWUgaWRlbnRpZmllclxyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgIGF1ZGlvOiB7XHJcbiAgICAgICAgICAgICAgICAgICAgdm9pY2VfdHlwZTogdGhpcy52b2ljZUNvbmZpZz8udm9pY2UgfHwgXCJ6aF9mZW1hbGVfc2h1YW5na3VhaXNpc2lfZW1vX3YyX21hcnNfYmlndHRzXCIsIC8vIERlZmF1bHQgdm9pY2UsIGNhbiBiZSBtYWRlIGNvbmZpZ3VyYWJsZVxyXG4gICAgICAgICAgICAgICAgICAgIGVuY29kaW5nOiBcInBjbVwiLCAvLyBVc2luZyBQQ00gZm9yIHN0cmVhbWluZ1xyXG4gICAgICAgICAgICAgICAgICAgIHJhdGU6IDI0MDAwLCAvLyBTYW1wbGUgcmF0ZVxyXG4gICAgICAgICAgICAgICAgICAgIHNwZWVkX3JhdGlvOiAxLjAsXHJcbiAgICAgICAgICAgICAgICAgICAgdm9sdW1lX3JhdGlvOiAxLjAsXHJcbiAgICAgICAgICAgICAgICAgICAgcGl0Y2hfcmF0aW86IDEuMCxcclxuICAgICAgICAgICAgICAgICAgICBsYW5ndWFnZTogXCJjblwiIC8vIERlZmF1bHQgdG8gQ2hpbmVzZVxyXG4gICAgICAgICAgICAgICAgfSxcclxuICAgICAgICAgICAgICAgIHJlcXVlc3Q6IHtcclxuICAgICAgICAgICAgICAgICAgICByZXFpZDogcmVxaWQsXHJcbiAgICAgICAgICAgICAgICAgICAgdGV4dDogdGV4dCxcclxuICAgICAgICAgICAgICAgICAgICB0ZXh0X3R5cGU6IGlzU1NNTCA/IFwic3NtbFwiIDogXCJwbGFpblwiLFxyXG4gICAgICAgICAgICAgICAgICAgIG9wZXJhdGlvbjogXCJzdWJtaXRcIiAvLyBGb3Igc3RyZWFtaW5nXHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIH07XHJcblxyXG4gICAgICAgICAgICAvLyBTZW5kIHRoZSByZXF1ZXN0XHJcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKCd0dHMgcmVxJyxyZXF1ZXN0KVxyXG4gICAgICAgICAgICBjb25zdCBiaW5hcnlNc2cgPSB0aGlzLmJ1aWxkQmluYXJ5TWVzc2FnZShyZXF1ZXN0KTtcclxuICAgICAgICAgICAgdGhpcy53cz8uc2VuZChiaW5hcnlNc2cpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMud3Mub25tZXNzYWdlID0gYXN5bmMgKGV2ZW50KSA9PiB7XHJcbiAgICAgICAgICAgIC8vIGNvbnNvbGUubG9nKFwiZGF0YVwiLGV2ZW50KVxyXG4gICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgaWYgKGV2ZW50LmRhdGEgaW5zdGFuY2VvZiBBcnJheUJ1ZmZlcikge1xyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IGRhdGEgPSBuZXcgVWludDhBcnJheShldmVudC5kYXRhKTtcclxuICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcInBhcnNlUmVzcG9uc2VcIilcclxuICAgICAgICAgICAgICAgICAgICAvLyB0aGlzLmF1ZGlvU3RyZWFtLndyaXRlKGRhdGEuYnVmZmVyLnNsaWNlKDApKTsgLy8gRXJyb3Ig5pyJ5aS06YOo5q+U54m5XHJcblxyXG4gICAgICAgICAgICAgICAgICAgIGNvbnN0IHBhcnNlZCA9IHRoaXMucGFyc2VSZXNwb25zZShkYXRhLG9uU3RhcnQpO1xyXG4gICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChwYXJzZWQuZXJyb3IpIHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgb25FcnJvcihwYXJzZWQuZXJyb3IpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgcmV0dXJuO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICBpZiAocGFyc2VkLmF1ZGlvKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuYXVkaW9DaHVua3MucHVzaChwYXJzZWQuYXVkaW8pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gU3RyZWFtIHRoZSBhdWRpbyB0byB0aGUgb3V0cHV0XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGlmICh0aGlzLmF1ZGlvU3RyZWFtKSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgICAgICAvLyBjb25zb2xlLmxvZyhcImF1ZGlvU3RyZWFtXCIscGFyc2VkLmF1ZGlvKVxyXG4gICAgICAgICAgICAgICAgICAgICAgICAgICAgLy8gdGhpcy5hdWRpb1N0cmVhbS53cml0ZShwYXJzZWQuYXVkaW8pO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAgICAgICAgIGlmIChwYXJzZWQuaXNMYXN0KSB7XHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuZXZlbnRNYXA/Lm9uQXVkaW9Db21wbGV0ZWQ/LigpO1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gQ29tYmluZSBhbGwgYXVkaW8gY2h1bmtzXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIC8vIOWQiOW5tlBDTeW5tui9rOaNouS4uldBVu+8jOWQjOaXtuiOt+WPluiuoeeul+WHuueahOaXtumVv1xyXG4gICAgICAgICAgICAgICAgICAgICAgICBjb25zdCB7IGJ1ZmZlcjogYXVkaW9BcnJheUJ1ZmZlciwgZHVyYXRpb246IGNhbGN1bGF0ZWREdXJhdGlvbiB9ID0gXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMubWVyZ2VQY21Ub1dhdih0aGlzLmF1ZGlvQ2h1bmtzKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uc3QgYXVkaW9CbG9iID0gbmV3IEJsb2IodGhpcy5hdWRpb0NodW5rcywgeyB0eXBlOiAnYXVkaW8vcGNtJyB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgLy8gY29uc3QgYXVkaW9BcnJheUJ1ZmZlciA9IGF3YWl0IHRoaXMuYmxvYlRvQXJyYXlCdWZmZXIoYXVkaW9CbG9iKTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIG9uUmVzdWx0KHtcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvRGF0YTogYXVkaW9BcnJheUJ1ZmZlcixcclxuICAgICAgICAgICAgICAgICAgICAgICAgICAgIGF1ZGlvRHVyYXRpb246IHBhcnNlZC5kdXJhdGlvbiB8fCBjYWxjdWxhdGVkRHVyYXRpb24gfHwgMFxyXG4gICAgICAgICAgICAgICAgICAgICAgICB9KTtcclxuICAgICAgICAgICAgICAgICAgICAgICAgXHJcbiAgICAgICAgICAgICAgICAgICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgICAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAgICAgLy8gSGFuZGxlIHRleHQgbWVzc2FnZSAoc2hvdWxkbid0IGhhcHBlbiB3aXRoIGJpbmFyeSBwcm90b2NvbClcclxuICAgICAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJVbmV4cGVjdGVkIHRleHQgbWVzc2FnZSBmcm9tIFRUUyBzZXJ2ZXI6XCIsIGV2ZW50LmRhdGEpO1xyXG4gICAgICAgICAgICAgICAgfVxyXG4gICAgICAgICAgICB9IGNhdGNoIChlcnIpIHtcclxuICAgICAgICAgICAgICAgIG9uRXJyb3IoYEVycm9yIHByb2Nlc3NpbmcgVFRTIHJlc3BvbnNlOiAke2Vycn1gKTtcclxuICAgICAgICAgICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfTtcclxuXHJcbiAgICAgICAgdGhpcy53cy5vbmVycm9yID0gKGVycm9yKSA9PiB7XHJcbiAgICAgICAgICAgIG9uRXJyb3IoYFdlYlNvY2tldCBlcnJvcjogJHtKU09OLnN0cmluZ2lmeShlcnJvcil9YCk7XHJcbiAgICAgICAgICAgIHRoaXMuc3RvcCgpO1xyXG4gICAgICAgIH07XHJcblxyXG4gICAgICAgIHRoaXMud3Mub25jbG9zZSA9ICgpID0+IHtcclxuICAgICAgICAgICAgaWYgKHRoaXMuaXNTeW50aGVzaXppbmcpIHtcclxuICAgICAgICAgICAgICAgIG9uRXJyb3IoXCJXZWJTb2NrZXQgY29ubmVjdGlvbiBjbG9zZWQgdW5leHBlY3RlZGx5XCIpO1xyXG4gICAgICAgICAgICAgICAgdGhpcy5zdG9wKCk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICB9O1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYnVpbGRCaW5hcnlNZXNzYWdlKGpzb25QYXlsb2FkOiBvYmplY3QpOiBBcnJheUJ1ZmZlciB7XHJcbiAgICAgICAgLy8gMS4g5bqP5YiX5YyWSlNPTlxyXG4gICAgICAgIGNvbnN0IGpzb25TdHIgPSBKU09OLnN0cmluZ2lmeShqc29uUGF5bG9hZCk7XHJcbiAgICAgICAgY29uc3QganNvbkRhdGEgPSBuZXcgVGV4dEVuY29kZXIoKS5lbmNvZGUoanNvblN0cik7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gMi4gR1pJUOWOi+e8qVxyXG4gICAgICAgIGNvbnN0IGNvbXByZXNzZWQgPSBwYWtvLmd6aXAoanNvbkRhdGEpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIC8vIDMuIOWIm+W7uue8k+WGsuWMuiAoNOWtl+iKguWktCArIDTlrZfoioJwYXlsb2Fk6ZW/5bqmICsg5Y6L57yp5ZCO55qE5pWw5o2uKVxyXG4gICAgICAgIGNvbnN0IGJ1ZmZlciA9IG5ldyBBcnJheUJ1ZmZlcig0ICsgNCArIGNvbXByZXNzZWQubGVuZ3RoKTtcclxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGJ1ZmZlcik7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gNC4g5YaZ5YWl5Y2P6K6u5aS0ICjlj4LogINHb+WunueOsClcclxuICAgICAgICAvLyAweDExID0gMDAwMTAwMDEgKHByb3RvY29sVmVyc2lvbj0xLCBoZWFkZXJTaXplPTEpXHJcbiAgICAgICAgLy8gMHgxMCA9IDAwMDEwMDAwIChtZXNzYWdlVHlwZT0xLCBmbGFncz0wKVxyXG4gICAgICAgIC8vIDB4MTEgPSAwMDAxMDAwMSAoc2VyaWFsaXphdGlvbj0xLCBjb21wcmVzc2lvbj0xKVxyXG4gICAgICAgIC8vIDB4MDAgPSAwMDAwMDAwMCAocmVzZXJ2ZWQpXHJcbiAgICAgICAgdmlldy5zZXRVaW50OCgwLCAweDExKTsgLy8gcHJvdG9jb2xWZXJzaW9uICsgaGVhZGVyU2l6ZVxyXG4gICAgICAgIHZpZXcuc2V0VWludDgoMSwgMHgxMCk7IC8vIG1lc3NhZ2VUeXBlICsgZmxhZ3NcclxuICAgICAgICB2aWV3LnNldFVpbnQ4KDIsIDB4MTEpOyAvLyBzZXJpYWxpemF0aW9uICsgY29tcHJlc3Npb25cclxuICAgICAgICB2aWV3LnNldFVpbnQ4KDMsIDB4MDApOyAvLyByZXNlcnZlZFxyXG4gICAgICAgIFxyXG4gICAgICAgIC8vIDUuIOWGmeWFpXBheWxvYWTplb/luqYgKOWkp+err+W6jylcclxuICAgICAgICB2aWV3LnNldFVpbnQzMig0LCBjb21wcmVzc2VkLmxlbmd0aCwgZmFsc2UpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIC8vIDYuIOWGmeWFpeWOi+e8qeWQjueahOaVsOaNrlxyXG4gICAgICAgIGNvbnN0IHVpbnQ4VmlldyA9IG5ldyBVaW50OEFycmF5KGJ1ZmZlcik7XHJcbiAgICAgICAgdWludDhWaWV3LnNldChjb21wcmVzc2VkLCA4KTtcclxuICAgICAgICBcclxuICAgICAgICByZXR1cm4gYnVmZmVyO1xyXG4gICAgfVxyXG5cclxuICAgIGlzU3RhcnRlZDpib29sZWFuID0gZmFsc2U7XHJcbiAgICBwcml2YXRlIHBhcnNlUmVzcG9uc2UoZGF0YTogVWludDhBcnJheSxvblN0YXJ0OkZ1bmN0aW9uKToge1xyXG4gICAgICAgIGF1ZGlvPzogQXJyYXlCdWZmZXIsXHJcbiAgICAgICAgaXNMYXN0PzogYm9vbGVhbixcclxuICAgICAgICBkdXJhdGlvbj86IG51bWJlcixcclxuICAgICAgICBlcnJvcj86IHN0cmluZ1xyXG4gICAgfSB7XHJcbiAgICAgICAgY29uc3QgdmlldyA9IG5ldyBEYXRhVmlldyhkYXRhLmJ1ZmZlcik7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8g6Kej5p6Q5aS06YOoXHJcbiAgICAgICAgY29uc3QgcHJvdG9jb2xWZXJzaW9uID0gZGF0YVswXSA+PiA0O1xyXG4gICAgICAgIGNvbnN0IGhlYWRlclNpemUgPSBkYXRhWzBdICYgMHgwZjtcclxuICAgICAgICBjb25zdCBtZXNzYWdlVHlwZSA9IGRhdGFbMV0gPj4gNDtcclxuICAgICAgICBjb25zdCBtZXNzYWdlVHlwZVNwZWNpZmljRmxhZ3MgPSBkYXRhWzFdICYgMHgwZjtcclxuICAgICAgICBjb25zdCBzZXJpYWxpemF0aW9uTWV0aG9kID0gZGF0YVsyXSA+PiA0O1xyXG4gICAgICAgIGNvbnN0IG1lc3NhZ2VDb21wcmVzc2lvbiA9IGRhdGFbMl0gJiAweDBmO1xyXG4gICAgICAgIGNvbnN0IHJlc2VydmVkID0gZGF0YVszXTtcclxuICAgICAgICBcclxuICAgICAgICAvLyDot7Pov4fmianlsZXlpLQgKOWmguaenOaciSlcclxuICAgICAgICBjb25zdCBwYXlsb2FkT2Zmc2V0ID0gaGVhZGVyU2l6ZSAqIDQ7XHJcbiAgICAgICAgbGV0IHBheWxvYWQgPSBkYXRhLnNsaWNlKHBheWxvYWRPZmZzZXQpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIC8vIGNvbnNvbGUubG9nKFwibWVzc2FnZVR5cGVcIixtZXNzYWdlVHlwZSlcclxuICAgICAgICAvLyBjb25zb2xlLmxvZyhcIm1lc3NhZ2VUeXBlU3BlY2lmaWNGbGFnc1wiLG1lc3NhZ2VUeXBlU3BlY2lmaWNGbGFncylcclxuICAgICAgICAvLyBjb25zb2xlLmxvZyhcInBheWxvYWRcIixwYXlsb2FkKVxyXG4gICAgICAgIC8vIOWkhOeQhuS4jeWQjOexu+Wei+eahOa2iOaBr1xyXG4gICAgICAgIGlmIChtZXNzYWdlVHlwZSA9PSAweGIpIHsgLy8gYXVkaW8tb25seSBzZXJ2ZXIgcmVzcG9uc2VcclxuICAgICAgICAgICAgaWYgKG1lc3NhZ2VUeXBlU3BlY2lmaWNGbGFncyA9PT0gMCkge1xyXG4gICAgICAgICAgICAgICAgLy8gQUNL5raI5oGv77yM5rKh5pyJ6Z+z6aKR5pWw5o2uXHJcbiAgICAgICAgICAgICAgICByZXR1cm4ge307XHJcbiAgICAgICAgICAgIH0gZWxzZSB7XHJcbiAgICAgICAgICAgICAgICAvLyDpn7PpopHmlbDmja7mtojmga9cclxuICAgICAgICAgICAgICAgIGNvbnN0IHNlcXVlbmNlTnVtYmVyID0gdmlldy5nZXRJbnQzMihwYXlsb2FkT2Zmc2V0LCBmYWxzZSk7XHJcbiAgICAgICAgICAgICAgICBjb25zdCBwYXlsb2FkU2l6ZSA9IHZpZXcuZ2V0SW50MzIocGF5bG9hZE9mZnNldCArIDQsIGZhbHNlKTtcclxuICAgICAgICAgICAgICAgIGNvbnN0IGF1ZGlvRGF0YSA9IHBheWxvYWQuc2xpY2UoOCk7IC8vIDAgOCDmtYvor5VcclxuXHJcbiAgICAgICAgICAgICAgICAvLyBwbGF5UENNKGF1ZGlvRGF0YS5idWZmZXIuc2xpY2UoMCkpO1xyXG4gICAgICAgICAgICAgICAgLy8gY29uc29sZS5sb2coXCJwbGF5UENNIDY2NlwiLHRoaXMuYXVkaW9TdHJlYW0pXHJcbiAgICAgICAgICAgICAgICB0aGlzLmF1ZGlvU3RyZWFtLndyaXRlKGF1ZGlvRGF0YS5idWZmZXIuc2xpY2UoMCkpXHJcblxyXG4gICAgICAgICAgICAgICAgaWYoIXRoaXMuaXNTdGFydGVkKXtcclxuICAgICAgICAgICAgICAgICAgICBvblN0YXJ0Py4oKTtcclxuICAgICAgICAgICAgICAgICAgICB0aGlzLmlzU3RhcnRlZCA9IHRydWU7XHJcbiAgICAgICAgICAgICAgICB9XHJcbiAgICAgICAgICAgICAgICByZXR1cm4ge1xyXG4gICAgICAgICAgICAgICAgICAgIGF1ZGlvOiBhdWRpb0RhdGEuYnVmZmVyLFxyXG4gICAgICAgICAgICAgICAgICAgIGlzTGFzdDogc2VxdWVuY2VOdW1iZXIgPCAwXHJcbiAgICAgICAgICAgICAgICB9O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIGlmIChtZXNzYWdlVHlwZSA9PT0gMHhmKSB7IC8vIGVycm9yIG1lc3NhZ2VcclxuICAgICAgICAgICAgY29uc3QgY29kZSA9IHZpZXcuZ2V0SW50MzIocGF5bG9hZE9mZnNldCwgZmFsc2UpO1xyXG4gICAgICAgICAgICBjb25zdCBtc2dTaXplID0gdmlldy5nZXRJbnQzMihwYXlsb2FkT2Zmc2V0ICsgNCwgZmFsc2UpO1xyXG4gICAgICAgICAgICBsZXQgZXJyb3JNc2cgPSBwYXlsb2FkLnNsaWNlKDgpO1xyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgaWYgKG1lc3NhZ2VDb21wcmVzc2lvbiA9PT0gMSkge1xyXG4gICAgICAgICAgICAgICAgZXJyb3JNc2cgPSBwYWtvLnVuZ3ppcChlcnJvck1zZyk7XHJcbiAgICAgICAgICAgIH1cclxuICAgICAgICAgICAgXHJcbiAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICBlcnJvcjogYFRUUyBlcnJvciAoY29kZSAke2NvZGV9KTogJHtuZXcgVGV4dERlY29kZXIoKS5kZWNvZGUoZXJyb3JNc2cpfWBcclxuICAgICAgICAgICAgfTtcclxuICAgICAgICB9IGVsc2UgaWYgKG1lc3NhZ2VUeXBlID09PSAweGMpIHsgLy8gZnJvbnRlbmQgc2VydmVyIHJlc3BvbnNlXHJcbiAgICAgICAgICAgIGNvbnN0IG1zZ1NpemUgPSB2aWV3LmdldEludDMyKHBheWxvYWRPZmZzZXQsIGZhbHNlKTtcclxuICAgICAgICAgICAgbGV0IG1lc3NhZ2UgPSBwYXlsb2FkLnNsaWNlKDQpO1xyXG4gICAgICAgICAgICBcclxuICAgICAgICAgICAgaWYgKG1lc3NhZ2VDb21wcmVzc2lvbiA9PT0gMSkge1xyXG4gICAgICAgICAgICAgICAgbWVzc2FnZSA9IHBha28udW5nemlwKG1lc3NhZ2UpO1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgICAgIFxyXG4gICAgICAgICAgICAvLyDlj6/ku6Xop6PmnpDov5Tlm57nmoTlhYPmlbDmja7vvIzlpoJkdXJhdGlvbuetiVxyXG4gICAgICAgICAgICB0cnkge1xyXG4gICAgICAgICAgICAgICAgY29uc3QgbWV0YSA9IEpTT04ucGFyc2UobmV3IFRleHREZWNvZGVyKCkuZGVjb2RlKG1lc3NhZ2UpKTtcclxuICAgICAgICAgICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgICAgICAgICAgZHVyYXRpb246IG1ldGEuZHVyYXRpb24gfHwgMFxyXG4gICAgICAgICAgICAgICAgfTtcclxuICAgICAgICAgICAgfSBjYXRjaCAoZXJyKSB7XHJcbiAgICAgICAgICAgICAgICBjb25zb2xlLndhcm4oXCJGYWlsZWQgdG8gcGFyc2UgVFRTIG1ldGFkYXRhOlwiLCBlcnIpO1xyXG4gICAgICAgICAgICAgICAgcmV0dXJuIHt9O1xyXG4gICAgICAgICAgICB9XHJcbiAgICAgICAgfSBlbHNlIHtcclxuICAgICAgICAgICAgcmV0dXJuIHtcclxuICAgICAgICAgICAgICAgIGVycm9yOiBgVW5rbm93biBtZXNzYWdlIHR5cGU6ICR7bWVzc2FnZVR5cGV9YFxyXG4gICAgICAgICAgICB9O1xyXG4gICAgICAgIH1cclxuICAgIH1cclxuXHJcbiAgICBzdG9wKCk6IHZvaWQge1xyXG4gICAgICAgIHRoaXMuaXNTeW50aGVzaXppbmcgPSBmYWxzZTtcclxuICAgICAgICBcclxuICAgICAgICBpZiAodGhpcy53cykge1xyXG4gICAgICAgICAgICB0aGlzLndzLmNsb3NlKCk7XHJcbiAgICAgICAgICAgIHRoaXMud3MgPSBudWxsO1xyXG4gICAgICAgIH1cclxuICAgICAgICBcclxuICAgICAgICB0aGlzLmF1ZGlvQ2h1bmtzID0gW107XHJcbiAgICB9XHJcblxyXG4gICAgZGlzcG9zZSgpOiB2b2lkIHtcclxuICAgICAgICB0aGlzLnN0b3AoKTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGV4dHJhY3RUZXh0RnJvbVNTTUwoc3NtbDogc3RyaW5nKTogc3RyaW5nIHtcclxuICAgICAgICAvLyBTaW1wbGUgU1NNTCB0byB0ZXh0IGV4dHJhY3Rpb24gLSBjYW4gYmUgZW5oYW5jZWQgYXMgbmVlZGVkXHJcbiAgICAgICAgcmV0dXJuIHNzbWwucmVwbGFjZSgvPFtePl0rPi9nLCAnJykudHJpbSgpO1xyXG4gICAgfVxyXG5cclxuICAgIHByaXZhdGUgYXN5bmMgYmxvYlRvQXJyYXlCdWZmZXIoYmxvYjogQmxvYik6IFByb21pc2U8QXJyYXlCdWZmZXI+IHtcclxuICAgICAgICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xyXG4gICAgICAgICAgICBjb25zdCByZWFkZXIgPSBuZXcgRmlsZVJlYWRlcigpO1xyXG4gICAgICAgICAgICByZWFkZXIub25sb2FkID0gKCkgPT4gcmVzb2x2ZShyZWFkZXIucmVzdWx0IGFzIEFycmF5QnVmZmVyKTtcclxuICAgICAgICAgICAgcmVhZGVyLm9uZXJyb3IgPSByZWplY3Q7XHJcbiAgICAgICAgICAgIHJlYWRlci5yZWFkQXNBcnJheUJ1ZmZlcihibG9iKTtcclxuICAgICAgICB9KTtcclxuICAgIH1cclxuXHJcbiAgICBwcml2YXRlIGFzeW5jIG1lcmdlUGNtVG9XYXYocGNtQ2h1bmtzOiBBcnJheUJ1ZmZlcltdKTogUHJvbWlzZTx7XHJcbiAgICAgICAgYnVmZmVyOiBBcnJheUJ1ZmZlcixcclxuICAgICAgICBkdXJhdGlvbjogbnVtYmVyXHJcbiAgICB9PiB7XHJcbiAgICAgICAgLy8gMS4g6K6h566X5oC76ZW/5bqm5ZKM5ZCI5bm25omA5pyJUENN5pWw5o2uXHJcbiAgICAgICAgbGV0IHRvdGFsTGVuZ3RoID0gMDtcclxuICAgICAgICBwY21DaHVua3MuZm9yRWFjaChjaHVuayA9PiB7XHJcbiAgICAgICAgICAgIHRvdGFsTGVuZ3RoICs9IGNodW5rLmJ5dGVMZW5ndGg7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gMi4g6K6h566X6Z+z6aKR5pe26ZW/ICjlgYforr7mmK8xNuS9jeWNleWjsOmBk1BDTe+8jOmHh+agt+eOhzI0MDAwKVxyXG4gICAgICAgIGNvbnN0IHNhbXBsZVJhdGUgPSAyNDAwMDtcclxuICAgICAgICBjb25zdCBudW1DaGFubmVscyA9IDE7XHJcbiAgICAgICAgY29uc3QgYml0c1BlclNhbXBsZSA9IDE2O1xyXG4gICAgICAgIGNvbnN0IGR1cmF0aW9uID0gMTAwMCAqIHRvdGFsTGVuZ3RoIC8gKHNhbXBsZVJhdGUgKiBudW1DaGFubmVscyAqIGJpdHNQZXJTYW1wbGUgLyA4KTtcclxuICAgICAgICBcclxuICAgICAgICAvLyAzLiDliJvlu7rlkIjlubblkI7nmoRQQ03mlbDmja7nvJPlhrLljLpcclxuICAgICAgICBjb25zdCBtZXJnZWRQY20gPSBuZXcgVWludDhBcnJheSh0b3RhbExlbmd0aCk7XHJcbiAgICAgICAgbGV0IG9mZnNldCA9IDA7XHJcbiAgICAgICAgcGNtQ2h1bmtzLmZvckVhY2goY2h1bmsgPT4ge1xyXG4gICAgICAgICAgICBtZXJnZWRQY20uc2V0KG5ldyBVaW50OEFycmF5KGNodW5rKSwgb2Zmc2V0KTtcclxuICAgICAgICAgICAgb2Zmc2V0ICs9IGNodW5rLmJ5dGVMZW5ndGg7XHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gNC4g5Yib5bu6V0FW5paH5Lu25aS0XHJcbiAgICAgICAgY29uc3Qgd2F2SGVhZGVyID0gdGhpcy5jcmVhdGVXYXZIZWFkZXIoe1xyXG4gICAgICAgICAgICBzYW1wbGVSYXRlLFxyXG4gICAgICAgICAgICBudW1DaGFubmVscyxcclxuICAgICAgICAgICAgYml0c1BlclNhbXBsZSxcclxuICAgICAgICAgICAgcGNtRGF0YVNpemU6IHRvdGFsTGVuZ3RoXHJcbiAgICAgICAgfSk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gNS4g5ZCI5bm2V0FW5aS05ZKMUENN5pWw5o2uXHJcbiAgICAgICAgY29uc3Qgd2F2QnVmZmVyID0gbmV3IFVpbnQ4QXJyYXkod2F2SGVhZGVyLmJ5dGVMZW5ndGggKyBtZXJnZWRQY20uYnl0ZUxlbmd0aCk7XHJcbiAgICAgICAgd2F2QnVmZmVyLnNldChuZXcgVWludDhBcnJheSh3YXZIZWFkZXIpLCAwKTtcclxuICAgICAgICB3YXZCdWZmZXIuc2V0KG1lcmdlZFBjbSwgd2F2SGVhZGVyLmJ5dGVMZW5ndGgpO1xyXG4gICAgICAgIFxyXG4gICAgICAgIHJldHVybiB7XHJcbiAgICAgICAgICAgIGJ1ZmZlcjogd2F2QnVmZmVyLmJ1ZmZlcixcclxuICAgICAgICAgICAgZHVyYXRpb25cclxuICAgICAgICB9O1xyXG4gICAgfVxyXG4gICAgXHJcbiAgICBcclxuICAgIC8qKlxyXG4gICAgICog5Yib5bu6V0FW5paH5Lu25aS0XHJcbiAgICAgKiBAcGFyYW0gb3B0aW9ucyDpn7PpopHlj4LmlbBcclxuICAgICAqIEByZXR1cm5zIFdBVuWktEFycmF5QnVmZmVyXHJcbiAgICAgKi9cclxuICAgIHByaXZhdGUgY3JlYXRlV2F2SGVhZGVyKG9wdGlvbnM6IHtcclxuICAgICAgICBzYW1wbGVSYXRlOiBudW1iZXIsXHJcbiAgICAgICAgbnVtQ2hhbm5lbHM6IG51bWJlcixcclxuICAgICAgICBiaXRzUGVyU2FtcGxlOiBudW1iZXIsXHJcbiAgICAgICAgcGNtRGF0YVNpemU6IG51bWJlclxyXG4gICAgfSk6IEFycmF5QnVmZmVyIHtcclxuICAgICAgICBjb25zdCB7IHNhbXBsZVJhdGUsIG51bUNoYW5uZWxzLCBiaXRzUGVyU2FtcGxlLCBwY21EYXRhU2l6ZSB9ID0gb3B0aW9ucztcclxuICAgICAgICBjb25zdCBieXRlUmF0ZSA9IHNhbXBsZVJhdGUgKiBudW1DaGFubmVscyAqIGJpdHNQZXJTYW1wbGUgLyA4O1xyXG4gICAgICAgIGNvbnN0IGJsb2NrQWxpZ24gPSBudW1DaGFubmVscyAqIGJpdHNQZXJTYW1wbGUgLyA4O1xyXG4gICAgICAgIFxyXG4gICAgICAgIC8vIFdBVuWktOWbuuWumjQ05a2X6IqCXHJcbiAgICAgICAgY29uc3QgYnVmZmVyID0gbmV3IEFycmF5QnVmZmVyKDQ0KTtcclxuICAgICAgICBjb25zdCB2aWV3ID0gbmV3IERhdGFWaWV3KGJ1ZmZlcik7XHJcbiAgICAgICAgXHJcbiAgICAgICAgLy8gUklGRuagh+ivhlxyXG4gICAgICAgIHRoaXMud3JpdGVTdHJpbmcodmlldywgMCwgJ1JJRkYnKTtcclxuICAgICAgICAvLyDmlofku7bmgLvplb/luqYgKFBDTeaVsOaNrumVv+W6piArIDQ0IC0gOClcclxuICAgICAgICB2aWV3LnNldFVpbnQzMig0LCAzNiArIHBjbURhdGFTaXplLCB0cnVlKTtcclxuICAgICAgICAvLyBXQVZF5qCH6K+GXHJcbiAgICAgICAgdGhpcy53cml0ZVN0cmluZyh2aWV3LCA4LCAnV0FWRScpO1xyXG4gICAgICAgIC8vIGZtdOWtkOWdl1xyXG4gICAgICAgIHRoaXMud3JpdGVTdHJpbmcodmlldywgMTIsICdmbXQgJyk7XHJcbiAgICAgICAgLy8gZm105Z2X6ZW/5bqmICgxNiBmb3IgUENNKVxyXG4gICAgICAgIHZpZXcuc2V0VWludDMyKDE2LCAxNiwgdHJ1ZSk7XHJcbiAgICAgICAgLy8g5qC85byP57G75Z6LICgxID0gUENNKVxyXG4gICAgICAgIHZpZXcuc2V0VWludDE2KDIwLCAxLCB0cnVlKTtcclxuICAgICAgICAvLyDlo7DpgZPmlbBcclxuICAgICAgICB2aWV3LnNldFVpbnQxNigyMiwgbnVtQ2hhbm5lbHMsIHRydWUpO1xyXG4gICAgICAgIC8vIOmHh+agt+eOh1xyXG4gICAgICAgIHZpZXcuc2V0VWludDMyKDI0LCBzYW1wbGVSYXRlLCB0cnVlKTtcclxuICAgICAgICAvLyDlrZfoioLnjodcclxuICAgICAgICB2aWV3LnNldFVpbnQzMigyOCwgYnl0ZVJhdGUsIHRydWUpO1xyXG4gICAgICAgIC8vIOWdl+Wvuem9kFxyXG4gICAgICAgIHZpZXcuc2V0VWludDE2KDMyLCBibG9ja0FsaWduLCB0cnVlKTtcclxuICAgICAgICAvLyDkvY3mt7FcclxuICAgICAgICB2aWV3LnNldFVpbnQxNigzNCwgYml0c1BlclNhbXBsZSwgdHJ1ZSk7XHJcbiAgICAgICAgLy8gZGF0Yeagh+ivhlxyXG4gICAgICAgIHRoaXMud3JpdGVTdHJpbmcodmlldywgMzYsICdkYXRhJyk7XHJcbiAgICAgICAgLy8gZGF0YeWdl+mVv+W6plxyXG4gICAgICAgIHZpZXcuc2V0VWludDMyKDQwLCBwY21EYXRhU2l6ZSwgdHJ1ZSk7XHJcbiAgICAgICAgXHJcbiAgICAgICAgcmV0dXJuIGJ1ZmZlcjtcclxuICAgIH1cclxuICAgIFxyXG4gICAgLyoqXHJcbiAgICAgKiDlkJFEYXRhVmlld+WGmeWFpeWtl+espuS4slxyXG4gICAgICovXHJcbiAgICBwcml2YXRlIHdyaXRlU3RyaW5nKHZpZXc6IERhdGFWaWV3LCBvZmZzZXQ6IG51bWJlciwgc3RyOiBzdHJpbmcpIHtcclxuICAgICAgICBmb3IgKGxldCBpID0gMDsgaSA8IHN0ci5sZW5ndGg7IGkrKykge1xyXG4gICAgICAgICAgICB2aWV3LnNldFVpbnQ4KG9mZnNldCArIGksIHN0ci5jaGFyQ29kZUF0KGkpKTtcclxuICAgICAgICB9XHJcbiAgICB9XHJcbn1cclxuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkRnVsbFVybCh1cmw6IHN0cmluZywgYXV0aDogUmVjb3JkPHN0cmluZywgc3RyaW5nPikge1xyXG4gICAgY29uc3QgYXJyID0gW107XHJcbiAgICBmb3IgKGNvbnN0IGtleSBpbiBhdXRoKSB7XHJcbiAgICAgIGFyci5wdXNoKGAke2tleX09JHtlbmNvZGVVUklDb21wb25lbnQoYXV0aFtrZXldKX1gKTtcclxuICAgIH1cclxuICAgIHJldHVybiBgJHt1cmx9PyR7YXJyLmpvaW4oJyYnKX1gO1xyXG4gIH1cclxuXHJcblxyXG4iXX0=
|
|
8
|
+
import pako from"pako";import{v4 as uuidv4}from"uuid";export class FmodeTTSProviderDoubao{constructor(){this.ws=null,this.audioChunks=[],this.isSynthesizing=!1,this.isStarted=!1}initialize(e){if(!e.appId||!e.accessToken)throw new Error("appId, accessToken are required for Doubao TTS");e.cluster=e.cluster||"volcano_tts",this.config=e,this.audioStream=e.audioStream}synthesize(e,t,s,i){this.isSynthesizing&&this.stop(),this.isSynthesizing=!0,this.audioChunks=[],this.eventMap?.onSpeakBefore?.();const r=e?.indexOf("<speak")>-1,n=r?this.extractTextFromSSML(e):e;let o=uuidv4();const a=buildFullUrl("wss://openspeech.bytedance.com/api/v1/tts/ws_binary",{api_jwt:this.config.stsToken});this.ws=new WebSocket(a),this.ws.binaryType="arraybuffer",this.ws.onopen=()=>{this.eventMap?.onStreamStarted?.();const e={app:{appid:this.config.appId,token:this.config.accessToken,cluster:this.config.cluster},user:{uid:"user123"},audio:{voice_type:this.voiceConfig?.voice||"zh_female_shuangkuaisisi_emo_v2_mars_bigtts",encoding:"pcm",rate:24e3,speed_ratio:1,volume_ratio:1,pitch_ratio:1,language:"cn"},request:{reqid:o,text:n,text_type:r?"ssml":"plain",operation:"submit"}},t=this.buildBinaryMessage(e);this.ws?.send(t)},this.ws.onmessage=async e=>{try{if(e.data instanceof ArrayBuffer){const r=new Uint8Array(e.data),n=this.parseResponse(r,i);if(n.error)return s(n.error),void this.stop();if(n.audio&&(this.audioChunks.push(n.audio),this.audioStream),n.isLast){this.eventMap?.onAudioCompleted?.();const{buffer:e,duration:s}=await this.mergePcmToWav(this.audioChunks);t({audioData:e,audioDuration:n.duration||s||0}),this.stop()}}else console.warn("Unexpected text message from TTS server:",e.data)}catch(e){s(`Error processing TTS response: ${e}`),this.stop()}},this.ws.onerror=e=>{s(`WebSocket error: ${JSON.stringify(e)}`),this.stop()},this.ws.onclose=()=>{this.isSynthesizing&&(s("WebSocket connection closed unexpectedly"),this.stop())}}buildBinaryMessage(e){const t=JSON.stringify(e),s=(new TextEncoder).encode(t),i=pako.gzip(s),r=new ArrayBuffer(8+i.length),n=new DataView(r);n.setUint8(0,17),n.setUint8(1,16),n.setUint8(2,17),n.setUint8(3,0),n.setUint32(4,i.length,!1);return new Uint8Array(r).set(i,8),r}parseResponse(e,t){const s=new DataView(e.buffer),i=(e[0],15&e[0]),r=e[1]>>4,n=15&e[1],o=(e[2],15&e[2]),a=(e[3],4*i);let u=e.slice(a);if(11==r){if(0===n)return{};{const e=s.getInt32(a,!1),i=(s.getInt32(a+4,!1),u.slice(8));return this.audioStream.write(i.buffer.slice(0)),this.isStarted||(t?.(),this.isStarted=!0),{audio:i.buffer,isLast:e<0}}}if(15===r){const e=s.getInt32(a,!1);s.getInt32(a+4,!1);let t=u.slice(8);return 1===o&&(t=pako.ungzip(t)),{error:`TTS error (code ${e}): ${(new TextDecoder).decode(t)}`}}if(12!==r)return{error:`Unknown message type: ${r}`};{s.getInt32(a,!1);let e=u.slice(4);1===o&&(e=pako.ungzip(e));try{return{duration:JSON.parse((new TextDecoder).decode(e)).duration||0}}catch(e){return console.warn("Failed to parse TTS metadata:",e),{}}}}stop(){this.isSynthesizing=!1,this.ws&&(this.ws.close(),this.ws=null),this.audioChunks=[]}dispose(){this.stop()}extractTextFromSSML(e){return e.replace(/<[^>]+>/g,"").trim()}async blobToArrayBuffer(e){return new Promise(((t,s)=>{const i=new FileReader;i.onload=()=>t(i.result),i.onerror=s,i.readAsArrayBuffer(e)}))}async mergePcmToWav(e){let t=0;e.forEach((e=>{t+=e.byteLength}));const s=1e3*t/48e3,i=new Uint8Array(t);let r=0;e.forEach((e=>{i.set(new Uint8Array(e),r),r+=e.byteLength}));const n=this.createWavHeader({sampleRate:24e3,numChannels:1,bitsPerSample:16,pcmDataSize:t}),o=new Uint8Array(n.byteLength+i.byteLength);return o.set(new Uint8Array(n),0),o.set(i,n.byteLength),{buffer:o.buffer,duration:s}}createWavHeader(e){const{sampleRate:t,numChannels:s,bitsPerSample:i,pcmDataSize:r}=e,n=t*s*i/8,o=s*i/8,a=new ArrayBuffer(44),u=new DataView(a);return this.writeString(u,0,"RIFF"),u.setUint32(4,36+r,!0),this.writeString(u,8,"WAVE"),this.writeString(u,12,"fmt "),u.setUint32(16,16,!0),u.setUint16(20,1,!0),u.setUint16(22,s,!0),u.setUint32(24,t,!0),u.setUint32(28,n,!0),u.setUint16(32,o,!0),u.setUint16(34,i,!0),this.writeString(u,36,"data"),u.setUint32(40,r,!0),a}writeString(e,t,s){for(let i=0;i<s.length;i++)e.setUint8(t+i,s.charCodeAt(i))}}export function buildFullUrl(e,t){const s=[];for(const e in t)s.push(`${e}=${encodeURIComponent(t[e])}`);return`${e}?${s.join("&")}`}
|
|
9
|
+
var MODULE_PATH_NEED = `6K+l5paH5Lu25piv5pys6aG555uu55qE5LiA6YOo5YiGIFRoaXMgZmlsZSBpcyBwYXJ0IG9mIHRoZSBDb21wb25lbnRzIGluIEZtb2RlIEluYy4KICAgIOeJiOadg+aJgOaciSDCqSDmnKrmnaXpo57pqawgwqkg5rGf6KW/6ISR5o6n56eR5oqA5pyJ6ZmQ5YWs5Y+4IENvcHlyaWdodCDCqSBGbW9kZSBUZWNobm9sb2d5IENvLiwgTHRkLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCBSaWdodHMgUmVzZXJ2ZWQuCiAgICDkuKXnpoHlnKjmnKrnu4/mjojmnYPnmoTmg4XlhrXkuIvvvIzpgJrov4fku7vkvZXlqpLku4vlpI3liLbmraTmlofku7YgVW5hdXRob3JpemVkIGNvcHlpbmcgb2YgdGhpcyBmaWxlLCB2aWEgYW55IG1lZGl1bSBpcyBzdHJpY3RseSBwcm9oaWJpdGVkCiAgICDor6Xmlofku7bmmK/kuJPmnInnmoTmnLrlr4bmlofku7YgUHJvcHJpZXRhcnkgYW5kIGNvbmZpZGVudGlhbAogICAKICAgIENvcHlyaWdodCAyMDIxLW5vdyBGbW9kZSBJbmMuIHN1cHBvcnRAZm1vZGUuY24uIDE4NjA3MDA3MDczLgogICAg5L+d55WZ5omA5pyJ5p2D5YipIEFsbCByaWdodHMgcmVzZXJ2ZWQuCgogICAgUEFUSDovaG9tZS9yeWFuL3dvcmtzcGFjZS9ub3ZhL25vdmEtYWRtaW4vZGlzdC9mbW9kZS1uZy9lc20yMDIyL2xpYi9haWdjL3ZvaWNlL3R0cy9wcm92aWRlci1kb3ViYW8ubWpz`
|
|
10
|
+
|