File size: 1,857 Bytes
9b9eafc
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
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>
  );
}