Disabled .env to keep entire app on client side
This commit is contained in:
parent
f303012075
commit
6e60df6b1e
@ -1 +0,0 @@
|
|||||||
OPENAI_API_KEY=""
|
|
@ -26,7 +26,7 @@ To set up the project locally, follow these steps:
|
|||||||
4. Start the development server with `npm run dev`.
|
4. Start the development server with `npm run dev`.
|
||||||
5. Open `http://localhost:3000` to view it in the browser.
|
5. Open `http://localhost:3000` to view it in the browser.
|
||||||
|
|
||||||
## How to use Environment Variable
|
## How to use Environment Variable (Disabled and reverted to keep things purely on Client Side)
|
||||||
1. Copy the `.env.example` file to:
|
1. Copy the `.env.example` file to:
|
||||||
- .env.local file: For Local Development (This should not be committed to Git) - `cp .env.example .env.local`
|
- .env.local file: For Local Development (This should not be committed to Git) - `cp .env.example .env.local`
|
||||||
- .env: For Production Deployment (This can be via Vercel Environment Variables under your Project's settings page. `cp .env.example .env`
|
- .env: For Production Deployment (This can be via Vercel Environment Variables under your Project's settings page. `cp .env.example .env`
|
||||||
|
@ -23,26 +23,18 @@ import {
|
|||||||
Box,
|
Box,
|
||||||
Tooltip,
|
Tooltip,
|
||||||
Switch,
|
Switch,
|
||||||
FormHelperText
|
FormHelperText,
|
||||||
} from '@chakra-ui/react';
|
} from "@chakra-ui/react";
|
||||||
import OpenAI from "openai";
|
import OpenAI from "openai";
|
||||||
import { useState, useRef, useEffect } from 'react';
|
import { useState, useRef, useEffect } from "react";
|
||||||
import { saveAs } from 'file-saver'; // You will need to install file-saver: npm install file-saver
|
import { saveAs } from "file-saver"; // You will need to install file-saver: npm install file-saver
|
||||||
|
|
||||||
|
|
||||||
export default function Home() {
|
export default function Home() {
|
||||||
const apiKeyFromEnv = process.env.OPENAI_API_KEY;
|
const [apiKeyInput, setApiKey] = useState("");
|
||||||
const [apiKeyInput, setApiKey] = useState('');
|
|
||||||
|
|
||||||
useEffect(() => {
|
const [model, setModel] = useState("tts-1");
|
||||||
if (!!apiKeyFromEnv) {
|
const [inputText, setInputText] = useState("");
|
||||||
setApiKey(apiKeyFromEnv);
|
const [voice, setVoice] = useState("alloy");
|
||||||
}
|
|
||||||
}, [apiKeyFromEnv]);
|
|
||||||
|
|
||||||
const [model, setModel] = useState('tts-1');
|
|
||||||
const [inputText, setInputText] = useState('');
|
|
||||||
const [voice, setVoice] = useState('alloy');
|
|
||||||
const [speed, setSpeed] = useState(1);
|
const [speed, setSpeed] = useState(1);
|
||||||
const [isSubmitting, setIsSubmitting] = useState(false);
|
const [isSubmitting, setIsSubmitting] = useState(false);
|
||||||
const [sliderValue, setSliderValue] = useState(1);
|
const [sliderValue, setSliderValue] = useState(1);
|
||||||
@ -62,14 +54,13 @@ export default function Home() {
|
|||||||
const toast = useToast();
|
const toast = useToast();
|
||||||
|
|
||||||
const handleModelToggle = () => {
|
const handleModelToggle = () => {
|
||||||
setModel(model === 'tts-1' ? 'tts-1-hd' : 'tts-1');
|
setModel(model === "tts-1" ? "tts-1-hd" : "tts-1");
|
||||||
};
|
};
|
||||||
|
|
||||||
const handleDownload = () => {
|
const handleDownload = () => {
|
||||||
saveAs(audioUrl, 'speech.mp3'); // This will save the file as "speech.mp3"
|
saveAs(audioUrl, "speech.mp3"); // This will save the file as "speech.mp3"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// Assuming `openai.audio.speech.create` returns a stream or binary data
|
// Assuming `openai.audio.speech.create` returns a stream or binary data
|
||||||
const handleSubmit = async (e) => {
|
const handleSubmit = async (e) => {
|
||||||
e.preventDefault();
|
e.preventDefault();
|
||||||
@ -78,7 +69,7 @@ export default function Home() {
|
|||||||
try {
|
try {
|
||||||
// Define the request headers
|
// Define the request headers
|
||||||
const headers = new Headers();
|
const headers = new Headers();
|
||||||
const apiKey = apiKeyFromEnv && !!apiKeyFromEnv ? apiKeyFromEnv : apiKeyInput;
|
const apiKey = apiKeyInput;
|
||||||
headers.append("Authorization", `Bearer ${apiKey}`);
|
headers.append("Authorization", `Bearer ${apiKey}`);
|
||||||
headers.append("Content-Type", "application/json");
|
headers.append("Content-Type", "application/json");
|
||||||
|
|
||||||
@ -87,12 +78,12 @@ export default function Home() {
|
|||||||
model: model,
|
model: model,
|
||||||
input: inputText,
|
input: inputText,
|
||||||
voice: voice,
|
voice: voice,
|
||||||
speed: speed.toFixed(1)
|
speed: speed.toFixed(1),
|
||||||
});
|
});
|
||||||
|
|
||||||
// Make the fetch request to the OpenAI API
|
// Make the fetch request to the OpenAI API
|
||||||
const response = await fetch('https://api.openai.com/v1/audio/speech', {
|
const response = await fetch("https://api.openai.com/v1/audio/speech", {
|
||||||
method: 'POST',
|
method: "POST",
|
||||||
headers: headers,
|
headers: headers,
|
||||||
body: body,
|
body: body,
|
||||||
});
|
});
|
||||||
@ -111,13 +102,12 @@ export default function Home() {
|
|||||||
|
|
||||||
// Update your component's state or context
|
// Update your component's state or context
|
||||||
setAudioUrl(audioUrl);
|
setAudioUrl(audioUrl);
|
||||||
|
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
console.error("Error:", error);
|
console.error("Error:", error);
|
||||||
toast({
|
toast({
|
||||||
title: 'An error occurred',
|
title: "An error occurred",
|
||||||
description: error.message,
|
description: error.message,
|
||||||
status: 'error',
|
status: "error",
|
||||||
duration: 5000,
|
duration: 5000,
|
||||||
isClosable: true,
|
isClosable: true,
|
||||||
});
|
});
|
||||||
@ -126,10 +116,6 @@ export default function Home() {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const handleInputChange = (e) => {
|
const handleInputChange = (e) => {
|
||||||
if (e.target.value.length <= 4096) {
|
if (e.target.value.length <= 4096) {
|
||||||
setInputText(e.target.value);
|
setInputText(e.target.value);
|
||||||
@ -137,9 +123,15 @@ export default function Home() {
|
|||||||
};
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Container bg={'gray.100'} maxW="container">
|
<Container bg={"gray.100"} maxW="container">
|
||||||
<Container centerContent p={4} maxW="container.md">
|
<Container centerContent p={4} maxW="container.md">
|
||||||
<Flex direction="column" align="center" justify="center" minH="100vh" w="full">
|
<Flex
|
||||||
|
direction="column"
|
||||||
|
align="center"
|
||||||
|
justify="center"
|
||||||
|
minH="100vh"
|
||||||
|
w="full"
|
||||||
|
>
|
||||||
<Box
|
<Box
|
||||||
bg="white" // Assuming the card is white
|
bg="white" // Assuming the card is white
|
||||||
borderRadius="lg" // Rounded corners
|
borderRadius="lg" // Rounded corners
|
||||||
@ -148,62 +140,85 @@ export default function Home() {
|
|||||||
w="full" // Full width of the parent
|
w="full" // Full width of the parent
|
||||||
maxW="md" // Maximum width
|
maxW="md" // Maximum width
|
||||||
>
|
>
|
||||||
<VStack spacing={6} as="form" onSubmit={handleSubmit} width="full" maxW="md">
|
<VStack
|
||||||
<Box bg='black' w='100%' p={5} borderTopRadius="md" boxShadow="lg">
|
spacing={6}
|
||||||
<Heading textAlign="center" color="white">Open-Audio TTS</Heading>
|
as="form"
|
||||||
<Text fontSize="xs" color="gray.100" textAlign="center" mt={2}>Powered by OpenAI TTS </Text>
|
onSubmit={handleSubmit}
|
||||||
<Text fontSize="xs" color="gray.100" textAlign="center" mt={2} fontWeight={'700'}>
|
width="full"
|
||||||
<a href="https://github.com/Justmalhar/open-audio" target="_blank" rel="noopener noreferrer" style={{ color: 'gray.100' }}>
|
maxW="md"
|
||||||
View on GitHub
|
>
|
||||||
</a>
|
<Box
|
||||||
</Text>
|
bg="black"
|
||||||
</Box>
|
w="100%"
|
||||||
|
p={5}
|
||||||
|
borderTopRadius="md"
|
||||||
|
boxShadow="lg"
|
||||||
|
>
|
||||||
|
<Heading textAlign="center" color="white">
|
||||||
|
Open-Audio TTS
|
||||||
|
</Heading>
|
||||||
|
<Text fontSize="xs" color="gray.100" textAlign="center" mt={2}>
|
||||||
|
Powered by OpenAI TTS{" "}
|
||||||
|
</Text>
|
||||||
|
<Text
|
||||||
|
fontSize="xs"
|
||||||
|
color="gray.100"
|
||||||
|
textAlign="center"
|
||||||
|
mt={2}
|
||||||
|
fontWeight={"700"}
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="https://github.com/Justmalhar/open-audio"
|
||||||
|
target="_blank"
|
||||||
|
rel="noopener noreferrer"
|
||||||
|
style={{ color: "gray.100" }}
|
||||||
|
>
|
||||||
|
View on GitHub
|
||||||
|
</a>
|
||||||
|
</Text>
|
||||||
|
</Box>
|
||||||
<Grid
|
<Grid
|
||||||
templateColumns={{ md: '4fr 1fr' }} // 80-20 ratio
|
templateColumns={{ md: "4fr 1fr" }} // 80-20 ratio
|
||||||
gap={4}
|
gap={4}
|
||||||
width="full"
|
width="full"
|
||||||
>
|
>
|
||||||
<FormControl isRequired>
|
<FormControl isRequired>
|
||||||
<FormLabel htmlFor='api-key'>API Key</FormLabel>
|
<FormLabel htmlFor="api-key">API Key</FormLabel>
|
||||||
<Input
|
<Input
|
||||||
id='api-key'
|
id="api-key"
|
||||||
placeholder='Enter your OpenAI API key'
|
placeholder="Enter your OpenAI API key"
|
||||||
type='password'
|
type="password"
|
||||||
value={apiKeyInput}
|
value={apiKeyInput}
|
||||||
onChange={(e) => setApiKey(e.target.value)}
|
onChange={(e) => setApiKey(e.target.value)}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
borderColor="black"
|
borderColor="black"
|
||||||
disabled={!!apiKeyFromEnv} // Disable the input if apiKeyFromEnv is truthy
|
|
||||||
/>
|
/>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl>
|
<FormControl>
|
||||||
<VStack align="start" spacing={0}>
|
<VStack align="start" spacing={0}>
|
||||||
<FormLabel htmlFor='model'>
|
<FormLabel htmlFor="model">Quality</FormLabel>
|
||||||
Quality
|
<HStack align="center" h="100%" mx="0" mt="2">
|
||||||
</FormLabel>
|
|
||||||
<HStack align="center" h='100%' mx='0' mt='2' >
|
|
||||||
<Switch
|
<Switch
|
||||||
id='model'
|
id="model"
|
||||||
colorScheme="blackAlpha"
|
colorScheme="blackAlpha"
|
||||||
isChecked={model === 'tts-1-hd'}
|
isChecked={model === "tts-1-hd"}
|
||||||
onChange={handleModelToggle}
|
onChange={handleModelToggle}
|
||||||
size="md" // Optional: if you want a larger switch
|
size="md" // Optional: if you want a larger switch
|
||||||
/>
|
/>
|
||||||
<FormHelperText textAlign="center" mt={'-1'}>
|
<FormHelperText textAlign="center" mt={"-1"}>
|
||||||
{model === 'tts-1' ? 'High' : 'HD'}
|
{model === "tts-1" ? "High" : "HD"}
|
||||||
</FormHelperText>
|
</FormHelperText>
|
||||||
</HStack>
|
</HStack>
|
||||||
</VStack>
|
</VStack>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<FormControl isRequired>
|
<FormControl isRequired>
|
||||||
<FormLabel htmlFor='input-text'>Input Text</FormLabel>
|
<FormLabel htmlFor="input-text">Input Text</FormLabel>
|
||||||
<Textarea
|
<Textarea
|
||||||
id='input-text'
|
id="input-text"
|
||||||
placeholder='Enter the text you want to convert to speech'
|
placeholder="Enter the text you want to convert to speech"
|
||||||
value={inputText}
|
value={inputText}
|
||||||
onChange={handleInputChange}
|
onChange={handleInputChange}
|
||||||
resize="vertical"
|
resize="vertical"
|
||||||
@ -217,9 +232,9 @@ export default function Home() {
|
|||||||
|
|
||||||
<HStack width="full" justifyContent="space-between">
|
<HStack width="full" justifyContent="space-between">
|
||||||
<FormControl isRequired width="45%">
|
<FormControl isRequired width="45%">
|
||||||
<FormLabel htmlFor='voice'>Voice</FormLabel>
|
<FormLabel htmlFor="voice">Voice</FormLabel>
|
||||||
<Select
|
<Select
|
||||||
id='voice'
|
id="voice"
|
||||||
value={voice}
|
value={voice}
|
||||||
onChange={(e) => setVoice(e.target.value)}
|
onChange={(e) => setVoice(e.target.value)}
|
||||||
variant="outline"
|
variant="outline"
|
||||||
@ -227,22 +242,22 @@ export default function Home() {
|
|||||||
borderColor="black"
|
borderColor="black"
|
||||||
focusBorderColor="black"
|
focusBorderColor="black"
|
||||||
colorScheme="blackAlpha"
|
colorScheme="blackAlpha"
|
||||||
_hover={{ borderColor: 'gray.400' }} // Optional: style for hover state
|
_hover={{ borderColor: "gray.400" }} // Optional: style for hover state
|
||||||
>
|
>
|
||||||
{/* List of supported voices */}
|
{/* List of supported voices */}
|
||||||
<option value='alloy'>Alloy</option>
|
<option value="alloy">Alloy</option>
|
||||||
<option value='echo'>Echo</option>
|
<option value="echo">Echo</option>
|
||||||
<option value='fable'>Fable</option>
|
<option value="fable">Fable</option>
|
||||||
<option value='onyx'>Onyx</option>
|
<option value="onyx">Onyx</option>
|
||||||
<option value='nova'>Nova</option>
|
<option value="nova">Nova</option>
|
||||||
<option value='shimmer'>Shimmer</option>
|
<option value="shimmer">Shimmer</option>
|
||||||
</Select>
|
</Select>
|
||||||
</FormControl>
|
</FormControl>
|
||||||
|
|
||||||
<FormControl width="40%" mt='-15'>
|
<FormControl width="40%" mt="-15">
|
||||||
<FormLabel htmlFor='speed'>Speed </FormLabel>
|
<FormLabel htmlFor="speed">Speed </FormLabel>
|
||||||
<Slider
|
<Slider
|
||||||
id='speed'
|
id="speed"
|
||||||
defaultValue={1}
|
defaultValue={1}
|
||||||
min={0.25}
|
min={0.25}
|
||||||
max={4}
|
max={4}
|
||||||
@ -251,18 +266,18 @@ export default function Home() {
|
|||||||
onMouseEnter={() => setShowTooltip(true)}
|
onMouseEnter={() => setShowTooltip(true)}
|
||||||
onMouseLeave={() => setShowTooltip(false)}
|
onMouseLeave={() => setShowTooltip(false)}
|
||||||
ref={sliderRef}
|
ref={sliderRef}
|
||||||
aria-label='slider-ex-1'
|
aria-label="slider-ex-1"
|
||||||
>
|
>
|
||||||
<SliderTrack bg="gray">
|
<SliderTrack bg="gray">
|
||||||
<SliderFilledTrack bg="black" />
|
<SliderFilledTrack bg="black" />
|
||||||
</SliderTrack>
|
</SliderTrack>
|
||||||
<Tooltip
|
<Tooltip
|
||||||
hasArrow
|
hasArrow
|
||||||
bg='black'
|
bg="black"
|
||||||
color='white'
|
color="white"
|
||||||
placement='bottom'
|
placement="bottom"
|
||||||
isOpen={showTooltip}
|
isOpen={showTooltip}
|
||||||
label={`${(sliderValue).toFixed(2)}x`}
|
label={`${sliderValue.toFixed(2)}x`}
|
||||||
>
|
>
|
||||||
<SliderThumb />
|
<SliderThumb />
|
||||||
</Tooltip>
|
</Tooltip>
|
||||||
@ -272,11 +287,11 @@ export default function Home() {
|
|||||||
|
|
||||||
<Button
|
<Button
|
||||||
size="lg"
|
size="lg"
|
||||||
bg='black'
|
bg="black"
|
||||||
color={'white'}
|
color={"white"}
|
||||||
colorScheme='black'
|
colorScheme="black"
|
||||||
borderColor="black"
|
borderColor="black"
|
||||||
type='submit'
|
type="submit"
|
||||||
isLoading={isSubmitting}
|
isLoading={isSubmitting}
|
||||||
loadingText="Generating..."
|
loadingText="Generating..."
|
||||||
>
|
>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user