PI / src /components /ModelDialog.tsx
noodcon's picture
Upload 64 files
9b9eafc verified
Raw
History Blame Contribute Delete
1.86 kB
import type { LoadState } from '../client/useAgent';
import type { PendingSend } from '../client/useAgent';
import { formatBytes } from '../lib/format';
interface Props {
pending: PendingSend | null;
load: LoadState | null;
loading: boolean;
onConfirm: () => void;
onCancel: () => void;
}
export function ModelDialog({ pending, load, loading, onConfirm, onCancel }: Props) {
if (!pending) return null;
const progress = load?.phase === 'download' ? load : null;
return (
<div className="overlay" onKeyDown={(e) => e.key === 'Escape' && onCancel()}>
<div className="dialog" role="dialog" aria-modal="true" aria-labelledby="dlg-title">
<h2 id="dlg-title">Download model weights</h2>
<p>Everything happens in your browser. Your prompts and files stay on this device.</p>
<div className="facts">
<strong>About 1.84 GB on the first download</strong>
<span>Saved in this browser (OPFS) and SHA-256 verified, so next starts are fast.</span>
</div>
<p>Your message</p>
<div className="preview">{pending.text}</div>
{loading && (
<>
<progress max={progress?.total ?? 1} value={progress?.loaded} />
<p>
{load?.phase === 'compile' ? 'Preparing GPU…' : load?.phase === 'warmup' ? 'Warming up…' : progress ? `${formatBytes(progress.loaded)} of ${formatBytes(progress.total)}` : 'Starting…'}
</p>
</>
)}
{pending.error && <p className="err" role="alert">{pending.error}</p>}
<div className="actions">
<button onClick={onCancel}>Cancel</button>
<button className="primary" onClick={onConfirm} disabled={loading} autoFocus>
{pending.error ? 'Retry' : 'Load model & send'}
</button>
</div>
</div>
</div>
);
}