Skip to content

Commit

Permalink
Add cmdk + ZetaAI (#406)
Browse files Browse the repository at this point in the history
  • Loading branch information
lucas-janon authored Jul 31, 2024
1 parent f7a7863 commit cd9078e
Show file tree
Hide file tree
Showing 29 changed files with 3,612 additions and 77 deletions.
11 changes: 9 additions & 2 deletions .github/workflows/check-links.yaml
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
name: Check Broken Links

env:
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
VERCEL_PROJECT_ID: ${{ secrets.VERCEL_PROJECT_ID }}
on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
build:
runs-on: ubuntu-latest
Expand All @@ -24,6 +25,12 @@ jobs:
- name: Install dependencies
run: yarn

- 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: Build project
run: EXPORT=true yarn build

Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/reindex-embeddings.yaml
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
1 change: 1 addition & 0 deletions next-env.d.ts
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.
25 changes: 22 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,51 +14,69 @@
"clean": "rimraf .next out",
"tsc:watch": "tsc --watch",
"typecheck": "tsc --project ./tsconfig.json --noEmit",
"analyze": "ANALYZE=true next build"
"analyze": "ANALYZE=true next build",
"supabase:generate": "npx supabase gen types typescript --project-id gkamfbosmcsrnzhsxufs > ./src/lib/supabase/__generated__/supabase.types.ts",
"generate-embeddings": "npx tsx src/lib/generate-embeddings.ts"
},
"dependencies": {
"@ai-sdk/openai": "0.0.36",
"@emotion/cache": "11.11.0",
"@emotion/react": "11.11.3",
"@emotion/serialize": "1.1.3",
"@emotion/server": "11.11.0",
"@emotion/styled": "11.11.0",
"@mui/icons-material": "5.11.16",
"@mui/material": "5.13.1",
"@mui/icons-material": "5.16.0",
"@mui/material": "5.16.0",
"@next/bundle-analyzer": "13.5.6",
"@reduxjs/toolkit": "1.9.7",
"@segment/analytics-next": "1.41.0",
"@shikijs/core": "1.3.0",
"@shikijs/transformers": "1.3.0",
"@supabase/supabase-js": "2.44.3",
"@svgr/webpack": "6.5.1",
"@t3-oss/env-nextjs": "0.7.1",
"@tailwindcss/line-clamp": "0.4.4",
"@types/react-syntax-highlighter": "15.5.13",
"@upstash/ratelimit": "2.0.1",
"@vercel/kv": "2.0.0",
"@zetachain/addresses": "0.0.13",
"@zetachain/toolkit": "^10.0.0",
"@zetachain/ui-toolkit": "1.0.3",
"ai": "3.2.19",
"axios": "1.6.5",
"bech32": "2.0.0",
"clsx": "1.2.1",
"cmdk": "1.0.0",
"dotenv": "16.3.1",
"ethers": "5.7.2",
"framer-motion": "6.5.1",
"js-yaml": "4.1.0",
"lodash-es": "4.17.21",
"mdast-util-from-markdown": "2.0.1",
"micromark-extension-mdxjs": "3.0.0",
"next": "14.0.4",
"next-redux-wrapper": "8.1.0",
"next-seo": "6.0.0",
"next-sitemap": "^4.2.3",
"nextra": "2.13.4",
"nextra-theme-docs": "2.13.4",
"openai": "4.52.7",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "9.0.1",
"react-redux": "8.1.3",
"react-syntax-highlighter": "15.5.0",
"react-use": "17.4.3",
"remark-gfm": "4.0.0",
"sharp": "0.32.6",
"shiki": "1.3.0",
"swagger-ui-react": "5.17.2",
"tailwindcss": "3.2.6",
"twin.macro": "3.1.0",
"typescript": "5.0.4",
"unist-builder": "4.0.0",
"unist-util-filter": "5.0.1",
"yargs": "17.7.2",
"zod": "3.22.4"
},
"devDependencies": {
Expand All @@ -76,6 +94,7 @@
"@types/react": "18.2.48",
"@types/react-dom": "18.2.18",
"@types/swagger-ui-react": "4.18.3",
"@types/yargs": "17.0.32",
"@typescript-eslint/eslint-plugin": "5.62.0",
"@typescript-eslint/parser": "5.62.0",
"autoprefixer": "10.4.16",
Expand Down
4 changes: 4 additions & 0 deletions public/img/logos/close.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/img/logos/experimental.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions public/img/logos/zeta-ai.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions public/img/logos/zeta.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
105 changes: 105 additions & 0 deletions src/app/api/chat/route.ts
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 });
}
}
7 changes: 7 additions & 0 deletions src/components/Cmdk/cmdk.constants.ts
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?",
];
25 changes: 25 additions & 0 deletions src/components/Cmdk/components/ArrowIcon.tsx
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;
}
23 changes: 23 additions & 0 deletions src/components/Cmdk/components/ArrowUpIcon.tsx
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;
}
Loading

0 comments on commit cd9078e

Please sign in to comment.