This commit is contained in:
Saifeddine ALOUI 2024-05-05 16:01:24 +02:00
parent fc8b48adf6
commit ab4ce7a857
11 changed files with 391 additions and 350 deletions

View File

@ -1,5 +1,5 @@
# =================== Lord Of Large Language Multimodal Systems Configuration file ===========================
version: 90
version: 91
binding_name: null
model_name: null
model_variant: null
@ -81,9 +81,9 @@ auto_show_browser: true
copy_to_clipboard_add_all_details: false
# Voice service
enable_voice_service: false
xtts_enable: false
xtts_base_url: http://localhost:8020
xtts_use_deepspeed: false
xtts_use_deepspeed: true
xtts_use_streaming_mode: true
auto_read: false
xtts_current_voice: null

@ -1 +1 @@
Subproject commit e63dcb81ad726108183724b23f6553e5d28d5258
Subproject commit c370b6ecceaa4437de1379ad1e08287b71bb51ca

View File

@ -433,7 +433,7 @@ class LOLLMSWebUI(LOLLMSElfServer):
run_scripts=True)
mounted_personalities.append(personality)
if self.config.enable_voice_service and self.config.auto_read and len(personality.audio_samples)>0:
if self.config.xtts_enable and self.config.auto_read and len(personality.audio_samples)>0:
try:
from lollms.services.xtts.lollms_xtts import LollmsXTTS
if self.tts is None:
@ -1194,7 +1194,7 @@ class LOLLMSWebUI(LOLLMSElfServer):
client_id=client_id,
callback=partial(self.process_chunk,client_id = client_id)
)
if self.config.enable_voice_service and self.config.auto_read and len(self.personality.audio_samples)>0:
if self.config.xtts_enable and self.config.auto_read and len(self.personality.audio_samples)>0:
try:
self.process_chunk("Generating voice output",MSG_TYPE.MSG_TYPE_STEP_START,client_id=client_id)
from lollms.services.xtts.lollms_xtts import LollmsXTTS

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

4
web/dist/index.html vendored
View File

@ -6,8 +6,8 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>LoLLMS WebUI - Welcome</title>
<script type="module" crossorigin src="/assets/index-9dd9fa43.js"></script>
<link rel="stylesheet" href="/assets/index-69152375.css">
<script type="module" crossorigin src="/assets/index-f1cd900e.js"></script>
<link rel="stylesheet" href="/assets/index-f6ab05b8.css">
</head>
<body>
<div id="app"></div>

View File

@ -155,7 +155,7 @@
</div>
<div class="flex flex-row items-center">
<div v-if="!isSynthesizingVoice" class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2 cursor-pointer"
title="read"
title="generate_audio"
@click.stop="read()"
>
<i data-feather="voicemail"></i>
@ -491,7 +491,7 @@ export default {
}
else{
this.isSynthesizingVoice=true
axios.post("./text2Audio",{text:this.message.content}).then(response => {
axios.post("./text2wav",{text:this.message.content}).then(response => {
this.isSynthesizingVoice=false
let url = response.data.url
console.log(url)
@ -520,81 +520,97 @@ export default {
}
},
speak() {
if (this.msg) {
this.speechSynthesis.cancel();
this.msg = null;
this.isSpeaking = false;
return;
}
let startIndex =0;
// Set isSpeaking to true before starting synthesis
console.log("voice on")
this.isSpeaking = true;
const chunkSize = 200; // You can adjust the chunk size as needed
this.message.content;
// Create a new SpeechSynthesisUtterance instance
this.msg = new SpeechSynthesisUtterance();
this.msg.pitch = this.$store.state.config.audio_pitch;
// Optionally, set the voice and other parameters as before
if (this.voices.length > 0) {
this.msg.voice = this.voices.filter(voice => voice.name === this.$store.state.config.audio_out_voice)[0];
}
// Function to find the index of the last sentence that fits within the chunk size
const findLastSentenceIndex = (startIndex) => {
let txt = this.message.content.substring(startIndex, startIndex+chunkSize)
// Define an array of characters that represent end of sentence markers.
const endOfSentenceMarkers = ['.', '!', '?', '\n'];
// Initialize a variable to store the index of the last end of sentence marker.
let lastIndex = -1;
// Iterate through the end of sentence markers and find the last occurrence in the txt string.
endOfSentenceMarkers.forEach(marker => {
const markerIndex = txt.lastIndexOf(marker);
if (markerIndex > lastIndex) {
lastIndex = markerIndex;
}
if(this.$store.state.config.xtts_enable){
this.isSpeaking = true;
axios.post("./text2Audio",{text:this.message.content}).then(response => {
this.isSpeaking = false;
}).catch(ex=>{
this.$store.state.toast.showToast(`Error: ${ex}`,4,false)
this.isSpeaking = false;
});
if(lastIndex==-1){lastIndex=txt.length}
console.log(lastIndex)
return lastIndex+startIndex+1;
};
}
else{
if (this.msg) {
this.speechSynthesis.cancel();
this.msg = null;
this.isSpeaking = false;
return;
}
let startIndex =0;
// Set isSpeaking to true before starting synthesis
console.log("voice on")
this.isSpeaking = true;
// Function to speak a chunk of text
const speakChunk = () => {
if (this.message.content.includes('.')){
const endIndex = findLastSentenceIndex(startIndex);
const chunk = this.message.content.substring(startIndex, endIndex);
this.msg.text = chunk;
startIndex = endIndex + 1;
this.msg.onend = (event) => {
if (startIndex < this.message.content.length-2) {
// Use setTimeout to add a brief delay before speaking the next chunk
setTimeout(() => {
const chunkSize = 200; // You can adjust the chunk size as needed
this.message.content;
// Create a new SpeechSynthesisUtterance instance
this.msg = new SpeechSynthesisUtterance();
this.msg.pitch = this.$store.state.config.audio_pitch;
// Optionally, set the voice and other parameters as before
if (this.voices.length > 0) {
this.msg.voice = this.voices.filter(voice => voice.name === this.$store.state.config.audio_out_voice)[0];
}
// Function to find the index of the last sentence that fits within the chunk size
const findLastSentenceIndex = (startIndex) => {
let txt = this.message.content.substring(startIndex, startIndex+chunkSize)
// Define an array of characters that represent end of sentence markers.
const endOfSentenceMarkers = ['.', '!', '?', '\n'];
// Initialize a variable to store the index of the last end of sentence marker.
let lastIndex = -1;
// Iterate through the end of sentence markers and find the last occurrence in the txt string.
endOfSentenceMarkers.forEach(marker => {
const markerIndex = txt.lastIndexOf(marker);
if (markerIndex > lastIndex) {
lastIndex = markerIndex;
}
});
if(lastIndex==-1){lastIndex=txt.length}
console.log(lastIndex)
return lastIndex+startIndex+1;
};
// Function to speak a chunk of text
const speakChunk = () => {
if (this.message.content.includes('.')){
const endIndex = findLastSentenceIndex(startIndex);
const chunk = this.message.content.substring(startIndex, endIndex);
this.msg.text = chunk;
startIndex = endIndex + 1;
this.msg.onend = (event) => {
if (startIndex < this.message.content.length-2) {
// Use setTimeout to add a brief delay before speaking the next chunk
setTimeout(() => {
speakChunk();
}, 1); // Adjust the delay as needed
} else {
this.isSpeaking = false;
console.log("voice off :",this.message.content.length," ",endIndex)
}
};
this.speechSynthesis.speak(this.msg);
}
else{
setTimeout(() => {
speakChunk();
}, 1); // Adjust the delay as needed
} else {
this.isSpeaking = false;
console.log("voice off :",this.message.content.length," ",endIndex)
}
};
this.speechSynthesis.speak(this.msg);
}
};
// Speak the first chunk
speakChunk();
}
}
else{
setTimeout(() => {
speakChunk();
}, 1); // Adjust the delay as needed
}
};
// Speak the first chunk
speakChunk();
},
toggleModel() {

View File

@ -21,6 +21,17 @@
>
Playground
</RouterLink>
<RouterLink
v-if="$store.state.config.enable_sd_service"
:to="{ name: 'AutoSD' }"
class="inline-block border-l border-t border-r rounded-t py-2 px-4 text-blue-700 font-semibold"
:class="{
'text-green-600 hover:text-green-500 dark:text-green-100 font-bold bg-bg-secondary shadow-no-bottom': isRouteActive('AutoSD'),
'bounce-in': isRouteActive('AutoSD'),
}"
>
Auto111-SD
</RouterLink>
<RouterLink
v-if="$store.state.config.enable_comfyui_service"
:to="{ name: 'ComfyUI' }"
@ -33,7 +44,7 @@
ComfyUI
</RouterLink>
<RouterLink
v-if="$store.state.config.enable_voice_service"
v-if="$store.state.config.xtts_enable"
:to="{ name: 'interactive' }"
class="inline-block border-l border-t border-r rounded-t py-2 px-4 text-blue-700 font-semibold"
:class="{

View File

@ -9,12 +9,18 @@ import DiscussionsView from '../views/DiscussionsView.vue'
import InteractiveView from '../views/InteractiveView.vue'
import NodesView from '../views/NodesView.vue'
import ComfyuiView from '../views/ComfyuiView.vue'
import AutoSDView from '../views/AutoSDView.vue'
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL),
routes: [
{
path: '/comfyui_view/',
path: '/auto_sd_view/',
name: 'AutoSD',
component: AutoSDView
},
{
path: '/autosd_view/',
name: 'ComfyUI',
component: ComfyuiView
},

View File

@ -1,10 +1,10 @@
<template>
<div style="width: 100vw; height: 100vh">
<iframe :src="$store.state.config.comfyui_base_url" class="m-0 p-0 w-full h-full"></iframe>
</div>
</template>
<script>
//import "../css/classic.css";
</script>
<div style="width: 100vw; height: 100vh">
<iframe :src="$store.state.config.comfyui_base_url" class="m-0 p-0 w-full h-full"></iframe>
</div>
</template>
<script>
//import "../css/classic.css";
</script>

View File

@ -228,10 +228,10 @@
<label for="app_custom_logo" class="text-sm font-bold" style="margin-right: 1rem;">Application logo:</label>
</td>
<td>
<label for="avatar-upload">
<img :src="configFile.app_custom_logo!=''? '/user_infos/'+configFile.app_custom_logo:storeLogo" class="w-50 h-50 rounded-full" style="max-width: 50px; max-height: 50px; cursor: pointer;">
<label for="logo-upload">
<img :src="configFile.app_custom_logo!=null && configFile.app_custom_logo!=''? '/user_infos/'+configFile.app_custom_logo:storeLogo" class="w-50 h-50 rounded-full" style="max-width: 50px; max-height: 50px; cursor: pointer;">
</label>
<input type="file" id="avatar-upload" style="display: none" @change="uploadLogo">
<input type="file" id="logo-upload" style="display: none" @change="uploadLogo">
</td>
<td style="width: 10%;">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 " title="Discard title changes"
@ -496,9 +496,9 @@
</td>
<td>
<label for="avatar-upload">
<img :src="configFile.user_avatar!=''?'/user_infos/'+configFile.user_avatar: storeLogo" class="w-50 h-50 rounded-full" style="max-width: 50px; max-height: 50px; cursor: pointer;">
<img :src="configFile.user_avatar!=null && configFile.user_avatar!=''?'/user_infos/'+configFile.user_avatar: storeLogo" class="w-50 h-50 rounded-full" style="max-width: 50px; max-height: 50px; cursor: pointer;">
</label>
<input type="file" id="avatar-upload" style="display: none" @change="uploadAvatar()">
<input type="file" id="avatar-upload" style="display: none" @change="uploadAvatar">
</td>
<td style="width: 10%;">
<button class="text-2xl hover:text-red-600 duration-75 active:scale-90 " title="Discard title changes"
@ -1458,6 +1458,11 @@
<a class="hover:text-primary bg-green-200 rounded-lg p-4 m-4 w-full text-center items-center" href="https://github.com/ParisNeo/stable-diffusion-webui/blob/master/LICENSE.txt" target="_blank">automatic1111's sd licence</a>
</div>
</td>
<td>
<div class="flex flex-row">
<button class="hover:text-primary bg-green-200 rounded-lg p-4 m-4 w-full text-center items-center" @click="reinstallSDService">install sd service</button>
</div>
</td>
</tr>
<tr>
<td style="min-width: 200px;">
@ -1839,7 +1844,7 @@
<table class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<tr>
<td style="min-width: 200px;">
<label for="enable_voice_service" class="text-sm font-bold" style="margin-right: 1rem;">Enable elastic search service:</label>
<label for="xtts_enable" class="text-sm font-bold" style="margin-right: 1rem;">Enable elastic search service:</label>
</td>
<td>
<div class="flex flex-row">
@ -1889,15 +1894,15 @@
<table class="bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:ring-blue-500 focus:border-blue-500 block w-full p-2.5 dark:bg-gray-700 dark:border-gray-600 dark:placeholder-gray-400 dark:text-white dark:focus:ring-blue-500 dark:focus:border-blue-500">
<tr>
<td style="min-width: 200px;">
<label for="enable_voice_service" class="text-sm font-bold" style="margin-right: 1rem;">Enable voice service:</label>
<label for="xtts_enable" class="text-sm font-bold" style="margin-right: 1rem;">Enable voice service:</label>
</td>
<td>
<div class="flex flex-row">
<input
type="checkbox"
id="enable_voice_service"
id="xtts_enable"
required
v-model="configFile.enable_voice_service"
v-model="configFile.xtts_enable"
@change="settingsChanged=true"
class="mt-1 px-2 py-1 border border-gray-300 rounded dark:bg-gray-600"
>
@ -1938,7 +1943,7 @@
</td>
<td>
<div class="flex flex-row">
<select v-model="current_language" @change="settingsChanged=true" :disabled="!enable_voice_service">
<select v-model="current_language" @change="settingsChanged=true" :disabled="!xtts_enable">
<option v-for="(value, key) in voice_languages" :key="key" :value="value">
{{ key }}
</option>
@ -1953,7 +1958,7 @@
</td>
<td>
<div class="flex flex-row">
<select v-model="xtts_current_voice" @change="settingsChanged=true" :disabled="!enable_voice_service">
<select v-model="xtts_current_voice" @change="settingsChanged=true" :disabled="!xtts_enable">
<option v-for="voice in voices" :key="voice" :value="voice">
{{ voice }}
</option>
@ -1974,7 +1979,7 @@
v-model="configFile.xtts_use_deepspeed"
@change="settingsChanged=true"
class="mt-1 px-2 py-1 border border-gray-300 rounded dark:bg-gray-600"
:disabled="!enable_voice_service"
:disabled="!xtts_enable"
>
</div>
</td>
@ -1992,7 +1997,7 @@
v-model="configFile.xtts_use_streaming_mode"
@change="settingsChanged=true"
class="mt-1 px-2 py-1 border border-gray-300 rounded dark:bg-gray-600"
:disabled="!enable_voice_service"
:disabled="!xtts_enable"
>
</div>
</td>
@ -2010,7 +2015,7 @@
v-model="configFile.auto_read"
@change="settingsChanged=true"
class="mt-1 px-2 py-1 border border-gray-300 rounded dark:bg-gray-600"
:disabled="!enable_voice_service"
:disabled="!xtts_enable"
>
</div>
</td>
@ -3112,9 +3117,12 @@ export default {
//await socket.on('install_progress', this.progressListener);
//refreshHardwareUsage()
},
methods: {
methods: {
install_model(){
},
reinstallSDService(){
axios.get('install_sd')
axios.post('/install_sd', {client_id:this.$store.state.client_id}, this.posts_headers)
.then(response => {
})
@ -3124,7 +3132,7 @@ export default {
},
upgradeSDService(){
axios.get('upgrade_sd')
axios.post('upgrade_sd', {client_id:this.$store.state.client_id}, this.posts_headers)
.then(response => {
})
@ -3134,7 +3142,7 @@ export default {
},
startSDService(){
axios.get('start_sd')
axios.post('start_sd', {client_id:this.$store.state.client_id}, this.posts_headers)
.then(response => {
})
@ -3144,7 +3152,7 @@ export default {
},
showSD(){
axios.get('show_sd')
axios.post('show_sd', {client_id:this.$store.state.client_id}, this.posts_headers)
.then(response => {
})
@ -3427,7 +3435,7 @@ export default {
const file = event.target.files[0]; // Get the selected file
const formData = new FormData(); // Create a FormData object
formData.append('logo', file); // Add the file to the form data with the key 'avatar'
console.log("Uploading avatar")
console.log("Uploading logo")
// Make an API request to upload the avatar
axios.post('/upload_logo', formData)
.then(response => {
@ -5478,13 +5486,13 @@ export default {
this.$store.state.config.auto_read = value
},
},
enable_voice_service:{
xtts_enable:{
get() {
return this.$store.state.config.enable_voice_service;
return this.$store.state.config.xtts_enable;
},
set(value) {
// You should not set the value directly here; use the updateSetting method instead
this.$store.state.config.enable_voice_service = value
this.$store.state.config.xtts_enable = value
},
},
current_language:{
@ -5726,7 +5734,7 @@ export default {
},
watch: {
enable_voice_service(newValue) {
xtts_enable(newValue) {
if (!newValue) {
this.configFile.auto_read = false;
}