openvibers/openvibe.live Commits

Home 'Right now': the AI note alone, never the raw speech-to-text after ' — heard:' (a Greek stream's 500-character transcript filled the featured card, owner 2026-10-17); static, so it applies before the server half (#236) can deploy (#237)

OP OpenVibers committed 27 days ago · e7b5800589 · 2 files, +23 −1

Changes

ddiff --git a/public/js/home-featured.js b/public/js/home-featured.js
iindex c8e36bce..5bd17b71 100644
---- a/public/js/home-featured.js
++++ b/public/js/home-featured.js
@@@ -116,6 +116,9 @@
function render(d) {
const s = d.stream;
const m = d.moment;
++ // The note alone: the raw speech-to-text after " — heard:" is the AI's context, not something to show (it can be
++ // 500 characters of another language; the server strips it too, server/db/database.js publicMemoryText).
++ const now = m && m.description ? String(m.description).replace(/\s+—\s+heard:[\s\S]*$/, '').trim() : '';
const chan = typeof channelPath === 'function' ? channelPath(s.username, s.managed_stream_slug || s.managed_stream_id || null) : `/@${s.username}`;
const viewers = Number(s.total_viewer_count || s.viewer_count || 0);
const up = (typeof formatUptime === 'function' && s.started_at) ? formatUptime(s.started_at) : '';
@@@ -138,7 +141,7 @@
${s.category ? `<span class="hf-tag"${s.ai_category && s.ai_category === s.category ? ' title="Category inferred by OpenVibe&#39;s AI from the stream"' : ''}>${escText(s.category)}${s.ai_category && s.ai_category === s.category ? '<span class="cat-inferred"> · inferred</span>' : ''}</span>` : ''}
${up ? `<span class="muted"><i class="fa-solid fa-clock"></i> ${escText(up)}</span>` : ''}
</a>
-- ${m && m.description ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(m.description)}</div>` : ''}
++ ${now ? `<div class="hf-now"><div class="hf-now-head"><i class="fa-solid fa-wand-magic-sparkles"></i> Right now <span>${m.captured_at ? escText(typeof timeAgo === 'function' ? timeAgo(m.captured_at) : '') : ''}</span></div>${escText(now)}</div>` : ''}
${s.ai_overview_short || s.ai_overview ? `<div class="hf-overview">${escText(s.ai_overview_short || s.ai_overview)}</div>` : ''}
<div class="hf-actions">
<a class="hf-watch" href="${escText(chan)}" onclick="return handleLinkClick(event, '${escText(chan)}')"><i class="fa-solid fa-play"></i> Watch &amp; chat</a>
ddiff --git a/test/home-featured-note.test.js b/test/home-featured-note.test.js
nnew file mode 100644
iindex 00000000..d371f147
---- /dev/null
++++ b/test/home-featured-note.test.js
@@@ -0,0 +1,19 @@
++'use strict';
++// The home page's Featured live card shows the AI note alone in "Right now": the raw speech-to-text after " — heard:"
++// (up to 500 characters, often another language) is never shown (owner, 2026-10-17: a Greek stream's transcript
++// filled the card).
++//
++// node test/home-featured-note.test.js
++const assert = require('assert');
++const fs = require('fs');
++const path = require('path');
++
++const src = fs.readFileSync(path.join(__dirname, '..', 'public', 'js', 'home-featured.js'), 'utf8');
++const m = /const now = m && m\.description \? String\(m\.description\)\.replace\((\/[^\n]*?\/), ''\)\.trim\(\) : '';/.exec(src);
++assert.ok(m, 'the card cuts the heard clause before showing the note');
++// eslint-disable-next-line no-eval
++const re = eval(m[1]);
++assert.strictEqual('The main screen is black. — heard: "Δεν θα πούμε άλλο."'.replace(re, '').trim(), 'The main screen is black.');
++assert.strictEqual('A quiet desk, chat is busy.'.replace(re, '').trim(), 'A quiet desk, chat is busy.', 'a note without one stays whole');
++assert.ok(/\$\{escText\(now\)\}/.test(src) && !/\$\{escText\(m\.description\)\}/.test(src), 'what is shown is the cut note');
++console.log('home featured note: all checks passed');