openvibers/openvibe.live Commits

Moments: opening words alone are not the same scene (#602)

OP OpenVibers committed 10 days ago · 6bec1c5d4d · 2 files, +10 −2

The registry's five-word signature is a description's first words, stopwords and all, so "the streamer is in a" and
"the streamer sits in a" matched unrelated VODs and skipped them (two in the 11-03 10:44 home run). With both full
scenes known, the signature now counts only when it carries three content words, and isSameScene (content words,
0.85) decides the rest; a legacy row or a candidate with no full scene still matches on the signature alone.

Changes

ddiff --git a/server/ai/moment-registry.js b/server/ai/moment-registry.js
iindex 66087110..09f710c8 100644
---- a/server/ai/moment-registry.js
++++ b/server/ai/moment-registry.js
@@@ -113,7 +113,11 @@ async function usedReason({ vod_id = null, stream_id = null, offset = null, sig:
ORDER BY created_at DESC LIMIT ${SCAN}`, [iso(now - SIG_TTL_MS)]);
for (const e of rows) {
const eEmb = Array.isArray(e.embedding) ? e.embedding : null;
-- const shortMatch = scene && e.sig && e.sig === scene;
++ // The five-word signature is the opening words, stopwords and all, so "the streamer is in a …" matched nearly
++ // every scene note and skipped unrelated VODs (11-03: two in one run). With both full scenes known it counts
++ // only when it carries three content words (a Japanese opening does; "the streamer sits in a" does not), and
++ // isSameScene decides the rest; a row or candidate with no full scene still matches on it alone.
++ const shortMatch = scene && e.sig && e.sig === scene && (!(full && e.scene) || dedupe.contentTokens(scene).length >= 3);
const sceneMatch = full && e.scene && dedupe.isSameScene(e.scene, full);
// Frame embeddings (when both sides have them) are independent evidence: the same footage
// is a repeat even if it was re-described or re-uploaded.
ddiff --git a/test/moment-registry.test.js b/test/moment-registry.test.js
iindex 6d62a45d..fafce7cf 100644
---- a/test/moment-registry.test.js
++++ b/test/moment-registry.test.js
@@@ -20,7 +20,11 @@ console.log('✅ legacy logs imported');
await reg.record({ kind: 'paste', vod_id: 42, stream_id: 7, offset: 1000, title: 'Depth Estimation tease', desc: 'The video appears to be a live streaming session with a chat overlay' });
assert.strictEqual(await reg.usedReason({ vod_id: 42, offset: 1050 }), 'paste already made at 1000s of this VOD', 'same VOD within 2 min is blocked');
--assert.ok(/same scene as a recent paste/.test(await reg.usedReason({ vod_id: 43, offset: 5, desc: 'the video appears to be a live streaming session with music' })), 'same opening words = same scene, even on another VOD');
++// Opening words alone are not a scene (11-03: "the streamer is in a" skipped two unrelated VODs); content words are.
++await reg.record({ kind: 'paste', vod_id: 44, stream_id: 8, offset: 60, title: 'Couch', desc: 'The streamer sits in a red gaming chair, laughing at chat' });
++assert.strictEqual(await reg.usedReason({ vod_id: 45, offset: 60, desc: 'The streamer sits in a dim kitchen cooking pasta' }), null, '"the streamer sits in a" is not a scene');
++assert.strictEqual(await reg.usedReason({ vod_id: 43, offset: 5, desc: 'the video appears to be a live streaming session with music' }), null, 'same opening words, different content: a new scene');
++assert.ok(/same scene as a recent paste/.test(await reg.usedReason({ vod_id: 43, offset: 5, desc: 'The video appears to be a live-streaming session with a chat overlay.' })), 'the same scene, reworded, on another VOD is still a repeat');
assert.strictEqual(await reg.usedReason({ vod_id: 42, offset: 1300, desc: 'A robot arm knocks over the coffee' }), null, '≥ 2 min away with a different scene is fine');
assert.ok(await reg.isUsed({ stream_id: 7, offset: 1010 }), 'live streams are matched by stream id too');
await reg.record({ kind: 'clip', vod_id: 42, stream_id: 7, offset: 1300, title: 'Robot arm vs coffee' });