Implement preview token for oss (#23)
This commit is contained in:
commit
36a1861d01
3 changed files with 93 additions and 20 deletions
|
|
@ -7,33 +7,27 @@ import { nanoid } from '@/lib/utils'
|
||||||
|
|
||||||
export const runtime = 'edge'
|
export const runtime = 'edge'
|
||||||
|
|
||||||
const configuration = new Configuration({
|
|
||||||
apiKey: process.env.OPENAI_API_KEY
|
|
||||||
})
|
|
||||||
|
|
||||||
const openai = new OpenAIApi(configuration)
|
|
||||||
|
|
||||||
if (!process.env.OPENAI_API_KEY) {
|
|
||||||
throw new Error('Missing env var from OpenAI')
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function POST(req: Request) {
|
export async function POST(req: Request) {
|
||||||
|
const json = await req.json()
|
||||||
|
const { messages, previewToken } = json
|
||||||
const session = await auth()
|
const session = await auth()
|
||||||
|
|
||||||
|
if (process.env.VERCEL_ENV !== 'preview') {
|
||||||
if (session == null) {
|
if (session == null) {
|
||||||
return new Response('Unauthorized', { status: 401 })
|
return new Response('Unauthorized', { status: 401 })
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const json = await req.json()
|
const configuration = new Configuration({
|
||||||
const { messages } = json
|
apiKey: previewToken || process.env.OPENAI_API_KEY
|
||||||
|
})
|
||||||
|
|
||||||
|
const openai = new OpenAIApi(configuration)
|
||||||
|
|
||||||
const res = await openai.createChatCompletion({
|
const res = await openai.createChatCompletion({
|
||||||
model: 'gpt-3.5-turbo',
|
model: 'gpt-3.5-turbo',
|
||||||
messages,
|
messages,
|
||||||
temperature: 0.7,
|
temperature: 0.7,
|
||||||
top_p: 1,
|
|
||||||
frequency_penalty: 1,
|
|
||||||
max_tokens: 500,
|
|
||||||
n: 1,
|
|
||||||
stream: true
|
stream: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,22 +7,41 @@ import { ChatList } from '@/components/chat-list'
|
||||||
import { ChatPanel } from '@/components/chat-panel'
|
import { ChatPanel } from '@/components/chat-panel'
|
||||||
import { EmptyScreen } from '@/components/empty-screen'
|
import { EmptyScreen } from '@/components/empty-screen'
|
||||||
import { ChatScrollAnchor } from '@/components/chat-scroll-anchor'
|
import { ChatScrollAnchor } from '@/components/chat-scroll-anchor'
|
||||||
|
import { useLocalStorage } from '@/lib/hooks/use-local-storage'
|
||||||
|
import {
|
||||||
|
Dialog,
|
||||||
|
DialogContent,
|
||||||
|
DialogDescription,
|
||||||
|
DialogFooter,
|
||||||
|
DialogHeader,
|
||||||
|
DialogTitle
|
||||||
|
} from '@/components/ui/dialog'
|
||||||
|
import { useState } from 'react'
|
||||||
|
import { Button } from './ui/button'
|
||||||
|
import { Input } from './ui/input'
|
||||||
|
|
||||||
|
const IS_PREVIEW = process.env.VERCEL_ENV === 'preview'
|
||||||
export interface ChatProps extends React.ComponentProps<'div'> {
|
export interface ChatProps extends React.ComponentProps<'div'> {
|
||||||
initialMessages?: Message[]
|
initialMessages?: Message[]
|
||||||
id?: string
|
id?: string
|
||||||
}
|
}
|
||||||
|
|
||||||
export function Chat({ id, initialMessages, className }: ChatProps) {
|
export function Chat({ id, initialMessages, className }: ChatProps) {
|
||||||
|
const [previewToken, setPreviewToken] = useLocalStorage<string | null>(
|
||||||
|
'ai-token',
|
||||||
|
null
|
||||||
|
)
|
||||||
|
const [previewTokenDialog, setPreviewTokenDialog] = useState(IS_PREVIEW)
|
||||||
|
const [previewTokenInput, setPreviewTokenInput] = useState(previewToken ?? '')
|
||||||
const { messages, append, reload, stop, isLoading, input, setInput } =
|
const { messages, append, reload, stop, isLoading, input, setInput } =
|
||||||
useChat({
|
useChat({
|
||||||
initialMessages,
|
initialMessages,
|
||||||
id,
|
id,
|
||||||
body: {
|
body: {
|
||||||
id
|
id,
|
||||||
|
previewToken
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className={cn('pb-[200px] pt-4 md:pt-10', className)}>
|
<div className={cn('pb-[200px] pt-4 md:pt-10', className)}>
|
||||||
|
|
@ -45,6 +64,42 @@ export function Chat({ id, initialMessages, className }: ChatProps) {
|
||||||
input={input}
|
input={input}
|
||||||
setInput={setInput}
|
setInput={setInput}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
|
<Dialog open={previewTokenDialog} onOpenChange={setPreviewTokenDialog}>
|
||||||
|
<DialogContent>
|
||||||
|
<DialogHeader>
|
||||||
|
<DialogTitle>Enter your OpenAI Key</DialogTitle>
|
||||||
|
<DialogDescription>
|
||||||
|
If you have not obtained your OpenAI API key, you can do so by{' '}
|
||||||
|
<a
|
||||||
|
href="https://platform.openai.com/signup/"
|
||||||
|
className="underline"
|
||||||
|
>
|
||||||
|
signing up
|
||||||
|
</a>{' '}
|
||||||
|
on the OpenAI website. This is only necessary for preview
|
||||||
|
environments so that the open source community can test the app.
|
||||||
|
The token will be saved to your browser's local storage under
|
||||||
|
the name <code className="font-mono">ai-token</code>.
|
||||||
|
</DialogDescription>
|
||||||
|
</DialogHeader>
|
||||||
|
<Input
|
||||||
|
value={previewTokenInput}
|
||||||
|
placeholder="OpenAI API key"
|
||||||
|
onChange={e => setPreviewTokenInput(e.target.value)}
|
||||||
|
/>
|
||||||
|
<DialogFooter className="items-center">
|
||||||
|
<Button
|
||||||
|
onClick={() => {
|
||||||
|
setPreviewToken(previewTokenInput)
|
||||||
|
setPreviewTokenDialog(false)
|
||||||
|
}}
|
||||||
|
>
|
||||||
|
Save Token
|
||||||
|
</Button>
|
||||||
|
</DialogFooter>
|
||||||
|
</DialogContent>
|
||||||
|
</Dialog>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
24
lib/hooks/use-local-storage.ts
Normal file
24
lib/hooks/use-local-storage.ts
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
import { useEffect, useState } from 'react'
|
||||||
|
|
||||||
|
export const useLocalStorage = <T>(
|
||||||
|
key: string,
|
||||||
|
initialValue: T
|
||||||
|
): [T, (value: T) => void] => {
|
||||||
|
const [storedValue, setStoredValue] = useState(initialValue)
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
// Retrieve from localStorage
|
||||||
|
const item = window.localStorage.getItem(key)
|
||||||
|
if (item) {
|
||||||
|
setStoredValue(JSON.parse(item))
|
||||||
|
}
|
||||||
|
}, [key])
|
||||||
|
|
||||||
|
const setValue = (value: T) => {
|
||||||
|
// Save state
|
||||||
|
setStoredValue(value)
|
||||||
|
// Save to localStorage
|
||||||
|
window.localStorage.setItem(key, JSON.stringify(value))
|
||||||
|
}
|
||||||
|
return [storedValue, setValue]
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue