ascenseur
This commit is contained in:
331
index.html
331
index.html
@@ -63,7 +63,14 @@ body > main {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#bouton_reconnaissance_vocale {
|
#bouton_reconnaissance_vocale {
|
||||||
padding: 0.7rem;
|
padding: 0;
|
||||||
|
width: 3rem;
|
||||||
|
margin-left: -3rem;
|
||||||
|
border: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#bouton_envoyer {
|
||||||
|
padding: 1.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media print {
|
@media print {
|
||||||
@@ -82,7 +89,7 @@ body > main {
|
|||||||
<button id="bouton_synthese_vocale" type="button" class="secondary" style="display: none;" disabled>🔈</button>
|
<button id="bouton_synthese_vocale" type="button" class="secondary" style="display: none;" disabled>🔈</button>
|
||||||
</nav>
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
<main class="container overflow-auto" id="conversation">
|
<main class="container" id="conversation">
|
||||||
<p class="reponse">Posez-moi toutes vos questions !</p>
|
<p class="reponse">Posez-moi toutes vos questions !</p>
|
||||||
</main>
|
</main>
|
||||||
<footer class="container">
|
<footer class="container">
|
||||||
@@ -102,7 +109,7 @@ body > main {
|
|||||||
</header>
|
</header>
|
||||||
<form>
|
<form>
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<label>Voix disponibles :</label>
|
<label for="select_voix">Voix disponibles :</label>
|
||||||
<select id="select_voix">
|
<select id="select_voix">
|
||||||
<option value="">Pas de synthèse vocale</option>
|
<option value="">Pas de synthèse vocale</option>
|
||||||
</select>
|
</select>
|
||||||
@@ -115,174 +122,182 @@ body > main {
|
|||||||
</article>
|
</article>
|
||||||
</dialog>
|
</dialog>
|
||||||
<script>
|
<script>
|
||||||
const formulaire = document.getElementById('formulaire');
|
const formulaire = document.getElementById('formulaire');
|
||||||
const bouton_envoyer = document.getElementById('bouton_envoyer');
|
const bouton_envoyer = document.getElementById('bouton_envoyer');
|
||||||
const conversation = document.getElementById('conversation');
|
const conversation = document.getElementById('conversation');
|
||||||
const question = document.getElementById('question');
|
const question = document.getElementById('question');
|
||||||
const bouton_synthese_vocale = document.getElementById('bouton_synthese_vocale');
|
const bouton_synthese_vocale = document.getElementById('bouton_synthese_vocale');
|
||||||
const boite_synthese_vocale = document.getElementById('boite_synthese_vocale');
|
const boite_synthese_vocale = document.getElementById('boite_synthese_vocale');
|
||||||
const select_voix = document.getElementById('select_voix');
|
const select_voix = document.getElementById('select_voix');
|
||||||
const aphone = select_voix.innerHTML;
|
const aphone = select_voix.innerHTML;
|
||||||
const bouton_fermer = document.getElementById('bouton_fermer');
|
const bouton_fermer = document.getElementById('bouton_fermer');
|
||||||
const bouton_annuler = document.getElementById('bouton_annuler');
|
const bouton_annuler = document.getElementById('bouton_annuler');
|
||||||
const bouton_ok = document.getElementById('bouton_ok');
|
const bouton_ok = document.getElementById('bouton_ok');
|
||||||
const footer = document.querySelector('footer');
|
const footer = document.querySelector('footer');
|
||||||
const langue = document.documentElement.lang;
|
const langue = document.documentElement.lang;
|
||||||
|
|
||||||
let voix = null;
|
question.addEventListener('keydown', e => {
|
||||||
function charger_voix() {
|
if (e.key === 'Enter' && !e.ctrlKey && !e.shiftKey) {
|
||||||
let liste_voix = speechSynthesis.getVoices().filter(voice => voice.lang.startsWith(langue));
|
e.preventDefault();
|
||||||
select_voix.innerHTML = aphone;
|
e.target.form.requestSubmit();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
if (!liste_voix.length) {
|
question.addEventListener('focus', () => {
|
||||||
bouton_synthese_vocale.disabled = true;
|
question.scrollIntoView({ block: 'nearest' });
|
||||||
speechSynthesis.addEventListener('voiceschanged', charger_voix);
|
});
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
speechSynthesis.removeEventListener('voiceschanged', charger_voix);
|
formulaire.addEventListener('submit', async (e) => {
|
||||||
liste_voix.forEach((v, i) => {
|
e.preventDefault();
|
||||||
const option = document.createElement('option');
|
if (bouton_envoyer.disabled == true) return;
|
||||||
option.value = i;
|
|
||||||
option.innerText = v.name;
|
|
||||||
select_voix.appendChild(option);
|
|
||||||
if (v.voiceURI === window.localStorage.getItem('voix')) {
|
|
||||||
select_voix.value = i;
|
|
||||||
voix = v;
|
|
||||||
option.selected = true;
|
|
||||||
bouton_synthese_vocale.innerHTML = "🔊";
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
bouton_synthese_vocale.disabled = false;
|
bouton_envoyer.disabled = true;
|
||||||
bouton_synthese_vocale.addEventListener('click', () => {
|
let bouton_envoyer_innerHTML = bouton_envoyer.innerHTML;
|
||||||
boite_synthese_vocale.showModal();
|
bouton_envoyer.innerHTML = "";
|
||||||
});
|
bouton_envoyer.setAttribute("aria-busy", true)
|
||||||
bouton_fermer.addEventListener('click', () => {
|
const formulaireData = new FormData(formulaire);
|
||||||
boite_synthese_vocale.close();
|
const citation = document.createElement('article');
|
||||||
});
|
citation.innerText = formulaireData.get('question');
|
||||||
bouton_annuler.addEventListener('click', () => {
|
conversation.appendChild(citation);
|
||||||
boite_synthese_vocale.close();
|
formulaire.reset();
|
||||||
});
|
|
||||||
bouton_ok.addEventListener('click', () => {
|
const paragraphe = document.createElement('p');
|
||||||
boite_synthese_vocale.close();
|
paragraphe.setAttribute("aria-busy", "true");
|
||||||
if (select_voix.value) {
|
conversation.appendChild(paragraphe);
|
||||||
voix = liste_voix[select_voix.value];
|
conversation.scrollTop = conversation.scrollHeight;
|
||||||
window.localStorage.setItem('voix', voix.voiceURI);
|
|
||||||
bouton_synthese_vocale.innerHTML = "🔊";
|
const requete = await fetch(formulaire.action, {
|
||||||
} else {
|
method: formulaire.method,
|
||||||
voix = null;
|
body: formulaireData
|
||||||
window.localStorage.removeItem('voix');
|
});
|
||||||
bouton_synthese_vocale.innerHTML = "🔈";
|
paragraphe.setAttribute('aria-busy', 'true');
|
||||||
}
|
const reponse = await requete.text();
|
||||||
});
|
paragraphe.setAttribute('aria-busy', 'false');
|
||||||
}
|
|
||||||
if ('speechSynthesis' in window) {
|
if (voix) {
|
||||||
bouton_synthese_vocale.style.display = 'block';
|
const utterance = new SpeechSynthesisUtterance(reponse);
|
||||||
charger_voix();
|
utterance.lang = langue;
|
||||||
|
utterance.voice = voix;
|
||||||
|
utterance.rate = 1;
|
||||||
|
speechSynthesis.speak(utterance);
|
||||||
|
}
|
||||||
|
let t = 0;
|
||||||
|
Array.from(reponse).forEach((lettre, i) => {
|
||||||
|
setTimeout(() => {
|
||||||
|
if (lettre == "\n") {
|
||||||
|
paragraphe.innerHTML += "<br>";
|
||||||
|
} else {
|
||||||
|
paragraphe.innerHTML += lettre;
|
||||||
}
|
}
|
||||||
|
paragraphe.scrollIntoView({ block: 'start', behavior: 'auto' });
|
||||||
|
}, t += 100 * Math.random());
|
||||||
|
});
|
||||||
|
setTimeout(() => {
|
||||||
|
const paragraphe = document.createElement('p');
|
||||||
|
paragraphe.classList.add('reponse');
|
||||||
|
paragraphe.innerHTML = 'Voulez-vous que je réponde à une autre question ?';
|
||||||
|
conversation.appendChild(paragraphe);
|
||||||
|
paragraphe.scrollIntoView({ block: 'start', behavior: 'auto' });
|
||||||
|
bouton_envoyer.disabled = false;
|
||||||
|
bouton_envoyer.setAttribute("aria-busy", false);
|
||||||
|
bouton_envoyer.innerHTML = bouton_envoyer_innerHTML;
|
||||||
|
question.focus()
|
||||||
|
}, t);
|
||||||
|
})
|
||||||
|
|
||||||
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
// Synthèse vocale
|
||||||
if (SpeechRecognition) {
|
let voix = null;
|
||||||
bouton_reconnaissance_vocale.addEventListener('click', () => {
|
function charger_voix() {
|
||||||
const reconnaissance= new SpeechRecognition();
|
let liste_voix = speechSynthesis.getVoices(); // .filter(voice => voice.lang.startsWith(langue));
|
||||||
reconnaissance.lang = langue;
|
select_voix.innerHTML = aphone;
|
||||||
bouton_reconnaissance_vocale_inner_HTML = bouton_reconnaissance_vocale.innerHTML
|
|
||||||
bouton_reconnaissance_vocale.innerHTML = ""
|
|
||||||
bouton_reconnaissance_vocale.setAttribute("aria-busy", true)
|
|
||||||
reconnaissance.addEventListener('result', (event) => {
|
|
||||||
const transcript = event.results[0][0].transcript;
|
|
||||||
question.value = transcript;
|
|
||||||
formulaire.requestSubmit()
|
|
||||||
});
|
|
||||||
reconnaissance.addEventListener('speechend', () => {
|
|
||||||
reconnaissance.stop();
|
|
||||||
bouton_reconnaissance_vocale.setAttribute("aria-busy", false)
|
|
||||||
bouton_reconnaissance_vocale.innerHTML = bouton_reconnaissance_vocale_inner_HTML
|
|
||||||
});
|
|
||||||
reconnaissance.addEventListener('error', (event) => {
|
|
||||||
bouton_reconnaissance_vocale.setAttribute("aria-busy", false)
|
|
||||||
bouton_reconnaissance_vocale.innerHTML = bouton_reconnaissance_vocale_inner_HTML
|
|
||||||
});
|
|
||||||
reconnaissance.start();
|
|
||||||
});
|
|
||||||
bouton_reconnaissance_vocale.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
question.addEventListener('keydown', e => {
|
if (!liste_voix.length) {
|
||||||
if (e.key === 'Enter' && !e.ctrlKey && !e.shiftKey) {
|
bouton_synthese_vocale.disabled = true;
|
||||||
e.preventDefault();
|
speechSynthesis.addEventListener('voiceschanged', charger_voix);
|
||||||
e.target.form.requestSubmit();
|
return;
|
||||||
}
|
}
|
||||||
});
|
|
||||||
|
|
||||||
question.addEventListener('focus', () => {
|
speechSynthesis.removeEventListener('voiceschanged', charger_voix);
|
||||||
question.scrollIntoView({ block: 'nearest' });
|
liste_voix.forEach((v, i) => {
|
||||||
});
|
const option = document.createElement('option');
|
||||||
|
option.value = i;
|
||||||
|
option.innerText = v.name;
|
||||||
|
select_voix.appendChild(option);
|
||||||
|
if (v.voiceURI === window.localStorage.getItem('voix')) {
|
||||||
|
select_voix.value = i;
|
||||||
|
voix = v;
|
||||||
|
option.selected = true;
|
||||||
|
bouton_synthese_vocale.innerHTML = "🔊";
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
formulaire.addEventListener('submit', async (e) => {
|
bouton_synthese_vocale.disabled = false;
|
||||||
e.preventDefault();
|
bouton_synthese_vocale.addEventListener('click', () => {
|
||||||
if (bouton_envoyer.disabled == true) return;
|
boite_synthese_vocale.showModal();
|
||||||
|
});
|
||||||
|
bouton_fermer.addEventListener('click', () => {
|
||||||
|
boite_synthese_vocale.close();
|
||||||
|
});
|
||||||
|
bouton_annuler.addEventListener('click', () => {
|
||||||
|
boite_synthese_vocale.close();
|
||||||
|
});
|
||||||
|
bouton_ok.addEventListener('click', () => {
|
||||||
|
boite_synthese_vocale.close();
|
||||||
|
if (select_voix.value) {
|
||||||
|
voix = liste_voix[select_voix.value];
|
||||||
|
window.localStorage.setItem('voix', voix.voiceURI);
|
||||||
|
bouton_synthese_vocale.innerHTML = "🔊";
|
||||||
|
} else {
|
||||||
|
voix = null;
|
||||||
|
window.localStorage.removeItem('voix');
|
||||||
|
bouton_synthese_vocale.innerHTML = "🔈";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
if ('speechSynthesis' in window) {
|
||||||
|
bouton_synthese_vocale.style.display = 'block';
|
||||||
|
charger_voix();
|
||||||
|
}
|
||||||
|
|
||||||
bouton_envoyer.disabled = true;
|
// Reconnaissance vocale
|
||||||
let bouton_envoyer_innerHTML = bouton_envoyer.innerHTML;
|
var SpeechRecognition = window.SpeechRecognition || window.webkitSpeechRecognition;
|
||||||
bouton_envoyer.innerHTML = "";
|
if (SpeechRecognition) {
|
||||||
bouton_envoyer.setAttribute("aria-busy", true)
|
bouton_reconnaissance_vocale.addEventListener('click', () => {
|
||||||
const formulaireData = new FormData(formulaire);
|
const reconnaissance= new SpeechRecognition();
|
||||||
const citation = document.createElement('article');
|
reconnaissance.lang = langue;
|
||||||
citation.innerText = formulaireData.get('question');
|
reconnaissance.continuous = false;
|
||||||
conversation.appendChild(citation);
|
reconnaissance.interimResults = false;
|
||||||
formulaire.reset();
|
reconnaissance.maxAlternatives = 1;
|
||||||
|
bouton_reconnaissance_vocale_inner_HTML = bouton_reconnaissance_vocale.innerHTML
|
||||||
|
bouton_reconnaissance_vocale.innerHTML = ""
|
||||||
|
bouton_reconnaissance_vocale.setAttribute("aria-busy", true)
|
||||||
|
|
||||||
const paragraphe = document.createElement('p');
|
reconnaissance.addEventListener('result', (event) => {
|
||||||
paragraphe.setAttribute("aria-busy", "true");
|
const transcript = event.results[0][0].transcript;
|
||||||
conversation.appendChild(paragraphe);
|
question.value = transcript;
|
||||||
conversation.scrollTop = conversation.scrollHeight;
|
if (!bouton_envoyer.disabled) formulaire.requestSubmit()
|
||||||
|
});
|
||||||
|
reconnaissance.onspeechend =
|
||||||
|
reconnaissance.onerror =
|
||||||
|
reconnaissance.onnomatch = function () {
|
||||||
|
reconnaissance.stop();
|
||||||
|
bouton_reconnaissance_vocale.setAttribute("aria-busy", false)
|
||||||
|
bouton_reconnaissance_vocale.innerHTML = bouton_reconnaissance_vocale_inner_HTML
|
||||||
|
};
|
||||||
|
|
||||||
const requete = await fetch(formulaire.action, {
|
reconnaissance.start();
|
||||||
method: formulaire.method,
|
});
|
||||||
body: formulaireData
|
bouton_reconnaissance_vocale.style.display = 'block';
|
||||||
});
|
}
|
||||||
paragraphe.setAttribute('aria-busy', 'true');
|
|
||||||
const reponse = await requete.text();
|
|
||||||
paragraphe.setAttribute('aria-busy', 'false');
|
|
||||||
|
|
||||||
if (voix) {
|
|
||||||
const utterance = new SpeechSynthesisUtterance(reponse);
|
|
||||||
utterance.lang = langue;
|
|
||||||
utterance.voice = voix;
|
|
||||||
utterance.rate = 1;
|
|
||||||
speechSynthesis.speak(utterance);
|
|
||||||
}
|
|
||||||
let t = 0;
|
|
||||||
Array.from(reponse).forEach((lettre, i) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
if (lettre == "\n") {
|
|
||||||
paragraphe.innerHTML += "<br>";
|
|
||||||
} else {
|
|
||||||
paragraphe.innerHTML += lettre;
|
|
||||||
}
|
|
||||||
conversation.scrollTop = conversation.scrollHeight;
|
|
||||||
}, t += 100 * Math.random());
|
|
||||||
});
|
|
||||||
setTimeout(() => {
|
|
||||||
conversation.innerHTML += '<p class="reponse">Voulez-vous que je réponde à une autre question ?</p>';
|
|
||||||
conversation.scrollTop = conversation.scrollHeight;
|
|
||||||
bouton_envoyer.disabled = false;
|
|
||||||
bouton_envoyer.setAttribute("aria-busy", false);
|
|
||||||
bouton_envoyer.innerHTML = bouton_envoyer_innerHTML;
|
|
||||||
question.focus()
|
|
||||||
}, t);
|
|
||||||
})
|
|
||||||
|
|
||||||
function onResize() {
|
|
||||||
document.body.style.setProperty("--vph", `${window.visualViewport.height}px`);
|
|
||||||
conversation.scrollTop = conversation.scrollHeight;
|
|
||||||
}
|
|
||||||
window.visualViewport?.addEventListener('resize', onResize);
|
|
||||||
window.addEventListener('resize', onResize);
|
|
||||||
onResize();
|
|
||||||
|
|
||||||
|
// Adaptation au clavier virtuel du téléphone
|
||||||
|
function onResize() {
|
||||||
|
document.body.style.setProperty("--vph", `${window.visualViewport.height}px`);
|
||||||
|
conversation.scrollTop = conversation.scrollHeight;
|
||||||
|
}
|
||||||
|
window.visualViewport?.addEventListener('resize', onResize);
|
||||||
|
window.addEventListener('resize', onResize);
|
||||||
|
onResize();
|
||||||
</script>
|
</script>
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user