Proff12's picture
Part 2
e618a4f verified
import React, { useEffect, useRef, useState } from 'react'
export default function App() {
const [messages, setMessages] = useState([
{ role: 'system', content: 'You are a helpful assistant that explains your reasoning clearly and concisely.' }
])
const [input, setInput] = useState('')
const [loading, setLoading] = useState(false)
const [model, setModel] = useState('')
const endRef = useRef(null)
useEffect(() => {
endRef.current?.scrollIntoView({ behavior: 'smooth' })
}, [messages, loading])
async function sendChat(nextMessages) {
const res = await fetch('/api/chat', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
messages: nextMessages,
max_new_tokens: 512,
temperature: 0.7,
top_p: 0.95
})
})
if (!res.ok) {
const t = await res.text()
throw new Error(`API ${res.status}: ${t}`)
}
return res.json()
}
const onSend = async () => {
const text = input.trim()
if (!text || loading) return
const next = [...messages, { role: 'user', content: text }]
setMessages(next)
setInput('')
setLoading(true)
try {
const { reply, model } = await sendChat(next)
setModel(model)
setMessages([...next, { role: 'assistant', content: reply }])
} catch (e) {
setMessages([...next, { role: 'assistant', content: `(Error) ${e.message}` }])
} finally {
setLoading(false)
}
}
const onKeyDown = (e) => {
if (e.key === 'Enter' && !e.shiftKey) {
e.preventDefault()
onSend()
}
}
return (
<div className="app">
<header className="header">
<div className="brand">Fathom R1 Chat</div>
{model && <div className="model">{model}</div>}
</header>
<main className="chat">
{messages.filter(m => m.role !== 'system').map((m, i) => (
<div key={i} className={`bubble ${m.role}`}>
<div className="sender">{m.role === 'user' ? 'You' : 'Assistant'}</div>
<div className="content">{m.content}</div>
</div>
))}
{loading && <div className="bubble assistant"><div className="content">Thinking…</div></div>}
<div ref={endRef} />
</main>
<footer className="composer">
<textarea
value={input}
onChange={(e) => setInput(e.target.value)}
onKeyDown={onKeyDown}
placeholder="Ask a question…"
rows={2}
/>
<button onClick={onSend} disabled={loading || !input.trim()}>Send</button>
</footer>
</div>
)
}