mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-24 10:40:07 +08:00
添加了 TTS 相关服务并更新了设置
This commit is contained in:
parent
b2a0a029d2
commit
788fb1fc17
@ -3,6 +3,8 @@ productName: Cherry Studio
|
||||
directories:
|
||||
buildResources: build
|
||||
files:
|
||||
- out/**/*
|
||||
- package.json
|
||||
- '!{.vscode,.yarn,.github}'
|
||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||
|
||||
@ -76,6 +76,7 @@
|
||||
"color": "^5.0.0",
|
||||
"diff": "^7.0.0",
|
||||
"docx": "^9.0.2",
|
||||
"edge-tts-node": "^1.5.7",
|
||||
"electron-log": "^5.1.5",
|
||||
"electron-store": "^8.2.0",
|
||||
"electron-updater": "^6.3.9",
|
||||
|
||||
@ -25,6 +25,9 @@ export enum IpcChannel {
|
||||
// MsTTS
|
||||
MsTTS_GetVoices = 'mstts:get-voices',
|
||||
MsTTS_Synthesize = 'mstts:synthesize',
|
||||
MsTTS_SynthesizeStream = 'mstts:synthesize-stream',
|
||||
MsTTS_StreamData = 'mstts:stream-data',
|
||||
MsTTS_StreamEnd = 'mstts:stream-end',
|
||||
|
||||
// Open
|
||||
Open_Path = 'open:path',
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
import { IpcChannel } from '@shared/IpcChannel'
|
||||
import { ipcMain } from 'electron'
|
||||
import { BrowserWindow, ipcMain } from 'electron'
|
||||
|
||||
import * as MsTTSService from './MsTTSService'
|
||||
|
||||
@ -14,4 +14,34 @@ export function registerMsTTSIpcHandlers(): void {
|
||||
ipcMain.handle(IpcChannel.MsTTS_Synthesize, (_, text: string, voice: string, outputFormat: string) =>
|
||||
MsTTSService.synthesize(text, voice, outputFormat)
|
||||
)
|
||||
|
||||
// 流式合成语音
|
||||
ipcMain.handle(IpcChannel.MsTTS_SynthesizeStream, async (event, requestId: string, text: string, voice: string, outputFormat: string) => {
|
||||
const window = BrowserWindow.fromWebContents(event.sender)
|
||||
if (!window) return
|
||||
|
||||
try {
|
||||
await MsTTSService.synthesizeStream(
|
||||
text,
|
||||
voice,
|
||||
outputFormat,
|
||||
(chunk: Uint8Array) => {
|
||||
// 发送音频数据块
|
||||
if (!window.isDestroyed()) {
|
||||
window.webContents.send(IpcChannel.MsTTS_StreamData, requestId, chunk)
|
||||
}
|
||||
},
|
||||
() => {
|
||||
// 发送流结束信号
|
||||
if (!window.isDestroyed()) {
|
||||
window.webContents.send(IpcChannel.MsTTS_StreamEnd, requestId)
|
||||
}
|
||||
}
|
||||
)
|
||||
return { success: true }
|
||||
} catch (error) {
|
||||
console.error('流式TTS合成失败:', error)
|
||||
return { success: false, error: error instanceof Error ? error.message : String(error) }
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@ -3,7 +3,8 @@ import path from 'node:path'
|
||||
|
||||
import { app } from 'electron'
|
||||
import log from 'electron-log'
|
||||
import { EdgeTTS } from 'node-edge-tts' // listVoices is no longer needed here
|
||||
import { EdgeTTS } from 'node-edge-tts' // 旧版TTS库
|
||||
import { MsEdgeTTS, OUTPUT_FORMAT } from 'edge-tts-node' // 新版支持流式的TTS库
|
||||
|
||||
// --- START OF HARDCODED VOICE LIST ---
|
||||
// WARNING: This list is static and may become outdated.
|
||||
@ -437,6 +438,77 @@ class MsTTSService {
|
||||
return MsTTSService.instance
|
||||
}
|
||||
|
||||
/**
|
||||
* 流式合成语音
|
||||
* @param text 要合成的文本
|
||||
* @param voice 语音的 ShortName (例如 'zh-CN-XiaoxiaoNeural')
|
||||
* @param outputFormat 输出格式 (例如 'audio-24khz-48kbitrate-mono-mp3')
|
||||
* @param onData 数据块回调
|
||||
* @param onEnd 结束回调
|
||||
*/
|
||||
public async synthesizeStream(
|
||||
text: string,
|
||||
voice: string,
|
||||
outputFormat: string,
|
||||
onData: (chunk: Uint8Array) => void,
|
||||
onEnd: () => void
|
||||
): Promise<void> {
|
||||
try {
|
||||
// 记录详细的请求信息
|
||||
log.info(`流式微软在线TTS合成语音: 文本="${text.substring(0, 30)}...", 语音=${voice}, 格式=${outputFormat}`)
|
||||
|
||||
// 验证输入参数
|
||||
if (!text || text.trim() === '') {
|
||||
throw new Error('要合成的文本不能为空')
|
||||
}
|
||||
|
||||
if (!voice || voice.trim() === '') {
|
||||
throw new Error('语音名称不能为空')
|
||||
}
|
||||
|
||||
// 创建一个新的MsEdgeTTS实例
|
||||
const tts = new MsEdgeTTS({
|
||||
enableLogger: false // 禁用内部日志
|
||||
})
|
||||
|
||||
// 设置元数据
|
||||
let msOutputFormat: OUTPUT_FORMAT
|
||||
if (outputFormat.includes('mp3')) {
|
||||
msOutputFormat = OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3
|
||||
} else if (outputFormat.includes('webm')) {
|
||||
msOutputFormat = OUTPUT_FORMAT.WEBM_24KHZ_16BIT_MONO_OPUS
|
||||
} else {
|
||||
msOutputFormat = OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3
|
||||
}
|
||||
|
||||
await tts.setMetadata(voice, msOutputFormat)
|
||||
|
||||
// 创建流
|
||||
const audioStream = tts.toStream(text)
|
||||
|
||||
// 监听数据事件
|
||||
audioStream.on('data', (data: Buffer) => {
|
||||
onData(data)
|
||||
})
|
||||
|
||||
// 监听结束事件
|
||||
audioStream.on('end', () => {
|
||||
log.info(`流式微软在线TTS合成成功`)
|
||||
onEnd()
|
||||
})
|
||||
|
||||
// 监听错误事件
|
||||
audioStream.on('error', (error: Error) => {
|
||||
log.error(`流式微软在线TTS语音合成失败:`, error)
|
||||
throw error
|
||||
})
|
||||
} catch (error: any) {
|
||||
// 记录详细的错误信息
|
||||
log.error(`流式微软在线TTS语音合成失败 (语音=${voice}):`, error)
|
||||
throw error
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取可用的语音列表 (返回硬编码列表)
|
||||
* @returns 语音列表
|
||||
@ -556,6 +628,16 @@ export const synthesize = async (text: string, voice: string, outputFormat: stri
|
||||
return await MsTTSService.getInstance().synthesize(text, voice, outputFormat)
|
||||
}
|
||||
|
||||
export const synthesizeStream = async (
|
||||
text: string,
|
||||
voice: string,
|
||||
outputFormat: string,
|
||||
onData: (chunk: Uint8Array) => void,
|
||||
onEnd: () => void
|
||||
) => {
|
||||
return await MsTTSService.getInstance().synthesizeStream(text, voice, outputFormat, onData, onEnd)
|
||||
}
|
||||
|
||||
export const cleanupTtsTempFiles = async () => {
|
||||
await MsTTSService.getInstance().cleanupTempDir()
|
||||
}
|
||||
|
||||
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
||||
import styled from 'styled-components'
|
||||
|
||||
interface Props {
|
||||
onTranscribed: (text: string) => void
|
||||
onTranscribed: (text: string, isFinal?: boolean) => void
|
||||
disabled?: boolean
|
||||
style?: React.CSSProperties
|
||||
}
|
||||
@ -33,7 +33,7 @@ const ASRButton: FC<Props> = ({ onTranscribed, disabled = false, style }) => {
|
||||
try {
|
||||
// 添加事件监听器,监听服务器发送的stopped消息
|
||||
const originalCallback = ASRService.resultCallback
|
||||
const stopCallback = (text: string) => {
|
||||
const stopCallback = (text: string, isFinal?: boolean) => {
|
||||
// 如果是空字符串,只重置状态,不调用原始回调
|
||||
if (text === '') {
|
||||
setIsProcessing(false)
|
||||
|
||||
@ -2,7 +2,7 @@ import { SoundOutlined } from '@ant-design/icons'
|
||||
import TTSService from '@renderer/services/TTSService'
|
||||
import { Message } from '@renderer/types'
|
||||
import { Button, Tooltip } from 'antd'
|
||||
import { useCallback, useState } from 'react'
|
||||
import { useCallback, useEffect, useState } from 'react'
|
||||
import { useTranslation } from 'react-i18next'
|
||||
|
||||
interface TTSButtonProps {
|
||||
@ -14,38 +14,45 @@ const TTSButton: React.FC<TTSButtonProps> = ({ message, className }) => {
|
||||
const { t } = useTranslation()
|
||||
const [isSpeaking, setIsSpeaking] = useState(false)
|
||||
|
||||
// 添加TTS状态变化事件监听器
|
||||
useEffect(() => {
|
||||
const handleTTSStateChange = (event: CustomEvent) => {
|
||||
const { isPlaying } = event.detail
|
||||
console.log('TTS按钮检测到TTS状态变化:', isPlaying)
|
||||
setIsSpeaking(isPlaying)
|
||||
}
|
||||
|
||||
// 添加事件监听器
|
||||
window.addEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
|
||||
// 组件卸载时移除事件监听器
|
||||
return () => {
|
||||
window.removeEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 初始化时检查TTS状态
|
||||
useEffect(() => {
|
||||
// 检查当前是否正在播放
|
||||
const isCurrentlyPlaying = TTSService.isCurrentlyPlaying()
|
||||
if (isCurrentlyPlaying !== isSpeaking) {
|
||||
setIsSpeaking(isCurrentlyPlaying)
|
||||
}
|
||||
}, [])
|
||||
|
||||
const handleTTS = useCallback(async () => {
|
||||
if (isSpeaking) {
|
||||
TTSService.stop()
|
||||
setIsSpeaking(false)
|
||||
return
|
||||
return // 不需要手动设置状态,事件监听器会处理
|
||||
}
|
||||
|
||||
setIsSpeaking(true)
|
||||
try {
|
||||
console.log('点击TTS按钮,开始播放消息')
|
||||
await TTSService.speakFromMessage(message)
|
||||
|
||||
// 监听播放结束
|
||||
const checkPlayingStatus = () => {
|
||||
if (!TTSService.isCurrentlyPlaying()) {
|
||||
setIsSpeaking(false)
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
}
|
||||
|
||||
const checkInterval = setInterval(checkPlayingStatus, 500)
|
||||
|
||||
// 安全机制,确保即使出错也会重置状态
|
||||
setTimeout(() => {
|
||||
if (isSpeaking) {
|
||||
TTSService.stop()
|
||||
setIsSpeaking(false)
|
||||
clearInterval(checkInterval)
|
||||
}
|
||||
}, 30000) // 30秒后检查
|
||||
// 不需要手动设置状态,事件监听器会处理
|
||||
} catch (error) {
|
||||
console.error('TTS error:', error)
|
||||
// 出错时才需要手动重置状态
|
||||
setIsSpeaking(false)
|
||||
}
|
||||
}, [isSpeaking, message])
|
||||
|
||||
@ -77,6 +77,7 @@ let _files: FileType[] = []
|
||||
|
||||
const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) => {
|
||||
const [text, setText] = useState(_text)
|
||||
const [asrCurrentText, setAsrCurrentText] = useState('')
|
||||
const [inputFocus, setInputFocus] = useState(false)
|
||||
const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id)
|
||||
const {
|
||||
@ -787,18 +788,40 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
}
|
||||
}
|
||||
|
||||
// 如果是语音通话消息,创建一个新的助手对象,并设置模型
|
||||
// 如果是语音通话消息,创建一个新的助手对象,并设置模型和提示词
|
||||
let assistantToUse = assistant
|
||||
if ((data.isVoiceCall || data.useVoiceCallModel) && userMessage.model) {
|
||||
if (data.isVoiceCall || data.useVoiceCallModel) {
|
||||
// 创建一个新的助手对象,以避免修改原始助手
|
||||
assistantToUse = { ...assistant }
|
||||
|
||||
// 设置助手的模型为语音通话专用模型
|
||||
assistantToUse.model = userMessage.model
|
||||
console.log(
|
||||
'为语音通话消息创建了新的助手对象,并设置了模型:',
|
||||
userMessage.model.name || userMessage.model.id
|
||||
)
|
||||
// 如果有语音通话专用模型,设置助手的模型
|
||||
if (userMessage.model) {
|
||||
assistantToUse.model = userMessage.model
|
||||
console.log(
|
||||
'为语音通话消息创建了新的助手对象,并设置了模型:',
|
||||
userMessage.model.name || userMessage.model.id
|
||||
)
|
||||
}
|
||||
|
||||
// 添加语音通话专属提示词
|
||||
const voiceCallPrompt = `当前是语音通话模式。请注意:
|
||||
1. 简洁直接地回答问题,避免冗长的引导和总结。
|
||||
2. 避免使用复杂的格式化内容,如表格、代码块、Markdown等。
|
||||
3. 使用自然、口语化的表达方式,就像与人对话一样。
|
||||
4. 如果需要列出要点,使用简单的数字或文字标记,而不是复杂的格式。
|
||||
5. 回答应该简短有力,便于用户通过语音理解。
|
||||
6. 避免使用特殊符号、表情符号、标点符号等,因为这些在语音播放时会影响理解。
|
||||
7. 使用完整的句子而非简单的关键词列表。
|
||||
8. 尽量使用常见词汇,避免生僻或专业术语,除非用户特别询问。`
|
||||
|
||||
// 如果助手已经有提示词,则在其后添加语音通话专属提示词
|
||||
if (assistantToUse.prompt) {
|
||||
assistantToUse.prompt += '\n\n' + voiceCallPrompt
|
||||
} else {
|
||||
assistantToUse.prompt = voiceCallPrompt
|
||||
}
|
||||
|
||||
console.log('为语音通话消息添加了专属提示词')
|
||||
}
|
||||
|
||||
// 分发发送消息的action
|
||||
@ -806,6 +829,8 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
|
||||
// 清空输入框
|
||||
setText('')
|
||||
// 重置语音识别状态
|
||||
setAsrCurrentText('')
|
||||
|
||||
console.log('已触发发送消息事件')
|
||||
}, 300)
|
||||
@ -1121,18 +1146,28 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
||||
<ToolbarMenu>
|
||||
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
|
||||
<ASRButton
|
||||
onTranscribed={(transcribedText) => {
|
||||
onTranscribed={(transcribedText, isFinal) => {
|
||||
// 如果是空字符串,不做任何处理
|
||||
if (!transcribedText) return
|
||||
|
||||
// 将识别的文本添加到当前输入框
|
||||
setText((prevText) => {
|
||||
// 如果当前有文本,添加空格后再添加识别的文本
|
||||
if (prevText.trim()) {
|
||||
if (isFinal) {
|
||||
// 最终结果,添加到输入框中
|
||||
setText((prevText) => {
|
||||
// 如果当前输入框为空,直接设置为识别的文本
|
||||
if (!prevText.trim()) {
|
||||
return transcribedText
|
||||
}
|
||||
|
||||
// 否则,添加识别的文本到输入框中,用空格分隔
|
||||
return prevText + ' ' + transcribedText
|
||||
}
|
||||
return transcribedText
|
||||
})
|
||||
})
|
||||
|
||||
// 清除当前识别的文本
|
||||
setAsrCurrentText('')
|
||||
} else {
|
||||
// 中间结果,保存到状态变量中,但不更新输入框
|
||||
setAsrCurrentText(transcribedText)
|
||||
}
|
||||
}}
|
||||
/>
|
||||
<VoiceCallButton disabled={loading} />
|
||||
|
||||
@ -153,15 +153,20 @@ const MessageItem: FC<Props> = ({
|
||||
|
||||
// 自动播放TTS的逻辑
|
||||
useEffect(() => {
|
||||
// 如果是最后一条助手消息,且消息状态为成功,且不是正在生成中,且TTS已启用,且语音通话窗口已打开
|
||||
// 如果是最后一条助手消息,且消息状态为成功,且不是正在生成中,且TTS已启用
|
||||
// 注意:只有在语音通话窗口打开时才自动播放TTS
|
||||
if (
|
||||
isLastMessage &&
|
||||
isAssistantMessage &&
|
||||
message.status === 'success' &&
|
||||
!generating &&
|
||||
ttsEnabled &&
|
||||
isVoiceCallActive
|
||||
ttsEnabled
|
||||
) {
|
||||
// 如果语音通话窗口没有打开,则不自动播放TTS
|
||||
if (!isVoiceCallActive) {
|
||||
console.log('不自动播放TTS,因为语音通话窗口没有打开:', isVoiceCallActive)
|
||||
return
|
||||
}
|
||||
// 检查是否需要跳过自动TTS
|
||||
if (skipNextAutoTTS) {
|
||||
console.log(
|
||||
@ -205,16 +210,6 @@ const MessageItem: FC<Props> = ({
|
||||
} else if (message.id === lastPlayedMessageId) {
|
||||
console.log('不自动播放TTS,因为该消息已经播放过:', message.id)
|
||||
}
|
||||
} else if (
|
||||
isLastMessage &&
|
||||
isAssistantMessage &&
|
||||
message.status === 'success' &&
|
||||
!generating &&
|
||||
ttsEnabled &&
|
||||
!isVoiceCallActive
|
||||
) {
|
||||
// 如果语音通话窗口没有打开,则不自动播放TTS
|
||||
console.log('不自动播放TTS,因为语音通话窗口没有打开')
|
||||
}
|
||||
}, [
|
||||
isLastMessage,
|
||||
|
||||
@ -9,14 +9,25 @@ const TTSStopButton: React.FC = () => {
|
||||
const { t } = useTranslation()
|
||||
const [isVisible, setIsVisible] = useState(false)
|
||||
|
||||
// 检查是否正在播放TTS
|
||||
// 添加TTS状态变化事件监听器
|
||||
useEffect(() => {
|
||||
const checkPlayingStatus = setInterval(() => {
|
||||
const isPlaying = TTSService.isCurrentlyPlaying()
|
||||
const handleTTSStateChange = (event: CustomEvent) => {
|
||||
const { isPlaying } = event.detail
|
||||
console.log('全局TTS停止按钮检测到TTS状态变化:', isPlaying)
|
||||
setIsVisible(isPlaying)
|
||||
}, 500)
|
||||
}
|
||||
|
||||
return () => clearInterval(checkPlayingStatus)
|
||||
// 添加事件监听器
|
||||
window.addEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
|
||||
// 初始检查当前状态
|
||||
const isCurrentlyPlaying = TTSService.isCurrentlyPlaying()
|
||||
setIsVisible(isCurrentlyPlaying)
|
||||
|
||||
// 组件卸载时移除事件监听器
|
||||
return () => {
|
||||
window.removeEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
}
|
||||
}, [])
|
||||
|
||||
// 停止TTS播放
|
||||
@ -26,17 +37,7 @@ const TTSStopButton: React.FC = () => {
|
||||
// 强制停止所有TTS播放
|
||||
TTSService.stop()
|
||||
|
||||
// 等待一下,确保播放已经完全停止
|
||||
await new Promise((resolve) => setTimeout(resolve, 100))
|
||||
|
||||
// 再次检查并停止,确保强制停止
|
||||
if (TTSService.isCurrentlyPlaying()) {
|
||||
console.log('第一次停止未成功,再次尝试')
|
||||
TTSService.stop()
|
||||
}
|
||||
|
||||
// 立即隐藏按钮
|
||||
setIsVisible(false)
|
||||
// 不需要手动设置状态,事件监听器会处理
|
||||
|
||||
// 显示停止消息
|
||||
window.message.success({ content: t('chat.tts.stopped', { defaultValue: '已停止语音播放' }), key: 'tts-stopped' })
|
||||
|
||||
@ -163,15 +163,14 @@ class ASRService {
|
||||
if (data.data.isFinal) {
|
||||
console.log('[ASRService] 收到最终结果,调用回调函数,文本:', data.data.text)
|
||||
|
||||
// 保存当前回调函数并立即清除,防止重复处理
|
||||
const tempCallback = this.resultCallback
|
||||
this.resultCallback = null
|
||||
// 不再清除回调函数,允许继续处理后续语音
|
||||
// const tempCallback = this.resultCallback
|
||||
// this.resultCallback = null
|
||||
|
||||
// 调用回调函数
|
||||
tempCallback(data.data.text, true)
|
||||
// 直接调用回调函数
|
||||
this.resultCallback(data.data.text, true)
|
||||
window.message.success({ content: i18n.t('settings.asr.success'), key: 'asr-processing' })
|
||||
} else if (this.isRecording) {
|
||||
// 只在录音中才处理中间结果
|
||||
} else if (this.isRecording) { // 只在录音中才处理中间结果
|
||||
// 非最终结果,也调用回调,但标记为非最终
|
||||
console.log('[ASRService] 收到中间结果,调用回调函数,文本:', data.data.text)
|
||||
this.resultCallback(data.data.text, false)
|
||||
@ -237,6 +236,14 @@ class ASRService {
|
||||
return
|
||||
}
|
||||
|
||||
// 先设置回调函数,确保在任何情况下都能正确设置
|
||||
if (onTranscribed && typeof onTranscribed === 'function') {
|
||||
console.log('[ASRService] 设置结果回调函数')
|
||||
this.resultCallback = onTranscribed
|
||||
} else {
|
||||
console.warn('[ASRService] 未提供有效的回调函数')
|
||||
}
|
||||
|
||||
// 如果是使用本地服务器
|
||||
if (asrServiceType === 'local') {
|
||||
// 连接WebSocket服务器
|
||||
@ -292,11 +299,6 @@ class ASRService {
|
||||
}
|
||||
}
|
||||
|
||||
// 保存回调函数(如果提供了)
|
||||
if (onTranscribed && typeof onTranscribed === 'function') {
|
||||
this.resultCallback = onTranscribed
|
||||
}
|
||||
|
||||
// 发送开始命令
|
||||
if (this.ws && this.wsConnected) {
|
||||
this.ws.send(JSON.stringify({ type: 'start' }))
|
||||
@ -376,11 +378,11 @@ class ASRService {
|
||||
}, 100)
|
||||
}
|
||||
|
||||
// 添加额外的安全措施,确保在停止后也清除回调
|
||||
setTimeout(() => {
|
||||
// 在停止后的一段时间内清除回调,防止后续结果被处理
|
||||
this.resultCallback = null
|
||||
}, 3000) // 3秒后清除回调
|
||||
// 不再清除回调函数,允许连续说多句话
|
||||
// setTimeout(() => {
|
||||
// // 在停止后的一段时间内清除回调,防止后续结果被处理
|
||||
// this.resultCallback = null
|
||||
// }, 3000) // 3秒后清除回调
|
||||
} else {
|
||||
throw new Error('WebSocket连接未就绪')
|
||||
}
|
||||
|
||||
@ -257,8 +257,8 @@ class VoiceCallServiceClass {
|
||||
} else {
|
||||
// 如果是临时结果,更新当前的识别结果
|
||||
this._currentTranscript = text
|
||||
// 显示累积结果 + 当前临时结果
|
||||
this.callbacks?.onTranscript(this._accumulatedTranscript + ' ' + text)
|
||||
// 只显示当前临时结果,不与累积结果拼接
|
||||
this.callbacks?.onTranscript(text)
|
||||
}
|
||||
|
||||
// 在录音过程中只更新transcript,不触发handleUserSpeech
|
||||
@ -595,12 +595,10 @@ class VoiceCallServiceClass {
|
||||
8. 尽量使用常见词汇,避免生僻或专业术语,除非用户特别询问。`
|
||||
|
||||
// 创建系统指令消息
|
||||
const systemMessage = getUserMessage({
|
||||
assistant,
|
||||
topic,
|
||||
type: 'text',
|
||||
const systemMessage = {
|
||||
role: 'system',
|
||||
content: voiceCallPrompt
|
||||
})
|
||||
}
|
||||
|
||||
// 修改用户消息的内容
|
||||
userMessage.content = text
|
||||
@ -637,14 +635,24 @@ class VoiceCallServiceClass {
|
||||
if (!this.isMuted && this.isCallActive) {
|
||||
// 手动设置语音状态
|
||||
this.callbacks?.onSpeakingStateChange(true)
|
||||
|
||||
// 添加TTS状态变化事件监听器
|
||||
const handleTTSStateChange = (event: CustomEvent) => {
|
||||
const { isPlaying } = event.detail
|
||||
console.log('语音通话中检测到TTS状态变化:', isPlaying)
|
||||
this.callbacks?.onSpeakingStateChange(isPlaying)
|
||||
}
|
||||
|
||||
// 添加事件监听器
|
||||
window.addEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
|
||||
// 开始播放
|
||||
this.ttsService.speak(fullResponse)
|
||||
|
||||
// 确保语音结束后状态正确
|
||||
// 设置超时安全机制,确保事件监听器被移除
|
||||
setTimeout(() => {
|
||||
if (this.ttsService && !this.ttsService.isCurrentlyPlaying()) {
|
||||
this.callbacks?.onSpeakingStateChange(false)
|
||||
}
|
||||
}, 1000) // 1秒后检查TTS状态
|
||||
window.removeEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||
}, 30000) // 30秒后移除事件监听器
|
||||
}
|
||||
|
||||
// 更新对话历史
|
||||
@ -910,9 +918,7 @@ class VoiceCallServiceClass {
|
||||
this.ttsService.stop()
|
||||
console.log('强制停止TTS播放')
|
||||
|
||||
// 手动触发TTS状态变化事件,确保 UI 状态更新
|
||||
const event = new CustomEvent('tts-state-change', { detail: { isPlaying: false } })
|
||||
window.dispatchEvent(event)
|
||||
// 注意:不需要手动触发事件,因为在TTSService.stop()中已经触发了
|
||||
}
|
||||
|
||||
setPaused(paused: boolean) {
|
||||
|
||||
90
src/renderer/src/services/tts/AudioStreamProcessor.ts
Normal file
90
src/renderer/src/services/tts/AudioStreamProcessor.ts
Normal file
@ -0,0 +1,90 @@
|
||||
/**
|
||||
* 音频流处理器
|
||||
* 用于处理流式TTS的音频数据
|
||||
*/
|
||||
export class AudioStreamProcessor {
|
||||
private audioContext: AudioContext | null = null
|
||||
private audioQueue: Uint8Array[] = []
|
||||
private isProcessing: boolean = false
|
||||
|
||||
// 回调函数
|
||||
public onAudioBuffer: ((buffer: AudioBuffer) => void) | null = null
|
||||
|
||||
/**
|
||||
* 初始化音频处理器
|
||||
*/
|
||||
public async initialize(): Promise<void> {
|
||||
// 创建音频上下文
|
||||
this.audioContext = new AudioContext()
|
||||
this.audioQueue = []
|
||||
this.isProcessing = false
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理音频数据块
|
||||
* @param chunk 音频数据块
|
||||
*/
|
||||
public async processAudioChunk(chunk: Uint8Array): Promise<void> {
|
||||
if (!this.audioContext) {
|
||||
throw new Error('AudioStreamProcessor not initialized')
|
||||
}
|
||||
|
||||
// 将数据块添加到队列
|
||||
this.audioQueue.push(chunk)
|
||||
|
||||
// 如果没有正在处理,开始处理
|
||||
if (!this.isProcessing) {
|
||||
this.processQueue()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理队列中的音频数据
|
||||
*/
|
||||
private async processQueue(): Promise<void> {
|
||||
if (!this.audioContext || this.audioQueue.length === 0) {
|
||||
this.isProcessing = false
|
||||
return
|
||||
}
|
||||
|
||||
this.isProcessing = true
|
||||
|
||||
// 获取队列中的第一个数据块
|
||||
const chunk = this.audioQueue.shift()!
|
||||
|
||||
try {
|
||||
// 解码音频数据
|
||||
// 将SharedArrayBuffer转换为ArrayBuffer
|
||||
const arrayBuffer = chunk.buffer instanceof SharedArrayBuffer
|
||||
? new Uint8Array(chunk.buffer).buffer
|
||||
: chunk.buffer
|
||||
const audioBuffer = await this.audioContext.decodeAudioData(arrayBuffer)
|
||||
|
||||
// 调用回调函数
|
||||
if (this.onAudioBuffer) {
|
||||
this.onAudioBuffer(audioBuffer)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('解码音频数据失败:', error)
|
||||
}
|
||||
|
||||
// 继续处理队列中的下一个数据块
|
||||
this.processQueue()
|
||||
}
|
||||
|
||||
/**
|
||||
* 完成处理
|
||||
*/
|
||||
public async finish(): Promise<void> {
|
||||
// 等待队列处理完成
|
||||
while (this.audioQueue.length > 0) {
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
// 关闭音频上下文
|
||||
if (this.audioContext) {
|
||||
await this.audioContext.close()
|
||||
this.audioContext = null
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,9 @@ import { TTSServiceInterface } from './TTSServiceInterface'
|
||||
// 全局变量来跟踪当前正在播放的语音
|
||||
let currentUtterance: SpeechSynthesisUtterance | null = null
|
||||
|
||||
// 全局变量来跟踪是否正在播放
|
||||
export let isEdgeTTSPlaying = false
|
||||
|
||||
/**
|
||||
* Edge TTS服务实现类
|
||||
*/
|
||||
@ -50,10 +53,12 @@ export class EdgeTTSService implements TTSServiceInterface {
|
||||
if (currentUtterance) {
|
||||
currentUtterance = null
|
||||
}
|
||||
isEdgeTTSPlaying = false
|
||||
|
||||
// 创建语音合成器实例
|
||||
const utterance = new SpeechSynthesisUtterance(text)
|
||||
currentUtterance = utterance
|
||||
isEdgeTTSPlaying = true
|
||||
|
||||
// 获取可用的语音合成声音
|
||||
const voices = window.speechSynthesis.getVoices()
|
||||
@ -93,6 +98,7 @@ export class EdgeTTSService implements TTSServiceInterface {
|
||||
utterance.onend = () => {
|
||||
console.log('语音合成已结束')
|
||||
currentUtterance = null
|
||||
isEdgeTTSPlaying = false
|
||||
|
||||
// 分发一个自定义事件,通知语音合成已结束
|
||||
// 这样TTSService可以监听这个事件并重置播放状态
|
||||
@ -100,9 +106,14 @@ export class EdgeTTSService implements TTSServiceInterface {
|
||||
document.dispatchEvent(event)
|
||||
}
|
||||
|
||||
utterance.onerror = (event) => {
|
||||
console.error('语音合成错误:', event)
|
||||
utterance.onerror = (errorEvent) => {
|
||||
console.error('语音合成错误:', errorEvent)
|
||||
currentUtterance = null
|
||||
isEdgeTTSPlaying = false
|
||||
|
||||
// 在错误时也触发结束事件,确保状态更新
|
||||
const completeEvent = new CustomEvent('edgeTTSComplete', { detail: { text, error: true } })
|
||||
document.dispatchEvent(completeEvent)
|
||||
}
|
||||
|
||||
// 开始语音合成
|
||||
@ -147,6 +158,7 @@ export class EdgeTTSService implements TTSServiceInterface {
|
||||
|
||||
// 停止当前正在播放的语音
|
||||
window.speechSynthesis.cancel()
|
||||
isEdgeTTSPlaying = false
|
||||
|
||||
// 创建语音合成器实例
|
||||
const utterance = new SpeechSynthesisUtterance(text)
|
||||
|
||||
@ -14,6 +14,7 @@ export class TTSService {
|
||||
private static instance: TTSService
|
||||
private audioElement: HTMLAudioElement | null = null
|
||||
private isPlaying = false
|
||||
private playingServiceType: string | null = null
|
||||
|
||||
// 错误消息节流控制
|
||||
private lastErrorTime = 0
|
||||
@ -42,15 +43,34 @@ export class TTSService {
|
||||
|
||||
// 监听音频播放结束事件
|
||||
this.audioElement.addEventListener('ended', () => {
|
||||
this.isPlaying = false
|
||||
console.log('TTS播放结束')
|
||||
// 只有在非EdgeTTS服务时才直接更新状态
|
||||
if (this.playingServiceType !== 'edge') {
|
||||
this.updatePlayingState(false)
|
||||
console.log('TTS播放结束 (音频元素事件)')
|
||||
}
|
||||
})
|
||||
|
||||
// 监听浏览器TTS直接播放结束的自定义事件
|
||||
document.addEventListener('edgeTTSComplete', () => {
|
||||
console.log('收到浏览器TTS直接播放结束事件')
|
||||
this.isPlaying = false
|
||||
this.updatePlayingState(false)
|
||||
})
|
||||
|
||||
// 监听全局的speechSynthesis状态
|
||||
if ('speechSynthesis' in window) {
|
||||
// 创建一个定时器,定期检查speechSynthesis的状态
|
||||
setInterval(() => {
|
||||
// 只有在使用EdgeTTS且标记为正在播放时才检查
|
||||
if (this.isPlaying && this.playingServiceType === 'edge') {
|
||||
// 检查是否还在播放
|
||||
const isSpeaking = window.speechSynthesis.speaking;
|
||||
if (!isSpeaking) {
|
||||
console.log('检测到speechSynthesis不再播放,更新状态')
|
||||
this.updatePlayingState(false);
|
||||
}
|
||||
}
|
||||
}, 500); // 每500毫秒检查一次
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@ -82,6 +102,32 @@ export class TTSService {
|
||||
return this.speak(filteredText)
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新播放状态并触发事件
|
||||
* @param isPlaying 是否正在播放
|
||||
*/
|
||||
private updatePlayingState(isPlaying: boolean): void {
|
||||
// 只有状态变化时才更新和触发事件
|
||||
if (this.isPlaying !== isPlaying) {
|
||||
this.isPlaying = isPlaying;
|
||||
console.log(`TTS播放状态更新: ${isPlaying ? '开始播放' : '停止播放'}`)
|
||||
|
||||
// 触发自定义事件,通知其他组件TTS状态变化
|
||||
const event = new CustomEvent('tts-state-change', { detail: { isPlaying } })
|
||||
window.dispatchEvent(event)
|
||||
|
||||
// 如果停止播放,清除服务类型
|
||||
if (!isPlaying) {
|
||||
this.playingServiceType = null;
|
||||
|
||||
// 确保Web Speech API也停止
|
||||
if ('speechSynthesis' in window) {
|
||||
window.speechSynthesis.cancel();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放文本
|
||||
* @param text 要播放的文本
|
||||
@ -101,6 +147,8 @@ export class TTSService {
|
||||
// 如果正在播放,先停止
|
||||
if (this.isPlaying) {
|
||||
this.stop()
|
||||
// 添加短暂延迟,确保上一个播放完全停止
|
||||
await new Promise(resolve => setTimeout(resolve, 100))
|
||||
}
|
||||
|
||||
// 确保文本不为空
|
||||
@ -114,6 +162,8 @@ export class TTSService {
|
||||
const latestSettings = store.getState().settings
|
||||
const serviceType = latestSettings.ttsServiceType || 'openai'
|
||||
console.log('使用的TTS服务类型:', serviceType)
|
||||
// 记录当前使用的服务类型
|
||||
this.playingServiceType = serviceType
|
||||
console.log('当前TTS设置详情:', {
|
||||
ttsServiceType: serviceType,
|
||||
ttsEdgeVoice: latestSettings.ttsEdgeVoice,
|
||||
@ -161,7 +211,8 @@ export class TTSService {
|
||||
}
|
||||
})
|
||||
|
||||
this.isPlaying = true
|
||||
// 更新播放状态
|
||||
this.updatePlayingState(true)
|
||||
console.log('开始播放TTS音频')
|
||||
|
||||
// 释放URL对象
|
||||
@ -172,22 +223,10 @@ export class TTSService {
|
||||
const isEdgeTTS = serviceType === 'edge'
|
||||
const isSmallBlob = audioBlob.size < 100
|
||||
|
||||
// 如果是浏览器TTS直接播放,则等待当前语音合成结束
|
||||
if (isEdgeTTS && isSmallBlob) {
|
||||
// 检查全局变量中的当前语音合成状态
|
||||
// 如果还在播放,则不重置播放状态
|
||||
// 注意:这里我们无法直接访问 EdgeTTSService 中的 currentUtterance
|
||||
// 所以我们使用定时器来检查语音合成是否完成
|
||||
console.log('浏览器TTS直接播放中,等待语音合成结束')
|
||||
// 保持播放状态,直到语音合成结束
|
||||
// 使用定时器来检查语音合成是否完成
|
||||
// 大多数语音合成应该在几秒内完成
|
||||
setTimeout(() => {
|
||||
this.isPlaying = false
|
||||
console.log('浏览器TTS直接播放完成')
|
||||
}, 10000) // 10秒后自动重置状态
|
||||
} else {
|
||||
this.isPlaying = false
|
||||
// 对于非EdgeTTS服务,直接更新状态
|
||||
// EdgeTTS服务的状态更新由定时器和edgeTTSComplete事件处理
|
||||
if (!(isEdgeTTS && isSmallBlob)) {
|
||||
this.updatePlayingState(false)
|
||||
}
|
||||
}
|
||||
|
||||
@ -216,13 +255,17 @@ export class TTSService {
|
||||
if (this.audioElement) {
|
||||
this.audioElement.pause()
|
||||
this.audioElement.currentTime = 0
|
||||
this.isPlaying = false
|
||||
console.log('强制停止TTS播放')
|
||||
|
||||
// 触发自定义事件,通知其他组件TTS已停止
|
||||
const event = new CustomEvent('tts-state-change', { detail: { isPlaying: false } })
|
||||
window.dispatchEvent(event)
|
||||
}
|
||||
|
||||
// 如果是EdgeTTS,确保Web Speech API也停止
|
||||
if ('speechSynthesis' in window) {
|
||||
window.speechSynthesis.cancel()
|
||||
console.log('停止Web Speech API播放')
|
||||
}
|
||||
|
||||
// 更新状态并触发事件
|
||||
this.updatePlayingState(false)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@ -9,4 +9,15 @@ export interface TTSServiceInterface {
|
||||
* @returns 返回音频Blob对象的Promise
|
||||
*/
|
||||
synthesize(text: string): Promise<Blob>
|
||||
|
||||
/**
|
||||
* 流式合成语音 (可选实现)
|
||||
* @param text 要合成的文本
|
||||
* @param onStart 开始回调
|
||||
* @param onData 数据块回调
|
||||
* @param onEnd 结束回调
|
||||
* @param onError 错误回调
|
||||
* @returns 返回请求ID
|
||||
*/
|
||||
synthesizeStream?(text: string, onStart: () => void, onData: (audioChunk: AudioBuffer) => void, onEnd: () => void, onError: (error: Error) => void): Promise<string>
|
||||
}
|
||||
|
||||
8
temp.txt
Normal file
8
temp.txt
Normal file
@ -0,0 +1,8 @@
|
||||
// 不再自动清除回调函数,允许持续接收语音识别结果
|
||||
// setTimeout(() => {
|
||||
// // 发送重置命令,确保浏览器不会继续发送结果
|
||||
// ASRService.cancelRecording()
|
||||
//
|
||||
// // 清除ASRService中的回调函数,防止后续结果被处理
|
||||
// ASRService.resultCallback = null
|
||||
// }, 2000) // 2秒后强制取消,作为安全措施
|
||||
415
yarn.lock
415
yarn.lock
@ -3952,6 +3952,7 @@ __metadata:
|
||||
diff: "npm:^7.0.0"
|
||||
docx: "npm:^9.0.2"
|
||||
dotenv-cli: "npm:^7.4.2"
|
||||
edge-tts-node: "npm:^1.5.7"
|
||||
electron: "npm:31.7.6"
|
||||
electron-builder: "npm:^24.13.3"
|
||||
electron-devtools-installer: "npm:^3.2.0"
|
||||
@ -4439,6 +4440,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asn1.js@npm:^4.10.1":
|
||||
version: 4.10.1
|
||||
resolution: "asn1.js@npm:4.10.1"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.0.0"
|
||||
inherits: "npm:^2.0.1"
|
||||
minimalistic-assert: "npm:^1.0.0"
|
||||
checksum: 10c0/afa7f3ab9e31566c80175a75b182e5dba50589dcc738aa485be42bdd787e2a07246a4b034d481861123cbe646a7656f318f4f1cad2e9e5e808a210d5d6feaa88
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"asn1@npm:~0.2.3":
|
||||
version: 0.2.6
|
||||
resolution: "asn1@npm:0.2.6"
|
||||
@ -4520,7 +4532,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"axios@npm:^1.7.3, axios@npm:^1.7.7":
|
||||
"axios@npm:^1.5.0, axios@npm:^1.7.3, axios@npm:^1.7.7":
|
||||
version: 1.8.4
|
||||
resolution: "axios@npm:1.8.4"
|
||||
dependencies:
|
||||
@ -4678,6 +4690,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bn.js@npm:^4.0.0, bn.js@npm:^4.1.0, bn.js@npm:^4.11.9":
|
||||
version: 4.12.1
|
||||
resolution: "bn.js@npm:4.12.1"
|
||||
checksum: 10c0/b7f37a0cd5e4b79142b6f4292d518b416be34ae55d6dd6b0f66f96550c8083a50ffbbf8bda8d0ab471158cb81aa74ea4ee58fe33c7802e4a30b13810e98df116
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"bn.js@npm:^5.2.1":
|
||||
version: 5.2.1
|
||||
resolution: "bn.js@npm:5.2.1"
|
||||
checksum: 10c0/bed3d8bd34ec89dbcf9f20f88bd7d4a49c160fda3b561c7bb227501f974d3e435a48fb9b61bc3de304acab9215a3bda0803f7017ffb4d0016a0c3a740a283caa
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"body-parser@npm:^2.0.1":
|
||||
version: 2.1.0
|
||||
resolution: "body-parser@npm:2.1.0"
|
||||
@ -4730,6 +4756,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"brorand@npm:^1.0.1, brorand@npm:^1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "brorand@npm:1.1.0"
|
||||
checksum: 10c0/6f366d7c4990f82c366e3878492ba9a372a73163c09871e80d82fb4ae0d23f9f8924cb8a662330308206e6b3b76ba1d528b4601c9ef73c2166b440b2ea3b7571
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browser-image-compression@npm:^2.0.2":
|
||||
version: 2.0.2
|
||||
resolution: "browser-image-compression@npm:2.0.2"
|
||||
@ -4739,6 +4772,72 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-aes@npm:^1.0.4, browserify-aes@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "browserify-aes@npm:1.2.0"
|
||||
dependencies:
|
||||
buffer-xor: "npm:^1.0.3"
|
||||
cipher-base: "npm:^1.0.0"
|
||||
create-hash: "npm:^1.1.0"
|
||||
evp_bytestokey: "npm:^1.0.3"
|
||||
inherits: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.0.1"
|
||||
checksum: 10c0/967f2ae60d610b7b252a4cbb55a7a3331c78293c94b4dd9c264d384ca93354c089b3af9c0dd023534efdc74ffbc82510f7ad4399cf82bc37bc07052eea485f18
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-cipher@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "browserify-cipher@npm:1.0.1"
|
||||
dependencies:
|
||||
browserify-aes: "npm:^1.0.4"
|
||||
browserify-des: "npm:^1.0.0"
|
||||
evp_bytestokey: "npm:^1.0.0"
|
||||
checksum: 10c0/aa256dcb42bc53a67168bbc94ab85d243b0a3b56109dee3b51230b7d010d9b78985ffc1fb36e145c6e4db151f888076c1cfc207baf1525d3e375cbe8187fe27d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-des@npm:^1.0.0":
|
||||
version: 1.0.2
|
||||
resolution: "browserify-des@npm:1.0.2"
|
||||
dependencies:
|
||||
cipher-base: "npm:^1.0.1"
|
||||
des.js: "npm:^1.0.0"
|
||||
inherits: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.1.2"
|
||||
checksum: 10c0/943eb5d4045eff80a6cde5be4e5fbb1f2d5002126b5a4789c3c1aae3cdddb1eb92b00fb92277f512288e5c6af330730b1dbabcf7ce0923e749e151fcee5a074d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-rsa@npm:^4.0.0, browserify-rsa@npm:^4.1.0":
|
||||
version: 4.1.1
|
||||
resolution: "browserify-rsa@npm:4.1.1"
|
||||
dependencies:
|
||||
bn.js: "npm:^5.2.1"
|
||||
randombytes: "npm:^2.1.0"
|
||||
safe-buffer: "npm:^5.2.1"
|
||||
checksum: 10c0/b650ee1192e3d7f3d779edc06dd96ed8720362e72ac310c367b9d7fe35f7e8dbb983c1829142b2b3215458be8bf17c38adc7224920843024ed8cf39e19c513c0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserify-sign@npm:^4.2.3":
|
||||
version: 4.2.3
|
||||
resolution: "browserify-sign@npm:4.2.3"
|
||||
dependencies:
|
||||
bn.js: "npm:^5.2.1"
|
||||
browserify-rsa: "npm:^4.1.0"
|
||||
create-hash: "npm:^1.2.0"
|
||||
create-hmac: "npm:^1.1.7"
|
||||
elliptic: "npm:^6.5.5"
|
||||
hash-base: "npm:~3.0"
|
||||
inherits: "npm:^2.0.4"
|
||||
parse-asn1: "npm:^5.1.7"
|
||||
readable-stream: "npm:^2.3.8"
|
||||
safe-buffer: "npm:^5.2.1"
|
||||
checksum: 10c0/30c0eba3f5970a20866a4d3fbba2c5bd1928cd24f47faf995f913f1499214c6f3be14bb4d6ec1ab5c6cafb1eca9cb76ba1c2e1c04ed018370634d4e659c77216
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"browserslist@npm:^4.21.1, browserslist@npm:^4.24.0":
|
||||
version: 4.24.4
|
||||
resolution: "browserslist@npm:4.24.4"
|
||||
@ -4812,6 +4911,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"buffer-xor@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "buffer-xor@npm:1.0.3"
|
||||
checksum: 10c0/fd269d0e0bf71ecac3146187cfc79edc9dbb054e2ee69b4d97dfb857c6d997c33de391696d04bdd669272751fa48e7872a22f3a6c7b07d6c0bc31dbe02a4075c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"buffer@npm:^5.1.0, buffer@npm:^5.2.0, buffer@npm:^5.2.1, buffer@npm:^5.5.0":
|
||||
version: 5.7.1
|
||||
resolution: "buffer@npm:5.7.1"
|
||||
@ -5209,6 +5315,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cipher-base@npm:^1.0.0, cipher-base@npm:^1.0.1, cipher-base@npm:^1.0.3":
|
||||
version: 1.0.6
|
||||
resolution: "cipher-base@npm:1.0.6"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.4"
|
||||
safe-buffer: "npm:^5.2.1"
|
||||
checksum: 10c0/f73268e0ee6585800875d9748f2a2377ae7c2c3375cba346f75598ac6f6bc3a25dec56e984a168ced1a862529ffffe615363f750c40349039d96bd30fba0fca8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"classcat@npm:^5.0.3":
|
||||
version: 5.0.5
|
||||
resolution: "classcat@npm:5.0.5"
|
||||
@ -5601,6 +5717,43 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"create-ecdh@npm:^4.0.4":
|
||||
version: 4.0.4
|
||||
resolution: "create-ecdh@npm:4.0.4"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.1.0"
|
||||
elliptic: "npm:^6.5.3"
|
||||
checksum: 10c0/77b11a51360fec9c3bce7a76288fc0deba4b9c838d5fb354b3e40c59194d23d66efe6355fd4b81df7580da0661e1334a235a2a5c040b7569ba97db428d466e7f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"create-hash@npm:^1.1.0, create-hash@npm:^1.1.2, create-hash@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "create-hash@npm:1.2.0"
|
||||
dependencies:
|
||||
cipher-base: "npm:^1.0.1"
|
||||
inherits: "npm:^2.0.1"
|
||||
md5.js: "npm:^1.3.4"
|
||||
ripemd160: "npm:^2.0.1"
|
||||
sha.js: "npm:^2.4.0"
|
||||
checksum: 10c0/d402e60e65e70e5083cb57af96d89567954d0669e90550d7cec58b56d49c4b193d35c43cec8338bc72358198b8cbf2f0cac14775b651e99238e1cf411490f915
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"create-hmac@npm:^1.1.4, create-hmac@npm:^1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "create-hmac@npm:1.1.7"
|
||||
dependencies:
|
||||
cipher-base: "npm:^1.0.3"
|
||||
create-hash: "npm:^1.1.0"
|
||||
inherits: "npm:^2.0.1"
|
||||
ripemd160: "npm:^2.0.0"
|
||||
safe-buffer: "npm:^5.0.1"
|
||||
sha.js: "npm:^2.4.8"
|
||||
checksum: 10c0/24332bab51011652a9a0a6d160eed1e8caa091b802335324ae056b0dcb5acbc9fcf173cf10d128eba8548c3ce98dfa4eadaa01bd02f44a34414baee26b651835
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6":
|
||||
version: 7.0.6
|
||||
resolution: "cross-spawn@npm:7.0.6"
|
||||
@ -5619,6 +5772,26 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"crypto-browserify@npm:^3.12.0":
|
||||
version: 3.12.1
|
||||
resolution: "crypto-browserify@npm:3.12.1"
|
||||
dependencies:
|
||||
browserify-cipher: "npm:^1.0.1"
|
||||
browserify-sign: "npm:^4.2.3"
|
||||
create-ecdh: "npm:^4.0.4"
|
||||
create-hash: "npm:^1.2.0"
|
||||
create-hmac: "npm:^1.1.7"
|
||||
diffie-hellman: "npm:^5.0.3"
|
||||
hash-base: "npm:~3.0.4"
|
||||
inherits: "npm:^2.0.4"
|
||||
pbkdf2: "npm:^3.1.2"
|
||||
public-encrypt: "npm:^4.0.3"
|
||||
randombytes: "npm:^2.1.0"
|
||||
randomfill: "npm:^1.0.4"
|
||||
checksum: 10c0/184a2def7b16628e79841243232ab5497f18d8e158ac21b7ce90ab172427d0a892a561280adc08f9d4d517bce8db2a5b335dc21abb970f787f8e874bd7b9db7d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"css-box-model@npm:^1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "css-box-model@npm:1.2.1"
|
||||
@ -6078,6 +6251,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"des.js@npm:^1.0.0":
|
||||
version: 1.1.0
|
||||
resolution: "des.js@npm:1.1.0"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.1"
|
||||
minimalistic-assert: "npm:^1.0.0"
|
||||
checksum: 10c0/671354943ad67493e49eb4c555480ab153edd7cee3a51c658082fcde539d2690ed2a4a0b5d1f401f9cde822edf3939a6afb2585f32c091f2d3a1b1665cd45236
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"destroy@npm:^1.2.0":
|
||||
version: 1.2.0
|
||||
resolution: "destroy@npm:1.2.0"
|
||||
@ -6149,6 +6332,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"diffie-hellman@npm:^5.0.3":
|
||||
version: 5.0.3
|
||||
resolution: "diffie-hellman@npm:5.0.3"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.1.0"
|
||||
miller-rabin: "npm:^4.0.0"
|
||||
randombytes: "npm:^2.0.0"
|
||||
checksum: 10c0/ce53ccafa9ca544b7fc29b08a626e23a9b6562efc2a98559a0c97b4718937cebaa9b5d7d0a05032cc9c1435e9b3c1532b9e9bf2e0ede868525922807ad6e1ecf
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"dingbat-to-unicode@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "dingbat-to-unicode@npm:1.0.1"
|
||||
@ -6383,6 +6577,22 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"edge-tts-node@npm:^1.5.7":
|
||||
version: 1.5.7
|
||||
resolution: "edge-tts-node@npm:1.5.7"
|
||||
dependencies:
|
||||
axios: "npm:^1.5.0"
|
||||
buffer: "npm:^6.0.3"
|
||||
crypto-browserify: "npm:^3.12.0"
|
||||
isomorphic-ws: "npm:^5.0.0"
|
||||
process: "npm:^0.11.10"
|
||||
randombytes: "npm:^2.1.0"
|
||||
stream-browserify: "npm:^3.0.0"
|
||||
ws: "npm:^8.14.1"
|
||||
checksum: 10c0/83b5df1d5312163006643fb6e6a9ca37ca6bc4c871b66f0c800f3e0bb1b2473fa0d67c125b256e2d93b493b8fbf59aaab06f60d4fa15fe3b7e2d3fb796016b1f
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ee-first@npm:1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "ee-first@npm:1.1.1"
|
||||
@ -6548,6 +6758,21 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"elliptic@npm:^6.5.3, elliptic@npm:^6.5.5":
|
||||
version: 6.6.1
|
||||
resolution: "elliptic@npm:6.6.1"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.11.9"
|
||||
brorand: "npm:^1.1.0"
|
||||
hash.js: "npm:^1.0.0"
|
||||
hmac-drbg: "npm:^1.0.1"
|
||||
inherits: "npm:^2.0.4"
|
||||
minimalistic-assert: "npm:^1.0.1"
|
||||
minimalistic-crypto-utils: "npm:^1.0.1"
|
||||
checksum: 10c0/8b24ef782eec8b472053793ea1e91ae6bee41afffdfcb78a81c0a53b191e715cbe1292aa07165958a9bbe675bd0955142560b1a007ffce7d6c765bcaf951a867
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"emittery@npm:^1.0.3":
|
||||
version: 1.1.0
|
||||
resolution: "emittery@npm:1.1.0"
|
||||
@ -7304,6 +7529,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"evp_bytestokey@npm:^1.0.0, evp_bytestokey@npm:^1.0.3":
|
||||
version: 1.0.3
|
||||
resolution: "evp_bytestokey@npm:1.0.3"
|
||||
dependencies:
|
||||
md5.js: "npm:^1.3.4"
|
||||
node-gyp: "npm:latest"
|
||||
safe-buffer: "npm:^5.1.1"
|
||||
checksum: 10c0/77fbe2d94a902a80e9b8f5a73dcd695d9c14899c5e82967a61b1fc6cbbb28c46552d9b127cff47c45fcf684748bdbcfa0a50410349109de87ceb4b199ef6ee99
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"execa@npm:^8.0.1":
|
||||
version: 8.0.1
|
||||
resolution: "execa@npm:8.0.1"
|
||||
@ -8480,7 +8716,28 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hash.js@npm:^1.1.7":
|
||||
"hash-base@npm:^3.0.0":
|
||||
version: 3.1.0
|
||||
resolution: "hash-base@npm:3.1.0"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.4"
|
||||
readable-stream: "npm:^3.6.0"
|
||||
safe-buffer: "npm:^5.2.0"
|
||||
checksum: 10c0/663eabcf4173326fbb65a1918a509045590a26cc7e0964b754eef248d281305c6ec9f6b31cb508d02ffca383ab50028180ce5aefe013e942b44a903ac8dc80d0
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hash-base@npm:~3.0, hash-base@npm:~3.0.4":
|
||||
version: 3.0.5
|
||||
resolution: "hash-base@npm:3.0.5"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.4"
|
||||
safe-buffer: "npm:^5.2.1"
|
||||
checksum: 10c0/6dc185b79bad9b6d525cd132a588e4215380fdc36fec6f7a8a58c5db8e3b642557d02ad9c367f5e476c7c3ad3ccffa3607f308b124e1ed80e3b80a1b254db61e
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hash.js@npm:^1.0.0, hash.js@npm:^1.0.3, hash.js@npm:^1.1.7":
|
||||
version: 1.1.7
|
||||
resolution: "hash.js@npm:1.1.7"
|
||||
dependencies:
|
||||
@ -8704,6 +8961,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hmac-drbg@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "hmac-drbg@npm:1.0.1"
|
||||
dependencies:
|
||||
hash.js: "npm:^1.0.3"
|
||||
minimalistic-assert: "npm:^1.0.0"
|
||||
minimalistic-crypto-utils: "npm:^1.0.1"
|
||||
checksum: 10c0/f3d9ba31b40257a573f162176ac5930109816036c59a09f901eb2ffd7e5e705c6832bedfff507957125f2086a0ab8f853c0df225642a88bf1fcaea945f20600d
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2":
|
||||
version: 3.3.2
|
||||
resolution: "hoist-non-react-statics@npm:3.3.2"
|
||||
@ -9073,7 +9341,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3":
|
||||
"inherits@npm:2, inherits@npm:2.0.4, inherits@npm:^2.0.1, inherits@npm:^2.0.3, inherits@npm:^2.0.4, inherits@npm:~2.0.3, inherits@npm:~2.0.4":
|
||||
version: 2.0.4
|
||||
resolution: "inherits@npm:2.0.4"
|
||||
checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
|
||||
@ -9441,6 +9709,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"isomorphic-ws@npm:^5.0.0":
|
||||
version: 5.0.0
|
||||
resolution: "isomorphic-ws@npm:5.0.0"
|
||||
peerDependencies:
|
||||
ws: "*"
|
||||
checksum: 10c0/a058ac8b5e6efe9e46252cb0bc67fd325005d7216451d1a51238bc62d7da8486f828ef017df54ddf742e0fffcbe4b1bcc2a66cc115b027ed0180334cd18df252
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"isstream@npm:~0.1.2":
|
||||
version: 0.1.2
|
||||
resolution: "isstream@npm:0.1.2"
|
||||
@ -10372,6 +10649,17 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"md5.js@npm:^1.3.4":
|
||||
version: 1.3.5
|
||||
resolution: "md5.js@npm:1.3.5"
|
||||
dependencies:
|
||||
hash-base: "npm:^3.0.0"
|
||||
inherits: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.1.2"
|
||||
checksum: 10c0/b7bd75077f419c8e013fc4d4dada48be71882e37d69a44af65a2f2804b91e253441eb43a0614423a1c91bb830b8140b0dc906bc797245e2e275759584f4efcc5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"md5@npm:^2.3.0":
|
||||
version: 2.3.0
|
||||
resolution: "md5@npm:2.3.0"
|
||||
@ -11288,6 +11576,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"miller-rabin@npm:^4.0.0":
|
||||
version: 4.0.1
|
||||
resolution: "miller-rabin@npm:4.0.1"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.0.0"
|
||||
brorand: "npm:^1.0.1"
|
||||
bin:
|
||||
miller-rabin: bin/miller-rabin
|
||||
checksum: 10c0/26b2b96f6e49dbcff7faebb78708ed2f5f9ae27ac8cbbf1d7c08f83cf39bed3d418c0c11034dce997da70d135cc0ff6f3a4c15dc452f8e114c11986388a64346
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"mime-db@npm:1.52.0":
|
||||
version: 1.52.0
|
||||
resolution: "mime-db@npm:1.52.0"
|
||||
@ -11405,13 +11705,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimalistic-assert@npm:^1.0.1":
|
||||
"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "minimalistic-assert@npm:1.0.1"
|
||||
checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimalistic-crypto-utils@npm:^1.0.1":
|
||||
version: 1.0.1
|
||||
resolution: "minimalistic-crypto-utils@npm:1.0.1"
|
||||
checksum: 10c0/790ecec8c5c73973a4fbf2c663d911033e8494d5fb0960a4500634766ab05d6107d20af896ca2132e7031741f19888154d44b2408ada0852446705441383e9f8
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "minimatch@npm:3.1.2"
|
||||
@ -12473,6 +12780,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-asn1@npm:^5.0.0, parse-asn1@npm:^5.1.7":
|
||||
version: 5.1.7
|
||||
resolution: "parse-asn1@npm:5.1.7"
|
||||
dependencies:
|
||||
asn1.js: "npm:^4.10.1"
|
||||
browserify-aes: "npm:^1.2.0"
|
||||
evp_bytestokey: "npm:^1.0.3"
|
||||
hash-base: "npm:~3.0"
|
||||
pbkdf2: "npm:^3.1.2"
|
||||
safe-buffer: "npm:^5.2.1"
|
||||
checksum: 10c0/05eb5937405c904eb5a7f3633bab1acc11f4ae3478a07ef5c6d81ce88c3c0e505ff51f9c7b935ebc1265c868343793698fc91025755a895d0276f620f95e8a82
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"parse-bmfont-ascii@npm:^1.0.3":
|
||||
version: 1.0.6
|
||||
resolution: "parse-bmfont-ascii@npm:1.0.6"
|
||||
@ -12661,6 +12982,19 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pbkdf2@npm:^3.1.2":
|
||||
version: 3.1.2
|
||||
resolution: "pbkdf2@npm:3.1.2"
|
||||
dependencies:
|
||||
create-hash: "npm:^1.1.2"
|
||||
create-hmac: "npm:^1.1.4"
|
||||
ripemd160: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.0.1"
|
||||
sha.js: "npm:^2.4.8"
|
||||
checksum: 10c0/5a30374e87d33fa080a92734d778cf172542cc7e41b96198c4c88763997b62d7850de3fbda5c3111ddf79805ee7c1da7046881c90ac4920b5e324204518b05fd
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pdf-parse@npm:1.1.1":
|
||||
version: 1.1.1
|
||||
resolution: "pdf-parse@npm:1.1.1"
|
||||
@ -13054,6 +13388,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"public-encrypt@npm:^4.0.3":
|
||||
version: 4.0.3
|
||||
resolution: "public-encrypt@npm:4.0.3"
|
||||
dependencies:
|
||||
bn.js: "npm:^4.1.0"
|
||||
browserify-rsa: "npm:^4.0.0"
|
||||
create-hash: "npm:^1.1.0"
|
||||
parse-asn1: "npm:^5.0.0"
|
||||
randombytes: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.1.2"
|
||||
checksum: 10c0/6c2cc19fbb554449e47f2175065d6b32f828f9b3badbee4c76585ac28ae8641aafb9bb107afc430c33c5edd6b05dbe318df4f7d6d7712b1093407b11c4280700
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"pump@npm:^3.0.0":
|
||||
version: 3.0.2
|
||||
resolution: "pump@npm:3.0.2"
|
||||
@ -13138,6 +13486,25 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"randombytes@npm:^2.0.0, randombytes@npm:^2.0.1, randombytes@npm:^2.0.5, randombytes@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "randombytes@npm:2.1.0"
|
||||
dependencies:
|
||||
safe-buffer: "npm:^5.1.0"
|
||||
checksum: 10c0/50395efda7a8c94f5dffab564f9ff89736064d32addf0cc7e8bf5e4166f09f8ded7a0849ca6c2d2a59478f7d90f78f20d8048bca3cdf8be09d8e8a10790388f3
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"randomfill@npm:^1.0.4":
|
||||
version: 1.0.4
|
||||
resolution: "randomfill@npm:1.0.4"
|
||||
dependencies:
|
||||
randombytes: "npm:^2.0.5"
|
||||
safe-buffer: "npm:^5.1.0"
|
||||
checksum: 10c0/11aeed35515872e8f8a2edec306734e6b74c39c46653607f03c68385ab8030e2adcc4215f76b5e4598e028c4750d820afd5c65202527d831d2a5f207fe2bc87c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1":
|
||||
version: 1.2.1
|
||||
resolution: "range-parser@npm:1.2.1"
|
||||
@ -13925,7 +14292,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"readable-stream@npm:3, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.6.0":
|
||||
"readable-stream@npm:3, readable-stream@npm:^3.1.1, readable-stream@npm:^3.4.0, readable-stream@npm:^3.5.0, readable-stream@npm:^3.6.0":
|
||||
version: 3.6.2
|
||||
resolution: "readable-stream@npm:3.6.2"
|
||||
dependencies:
|
||||
@ -13936,7 +14303,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"readable-stream@npm:^2.0.6, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5, readable-stream@npm:~2.3.6":
|
||||
"readable-stream@npm:^2.0.6, readable-stream@npm:^2.2.2, readable-stream@npm:^2.3.0, readable-stream@npm:^2.3.5, readable-stream@npm:^2.3.8, readable-stream@npm:~2.3.6":
|
||||
version: 2.3.8
|
||||
resolution: "readable-stream@npm:2.3.8"
|
||||
dependencies:
|
||||
@ -14416,6 +14783,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ripemd160@npm:^2.0.0, ripemd160@npm:^2.0.1":
|
||||
version: 2.0.2
|
||||
resolution: "ripemd160@npm:2.0.2"
|
||||
dependencies:
|
||||
hash-base: "npm:^3.0.0"
|
||||
inherits: "npm:^2.0.1"
|
||||
checksum: 10c0/f6f0df78817e78287c766687aed4d5accbebc308a8e7e673fb085b9977473c1f139f0c5335d353f172a915bb288098430755d2ad3c4f30612f4dd0c901cd2c3a
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"roarr@npm:^2.15.3":
|
||||
version: 2.15.4
|
||||
resolution: "roarr@npm:2.15.4"
|
||||
@ -14551,7 +14928,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0":
|
||||
"safe-buffer@npm:5.2.1, safe-buffer@npm:^5.0.1, safe-buffer@npm:^5.1.0, safe-buffer@npm:^5.1.1, safe-buffer@npm:^5.1.2, safe-buffer@npm:^5.2.0, safe-buffer@npm:^5.2.1, safe-buffer@npm:~5.2.0":
|
||||
version: 5.2.1
|
||||
resolution: "safe-buffer@npm:5.2.1"
|
||||
checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3
|
||||
@ -14747,6 +15124,18 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"sha.js@npm:^2.4.0, sha.js@npm:^2.4.8":
|
||||
version: 2.4.11
|
||||
resolution: "sha.js@npm:2.4.11"
|
||||
dependencies:
|
||||
inherits: "npm:^2.0.1"
|
||||
safe-buffer: "npm:^5.0.1"
|
||||
bin:
|
||||
sha.js: ./bin.js
|
||||
checksum: 10c0/b7a371bca8821c9cc98a0aeff67444a03d48d745cb103f17228b96793f455f0eb0a691941b89ea1e60f6359207e36081d9be193252b0f128e0daf9cfea2815a5
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"shallowequal@npm:1.1.0":
|
||||
version: 1.1.0
|
||||
resolution: "shallowequal@npm:1.1.0"
|
||||
@ -15135,6 +15524,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stream-browserify@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "stream-browserify@npm:3.0.0"
|
||||
dependencies:
|
||||
inherits: "npm:~2.0.4"
|
||||
readable-stream: "npm:^3.5.0"
|
||||
checksum: 10c0/ec3b975a4e0aa4b3dc5e70ffae3fc8fd29ac725353a14e72f213dff477b00330140ad014b163a8cbb9922dfe90803f81a5ea2b269e1bbfd8bd71511b88f889ad
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"stream-head@npm:^3.0.0":
|
||||
version: 3.0.0
|
||||
resolution: "stream-head@npm:3.0.0"
|
||||
@ -16670,7 +17069,7 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"ws@npm:^8.13.0, ws@npm:^8.18.0":
|
||||
"ws@npm:^8.13.0, ws@npm:^8.14.1, ws@npm:^8.18.0":
|
||||
version: 8.18.1
|
||||
resolution: "ws@npm:8.18.1"
|
||||
peerDependencies:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user