diff --git a/speech-to-text/nextjs/realtime/example/app/page.tsx b/speech-to-text/nextjs/realtime/example/app/page.tsx index 992acccb..dfbed4ac 100644 --- a/speech-to-text/nextjs/realtime/example/app/page.tsx +++ b/speech-to-text/nextjs/realtime/example/app/page.tsx @@ -1,7 +1,7 @@ "use client"; -import { useState, useCallback, useEffect } from "react"; -import { useScribe, CommitStrategy } from "@elevenlabs/react"; +import { useCallback, useState } from "react"; +import { CommitStrategy, useScribe } from "@elevenlabs/react"; import { LiveWaveform } from "@/components/ui/live-waveform"; export default function Home() { @@ -18,43 +18,60 @@ export default function Home() { setPartialTranscript(data.text || ""); }, onCommittedTranscript: data => { - if (data.text && data.text.trim()) { + if (data.text?.trim()) { setCommittedHistory(prev => [data.text, ...prev]); } setPartialTranscript(""); }, onError: err => { console.error("Scribe error:", err); + setPartialTranscript(""); setError("Connection error occurred. Please try again."); }, - }); - - useEffect(() => { - if (scribe.status === "disconnected" || scribe.status === "error") { + onDisconnect: () => { setPartialTranscript(""); - } - }, [scribe.status]); + }, + }); - // Check both connected and transcribing states to properly show active status const isActive = scribe.status === "connected" || scribe.status === "transcribing"; const isConnecting = scribe.status === "connecting"; + const statusLabel = (() => { + switch (scribe.status) { + case "connected": + return "Connected"; + case "transcribing": + return "Transcribing"; + case "connecting": + return "Connecting"; + case "error": + return "Error"; + default: + return "Disconnected"; + } + })(); + const handleStart = useCallback(async () => { try { setError(null); setPartialTranscript(""); - // Fetch a fresh single-use token from our API const response = await fetch("/api/scribe-token"); - if (!response.ok) { - throw new Error("Failed to get transcription token"); + const data = (await response.json()) as { + token?: string; + error?: string; + }; + if (!response.ok || typeof data.token !== "string") { + throw new Error( + typeof data.error === "string" + ? data.error + : "Failed to get transcription token" + ); } - const { token } = await response.json(); - // Connect with microphone access await scribe.connect({ - token, + token: data.token, microphone: { echoCancellation: true, noiseSuppression: true, @@ -64,7 +81,9 @@ export default function Home() { } catch (err) { console.error("Failed to start transcription:", err); setError( - "Failed to start transcription. Please check your permissions and try again." + err instanceof Error + ? err.message + : "Failed to start transcription. Please check your permissions and try again." ); } }, [scribe]); @@ -77,15 +96,11 @@ export default function Home() { const handleToggle = () => { if (isActive) { handleStop(); - } else { - handleStart(); + } else if (!isConnecting) { + void handleStart(); } }; - const handleClearHistory = () => { - setCommittedHistory([]); - }; - return (
@@ -98,106 +113,57 @@ export default function Home() {

-
- {/* Controls */} -
-
- - {committedHistory.length > 0 && ( - - )} -
-
- {isActive ? ( - - - {scribe.status === "transcribing" - ? "Transcribing" - : "Connected"} - - ) : ( - Disconnected - )} -
+
+
+ + + Status: {statusLabel} +
- {/* Error message */} - {error && ( -
+ {error ? ( +

{error} -

- )} - - {/* Live waveform */} -
- -
+

+ ) : null} + + - {/* Partial transcript */} {(isActive || partialTranscript) && ( -
-

- Live Transcript -

-
-

- {partialTranscript || ( - Listening... - )} -

-
+
+

Live transcript

+

+ {partialTranscript || "Listening…"} +

)} - {/* Committed transcript history */} {committedHistory.length > 0 && (
-

- History -

-
+

History

+
{committedHistory.map((text, index) => ( -
+

{text} -

+

))}
)} - - {/* Instructions when not started */} - {!isActive && !isConnecting && committedHistory.length === 0 && ( -
- Click "Start" to begin transcribing audio from your microphone. -
- )}