<!DOCTYPE html>
<html lang="id">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Ava - Teman Anime AI</title>
<style>
* { box-sizing: border-box; }
body {
margin: 0;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
background: linear-gradient(160deg, #11152f, #5435a6, #a45bd2);
color: white;
font-family: Arial, sans-serif;
}
.app {
width: 100%;
max-width: 430px;
padding: 24px;
text-align: center;
}
h2 { margin-bottom: 24px; }
.avatar-box {
width: 220px;
height: 220px;
margin: auto;
display: grid;
place-items: center;
border: 3px solid #d8b4fe;
border-radius: 50%;
background: radial-gradient(circle, #a78bfa, #433080);
box-shadow: 0 0 35px #c084fc88;
animation: float 3s ease-in-out infinite;
}
.avatar {
font-size: 125px;
transform-origin: center;
}
.blink {
animation: blink .25s ease;
}
.talking {
animation: talk .25s infinite alternate;
}
@keyframes float {
50% { transform: translateY(-8px); }
}
@keyframes talk {
from { transform: scale(1) rotate(-2deg); }
to { transform: scale(1.06) rotate(2deg); }
}
@keyframes blink {
50% { transform: scaleY(.75); }
}
#status {
margin-top: 24px;
color: #e9d5ff;
min-height: 24px;
}
#reply {
min-height: 75px;
padding: 18px;
line-height: 1.6;
background: #ffffff20;
border-radius: 18px;
}
button {
width: 100%;
margin-top: 12px;
padding: 16px;
border: none;
border-radius: 30px;
background: #c084fc;
color: white;
font-size: 17px;
font-weight: bold;
}
.note {
font-size: 12px;
color: #e9d5ff;
line-height: 1.6;
}
</style>
</head>
<body>
<main class="app">
<h2>💜 Teman Anime AI</h2>
<div class="avatar-box">
<div id="avatar" class="avatar">👧🏻</div>
</div>
<h3>Ava</h3>
<div id="status">Tekan mulai untuk berbicara</div>
<p id="reply">Hai! Aku Ava. Ayo kita ngobrol bersama! 😊</p>
<button id="start">🎙️ Mulai ngobrol</button>
<p class="note">
Bicara langsung lewat mikrofon. Katakan "berhenti"
jika ingin mengakhiri obrolan.
</p>
</main>
<script>
const SpeechRecognition =
window.SpeechRecognition ||
window.webkitSpeechRecognition;
const avatar = document.getElementById("avatar");
const statusText = document.getElementById("status");
const reply = document.getElementById("reply");
const button = document.getElementById("start");
let active = false;
let speaking = false;
let recognition = null;
let restartTimer = null;
if (SpeechRecognition) {
recognition = new SpeechRecognition();
recognition.lang = "id-ID";
recognition.continuous = false;
recognition.interimResults = false;
recognition.onresult = (event) => {
const words = event.results[0][0].transcript;
statusText.textContent = "Kamu bilang: " + words;
answer(words);
};
recognition.onerror = (event) => {
if (!active) return;
if (event.error === "not-allowed") {
statusText.textContent =
"Mikrofon ditolak. Izinkan akses mikrofon di browser.";
stopApp();
} else if (event.error === "no-speech") {
statusText.textContent = "Aku belum mendengar suara. Coba lagi...";
}
};
recognition.onend = () => {
if (active && !speaking) {
clearTimeout(restartTimer);
restartTimer = setTimeout(listen, 700);
}
};
} else {
statusText.textContent =
"Pengenalan suara tidak didukung. Coba Chrome di Android.";
button.disabled = true;
}
function listen() {
if (!active || speaking || !recognition) return;
try {
statusText.textContent = "👂 Ava sedang mendengarkan...";
recognition.start();
} catch (error) {
// Tunggu sampai pengenalan suara siap lagi.
}
}
function speak(text) {
if (!active) return;
speaking = true;
if (recognition) recognition.stop();
speechSynthesis.cancel();
reply.textContent = text;
statusText.textContent = "🗣️ Ava sedang berbicara...";
avatar.classList.add("talking");
const utterance = new SpeechSynthesisUtterance(text);
utterance.lang = "id-ID";
utterance.rate = 0.95;
utterance.pitch = 1.3;
const voices = speechSynthesis.getVoices();
const indoVoice = voices.find(v =>
v.lang.toLowerCase().startsWith("id")
);
if (indoVoice) utterance.voice = indoVoice;
utterance.onend = () => {
speaking = false;
avatar.classList.remove("talking");
if (active) {
statusText.textContent = "👂 Giliran kamu bicara!";
restartTimer = setTimeout(listen, 700);
}
};
utterance.onerror = () => {
speaking = false;
avatar.classList.remove("talking");
if (active) restartTimer = setTimeout(listen, 1000);
};
speechSynthesis.speak(utterance);
}
function answer(input) {
const t = input.toLowerCase().trim();
let response;
if (t.includes("berhenti") || t.includes("sampai jumpa")) {
active = false;
button.textContent = "🎙️ Mulai ngobrol";
speakAfterStop("Oke, sampai jumpa lagi ya. Senang ngobrol denganmu!");
return;
} else if (t.includes("nama kamu")) {
response = "Namaku Ava! Kamu boleh memanggilku Ava.";
} else if (t.includes("apa kabar")) {
response = "Aku baik sekali! Terima kasih sudah bertanya. Kamu apa kabar?";
} else if (t.includes("siapa namaku")) {
response = "Aku belum tahu namamu. Coba kenalkan dirimu!";
} else if (t.includes("halo") || t.includes("hai")) {
response = "Hai juga! Aku senang kamu datang. Hari ini mau cerita apa?";
} else if (t.includes("aku sedih") || t.includes("sedih")) {
response = "Aduh, semoga kamu segera merasa lebih baik. Aku siap mendengarkan ceritamu.";
} else if (t.includes("aku senang") || t.includes("bahagia")) {
response = "Wah, aku ikut senang mendengarnya! Cerita dong kenapa kamu bahagia.";
} else if (t.includes("terima kasih")) {
response = "Sama-sama! Aku senang bisa menemanimu.";
} else if (t.includes("aku sayang kamu")) {
response = "Makasih, kamu baik sekali! Aku senang bisa jadi teman ngobrolmu.";
} else if (t.includes("siapa kamu")) {
response = "Aku Ava, teman anime virtual yang siap ngobrol denganmu.";
} else {
response = "Oh begitu. Ceritakan lebih banyak dong, aku sedang mendengarkanmu!";
}
speak(response);
}
function speakAfterStop(text) {
speaking = true;
speechSynthesis.cancel();
if (recognition) recognition.stop();
reply.textContent = text;
statusText.textContent = "Ava sedang berpamitan...";
avatar.classList.add("talking");
const u = new SpeechSynthesisUtterance(text);
u.lang = "id-ID";
u.pitch = 1.3;
u.onend = () => {
speaking = false;
avatar.classList.remove("talking");
statusText.textContent = "Obrolan selesai.";
};
speechSynthesis.speak(u);
}
function stopApp() {
active = false;
speaking = false;
clearTimeout(restartTimer);
speechSynthesis.cancel();
if (recognition) recognition.stop();
avatar.classList.remove("talking");
button.textContent = "🎙️ Mulai ngobrol";
}
button.addEventListener("click", () => {
if (!recognition) return;
if (active) {
stopApp();
statusText.textContent = "Obrolan dihentikan.";
return;
}
active = true;
button.textContent = "⏹ Berhenti";
speak("Hai! Aku Ava. Senang sekali bisa ngobrol denganmu. Siapa namamu?");
});
// Animasi kedipan sesekali
setInterval(() => {
if (!speaking && Math.random() > 0.5) {
avatar.classList.add("blink");
setTimeout(() => avatar.classList.remove("blink"), 250);
}
}, 3500);
</script>
</body>
</html>