openvibers/openvibe.vision Commits
Home: the compare table reads real benchmarks; every drawn number says Example (#99)
Changes
@@@ -97,8 +97,9 @@ function createPageRoutes(ctx) {const formError = (message, status = 400) => ({ message, status });// ── Home ─────────────────────────────────────────────────-- r.get('/', (req, res) => {-- const home = views.home({ signedIn: Boolean(signedIn(req)), ai: ai.enabled });++ r.get('/', async (req, res) => {++ const benchmarks = await store.benchmarks({ limit: 6 }).catch(() => []);++ const home = views.home({ signedIn: Boolean(signedIn(req)), ai: ai.enabled, benchmarks });return page(req, res, {index: true, cache: PUBLIC_CACHE, title: null,description: 'Ask a picture, read text, check a page, find your images and use local face privacy tools with consent for personal matching.',@@@ -24,16 +24,30 @@ function motif() {<div class="vi-sc-tabs">${tab(1, 'Read', true)}${tab(2, 'Find')}${tab(3, 'Watch')}</div><div class="vi-sc-panes"><div class="vi-sc-pane vi-sc-read"><div class="vi-sc-receipt"><b>OPENVIBE MARKET</b><span>Oat milk<i>3.40</i></span><span>Bread<i>2.10</i></span><span class="vi-sc-total">TOTAL<i>5.50</i></span></div>--<p class="vi-sc-answer"><b>TOTAL 5.50</b><small>read on this host · $0 · 38 ms</small></p></div>++<p class="vi-sc-answer"><b>TOTAL 5.50</b><small>read on this host · an example</small></p></div><div class="vi-sc-pane vi-sc-find"><p class="vi-sc-query">the red bike at the beach</p><div class="vi-sc-grid"><span class="vi-sc-ph vi-sc-ph-a"></span><span class="vi-sc-ph vi-sc-ph-b is-hit"><i></i></span><span class="vi-sc-ph vi-sc-ph-c"></span><span class="vi-sc-ph vi-sc-ph-d"></span></div>--<p class="vi-sc-answer"><b>Your photo, July 12</b><small>only your pictures are searched</small></p></div>++<p class="vi-sc-answer"><b>Your photo</b><small>only your pictures are searched</small></p></div><div class="vi-sc-pane vi-sc-watch"><div class="vi-sc-cam"><span class="vi-sc-door"></span><span class="vi-sc-box"><em>package</em></span><span class="vi-sc-rec">CAM 1 · 14:02</span></div>--<p class="vi-sc-answer"><b>A delivery at the door</b><small>told you at 14:02 · nobody identified</small></p></div>++<p class="vi-sc-answer"><b>A delivery at the door</b><small>an example alert · nobody identified</small></p></div></div></div>`;}--function home({ signedIn = false, ai = false } = {}) {++/** The compare scene: measured public benchmark aggregates when there are any, else the same table labelled Example. */++function compareScene(benchmarks) {++ const rows = Array.isArray(benchmarks) ? benchmarks.slice(0, 3) : [];++ if (!rows.length) {++ return `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>Example: one image, three answers</caption><thead><tr><th scope="col">engine</th><th scope="col">answer</th><th scope="col">cost</th><th scope="col">time</th></tr></thead><tbody><tr><td>local OCR</td><td>“TOTAL 5.50”</td><td>0.0000</td><td>38 ms</td></tr><tr><td>pool:fast</td><td>a receipt from a market</td><td>0.0004</td><td>1.1 s</td></tr><tr><td>pool:best</td><td>the total is 5.50</td><td>0.0012</td><td>2.4 s</td></tr></tbody></table></div>`;++ }++ const body = rows.map((b) => {++ const engine = b.provider ? `${b.provider}:${b.model}` : b.model;++ const cost = Number(b.avg_cost_usd) > 0 ? `$${Number(b.avg_cost_usd).toFixed(4)}` : 'free';++ return `<tr><td>${esc(engine)}</td><td>${Number(b.samples) || 0} ${Number(b.samples) === 1 ? 'sample' : 'samples'} · ${esc(b.task)}</td><td>${esc(cost)}</td><td>${Number(b.avg_latency_ms) || 0} ms</td></tr>`;++ }).join('');++ return `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>measured compare samples · mean cost and time per engine</caption><thead><tr><th scope="col">engine</th><th scope="col">task · samples</th><th scope="col">mean cost</th><th scope="col">mean time</th></tr></thead><tbody>${body}</tbody></table></div>`;++}++++function home({ signedIn = false, ai = false, benchmarks = [] } = {}) {const tryIt = `<section class="vi-section vi-tasks-wrap" id="vi-try" aria-labelledby="vi-try-h"><div class="vi-head-row"><h2 id="vi-try-h">Pick one thing to do</h2><span class="vi-count">${ai ? 'local first, AI when it helps' : 'local engines on this host'}</span></div><ul class="vi-tasklist">@@@ -63,19 +77,19 @@ ${signedIn ? '' : '<p class="vi-fine">Reading, watching and the page check work{title: 'A receipt, read for nothing',text: 'The local reader (Tesseract, on this host) reads the words a receipt actually needs: merchant, date, lines, total. No image leaves the machine and no model is called. Only when the local pass finds no usable text does a signed-in person\'s AI fallback run, and the answer says so.',-- html: `<div class="vi-demo-receipt"><span class="vi-demo-kicker">LOCAL OCR</span><b>OPENVIBE MARKET</b><span>2026-10-28 · 14:02</span><span>Oat milk 3.40</span><span>Bread 2.10</span><strong>TOTAL 5.50</strong><small>confidence 91.4 · 0.0000 USD · 38 ms</small></div>`,++ html: `<div class="vi-demo-receipt"><span class="vi-demo-kicker">Example · local OCR</span><b>OPENVIBE MARKET</b><span>a date</span><span>Oat milk 3.40</span><span>Bread 2.10</span><strong>TOTAL 5.50</strong><small>example values · not a measured result</small></div>`,action: { href: '/ocr', label: 'Read a picture' },},{title: 'The same image, side by side',text: 'A compare sends one image to the local reader and to OpenVibe.AI. AI\'s router is the authority: the provider and model shown are the ones that answered, never the hint. Cost comes from AI\'s own run, latency is measured here.',-- html: `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>one image, three answers</caption><thead><tr><th scope="col">engine</th><th scope="col">answer</th><th scope="col">cost</th><th scope="col">time</th></tr></thead><tbody><tr><td>local OCR</td><td>“TOTAL 5.50”</td><td>0.0000</td><td>38 ms</td></tr><tr><td>pool:fast</td><td>a receipt from a market</td><td>0.0004</td><td>1.1 s</td></tr><tr><td>pool:best</td><td>the total is 5.50</td><td>0.0012</td><td>2.4 s</td></tr></tbody></table></div>`,++ html: compareScene(benchmarks),action: { href: '/compare', label: 'Run a compare' },},{title: 'The UI check catches the overflow',text: 'Drop in HTML, a page URL or a screenshot. The static pass reads the boxes and the colours: a container wider than the viewport, nowrap text clipped by its box, body text under 4.5:1, positioned boxes on top of each other, a z-index with no effect. Arena calls the same API after it generates a page.',-- html: `<div class="vi-demo-check"><div class="vi-demo-page"><span class="vi-demo-overflow">this card is 1400px wide</span><span class="vi-demo-clip">a headline that gets cut off at the edge</span></div><ul><li class="is-bad"><b>overflow</b><span>1400px in a 390px view</span></li><li class="is-bad"><b>cut off</b><span>nowrap inside 120px</span></li><li class="is-bad"><b>contrast</b><span>2.4:1, needs 4.5:1</span></li></ul></div>`,++ html: `<div class="vi-demo-check"><span class="vi-demo-kicker">Example</span><div class="vi-demo-page"><span class="vi-demo-overflow">this card is 1400px wide</span><span class="vi-demo-clip">a headline that gets cut off at the edge</span></div><ul><li class="is-bad"><b>overflow</b><span>1400px in a 390px view</span></li><li class="is-bad"><b>cut off</b><span>nowrap inside 120px</span></li><li class="is-bad"><b>contrast</b><span>2.4:1, needs 4.5:1</span></li></ul></div>`,action: { href: '/ui-check', label: 'Check a page' },},{nnew file mode 100644@@@ -0,0 +1,23 @@++'use strict';++// The home's compare scene shows the measured public benchmark aggregates when there are any; when there are none it,++// the receipt and the UI check are labelled Example instead of presenting drawn numbers as measured results.++const assert = require('assert');++const views = require('../server/views');++++const bench = [{ task: 'ocr', engine: 'ai', provider: 'openrouter', model: 'model-x', samples: 12, avg_latency_ms: 240, avg_cost_usd: 0.0004 }];++const measured = views.home({ benchmarks: bench }).body;++assert.ok(measured.includes('openrouter:model-x'), 'the real engine that answered');++assert.ok(measured.includes('12 samples') && measured.includes('ocr'), 'its real sample count and task');++assert.ok(measured.includes('$0.0004') && measured.includes('240 ms'), 'its real mean cost and time');++assert.ok(measured.includes('measured compare samples'), 'the table says it is measured data');++assert.ok(!measured.includes('pool:fast'), 'the drawn engines are gone when real ones exist');++++const example = views.home({}).body;++assert.ok(example.includes('Example: one image, three answers'), 'the drawn table is labelled Example');++assert.ok(example.includes('Example · local OCR') && example.includes('example values · not a measured result'), 'the receipt is labelled Example');++assert.ok(example.includes('>Example</span>'), 'the UI check is labelled Example');++assert.ok(!example.includes('confidence 91.4'), 'no invented confidence');++assert.ok(!example.includes('read on this host · $0 · 38 ms'), 'no invented cost or time in the hero');++assert.ok(!example.includes('Your photo, July 12'), 'no invented date');++++console.log('vision home: measured benchmarks when present, and every drawn number says Example');
@@ -97,8 +97,9 @@ function createPageRoutes(ctx) {
@@ -97,8 +97,9 @@ function createPageRoutes(ctx) {
const formError = (message, status = 400) => ({ message, status });
const formError = (message, status = 400) => ({ message, status });
// ── Home ─────────────────────────────────────────────────
// ── Home ─────────────────────────────────────────────────
- r.get('/', (req, res) => {
- const home = views.home({ signedIn: Boolean(signedIn(req)), ai: ai.enabled });
+ r.get('/', async (req, res) => {
+ const benchmarks = await store.benchmarks({ limit: 6 }).catch(() => []);
+ const home = views.home({ signedIn: Boolean(signedIn(req)), ai: ai.enabled, benchmarks });
return page(req, res, {
return page(req, res, {
index: true, cache: PUBLIC_CACHE, title: null,
index: true, cache: PUBLIC_CACHE, title: null,
description: 'Ask a picture, read text, check a page, find your images and use local face privacy tools with consent for personal matching.',
description: 'Ask a picture, read text, check a page, find your images and use local face privacy tools with consent for personal matching.',
@@ -24,16 +24,30 @@ function motif() {
@@ -24,16 +24,30 @@ function motif() {
<div class="vi-sc-tabs">${tab(1, 'Read', true)}${tab(2, 'Find')}${tab(3, 'Watch')}</div>
<div class="vi-sc-tabs">${tab(1, 'Read', true)}${tab(2, 'Find')}${tab(3, 'Watch')}</div>
<div class="vi-sc-panes">
<div class="vi-sc-panes">
<div class="vi-sc-pane vi-sc-read"><div class="vi-sc-receipt"><b>OPENVIBE MARKET</b><span>Oat milk<i>3.40</i></span><span>Bread<i>2.10</i></span><span class="vi-sc-total">TOTAL<i>5.50</i></span></div>
<div class="vi-sc-pane vi-sc-read"><div class="vi-sc-receipt"><b>OPENVIBE MARKET</b><span>Oat milk<i>3.40</i></span><span>Bread<i>2.10</i></span><span class="vi-sc-total">TOTAL<i>5.50</i></span></div>
-<p class="vi-sc-answer"><b>TOTAL 5.50</b><small>read on this host · $0 · 38 ms</small></p></div>
+<p class="vi-sc-answer"><b>TOTAL 5.50</b><small>read on this host · an example</small></p></div>
<div class="vi-sc-pane vi-sc-find"><p class="vi-sc-query">the red bike at the beach</p><div class="vi-sc-grid"><span class="vi-sc-ph vi-sc-ph-a"></span><span class="vi-sc-ph vi-sc-ph-b is-hit"><i></i></span><span class="vi-sc-ph vi-sc-ph-c"></span><span class="vi-sc-ph vi-sc-ph-d"></span></div>
<div class="vi-sc-pane vi-sc-find"><p class="vi-sc-query">the red bike at the beach</p><div class="vi-sc-grid"><span class="vi-sc-ph vi-sc-ph-a"></span><span class="vi-sc-ph vi-sc-ph-b is-hit"><i></i></span><span class="vi-sc-ph vi-sc-ph-c"></span><span class="vi-sc-ph vi-sc-ph-d"></span></div>
-<p class="vi-sc-answer"><b>Your photo, July 12</b><small>only your pictures are searched</small></p></div>
+<p class="vi-sc-answer"><b>Your photo</b><small>only your pictures are searched</small></p></div>
<div class="vi-sc-pane vi-sc-watch"><div class="vi-sc-cam"><span class="vi-sc-door"></span><span class="vi-sc-box"><em>package</em></span><span class="vi-sc-rec">CAM 1 · 14:02</span></div>
<div class="vi-sc-pane vi-sc-watch"><div class="vi-sc-cam"><span class="vi-sc-door"></span><span class="vi-sc-box"><em>package</em></span><span class="vi-sc-rec">CAM 1 · 14:02</span></div>
-<p class="vi-sc-answer"><b>A delivery at the door</b><small>told you at 14:02 · nobody identified</small></p></div>
+<p class="vi-sc-answer"><b>A delivery at the door</b><small>an example alert · nobody identified</small></p></div>
</div>
</div>
</div>`;
</div>`;
}
}
-function home({ signedIn = false, ai = false } = {}) {
+/** The compare scene: measured public benchmark aggregates when there are any, else the same table labelled Example. */
+function compareScene(benchmarks) {
+ const rows = Array.isArray(benchmarks) ? benchmarks.slice(0, 3) : [];
+ if (!rows.length) {
+ return `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>Example: one image, three answers</caption><thead><tr><th scope="col">engine</th><th scope="col">answer</th><th scope="col">cost</th><th scope="col">time</th></tr></thead><tbody><tr><td>local OCR</td><td>“TOTAL 5.50”</td><td>0.0000</td><td>38 ms</td></tr><tr><td>pool:fast</td><td>a receipt from a market</td><td>0.0004</td><td>1.1 s</td></tr><tr><td>pool:best</td><td>the total is 5.50</td><td>0.0012</td><td>2.4 s</td></tr></tbody></table></div>`;
+ }
+ const body = rows.map((b) => {
+ const engine = b.provider ? `${b.provider}:${b.model}` : b.model;
+ const cost = Number(b.avg_cost_usd) > 0 ? `$${Number(b.avg_cost_usd).toFixed(4)}` : 'free';
+ return `<tr><td>${esc(engine)}</td><td>${Number(b.samples) || 0} ${Number(b.samples) === 1 ? 'sample' : 'samples'} · ${esc(b.task)}</td><td>${esc(cost)}</td><td>${Number(b.avg_latency_ms) || 0} ms</td></tr>`;
+ }).join('');
+ return `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>measured compare samples · mean cost and time per engine</caption><thead><tr><th scope="col">engine</th><th scope="col">task · samples</th><th scope="col">mean cost</th><th scope="col">mean time</th></tr></thead><tbody>${body}</tbody></table></div>`;
+}
+
+function home({ signedIn = false, ai = false, benchmarks = [] } = {}) {
const tryIt = `<section class="vi-section vi-tasks-wrap" id="vi-try" aria-labelledby="vi-try-h">
const tryIt = `<section class="vi-section vi-tasks-wrap" id="vi-try" aria-labelledby="vi-try-h">
<div class="vi-head-row"><h2 id="vi-try-h">Pick one thing to do</h2><span class="vi-count">${ai ? 'local first, AI when it helps' : 'local engines on this host'}</span></div>
<div class="vi-head-row"><h2 id="vi-try-h">Pick one thing to do</h2><span class="vi-count">${ai ? 'local first, AI when it helps' : 'local engines on this host'}</span></div>
<ul class="vi-tasklist">
<ul class="vi-tasklist">
@@ -63,19 +77,19 @@ ${signedIn ? '' : '<p class="vi-fine">Reading, watching and the page check work
@@ -63,19 +77,19 @@ ${signedIn ? '' : '<p class="vi-fine">Reading, watching and the page check work
{
{
title: 'A receipt, read for nothing',
title: 'A receipt, read for nothing',
text: 'The local reader (Tesseract, on this host) reads the words a receipt actually needs: merchant, date, lines, total. No image leaves the machine and no model is called. Only when the local pass finds no usable text does a signed-in person\'s AI fallback run, and the answer says so.',
text: 'The local reader (Tesseract, on this host) reads the words a receipt actually needs: merchant, date, lines, total. No image leaves the machine and no model is called. Only when the local pass finds no usable text does a signed-in person\'s AI fallback run, and the answer says so.',
- html: `<div class="vi-demo-receipt"><span class="vi-demo-kicker">LOCAL OCR</span><b>OPENVIBE MARKET</b><span>2026-10-28 · 14:02</span><span>Oat milk 3.40</span><span>Bread 2.10</span><strong>TOTAL 5.50</strong><small>confidence 91.4 · 0.0000 USD · 38 ms</small></div>`,
+ html: `<div class="vi-demo-receipt"><span class="vi-demo-kicker">Example · local OCR</span><b>OPENVIBE MARKET</b><span>a date</span><span>Oat milk 3.40</span><span>Bread 2.10</span><strong>TOTAL 5.50</strong><small>example values · not a measured result</small></div>`,
action: { href: '/ocr', label: 'Read a picture' },
action: { href: '/ocr', label: 'Read a picture' },
},
},
{
{
title: 'The same image, side by side',
title: 'The same image, side by side',
text: 'A compare sends one image to the local reader and to OpenVibe.AI. AI\'s router is the authority: the provider and model shown are the ones that answered, never the hint. Cost comes from AI\'s own run, latency is measured here.',
text: 'A compare sends one image to the local reader and to OpenVibe.AI. AI\'s router is the authority: the provider and model shown are the ones that answered, never the hint. Cost comes from AI\'s own run, latency is measured here.',
- html: `<div class="vi-demo-scroll"><table class="vi-demo-table"><caption>one image, three answers</caption><thead><tr><th scope="col">engine</th><th scope="col">answer</th><th scope="col">cost</th><th scope="col">time</th></tr></thead><tbody><tr><td>local OCR</td><td>“TOTAL 5.50”</td><td>0.0000</td><td>38 ms</td></tr><tr><td>pool:fast</td><td>a receipt from a market</td><td>0.0004</td><td>1.1 s</td></tr><tr><td>pool:best</td><td>the total is 5.50</td><td>0.0012</td><td>2.4 s</td></tr></tbody></table></div>`,
+ html: compareScene(benchmarks),
action: { href: '/compare', label: 'Run a compare' },
action: { href: '/compare', label: 'Run a compare' },
},
},
{
{
title: 'The UI check catches the overflow',
title: 'The UI check catches the overflow',
text: 'Drop in HTML, a page URL or a screenshot. The static pass reads the boxes and the colours: a container wider than the viewport, nowrap text clipped by its box, body text under 4.5:1, positioned boxes on top of each other, a z-index with no effect. Arena calls the same API after it generates a page.',
text: 'Drop in HTML, a page URL or a screenshot. The static pass reads the boxes and the colours: a container wider than the viewport, nowrap text clipped by its box, body text under 4.5:1, positioned boxes on top of each other, a z-index with no effect. Arena calls the same API after it generates a page.',
- html: `<div class="vi-demo-check"><div class="vi-demo-page"><span class="vi-demo-overflow">this card is 1400px wide</span><span class="vi-demo-clip">a headline that gets cut off at the edge</span></div><ul><li class="is-bad"><b>overflow</b><span>1400px in a 390px view</span></li><li class="is-bad"><b>cut off</b><span>nowrap inside 120px</span></li><li class="is-bad"><b>contrast</b><span>2.4:1, needs 4.5:1</span></li></ul></div>`,
+ html: `<div class="vi-demo-check"><span class="vi-demo-kicker">Example</span><div class="vi-demo-page"><span class="vi-demo-overflow">this card is 1400px wide</span><span class="vi-demo-clip">a headline that gets cut off at the edge</span></div><ul><li class="is-bad"><b>overflow</b><span>1400px in a 390px view</span></li><li class="is-bad"><b>cut off</b><span>nowrap inside 120px</span></li><li class="is-bad"><b>contrast</b><span>2.4:1, needs 4.5:1</span></li></ul></div>`,
action: { href: '/ui-check', label: 'Check a page' },
action: { href: '/ui-check', label: 'Check a page' },
},
},
{
{
new file mode 100644
new file mode 100644
@@ -0,0 +1,23 @@
@@ -0,0 +1,23 @@
+'use strict';
+// The home's compare scene shows the measured public benchmark aggregates when there are any; when there are none it,
+// the receipt and the UI check are labelled Example instead of presenting drawn numbers as measured results.
+const assert = require('assert');
+const views = require('../server/views');
+
+const bench = [{ task: 'ocr', engine: 'ai', provider: 'openrouter', model: 'model-x', samples: 12, avg_latency_ms: 240, avg_cost_usd: 0.0004 }];
+const measured = views.home({ benchmarks: bench }).body;
+assert.ok(measured.includes('openrouter:model-x'), 'the real engine that answered');
+assert.ok(measured.includes('12 samples') && measured.includes('ocr'), 'its real sample count and task');
+assert.ok(measured.includes('$0.0004') && measured.includes('240 ms'), 'its real mean cost and time');
+assert.ok(measured.includes('measured compare samples'), 'the table says it is measured data');
+assert.ok(!measured.includes('pool:fast'), 'the drawn engines are gone when real ones exist');
+
+const example = views.home({}).body;
+assert.ok(example.includes('Example: one image, three answers'), 'the drawn table is labelled Example');
+assert.ok(example.includes('Example · local OCR') && example.includes('example values · not a measured result'), 'the receipt is labelled Example');
+assert.ok(example.includes('>Example</span>'), 'the UI check is labelled Example');
+assert.ok(!example.includes('confidence 91.4'), 'no invented confidence');
+assert.ok(!example.includes('read on this host · $0 · 38 ms'), 'no invented cost or time in the hero');
+assert.ok(!example.includes('Your photo, July 12'), 'no invented date');
+
+console.log('vision home: measured benchmarks when present, and every drawn number says Example');