enhanced ui and upgraded. Now audio in and audio out are working

This commit is contained in:
Saifeddine ALOUI 2023-07-22 02:26:40 +02:00
parent e43d9cf4b2
commit dec6811571
8 changed files with 262 additions and 55 deletions

View File

@ -1,5 +1,5 @@
# =================== Lord Of Large Language Models Configuration file ===========================
version: 13
version: 14
binding_name: null
model_name: null
@ -42,5 +42,6 @@ auto_update: false
# Audio
audio_language: 'en-US'
audio_in_language: 'en-US'
audio_out_voice: null
silenceTimer: 5000

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-88284c86.js"></script>
<link rel="stylesheet" href="/assets/index-3c6d3c05.css">
<script type="module" crossorigin src="/assets/index-559e0f27.js"></script>
<link rel="stylesheet" href="/assets/index-ccd4ce08.css">
</head>
<body>
<div id="app"></div>

View File

@ -281,7 +281,7 @@ export default {
startSpeechRecognition() {
if ('SpeechRecognition' in window || 'webkitSpeechRecognition' in window) {
this.recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
this.recognition.lang = this.$store.state.config.audio_language; // Set the language, adjust as needed
this.recognition.lang = this.$store.state.config.audio_in_language; // Set the language, adjust as needed
this.recognition.interimResults = true; // Enable interim results to get real-time updates
this.recognition.onstart = () => {

View File

@ -27,7 +27,14 @@
</button>
<button
@click="validateChoice"
class="py-2 px-4 bg-blue-500 hover:bg-blue-600 text-white rounded-lg transition duration-300"
:class="{
'bg-gray-400 cursor-not-allowed': !selectedChoice,
'bg-blue-500 hover:bg-blue-600': selectedChoice,
'text-white': selectedChoice,
'text-gray-500': !selectedChoice,
}"
:disabled="!selectedChoice"
class="py-2 px-4 rounded-lg transition duration-300"
>
Validate
</button>

View File

@ -115,6 +115,14 @@
message.rank }}
</div>
</div>
<div class="flex flex-row items-center">
<div class="text-lg hover:text-red-600 duration-75 active:scale-90 p-2"
title="speak"
@click.stop="speak()"
:class="{ 'text-red-500': isTalking }">
<i data-feather="volume-2"></i>
</div>
</div>
</div>
</div>
</div>
@ -133,7 +141,7 @@
<textarea v-if="editMsgMode" ref="mdTextarea" :rows="4"
class="block p-2.5 w-full text-sm text-gray-900 bg-gray-50 rounded-lg border border-gray-300 focus:ring-blue-500 focus:border-blue-500 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"
:style="{ minHeight: mdRenderHeight + `px` }" placeholder="Enter message here..."
v-model="new_message_content"></textarea>
v-model="this.message.content"></textarea>
</div>
<!-- FOOTER -->
<div class="text-sm text-gray-400 mt-2">
@ -189,8 +197,10 @@ export default {
},
data() {
return {
isVoiceActive:false,
speechSynthesis: null,
voices: [],
expanded: false,
new_message_content: '',
showConfirmation: false,
editMsgMode: false,
deleteMsgMode: false,
@ -198,13 +208,57 @@ export default {
}
}, mounted() {
this.new_message_content = this.message.content
// Check if speech synthesis is supported by the browser
if ('speechSynthesis' in window) {
this.speechSynthesis = window.speechSynthesis;
// Load the available voices
this.voices = this.speechSynthesis.getVoices();
// Make sure the voices are loaded before starting speech synthesis
if (this.voices.length === 0) {
this.speechSynthesis.addEventListener('voiceschanged', this.onVoicesChanged);
} else {
}
} else {
console.error('Speech synthesis is not supported in this browser.');
}
nextTick(() => {
feather.replace()
this.mdRenderHeight = this.$refs.mdRender.$el.offsetHeight
})
}, methods: {
onVoicesChanged() {
// This event will be triggered when the voices are loaded
this.voices = this.speechSynthesis.getVoices();
},
speak() {
// Assuming you have received the text from your backend and stored it in a variable called "streamedText"
const textToSpeak = this.message.content;
// Create a new SpeechSynthesisUtterance instance
const msg = new SpeechSynthesisUtterance();
msg.text = textToSpeak;
// Optionally, you can set the voice and other parameters
// For example, to set the voice, assuming you want the first voice available:
if (this.voices.length > 0) {
msg.voice = this.voices[0];
}
// Set isVoiceActive to true before starting synthesis
this.isVoiceActive = true;
// Listen for the end event to set isVoiceActive to false after synthesis completes
msg.addEventListener('end', () => {
this.isVoiceActive = false;
});
// Speak the text
this.speechSynthesis.speak(msg);
},
toggleModel() {
this.expanded = !this.expanded;
},
@ -225,14 +279,14 @@ export default {
},
updateMessage() {
this.$emit('updateMessage', this.message.id, this.new_message_content)
this.$emit('updateMessage', this.message.id, this.message.content)
this.editMsgMode = false
},
resendMessage() {
this.$emit('resendMessage', this.message.id, this.new_message_content)
this.$emit('resendMessage', this.message.id, this.message.content)
},
continueMessage() {
this.$emit('continueMessage', this.message.id, this.new_message_content)
this.$emit('continueMessage', this.message.id, this.message.content)
},
getImgUrl() {
if (this.avatar) {
@ -314,10 +368,6 @@ export default {
editMsgMode(val) {
if (!val) {
this.new_message_content = this.message.content
}
nextTick(() => {
feather.replace()
@ -332,6 +382,11 @@ export default {
},
computed: {
isTalking :{
get(){
return this.isVoiceActive
}
},
created_at() {
return this.prettyDate(this.message.created_at)

View File

@ -668,6 +668,60 @@
</button>
</td>
</tr>
<tr>
<td style="min-width: 200px;">
<label for="audio_in_language" class="text-sm font-bold" style="margin-right: 1rem;">Input Audio Language:</label>
</td>
<td>
<!-- Select element for choosing the input audio language -->
<select
id="audio_in_language"
v-model="audio_in_language"
class="mt-1 px-2 py-1 border border-gray-300 rounded"
>
<!-- Options with language codes and corresponding language names -->
<option v-for="language in audioLanguages" :key="language.code" :value="language.code">
{{ language.name }}
</option>
</select>
</td>
<td>
<button
class="hover:text-secondary bg-blue-100 m-2 p-2 duration-75 flex justify-center w-full hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg"
@click="update_setting('audio_in_language', audio_in_language)"
>
<i data-feather="check"></i>
</button>
</td>
</tr>
<tr>
<td style="min-width: 200px;">
<label for="audio_out_voice" class="text-sm font-bold" style="margin-right: 1rem;">Output Audio Voice:</label>
</td>
<td>
<!-- Select element for choosing the output audio voice -->
<select
id="audio_out_voice"
v-model="audio_out_voice"
class="mt-1 px-2 py-1 border border-gray-300 rounded"
>
<!-- Options with available voices in the browser -->
<option v-for="voice in audioVoices" :key="voice.name" :value="voice.name">
{{ voice.name }}
</option>
</select>
</td>
<td>
<button
class="hover:text-secondary bg-blue-100 m-2 p-2 duration-75 flex justify-center w-full hover:bg-bg-light-tone hover:dark:bg-bg-dark-tone rounded-lg"
@click="update_setting('audio_out_voice', audio_out_voice)"
>
<i data-feather="check"></i>
</button>
</td>
</tr>
</table>
<!-- Row 0 -->
@ -1526,6 +1580,8 @@ export default {
data() {
return {
audioVoices:[],
// update
has_updates:false,
// Variant selection
variant_choices:[],
@ -1591,6 +1647,18 @@ export default {
},
methods: {
getVoices() {
// Fetch available voices from the SpeechSynthesis API
if ('speechSynthesis' in window) {
speechSynthesis.onvoiceschanged = () => {
this.audioVoices = speechSynthesis.getVoices();
// Set a default voice if needed
if (!this.audio_out_voice && this.audioVoices.length > 0) {
this.audio_out_voice = this.audioVoices[0].name;
}
};
}
},
async updateHasUpdates() {
let res = await this.api_get_req("check_update");
this.has_updates = res["update_availability"];
@ -2870,7 +2938,8 @@ export default {
}, async mounted() {
this.constructor()
console.log("Getting voices")
this.getVoices();
},
activated() {
if (this.isMounted) {
@ -2878,6 +2947,72 @@ export default {
}
},
computed: {
audio_out_voice:{
get() {
return this.$store.state.config.audio_out_voice;
},
set(value) {
this.$store.state.config.audio_out_voice = value;
},
},
audioLanguages() {
// Replace this with your own list of language codes and names
// Example data structure: [{ code: 'en-US', name: 'English (US)' }, ...]
return [
{ code: 'en-US', name: 'English (US)' },
{ code: 'en-GB', name: 'English (UK)' },
{ code: 'es-ES', name: 'Spanish (Spain)' },
{ code: 'es-MX', name: 'Spanish (Mexico)' },
{ code: 'fr-FR', name: 'French (France)' },
{ code: 'fr-CA', name: 'French (Canada)' },
{ code: 'de-DE', name: 'German (Germany)' },
{ code: 'it-IT', name: 'Italian (Italy)' },
{ code: 'pt-BR', name: 'Portuguese (Brazil)' },
{ code: 'pt-PT', name: 'Portuguese (Portugal)' },
{ code: 'ru-RU', name: 'Russian (Russia)' },
{ code: 'zh-CN', name: 'Chinese (China)' },
{ code: 'ja-JP', name: 'Japanese (Japan)' },
{ code: 'ar-SA', name: 'Arabic (Saudi Arabia)' },
{ code: 'tr-TR', name: 'Turkish (Turkey)' },
{ code: 'ms-MY', name: 'Malay (Malaysia)' },
{ code: 'ko-KR', name: 'Korean (South Korea)' },
{ code: 'nl-NL', name: 'Dutch (Netherlands)' },
{ code: 'sv-SE', name: 'Swedish (Sweden)' },
{ code: 'da-DK', name: 'Danish (Denmark)' },
{ code: 'fi-FI', name: 'Finnish (Finland)' },
{ code: 'no-NO', name: 'Norwegian (Norway)' },
{ code: 'pl-PL', name: 'Polish (Poland)' },
{ code: 'el-GR', name: 'Greek (Greece)' },
{ code: 'hu-HU', name: 'Hungarian (Hungary)' },
{ code: 'cs-CZ', name: 'Czech (Czech Republic)' },
{ code: 'th-TH', name: 'Thai (Thailand)' },
{ code: 'hi-IN', name: 'Hindi (India)' },
{ code: 'he-IL', name: 'Hebrew (Israel)' },
{ code: 'id-ID', name: 'Indonesian (Indonesia)' },
{ code: 'vi-VN', name: 'Vietnamese (Vietnam)' },
{ code: 'uk-UA', name: 'Ukrainian (Ukraine)' },
{ code: 'ro-RO', name: 'Romanian (Romania)' },
{ code: 'bg-BG', name: 'Bulgarian (Bulgaria)' },
{ code: 'hr-HR', name: 'Croatian (Croatia)' },
{ code: 'sr-RS', name: 'Serbian (Serbia)' },
{ code: 'sk-SK', name: 'Slovak (Slovakia)' },
{ code: 'sl-SI', name: 'Slovenian (Slovenia)' },
{ code: 'et-EE', name: 'Estonian (Estonia)' },
{ code: 'lv-LV', name: 'Latvian (Latvia)' },
{ code: 'lt-LT', name: 'Lithuanian (Lithuania)' },
{ code: 'ka-GE', name: 'Georgian (Georgia)' },
{ code: 'hy-AM', name: 'Armenian (Armenia)' },
{ code: 'az-AZ', name: 'Azerbaijani (Azerbaijan)' },
{ code: 'kk-KZ', name: 'Kazakh (Kazakhstan)' },
{ code: 'uz-UZ', name: 'Uzbek (Uzbekistan)' },
{ code: 'kkj-CM', name: 'Kako (Cameroon)' },
{ code: 'my-MM', name: 'Burmese (Myanmar)' },
{ code: 'ne-NP', name: 'Nepali (Nepal)' },
{ code: 'si-LK', name: 'Sinhala (Sri Lanka)' },
// Add more language entries as needed
];
},
configFile: {
get() {
return this.$store.state.config;
@ -2925,6 +3060,15 @@ export default {
},
},
audio_in_language:{
get() {
return this.$store.state.config.audio_in_language;
},
set(value) {
// You should not set the value directly here; use the updateSetting method instead
this.$store.state.config.audio_in_language = value
},
},
use_user_name_in_discussions: {
get() {