Durga-7780 commited on
Commit
4a135f5
·
verified ·
1 Parent(s): b81c8cc

Create VoiceBot.jsx

Browse files
Files changed (1) hide show
  1. src/VoiceBot.jsx +91 -0
src/VoiceBot.jsx ADDED
@@ -0,0 +1,91 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import React, { useRef, useState } from "react";
2
+ import Loader from "./Loader";
3
+
4
+ const SILENCE_THRESHOLD = 0.01;
5
+ const SILENCE_DURATION = 1500;
6
+
7
+ export default function VoiceBot() {
8
+ const mediaRecorderRef = useRef(null);
9
+ const audioChunksRef = useRef([]);
10
+ const analyserRef = useRef(null);
11
+ const audioContextRef = useRef(null);
12
+ const silenceTimerRef = useRef(null);
13
+ const streamRef = useRef(null);
14
+
15
+ const [status, setStatus] = useState("idle");
16
+ // idle | listening | thinking | speaking
17
+
18
+ // =========================
19
+ // START RECORDING
20
+ // =========================
21
+ const startRecording = async () => {
22
+ setStatus("listening");
23
+
24
+ const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
25
+ streamRef.current = stream;
26
+
27
+ mediaRecorderRef.current = new MediaRecorder(stream);
28
+ audioChunksRef.current = [];
29
+
30
+ mediaRecorderRef.current.ondataavailable = e =>
31
+ audioChunksRef.current.push(e.data);
32
+
33
+ mediaRecorderRef.current.onstop = handleStop;
34
+ mediaRecorderRef.current.start();
35
+
36
+ setupSilenceDetection(stream);
37
+ };
38
+
39
+ // =========================
40
+ // SILENCE DETECTION
41
+ // =========================
42
+ const setupSilenceDetection = stream => {
43
+ audioContextRef.current = new AudioContext();
44
+ const source = audioContextRef.current.createMediaStreamSource(stream);
45
+
46
+ analyserRef.current = audioContextRef.current.createAnalyser();
47
+ analyserRef.current.fftSize = 2048;
48
+ source.connect(analyserRef.current);
49
+
50
+ const data = new Uint8Array(analyserRef.current.fftSize);
51
+
52
+ const check = () => {
53
+ analyserRef.current.getByteTimeDomainData(data);
54
+ let sum = 0;
55
+ for (let i = 0; i < data.length; i++) {
56
+ const v = (data[i] - 128) / 128;
57
+ sum += v * v;
58
+ }
59
+ const volume = Math.sqrt(sum / data.length);
60
+
61
+ if (volume < SILENCE_THRESHOLD) {
62
+ if (!silenceTimerRef.current) {
63
+ silenceTimerRef.current = setTimeout(stopRecording, SILENCE_DURATION);
64
+ }
65
+ } else {
66
+ clearTimeout(silenceTimerRef.current);
67
+ silenceTimerRef.current = null;
68
+ }
69
+
70
+ if (status === "listening") requestAnimationFrame(check);
71
+ };
72
+
73
+ check();
74
+ };
75
+
76
+ // =========================
77
+ // STOP RECORDING
78
+ // =========================
79
+ const stopRecording = () => {
80
+ mediaRecorderRef.current?.stop();
81
+ streamRef.current?.getTracks().forEach(t => t.stop());
82
+ audioContextRef.current?.close();
83
+ };
84
+
85
+ // =========================
86
+ // SEND TO BACKEND
87
+ // =========================
88
+ const handleStop = async () => {
89
+ setStatus("thinking");
90
+
91
+ const blob = new Blob(audi