2023-07-20 19:32:15 +02:00
import { doExtrasFetch , getApiUrl , modules } from "../../extensions.js"
2023-08-26 05:52:26 +02:00
import { saveTtsProviderSettings } from "./index.js"
2023-07-20 19:32:15 +02:00
export { SileroTtsProvider }
class SileroTtsProvider {
//########//
// Config //
//########//
settings
2023-08-22 15:30:33 +02:00
ready = false
2023-07-20 19:32:15 +02:00
voices = [ ]
separator = ' .. '
defaultSettings = {
provider _endpoint : "http://localhost:8001/tts" ,
voiceMap : { }
}
get settingsHtml ( ) {
let html = `
< label for = "silero_tts_endpoint" > Provider Endpoint : < / l a b e l >
< input id = "silero_tts_endpoint" type = "text" class = "text_pole" maxlength = "250" value = "${this.defaultSettings.provider_endpoint}" / >
< span >
< span > Use < a target = "_blank" href = "https://github.com/SillyTavern/SillyTavern-extras" > SillyTavern Extras API < /a> or <a target="_blank" href="https:/ / github . com / ouoertheo / silero - api - server " > Silero TTS Server < / a > . < / s p a n >
`
return html
}
onSettingsChange ( ) {
// Used when provider settings are updated from UI
this . settings . provider _endpoint = $ ( '#silero_tts_endpoint' ) . val ( )
2023-08-26 05:52:26 +02:00
saveTtsProviderSettings ( )
2023-07-20 19:32:15 +02:00
}
2023-08-28 20:58:46 +02:00
async loadSettings ( settings ) {
2023-07-20 19:32:15 +02:00
// 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 } `
}
}
const apiCheckInterval = setInterval ( ( ) => {
// Use Extras API if TTS support is enabled
if ( modules . includes ( 'tts' ) || modules . includes ( 'silero-tts' ) ) {
const baseUrl = new URL ( getApiUrl ( ) ) ;
baseUrl . pathname = '/api/tts' ;
this . settings . provider _endpoint = baseUrl . toString ( ) ;
$ ( '#silero_tts_endpoint' ) . val ( this . settings . provider _endpoint ) ;
clearInterval ( apiCheckInterval ) ;
}
} , 2000 ) ;
$ ( '#silero_tts_endpoint' ) . val ( this . settings . provider _endpoint )
2023-08-25 15:51:35 +02:00
$ ( '#silero_tts_endpoint' ) . on ( "input" , ( ) => { this . onSettingsChange ( ) } )
2023-08-22 15:30:33 +02:00
2023-08-28 20:58:46 +02:00
await this . checkReady ( )
2023-08-22 15:30:33 +02:00
2023-09-05 17:23:24 +02:00
console . debug ( "SileroTTS: Settings loaded" )
2023-07-20 19:32:15 +02:00
}
2023-08-22 15:30:33 +02:00
// Perform a simple readiness check by trying to fetch voiceIds
async checkReady ( ) {
2023-08-26 05:52:26 +02:00
await this . fetchTtsVoiceObjects ( )
2023-08-22 15:30:33 +02:00
}
2023-07-20 19:32:15 +02:00
2023-08-26 05:52:26 +02:00
async onRefreshClick ( ) {
2023-07-20 19:32:15 +02:00
return
}
//#################//
// TTS Interfaces //
//#################//
async getVoice ( voiceName ) {
if ( this . voices . length == 0 ) {
2023-08-26 05:52:26 +02:00
this . voices = await this . fetchTtsVoiceObjects ( )
2023-07-20 19:32:15 +02:00
}
const match = this . voices . filter (
sileroVoice => sileroVoice . 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 //
//###########//
2023-08-26 05:52:26 +02:00
async fetchTtsVoiceObjects ( ) {
2023-07-20 19:32:15 +02:00
const response = await doExtrasFetch ( ` ${ this . settings . provider _endpoint } /speakers ` )
if ( ! response . ok ) {
throw new Error ( ` HTTP ${ response . status } : ${ await response . json ( ) } ` )
}
const responseJson = await response . json ( )
return responseJson
}
async fetchTtsGeneration ( inputText , voiceId ) {
console . info ( ` Generating new TTS for voice_id ${ voiceId } ` )
const response = await doExtrasFetch (
` ${ this . settings . provider _endpoint } /generate ` ,
{
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
'Cache-Control' : 'no-cache' // Added this line to disable caching of file so new files are always played - Rolyat 7/7/23
} ,
body : JSON . stringify ( {
"text" : inputText ,
"speaker" : voiceId
} )
}
)
if ( ! response . ok ) {
toastr . error ( response . statusText , 'TTS Generation Failed' ) ;
throw new Error ( ` HTTP ${ response . status } : ${ await response . text ( ) } ` ) ;
}
return response
}
// Interface not used by Silero TTS
async fetchTtsFromHistory ( history _item _id ) {
return Promise . resolve ( history _item _id ) ;
}
}