Skip to content

BustosAndrew/lirical

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

This is a Next.js project bootstrapped with create-next-app and styled with Chakra UI. Stripe is used for subscriptions and OpenAI's Whisper to perform speech to text with audio files. All text, except audio file transcription, is streamed to provide a smoother user experience.

Live Deployment

https://www.lirical.xyz/

Getting Started

First, run the development server:

npm run dev
# or
yarn dev
# or
pnpm dev

Open http://localhost:3000 with your browser to see the result.

Code Examples

lirical/pages/index.js

Lines 1 to 197 in 052238c

import Head from "next/head"
import { useState } from "react"
import {
Button,
Heading,
Flex,
Text,
Accordion,
AccordionItem,
AccordionButton,
AccordionPanel,
AccordionIcon,
Box,
Link,
HStack,
Divider,
} from "@chakra-ui/react"
import NextLink from "next/link"
import { Step, Steps, useSteps } from "chakra-ui-steps"
import { steps } from "@/data/steps"
export default function Home() {
const [input, setInput] = useState("")
const [output, setOutput] = useState("")
const { nextStep, prevStep, setStep, reset, activeStep } = useSteps({
initialStep: 0,
})
const [submitted, setSubmitted] = useState(false)
const changeInputType = (val) => {
setInput(val)
}
const outputHandler = (output) => {
setOutput((prev) => prev + output)
}
const toggleSumbitted = () => {
setSubmitted(true)
}
const restart = () => {
setSubmitted(!submitted)
}
return (
<>
<Head>
<title>Lirical App</title>
<meta name='viewport' content='width=device-width, initial-scale=1' />
<link rel='icon' href='/favicon.ico' />
</Head>
<Flex h='100vh' justifyContent='center' alignItems='flex-start'>
<Flex alignItems='center' flexDir='column' textAlign='center' pb={5}>
<HStack alignContent='center' mt={10}>
<Link fontSize={20} as={NextLink} color='brand.900' href='/'>
Home
</Link>
<Divider orientation='vertical' borderColor='brand.900' h={8} />
<Link
fontSize={20}
as={NextLink}
color='brand.900'
href='/subscribe'
>
Subscribe
</Link>
<Divider orientation='vertical' borderColor='brand.900' h={8} />
<Link fontSize={20} as={NextLink} color='brand.900' href='/account'>
Account
</Link>
</HStack>
<Steps mt={[0, 0, 20]} w='sm' p={5} activeStep={activeStep}>
{steps.map(({ label }, indx) => (
<Step key={indx}>
{(indx === 0 && steps[0].content(changeInputType)) ||
(indx === 1 &&
steps[1].content(input, outputHandler, toggleSumbitted)) ||
(indx === 2 && steps[2].content(output))}
</Step>
))}
</Steps>
{activeStep === steps.length ? (
<Flex direction='column' gap={5} p={4}>
<Text fontWeight='bold' color='brand.800'>
Would you like to start all over?
</Text>
<Button
bg='brand.900'
mx='auto'
size='md'
onClick={() => {
reset()
restart()
}}
_hover={{ background: "#f1ecaf" }}
>
Reset
</Button>
</Flex>
) : (
<Flex width='100%' justify='flex-end' pr={5}>
<Button
isDisabled={activeStep === 0}
mr={4}
onClick={prevStep}
size='sm'
variant='ghost'
_disabled={{
cursor: "not-allowed",
opacity: 0.2,
}}
_hover={
activeStep !== 0 && {
background: "brand.900",
color: "black",
}
}
color='brand.800'
>
Prev
</Button>
<Button
size='sm'
bg='brand.900'
onClick={nextStep}
_hover={{ background: "brand.800" }}
isDisabled={!input || (activeStep === 1 && !submitted)}
>
{activeStep === steps.length - 1 ? "Finish" : "Next"}
</Button>
</Flex>
)}
<Heading
mt={5}
w={["80%", "sm"]}
justifySelf='left'
color='brand.900'
size='lg'
>
Disclaimer
</Heading>
<Accordion
allowToggle
textAlign='left'
w={["80%", "xs"]}
color='brand.800'
>
<AccordionItem>
<h2>
<AccordionButton>
<Box as='span' flex='1' textAlign='left'>
Why is it saying my lyrics are inappropriate or offensive?
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Besides the reason it gives you, it&apos;s because Open AI has
policies that prevent discrimination, harassment, and hate
speech. You may have to try again with different lyrics.
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box as='span' flex='1' textAlign='left'>
How do I restart from the beginning?
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Go to step 3, hit Finish and then hit Reset.
</AccordionPanel>
</AccordionItem>
<AccordionItem>
<h2>
<AccordionButton>
<Box as='span' flex='1' textAlign='left'>
There is an issue with my account.
</Box>
<AccordionIcon />
</AccordionButton>
</h2>
<AccordionPanel pb={4}>
Please email me at [email protected] with any account
issues.
</AccordionPanel>
</AccordionItem>
</Accordion>
</Flex>
</Flex>
</>
)
}

const dotenv = require("dotenv").config()
const fs = require("fs")
const FormData = require("form-data")
const formidable = require("formidable")
import fetch from "node-fetch"
// import { clearTimeout } from "timers"
export const config = {
api: {
bodyParser: false,
},
}
const key = process.env.OPEN_AI_KEY
const model = "whisper-1"
export default async function handler(req, res) {
if (req.method !== "POST") {
res.status(405).send({ message: "Only POST requests allowed" })
return
}
const form = new formidable.IncomingForm({
keepExtensions: true,
})
form.parse(req, async (err, fields, files) => {
if (err) return res.status(400).send({ error: "Parse error: " + err })
const formData = new FormData()
formData.append(
"file",
fs.createReadStream(files.file.filepath),
files.file.originalFilename
)
formData.append("model", model)
const id = setTimeout(
() =>
res.status(400).send({
error:
"Whisper is currently experience slowdowns. Please try again later.",
}),
9900
)
const response = await fetch(
"https://api.openai.com/v1/audio/transcriptions",
{
method: "POST",
headers: {
...formData.getHeaders(),
Authorization: `Bearer ${key}`,
},
body: formData,
}
)
clearTimeout(id)
const { text, error } = await response.json()
if (response.ok) {
res.status(200).send({ text: text })
} else {
console.log("OPEN AI ERROR:")
console.log(error.message)
res.status(400).send({ error: "OPEN AI ERROR: " + error.message })
}
})
// res.status(200).json({ text: "end req" })
}

// import { Configuration, OpenAIApi } from "openai"
import { OpenAIStream } from "../../helpers/OpenAIStream"
export const config = {
runtime: "edge",
}
export default async function handler(req, res) {
if (req.method !== "POST") {
res.status(405).send({ message: "Only POST requests allowed" })
return
}
const { text } = await req.json()
try {
const payload = {
model: "gpt-3.5-turbo",
messages: [
{
role: "user",
content: "Suggest lyrics specifically after " + text + "",
},
],
temperature: 0.7,
stream: true,
}
// clearTimeout(id)
const stream = await OpenAIStream(payload)
return new Response(stream)
// res.status(200).send({ text: completion.data.choices[0].message.content })
} catch (err) {
res.status(400).send({ error: err })
}
}