Download src/App.tsx from noodcon/PI: direct link, hf CLI and curl.
- Browser
- Download file 3.92 kB
-
https://huggingface.co/spaces/noodcon/PI/resolve/main/src/App.tsx
- Command line
-
hf download hf://spaces/noodcon/PI/src/App.tsx
-
curl -L -o App.tsx https://huggingface.co/spaces/noodcon/PI/resolve/main/src/App.tsx
3.92 kB
| import { useCallback, useRef, useState } from 'react'; | |
| import { useAgent } from './client/useAgent'; | |
| import { ChatPanel } from './components/Chat'; | |
| import { ModelDialog } from './components/ModelDialog'; | |
| import { TopBar } from './components/TopBar'; | |
| import { WorkspacePanel } from './components/Workspace'; | |
| const embedded = typeof window !== 'undefined' && window.self !== window.top; | |
| const noWebGpu = typeof navigator !== 'undefined' && !('gpu' in navigator); | |
| export default function App() { | |
| const { state, pending, shell, actions } = useAgent(); | |
| const [draft, setDraft] = useState(''); | |
| const [split, setSplit] = useState(55); | |
| const mainRef = useRef<HTMLElement>(null); | |
| const send = useCallback(() => { | |
| void actions.send(draft, () => setDraft('')); | |
| }, [actions, draft]); | |
| const loadClick = () => { | |
| actions.loadModel(false).catch((e: Error) => { | |
| if (e.name !== 'AbortError') actions.setError(e.message); | |
| }); | |
| }; | |
| const startDrag = (e: React.PointerEvent) => { | |
| const el = mainRef.current; | |
| if (!el) return; | |
| (e.currentTarget as HTMLElement).setPointerCapture(e.pointerId); | |
| const move = (ev: PointerEvent) => { | |
| const r = el.getBoundingClientRect(); | |
| setSplit(Math.min(80, Math.max(25, ((ev.clientX - r.left) / r.width) * 100))); | |
| }; | |
| const up = () => { | |
| window.removeEventListener('pointermove', move); | |
| window.removeEventListener('pointerup', up); | |
| }; | |
| window.addEventListener('pointermove', move); | |
| window.addEventListener('pointerup', up); | |
| }; | |
| const message = state.error || state.notice; | |
| return ( | |
| <div className="app"> | |
| <TopBar meter={state.meter} modelLoaded={state.modelLoaded} busy={state.busy} load={state.load} onLoad={loadClick} /> | |
| {(embedded || noWebGpu) && ( | |
| <div className="banner" role="note"> | |
| <span> | |
| {noWebGpu | |
| ? 'WebGPU is not available in this browser or frame. Use a recent Chrome or Edge.' | |
| : 'This app is running inside a frame. If model loading fails because WebGPU or browser storage is blocked, open it in its own tab.'} | |
| </span> | |
| <a href={window.location.href} target="_blank" rel="noopener noreferrer">Open in a new tab ↗</a> | |
| </div> | |
| )} | |
| {message && ( | |
| <div className={`banner${state.error ? ' error' : ''}`} role="status"> | |
| <span>{message}</span> | |
| <button className="quiet" onClick={actions.dismissNotice}>Dismiss</button> | |
| </div> | |
| )} | |
| <main ref={mainRef} style={{ gridTemplateColumns: `${split}fr 10px ${100 - split}fr` }}> | |
| <ChatPanel | |
| messages={state.messages} | |
| streaming={state.streaming} | |
| busy={state.busy} | |
| draft={draft} | |
| contextTokens={state.context.input + state.context.output} | |
| onDraft={setDraft} | |
| onSend={send} | |
| onStop={actions.stop} | |
| onNewChat={actions.newChat} | |
| /> | |
| <div | |
| className="resizer" | |
| role="separator" | |
| aria-orientation="vertical" | |
| aria-label="Resize chat and workspace" | |
| tabIndex={0} | |
| onPointerDown={startDrag} | |
| onDoubleClick={() => setSplit(55)} | |
| onKeyDown={(e) => { | |
| if (e.key === 'ArrowLeft') setSplit((s) => Math.max(25, s - 3)); | |
| if (e.key === 'ArrowRight') setSplit((s) => Math.min(80, s + 3)); | |
| }} | |
| /> | |
| <WorkspacePanel | |
| files={state.files} | |
| shell={shell} | |
| busy={state.busy} | |
| onSave={actions.writeFile} | |
| onRun={actions.runShell} | |
| onClearShell={actions.clearShell} | |
| onError={actions.setError} | |
| /> | |
| </main> | |
| <ModelDialog | |
| pending={pending} | |
| load={state.load} | |
| loading={state.busy === 'load'} | |
| onConfirm={actions.confirmPending} | |
| onCancel={actions.cancelPending} | |
| /> | |
| </div> | |
| ); | |
| } | |