openvibers/openvibe.chat Commits

The timeline counts people only: Live's AI viewers make no spike (item 151, C07) (#338)

OP OpenVibers committed 11 days ago · 01f4819111 · 2 files, +14 −1

Live's clip picker reads these buckets to find chat spikes, and its AI viewers chat (source_platform 'ai'), so the
AI's chatter could make the spike the AI then clips. The timeline leaves those messages out.

Changes

ddiff --git a/server/chat/internal-reads.js b/server/chat/internal-reads.js
iindex b9196bd..536fe92 100644
---- a/server/chat/internal-reads.js
++++ b/server/chat/internal-reads.js
@@@ -210,6 +210,8 @@ async function dmBlockState(req) {
}
// ── N3: timeline ──
++// People's chat only: Live's AI viewers (source_platform 'ai') are left out, so their chatter never makes a "spike" the
++// AI then clips (item 151, C07: AI clips are excluded from human signals).
async function timeline(req) {
const q = query(req, { channel_user_id: 'id', stream_id: 'id', since: 'ms', until: 'ms', bucket_ms: 'id' });
if ((q.channel_user_id == null) === (q.stream_id == null)) bad('Give channel_user_id or stream_id');
@@@ -223,7 +225,8 @@ async function timeline(req) {
`SELECT n, COUNT(*) AS count, MAX(id) AS max_id FROM (
SELECT id, floor((extract(epoch FROM ov_ts(timestamp)) * 1000 - ?) / ?)::bigint AS n
FROM chat_messages
-- WHERE ${col} = ? AND is_deleted = 0 AND timestamp >= ? AND timestamp < ?) m
++ WHERE ${col} = ? AND is_deleted = 0 AND timestamp >= ? AND timestamp < ?
++ AND COALESCE(source_platform, '') <> 'ai') m
WHERE n IS NOT NULL AND n >= 0 GROUP BY n ORDER BY n`,
[q.since, q.bucket_ms, q[col], sqlTime(q.since), sqlTime(until)]);
return {
ddiff --git a/test/chat-internal-reads.test.js b/test/chat-internal-reads.test.js
iindex 413b732..25a87af 100644
---- a/test/chat-internal-reads.test.js
++++ b/test/chat-internal-reads.test.js
@@@ -204,6 +204,16 @@ t('N3 timeline: buckets from since, oldest first, empty ones left out', async ()
check('chat.timeline-result@1', await tl(q, 400));
});
++t('N3 timeline: Live\'s AI viewers (source_platform ai) are not chat activity', async () => {
++ const tl = (q) => read(`/timeline?${q}`, 'chat.analysis.read', 'chat.timeline-result@1');
++ const before = await tl(`stream_id=${streamId}&since=${T}&until=${T + 600e3}&bucket_ms=60000`);
++ await line('ai1', { ms: T + 70e3, username: 'Sora (AI)', platform: 'ai' });
++ await line('ai2', { ms: T + 75e3, username: 'Kai (AI)', platform: 'ai' });
++ const after = await tl(`stream_id=${streamId}&since=${T}&until=${T + 600e3}&bucket_ms=60000`);
++ assert.deepStrictEqual(after.buckets, before.buckets, 'the AI\'s chatter makes no spike');
++ await h.db.run('DELETE FROM chat_messages WHERE id = ANY(?::bigint[])', [[ids.ai1, ids.ai2]]);
++});
++
t('N1c first chat: whether this identity has ever chatted in the channel', async () => {
await h.db.run(`INSERT INTO stream_first_chats (chatter_key, channel_user_id) VALUES ('user:123', ?), ('anon:anonX', ?), ('ext:[Twitch] foo', ?)`,
[streamer.id, streamer.id, streamer.id]);