-
Notifications
You must be signed in to change notification settings - Fork 61
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
f7a7863
commit cd9078e
Showing
29 changed files
with
3,612 additions
and
77 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
name: Reindex embeddings | ||
env: | ||
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }} | ||
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }} | ||
on: | ||
push: | ||
branches: [main] | ||
jobs: | ||
reindex-embeddings: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@v3 | ||
- name: Set up Node.js 20 | ||
uses: actions/setup-node@v3 | ||
with: | ||
node-version: 20 | ||
|
||
- uses: actions/cache@v3 | ||
id: yarn-cache | ||
with: | ||
path: "**/node_modules" | ||
key: ${{ runner.os }}-yarn-${{ hashFiles('yarn.lock') }} | ||
|
||
- name: Install yarn packages | ||
if: steps.yarn-cache.outputs.cache-hit != 'true' | ||
run: yarn install | ||
|
||
- name: Install Vercel CLI | ||
run: npm install --global vercel@latest | ||
|
||
- name: Pull Vercel Environment Information | ||
run: vercel pull --yes --environment=production --token=${{ secrets.VERCEL_TOKEN }} | ||
|
||
- name: Generate embeddings | ||
run: yarn generate-embeddings |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,6 @@ | ||
/// <reference types="next" /> | ||
/// <reference types="next/image-types/global" /> | ||
/// <reference types="next/navigation-types/compat/navigation" /> | ||
|
||
// NOTE: This file should not be edited | ||
// see https://nextjs.org/docs/basic-features/typescript for more information. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
/* eslint-disable no-console */ | ||
import { openai } from "@ai-sdk/openai"; | ||
import { Ratelimit } from "@upstash/ratelimit"; | ||
import { kv } from "@vercel/kv"; | ||
import { CoreMessage, embed, streamText } from "ai"; | ||
|
||
import { supabaseClient } from "~/lib/supabase/client"; | ||
|
||
const getPrompt = ( | ||
userPrompt: string, | ||
pageSections: | ||
| { | ||
id: number; | ||
page_id: number; | ||
slug: string; | ||
heading: string; | ||
content: string; | ||
similarity: number; | ||
}[] | ||
| null | ||
) => { | ||
if (typeof process.env.ZETA_AI_PROMPT !== "string") throw new Error("ZETA_AI_PROMPT is not a string"); | ||
|
||
return Buffer.from(process.env.ZETA_AI_PROMPT, "base64") | ||
.toString("utf-8") | ||
.replace("{{userPrompt}}", userPrompt) | ||
.replace( | ||
"{{pageSections}}", | ||
pageSections?.length | ||
? (pageSections || []).map((section) => section.content).join("\n") | ||
: "No ZetaChain data available: just answer \"I'm sorry, I don't have the information to answer that question.\"" | ||
); | ||
}; | ||
|
||
// Allow streaming responses up to 45 seconds | ||
export const maxDuration = 45; | ||
|
||
export async function POST(req: Request) { | ||
try { | ||
if (!process.env.KV_REST_API_URL || !process.env.KV_REST_API_TOKEN) { | ||
throw new Error("KV_REST_API_URL and KV_REST_API_TOKEN env vars not found."); | ||
} | ||
|
||
const ip = req.headers.get("x-forwarded-for"); | ||
const ratelimit = new Ratelimit({ | ||
redis: kv, | ||
limiter: Ratelimit.fixedWindow(15, "10m"), | ||
}); | ||
|
||
const { success, limit, reset, remaining } = await ratelimit.limit(`ratelimit_${ip}`); | ||
|
||
if (!success) { | ||
console.error("Rate limit exceeded for IP:", ip); | ||
|
||
return new Response("You have reached your request limit for the day.", { | ||
status: 429, | ||
headers: { | ||
"X-RateLimit-Limit": limit.toString(), | ||
"X-RateLimit-Remaining": remaining.toString(), | ||
"X-RateLimit-Reset": reset.toString(), | ||
}, | ||
}); | ||
} | ||
|
||
const { messages: _messages } = await req.json(); | ||
const messages = _messages as CoreMessage[]; | ||
|
||
const userPrompt = messages[messages.length - 1].content; | ||
|
||
const { embedding } = await embed({ | ||
model: openai.embedding("text-embedding-ada-002"), | ||
value: userPrompt, | ||
}); | ||
|
||
const { | ||
error: matchError, | ||
data: pageSections, | ||
status, | ||
} = await supabaseClient.rpc("match_page_sections", { | ||
embedding: embedding as any, | ||
match_threshold: 0.7, | ||
match_count: 10, | ||
min_content_length: 50, | ||
}); | ||
|
||
if (process.env.NODE_ENV === "development") { | ||
console.log(matchError, pageSections, status); | ||
|
||
console.log(`Got the following sections: ${pageSections?.map((s) => `${s.heading}\n`)}`); | ||
} | ||
|
||
const prompt = getPrompt(userPrompt as string, pageSections); | ||
|
||
const result = await streamText({ | ||
model: openai("gpt-4o-mini"), | ||
prompt, | ||
}); | ||
|
||
return result.toAIStreamResponse(); | ||
} catch (error) { | ||
console.error(error); | ||
|
||
return new Response("Internal Server Error", { status: 500 }); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
export const cmdkChatQuestions = [ | ||
"What are universal apps?", | ||
"What is a ZRC-20 token?", | ||
"What is an observer-signer validator?", | ||
"What is ZetaHub?", | ||
"How can I run a validator?", | ||
]; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
import React from "react"; | ||
|
||
export const ArrowIcon: React.FC<ArrowIconProps> = ({ className }) => { | ||
return ( | ||
<svg | ||
width="24" | ||
height="24" | ||
viewBox="0 0 24 24" | ||
fill="none" | ||
xmlns="http://www.w3.org/2000/svg" | ||
className={className} | ||
> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M7 6.93945L2.46967 11.4698C2.17678 11.7627 2.17678 12.2375 2.46967 12.5304L7 17.0608L8.06066 16.0001L4.81066 12.7501L21.75 12.7501L21.75 11.2501L4.81066 11.2501L8.06066 8.00011L7 6.93945Z" | ||
className="dark:fill-white fill-[#696E75]" | ||
/> | ||
</svg> | ||
); | ||
}; | ||
|
||
interface ArrowIconProps { | ||
className?: string; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import clsx from "clsx"; | ||
import React from "react"; | ||
|
||
export const ArrowUpIcon: React.FC<ArrowUpIconProps> = ({ className, enabled }) => { | ||
return ( | ||
<svg width="8" height="8" viewBox="0 0 8 8" fill="none" xmlns="http://www.w3.org/2000/svg" className={className}> | ||
<path | ||
fillRule="evenodd" | ||
clipRule="evenodd" | ||
d="M2.55024 0H7.05024C7.32638 0 7.55024 0.223858 7.55024 0.5V5H6.55024V1.70711L0.928786 7.32856L0.22168 6.62145L5.84313 1H2.55024V0Z" | ||
className={clsx({ | ||
"fill-black dark:fill-grey-300": !enabled, | ||
"fill-black": enabled, | ||
})} | ||
/> | ||
</svg> | ||
); | ||
}; | ||
|
||
interface ArrowUpIconProps { | ||
className: string; | ||
enabled: boolean; | ||
} |
Oops, something went wrong.