mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2026-01-03 11:19:10 +08:00
添加了 TTS 相关服务并更新了设置
This commit is contained in:
parent
e0531ca5b6
commit
42c38b73ce
@ -3,6 +3,8 @@ productName: Cherry Studio
|
|||||||
directories:
|
directories:
|
||||||
buildResources: build
|
buildResources: build
|
||||||
files:
|
files:
|
||||||
|
- out/**/*
|
||||||
|
- package.json
|
||||||
- '!{.vscode,.yarn,.github}'
|
- '!{.vscode,.yarn,.github}'
|
||||||
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
- '!electron.vite.config.{js,ts,mjs,cjs}'
|
||||||
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
- '!{.eslintignore,.eslintrc.cjs,.prettierignore,.prettierrc.yaml,dev-app-update.yml,CHANGELOG.md,README.md}'
|
||||||
|
|||||||
@ -76,6 +76,7 @@
|
|||||||
"color": "^5.0.0",
|
"color": "^5.0.0",
|
||||||
"diff": "^7.0.0",
|
"diff": "^7.0.0",
|
||||||
"docx": "^9.0.2",
|
"docx": "^9.0.2",
|
||||||
|
"edge-tts-node": "^1.5.7",
|
||||||
"electron-log": "^5.1.5",
|
"electron-log": "^5.1.5",
|
||||||
"electron-store": "^8.2.0",
|
"electron-store": "^8.2.0",
|
||||||
"electron-updater": "^6.3.9",
|
"electron-updater": "^6.3.9",
|
||||||
|
|||||||
@ -25,6 +25,9 @@ export enum IpcChannel {
|
|||||||
// MsTTS
|
// MsTTS
|
||||||
MsTTS_GetVoices = 'mstts:get-voices',
|
MsTTS_GetVoices = 'mstts:get-voices',
|
||||||
MsTTS_Synthesize = 'mstts:synthesize',
|
MsTTS_Synthesize = 'mstts:synthesize',
|
||||||
|
MsTTS_SynthesizeStream = 'mstts:synthesize-stream',
|
||||||
|
MsTTS_StreamData = 'mstts:stream-data',
|
||||||
|
MsTTS_StreamEnd = 'mstts:stream-end',
|
||||||
|
|
||||||
// Open
|
// Open
|
||||||
Open_Path = 'open:path',
|
Open_Path = 'open:path',
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import { IpcChannel } from '@shared/IpcChannel'
|
import { IpcChannel } from '@shared/IpcChannel'
|
||||||
import { ipcMain } from 'electron'
|
import { BrowserWindow, ipcMain } from 'electron'
|
||||||
|
|
||||||
import * as MsTTSService from './MsTTSService'
|
import * as MsTTSService from './MsTTSService'
|
||||||
|
|
||||||
@ -14,4 +14,34 @@ export function registerMsTTSIpcHandlers(): void {
|
|||||||
ipcMain.handle(IpcChannel.MsTTS_Synthesize, (_, text: string, voice: string, outputFormat: string) =>
|
ipcMain.handle(IpcChannel.MsTTS_Synthesize, (_, text: string, voice: string, outputFormat: string) =>
|
||||||
MsTTSService.synthesize(text, voice, outputFormat)
|
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 { app } from 'electron'
|
||||||
import log from 'electron-log'
|
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 ---
|
// --- START OF HARDCODED VOICE LIST ---
|
||||||
// WARNING: This list is static and may become outdated.
|
// WARNING: This list is static and may become outdated.
|
||||||
@ -437,6 +438,77 @@ class MsTTSService {
|
|||||||
return MsTTSService.instance
|
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 语音列表
|
* @returns 语音列表
|
||||||
@ -556,6 +628,16 @@ export const synthesize = async (text: string, voice: string, outputFormat: stri
|
|||||||
return await MsTTSService.getInstance().synthesize(text, voice, outputFormat)
|
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 () => {
|
export const cleanupTtsTempFiles = async () => {
|
||||||
await MsTTSService.getInstance().cleanupTempDir()
|
await MsTTSService.getInstance().cleanupTempDir()
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import { useTranslation } from 'react-i18next'
|
|||||||
import styled from 'styled-components'
|
import styled from 'styled-components'
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
onTranscribed: (text: string) => void
|
onTranscribed: (text: string, isFinal?: boolean) => void
|
||||||
disabled?: boolean
|
disabled?: boolean
|
||||||
style?: React.CSSProperties
|
style?: React.CSSProperties
|
||||||
}
|
}
|
||||||
@ -33,7 +33,7 @@ const ASRButton: FC<Props> = ({ onTranscribed, disabled = false, style }) => {
|
|||||||
try {
|
try {
|
||||||
// 添加事件监听器,监听服务器发送的stopped消息
|
// 添加事件监听器,监听服务器发送的stopped消息
|
||||||
const originalCallback = ASRService.resultCallback
|
const originalCallback = ASRService.resultCallback
|
||||||
const stopCallback = (text: string) => {
|
const stopCallback = (text: string, isFinal?: boolean) => {
|
||||||
// 如果是空字符串,只重置状态,不调用原始回调
|
// 如果是空字符串,只重置状态,不调用原始回调
|
||||||
if (text === '') {
|
if (text === '') {
|
||||||
setIsProcessing(false)
|
setIsProcessing(false)
|
||||||
|
|||||||
@ -2,7 +2,7 @@ import { SoundOutlined } from '@ant-design/icons'
|
|||||||
import TTSService from '@renderer/services/TTSService'
|
import TTSService from '@renderer/services/TTSService'
|
||||||
import { Message } from '@renderer/types'
|
import { Message } from '@renderer/types'
|
||||||
import { Button, Tooltip } from 'antd'
|
import { Button, Tooltip } from 'antd'
|
||||||
import { useCallback, useState } from 'react'
|
import { useCallback, useEffect, useState } from 'react'
|
||||||
import { useTranslation } from 'react-i18next'
|
import { useTranslation } from 'react-i18next'
|
||||||
|
|
||||||
interface TTSButtonProps {
|
interface TTSButtonProps {
|
||||||
@ -14,38 +14,45 @@ const TTSButton: React.FC<TTSButtonProps> = ({ message, className }) => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [isSpeaking, setIsSpeaking] = useState(false)
|
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 () => {
|
const handleTTS = useCallback(async () => {
|
||||||
if (isSpeaking) {
|
if (isSpeaking) {
|
||||||
TTSService.stop()
|
TTSService.stop()
|
||||||
setIsSpeaking(false)
|
return // 不需要手动设置状态,事件监听器会处理
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setIsSpeaking(true)
|
|
||||||
try {
|
try {
|
||||||
console.log('点击TTS按钮,开始播放消息')
|
console.log('点击TTS按钮,开始播放消息')
|
||||||
await TTSService.speakFromMessage(message)
|
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) {
|
} catch (error) {
|
||||||
console.error('TTS error:', error)
|
console.error('TTS error:', error)
|
||||||
|
// 出错时才需要手动重置状态
|
||||||
setIsSpeaking(false)
|
setIsSpeaking(false)
|
||||||
}
|
}
|
||||||
}, [isSpeaking, message])
|
}, [isSpeaking, message])
|
||||||
|
|||||||
@ -77,6 +77,7 @@ let _files: FileType[] = []
|
|||||||
|
|
||||||
const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) => {
|
const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) => {
|
||||||
const [text, setText] = useState(_text)
|
const [text, setText] = useState(_text)
|
||||||
|
const [asrCurrentText, setAsrCurrentText] = useState('')
|
||||||
const [inputFocus, setInputFocus] = useState(false)
|
const [inputFocus, setInputFocus] = useState(false)
|
||||||
const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id)
|
const { assistant, addTopic, model, setModel, updateAssistant } = useAssistant(_assistant.id)
|
||||||
const {
|
const {
|
||||||
@ -787,18 +788,40 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是语音通话消息,创建一个新的助手对象,并设置模型
|
// 如果是语音通话消息,创建一个新的助手对象,并设置模型和提示词
|
||||||
let assistantToUse = assistant
|
let assistantToUse = assistant
|
||||||
if ((data.isVoiceCall || data.useVoiceCallModel) && userMessage.model) {
|
if (data.isVoiceCall || data.useVoiceCallModel) {
|
||||||
// 创建一个新的助手对象,以避免修改原始助手
|
// 创建一个新的助手对象,以避免修改原始助手
|
||||||
assistantToUse = { ...assistant }
|
assistantToUse = { ...assistant }
|
||||||
|
|
||||||
// 设置助手的模型为语音通话专用模型
|
// 如果有语音通话专用模型,设置助手的模型
|
||||||
assistantToUse.model = userMessage.model
|
if (userMessage.model) {
|
||||||
console.log(
|
assistantToUse.model = userMessage.model
|
||||||
'为语音通话消息创建了新的助手对象,并设置了模型:',
|
console.log(
|
||||||
userMessage.model.name || userMessage.model.id
|
'为语音通话消息创建了新的助手对象,并设置了模型:',
|
||||||
)
|
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
|
// 分发发送消息的action
|
||||||
@ -806,6 +829,8 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
|
|
||||||
// 清空输入框
|
// 清空输入框
|
||||||
setText('')
|
setText('')
|
||||||
|
// 重置语音识别状态
|
||||||
|
setAsrCurrentText('')
|
||||||
|
|
||||||
console.log('已触发发送消息事件')
|
console.log('已触发发送消息事件')
|
||||||
}, 300)
|
}, 300)
|
||||||
@ -1121,18 +1146,28 @@ const Inputbar: FC<Props> = ({ assistant: _assistant, setActiveTopic, topic }) =
|
|||||||
<ToolbarMenu>
|
<ToolbarMenu>
|
||||||
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
|
<TranslateButton text={text} onTranslated={onTranslated} isLoading={isTranslating} />
|
||||||
<ASRButton
|
<ASRButton
|
||||||
onTranscribed={(transcribedText) => {
|
onTranscribed={(transcribedText, isFinal) => {
|
||||||
// 如果是空字符串,不做任何处理
|
// 如果是空字符串,不做任何处理
|
||||||
if (!transcribedText) return
|
if (!transcribedText) return
|
||||||
|
|
||||||
// 将识别的文本添加到当前输入框
|
if (isFinal) {
|
||||||
setText((prevText) => {
|
// 最终结果,添加到输入框中
|
||||||
// 如果当前有文本,添加空格后再添加识别的文本
|
setText((prevText) => {
|
||||||
if (prevText.trim()) {
|
// 如果当前输入框为空,直接设置为识别的文本
|
||||||
|
if (!prevText.trim()) {
|
||||||
|
return transcribedText
|
||||||
|
}
|
||||||
|
|
||||||
|
// 否则,添加识别的文本到输入框中,用空格分隔
|
||||||
return prevText + ' ' + transcribedText
|
return prevText + ' ' + transcribedText
|
||||||
}
|
})
|
||||||
return transcribedText
|
|
||||||
})
|
// 清除当前识别的文本
|
||||||
|
setAsrCurrentText('')
|
||||||
|
} else {
|
||||||
|
// 中间结果,保存到状态变量中,但不更新输入框
|
||||||
|
setAsrCurrentText(transcribedText)
|
||||||
|
}
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<VoiceCallButton disabled={loading} />
|
<VoiceCallButton disabled={loading} />
|
||||||
|
|||||||
@ -153,15 +153,20 @@ const MessageItem: FC<Props> = ({
|
|||||||
|
|
||||||
// 自动播放TTS的逻辑
|
// 自动播放TTS的逻辑
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// 如果是最后一条助手消息,且消息状态为成功,且不是正在生成中,且TTS已启用,且语音通话窗口已打开
|
// 如果是最后一条助手消息,且消息状态为成功,且不是正在生成中,且TTS已启用
|
||||||
|
// 注意:只有在语音通话窗口打开时才自动播放TTS
|
||||||
if (
|
if (
|
||||||
isLastMessage &&
|
isLastMessage &&
|
||||||
isAssistantMessage &&
|
isAssistantMessage &&
|
||||||
message.status === 'success' &&
|
message.status === 'success' &&
|
||||||
!generating &&
|
!generating &&
|
||||||
ttsEnabled &&
|
ttsEnabled
|
||||||
isVoiceCallActive
|
|
||||||
) {
|
) {
|
||||||
|
// 如果语音通话窗口没有打开,则不自动播放TTS
|
||||||
|
if (!isVoiceCallActive) {
|
||||||
|
console.log('不自动播放TTS,因为语音通话窗口没有打开:', isVoiceCallActive)
|
||||||
|
return
|
||||||
|
}
|
||||||
// 检查是否需要跳过自动TTS
|
// 检查是否需要跳过自动TTS
|
||||||
if (skipNextAutoTTS) {
|
if (skipNextAutoTTS) {
|
||||||
console.log(
|
console.log(
|
||||||
@ -205,16 +210,6 @@ const MessageItem: FC<Props> = ({
|
|||||||
} else if (message.id === lastPlayedMessageId) {
|
} else if (message.id === lastPlayedMessageId) {
|
||||||
console.log('不自动播放TTS,因为该消息已经播放过:', message.id)
|
console.log('不自动播放TTS,因为该消息已经播放过:', message.id)
|
||||||
}
|
}
|
||||||
} else if (
|
|
||||||
isLastMessage &&
|
|
||||||
isAssistantMessage &&
|
|
||||||
message.status === 'success' &&
|
|
||||||
!generating &&
|
|
||||||
ttsEnabled &&
|
|
||||||
!isVoiceCallActive
|
|
||||||
) {
|
|
||||||
// 如果语音通话窗口没有打开,则不自动播放TTS
|
|
||||||
console.log('不自动播放TTS,因为语音通话窗口没有打开')
|
|
||||||
}
|
}
|
||||||
}, [
|
}, [
|
||||||
isLastMessage,
|
isLastMessage,
|
||||||
|
|||||||
@ -9,14 +9,25 @@ const TTSStopButton: React.FC = () => {
|
|||||||
const { t } = useTranslation()
|
const { t } = useTranslation()
|
||||||
const [isVisible, setIsVisible] = useState(false)
|
const [isVisible, setIsVisible] = useState(false)
|
||||||
|
|
||||||
// 检查是否正在播放TTS
|
// 添加TTS状态变化事件监听器
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const checkPlayingStatus = setInterval(() => {
|
const handleTTSStateChange = (event: CustomEvent) => {
|
||||||
const isPlaying = TTSService.isCurrentlyPlaying()
|
const { isPlaying } = event.detail
|
||||||
|
console.log('全局TTS停止按钮检测到TTS状态变化:', isPlaying)
|
||||||
setIsVisible(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播放
|
// 停止TTS播放
|
||||||
@ -26,17 +37,7 @@ const TTSStopButton: React.FC = () => {
|
|||||||
// 强制停止所有TTS播放
|
// 强制停止所有TTS播放
|
||||||
TTSService.stop()
|
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' })
|
window.message.success({ content: t('chat.tts.stopped', { defaultValue: '已停止语音播放' }), key: 'tts-stopped' })
|
||||||
|
|||||||
@ -163,15 +163,14 @@ class ASRService {
|
|||||||
if (data.data.isFinal) {
|
if (data.data.isFinal) {
|
||||||
console.log('[ASRService] 收到最终结果,调用回调函数,文本:', data.data.text)
|
console.log('[ASRService] 收到最终结果,调用回调函数,文本:', data.data.text)
|
||||||
|
|
||||||
// 保存当前回调函数并立即清除,防止重复处理
|
// 不再清除回调函数,允许继续处理后续语音
|
||||||
const tempCallback = this.resultCallback
|
// const tempCallback = this.resultCallback
|
||||||
this.resultCallback = null
|
// 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' })
|
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)
|
console.log('[ASRService] 收到中间结果,调用回调函数,文本:', data.data.text)
|
||||||
this.resultCallback(data.data.text, false)
|
this.resultCallback(data.data.text, false)
|
||||||
@ -237,6 +236,14 @@ class ASRService {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 先设置回调函数,确保在任何情况下都能正确设置
|
||||||
|
if (onTranscribed && typeof onTranscribed === 'function') {
|
||||||
|
console.log('[ASRService] 设置结果回调函数')
|
||||||
|
this.resultCallback = onTranscribed
|
||||||
|
} else {
|
||||||
|
console.warn('[ASRService] 未提供有效的回调函数')
|
||||||
|
}
|
||||||
|
|
||||||
// 如果是使用本地服务器
|
// 如果是使用本地服务器
|
||||||
if (asrServiceType === 'local') {
|
if (asrServiceType === 'local') {
|
||||||
// 连接WebSocket服务器
|
// 连接WebSocket服务器
|
||||||
@ -292,11 +299,6 @@ class ASRService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 保存回调函数(如果提供了)
|
|
||||||
if (onTranscribed && typeof onTranscribed === 'function') {
|
|
||||||
this.resultCallback = onTranscribed
|
|
||||||
}
|
|
||||||
|
|
||||||
// 发送开始命令
|
// 发送开始命令
|
||||||
if (this.ws && this.wsConnected) {
|
if (this.ws && this.wsConnected) {
|
||||||
this.ws.send(JSON.stringify({ type: 'start' }))
|
this.ws.send(JSON.stringify({ type: 'start' }))
|
||||||
@ -376,11 +378,11 @@ class ASRService {
|
|||||||
}, 100)
|
}, 100)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 添加额外的安全措施,确保在停止后也清除回调
|
// 不再清除回调函数,允许连续说多句话
|
||||||
setTimeout(() => {
|
// setTimeout(() => {
|
||||||
// 在停止后的一段时间内清除回调,防止后续结果被处理
|
// // 在停止后的一段时间内清除回调,防止后续结果被处理
|
||||||
this.resultCallback = null
|
// this.resultCallback = null
|
||||||
}, 3000) // 3秒后清除回调
|
// }, 3000) // 3秒后清除回调
|
||||||
} else {
|
} else {
|
||||||
throw new Error('WebSocket连接未就绪')
|
throw new Error('WebSocket连接未就绪')
|
||||||
}
|
}
|
||||||
|
|||||||
@ -257,8 +257,8 @@ class VoiceCallServiceClass {
|
|||||||
} else {
|
} else {
|
||||||
// 如果是临时结果,更新当前的识别结果
|
// 如果是临时结果,更新当前的识别结果
|
||||||
this._currentTranscript = text
|
this._currentTranscript = text
|
||||||
// 显示累积结果 + 当前临时结果
|
// 只显示当前临时结果,不与累积结果拼接
|
||||||
this.callbacks?.onTranscript(this._accumulatedTranscript + ' ' + text)
|
this.callbacks?.onTranscript(text)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 在录音过程中只更新transcript,不触发handleUserSpeech
|
// 在录音过程中只更新transcript,不触发handleUserSpeech
|
||||||
@ -595,12 +595,10 @@ class VoiceCallServiceClass {
|
|||||||
8. 尽量使用常见词汇,避免生僻或专业术语,除非用户特别询问。`
|
8. 尽量使用常见词汇,避免生僻或专业术语,除非用户特别询问。`
|
||||||
|
|
||||||
// 创建系统指令消息
|
// 创建系统指令消息
|
||||||
const systemMessage = getUserMessage({
|
const systemMessage = {
|
||||||
assistant,
|
role: 'system',
|
||||||
topic,
|
|
||||||
type: 'text',
|
|
||||||
content: voiceCallPrompt
|
content: voiceCallPrompt
|
||||||
})
|
}
|
||||||
|
|
||||||
// 修改用户消息的内容
|
// 修改用户消息的内容
|
||||||
userMessage.content = text
|
userMessage.content = text
|
||||||
@ -637,14 +635,24 @@ class VoiceCallServiceClass {
|
|||||||
if (!this.isMuted && this.isCallActive) {
|
if (!this.isMuted && this.isCallActive) {
|
||||||
// 手动设置语音状态
|
// 手动设置语音状态
|
||||||
this.callbacks?.onSpeakingStateChange(true)
|
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)
|
this.ttsService.speak(fullResponse)
|
||||||
|
|
||||||
// 确保语音结束后状态正确
|
// 设置超时安全机制,确保事件监听器被移除
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
if (this.ttsService && !this.ttsService.isCurrentlyPlaying()) {
|
window.removeEventListener('tts-state-change', handleTTSStateChange as EventListener)
|
||||||
this.callbacks?.onSpeakingStateChange(false)
|
}, 30000) // 30秒后移除事件监听器
|
||||||
}
|
|
||||||
}, 1000) // 1秒后检查TTS状态
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 更新对话历史
|
// 更新对话历史
|
||||||
@ -910,9 +918,7 @@ class VoiceCallServiceClass {
|
|||||||
this.ttsService.stop()
|
this.ttsService.stop()
|
||||||
console.log('强制停止TTS播放')
|
console.log('强制停止TTS播放')
|
||||||
|
|
||||||
// 手动触发TTS状态变化事件,确保 UI 状态更新
|
// 注意:不需要手动触发事件,因为在TTSService.stop()中已经触发了
|
||||||
const event = new CustomEvent('tts-state-change', { detail: { isPlaying: false } })
|
|
||||||
window.dispatchEvent(event)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
setPaused(paused: boolean) {
|
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
|
let currentUtterance: SpeechSynthesisUtterance | null = null
|
||||||
|
|
||||||
|
// 全局变量来跟踪是否正在播放
|
||||||
|
export let isEdgeTTSPlaying = false
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edge TTS服务实现类
|
* Edge TTS服务实现类
|
||||||
*/
|
*/
|
||||||
@ -50,10 +53,12 @@ export class EdgeTTSService implements TTSServiceInterface {
|
|||||||
if (currentUtterance) {
|
if (currentUtterance) {
|
||||||
currentUtterance = null
|
currentUtterance = null
|
||||||
}
|
}
|
||||||
|
isEdgeTTSPlaying = false
|
||||||
|
|
||||||
// 创建语音合成器实例
|
// 创建语音合成器实例
|
||||||
const utterance = new SpeechSynthesisUtterance(text)
|
const utterance = new SpeechSynthesisUtterance(text)
|
||||||
currentUtterance = utterance
|
currentUtterance = utterance
|
||||||
|
isEdgeTTSPlaying = true
|
||||||
|
|
||||||
// 获取可用的语音合成声音
|
// 获取可用的语音合成声音
|
||||||
const voices = window.speechSynthesis.getVoices()
|
const voices = window.speechSynthesis.getVoices()
|
||||||
@ -93,6 +98,7 @@ export class EdgeTTSService implements TTSServiceInterface {
|
|||||||
utterance.onend = () => {
|
utterance.onend = () => {
|
||||||
console.log('语音合成已结束')
|
console.log('语音合成已结束')
|
||||||
currentUtterance = null
|
currentUtterance = null
|
||||||
|
isEdgeTTSPlaying = false
|
||||||
|
|
||||||
// 分发一个自定义事件,通知语音合成已结束
|
// 分发一个自定义事件,通知语音合成已结束
|
||||||
// 这样TTSService可以监听这个事件并重置播放状态
|
// 这样TTSService可以监听这个事件并重置播放状态
|
||||||
@ -100,9 +106,14 @@ export class EdgeTTSService implements TTSServiceInterface {
|
|||||||
document.dispatchEvent(event)
|
document.dispatchEvent(event)
|
||||||
}
|
}
|
||||||
|
|
||||||
utterance.onerror = (event) => {
|
utterance.onerror = (errorEvent) => {
|
||||||
console.error('语音合成错误:', event)
|
console.error('语音合成错误:', errorEvent)
|
||||||
currentUtterance = null
|
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()
|
window.speechSynthesis.cancel()
|
||||||
|
isEdgeTTSPlaying = false
|
||||||
|
|
||||||
// 创建语音合成器实例
|
// 创建语音合成器实例
|
||||||
const utterance = new SpeechSynthesisUtterance(text)
|
const utterance = new SpeechSynthesisUtterance(text)
|
||||||
|
|||||||
@ -14,6 +14,7 @@ export class TTSService {
|
|||||||
private static instance: TTSService
|
private static instance: TTSService
|
||||||
private audioElement: HTMLAudioElement | null = null
|
private audioElement: HTMLAudioElement | null = null
|
||||||
private isPlaying = false
|
private isPlaying = false
|
||||||
|
private playingServiceType: string | null = null
|
||||||
|
|
||||||
// 错误消息节流控制
|
// 错误消息节流控制
|
||||||
private lastErrorTime = 0
|
private lastErrorTime = 0
|
||||||
@ -42,15 +43,34 @@ export class TTSService {
|
|||||||
|
|
||||||
// 监听音频播放结束事件
|
// 监听音频播放结束事件
|
||||||
this.audioElement.addEventListener('ended', () => {
|
this.audioElement.addEventListener('ended', () => {
|
||||||
this.isPlaying = false
|
// 只有在非EdgeTTS服务时才直接更新状态
|
||||||
console.log('TTS播放结束')
|
if (this.playingServiceType !== 'edge') {
|
||||||
|
this.updatePlayingState(false)
|
||||||
|
console.log('TTS播放结束 (音频元素事件)')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
// 监听浏览器TTS直接播放结束的自定义事件
|
// 监听浏览器TTS直接播放结束的自定义事件
|
||||||
document.addEventListener('edgeTTSComplete', () => {
|
document.addEventListener('edgeTTSComplete', () => {
|
||||||
console.log('收到浏览器TTS直接播放结束事件')
|
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)
|
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 要播放的文本
|
* @param text 要播放的文本
|
||||||
@ -101,6 +147,8 @@ export class TTSService {
|
|||||||
// 如果正在播放,先停止
|
// 如果正在播放,先停止
|
||||||
if (this.isPlaying) {
|
if (this.isPlaying) {
|
||||||
this.stop()
|
this.stop()
|
||||||
|
// 添加短暂延迟,确保上一个播放完全停止
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 100))
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保文本不为空
|
// 确保文本不为空
|
||||||
@ -114,6 +162,8 @@ export class TTSService {
|
|||||||
const latestSettings = store.getState().settings
|
const latestSettings = store.getState().settings
|
||||||
const serviceType = latestSettings.ttsServiceType || 'openai'
|
const serviceType = latestSettings.ttsServiceType || 'openai'
|
||||||
console.log('使用的TTS服务类型:', serviceType)
|
console.log('使用的TTS服务类型:', serviceType)
|
||||||
|
// 记录当前使用的服务类型
|
||||||
|
this.playingServiceType = serviceType
|
||||||
console.log('当前TTS设置详情:', {
|
console.log('当前TTS设置详情:', {
|
||||||
ttsServiceType: serviceType,
|
ttsServiceType: serviceType,
|
||||||
ttsEdgeVoice: latestSettings.ttsEdgeVoice,
|
ttsEdgeVoice: latestSettings.ttsEdgeVoice,
|
||||||
@ -161,7 +211,8 @@ export class TTSService {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
this.isPlaying = true
|
// 更新播放状态
|
||||||
|
this.updatePlayingState(true)
|
||||||
console.log('开始播放TTS音频')
|
console.log('开始播放TTS音频')
|
||||||
|
|
||||||
// 释放URL对象
|
// 释放URL对象
|
||||||
@ -172,22 +223,10 @@ export class TTSService {
|
|||||||
const isEdgeTTS = serviceType === 'edge'
|
const isEdgeTTS = serviceType === 'edge'
|
||||||
const isSmallBlob = audioBlob.size < 100
|
const isSmallBlob = audioBlob.size < 100
|
||||||
|
|
||||||
// 如果是浏览器TTS直接播放,则等待当前语音合成结束
|
// 对于非EdgeTTS服务,直接更新状态
|
||||||
if (isEdgeTTS && isSmallBlob) {
|
// EdgeTTS服务的状态更新由定时器和edgeTTSComplete事件处理
|
||||||
// 检查全局变量中的当前语音合成状态
|
if (!(isEdgeTTS && isSmallBlob)) {
|
||||||
// 如果还在播放,则不重置播放状态
|
this.updatePlayingState(false)
|
||||||
// 注意:这里我们无法直接访问 EdgeTTSService 中的 currentUtterance
|
|
||||||
// 所以我们使用定时器来检查语音合成是否完成
|
|
||||||
console.log('浏览器TTS直接播放中,等待语音合成结束')
|
|
||||||
// 保持播放状态,直到语音合成结束
|
|
||||||
// 使用定时器来检查语音合成是否完成
|
|
||||||
// 大多数语音合成应该在几秒内完成
|
|
||||||
setTimeout(() => {
|
|
||||||
this.isPlaying = false
|
|
||||||
console.log('浏览器TTS直接播放完成')
|
|
||||||
}, 10000) // 10秒后自动重置状态
|
|
||||||
} else {
|
|
||||||
this.isPlaying = false
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,13 +255,17 @@ export class TTSService {
|
|||||||
if (this.audioElement) {
|
if (this.audioElement) {
|
||||||
this.audioElement.pause()
|
this.audioElement.pause()
|
||||||
this.audioElement.currentTime = 0
|
this.audioElement.currentTime = 0
|
||||||
this.isPlaying = false
|
|
||||||
console.log('强制停止TTS播放')
|
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
|
* @returns 返回音频Blob对象的Promise
|
||||||
*/
|
*/
|
||||||
synthesize(text: string): Promise<Blob>
|
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"
|
diff: "npm:^7.0.0"
|
||||||
docx: "npm:^9.0.2"
|
docx: "npm:^9.0.2"
|
||||||
dotenv-cli: "npm:^7.4.2"
|
dotenv-cli: "npm:^7.4.2"
|
||||||
|
edge-tts-node: "npm:^1.5.7"
|
||||||
electron: "npm:31.7.6"
|
electron: "npm:31.7.6"
|
||||||
electron-builder: "npm:^24.13.3"
|
electron-builder: "npm:^24.13.3"
|
||||||
electron-devtools-installer: "npm:^3.2.0"
|
electron-devtools-installer: "npm:^3.2.0"
|
||||||
@ -4439,6 +4440,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"asn1@npm:~0.2.3":
|
||||||
version: 0.2.6
|
version: 0.2.6
|
||||||
resolution: "asn1@npm:0.2.6"
|
resolution: "asn1@npm:0.2.6"
|
||||||
@ -4520,7 +4532,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 1.8.4
|
||||||
resolution: "axios@npm:1.8.4"
|
resolution: "axios@npm:1.8.4"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -4678,6 +4690,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"body-parser@npm:^2.0.1":
|
||||||
version: 2.1.0
|
version: 2.1.0
|
||||||
resolution: "body-parser@npm:2.1.0"
|
resolution: "body-parser@npm:2.1.0"
|
||||||
@ -4730,6 +4756,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"browser-image-compression@npm:^2.0.2":
|
||||||
version: 2.0.2
|
version: 2.0.2
|
||||||
resolution: "browser-image-compression@npm:2.0.2"
|
resolution: "browser-image-compression@npm:2.0.2"
|
||||||
@ -4739,6 +4772,72 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"browserslist@npm:^4.21.1, browserslist@npm:^4.24.0":
|
||||||
version: 4.24.4
|
version: 4.24.4
|
||||||
resolution: "browserslist@npm:4.24.4"
|
resolution: "browserslist@npm:4.24.4"
|
||||||
@ -4812,6 +4911,13 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"buffer@npm:^5.1.0, buffer@npm:^5.2.0, buffer@npm:^5.2.1, buffer@npm:^5.5.0":
|
||||||
version: 5.7.1
|
version: 5.7.1
|
||||||
resolution: "buffer@npm:5.7.1"
|
resolution: "buffer@npm:5.7.1"
|
||||||
@ -5209,6 +5315,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"classcat@npm:^5.0.3":
|
||||||
version: 5.0.5
|
version: 5.0.5
|
||||||
resolution: "classcat@npm:5.0.5"
|
resolution: "classcat@npm:5.0.5"
|
||||||
@ -5601,6 +5717,43 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"cross-spawn@npm:^7.0.1, cross-spawn@npm:^7.0.3, cross-spawn@npm:^7.0.6":
|
||||||
version: 7.0.6
|
version: 7.0.6
|
||||||
resolution: "cross-spawn@npm:7.0.6"
|
resolution: "cross-spawn@npm:7.0.6"
|
||||||
@ -5619,6 +5772,26 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"css-box-model@npm:^1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "css-box-model@npm:1.2.1"
|
resolution: "css-box-model@npm:1.2.1"
|
||||||
@ -6078,6 +6251,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"destroy@npm:^1.2.0":
|
||||||
version: 1.2.0
|
version: 1.2.0
|
||||||
resolution: "destroy@npm:1.2.0"
|
resolution: "destroy@npm:1.2.0"
|
||||||
@ -6149,6 +6332,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"dingbat-to-unicode@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "dingbat-to-unicode@npm:1.0.1"
|
resolution: "dingbat-to-unicode@npm:1.0.1"
|
||||||
@ -6383,6 +6577,22 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"ee-first@npm:1.1.1":
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
resolution: "ee-first@npm:1.1.1"
|
resolution: "ee-first@npm:1.1.1"
|
||||||
@ -6548,6 +6758,21 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"emittery@npm:^1.0.3":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "emittery@npm:1.1.0"
|
resolution: "emittery@npm:1.1.0"
|
||||||
@ -7304,6 +7529,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"execa@npm:^8.0.1":
|
||||||
version: 8.0.1
|
version: 8.0.1
|
||||||
resolution: "execa@npm:8.0.1"
|
resolution: "execa@npm:8.0.1"
|
||||||
@ -8480,7 +8716,28 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 1.1.7
|
||||||
resolution: "hash.js@npm:1.1.7"
|
resolution: "hash.js@npm:1.1.7"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -8704,6 +8961,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"hoist-non-react-statics@npm:^3.3.0, hoist-non-react-statics@npm:^3.3.2":
|
||||||
version: 3.3.2
|
version: 3.3.2
|
||||||
resolution: "hoist-non-react-statics@npm:3.3.2"
|
resolution: "hoist-non-react-statics@npm:3.3.2"
|
||||||
@ -9073,7 +9341,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 2.0.4
|
||||||
resolution: "inherits@npm:2.0.4"
|
resolution: "inherits@npm:2.0.4"
|
||||||
checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
|
checksum: 10c0/4e531f648b29039fb7426fb94075e6545faa1eb9fe83c29f0b6d9e7263aceb4289d2d4557db0d428188eeb449cc7c5e77b0a0b2c4e248ff2a65933a0dee49ef2
|
||||||
@ -9441,6 +9709,15 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"isstream@npm:~0.1.2":
|
||||||
version: 0.1.2
|
version: 0.1.2
|
||||||
resolution: "isstream@npm:0.1.2"
|
resolution: "isstream@npm:0.1.2"
|
||||||
@ -10372,6 +10649,17 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"md5@npm:^2.3.0":
|
||||||
version: 2.3.0
|
version: 2.3.0
|
||||||
resolution: "md5@npm:2.3.0"
|
resolution: "md5@npm:2.3.0"
|
||||||
@ -11288,6 +11576,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"mime-db@npm:1.52.0":
|
||||||
version: 1.52.0
|
version: 1.52.0
|
||||||
resolution: "mime-db@npm:1.52.0"
|
resolution: "mime-db@npm:1.52.0"
|
||||||
@ -11405,13 +11705,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
linkType: hard
|
||||||
|
|
||||||
"minimalistic-assert@npm:^1.0.1":
|
"minimalistic-assert@npm:^1.0.0, minimalistic-assert@npm:^1.0.1":
|
||||||
version: 1.0.1
|
version: 1.0.1
|
||||||
resolution: "minimalistic-assert@npm:1.0.1"
|
resolution: "minimalistic-assert@npm:1.0.1"
|
||||||
checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd
|
checksum: 10c0/96730e5601cd31457f81a296f521eb56036e6f69133c0b18c13fe941109d53ad23a4204d946a0d638d7f3099482a0cec8c9bb6d642604612ce43ee536be3dddd
|
||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2":
|
||||||
version: 3.1.2
|
version: 3.1.2
|
||||||
resolution: "minimatch@npm:3.1.2"
|
resolution: "minimatch@npm:3.1.2"
|
||||||
@ -12473,6 +12780,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"parse-bmfont-ascii@npm:^1.0.3":
|
||||||
version: 1.0.6
|
version: 1.0.6
|
||||||
resolution: "parse-bmfont-ascii@npm:1.0.6"
|
resolution: "parse-bmfont-ascii@npm:1.0.6"
|
||||||
@ -12661,6 +12982,19 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"pdf-parse@npm:1.1.1":
|
||||||
version: 1.1.1
|
version: 1.1.1
|
||||||
resolution: "pdf-parse@npm:1.1.1"
|
resolution: "pdf-parse@npm:1.1.1"
|
||||||
@ -13054,6 +13388,20 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"pump@npm:^3.0.0":
|
||||||
version: 3.0.2
|
version: 3.0.2
|
||||||
resolution: "pump@npm:3.0.2"
|
resolution: "pump@npm:3.0.2"
|
||||||
@ -13138,6 +13486,25 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"range-parser@npm:^1.2.1, range-parser@npm:~1.2.1":
|
||||||
version: 1.2.1
|
version: 1.2.1
|
||||||
resolution: "range-parser@npm:1.2.1"
|
resolution: "range-parser@npm:1.2.1"
|
||||||
@ -13925,7 +14292,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 3.6.2
|
||||||
resolution: "readable-stream@npm:3.6.2"
|
resolution: "readable-stream@npm:3.6.2"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -13936,7 +14303,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 2.3.8
|
||||||
resolution: "readable-stream@npm:2.3.8"
|
resolution: "readable-stream@npm:2.3.8"
|
||||||
dependencies:
|
dependencies:
|
||||||
@ -14416,6 +14783,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"roarr@npm:^2.15.3":
|
||||||
version: 2.15.4
|
version: 2.15.4
|
||||||
resolution: "roarr@npm:2.15.4"
|
resolution: "roarr@npm:2.15.4"
|
||||||
@ -14551,7 +14928,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 5.2.1
|
||||||
resolution: "safe-buffer@npm:5.2.1"
|
resolution: "safe-buffer@npm:5.2.1"
|
||||||
checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3
|
checksum: 10c0/6501914237c0a86e9675d4e51d89ca3c21ffd6a31642efeba25ad65720bce6921c9e7e974e5be91a786b25aa058b5303285d3c15dbabf983a919f5f630d349f3
|
||||||
@ -14747,6 +15124,18 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"shallowequal@npm:1.1.0":
|
||||||
version: 1.1.0
|
version: 1.1.0
|
||||||
resolution: "shallowequal@npm:1.1.0"
|
resolution: "shallowequal@npm:1.1.0"
|
||||||
@ -15135,6 +15524,16 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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":
|
"stream-head@npm:^3.0.0":
|
||||||
version: 3.0.0
|
version: 3.0.0
|
||||||
resolution: "stream-head@npm:3.0.0"
|
resolution: "stream-head@npm:3.0.0"
|
||||||
@ -16670,7 +17069,7 @@ __metadata:
|
|||||||
languageName: node
|
languageName: node
|
||||||
linkType: hard
|
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
|
version: 8.18.1
|
||||||
resolution: "ws@npm:8.18.1"
|
resolution: "ws@npm:8.18.1"
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user