mirror of
https://github.com/leon-ai/leon.git
synced 2024-09-19 22:07:10 +03:00
refactor(server): remove already-refactored synthesizers
This commit is contained in:
parent
885f3738fc
commit
0f897942fa
@ -1,101 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import { Polly, SynthesizeSpeechCommand } from '@aws-sdk/client-polly'
|
||||
import Ffmpeg from 'fluent-ffmpeg'
|
||||
import { path as ffmpegPath } from '@ffmpeg-installer/ffmpeg'
|
||||
import { path as ffprobePath } from '@ffprobe-installer/ffprobe'
|
||||
|
||||
import { TMP_PATH } from '@/constants'
|
||||
import { LogHelper } from '@/helpers/log-helper'
|
||||
import { StringHelper } from '@/helpers/string-helper'
|
||||
|
||||
LogHelper.title('Amazon Polly Synthesizer')
|
||||
|
||||
const synthesizer = {}
|
||||
const voices = {
|
||||
'en-US': {
|
||||
VoiceId: 'Matthew'
|
||||
},
|
||||
'fr-FR': {
|
||||
VoiceId: 'Mathieu'
|
||||
}
|
||||
}
|
||||
let client = {}
|
||||
|
||||
synthesizer.conf = {
|
||||
OutputFormat: 'mp3',
|
||||
VoiceId: ''
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Amazon Polly based on credentials in the JSON file
|
||||
*/
|
||||
synthesizer.init = (lang) => {
|
||||
const config = JSON.parse(
|
||||
fs.readFileSync(
|
||||
path.join(process.cwd(), 'core/config/voice/amazon.json'),
|
||||
'utf8'
|
||||
)
|
||||
)
|
||||
synthesizer.conf.VoiceId = voices[lang].VoiceId
|
||||
|
||||
try {
|
||||
client = new Polly(config)
|
||||
|
||||
LogHelper.success('Synthesizer initialized')
|
||||
} catch (e) {
|
||||
LogHelper.error(`Amazon Polly: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save string to audio file
|
||||
*/
|
||||
synthesizer.save = (speech, em, cb) => {
|
||||
const file = path.join(
|
||||
TMP_PATH,
|
||||
`${Date.now()}-${StringHelper.random(4)}.mp3`
|
||||
)
|
||||
|
||||
synthesizer.conf.Text = speech
|
||||
|
||||
client
|
||||
.send(new SynthesizeSpeechCommand(synthesizer.conf))
|
||||
.then(({ AudioStream }) => {
|
||||
const wStream = fs.createWriteStream(file)
|
||||
|
||||
AudioStream.pipe(wStream)
|
||||
|
||||
wStream.on('finish', () => {
|
||||
const ffmpeg = new Ffmpeg()
|
||||
ffmpeg.setFfmpegPath(ffmpegPath)
|
||||
ffmpeg.setFfprobePath(ffprobePath)
|
||||
|
||||
// Get file duration thanks to ffprobe
|
||||
ffmpeg.input(file).ffprobe((err, data) => {
|
||||
if (err) LogHelper.error(err)
|
||||
else {
|
||||
const duration = data.streams[0].duration * 1_000
|
||||
em.emit('saved', duration)
|
||||
cb(file, duration)
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
wStream.on('error', (err) => {
|
||||
LogHelper.error(`Amazon Polly: ${err}`)
|
||||
})
|
||||
})
|
||||
.catch((err) => {
|
||||
if (err.code === 'UnknownEndpoint') {
|
||||
LogHelper.error(
|
||||
`Amazon Polly: the region "${err.region}" does not exist or does not support the Polly service`
|
||||
)
|
||||
} else {
|
||||
LogHelper.error(`Amazon Polly: ${err.message}`)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export default synthesizer
|
@ -1,92 +0,0 @@
|
||||
import { spawn } from 'node:child_process'
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import Ffmpeg from 'fluent-ffmpeg'
|
||||
import { path as ffmpegPath } from '@ffmpeg-installer/ffmpeg'
|
||||
import { path as ffprobePath } from '@ffprobe-installer/ffprobe'
|
||||
|
||||
import { TMP_PATH } from '@/constants'
|
||||
import { LogHelper } from '@/helpers/log-helper'
|
||||
import { StringHelper } from '@/helpers/string-helper'
|
||||
|
||||
LogHelper.title('Flite Synthesizer')
|
||||
|
||||
const synthesizer = {}
|
||||
|
||||
synthesizer.conf = {
|
||||
int_f0_target_mean: 115.0, // Intonation (85-180 Hz men; 165-255 Hz women)
|
||||
f0_shift: 1.0, // Low or high
|
||||
duration_stretch: 1.0, // Speed (lower = faster)
|
||||
int_f0_target_stddev: 15.0 // Pitch variability (lower = more flat)
|
||||
}
|
||||
|
||||
/**
|
||||
* There is nothing to initialize for this synthesizer
|
||||
*/
|
||||
synthesizer.init = (lang) => {
|
||||
const flitePath = 'bin/flite/flite'
|
||||
|
||||
if (lang !== 'en-US') {
|
||||
LogHelper.warning(
|
||||
'The Flite synthesizer only accepts the "en-US" language for the moment'
|
||||
)
|
||||
}
|
||||
|
||||
if (!fs.existsSync(flitePath)) {
|
||||
LogHelper.error(
|
||||
`Cannot find ${flitePath} You can set up the offline TTS by running: "npm run setup:offline-tts"`
|
||||
)
|
||||
return false
|
||||
}
|
||||
|
||||
LogHelper.success('Synthesizer initialized')
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Save string to audio file
|
||||
*/
|
||||
synthesizer.save = (speech, em, cb) => {
|
||||
const file = path.join(
|
||||
TMP_PATH,
|
||||
`${Date.now()}-${StringHelper.random(4)}.wav`
|
||||
)
|
||||
const process = spawn('bin/flite/flite', [
|
||||
speech,
|
||||
'--setf',
|
||||
`int_f0_target_mean=${synthesizer.conf.int_f0_target_mean}`,
|
||||
'--setf',
|
||||
`f0_shift=${synthesizer.conf.f0_shift}`,
|
||||
'--setf',
|
||||
`duration_stretch=${synthesizer.conf.duration_stretch}`,
|
||||
'--setf',
|
||||
`int_f0_target_stddev=${synthesizer.conf.int_f0_target_stddev}`,
|
||||
'-o',
|
||||
file
|
||||
])
|
||||
|
||||
// Handle error
|
||||
process.stderr.on('data', (data) => {
|
||||
LogHelper.error(data.toString())
|
||||
})
|
||||
|
||||
process.stdout.on('end', () => {
|
||||
const ffmpeg = new Ffmpeg()
|
||||
ffmpeg.setFfmpegPath(ffmpegPath)
|
||||
ffmpeg.setFfprobePath(ffprobePath)
|
||||
|
||||
// Get file duration thanks to ffprobe
|
||||
ffmpeg.input(file).ffprobe((err, data) => {
|
||||
if (err) LogHelper.error(err)
|
||||
else {
|
||||
const duration = data.streams[0].duration * 1_000
|
||||
em.emit('saved', duration)
|
||||
cb(file, duration)
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default synthesizer
|
@ -1,98 +0,0 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
|
||||
import tts from '@google-cloud/text-to-speech'
|
||||
import Ffmpeg from 'fluent-ffmpeg'
|
||||
import { path as ffmpegPath } from '@ffmpeg-installer/ffmpeg'
|
||||
import { path as ffprobePath } from '@ffprobe-installer/ffprobe'
|
||||
|
||||
import { TMP_PATH } from '@/constants'
|
||||
import { LogHelper } from '@/helpers/log-helper'
|
||||
import { StringHelper } from '@/helpers/string-helper'
|
||||
|
||||
LogHelper.title('Google Cloud TTS Synthesizer')
|
||||
|
||||
const synthesizer = {}
|
||||
const voices = {
|
||||
'en-US': {
|
||||
languageCode: 'en-US',
|
||||
name: 'en-US-Wavenet-A',
|
||||
// name: 'en-GB-Standard-B', // Standard
|
||||
ssmlGender: 'MALE'
|
||||
},
|
||||
'fr-FR': {
|
||||
languageCode: 'fr-FR',
|
||||
name: 'fr-FR-Wavenet-B',
|
||||
ssmlGender: 'MALE'
|
||||
}
|
||||
}
|
||||
let client = {}
|
||||
|
||||
synthesizer.conf = {
|
||||
voice: '',
|
||||
audioConfig: {
|
||||
audioEncoding: 'MP3'
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize Google Cloud Text-to-Speech based on credentials in the JSON file
|
||||
* The env variable "GOOGLE_APPLICATION_CREDENTIALS" provides the JSON file path
|
||||
*/
|
||||
synthesizer.init = (lang) => {
|
||||
process.env.GOOGLE_APPLICATION_CREDENTIALS = path.join(
|
||||
process.cwd(),
|
||||
'core/config/voice/google-cloud.json'
|
||||
)
|
||||
synthesizer.conf.voice = voices[lang]
|
||||
|
||||
try {
|
||||
client = new tts.TextToSpeechClient()
|
||||
|
||||
LogHelper.success('Synthesizer initialized')
|
||||
} catch (e) {
|
||||
LogHelper.error(`Google Cloud TTS: ${e}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save string to audio file
|
||||
*/
|
||||
synthesizer.save = (speech, em, cb) => {
|
||||
const file = path.join(
|
||||
TMP_PATH,
|
||||
`${Date.now()}-${StringHelper.random(4)}.mp3`
|
||||
)
|
||||
|
||||
synthesizer.conf.input = { text: speech }
|
||||
|
||||
client.synthesizeSpeech(synthesizer.conf, (err, res) => {
|
||||
if (err) {
|
||||
LogHelper.error(`Google Cloud TTS: ${err}`)
|
||||
return
|
||||
}
|
||||
|
||||
fs.writeFile(file, res.audioContent, 'binary', (err) => {
|
||||
if (err) {
|
||||
LogHelper.error(`Google Cloud TTS: ${err}`)
|
||||
return
|
||||
}
|
||||
|
||||
const ffmpeg = new Ffmpeg()
|
||||
ffmpeg.setFfmpegPath(ffmpegPath)
|
||||
ffmpeg.setFfprobePath(ffprobePath)
|
||||
|
||||
// Get file duration thanks to ffprobe
|
||||
ffmpeg.input(file).ffprobe((err, data) => {
|
||||
if (err) LogHelper.error(err)
|
||||
else {
|
||||
const duration = data.streams[0].duration * 1_000
|
||||
em.emit('saved', duration)
|
||||
cb(file, duration)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
export default synthesizer
|
Loading…
Reference in New Issue
Block a user