-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathbasic.html
More file actions
121 lines (104 loc) · 5.01 KB
/
Copy pathbasic.html
File metadata and controls
121 lines (104 loc) · 5.01 KB
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>PAW Browser Inference Demo</title>
<style>
*, *::before, *::after { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif; background: #f5f5f5; color: #1a1a1a; padding: 2rem; max-width: 640px; margin: 0 auto; }
h1 { font-size: 1.5rem; margin-bottom: 0.5rem; }
.subtitle { color: #666; font-size: 0.9rem; margin-bottom: 2rem; }
.card { background: white; border-radius: 12px; padding: 1.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); margin-bottom: 1rem; }
label { display: block; font-size: 0.85rem; font-weight: 600; color: #333; margin-bottom: 0.5rem; }
textarea { width: 100%; padding: 0.75rem; border: 1px solid #ddd; border-radius: 8px; font-size: 0.9rem; resize: none; font-family: inherit; }
textarea:focus { outline: none; border-color: #4f6df5; box-shadow: 0 0 0 3px rgba(79,109,245,0.1); }
button { background: #1a1a1a; color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 8px; font-size: 0.9rem; font-weight: 600; cursor: pointer; width: 100%; margin-top: 1rem; }
button:hover { background: #333; }
button:disabled { opacity: 0.5; cursor: not-allowed; }
.progress-bar { height: 4px; background: #eee; border-radius: 2px; margin-top: 0.5rem; overflow: hidden; }
.progress-fill { height: 100%; background: #4f6df5; transition: width 0.3s; width: 0%; }
.status { font-size: 0.8rem; color: #888; margin-top: 0.5rem; }
.output { background: #f0fdf4; border: 1px solid #bbf7d0; border-radius: 8px; padding: 0.75rem; font-family: 'SF Mono', Monaco, monospace; font-size: 0.9rem; white-space: pre-wrap; min-height: 2rem; }
.hidden { display: none; }
</style>
</head>
<body>
<h1>PAW Browser Inference</h1>
<p class="subtitle">Run neural programs locally in your browser — no custom server needed for inference.</p>
<div class="card">
<label for="program">Program</label>
<input id="program" type="text" value="email-triage-browser"
style="width:100%; padding:0.75rem; border:1px solid #ddd; border-radius:8px; font-size:0.9rem;"
placeholder="Program slug or ID">
<label for="input" style="margin-top:1rem;">Input</label>
<textarea id="input" rows="3" placeholder="Enter text to process...">Urgent: the production server is down and customers are affected!</textarea>
<button id="run" disabled>Loading model...</button>
<div class="progress-bar" id="progress-container">
<div class="progress-fill" id="progress-fill"></div>
</div>
<div class="status" id="status"></div>
</div>
<div class="card hidden" id="output-card">
<label>Output</label>
<div class="output" id="output"></div>
</div>
<script type="module">
import paw from 'https://cdn.jsdelivr.net/npm/@programasweights/web';
const btnRun = document.getElementById('run');
const elStatus = document.getElementById('status');
const elProgress = document.getElementById('progress-fill');
const elOutput = document.getElementById('output');
const elOutputCard = document.getElementById('output-card');
const elProgram = document.getElementById('program');
const elInput = document.getElementById('input');
let fn = null;
async function loadProgram() {
const slug = elProgram.value.trim();
if (!slug) return;
btnRun.disabled = true;
btnRun.textContent = 'Loading model...';
elStatus.textContent = 'Downloading base model (first time only, ~134 MB)...';
try {
fn = await paw.function(slug, {
onProgress: ({ loaded, total, stage }) => {
const pct = total > 0 ? Math.round((loaded / total) * 100) : 0;
elProgress.style.width = `${pct}%`;
elStatus.textContent = stage === 'base-model'
? `Downloading base model... ${pct}%`
: `Loading adapter... ${pct}%`;
},
});
btnRun.disabled = false;
btnRun.textContent = 'Run';
elStatus.textContent = 'Ready! Model loaded and cached.';
elProgress.style.width = '100%';
} catch (err) {
elStatus.textContent = `Error: ${err.message}`;
btnRun.textContent = 'Failed';
}
}
btnRun.addEventListener('click', async () => {
if (!fn) return;
const input = elInput.value.trim();
if (!input) return;
btnRun.disabled = true;
btnRun.textContent = 'Running...';
try {
const t0 = performance.now();
const result = await fn(input);
const elapsed = Math.round(performance.now() - t0);
elOutput.textContent = result;
elOutputCard.classList.remove('hidden');
elStatus.textContent = `Done in ${elapsed}ms`;
} catch (err) {
elStatus.textContent = `Error: ${err.message}`;
} finally {
btnRun.disabled = false;
btnRun.textContent = 'Run';
}
});
loadProgram();
</script>
</body>
</html>