Skip to content

Commit

Permalink
(Feature) Vercel AI SDK (#2024)
Browse files Browse the repository at this point in the history
  • Loading branch information
whysosaket authored Nov 19, 2024
1 parent a02597e commit 13374a1
Show file tree
Hide file tree
Showing 70 changed files with 4,074 additions and 0 deletions.
2 changes: 2 additions & 0 deletions examples/vercel-ai-sdk-chat-app/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto
29 changes: 29 additions & 0 deletions examples/vercel-ai-sdk-chat-app/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
**/.env
**/node_modules
**/dist
**/.DS_Store

# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
pnpm-debug.log*
lerna-debug.log*

node_modules
dist
dist-ssr
*.local

# Editor directories and files
.vscode/*
!.vscode/extensions.json
.idea
.DS_Store
*.suo
*.ntvs*
*.njsproj
*.sln
*.sw?
20 changes: 20 additions & 0 deletions examples/vercel-ai-sdk-chat-app/components.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "new-york",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.js",
"css": "src/index.css",
"baseColor": "zinc",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}
28 changes: 28 additions & 0 deletions examples/vercel-ai-sdk-chat-app/eslint.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import js from '@eslint/js'
import globals from 'globals'
import reactHooks from 'eslint-plugin-react-hooks'
import reactRefresh from 'eslint-plugin-react-refresh'
import tseslint from 'typescript-eslint'

export default tseslint.config(
{ ignores: ['dist'] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ['**/*.{ts,tsx}'],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
'react-hooks': reactHooks,
'react-refresh': reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
'react-refresh/only-export-components': [
'warn',
{ allowConstantExport: true },
],
},
},
)
13 changes: 13 additions & 0 deletions examples/vercel-ai-sdk-chat-app/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/mem0_logo.jpeg" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>JustChat | Chat with AI</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>
51 changes: 51 additions & 0 deletions examples/vercel-ai-sdk-chat-app/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
{
"name": "mem0-sdk-chat-bot",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "tsc -b && vite build",
"lint": "eslint .",
"preview": "vite preview"
},
"dependencies": {
"@mem0/vercel-ai-provider": "^0.0.7",
"@radix-ui/react-avatar": "^1.1.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-icons": "^1.3.1",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-scroll-area": "^1.2.0",
"@radix-ui/react-select": "^2.1.2",
"@radix-ui/react-slot": "^1.1.0",
"ai": "^3.4.31",
"buffer": "^6.0.3",
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.1",
"framer-motion": "^11.11.11",
"lucide-react": "^0.454.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-markdown": "^9.0.1",
"tailwind-merge": "^2.5.4",
"tailwindcss-animate": "^1.0.7",
"zod": "^3.23.8"
},
"devDependencies": {
"@eslint/js": "^9.13.0",
"@types/node": "^22.8.6",
"@types/react": "^18.3.12",
"@types/react-dom": "^18.3.1",
"@vitejs/plugin-react": "^4.3.3",
"autoprefixer": "^10.4.20",
"eslint": "^9.13.0",
"eslint-plugin-react-hooks": "^5.0.0",
"eslint-plugin-react-refresh": "^0.4.14",
"globals": "^15.11.0",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.14",
"typescript": "~5.6.2",
"typescript-eslint": "^8.11.0",
"vite": "^5.4.10"
}
}
6 changes: 6 additions & 0 deletions examples/vercel-ai-sdk-chat-app/postcss.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 13 additions & 0 deletions examples/vercel-ai-sdk-chat-app/src/App.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Home from "./page"


function App() {

return (
<>
<Home />
</>
)
}

export default App
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions examples/vercel-ai-sdk-chat-app/src/assets/react.svg
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.
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
import { Dispatch, SetStateAction, useContext, useEffect, useState } from 'react'
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Label } from "@/components/ui/label"
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"
import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter } from "@/components/ui/dialog"
import GlobalContext from '@/contexts/GlobalContext'

export default function ApiSettingsPopup(props: { isOpen: boolean, setIsOpen: Dispatch<SetStateAction<boolean>> }) {
const {isOpen, setIsOpen} = props
const [mem0ApiKey, setMem0ApiKey] = useState('')
const [providerApiKey, setProviderApiKey] = useState('')
const [provider, setProvider] = useState('OpenAI')
const { selectorHandler, selectedOpenAIKey, selectedMem0Key, selectedProvider } = useContext(GlobalContext);

const handleSave = () => {
// Here you would typically save the settings to your backend or local storage
selectorHandler(mem0ApiKey, providerApiKey, provider);
setIsOpen(false)
}

useEffect(() => {
if (selectedOpenAIKey) {
setProviderApiKey(selectedOpenAIKey);
}
if (selectedMem0Key) {
setMem0ApiKey(selectedMem0Key);
}
if (selectedProvider) {
setProvider(selectedProvider);
}
}, [selectedOpenAIKey, selectedMem0Key, selectedProvider]);



return (
<>
<Dialog open={isOpen} onOpenChange={setIsOpen}>
<DialogContent className="sm:max-w-[425px]">
<DialogHeader>
<DialogTitle>API Configuration Settings</DialogTitle>
</DialogHeader>
<div className="grid gap-4 py-4">
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="mem0-api-key" className="text-right">
Mem0 API Key
</Label>
<Input
id="mem0-api-key"
value={mem0ApiKey}
onChange={(e) => setMem0ApiKey(e.target.value)}
className="col-span-3 rounded-3xl"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="provider-api-key" className="text-right">
Provider API Key
</Label>
<Input
id="provider-api-key"
value={providerApiKey}
onChange={(e) => setProviderApiKey(e.target.value)}
className="col-span-3 rounded-3xl"
/>
</div>
<div className="grid grid-cols-4 items-center gap-4">
<Label htmlFor="provider" className="text-right">
Provider
</Label>
<Select value={provider} onValueChange={setProvider}>
<SelectTrigger className="col-span-3 rounded-3xl">
<SelectValue placeholder="Select provider" />
</SelectTrigger>
<SelectContent className='rounded-3xl'>
<SelectItem value="openai" className='rounded-3xl'>OpenAI</SelectItem>
<SelectItem value="anthropic" className='rounded-3xl'>Anthropic</SelectItem>
<SelectItem value="cohere" className='rounded-3xl'>Cohere</SelectItem>
<SelectItem value="groq" className='rounded-3xl'>Groq</SelectItem>
</SelectContent>
</Select>
</div>
</div>
<DialogFooter>
<Button className='rounded-3xl' variant="outline" onClick={() => setIsOpen(false)}>Cancel</Button>
<Button className='rounded-3xl' onClick={handleSave}>Save</Button>
</DialogFooter>
</DialogContent>
</Dialog>
</>
)
}
35 changes: 35 additions & 0 deletions examples/vercel-ai-sdk-chat-app/src/components/chevron-toggle.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import { Button } from "@/components/ui/button";
import { ChevronLeft, ChevronRight } from "lucide-react";
import React from "react";

const ChevronToggle = (props: {
isMemoriesExpanded: boolean;
setIsMemoriesExpanded: React.Dispatch<React.SetStateAction<boolean>>;
}) => {
const { isMemoriesExpanded, setIsMemoriesExpanded } = props;
return (
<>
<div className="relaive">
<div className="flex items-center absolute top-1/2 z-10">
<Button
variant="ghost"
size="icon"
className="h-8 w-8 border-y border rounded-lg relative right-10"
onClick={() => setIsMemoriesExpanded(!isMemoriesExpanded)}
aria-label={
isMemoriesExpanded ? "Collapse memories" : "Expand memories"
}
>
{isMemoriesExpanded ? (
<ChevronRight className="h-4 w-4" />
) : (
<ChevronLeft className="h-4 w-4" />
)}
</Button>
</div>
</div>
</>
);
};

export default ChevronToggle;
81 changes: 81 additions & 0 deletions examples/vercel-ai-sdk-chat-app/src/components/header.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import { Button } from "@/components/ui/button";
import { ChevronRight, X, RefreshCcw, Settings } from "lucide-react";
import { Dispatch, SetStateAction, useContext, useEffect, useState } from "react";
import GlobalContext from "../contexts/GlobalContext";
import { Input } from "./ui/input";

const Header = (props: {
setIsSettingsOpen: Dispatch<SetStateAction<boolean>>;
}) => {
const { setIsSettingsOpen } = props;
const { selectUserHandler, clearUserHandler, selectedUser, clearConfiguration } = useContext(GlobalContext);
const [userId, setUserId] = useState<string>("");

const handleSelectUser = (e: React.ChangeEvent<HTMLInputElement>) => {
setUserId(e.target.value);
};

const handleClearUser = () => {
clearUserHandler();
setUserId("");
};

const handleSubmit = () => {
selectUserHandler(userId);
};

// New function to handle key down events
const handleKeyDown = (e: React.KeyboardEvent<HTMLInputElement>) => {
if (e.key === 'Enter') {
e.preventDefault(); // Prevent form submission if it's in a form
handleSubmit();
}
};

useEffect(() => {
if (selectedUser) {
setUserId(selectedUser);
}
}, [selectedUser]);

return (
<>
<header className="border-b p-4 flex items-center justify-between">
<div className="flex items-center space-x-2">
<span className="text-xl font-semibold">Mem0 Assistant</span>
</div>
<div className="flex items-center space-x-2 text-sm">
<div className="flex">
<Input
placeholder="UserId"
className="w-full rounded-3xl pr-6 pl-4"
value={userId}
onChange={handleSelectUser}
onKeyDown={handleKeyDown} // Attach the key down handler here
/>
<Button variant="ghost" size="icon" onClick={handleClearUser} className="relative hover:bg-transparent hover:text-neutral-400 right-8">
<X className="h-4 w-4" />
</Button>
<Button variant="ghost" size="icon" onClick={handleSubmit} className="relative right-6">
<ChevronRight className="h-4 w-4" />
</Button>
</div>
<div className="flex items-center space-x-2">
<Button variant="ghost" size="icon" onClick={clearConfiguration}>
<RefreshCcw className="h-4 w-4" />
</Button>
<Button
variant="ghost"
size="icon"
onClick={() => setIsSettingsOpen(true)}
>
<Settings className="h-4 w-4" />
</Button>
</div>
</div>
</header>
</>
);
};

export default Header;
Loading

0 comments on commit 13374a1

Please sign in to comment.