mirror of
https://github.com/ParisNeo/lollms-webui.git
synced 2025-02-21 09:31:45 +00:00
First working AUdio in and audio out
This commit is contained in:
parent
8a38b44b88
commit
f5fdf189d2
17
app.py
17
app.py
@ -61,6 +61,10 @@ class Gpt4AllWebUI:
|
|||||||
"/list_personalities", "list_personalities", self.list_personalities, methods=["GET"]
|
"/list_personalities", "list_personalities", self.list_personalities, methods=["GET"]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
self.add_endpoint(
|
||||||
|
"/list_languages", "list_languages", self.list_languages, methods=["GET"]
|
||||||
|
)
|
||||||
|
|
||||||
self.add_endpoint(
|
self.add_endpoint(
|
||||||
"/list_discussions", "list_discussions", self.list_discussions, methods=["GET"]
|
"/list_discussions", "list_discussions", self.list_discussions, methods=["GET"]
|
||||||
)
|
)
|
||||||
@ -138,6 +142,19 @@ class Gpt4AllWebUI:
|
|||||||
personalities = [f.name for f in personalities_dir.glob('*.yaml')]
|
personalities = [f.name for f in personalities_dir.glob('*.yaml')]
|
||||||
return jsonify(personalities)
|
return jsonify(personalities)
|
||||||
|
|
||||||
|
def list_languages(self):
|
||||||
|
lanuguages= [
|
||||||
|
{ "value": "en-US", "label": "English" },
|
||||||
|
{ "value": "fr-FR", "label": "Français" },
|
||||||
|
{ "value": "ar-AR", "label": "العربية" },
|
||||||
|
{ "value": "it-IT", "label": "Italiano" },
|
||||||
|
{ "value": "de-DE", "label": "Deutsch" },
|
||||||
|
{ "value": "nl-XX", "label": "Dutch" },
|
||||||
|
{ "value": "zh-CN", "label": "中國人" }
|
||||||
|
]
|
||||||
|
return jsonify(lanuguages)
|
||||||
|
|
||||||
|
|
||||||
def list_discussions(self):
|
def list_discussions(self):
|
||||||
discussions = self.db.get_discussions()
|
discussions = self.db.get_discussions()
|
||||||
return jsonify(discussions)
|
return jsonify(discussions)
|
||||||
|
@ -12,4 +12,5 @@ host: "localhost"
|
|||||||
port: 9600
|
port: 9600
|
||||||
db_path: "database.db"
|
db_path: "database.db"
|
||||||
nb_messages_to_remember: 5
|
nb_messages_to_remember: 5
|
||||||
personality: "gpt4all_chatbot"
|
personality: "gpt4all_chatbot"
|
||||||
|
language: "en_XX"
|
202
static/js/audio.js
Normal file
202
static/js/audio.js
Normal file
@ -0,0 +1,202 @@
|
|||||||
|
isStarted = false;
|
||||||
|
isSpeaking = false;
|
||||||
|
const SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
|
||||||
|
const recognition = new SpeechRecognition();
|
||||||
|
const synth = window.speechSynthesis || webkitspeechSynthesis;
|
||||||
|
var voices = synth.getVoices();
|
||||||
|
function prepre_audio(){
|
||||||
|
recognition.continuous = true;
|
||||||
|
recognition.interimResults = true;
|
||||||
|
recognition.maxAlternatives = 10;
|
||||||
|
language_select = document.getElementById("language")
|
||||||
|
}
|
||||||
|
voices = [];
|
||||||
|
function populateVoicesList() {
|
||||||
|
voices = synth.getVoices();
|
||||||
|
voice_select = document.getElementById("voice")
|
||||||
|
voice_select.innerHTML="";
|
||||||
|
for (let i = 0; i < voices.length; i++) {
|
||||||
|
if (
|
||||||
|
voices[i].lang.startsWith(
|
||||||
|
language_select.value.substring(0, 2)
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.textContent = `${voices[i].name} (${voices[i].lang})`;
|
||||||
|
|
||||||
|
if (voices[i].default) {
|
||||||
|
option.textContent += " — DEFAULT";
|
||||||
|
}
|
||||||
|
|
||||||
|
option.setAttribute("data-lang", voices[i].lang);
|
||||||
|
option.setAttribute("data-name", voices[i].name);
|
||||||
|
voice_select.appendChild(option);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
voice_select.addEventListener("change", function () {
|
||||||
|
});
|
||||||
|
}
|
||||||
|
// Audio code
|
||||||
|
function splitString(string, maxLength) {
|
||||||
|
const sentences = string.match(/[^.!?]+[.!?]/g);
|
||||||
|
const strings = [];
|
||||||
|
let currentString = "";
|
||||||
|
|
||||||
|
if (sentences) {
|
||||||
|
for (const sentence of sentences) {
|
||||||
|
if (currentString.length + sentence.length > maxLength) {
|
||||||
|
strings.push(currentString);
|
||||||
|
currentString = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
currentString += `${sentence} `;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
strings.push(string);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentString) {
|
||||||
|
strings.push(currentString);
|
||||||
|
}
|
||||||
|
|
||||||
|
return strings;
|
||||||
|
}
|
||||||
|
function addListeners(button, utterThis) {
|
||||||
|
utterThis.onstart = (event) => {
|
||||||
|
isSpeaking = true;
|
||||||
|
button.style.backgroundColor = "red";
|
||||||
|
button.style.boxShadow = "2px 2px 0.5px #808080";
|
||||||
|
};
|
||||||
|
|
||||||
|
utterThis.onend = (event) => {
|
||||||
|
isSpeaking = false;
|
||||||
|
button.style.backgroundColor = "";
|
||||||
|
button.style.boxShadow = "";
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
function attachAudio_modules(div) {
|
||||||
|
if (div.parentNode.getElementsByClassName("audio-out-button").length > 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const audio_out_button = document.createElement("button");
|
||||||
|
audio_out_button.id = "audio-out-button";
|
||||||
|
audio_out_button.classList.add("audio_btn");
|
||||||
|
audio_out_button.innerHTML = "🕪";
|
||||||
|
div.classList.add("flex-1");
|
||||||
|
audio_out_button.classList.add("audio-out-button");
|
||||||
|
div.appendChild(audio_out_button);
|
||||||
|
|
||||||
|
function play_audio() {
|
||||||
|
if (isSpeaking) {
|
||||||
|
|
||||||
|
audio_out_button.style.backgroundColor = "";
|
||||||
|
audio_out_button.style.boxShadow = "";
|
||||||
|
synth.cancel();
|
||||||
|
isSpeaking = false;
|
||||||
|
} else {
|
||||||
|
isSpeaking = true;
|
||||||
|
text = audio_out_button.previousSibling.textContent;
|
||||||
|
|
||||||
|
const selectedOption =
|
||||||
|
voice_select.selectedOptions[0].getAttribute("data-name");
|
||||||
|
var selectedVoice = null;
|
||||||
|
for (let i = 0; i < voices.length; i++) {
|
||||||
|
if (voices[i].name === selectedOption) {
|
||||||
|
selectedVoice = voices[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (selectedVoice && selectedVoice.voiceURI === "native") {
|
||||||
|
const utterThis = new SpeechSynthesisUtterance(text);
|
||||||
|
utterThis.voice = selectedVoice;
|
||||||
|
addListeners(audio_out_button, utterThis);
|
||||||
|
synth.speak(utterThis);
|
||||||
|
} else {
|
||||||
|
texts = splitString(text, 200);
|
||||||
|
texts.forEach((text) => {
|
||||||
|
const utterThis = new SpeechSynthesisUtterance(text);
|
||||||
|
utterThis.voice = selectedVoice;
|
||||||
|
addListeners(audio_out_button, utterThis);
|
||||||
|
synth.speak(utterThis);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
audio_out_button.addEventListener("click", () => {
|
||||||
|
play_audio();
|
||||||
|
});
|
||||||
|
// TODO : activate using configuration file
|
||||||
|
//if (global["auto_audio"]) {
|
||||||
|
// play_audio();
|
||||||
|
//}
|
||||||
|
}
|
||||||
|
|
||||||
|
function add_audio_in_ui() {
|
||||||
|
const inputs = document.querySelectorAll("#user-input");
|
||||||
|
inputs.forEach((input) => {
|
||||||
|
// const wrapper = document.createElement("div");
|
||||||
|
// wrapper.classList.add("flex", "items-center");
|
||||||
|
var btn = document.querySelectorAll("#audio_in_tool");
|
||||||
|
|
||||||
|
var found = false;
|
||||||
|
// Iterate through the children
|
||||||
|
for (var i = 0; i < btn.length; i++) {
|
||||||
|
var child = btn[i];
|
||||||
|
// Check if the wrapper element contains the current child element
|
||||||
|
if (input.parentNode.parentNode.contains(child)) {
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
const audio_in_button = document.createElement("button");
|
||||||
|
audio_in_button.id = "audio_in_tool";
|
||||||
|
audio_in_button.classList.add("audio_btn");
|
||||||
|
audio_in_button.innerHTML = "🎤";
|
||||||
|
|
||||||
|
input.parentNode.insertBefore(
|
||||||
|
audio_in_button,
|
||||||
|
input
|
||||||
|
);
|
||||||
|
|
||||||
|
input.classList.add("flex-1");
|
||||||
|
audio_in_button.classList.add("ml-2");
|
||||||
|
//wrapper.appendChild(audio_in_button);
|
||||||
|
//input.parentNode.parentNode.insertBefore(wrapper, input);
|
||||||
|
//input.parentNode.removeChild(input);
|
||||||
|
//wrapper.appendChild(input);
|
||||||
|
|
||||||
|
audio_in_button.addEventListener("click", () => {
|
||||||
|
if (isStarted) {
|
||||||
|
recognition.stop();
|
||||||
|
isStarted = false;
|
||||||
|
} else {
|
||||||
|
recognition.lang = language_select.value;
|
||||||
|
recognition.start();
|
||||||
|
isStarted = true;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recognition.addEventListener("result", (event) => {
|
||||||
|
let transcript = "";
|
||||||
|
for (const result of event.results) {
|
||||||
|
transcript += result[0].transcript;
|
||||||
|
}
|
||||||
|
if (transcript != "") {
|
||||||
|
input.value = transcript;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
recognition.addEventListener("start", () => {
|
||||||
|
audio_in_button.style.backgroundColor = "red";
|
||||||
|
audio_in_button.style.boxShadow = "2px 2px 0.5px #808080";
|
||||||
|
});
|
||||||
|
|
||||||
|
recognition.addEventListener("end", () => {
|
||||||
|
audio_in_button.style.backgroundColor = "";
|
||||||
|
audio_in_button.style.boxShadow = "";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
@ -319,6 +319,8 @@ function addMessage(sender, message, id, rank=0, can_edit=false) {
|
|||||||
}
|
}
|
||||||
chatWindow.appendChild(messageElement);
|
chatWindow.appendChild(messageElement);
|
||||||
chatWindow.appendChild(hiddenElement);
|
chatWindow.appendChild(hiddenElement);
|
||||||
|
|
||||||
|
attachAudio_modules(messageTextElement);
|
||||||
|
|
||||||
// scroll to bottom of chat window
|
// scroll to bottom of chat window
|
||||||
chatWindow.scrollTop = chatWindow.scrollHeight;
|
chatWindow.scrollTop = chatWindow.scrollHeight;
|
||||||
|
@ -5,6 +5,8 @@ fetch('/settings')
|
|||||||
document.getElementById('settings').innerHTML = html;
|
document.getElementById('settings').innerHTML = html;
|
||||||
|
|
||||||
modelInput = document.getElementById('model');
|
modelInput = document.getElementById('model');
|
||||||
|
personalityInput = document.getElementById('personalities');
|
||||||
|
languageInput = document.getElementById('language');
|
||||||
seedInput = document.getElementById('seed');
|
seedInput = document.getElementById('seed');
|
||||||
tempInput = document.getElementById('temp');
|
tempInput = document.getElementById('temp');
|
||||||
nPredictInput = document.getElementById('n-predict');
|
nPredictInput = document.getElementById('n-predict');
|
||||||
@ -52,6 +54,8 @@ fetch('/settings')
|
|||||||
.then((data) => {
|
.then((data) => {
|
||||||
console.log(data);
|
console.log(data);
|
||||||
modelInput.value = data["model"]
|
modelInput.value = data["model"]
|
||||||
|
personalityInput.value = data["personality"]
|
||||||
|
languageInput.value = data["language"]
|
||||||
seedInput.value = data["seed"]
|
seedInput.value = data["seed"]
|
||||||
tempInput.value = data["temp"]
|
tempInput.value = data["temp"]
|
||||||
nPredictInput.value = data["n_predict"]
|
nPredictInput.value = data["n_predict"]
|
||||||
@ -168,6 +172,30 @@ function populate_models(){
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// Fetch the list of .yaml files from the models subfolder
|
||||||
|
fetch('/list_languages')
|
||||||
|
.then(response => response.json())
|
||||||
|
.then(data => {
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
// data is an array
|
||||||
|
const selectElement = document.getElementById('language');
|
||||||
|
data.forEach(row => {
|
||||||
|
const optionElement = document.createElement('option');
|
||||||
|
optionElement.value = row.value;
|
||||||
|
optionElement.innerHTML = row.label;
|
||||||
|
selectElement.appendChild(optionElement);
|
||||||
|
});
|
||||||
|
|
||||||
|
// fetch('/get_args')
|
||||||
|
// .then(response=> response.json())
|
||||||
|
// .then(data=>{
|
||||||
|
|
||||||
|
// })
|
||||||
|
} else {
|
||||||
|
console.error('Expected an array, but received:', data);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
populate_models()
|
populate_models()
|
||||||
|
@ -32,6 +32,9 @@ fetch('/main')
|
|||||||
load_discussion();
|
load_discussion();
|
||||||
update_main();
|
update_main();
|
||||||
db_export();
|
db_export();
|
||||||
|
prepre_audio();
|
||||||
|
add_audio_in_ui();
|
||||||
|
populateVoicesList();
|
||||||
|
|
||||||
})
|
})
|
||||||
.catch(error => {
|
.catch(error => {
|
||||||
|
@ -55,6 +55,7 @@
|
|||||||
|
|
||||||
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/settings.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/db_export.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/db_export.js') }}"></script>
|
||||||
|
<script src="{{ url_for('static', filename='js/audio.js') }}"></script>
|
||||||
<script src="{{ url_for('static', filename='js/tabs.js') }}"></script>
|
<script src="{{ url_for('static', filename='js/tabs.js') }}"></script>
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
|
@ -10,6 +10,16 @@
|
|||||||
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="personalities" name="personalities" value="gpt4all_chatbot.yaml">
|
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="personalities" name="personalities" value="gpt4all_chatbot.yaml">
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="block font-bold mb-2" for="model">Language</label>
|
||||||
|
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="language" name="language" value="english">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="mb-4">
|
||||||
|
<label class="block font-bold mb-2" for="model">Voice</label>
|
||||||
|
<select class="bg-gray-700 shadow appearance-none border rounded w-full py-2 px-3 leading-tight focus:outline-none focus:shadow-outline" id="voice" name="voice" value="english">
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="mb-4">
|
<div class="mb-4">
|
||||||
<label class="block font-bold mb-2" for="seed">Seed</label>
|
<label class="block font-bold mb-2" for="seed">Seed</label>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user