mirror of
https://github.com/SillyTavern/SillyTavern.git
synced 2025-06-05 21:59:27 +02:00
Add MS Edge TTS
This commit is contained in:
@ -1,5 +1,5 @@
|
||||
|
||||
const port = 8000;
|
||||
const port = 8100;
|
||||
const whitelist = ['127.0.0.1']; //Example for add several IP in whitelist: ['127.0.0.1', '192.168.0.10']
|
||||
const whitelistMode = true; //Disabling enabling the ip whitelist mode. true/false
|
||||
const basicAuthMode = false; //Toggle basic authentication for endpoints.
|
||||
@ -17,7 +17,7 @@ const securityOverride = false;
|
||||
|
||||
module.exports = {
|
||||
port,
|
||||
whitelist,
|
||||
whitelist,
|
||||
whitelistMode,
|
||||
basicAuthMode,
|
||||
basicAuthUser,
|
||||
|
167
package-lock.json
generated
167
package-lock.json
generated
@ -28,6 +28,7 @@
|
||||
"json5": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"mime-types": "^2.1.35",
|
||||
"msedge-tts": "^1.1.4",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^2.6.11",
|
||||
"node-rest-client": "^3.1.1",
|
||||
@ -838,6 +839,18 @@
|
||||
"version": "1.1.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bufferutil": {
|
||||
"version": "4.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.0.7.tgz",
|
||||
"integrity": "sha512-kukuqc39WOHtdxtw4UScxF/WVnMFVSQVKhtx3AjZJzhd0RGZZldcrfSEbVsWWe6KNH253574cq5F+wpv0G9pJw==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/busboy": {
|
||||
"version": "1.6.0",
|
||||
"dependencies": {
|
||||
@ -1069,6 +1082,15 @@
|
||||
"http-errors": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/d": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz",
|
||||
"integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==",
|
||||
"dependencies": {
|
||||
"es5-ext": "^0.10.50",
|
||||
"type": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/debug": {
|
||||
"version": "4.3.4",
|
||||
"license": "MIT",
|
||||
@ -1194,6 +1216,39 @@
|
||||
"once": "^1.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/es5-ext": {
|
||||
"version": "0.10.62",
|
||||
"resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.62.tgz",
|
||||
"integrity": "sha512-BHLqn0klhEpnOKSrzn/Xsz2UIW8j+cGmo9JLzr8BiUapV8hPL9+FliFqjwr9ngW7jWdnxv6eO+/LqyhJVqgrjA==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"es6-iterator": "^2.0.3",
|
||||
"es6-symbol": "^3.1.3",
|
||||
"next-tick": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-iterator": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz",
|
||||
"integrity": "sha512-zw4SRzoUkd+cl+ZoE15A9o1oQd920Bb0iOJMQkQhl3jNc03YqVjAhG7scf9C5KWRU/R13Orf588uCC6525o02g==",
|
||||
"dependencies": {
|
||||
"d": "1",
|
||||
"es5-ext": "^0.10.35",
|
||||
"es6-symbol": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/es6-symbol": {
|
||||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz",
|
||||
"integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==",
|
||||
"dependencies": {
|
||||
"d": "^1.0.1",
|
||||
"ext": "^1.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/escalade": {
|
||||
"version": "3.1.1",
|
||||
"license": "MIT",
|
||||
@ -1283,6 +1338,19 @@
|
||||
"version": "2.0.0",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ext": {
|
||||
"version": "1.7.0",
|
||||
"resolved": "https://registry.npmjs.org/ext/-/ext-1.7.0.tgz",
|
||||
"integrity": "sha512-6hxeJYaL110a9b5TEJSj0gojyHQAmA2ch5Os+ySCiA1QGdS697XWY1pzsrSjqA9LDEEgdB/KypIlR59RcLuHYw==",
|
||||
"dependencies": {
|
||||
"type": "^2.7.2"
|
||||
}
|
||||
},
|
||||
"node_modules/ext/node_modules/type": {
|
||||
"version": "2.7.2",
|
||||
"resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz",
|
||||
"integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw=="
|
||||
},
|
||||
"node_modules/fast-glob": {
|
||||
"version": "3.2.12",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz",
|
||||
@ -1778,6 +1846,11 @@
|
||||
"node": ">=0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/is-typedarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
|
||||
"integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA=="
|
||||
},
|
||||
"node_modules/is-wsl": {
|
||||
"version": "2.2.0",
|
||||
"license": "MIT",
|
||||
@ -2006,6 +2079,23 @@
|
||||
"version": "2.1.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/msedge-tts": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/msedge-tts/-/msedge-tts-1.1.4.tgz",
|
||||
"integrity": "sha512-0f7o3CqZJTpNHI4Ua4xr9Hf+GtjrC/KEVoNtJXfK3YLu/xC0/33q9LSlOdLVMZho3CFKboxOSpUQcI5nihR+Qg==",
|
||||
"dependencies": {
|
||||
"axios": "^0.21.1",
|
||||
"websocket": "^1.0.34"
|
||||
}
|
||||
},
|
||||
"node_modules/msedge-tts/node_modules/axios": {
|
||||
"version": "0.21.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-0.21.4.tgz",
|
||||
"integrity": "sha512-ut5vewkiu8jjGBdqpM44XxjuCjq9LAKeHVmoVfHVzy8eHgxxq8SbAVQNovDA8mVi05kP0Ea/n/UzcSHcTJQfNg==",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.14.0"
|
||||
}
|
||||
},
|
||||
"node_modules/multer": {
|
||||
"version": "1.4.5-lts.1",
|
||||
"license": "MIT",
|
||||
@ -2073,6 +2163,11 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/next-tick": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz",
|
||||
"integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ=="
|
||||
},
|
||||
"node_modules/node-abi": {
|
||||
"version": "3.40.0",
|
||||
"resolved": "https://registry.npmjs.org/node-abi/-/node-abi-3.40.0.tgz",
|
||||
@ -2104,6 +2199,16 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/node-gyp-build": {
|
||||
"version": "4.6.0",
|
||||
"resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.6.0.tgz",
|
||||
"integrity": "sha512-NTZVKn9IylLwUzaKjkas1e4u2DLNcV4rdYagA4PWdPwW87Bi7z+BznyKSRwS/761tV/lzCGXplWsiaMjLqP2zQ==",
|
||||
"bin": {
|
||||
"node-gyp-build": "bin.js",
|
||||
"node-gyp-build-optional": "optional.js",
|
||||
"node-gyp-build-test": "build-test.js"
|
||||
}
|
||||
},
|
||||
"node_modules/node-rest-client": {
|
||||
"version": "3.1.1",
|
||||
"license": "MIT",
|
||||
@ -3171,6 +3276,11 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/type": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz",
|
||||
"integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg=="
|
||||
},
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"license": "MIT",
|
||||
@ -3186,6 +3296,14 @@
|
||||
"version": "0.0.6",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/typedarray-to-buffer": {
|
||||
"version": "3.1.5",
|
||||
"resolved": "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz",
|
||||
"integrity": "sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==",
|
||||
"dependencies": {
|
||||
"is-typedarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uniqolor": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/uniqolor/-/uniqolor-1.1.0.tgz",
|
||||
@ -3207,6 +3325,18 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/utf-8-validate": {
|
||||
"version": "5.0.10",
|
||||
"resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-5.0.10.tgz",
|
||||
"integrity": "sha512-Z6czzLq4u8fPOyx7TU6X3dvUZVvoJmxSQ+IcrlmagKhilxlhZgxPK6C5Jqbkw1IDUmFTM+cz9QDnnLTwDz/2gQ==",
|
||||
"hasInstallScript": true,
|
||||
"dependencies": {
|
||||
"node-gyp-build": "^4.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.14.2"
|
||||
}
|
||||
},
|
||||
"node_modules/utf8-byte-length": {
|
||||
"version": "1.0.4",
|
||||
"license": "WTFPL"
|
||||
@ -3245,6 +3375,35 @@
|
||||
"version": "2.3.2",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/websocket": {
|
||||
"version": "1.0.34",
|
||||
"resolved": "https://registry.npmjs.org/websocket/-/websocket-1.0.34.tgz",
|
||||
"integrity": "sha512-PRDso2sGwF6kM75QykIesBijKSVceR6jL2G8NGYyq2XrItNC2P5/qL5XeR056GhA+Ly7JMFvJb9I312mJfmqnQ==",
|
||||
"dependencies": {
|
||||
"bufferutil": "^4.0.1",
|
||||
"debug": "^2.2.0",
|
||||
"es5-ext": "^0.10.50",
|
||||
"typedarray-to-buffer": "^3.1.5",
|
||||
"utf-8-validate": "^5.0.2",
|
||||
"yaeti": "^0.0.6"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/websocket/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/websocket/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/whatwg-fetch": {
|
||||
"version": "3.6.2",
|
||||
"license": "MIT"
|
||||
@ -3342,6 +3501,14 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/yaeti": {
|
||||
"version": "0.0.6",
|
||||
"resolved": "https://registry.npmjs.org/yaeti/-/yaeti-0.0.6.tgz",
|
||||
"integrity": "sha512-MvQa//+KcZCUkBTIC9blM+CU9J2GzuTytsOUwf2lidtvkx/6gnEp1QvJv34t9vdjhFmha/mUiNDbN0D0mJWdug==",
|
||||
"engines": {
|
||||
"node": ">=0.10.32"
|
||||
}
|
||||
},
|
||||
"node_modules/yallist": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
|
@ -19,6 +19,7 @@
|
||||
"json5": "^2.2.3",
|
||||
"lodash": "^4.17.21",
|
||||
"mime-types": "^2.1.35",
|
||||
"msedge-tts": "^1.1.4",
|
||||
"multer": "^1.4.5-lts.1",
|
||||
"node-fetch": "^2.6.11",
|
||||
"node-rest-client": "^3.1.1",
|
||||
@ -69,7 +70,7 @@
|
||||
],
|
||||
"assets": [
|
||||
"node_modules/**/*",
|
||||
"poe_graphql/**/*"
|
||||
"src/poe_graphql/**/*"
|
||||
],
|
||||
"outputPath": "dist",
|
||||
"scripts": [
|
||||
|
@ -1,9 +1,9 @@
|
||||
const poe = require('./poe-client');
|
||||
const poe = require('./src/poe-client');
|
||||
|
||||
async function test() {
|
||||
const client = new poe.Client();
|
||||
await client.init('pb-cookie');
|
||||
|
||||
|
||||
const bots = client.get_bot_names();
|
||||
console.log(bots);
|
||||
|
||||
@ -18,4 +18,4 @@ async function test() {
|
||||
client.disconnect_ws();
|
||||
}
|
||||
|
||||
test();
|
||||
test();
|
||||
|
124
public/scripts/extensions/tts/edge.js
Normal file
124
public/scripts/extensions/tts/edge.js
Normal file
@ -0,0 +1,124 @@
|
||||
import { getRequestHeaders } from "../../../script.js"
|
||||
import { doExtrasFetch, getApiUrl, modules } from "../../extensions.js"
|
||||
import { getPreviewString } from "./index.js"
|
||||
|
||||
export { EdgeTtsProvider }
|
||||
|
||||
class EdgeTtsProvider {
|
||||
//########//
|
||||
// Config //
|
||||
//########//
|
||||
|
||||
settings
|
||||
voices = []
|
||||
separator = ' .. '
|
||||
|
||||
defaultSettings = {
|
||||
voiceMap: {}
|
||||
}
|
||||
|
||||
get settingsHtml() {
|
||||
let html = `Microsoft Edge TTS Provider<br>`
|
||||
return html
|
||||
}
|
||||
|
||||
onSettingsChange() {
|
||||
}
|
||||
|
||||
loadSettings(settings) {
|
||||
// Pupulate Provider UI given input settings
|
||||
if (Object.keys(settings).length == 0) {
|
||||
console.info("Using default TTS Provider settings")
|
||||
}
|
||||
|
||||
// Only accept keys defined in defaultSettings
|
||||
this.settings = this.defaultSettings
|
||||
|
||||
for (const key in settings){
|
||||
if (key in this.settings){
|
||||
this.settings[key] = settings[key]
|
||||
} else {
|
||||
throw `Invalid setting passed to TTS Provider: ${key}`
|
||||
}
|
||||
}
|
||||
|
||||
console.info("Settings loaded")
|
||||
}
|
||||
|
||||
|
||||
async onApplyClick() {
|
||||
return
|
||||
}
|
||||
|
||||
//#################//
|
||||
// TTS Interfaces //
|
||||
//#################//
|
||||
|
||||
async getVoice(voiceName) {
|
||||
if (this.voices.length == 0) {
|
||||
this.voices = await this.fetchTtsVoiceIds()
|
||||
}
|
||||
const match = this.voices.filter(
|
||||
voice => voice.name == voiceName
|
||||
)[0]
|
||||
if (!match) {
|
||||
throw `TTS Voice name ${voiceName} not found`
|
||||
}
|
||||
return match
|
||||
}
|
||||
|
||||
async generateTts(text, voiceId){
|
||||
const response = await this.fetchTtsGeneration(text, voiceId)
|
||||
return response
|
||||
}
|
||||
|
||||
//###########//
|
||||
// API CALLS //
|
||||
//###########//
|
||||
async fetchTtsVoiceIds() {
|
||||
const response = await doExtrasFetch(`/edge_voices`)
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${await response.json()}`)
|
||||
}
|
||||
let responseJson = await response.json()
|
||||
responseJson = responseJson
|
||||
.sort((a, b) => a.Locale.localeCompare(b.Locale) || a.ShortName.localeCompare(b.ShortName))
|
||||
.map(x => ({ name: x.ShortName, voice_id: x.ShortName, preview_url: false, lang: x.Locale }));
|
||||
return responseJson
|
||||
}
|
||||
|
||||
|
||||
async previewTtsVoice(id) {
|
||||
const voice = await this.getVoice(id);
|
||||
const text = getPreviewString(voice.lang);
|
||||
const response = await this.fetchTtsGeneration(text, id)
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${await response.json()}`)
|
||||
}
|
||||
|
||||
const audio = await response.blob();
|
||||
const url = URL.createObjectURL(audio);
|
||||
const audioElement = document.createElement("audio");
|
||||
audioElement.src = url;
|
||||
audioElement.play();
|
||||
}
|
||||
|
||||
async fetchTtsGeneration(inputText, voiceId) {
|
||||
console.info(`Generating new TTS for voice_id ${voiceId}`)
|
||||
const response = await doExtrasFetch(
|
||||
`/edge_speech`,
|
||||
{
|
||||
method: 'POST',
|
||||
headers: getRequestHeaders(),
|
||||
body: JSON.stringify({
|
||||
"text": inputText,
|
||||
"voice": voiceId
|
||||
})
|
||||
}
|
||||
)
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP ${response.status}: ${await response.json()}`)
|
||||
}
|
||||
return response
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
import { callPopup, cancelTtsPlay, eventSource, event_types, isMultigenEnabled, is_send_press, saveSettingsDebounced } from '../../../script.js'
|
||||
import { ModuleWorkerWrapper, extension_settings, getContext } from '../../extensions.js'
|
||||
import { getStringHash } from '../../utils.js'
|
||||
import { EdgeTtsProvider } from './edge.js'
|
||||
import { ElevenLabsTtsProvider } from './elevenlabs.js'
|
||||
import { SileroTtsProvider } from './silerotts.js'
|
||||
import { SystemTtsProvider } from './system.js'
|
||||
@ -15,11 +16,52 @@ let lastGroupId = null
|
||||
let lastChatId = null
|
||||
let lastMessageHash = null
|
||||
|
||||
export function getPreviewString(lang) {
|
||||
const previewStrings = {
|
||||
'en-US': 'The quick brown fox jumps over the lazy dog',
|
||||
'en-GB': 'Sphinx of black quartz, judge my vow',
|
||||
'fr-FR': 'Portez ce vieux whisky au juge blond qui fume',
|
||||
'de-DE': 'Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich',
|
||||
'it-IT': "Pranzo d'acqua fa volti sghembi",
|
||||
'es-ES': 'Quiere la boca exhausta vid, kiwi, piña y fugaz jamón',
|
||||
'es-MX': 'Fabio me exige, sin tapujos, que añada cerveza al whisky',
|
||||
'ru-RU': 'В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!',
|
||||
'pt-BR': 'Vejo xá gritando que fez show sem playback.',
|
||||
'pt-PR': 'Todo pajé vulgar faz boquinha sexy com kiwi.',
|
||||
'uk-UA': "Фабрикуймо гідність, лящім їжею, ґав хапаймо, з'єднавці чаш!",
|
||||
'pl-PL': 'Pchnąć w tę łódź jeża lub ośm skrzyń fig',
|
||||
'cs-CZ': 'Příliš žluťoučký kůň úpěl ďábelské ódy',
|
||||
'sk-SK': 'Vyhŕňme si rukávy a vyprážajme čínske ryžové cestoviny',
|
||||
'hu-HU': 'Árvíztűrő tükörfúrógép',
|
||||
'tr-TR': 'Pijamalı hasta yağız şoföre çabucak güvendi',
|
||||
'nl-NL': 'De waard heeft een kalfje en een pinkje opgegeten',
|
||||
'sv-SE': 'Yxskaftbud, ge vårbygd, zinkqvarn',
|
||||
'da-DK': 'Quizdeltagerne spiste jordbær med fløde, mens cirkusklovnen Walther spillede på xylofon',
|
||||
'ja-JP': 'いろはにほへと ちりぬるを わかよたれそ つねならむ うゐのおくやま けふこえて あさきゆめみし ゑひもせす',
|
||||
'ko-KR': '가나다라마바사아자차카타파하',
|
||||
'zh-CN': '我能吞下玻璃而不伤身体',
|
||||
'ro-RO': 'Muzicologă în bej vând whisky și tequila, preț fix',
|
||||
'bg-BG': 'Щъркелите се разпръснаха по цялото небе',
|
||||
'el-GR': 'Ταχίστη αλώπηξ βαφής ψημένη γη, δρασκελίζει υπέρ νωθρού κυνός',
|
||||
'fi-FI': 'Voi veljet, miksi juuri teille myin nämä vehkeet?',
|
||||
'he-IL': 'הקצינים צעקו: "כל הכבוד לצבא הצבאות!"',
|
||||
'id-ID': 'Jangkrik itu memang enak, apalagi kalau digoreng',
|
||||
'ms-MY': 'Muzik penyanyi wanita itu menggambarkan kehidupan yang penuh dengan duka nestapa',
|
||||
'th-TH': 'เป็นไงบ้างครับ ผมชอบกินข้าวผัดกระเพราหมูกรอบ',
|
||||
'vi-VN': 'Cô bé quàng khăn đỏ đang ngồi trên bãi cỏ xanh',
|
||||
'ar-SA': 'أَبْجَدِيَّة عَرَبِيَّة',
|
||||
'hi-IN': 'श्वेता ने श्वेता के श्वेते हाथों में श्वेता का श्वेता चावल पकड़ा',
|
||||
}
|
||||
const fallbackPreview = 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet'
|
||||
|
||||
return previewStrings[lang] ?? fallbackPreview;
|
||||
}
|
||||
|
||||
let ttsProviders = {
|
||||
ElevenLabs: ElevenLabsTtsProvider,
|
||||
Silero: SileroTtsProvider,
|
||||
System: SystemTtsProvider,
|
||||
Edge: EdgeTtsProvider,
|
||||
}
|
||||
let ttsProvider
|
||||
let ttsProviderName
|
||||
|
@ -1,3 +1,5 @@
|
||||
import { getPreviewString } from "./index.js";
|
||||
|
||||
export { SystemTtsProvider }
|
||||
|
||||
/**
|
||||
@ -74,20 +76,6 @@ class SystemTtsProvider {
|
||||
// Config //
|
||||
//########//
|
||||
|
||||
previewStrings = {
|
||||
'en-US': 'The quick brown fox jumps over the lazy dog',
|
||||
'en-GB': 'Sphinx of black quartz, judge my vow',
|
||||
'fr-FR': 'Portez ce vieux whisky au juge blond qui fume',
|
||||
'de-DE': 'Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich',
|
||||
'it-IT': "Pranzo d'acqua fa volti sghembi",
|
||||
'es-ES': 'Quiere la boca exhausta vid, kiwi, piña y fugaz jamón',
|
||||
'es-MX': 'Fabio me exige, sin tapujos, que añada cerveza al whisky',
|
||||
'ru-RU': 'В чащах юга жил бы цитрус? Да, но фальшивый экземпляр!',
|
||||
'pt-BR': 'Vejo xá gritando que fez show sem playback.',
|
||||
'pt-PR': 'Todo pajé vulgar faz boquinha sexy com kiwi.',
|
||||
'uk-UA': "Фабрикуймо гідність, лящім їжею, ґав хапаймо, з'єднавці чаш!",
|
||||
}
|
||||
fallbackPreview = 'Neque porro quisquam est qui dolorem ipsum quia dolor sit amet'
|
||||
settings
|
||||
voices = []
|
||||
separator = ' ... '
|
||||
@ -172,7 +160,7 @@ class SystemTtsProvider {
|
||||
}
|
||||
|
||||
speechSynthesis.cancel();
|
||||
const text = this.previewStrings[voice.lang] ?? this.fallbackPreview;
|
||||
const text = getPreviewString(voice.lang);
|
||||
const utterance = new SpeechSynthesisUtterance(text);
|
||||
utterance.voice = voice;
|
||||
utterance.rate = 1;
|
||||
|
@ -104,7 +104,7 @@ client.on('error', (err) => {
|
||||
console.error('An error occurred:', err);
|
||||
});
|
||||
|
||||
const poe = require('./poe-client');
|
||||
const poe = require('./src/poe-client');
|
||||
|
||||
let api_server = "http://0.0.0.0:5000";
|
||||
let api_novelai = "https://api.novelai.net";
|
||||
@ -3379,3 +3379,7 @@ async function getImageBuffers(zipFilePath) {
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
const edgeTts = require('./src/edge-tts');
|
||||
|
||||
edgeTts.addEdgeTtsEndpoints(app, jsonParser);
|
||||
|
49
src/edge-tts.js
Normal file
49
src/edge-tts.js
Normal file
@ -0,0 +1,49 @@
|
||||
const MsEdgeTTS = require('msedge-tts').MsEdgeTTS;
|
||||
|
||||
const tts = new MsEdgeTTS(true);
|
||||
|
||||
function getVoices() {
|
||||
return tts.getVoices();
|
||||
}
|
||||
|
||||
async function generateSpeech(text, voice) {
|
||||
await tts.setMetadata(voice, MsEdgeTTS.OUTPUT_FORMAT.AUDIO_24KHZ_48KBITRATE_MONO_MP3);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const readable = tts.toStream(text);
|
||||
const chunks = [];
|
||||
|
||||
readable.on("data", (data) => {
|
||||
chunks.push(data);
|
||||
});
|
||||
|
||||
readable.on("close", () => {
|
||||
const buffer = Buffer.concat(chunks);
|
||||
resolve(buffer);
|
||||
});
|
||||
|
||||
readable.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function addEdgeTtsEndpoints(app, jsonParser) {
|
||||
app.get("/edge_voices", jsonParser, async (req, res) => {
|
||||
const voices = await getVoices();
|
||||
return res.send(voices);
|
||||
});
|
||||
app.post("/edge_speech", jsonParser, async (req, res) => {
|
||||
const { text, voice } = req.body;
|
||||
|
||||
if (!text || !voice) {
|
||||
return res.sendStatus(400);
|
||||
}
|
||||
|
||||
const buffer = await generateSpeech(text, voice);
|
||||
res.set("Content-Type", "audio/mpeg");
|
||||
return res.send(buffer);
|
||||
});
|
||||
}
|
||||
|
||||
module.exports = { addEdgeTtsEndpoints };
|
Reference in New Issue
Block a user