import { useState, useRef } from "react"; import API from "../api"; import "./PurityAI.css"; const ELEVEN_KEY = "sk_2d090a3d6c13a30f2a89c5913a30c3f83ac82ff99a46c9b8"; const VOICE_ID = "EXAVITQu4vr4xnSDxMaL"; export default function PurityAI({ balance, onTransfer, onExternalTransfer }) { const [active, setActive] = useState(false); const [status, setStatus] = useState("idle"); const [transcript, setTranscript] = useState(""); const [response, setResponse] = useState(""); const speak = async (text) => { setStatus("speaking"); setResponse(text); try { const res = await fetch(`https://api.elevenlabs.io/v1/text-to-speech/${VOICE_ID}`, { method: "POST", headers: { "xi-api-key": ELEVEN_KEY, "Content-Type": "application/json", }, body: JSON.stringify({ text, model_id: "eleven_monolingual_v1", voice_settings: { stability: 0.5, similarity_boost: 0.75 }, }), }); if (!res.ok) throw new Error("ElevenLabs failed"); const blob = await res.blob(); const url = URL.createObjectURL(blob); const audio = new Audio(url); audio.onended = () => setStatus("idle"); await audio.play(); } catch { const u = new SpeechSynthesisUtterance(text); u.rate = 0.9; u.pitch = 1.1; const voices = speechSynthesis.getVoices(); const female = voices.find(v => v.name.includes("Female") || v.name.includes("Samantha") || v.name.includes("Google UK English Female")); if (female) u.voice = female; u.onend = () => setStatus("idle"); speechSynthesis.speak(u); } }; const handleCommand = async (text) => { const lower = text.toLowerCase(); if (lower.includes("balance") || lower.includes("how much")) { const bal = balance?.balance?.toLocaleString("en-NG") ?? "unavailable"; speak(`Your available balance is ${bal} Naira.`); } else if (lower.includes("send") || lower.includes("transfer") || lower.includes("pay")) { speak("Opening the transfer screen for you right now."); setTimeout(() => onTransfer && onTransfer(), 1500); } else if (lower.includes("bank") || lower.includes("external") || lower.includes("moniepoint")) { speak("Opening external bank transfer."); setTimeout(() => onExternalTransfer && onExternalTransfer(), 1500); } else if (lower.includes("hello") || lower.includes("hi") || lower.includes("hey")) { speak(`Hello! I'm Purity, your dolor3v assistant. I can check your balance, help you send money, or transfer to other banks. What would you like to do?`); } else if (lower.includes("account") || lower.includes("number")) { speak(`Your account number is ${balance?.account_number ?? "unavailable"}.`); } else { speak("I can help you check your balance, send money, or make a bank transfer. Just tell me what you need!"); } }; const startListening = () => { const SR = window.SpeechRecognition || window.webkitSpeechRecognition; if (!SR) { speak("Voice recognition isn't available on this browser. Try Chrome."); return; } const r = new SR(); r.lang = "en-US"; r.onstart = () => setStatus("listening"); r.onresult = (e) => { const text = e.results[0][0].transcript; setTranscript(text); handleCommand(text); }; r.onerror = () => { setStatus("idle"); speak("I didn't catch that. Please try again."); }; r.onend = () => { if (status === "listening") setStatus("idle"); }; r.start(); }; const handleTap = () => { if (!active) { setActive(true); speak("Hi! I'm Purity, your dolor3v banking assistant. How can I help you today?"); } else { startListening(); } }; return (
{status === "listening" ? "Listening..." : status === "speaking" ? "Speaking..." : active ? "Tap to speak" : "Tap to wake up"}
{transcript && (