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 {
|
body {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.drag {
|
||||||
|
-webkit-app-region: drag;
|
||||||
|
}
|
||||||
|
|
|
@ -25,14 +25,7 @@ interface RootLayoutProps {
|
||||||
export default function RootLayout({ children }: RootLayoutProps) {
|
export default function RootLayout({ children }: RootLayoutProps) {
|
||||||
return (
|
return (
|
||||||
<html lang='en' suppressHydrationWarning>
|
<html lang='en' suppressHydrationWarning>
|
||||||
<head />
|
<body className='flex min-h-screen w-full bg-white font-sans antialiased'>{children}</body>
|
||||||
<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>
|
|
||||||
</html>
|
</html>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,21 +1,112 @@
|
||||||
'use client'
|
'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() {
|
export default function Home() {
|
||||||
|
const [prompt, setPrompt] = useState('')
|
||||||
|
const [messages, setMessages] = useState<Message[]>([])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className='flex min-h-screen flex-col items-center justify-between p-24'>
|
<div className='flex min-h-screen flex-1 flex-col justify-between'>
|
||||||
hello
|
<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'>
|
||||||
<textarea
|
<div className='mx-auto w-full max-w-xl leading-none'>
|
||||||
autoFocus
|
<h1 className='text-sm font-medium'>LLaMa</h1>
|
||||||
rows={1}
|
<h2 className='text-xs text-black/50'>Meta Platforms, Inc.</h2>
|
||||||
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'
|
</div>
|
||||||
onKeyDownCapture={e => {
|
</header>
|
||||||
if (e.key === 'Enter' && !e.shiftKey) {
|
<section className='mx-auto mb-10 w-full max-w-xl flex-1 break-words'>
|
||||||
e.preventDefault() // Prevents the newline character from being inserted
|
{messages.map((m, i) => (
|
||||||
// Perform your desired action here, such as submitting the form or handling the entered text
|
<div className='my-4 flex gap-4' key={i}>
|
||||||
console.log('Enter key pressed!')
|
<div className='flex-none pr-2 text-lg'>{m.sender === 'human' ? '👩' : '🤖'}</div>
|
||||||
}
|
<div className='flex-1 text-gray-900'>
|
||||||
}}
|
{m.content}
|
||||||
></textarea>
|
{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}
|
||||||
|
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
|
||||||
|
|
||||||
|
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>
|
</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/node": "20.3.1",
|
||||||
"@types/react": "18.2.13",
|
"@types/react": "18.2.13",
|
||||||
"@types/react-dom": "18.2.6",
|
"@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",
|
"autoprefixer": "10.4.14",
|
||||||
"eslint": "8.43.0",
|
"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({
|
const mainWindow = new BrowserWindow({
|
||||||
width: 800,
|
width: 800,
|
||||||
height: 600,
|
height: 600,
|
||||||
titleBarStyle: 'hidden',
|
minWidth: 400,
|
||||||
trafficLightPosition: { x: 20, y: 18 },
|
minHeight: 300,
|
||||||
vibrancy: 'titlebar',
|
titleBarStyle: 'hiddenInset',
|
||||||
|
// trafficLightPosition: { x: 20, y: 18 },
|
||||||
|
// vibrancy: 'titlebar',
|
||||||
transparent: true,
|
transparent: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
3
dev.sh
3
dev.sh
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
# Function to handle Ctrl+C
|
# Function to handle Ctrl+C
|
||||||
handle_sigint() {
|
handle_sigint() {
|
||||||
kill $pid1 $pid2 $pid3
|
kill $pid1 $pid2
|
||||||
exit
|
exit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -12,7 +12,6 @@ trap 'handle_sigint' SIGINT
|
||||||
# Start three processes in the background
|
# Start three processes in the background
|
||||||
npm run dev --prefix ./client & pid1=$!
|
npm run dev --prefix ./client & pid1=$!
|
||||||
npm start --prefix ./desktop & pid2=$!
|
npm start --prefix ./desktop & pid2=$!
|
||||||
go run -C ./server . & pid3=$!
|
|
||||||
|
|
||||||
# Wait for all processes to finish
|
# Wait for all processes to finish
|
||||||
wait
|
wait
|
||||||
|
|
Loading…
Reference in a new issue