-
Notifications
You must be signed in to change notification settings - Fork 12
/
App.tsx
177 lines (164 loc) · 4.77 KB
/
App.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
import React, { useEffect, useState } from "react";
import { Button, Image, Pressable, StyleSheet, Text, View } from "react-native";
import { useVoiceRecognition } from "./hooks/useVoiceRecognition";
import { Audio } from "expo-av";
import * as FileSystem from "expo-file-system";
Audio.setAudioModeAsync({
allowsRecordingIOS: false,
staysActiveInBackground: false,
playsInSilentModeIOS: true,
shouldDuckAndroid: true,
playThroughEarpieceAndroid: false,
});
export default function App() {
const { state, startRecognizing, stopRecognizing, destroyRecognizer } =
useVoiceRecognition();
const [borderColor, setBorderColor] = useState<"lightgray" | "lightgreen">(
"lightgray"
);
const [urlPath, setUrlPath] = useState("");
useEffect(() => {
listFiles();
}, []);
const listFiles = async () => {
try {
const result = await FileSystem.readDirectoryAsync(
FileSystem.documentDirectory!
);
if (result.length > 0) {
const filename = result[0];
const path = FileSystem.documentDirectory + filename;
console.log("Full path to the file:", path);
setUrlPath(path);
}
} catch (error) {
console.error("An error occurred while listing the files:", error);
}
};
const handleSubmit = async () => {
if (!state.results[0]) return;
try {
// Fetch the audio blob from the server
const audioBlob = await fetchAudio(state.results[0]);
const reader = new FileReader();
reader.onload = async (e) => {
if (e.target && typeof e.target.result === "string") {
// data:audio/mpeg;base64,....(actual base64 data)...
const audioData = e.target.result.split(",")[1];
// Write the audio data to a local file
const path = await writeAudioToFile(audioData);
await playFromPath(path);
destroyRecognizer();
}
};
reader.readAsDataURL(audioBlob);
} catch (e) {
console.error("An error occurred:", e);
}
};
// Function to fetch synthesized audio from the server
const fetchAudio = async (text: string) => {
const response = await fetch(
"http://localhost:3000/text-to-speech/synthesize",
{
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ text }),
}
);
return await response.blob();
};
// Function to write the audio data to a local file
const writeAudioToFile = async (audioData: string) => {
const path = FileSystem.documentDirectory + "temp.mp3";
await FileSystem.writeAsStringAsync(path, audioData, {
encoding: FileSystem.EncodingType.Base64,
});
return path;
};
async function playFromPath(path: string) {
try {
const soundObject = new Audio.Sound();
await soundObject.loadAsync({ uri: path });
await soundObject.playAsync();
} catch (error) {
console.log("An error occurred while playing the audio:", error);
}
}
return (
<View style={styles.container}>
<Text style={{ fontSize: 32, fontWeight: "bold", marginBottom: 30 }}>
Talk GPT 🤖
</Text>
<Text style={styles.instructions}>
Press and hold this button to record your voice. Release the button to
send the recording, and you'll hear a response
</Text>
<Text style={styles.welcome}>Your message: "{state.results[0]}"</Text>
<Pressable
onPressIn={() => {
setBorderColor("lightgreen");
startRecognizing();
}}
onPressOut={() => {
setBorderColor("lightgray");
stopRecognizing();
handleSubmit();
}}
style={{
width: "90%",
padding: 30,
gap: 10,
borderWidth: 3,
alignItems: "center",
borderRadius: 10,
borderColor: borderColor,
}}
>
<Text style={styles.welcome}>
{state.isRecording ? "Release to Send" : "Hold to Speak"}
</Text>
<Image style={styles.button} source={require("./assets/button.png")} />
</Pressable>
<Button
title="Replay last message"
onPress={async () => await playFromPath(urlPath)}
/>
</View>
);
}
const styles = StyleSheet.create({
button: {
width: 50,
height: 50,
},
container: {
flex: 1,
justifyContent: "center",
alignItems: "center",
backgroundColor: "#F5FCFF",
padding: 20,
},
welcome: {
fontSize: 20,
textAlign: "center",
margin: 10,
},
action: {
textAlign: "center",
color: "#0000FF",
marginVertical: 5,
fontWeight: "bold",
},
instructions: {
textAlign: "center",
color: "#333333",
marginBottom: 5,
fontSize: 12,
},
stat: {
textAlign: "center",
color: "#B0171F",
marginBottom: 1,
},
});