openvibers/openvibe.live Commits

Live's AI viewers are not evidence that a moment landed (item 151, C07) (#579)

OP OpenVibers committed 10 days ago · c8965e6e37 · 2 files, +30 −2

The clip picker's 'a crowd reacted' (recentChatters, three people for a public clip) and the chat lines sent to the
AI's confirm step counted Live's own AI viewers (source_platform 'ai'). Both now leave them out; relayed people
(Twitch and the rest) still count. Chat #338 does the same for the spike buckets.

Changes

ddiff --git a/server/chat/chat-reads.js b/server/chat/chat-reads.js
iindex fb798518..f332d11e 100644
---- a/server/chat/chat-reads.js
++++ b/server/chat/chat-reads.js
@@@ -472,8 +472,9 @@ function recentChatText(streamId, sinceSec = 120, limit = 40) {
const out = await client.readMessages({ stream_id: id, limit });
if (!out || !Array.isArray(out.messages)) throw unavailable('recent messages');
const floor = Date.now() - Math.max(1, sinceSec) * 1000;
++ // People's chat only: Live's own AI viewers (source_platform 'ai') are not evidence that a moment landed.
return out.messages
-- .filter((m) => m.message && Date.parse(String(m.timestamp).replace(' ', 'T') + 'Z') >= floor)
++ .filter((m) => m.message && m.source_platform !== 'ai' && Date.parse(String(m.timestamp).replace(' ', 'T') + 'Z') >= floor)
.map((m) => String(m.message))
.reverse();
}, () => []);
@@@ -489,8 +490,9 @@ function recentChatters(streamId, sinceSec = 30, limit = 200) {
const out = await client.readMessages({ stream_id: id, limit });
if (!out || !Array.isArray(out.messages)) throw unavailable('recent messages');
const floor = Date.now() - Math.max(1, sinceSec) * 1000;
++ // Live's AI viewers (source_platform 'ai') are not people: they never make "a crowd reacted" (item 151, C07).
const people = new Set(out.messages
-- .filter((m) => m.message && Date.parse(String(m.timestamp).replace(' ', 'T') + 'Z') >= floor)
++ .filter((m) => m.message && m.source_platform !== 'ai' && Date.parse(String(m.timestamp).replace(' ', 'T') + 'Z') >= floor)
.map((m) => (m.user_id != null ? `u${m.user_id}` : m.username ? `n${String(m.username).toLowerCase()}` : null))
.filter(Boolean));
return people.size;
ddiff --git a/test/ai-viewers-not-signal.test.js b/test/ai-viewers-not-signal.test.js
nnew file mode 100644
iindex 00000000..5850d551
---- /dev/null
++++ b/test/ai-viewers-not-signal.test.js
@@@ -0,0 +1,26 @@
++'use strict';
++// Live's own AI viewers are not evidence that a moment landed (item 151, C07): they never count as "a crowd reacted"
++// (recentChatters) and their lines never reach the AI's clip confirmation (recentChatText). Chat's timeline leaves them
++// out of the spike counts on its side (Chat #338).
++const assert = require('assert');
++console.warn = () => {};
++
++const client = require('../server/chat/chat-client');
++const now = () => new Date().toISOString().replace('T', ' ').slice(0, 19);
++client.available = () => true;
++client.readMessages = async () => ({ messages: [
++ { user_id: 1, username: 'ann', message: 'NO WAY', source_platform: null, timestamp: now() },
++ { user_id: 2, username: 'bob', message: 'clip it', source_platform: null, timestamp: now() },
++ { user_id: null, username: 'Sora (AI)', message: 'what a play!', source_platform: 'ai', timestamp: now() },
++ { user_id: null, username: 'Kai (AI)', message: 'insane', source_platform: 'ai', timestamp: now() },
++ { user_id: null, username: 'twitchfan', message: 'LUL', source_platform: 'twitch', timestamp: now() },
++] });
++const chatReads = require('../server/chat/chat-reads');
++
++(async () => {
++ assert.strictEqual(await chatReads.recentChatters(9001, 60), 3, 'ann, bob and the Twitch viewer; never the AI viewers');
++ const text = await chatReads.recentChatText(9002, 120);
++ assert.ok(!text.includes('what a play!') && !text.includes('insane'), 'the AI viewers\' lines never reach the confirm step');
++ assert.ok(text.includes('NO WAY') && text.includes('LUL'), 'people, relayed ones included, do');
++ console.log('ai viewers are not a signal: all checks passed');
++})().catch((e) => { console.error(e); process.exit(1); });