openvibers/openvibe.live Commits

AI moment and clip titles also pass the shared looks rule (db.hasLooks): "A Naked Man Lying On Their Back" reached Live's home (#339)

OP OpenVibers committed 20 days ago · 4b0f808876 · 2 files, +10 −3

Changes

ddiff --git a/server/ai/ai-moments-job.js b/server/ai/ai-moments-job.js
iindex 1debd8b5..395336bc 100644
---- a/server/ai/ai-moments-job.js
++++ b/server/ai/ai-moments-job.js
@@@ -58,20 +58,23 @@ function _deJson(desc) {
// dangling word ("…Speaking To") and never about how someone looks (owner's rule for public AI text: "A Man With A
// Beard Is Speaking To" and "A Person In A Bright Yellow High-Visibility Jacket" titled public clips, 2026-10-17).
// Otherwise the stream's own title and the moment's time ("Fortnite! at 41:20").
--const LOOKS_WORDS = /\b(wearing|wears|dressed|beard(ed)?|mustache|glasses|sunglasses|jacket|hoodie|sweater|vest|shirt|shirtless|tank top|t-shirt|beanie|cap|hat|helmet|headset|headphones|hair|bald|blonde|expression|face|smil(e|ing)|clothing|outfit|tattoo(ed)?|young|old(er)?|teen(age)?|boy|girl|kid|child|blurred|body|skin)\b/i;
++const LOOKS_WORDS = /\b(wearing|wears|dressed|beard(ed)?|mustache|glasses|sunglasses|jacket|hoodie|sweater|vest|shirt|shirtless|topless|naked|nude|tank top|t-shirt|beanie|cap|hat|helmet|headset|headphones|hair|bald|blonde|expression|face|smil(e|ing)|clothing|outfit|tattoo(ed)?|young|old(er)?|teen(age)?|boy|girl|kid|child|blurred|body|skin)\b/i;
++// A title also fails the shared rule (openvibe-sdk/no-looks, db.hasLooks): this list alone let "A Naked Man Lying On
++// Their Back With Legs" through to Live's home (clip 483, 2026-10-23): it named neither "man" nor "naked".
++const namesLooks = (s) => LOOKS_WORDS.test(s) || db.hasLooks(s);
const DANGLING = /\s+(to|in|with|a|an|of|and|the|on|at|is|are|was|from|for|by|near|while|as|or|into|onto|its|his|her|their)$/i;
function _captionTitle(desc) {
let s = _cleanText(desc).split(/[.!?;:]|,\s(?=(?:with|and|as|while|near|showing|likely)\b)/i)[0].trim();
s = s.split(' ').filter(Boolean).slice(0, 9).join(' ').replace(/[,\s]+$/, '');
while (DANGLING.test(s)) s = s.replace(DANGLING, '');
-- if (s.split(' ').length < 3 || LOOKS_WORDS.test(s)) return null;
++ if (s.split(' ').length < 3 || namesLooks(s)) return null;
return s.replace(/\b\w/g, (ch) => ch.toUpperCase()).slice(0, 70);
}
// An AI-written title is used unless it is about looks ("Red Beanie Moment", "Glasses Adjustment Tension"); then the
// fallback above.
function _publicTitle(title, vod, offset, desc) {
const t = _cleanTitle(title);
-- return t && !LOOKS_WORDS.test(t) ? t : _fallbackTitle(vod, offset, desc);
++ return t && !namesLooks(t) ? t : _fallbackTitle(vod, offset, desc);
}
function _fallbackTitle(vod, offset, desc) {
const fromCaption = desc ? _captionTitle(desc) : null;
ddiff --git a/test/moment-fallback-title.test.js b/test/moment-fallback-title.test.js
iindex 62ae9519..55ec44f5 100644
---- a/test/moment-fallback-title.test.js
++++ b/test/moment-fallback-title.test.js
@@@ -28,6 +28,10 @@ assert.ok(fallbackTitle({ title: 'x'.repeat(200) }, 59).length <= 80, 'at most 8
const { publicTitle } = require('../server/ai/ai-moments-job');
assert.strictEqual(publicTitle('Boss Fight Comeback', vod, 60, ''), 'Boss Fight Comeback');
assert.strictEqual(publicTitle('Red Beanie Moment', vod, 2480, 'A man wearing a red beanie looks up.'), 'Fortnite! at 41:20');
++// The shared rule too (openvibe-sdk/no-looks via db.hasLooks): clip 483 was titled this on Live's home (2026-10-23).
++assert.strictEqual(publicTitle('A Naked Man Lying On Their Back With Legs', vod, 2480, ''), 'Fortnite! at 41:20');
++assert.strictEqual(publicTitle('Woman Laughs At Chat', vod, 2480, ''), 'Fortnite! at 41:20', 'a guessed gender is a look');
++assert.strictEqual(captionTitle('A naked man lies on a bed near a window.'), null);
assert.strictEqual(publicTitle('Headphones Hit a Revelation', { title: 'A little couch surfing before the store.' }, 61, ''), 'A little couch surfing before the store at 1:01');
assert.strictEqual(publicTitle('', { title: '', username: 'goosely' }, 75, ''), "goosely's stream at 1:15");
process.stdout.write('moment fallback title: all checks passed\n');