Skip to content

Commit

Permalink
first commit
Browse files Browse the repository at this point in the history
  • Loading branch information
gannonh committed Jan 1, 2023
0 parents commit d157180
Show file tree
Hide file tree
Showing 13 changed files with 535 additions and 0 deletions.
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
OPENAI_API_KEY=<YOUR_API_KEY>
32 changes: 32 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.

# dependencies
/node_modules
/.pnp
.pnp.js

# testing
/coverage

# next.js
/.next/
/out/

# production
/build

# misc
.DS_Store
package-lock.json

# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# env files
.env
.env.local
.env.development.local
.env.test.local
.env.production.local
53 changes: 53 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
# OpenAI API - Next.js Starter Project

This is a Javascript starter project for using the Open AI API to build a Node app.

In this example app, you enter the name of a product and it outputs a product review, formatted in a very specific way in markdown. You can use this as a starting point to build purpose-built generative API functionality.

Technologies used:

- [OpenAI API](https://openai.com/api/)
- [Node.js](https://nodejs.org/en/)
- [Next.js](https://nextjs.org/)
- [React](https://reactjs.org/)
- [TailwindCSS](https://tailwindcss.com/)
- [Highlight.js](https://highlightjs.org/)

## Setup

1. If you don’t have Node.js installed, [install it from here](https://nodejs.org/en/)

2. Clone this repository

3. Navigate into the project directory

```bash
$ cd openai-api-next-starter
```

4. Install the requirements

```bash
$ npm install
```

5. Make a copy of the example environment variables file

```bash
$ cp .env.example .env
```

6. Add your [API key](https://beta.openai.com/account/api-keys) to the newly created `.env` file

7. Run the app

```bash
$ npm run dev

You should now be able to access the app at [http://localhost:3000](http://localhost:3000). Happy hacking.

## Deployment

I've run this successfully on Vercel and I'd recommend them for any Next.js (they invented Next and their DX is the best!)

Included in the repo is a vercel.json file. You need this to set a higher serverless function timeout since the Open AI PI takes about 20=30 seconds to compute. Please note that Hobby accounts with always timeout at 10s so you need to upgrade to a pro account for this to work. Totally worth it.
5 changes: 5 additions & 0 deletions next-env.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />

// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.
29 changes: 29 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
{
"name": "openai-gpt3-node-starter",
"version": "1.0.0",
"author": "Gannon Hall",
"license": "MIT",
"private": false,
"description": "OpenAI GPT-3 Node Starter Project",

"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start"
},
"dependencies": {
"highlight.js": "^11.7.0",
"next": "^12.1.6",
"openai": "^3.0.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"@types/node": "^18.11.18",
"@types/react": "^18.0.26",
"autoprefixer": "^10.4.13",
"postcss": "^8.4.20",
"tailwindcss": "^3.2.4",
"typescript": "^4.9.4"
}
}
6 changes: 6 additions & 0 deletions pages/_app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// pages/_app.js
import './styles/globals.css'

export default function MyApp({ Component, pageProps }) {
return <Component {...pageProps} />
}
64 changes: 64 additions & 0 deletions pages/api/generate.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import { Configuration, OpenAIApi } from "openai";

const configuration = new Configuration({
apiKey: process.env.OPENAI_API_KEY,
});
const openai = new OpenAIApi(configuration);

export default async function (req, res) {
const completion = await openai.createCompletion({
model: "text-davinci-003",
prompt: generatePrompt(req.body.animal),
max_tokens: 2000,
temperature: 0.6,
});
res.status(200).json({ result: completion.data.choices[0].text });
}

function generatePrompt(animal) {
const capitalizedAnimal = animal;
return `Product name: KRK ROKIT 5 G4 5 inch Powered Studio Monitors
Review:
## KRK ROKIT 5 G4 5 inch Powered Studio Monitors
<ProductImage imageName="krk-rokit-5-g4.jpg" imageAlt="KRK GoAux 4" />
| Attribute | Score |
| --------- | ------ |
| Build quality | 8.0 |
| Sound quality | 8.5 |
| Playability / Ease-of-use | 8.5 |
| Compatibility | 8.0 |
| Value | 8.5 |
The KRK ROKIT 5 G4 5 inch Powered Studio Monitors are a reliable choice for recording and mixing in a home studio or professional setting. With their bi-amped design and Kevlar drivers, these monitors deliver accurate sound with a wide frequency response.
The ROKIT 5 G4 monitors feature a built-in DSP-driven EQ that allows for precise tailoring of the monitors' response to the room. The included Auto Room Correction feature uses a measurement microphone to optimize the monitors' response to the acoustic environment.
<ProductLinks gcUrl="" amzUrl="" />
### Pros
- Accurate sound with wide frequency response
- Built-in DSP-driven EQ and Auto Room Correction feature
- Variety of connectivity options
### Cons
- Some users may find the bass response to be lacking
## Best For
The KRK ROKIT 5 G4 5 inch Powered Studio Monitors are suitable for recording and mixing in a home or professional studio. They are particularly useful for those who need precise control over the monitors' response to the room.
## Key Specifications
- Frequency response: 43Hz-40kHz
- Power: 50 W RMS / 100 W peak
- Inputs: XLR, TRS, RCA
- Outputs: 1/8" stereo headphone output
<ProductLinks gcUrl="" amzUrl="" />
Product name: ${capitalizedAnimal}
Review:`;
}



152 changes: 152 additions & 0 deletions pages/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
import Head from "next/head";
import { useState, useRef, useEffect } from "react";
import hljs from "highlight.js";

export default function Home() {
// Create a ref for the div element
const textDivRef = useRef(null);

const [animalInput, setAnimalInput] = useState("");
const [result, setResult] = useState();
const [isLoading, setIsLoading] = useState(false);

// Add a click event listener to the copy icon that copies the text in the div to the clipboard when clicked
useEffect(() => {
const copyIcon = document.querySelector(".copy-icon");
if (!copyIcon) return;
copyIcon.addEventListener("click", () => {
const textDiv = textDivRef.current;
const text = textDiv.textContent;

// Create a hidden textarea element
const textArea = document.createElement("textarea");
textArea.value = text;
document.body.appendChild(textArea);

// Select the text in the textarea
textArea.select();

// Copy the text to the clipboard
document.execCommand("copy");

// Remove the textarea element
document.body.removeChild(textArea);
});
}, []); // Run this only once

async function onSubmit(event) {
event.preventDefault();
setIsLoading(true);
const response = await fetch("/api/generate", {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({ animal: animalInput }),
});
const data = await response.json();
console.log("data", data);
console.log("data.result", data.result);

let rawResult = data.result;

console.log("rawResult");

const hljsResult = hljs.highlightAuto(rawResult).value;

setResult(hljsResult);
setAnimalInput("");
setIsLoading(false);
}

return (
<div>
<Head>
<title>training exp</title>
</Head>

<main
className="flex flex-col
items-center justify-center m-20"
>
<h3 className="text-slate-900 text-xl mb-3">
Product Review Generator
</h3>
<p className="text-slate-700 text-lg mb-3">
Open AI starter app to generate product reviews
</p>
<form onSubmit={onSubmit}>
<input
className="text-sm text-gray-base w-full
mr-3 py-5 px-4 h-2 border
border-gray-200 rounded mb-2"

type="text"
name="animal"
placeholder="Enter a product name"
value={animalInput}
onChange={(e) => setAnimalInput(e.target.value)}
/>

<button
className="text-sm w-full bg-fuchsia-600 h-7 text-white
rounded-2xl mb-10"
type="submit"
>
Generate article
</button>
</form>
{isLoading ? (
<p>Loading... Be patient.. may take 30s+</p>
) : result ? (
<div className="relative w-2/4 ">
<div
ref={textDivRef}
className="rounded-md border-spacing-2 border-slate-900 bg-slate-100 break-words max-w-500 overflow-x-auto "
>
<pre className="">
<code
className=""
dangerouslySetInnerHTML={{ __html: result }}
/>
</pre>
</div>
<span className="absolute top-0 right-0 mt-2 mr-2 cursor-pointer">
<svg
xmlns="http://www.w3.org/2000/svg"
className="icon icon-tabler icon-tabler-copy"
width="24"
height="24"
viewBox="0 0 24 24"
strokeWidth="2"
stroke="currentColor"
fill="none"
strokeLinecap="round"
strokeLinejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<rect x="8" y="8" width="12" height="12" rx="2"></rect>
<path d="M16 8v-2a2 2 0 0 0 -2 -2h-8a2 2 0 0 0 -2 2v8a2 2 0 0 0 2 2h2"></path>
</svg>
</span>
</div>
) : null}
</main>
</div>
);
}

{
/*
<div dangerouslySetInnerHTML={{ __html: result }} />
<pre>
<code dangerouslySetInnerHTML={{ __html: result }} />
</pre>
<div>{result}</div>
<pre><code>{result}</code></pre>
*/
}
Loading

0 comments on commit d157180

Please sign in to comment.