I’m new on IOS Methods and likewise new to Apple units an bumped into an enormous Downside. I created a script that may be carried out in Person Web sites which is kindo of a voice agent. On non IOS Methods equivalent to Android or a easy Laptop computer beneath Home windows it runs as anticipated. The consumer aks one thing and will get a solution voice pushed. Below IOS it wants some type of interplay which is completed by an modal which opens however after the primary message is given out to the consumer the script stops working. So no second interplay could be completed what do i miss or what do i fallacious that is the JS script half.
(operate() {
doc.addEventListener('DOMContentLoaded', operate() {
// Funktion zum Setzen eines Cookies
operate setCookie(identify, worth, days) {
const date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
const expires = "expires=" + date.toUTCString();
doc.cookie = identify + "=" + worth + ";" + expires + ";path=/";
}
// Funktion zum Abrufen eines Cookies
operate getCookie(identify) {
const nameEQ = identify + "=";
const ca = doc.cookie.break up(';');
for(let i = 0; i < ca.size; i++) {
let c = ca[i];
whereas (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(nameEQ) == 0) {
return c.substring(nameEQ.size, c.size);
}
}
return null;
}
// Überprüfen, ob der Tooltip bereits geschlossen wurde
const tooltipClosed = getCookie('tooltipClosed');
// Parameter aus der URL der eingebetteten JavaScript-Datei auslesen
const scriptTag = doc.currentScript || doc.querySelector('script[src*="micButton.js"]');
if (!scriptTag) {
console.error('Das aktuelle Skript konnte nicht gefunden werden.');
return;
}
const scriptUrl = new URL(scriptTag.src);
const userId = scriptUrl.searchParams.get('user_id');
// Überprüfen, ob die erforderlichen Parameter vorhanden sind
if (!userId) {
console.error('Fehlende Parameter: user_id');
return;
}
// CSS hinzufügen
const fashion = doc.createElement('fashion');
fashion.textContent = `
.mic-checkbox {
show: none;
}
.mic-checkbox:checked + .mic-button {
remodel: rotateY(180deg);
}
.mic-checkbox:checked + .mic-button span {
}
.button-container {
perspective: 500px;
place: fastened;
backside: 10px;
proper: 10px;
opacity: 0;
remodel: translateY(10px);
animation: fadeInButton 0.5s forwards;
}
.mic-button {
show: flex;
align-items: middle;
justify-content: middle;
peak: 100px;
width: 100px;
border-radius: 100%;
transition: remodel 0.4s;
border: 2px strong #333;
transform-style: preserve-3d;
place: relative;
font-size: 58px;
}
.button-message, .mic, .mic-back {
backface-visibility: hidden;
}
.button-message {
place: absolute;
width: 100px;
peak: 100px;
z-index: 2;
remodel: rotateY(0deg);
pointer-events: none;
left: 0;
prime: 0;
show: flex;
align-items: middle;
justify-content: middle;
}
.button-message img {
width: 100%;
peak: 100%;
object-fit: cowl;
border-radius: 50%;
}
.mic-back {
place: absolute;
width: 100%;
peak: 100%;
z-index: 2;
remodel: rotateY(180deg);
pointer-events: none;
prime: 0;
left: 0;
background-image: url('information:picture/png;base64,'); /* Hier dein Base64-Bild */
background-size: cowl;
background-position: middle;
background-repeat: no-repeat;
border-radius: 50%;
}
.mic-button-loader {
place: absolute;
peak: 102px;
width: 100px;
background-color: clear;
remodel: rotateY(180deg);
prime: -31px;
left: -50px;
}
.mic-checkbox:checked + .mic-button > .mic > .mic-button-loader {
border-top: 3px strong #AA1111;
border-radius: 100%;
animation: borderLoader 1.3s 0.2s ease-in-out infinite;
}
.mic {
place: relative;
prime: -11px;
peak: 20px;
width: 0;
border-radius: 10px;
remodel: rotateY(180deg);
}
.mic:after, .mic:earlier than, .mic-base {
place: absolute;
}
@keyframes borderLoader {
from {
remodel: rotate(0deg);
}
to {
remodel: rotate(359deg);
}
}
.tooltip-speaksdata {
place: fastened;
backside: 25px;
proper: 110px;
background-color: #333;
colour: #fff;
padding: 10px;
border-radius: 5px;
font-family: 'Montserrat', sans-serif;
font-size: 14px;
show: flex;
align-items: middle;
z-index: 1000;
width: 170px;
opacity: 0;
animation: fadeIn 0.5s forwards;
transition: opacity 0.5s, remodel 0.5s;
}
.tooltip-speaksdata span {
margin-right: 10px;
}
.tooltip-speaksdata .close-tooltip {
cursor: pointer;
background-color: #555;
border: none;
colour: #fff;
border-radius: 50%;
width: 20px;
peak: 20px;
show: flex;
align-items: middle;
justify-content: middle;
font-size: 14px;
place:absolute;
proper:-10px;
prime:-10px;
}
@keyframes fadeIn {
from {
opacity: 0;
remodel: translateY(-10px);
}
to {
opacity: 1;
remodel: translateY(0);
}
}
@keyframes fadeOut {
from {
opacity: 1;
remodel: translateY(0);
}
to {
opacity: 0;
remodel: translateY(-10px);
}
}
@keyframes fadeInButton {
from {
opacity: 0;
remodel: translateY(10px);
}
to {
opacity: 1;
remodel: translateY(0);
}
}
`;
doc.head.appendChild(fashion);
// Base64-Icons für verschiedene Zustände
const loadingIconBase64 = 'information:picture/png;base64,'; // Lade-Icon
const successIconBase64 = 'information:picture/png;base64,'; // Erfolgs-Icon
const errorIconBase64 = 'information:picture/png;base64,'; // Fehler-Icon
const defaultIconBase64 = 'information:picture/png;base64,'; // Customary-Icon
const buttonContainer = doc.createElement('div');
buttonContainer.classList.add('button-container');
buttonContainer.innerHTML = `
`;
doc.physique.appendChild(buttonContainer);
const micButtonCheckbox = doc.getElementById('micButton');
const buttonIcon = doc.getElementById('buttonIcon');
// Tooltip-Ingredient erstellen
if (!tooltipClosed) {
setTimeout(() => {
const tooltip = doc.createElement('div');
tooltip.classList.add('tooltip-speaksdata');
tooltip.innerHTML = `
Ich bin der Speaksdata Assistent!
Ich helfe Ihnen bei Fragen!
`;
doc.physique.appendChild(tooltip);
// Tooltip schließen
doc.querySelector('.close-tooltip').addEventListener('click on', operate() {
tooltip.fashion.animation = 'fadeOut 0.5s forwards';
setCookie('tooltipClosed', 'true', 365);
});
}, 5000); // Tooltip erscheint nach 5 Sekunden
}
// Hilfsfunktionen zum Verwalten von Elementen
operate updateOrCreateElement(id, tag, mother or father, content material="") {
let aspect = doc.getElementById(id);
if (!aspect) {
aspect = doc.createElement(tag);
aspect.id = id;
aspect.fashion.show = 'none';
mother or father.appendChild(aspect);
}
aspect.textContent = content material;
return aspect;
}
// Funktionen zur Characteristic-Erkennung für iOS und Safari
operate isIos() iPod/.check(navigator.userAgent);
operate isSafari() android).)*safari/i.check(navigator.userAgent);
// Funktion zur Anzeige eines Modals zur Bestätigung der Audiowiedergabe
operate showAudioConsentModal(audioUrl) {
const modal = doc.createElement('div');
modal.fashion.place = 'fastened';
modal.fashion.prime = '50%';
modal.fashion.left="50%";
modal.fashion.remodel = 'translate(-50%, -50%)';
modal.fashion.padding = '20px';
modal.fashion.backgroundColor="white";
modal.fashion.border="1px strong black";
modal.fashion.zIndex = '10000';
modal.innerHTML = `
Möchten Sie die Antwort anhören?
`;
doc.physique.appendChild(modal);
doc.getElementById('playAudioButton').addEventListener('click on', () => {
const audio = new Audio(audioUrl);
audio.play().catch(error => {
console.error('Audio playback failed:', error);
});
modal.take away();
});
doc.getElementById('cancelButton').addEventListener('click on', () => {
modal.take away();
});
}
micButtonCheckbox.addEventListener('change', () => {
if (micButtonCheckbox.checked) {
const recognition = new (window.SpeechRecognition || window.webkitSpeechRecognition)();
recognition.lang = 'de-DE';
const resetButtonIcon = () => {
buttonIcon.src = defaultIconBase64;
};
recognition.onresult = async (occasion) => {
if (occasion.outcomes.size > 0) {
const textual content = occasion.outcomes[0][0].transcript;
// Verwende updateOrCreateElement, um das Gesprochen-Textual content-Ingredient zu aktualisieren oder zu erstellen
const spokenTextElement = updateOrCreateElement('spokenText', 'p', doc.physique, `Gesprochen: ${textual content}`);
recognition.cease();
micButtonCheckbox.checked = false;
// Lade-Icon sofort anzeigen, nachdem die Spracherkennung beendet ist
buttonIcon.src = loadingIconBase64;
attempt {
const response = await fetch('https://www.speaksdata.com/question.php', {
technique: 'POST',
headers: {
'Content material-Sort': 'software/json'
},
physique: JSON.stringify({
question: textual content,
user_id: userId
})
});
if (!response.okay) {
throw new Error(`HTTP error! standing: ${response.standing}`);
}
const end result = await response.json();
// Verwende updateOrCreateElement, um das Antwort-Textual content-Ingredient zu aktualisieren oder zu erstellen
const responseTextElement = updateOrCreateElement('responseText', 'p', doc.physique, `Antwort: ${end result.reply}`);
buttonIcon.src = successIconBase64;
if (end result.audio_base64) {
const audioBlob = new Blob([Uint8Array.from(atob(result.audio_base64), c => c.charCodeAt(0))], { kind: 'audio/mp3' });
const audioUrl = URL.createObjectURL(audioBlob);
if (isIos() || isSafari()) {
showAudioConsentModal(audioUrl);
} else {
const audio = new Audio(audioUrl);
audio.play().catch(error => {
console.error('Audio playback failed:', error);
});
audio.onended = () => {
URL.revokeObjectURL(audioUrl);
resetButtonIcon(); // Zurücksetzen auf das Customary-Icon nach Audiowiedergabe
};
}
} else {
const utterance = new SpeechSynthesisUtterance(end result.reply);
window.speechSynthesis.converse(utterance);
utterance.onend = resetButtonIcon; // Zurücksetzen auf das Customary-Icon nach Textual content-to-Speech
}
} catch (error) {
// Verwende updateOrCreateElement, um das Fehler-Textual content-Ingredient zu aktualisieren oder zu erstellen
const responseTextElement = updateOrCreateElement('responseText', 'p', doc.physique, `Fehler bei der Anfrage: ${error.message}`);
buttonIcon.src = errorIconBase64;
const utterance = new SpeechSynthesisUtterance("Ein Fehler ist aufgetreten");
utterance.onerror = (e) => {
console.error('TTS Error:', e);
alert("Ein Fehler ist aufgetreten");
};
window.speechSynthesis.converse(utterance);
// Icon auf Customary-Icon zurücksetzen, nachdem die Fehlermeldung abgeschlossen ist
utterance.onend = resetButtonIcon;
}
} else {
micButtonCheckbox.checked = false;
recognition.cease();
}
};
recognition.onerror = (occasion) => {
const responseTextElement = updateOrCreateElement('responseText', 'p', doc.physique, `Spracherkennungsfehler: ${occasion.error}`);
micButtonCheckbox.checked = false;
recognition.cease();
buttonIcon.src = errorIconBase64;
const utterance = new SpeechSynthesisUtterance("Ein Fehler ist aufgetreten");
utterance.onerror = (e) => {
console.error('TTS Error:', e);
alert("Ein Fehler ist aufgetreten");
};
window.speechSynthesis.converse(utterance);
// Icon auf Customary-Icon zurücksetzen, nachdem die Fehlermeldung abgeschlossen ist
utterance.onend = resetButtonIcon;
};
recognition.onspeechend = () => {
recognition.cease();
micButtonCheckbox.checked = false;
buttonIcon.src = loadingIconBase64; // Lade-Icon wird sofort nach Ende der Spracherkennung angezeigt
};
recognition.begin();
}
});
});
})();
I would not have a mac or Iphone myself and recordnized it by a good friend, hope somebody might help me with this drawback.
If a web site will likely be wanted i will even present this to seek out the failure and set this script up.
Regards and thanks, Phil
I needed to get an voice pushed reply from the script everytime i requested i attempted a number of userinteractions however nothing labored.