Skip to content

Commit 469f9af

Browse files
committed
first commit
0 parents  commit 469f9af

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

53 files changed

+27161
-0
lines changed

.env.local.example

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Supabase
2+
SUPABASE_ANON_KEY=""
3+
NEXT_PUBLIC_SUPABASE_URL=""
4+
# OpenAI
5+
OPENAI_API_KEY=""

.gitignore

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
2+
3+
# dependencies
4+
/node_modules
5+
/.pnp
6+
.pnp.js
7+
8+
# testing
9+
/coverage
10+
11+
# next.js
12+
/.next/
13+
/out/
14+
15+
# production
16+
/build
17+
18+
# misc
19+
.DS_Store
20+
*.pem
21+
22+
# debug
23+
npm-debug.log*
24+
yarn-debug.log*
25+
yarn-error.log*
26+
27+
# local env files
28+
.env.local
29+
.env.development.local
30+
.env.test.local
31+
.env.production.local
32+
33+
# vercel
34+
.vercel
35+
.next
36+
37+
# editors
38+
.vscode

README.md

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
# Domain-specific Chat GPT-3 Starter App
2+
3+
Use this starter app to build your own ChatGPT style app, that cites its sources and is trained on specifc websites that you define. Check out the live demo to get a sense of how it works: https://astro-labs.app/docs
4+
5+
## Overview
6+
7+
ChatGPT is great for casual, general-purpose question-answers but falls short when domain-specific knowledge is needed. Further, it makes up answers to fill its knowledge gaps and never cites its sources, so it can't really be trusted. This starter app uses embeddings coupled with vector search to solve this, or more specifically, to show how OpenAI's GPT-3 API can be used to create a conversational interfaces to domain-specific knowledge.
8+
9+
Embeddings, as represented by vectors of floating-point numbers, measure the "relatedness" of text strings. These are super useful for ranking search results, clustering, classification, etc. Relatedness is measured by cosine similarity. If the cosine similarity between two vectors is close to 1, the vectors are highly similar and point in the same direction. In the case of text embeddings, a high cosine similarity between two embedding vectors indicates that the corresponding text strings are highly related.
10+
11+
This starter app uses embeddings to generate a vector representation of a document, and then uses vector search to find the most similar documents to the query. The results of the vector search are then used to construct a prompt for GPT-3, which is then used to generate a response. The response is then streamed to the user.
12+
13+
Technologies used:
14+
- Nextjs (React framework) + Vercel hosting
15+
- Supabase (using their pgvector implementation as the vector database)
16+
- OpenAI API (for generating embeddings and GPT-3 responses)
17+
- TailwindCSS (for styling)
18+
19+
## Functional Overview
20+
21+
Creating and storing the embeddings:
22+
- Web pages are scraped, stripped to plain text and split into 1000-character documents
23+
- OpenAI's embedding API is used to generate embeddings for each document using the "text-embedding-ada-002" model
24+
- The embeddings are then stored in a Supabase postgres table using pgvector; the table has three columns: the document text, the source URL, and the embedding vectors returned from the OpenAI API.
25+
26+
Responding to queries:
27+
- A single embedding is generated from the user prompt
28+
- That embedding is used to perform a similarity search against the vector database
29+
- The results of the similarity search are used to construct a prompt for GPT-3
30+
- The GTP-3 response is then streamed to the user.
31+
32+
## Getting Started
33+
34+
The following set-up guide assumes at least basic familiarity developing web apps with React and Nextjs. Experience with OpenAI APIs and Supabase is helpful but not required to get things working.
35+
36+
### Set-up Supabase
37+
38+
- Create a Supabase account and project at https://app.supabase.com/sign-in. NOTE: Supabase support for pgvector is relatively new (02/2023), so it's important to create a new project if your project was created before then.
39+
- First we'll enable the Vector extension. In Supabase, this can be done from the web portal through ```Database``````Extensions```. You can also do this in SQL by running:
40+
```
41+
create extension vector;
42+
```
43+
- Next let's create a table to store our documents and their embeddings. Head over to the SQL Editor and run the following query:
44+
```sql
45+
create table documents (
46+
id bigserial primary key,
47+
content text,
48+
url text,
49+
embedding vector (1536)
50+
);
51+
```
52+
- Finally, we'll create a function that will be used to perform similarity searches. Head over to the SQL Editor and run the following query:
53+
```sql
54+
create or replace function match_documents (
55+
query_embedding vector(1536),
56+
similarity_threshold float,
57+
match_count int
58+
)
59+
returns table (
60+
id bigint,
61+
content text,
62+
url text,
63+
similarity float
64+
)
65+
language plpgsql
66+
as $$
67+
begin
68+
return query
69+
select
70+
documents.id,
71+
documents.content,
72+
documents.url,
73+
(documents.embedding <=> query_embedding) as similarity
74+
from documents
75+
where (documents.embedding <=> query_embedding) > similarity_threshold
76+
order by documents.embedding <=> query_embedding
77+
limit match_count;
78+
end;
79+
$$;
80+
```
81+
### Set-up local environment
82+
83+
- download the source code: ````gpt3-pgvector.zip```
84+
- unzip and open in your favorite editor (the following assumes VS Code on a Mac)
85+
```bash
86+
unzip gpt3-pgvector.zip
87+
cd gpt3-pgvector
88+
code .
89+
```
90+
- install dependencies
91+
```bash
92+
npm install
93+
```
94+
- create a .env.local file in the root directory to store environment variables:
95+
```bash
96+
cp .env.example .env.local
97+
```
98+
- open the .env.local file and add your Supabase project URL and API key. You can find these in the Supabase web portal under ```Project``````API```. The API key should be stored in the ```SUPABASE_ANON_KEY``` variable and project URL should be stored under ```NEXT_PUBLIC_SUPABASE_URL```.
99+
- Add your OPENAI PI key to .env.local. You can find this in the OpenAI web portal under ```API Keys```. The API key should be stored in the ```OPENAI_API_KEY``` variable.
100+
- Start the app
101+
```bash
102+
npm run dev
103+
```
104+
- Open http://localhost:3000 in your browser to view the app.
105+
106+
107+
108+
109+
110+
111+
112+
113+
114+

components/LoadingDots.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import styles from "../styles/loading-dots.module.css";
2+
3+
const LoadingDots = ({
4+
color = "#000",
5+
style = "small",
6+
}: {
7+
color: string;
8+
style: string;
9+
}) => {
10+
return (
11+
<span className={style == "small" ? styles.loading2 : styles.loading}>
12+
<span style={{ backgroundColor: color }} />
13+
<span style={{ backgroundColor: color }} />
14+
<span style={{ backgroundColor: color }} />
15+
</span>
16+
);
17+
};
18+
19+
export default LoadingDots;
20+
21+
LoadingDots.defaultProps = {
22+
style: "small",
23+
};

components/MetaTags.tsx

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
// components/PageMeta.tsx
2+
import Head from "next/head";
3+
4+
interface Props {
5+
title: string;
6+
description: string;
7+
cardImage: string;
8+
url: string;
9+
}
10+
11+
const MetaTags = ({ title, description, cardImage, url }: Props) => (
12+
<Head>
13+
<title>{title}</title>
14+
<meta name="robots" content="follow, index" />
15+
<meta content={description} name="description" />
16+
<meta property="og:url" content={url} />
17+
<meta property="og:type" content="website" />
18+
<meta property="og:site_name" content={title} />
19+
<meta property="og:description" content={description} />
20+
<meta property="og:title" content={title} />
21+
<meta property="og:image" content={cardImage} />
22+
<meta name="twitter:card" content="summary_large_image" />
23+
<meta name="twitter:site" content="@gannonh" />
24+
<meta name="twitter:title" content={title} />
25+
<meta name="twitter:description" content={description} />
26+
<meta name="twitter:image" content={cardImage} />
27+
<link
28+
rel="apple-touch-icon-precomposed"
29+
sizes="57x57"
30+
href="/bot/apple-touch-icon-57x57.png"
31+
/>
32+
<link
33+
rel="apple-touch-icon-precomposed"
34+
sizes="114x114"
35+
href="/bot/apple-touch-icon-114x114.png"
36+
/>
37+
<link
38+
rel="apple-touch-icon-precomposed"
39+
sizes="72x72"
40+
href="/bot/apple-touch-icon-72x72.png"
41+
/>
42+
<link
43+
rel="apple-touch-icon-precomposed"
44+
sizes="144x144"
45+
href="/bot/apple-touch-icon-144x144.png"
46+
/>
47+
<link
48+
rel="apple-touch-icon-precomposed"
49+
sizes="60x60"
50+
href="/bot/apple-touch-icon-60x60.png"
51+
/>
52+
<link
53+
rel="apple-touch-icon-precomposed"
54+
sizes="120x120"
55+
href="/bot/apple-touch-icon-120x120.png"
56+
/>
57+
<link
58+
rel="apple-touch-icon-precomposed"
59+
sizes="76x76"
60+
href="/bot/apple-touch-icon-76x76.png"
61+
/>
62+
<link
63+
rel="apple-touch-icon-precomposed"
64+
sizes="152x152"
65+
href="/bot/apple-touch-icon-152x152.png"
66+
/>
67+
<link
68+
rel="icon"
69+
type="image/png"
70+
href="/bot/favicon-196x196.png"
71+
sizes="196x196"
72+
/>
73+
<link
74+
rel="icon"
75+
type="image/png"
76+
href="/bot/favicon-96x96.png"
77+
sizes="96x96"
78+
/>
79+
<link
80+
rel="icon"
81+
type="image/png"
82+
href="/bot/favicon-32x32.png"
83+
sizes="32x32"
84+
/>
85+
<link
86+
rel="icon"
87+
type="image/png"
88+
href="/bot/favicon-16x16.png"
89+
sizes="16x16"
90+
/>
91+
<link
92+
rel="icon"
93+
type="image/png"
94+
href="/bot/favicon-128.png"
95+
sizes="128x128"
96+
/>
97+
<meta name="application-name" content="&nbsp;" />
98+
<meta name="msapplication-TileColor" content="#FFFFFF" />
99+
<meta
100+
name="msapplication-TileImage"
101+
content="/bot/mstile-144x144.png"
102+
/>
103+
<meta
104+
name="msapplication-square70x70logo"
105+
content="/bot/mstile-70x70.png"
106+
/>
107+
<meta
108+
name="msapplication-square150x150logo"
109+
content="/bot/mstile-150x150.png"
110+
/>
111+
<meta
112+
name="msapplication-wide310x150logo"
113+
content="/bot/mstile-310x150.png"
114+
/>
115+
<meta
116+
name="msapplication-square310x310logo"
117+
content="/bot/mstile-310x310.png"
118+
/>
119+
</Head>
120+
)
121+
122+
export default MetaTags;

components/ResizablePanel.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import { motion } from "framer-motion";
2+
import useMeasure from "react-use-measure";
3+
4+
export default function ResizablePanel({
5+
children,
6+
}: {
7+
children: React.ReactNode;
8+
}) {
9+
let [ref, { height }] = useMeasure();
10+
11+
return (
12+
<motion.div
13+
animate={height ? { height } : {}}
14+
style={height ? { height } : {}}
15+
className="relative w-full overflow-hidden"
16+
transition={{ type: "tween", duration: 0.5 }}
17+
>
18+
<div ref={ref} className={height ? "absolute inset-x-0" : "relative"}>
19+
{children}
20+
</div>
21+
</motion.div>
22+
);
23+
}

lib/embeddings-supabase.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import { createClient } from "@supabase/supabase-js";
2+
3+
interface Client {
4+
url?: string;
5+
key?: string;
6+
}
7+
8+
const client: Client = {
9+
url: process.env.NEXT_PUBLIC_SUPABASE_URL,
10+
key: process.env.SUPABASE_ANON_KEY
11+
};
12+
13+
if (!client.url || !client.key) {
14+
throw new Error("Missing Supabase credentials");
15+
}
16+
17+
export const supabaseClient = createClient(client.url!, client.key!);

next-env.d.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/// <reference types="next" />
2+
/// <reference types="next/image-types/global" />
3+
4+
// NOTE: This file should not be edited
5+
// see https://nextjs.org/docs/basic-features/typescript for more information.

next.config.js

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
3+
}

0 commit comments

Comments
 (0)