dograh/evals/visualizer/src/components/AudioPlayer.tsx
Abhishek 911c5ed416
fix: changes to update pipecat version to 0.0.100 (#122)
* feat: add stt evals

* add smart turn as provider

* chore: remove deprecations

* chore: format files

* fix: remove deprecated UserIdleProcessor

* fix: remove deprecated TranscriptProcessor

* chore: update pipecat submodule

* feat: add evals visualisation

* fix: trigger llm generation on client connected and pipeline started

* chore: update pipecat

* chore: update pipecat submodule

* Add tests

* fix: slow loading of workflow page

* chore: update pipecat submodule

* Show version after release

* Fixes #99

* fix: provider check for websocket connection

* Fixes #107

* Fix #96

* chore: fix documentation

* fix: cloudonix campaign call error

---------

Co-authored-by: Sabiha Khan <sabihak89@gmail.com>
2026-01-23 18:53:59 +05:30

145 lines
4.2 KiB
TypeScript

"use client";
import { useRef, useEffect, useState, useCallback } from "react";
interface AudioPlayerProps {
audioUrl: string;
duration: number;
currentTime: number;
onTimeUpdate: (time: number) => void;
onPlayingChange: (playing: boolean) => void;
}
function formatTime(seconds: number): string {
const mins = Math.floor(seconds / 60);
const secs = Math.floor(seconds % 60);
return `${mins}:${secs.toString().padStart(2, "0")}`;
}
export default function AudioPlayer({
audioUrl,
duration,
currentTime,
onTimeUpdate,
onPlayingChange,
}: AudioPlayerProps) {
const audioRef = useRef<HTMLAudioElement>(null);
const [isPlaying, setIsPlaying] = useState(false);
const [internalTime, setInternalTime] = useState(0);
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
const handleTimeUpdate = () => {
setInternalTime(audio.currentTime);
onTimeUpdate(audio.currentTime);
};
const handlePlay = () => {
setIsPlaying(true);
onPlayingChange(true);
};
const handlePause = () => {
setIsPlaying(false);
onPlayingChange(false);
};
const handleEnded = () => {
setIsPlaying(false);
onPlayingChange(false);
};
audio.addEventListener("timeupdate", handleTimeUpdate);
audio.addEventListener("play", handlePlay);
audio.addEventListener("pause", handlePause);
audio.addEventListener("ended", handleEnded);
return () => {
audio.removeEventListener("timeupdate", handleTimeUpdate);
audio.removeEventListener("play", handlePlay);
audio.removeEventListener("pause", handlePause);
audio.removeEventListener("ended", handleEnded);
};
}, [onTimeUpdate, onPlayingChange]);
// Seek to currentTime when it changes externally
useEffect(() => {
const audio = audioRef.current;
if (!audio) return;
// Only seek if the difference is significant (user clicked timeline)
if (Math.abs(audio.currentTime - currentTime) > 0.5) {
audio.currentTime = currentTime;
}
}, [currentTime]);
const togglePlay = useCallback(() => {
const audio = audioRef.current;
if (!audio) return;
if (isPlaying) {
audio.pause();
} else {
audio.play();
}
}, [isPlaying]);
const handleSeek = useCallback((e: React.ChangeEvent<HTMLInputElement>) => {
const audio = audioRef.current;
if (!audio) return;
const newTime = parseFloat(e.target.value);
audio.currentTime = newTime;
setInternalTime(newTime);
onTimeUpdate(newTime);
}, [onTimeUpdate]);
return (
<div className="bg-zinc-900 rounded-lg p-4 space-y-3">
<audio ref={audioRef} src={audioUrl} preload="metadata" />
<div className="flex items-center gap-4">
<button
onClick={togglePlay}
className="w-12 h-12 rounded-full bg-white text-black flex items-center justify-center hover:bg-zinc-200 transition-colors"
>
{isPlaying ? (
<svg className="w-5 h-5" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M18 10a8 8 0 11-16 0 8 8 0 0116 0zM7 8a1 1 0 012 0v4a1 1 0 11-2 0V8zm5-1a1 1 0 00-1 1v4a1 1 0 102 0V8a1 1 0 00-1-1z"
clipRule="evenodd"
/>
</svg>
) : (
<svg className="w-5 h-5 ml-1" fill="currentColor" viewBox="0 0 20 20">
<path
fillRule="evenodd"
d="M10 18a8 8 0 100-16 8 8 0 000 16zM9.555 7.168A1 1 0 008 8v4a1 1 0 001.555.832l3-2a1 1 0 000-1.664l-3-2z"
clipRule="evenodd"
/>
</svg>
)}
</button>
<div className="flex-1 space-y-1">
<input
type="range"
min={0}
max={duration}
step={0.1}
value={internalTime}
onChange={handleSeek}
className="w-full h-2 bg-zinc-700 rounded-lg appearance-none cursor-pointer accent-white"
/>
<div className="flex justify-between text-xs text-zinc-400">
<span>{formatTime(internalTime)}</span>
<span>{formatTime(duration)}</span>
</div>
</div>
</div>
</div>
);
}