2023-12-02 20:11:06 +01:00
import { doExtrasFetch , getApiUrl , modules } from '../../extensions.js' ;
import { saveTtsProviderSettings } from './index.js' ;
2023-07-20 19:32:15 +02:00
2023-12-02 20:11:06 +01:00
export { SileroTtsProvider } ;
2023-07-20 19:32:15 +02:00
class SileroTtsProvider {
//########//
// Config //
//########//
2023-12-02 20:11:06 +01:00
settings ;
ready = false ;
voices = [ ] ;
2024-03-14 13:56:58 +01:00
separator = ' ' ;
2023-07-20 19:32:15 +02:00
defaultSettings = {
2023-12-02 19:04:51 +01:00
provider _endpoint : 'http://localhost:8001/tts' ,
2023-12-02 21:06:57 +01:00
voiceMap : { } ,
2023-12-02 20:11:06 +01:00
} ;
2023-07-20 19:32:15 +02:00
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 >
2023-12-02 20:11:06 +01:00
` ;
return html ;
2023-07-20 19:32:15 +02:00
}
onSettingsChange ( ) {
// Used when provider settings are updated from UI
2023-12-02 20:11:06 +01:00
this . settings . provider _endpoint = $ ( '#silero_tts_endpoint' ) . val ( ) ;
saveTtsProviderSettings ( ) ;
this . refreshSession ( ) ;
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 ) {
2023-12-02 20:11:06 +01:00
console . info ( 'Using default TTS Provider settings' ) ;
2023-07-20 19:32:15 +02:00
}
// Only accept keys defined in defaultSettings
2023-12-02 20:11:06 +01:00
this . settings = this . defaultSettings ;
2023-07-20 19:32:15 +02:00
2023-11-28 18:24:26 +01:00
for ( const key in settings ) {
if ( key in this . settings ) {
2023-12-02 20:11:06 +01:00
this . settings [ key ] = settings [ key ] ;
2023-07-20 19:32:15 +02:00
} else {
2023-12-02 20:11:06 +01:00
throw ` Invalid setting passed to TTS Provider: ${ key } ` ;
2023-07-20 19:32:15 +02:00
}
}
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 ) ;
2023-12-02 20:11:06 +01:00
$ ( '#silero_tts_endpoint' ) . val ( this . settings . provider _endpoint ) ;
$ ( '#silero_tts_endpoint' ) . on ( 'input' , ( ) => { this . onSettingsChange ( ) ; } ) ;
this . refreshSession ( ) ;
2023-08-22 15:30:33 +02:00
2023-12-02 20:11:06 +01:00
await this . checkReady ( ) ;
2023-08-22 15:30:33 +02:00
2023-12-02 20:11:06 +01: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
2023-11-28 18:24:26 +01:00
async checkReady ( ) {
2023-12-02 20:11:06 +01: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-12-02 20:11:06 +01:00
return ;
2023-07-20 19:32:15 +02:00
}
2023-11-28 18:24:26 +01:00
2023-10-29 17:18:21 +01:00
async refreshSession ( ) {
2023-12-02 20:11:06 +01:00
await this . initSession ( ) ;
2023-10-29 17:18:21 +01:00
}
2023-07-20 19:32:15 +02:00
//#################//
// TTS Interfaces //
//#################//
async getVoice ( voiceName ) {
if ( this . voices . length == 0 ) {
2023-12-02 20:11:06 +01:00
this . voices = await this . fetchTtsVoiceObjects ( ) ;
2023-07-20 19:32:15 +02:00
}
const match = this . voices . filter (
2023-12-02 21:06:57 +01:00
sileroVoice => sileroVoice . name == voiceName ,
2023-12-02 20:11:06 +01:00
) [ 0 ] ;
2023-07-20 19:32:15 +02:00
if ( ! match ) {
2023-12-02 20:11:06 +01:00
throw ` TTS Voice name ${ voiceName } not found ` ;
2023-07-20 19:32:15 +02:00
}
2023-12-02 20:11:06 +01:00
return match ;
2023-07-20 19:32:15 +02:00
}
2023-11-28 18:24:26 +01:00
async generateTts ( text , voiceId ) {
2023-12-02 20:11:06 +01:00
const response = await this . fetchTtsGeneration ( text , voiceId ) ;
return response ;
2023-07-20 19:32:15 +02:00
}
//###########//
// API CALLS //
//###########//
2023-08-26 05:52:26 +02:00
async fetchTtsVoiceObjects ( ) {
2023-12-02 20:11:06 +01:00
const response = await doExtrasFetch ( ` ${ this . settings . provider _endpoint } /speakers ` ) ;
2023-07-20 19:32:15 +02:00
if ( ! response . ok ) {
2023-12-02 20:11:06 +01:00
throw new Error ( ` HTTP ${ response . status } : ${ await response . json ( ) } ` ) ;
2023-07-20 19:32:15 +02:00
}
2023-12-02 20:11:06 +01:00
const responseJson = await response . json ( ) ;
return responseJson ;
2023-07-20 19:32:15 +02:00
}
async fetchTtsGeneration ( inputText , voiceId ) {
2023-12-02 20:11:06 +01:00
console . info ( ` Generating new TTS for voice_id ${ voiceId } ` ) ;
2023-07-20 19:32:15 +02:00
const response = await doExtrasFetch (
` ${ this . settings . provider _endpoint } /generate ` ,
{
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
2023-12-02 21:06:57 +01:00
'Cache-Control' : 'no-cache' , // Added this line to disable caching of file so new files are always played - Rolyat 7/7/23
2023-07-20 19:32:15 +02:00
} ,
body : JSON . stringify ( {
2023-12-02 19:04:51 +01:00
'text' : inputText ,
'speaker' : voiceId ,
2023-12-02 21:06:57 +01:00
'session' : 'sillytavern' ,
} ) ,
} ,
2023-12-02 20:11:06 +01:00
) ;
2023-07-20 19:32:15 +02:00
if ( ! response . ok ) {
toastr . error ( response . statusText , 'TTS Generation Failed' ) ;
throw new Error ( ` HTTP ${ response . status } : ${ await response . text ( ) } ` ) ;
}
2023-12-02 20:11:06 +01:00
return response ;
2023-07-20 19:32:15 +02:00
}
2023-11-28 18:24:26 +01:00
2023-10-29 17:18:21 +01:00
async initSession ( ) {
2023-12-02 19:04:51 +01:00
console . info ( 'Silero TTS: requesting new session' ) ;
2023-11-28 18:24:26 +01:00
try {
const response = await doExtrasFetch (
` ${ this . settings . provider _endpoint } /session ` ,
{
method : 'POST' ,
headers : {
'Content-Type' : 'application/json' ,
'Cache-Control' : 'no-cache' ,
} ,
body : JSON . stringify ( {
2023-12-02 19:04:51 +01:00
'path' : 'sillytavern' ,
2023-11-28 18:24:26 +01:00
} ) ,
2023-12-02 21:06:57 +01:00
} ,
2023-12-02 20:11:06 +01:00
) ;
2023-11-28 18:24:26 +01:00
if ( ! response . ok && response . status !== 404 ) {
throw new Error ( ` HTTP ${ response . status } : ${ await response . text ( ) } ` ) ;
2023-10-29 17:18:21 +01:00
}
2023-11-28 18:24:26 +01:00
} catch ( error ) {
console . info ( 'Silero TTS: endpoint not available' , error ) ;
2023-10-29 17:18:21 +01:00
}
}
2023-07-20 19:32:15 +02:00
// Interface not used by Silero TTS
async fetchTtsFromHistory ( history _item _id ) {
return Promise . resolve ( history _item _id ) ;
}
}