Exploratory client
This commit is contained in:
parent
db81d81b23
commit
2f4aa42d2e
8 changed files with 6605 additions and 89 deletions
|
@ -6,3 +6,7 @@ html,
|
|||
body {
|
||||
background: transparent;
|
||||
}
|
||||
|
||||
.drag {
|
||||
-webkit-app-region: drag;
|
||||
}
|
||||
|
|
|
@ -25,14 +25,7 @@ interface RootLayoutProps {
|
|||
export default function RootLayout({ children }: RootLayoutProps) {
|
||||
return (
|
||||
<html lang='en' suppressHydrationWarning>
|
||||
<head />
|
||||
<body className='font-sans antialiased min-h-screen flex'>
|
||||
<aside className='w-52 flex-none'></aside>
|
||||
<section className='flex-1 bg-white border-l border-gray-300'>
|
||||
<header className='sticky top-0 z-50 flex h-16 w-full shrink-0 items-center justify-between px-4 backdrop-blur-xl'></header>
|
||||
<section className='flex flex-col flex-1'>{children}</section>
|
||||
</section>
|
||||
</body>
|
||||
<body className='flex min-h-screen w-full bg-white font-sans antialiased'>{children}</body>
|
||||
</html>
|
||||
)
|
||||
}
|
||||
|
|
|
@ -1,21 +1,112 @@
|
|||
'use client'
|
||||
import { useState } from 'react'
|
||||
|
||||
const API_URL = 'http://127.0.0.1:8080'
|
||||
|
||||
type Message = {
|
||||
sender: string
|
||||
content: string
|
||||
}
|
||||
|
||||
async function completion(prompt: string, callback: (res: string) => void) {
|
||||
const result = await fetch(`${API_URL}/completion`, {
|
||||
method: 'POST',
|
||||
body: JSON.stringify({
|
||||
prompt: prompt,
|
||||
temperature: 0.2,
|
||||
top_k: 40,
|
||||
top_p: 0.9,
|
||||
n_predict: 256,
|
||||
stop: ['\n### Human:'], // stop completion after generating this
|
||||
stream: true,
|
||||
}),
|
||||
})
|
||||
|
||||
if (!result.ok || !result.body) {
|
||||
return
|
||||
}
|
||||
|
||||
let reader = result.body.getReader()
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read()
|
||||
|
||||
if (done) {
|
||||
break
|
||||
}
|
||||
|
||||
const t = Buffer.from(value).toString('utf8')
|
||||
if (t.startsWith('data: ')) {
|
||||
const message = JSON.parse(t.substring(6))
|
||||
callback(message.content)
|
||||
if (message.stop) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
export default function Home() {
|
||||
const [prompt, setPrompt] = useState('')
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
|
||||
return (
|
||||
<div className='flex min-h-screen flex-col items-center justify-between p-24'>
|
||||
hello
|
||||
<div className='flex min-h-screen flex-1 flex-col justify-between'>
|
||||
<header className='drag sticky top-0 z-50 flex w-full flex-row items-center border-b border-black/5 bg-gray-50/75 p-3 backdrop-blur-md'>
|
||||
<div className='mx-auto w-full max-w-xl leading-none'>
|
||||
<h1 className='text-sm font-medium'>LLaMa</h1>
|
||||
<h2 className='text-xs text-black/50'>Meta Platforms, Inc.</h2>
|
||||
</div>
|
||||
</header>
|
||||
<section className='mx-auto mb-10 w-full max-w-xl flex-1 break-words'>
|
||||
{messages.map((m, i) => (
|
||||
<div className='my-4 flex gap-4' key={i}>
|
||||
<div className='flex-none pr-2 text-lg'>{m.sender === 'human' ? '👩' : '🤖'}</div>
|
||||
<div className='flex-1 text-gray-900'>
|
||||
{m.content}
|
||||
{m.sender === 'bot' && <span className='relative -top-[3px] left-1 text-[10px] text-blue-600'>⬤</span>}
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</section>
|
||||
<div className='sticky bottom-0 bg-gradient-to-b from-transparent to-white'>
|
||||
<textarea
|
||||
autoFocus
|
||||
rows={1}
|
||||
className='w-full border border-gray-200 rounded-xl px-5 py-3.5 resize-none text-[15px] shadow-lg shadow-black/5 block mx-4 focus:outline-none'
|
||||
onKeyDownCapture={e => {
|
||||
value={prompt}
|
||||
placeholder='Send a message...'
|
||||
onChange={e => setPrompt(e.target.value)}
|
||||
className='mx-auto my-4 block w-full max-w-xl resize-none rounded-xl border border-gray-200 px-5 py-3.5 text-[15px] shadow-lg shadow-black/5 focus:outline-none'
|
||||
onKeyDownCapture={async e => {
|
||||
if (e.key === 'Enter' && !e.shiftKey) {
|
||||
e.preventDefault() // Prevents the newline character from being inserted
|
||||
// Perform your desired action here, such as submitting the form or handling the entered text
|
||||
console.log('Enter key pressed!')
|
||||
|
||||
await setMessages(messages => {
|
||||
return [...messages, { sender: 'human', content: prompt }]
|
||||
})
|
||||
|
||||
const index = messages.length + 1
|
||||
completion(prompt, res => {
|
||||
setMessages(messages => {
|
||||
let message = messages[index]
|
||||
if (!message) {
|
||||
message = { sender: 'bot', content: '' }
|
||||
}
|
||||
|
||||
message.content = message.content + res
|
||||
|
||||
return [...messages.slice(0, index), message]
|
||||
})
|
||||
})
|
||||
|
||||
setPrompt('')
|
||||
}
|
||||
}}
|
||||
></textarea>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
|
526
client/package-lock.json
generated
526
client/package-lock.json
generated
File diff suppressed because it is too large
Load diff
|
@ -27,12 +27,14 @@
|
|||
"@types/node": "20.3.1",
|
||||
"@types/react": "18.2.13",
|
||||
"@types/react-dom": "18.2.6",
|
||||
"pkg": "^5.8.1",
|
||||
"tailwindcss": "3.3.2",
|
||||
"typescript": "5.1.3",
|
||||
"postcss": "8.4.24",
|
||||
"autoprefixer": "10.4.14",
|
||||
"eslint": "8.43.0",
|
||||
"eslint-config-next": "13.4.7"
|
||||
"eslint-config-next": "13.4.7",
|
||||
"pkg": "^5.8.1",
|
||||
"postcss": "8.4.24",
|
||||
"prettier": "^2.8.8",
|
||||
"prettier-plugin-tailwindcss": "^0.3.0",
|
||||
"tailwindcss": "3.3.2",
|
||||
"typescript": "5.1.3"
|
||||
}
|
||||
}
|
||||
|
|
6013
desktop/package-lock.json
generated
Normal file
6013
desktop/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
|
@ -11,9 +11,11 @@ const createWindow = () => {
|
|||
const mainWindow = new BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
titleBarStyle: 'hidden',
|
||||
trafficLightPosition: { x: 20, y: 18 },
|
||||
vibrancy: 'titlebar',
|
||||
minWidth: 400,
|
||||
minHeight: 300,
|
||||
titleBarStyle: 'hiddenInset',
|
||||
// trafficLightPosition: { x: 20, y: 18 },
|
||||
// vibrancy: 'titlebar',
|
||||
transparent: true,
|
||||
})
|
||||
|
||||
|
|
3
dev.sh
3
dev.sh
|
@ -2,7 +2,7 @@
|
|||
|
||||
# Function to handle Ctrl+C
|
||||
handle_sigint() {
|
||||
kill $pid1 $pid2 $pid3
|
||||
kill $pid1 $pid2
|
||||
exit
|
||||
}
|
||||
|
||||
|
@ -12,7 +12,6 @@ trap 'handle_sigint' SIGINT
|
|||
# Start three processes in the background
|
||||
npm run dev --prefix ./client & pid1=$!
|
||||
npm start --prefix ./desktop & pid2=$!
|
||||
go run -C ./server . & pid3=$!
|
||||
|
||||
# Wait for all processes to finish
|
||||
wait
|
||||
|
|
Loading…
Reference in a new issue