openvibers/openvibe.ai Commits
live.moments.pick offers a way out to clips only (#277)
Changes
@@@ -73,6 +73,7 @@ const MOMENT_FLAVOR = {paste: 'This moment becomes a SCREENSHOT paste: pick something visually striking in a single frame — a face or reaction, a visual gag, something odd on screen, a scene change. What was said matters less than what is SEEN.',clip: 'This moment becomes a 25-SECOND VIDEO CLIP: pick a beat that plays out over time — a line that lands, a reaction, a sound, chat exploding, something HAPPENING — not a static pretty frame.',};++const ABSTAIN_CLIP = 'If NOTHING here is clearly worth a clip (only routine talk with no reaction, a static screen, nothing happening, or only moments already used), say so instead of forcing a pick: a missed clip costs less than a bad one. Then answer {"t": null, "title": "", "desc": "", "why": "<a few words>"}. Otherwise: ';const oneLine = (t, max) => String(t || '').replace(/\s+/g, ' ').trim().slice(0, max);// Text shown to the public as a description: one paragraph of prose. A model that answers with a list, headings or// bold labels ("- Streamer handle: x (@x).") has its markup and labels dropped, line by line, and headings left out,@@@ -201,6 +202,9 @@ const PREPARE = {clipped: times(input.clipped, 12),spikes: times(input.spikes, 6),flavor_hint: MOMENT_FLAVOR[input.flavor] || MOMENT_FLAVOR.paste,++ // Only a clip may come back empty (C09): a paste needs one good frame, and offering it the same way out++ // made the model decline all twelve VODs of the 11-03 run, leaving the home with no new pastes.++ abstain_hint: input.flavor === 'clip' ? ABSTAIN_CLIP : '',avoid: avoid.map(mmss).join(', '),},};@@@ -236,7 +236,7 @@ const templates = [},},system_prompt: '',-- user_prompt: 'Below is a single livestream VOD titled "{{title}}", described by its on-screen TIMELINE (visual scene notes) and its AUDIO TRANSCRIPT, each line timestamped [m:ss]. Titles and descriptions are about what happens.\n\nTIMELINE:\n{{timeline}}\n\nTRANSCRIPT:\n{{transcript}}\n\nSOUNDS HEARD (non-speech audio events):\n{{sounds}}\n\nViewers CLIPPED these timestamps (very strong "this was a highlight" signal): {{clipped}}\nChat activity SPIKED around: {{spikes}}\n\n{{flavor_hint}}\n{{#avoid}}ALREADY USED (a paste or clip exists there) — do NOT pick these or anything within 2 minutes of them: {{avoid}}. Find a DIFFERENT moment.{{/avoid}}\n\nFind the SINGLE most interesting/funny/dramatic/surprising/striking moment in this VOD with something clearly VISIBLE happening. Prefer moments backed by the clip/chat signals when they line up with something notable. NEVER pick a black/dark/loading/blank screen, an intro/BRB card, or a moment with no visible content or activity. If NOTHING here is clearly worth it — only routine talk with no reaction, a static screen, nothing happening, or only moments already used — say so instead of forcing a pick: a missed moment costs less than a bad one. Then answer {"t": null, "title": "", "desc": "", "why": "<a few words>"}. Otherwise return STRICT JSON only, nothing else: {"t": <seconds into the vod>, "title": "<specific punchy 3-8 word title, not the stream name, funny, never generic>", "desc": "<one vivid sentence describing the moment>"}',++ user_prompt: 'Below is a single livestream VOD titled "{{title}}", described by its on-screen TIMELINE (visual scene notes) and its AUDIO TRANSCRIPT, each line timestamped [m:ss]. Titles and descriptions are about what happens.\n\nTIMELINE:\n{{timeline}}\n\nTRANSCRIPT:\n{{transcript}}\n\nSOUNDS HEARD (non-speech audio events):\n{{sounds}}\n\nViewers CLIPPED these timestamps (very strong "this was a highlight" signal): {{clipped}}\nChat activity SPIKED around: {{spikes}}\n\n{{flavor_hint}}\n{{#avoid}}ALREADY USED (a paste or clip exists there) — do NOT pick these or anything within 2 minutes of them: {{avoid}}. Find a DIFFERENT moment.{{/avoid}}\n\nFind the SINGLE most interesting/funny/dramatic/surprising/striking moment in this VOD with something clearly VISIBLE happening. Prefer moments backed by the clip/chat signals when they line up with something notable. NEVER pick a black/dark/loading/blank screen, an intro/BRB card, or a moment with no visible content or activity. {{abstain_hint}}Return STRICT JSON only, nothing else: {"t": <seconds into the vod>, "title": "<specific punchy 3-8 word title, not the stream name, funny, never generic>", "desc": "<one vivid sentence describing the moment>"}',default_route: 'live.legacy', owner: 'live', metadata: { json_name: 'moment_pick' },},{@@@ -30,6 +30,15 @@ t.test('the prompt renders as Live rendered it', () => {assert.deepStrictEqual(PREPARE['live.moments.pick']({ title: 'x' }), { output: null }, 'nothing to work from: no run');});++t.test('only a clip is offered the way out (C09): a paste always names its frame', () => {++ const clip = render(tpl.user_prompt, PREPARE['live.moments.pick']({ title: 'x', flavor: 'clip', timeline: [{ t: 1, text: 'a' }] }).vars);++ const paste = render(tpl.user_prompt, PREPARE['live.moments.pick']({ title: 'x', flavor: 'paste', timeline: [{ t: 1, text: 'a' }] }).vars);++ assert.match(clip, /If NOTHING here is clearly worth a clip[\s\S]*"t": null[\s\S]*Otherwise: Return STRICT JSON only/);++ assert.ok(!/"t": null/.test(paste) && !/NOTHING here/.test(paste), 'no way out for a paste');++ assert.match(paste, /Return STRICT JSON only, nothing else: \{"t": <seconds into the vod>/);++ assert.ok(!/\{\{|\$\{/.test(clip + paste), 'nothing left unrendered');++});++t.test('the answer is read like Live read it', () => {const post = POSTPROCESS['live.moments.pick'];assert.deepStrictEqual(post({ text: 'Sure! {"t": 95.7, "title": "\\"It Compiles\\"", "desc": "He jumps."}' }), { t: 95, title: 'It Compiles', desc: 'He jumps.' });
@@ -73,6 +73,7 @@ const MOMENT_FLAVOR = {
@@ -73,6 +73,7 @@ const MOMENT_FLAVOR = {
paste: 'This moment becomes a SCREENSHOT paste: pick something visually striking in a single frame — a face or reaction, a visual gag, something odd on screen, a scene change. What was said matters less than what is SEEN.',
paste: 'This moment becomes a SCREENSHOT paste: pick something visually striking in a single frame — a face or reaction, a visual gag, something odd on screen, a scene change. What was said matters less than what is SEEN.',
clip: 'This moment becomes a 25-SECOND VIDEO CLIP: pick a beat that plays out over time — a line that lands, a reaction, a sound, chat exploding, something HAPPENING — not a static pretty frame.',
clip: 'This moment becomes a 25-SECOND VIDEO CLIP: pick a beat that plays out over time — a line that lands, a reaction, a sound, chat exploding, something HAPPENING — not a static pretty frame.',
};
};
+const ABSTAIN_CLIP = 'If NOTHING here is clearly worth a clip (only routine talk with no reaction, a static screen, nothing happening, or only moments already used), say so instead of forcing a pick: a missed clip costs less than a bad one. Then answer {"t": null, "title": "", "desc": "", "why": "<a few words>"}. Otherwise: ';
const oneLine = (t, max) => String(t || '').replace(/\s+/g, ' ').trim().slice(0, max);
const oneLine = (t, max) => String(t || '').replace(/\s+/g, ' ').trim().slice(0, max);
// Text shown to the public as a description: one paragraph of prose. A model that answers with a list, headings or
// Text shown to the public as a description: one paragraph of prose. A model that answers with a list, headings or
// bold labels ("- Streamer handle: x (@x).") has its markup and labels dropped, line by line, and headings left out,
// bold labels ("- Streamer handle: x (@x).") has its markup and labels dropped, line by line, and headings left out,
@@ -201,6 +202,9 @@ const PREPARE = {
@@ -201,6 +202,9 @@ const PREPARE = {
clipped: times(input.clipped, 12),
clipped: times(input.clipped, 12),
spikes: times(input.spikes, 6),
spikes: times(input.spikes, 6),
flavor_hint: MOMENT_FLAVOR[input.flavor] || MOMENT_FLAVOR.paste,
flavor_hint: MOMENT_FLAVOR[input.flavor] || MOMENT_FLAVOR.paste,
+ // Only a clip may come back empty (C09): a paste needs one good frame, and offering it the same way out
+ // made the model decline all twelve VODs of the 11-03 run, leaving the home with no new pastes.
+ abstain_hint: input.flavor === 'clip' ? ABSTAIN_CLIP : '',
avoid: avoid.map(mmss).join(', '),
avoid: avoid.map(mmss).join(', '),
},
},
};
};
@@ -236,7 +236,7 @@ const templates = [
@@ -236,7 +236,7 @@ const templates = [
},
},
},
},
system_prompt: '',
system_prompt: '',
- user_prompt: 'Below is a single livestream VOD titled "{{title}}", described by its on-screen TIMELINE (visual scene notes) and its AUDIO TRANSCRIPT, each line timestamped [m:ss]. Titles and descriptions are about what happens.\n\nTIMELINE:\n{{timeline}}\n\nTRANSCRIPT:\n{{transcript}}\n\nSOUNDS HEARD (non-speech audio events):\n{{sounds}}\n\nViewers CLIPPED these timestamps (very strong "this was a highlight" signal): {{clipped}}\nChat activity SPIKED around: {{spikes}}\n\n{{flavor_hint}}\n{{#avoid}}ALREADY USED (a paste or clip exists there) — do NOT pick these or anything within 2 minutes of them: {{avoid}}. Find a DIFFERENT moment.{{/avoid}}\n\nFind the SINGLE most interesting/funny/dramatic/surprising/striking moment in this VOD with something clearly VISIBLE happening. Prefer moments backed by the clip/chat signals when they line up with something notable. NEVER pick a black/dark/loading/blank screen, an intro/BRB card, or a moment with no visible content or activity. If NOTHING here is clearly worth it — only routine talk with no reaction, a static screen, nothing happening, or only moments already used — say so instead of forcing a pick: a missed moment costs less than a bad one. Then answer {"t": null, "title": "", "desc": "", "why": "<a few words>"}. Otherwise return STRICT JSON only, nothing else: {"t": <seconds into the vod>, "title": "<specific punchy 3-8 word title, not the stream name, funny, never generic>", "desc": "<one vivid sentence describing the moment>"}',
+ user_prompt: 'Below is a single livestream VOD titled "{{title}}", described by its on-screen TIMELINE (visual scene notes) and its AUDIO TRANSCRIPT, each line timestamped [m:ss]. Titles and descriptions are about what happens.\n\nTIMELINE:\n{{timeline}}\n\nTRANSCRIPT:\n{{transcript}}\n\nSOUNDS HEARD (non-speech audio events):\n{{sounds}}\n\nViewers CLIPPED these timestamps (very strong "this was a highlight" signal): {{clipped}}\nChat activity SPIKED around: {{spikes}}\n\n{{flavor_hint}}\n{{#avoid}}ALREADY USED (a paste or clip exists there) — do NOT pick these or anything within 2 minutes of them: {{avoid}}. Find a DIFFERENT moment.{{/avoid}}\n\nFind the SINGLE most interesting/funny/dramatic/surprising/striking moment in this VOD with something clearly VISIBLE happening. Prefer moments backed by the clip/chat signals when they line up with something notable. NEVER pick a black/dark/loading/blank screen, an intro/BRB card, or a moment with no visible content or activity. {{abstain_hint}}Return STRICT JSON only, nothing else: {"t": <seconds into the vod>, "title": "<specific punchy 3-8 word title, not the stream name, funny, never generic>", "desc": "<one vivid sentence describing the moment>"}',
default_route: 'live.legacy', owner: 'live', metadata: { json_name: 'moment_pick' },
default_route: 'live.legacy', owner: 'live', metadata: { json_name: 'moment_pick' },
},
},
{
{
@@ -30,6 +30,15 @@ t.test('the prompt renders as Live rendered it', () => {
@@ -30,6 +30,15 @@ t.test('the prompt renders as Live rendered it', () => {
assert.deepStrictEqual(PREPARE['live.moments.pick']({ title: 'x' }), { output: null }, 'nothing to work from: no run');
assert.deepStrictEqual(PREPARE['live.moments.pick']({ title: 'x' }), { output: null }, 'nothing to work from: no run');
});
});
+t.test('only a clip is offered the way out (C09): a paste always names its frame', () => {
+ const clip = render(tpl.user_prompt, PREPARE['live.moments.pick']({ title: 'x', flavor: 'clip', timeline: [{ t: 1, text: 'a' }] }).vars);
+ const paste = render(tpl.user_prompt, PREPARE['live.moments.pick']({ title: 'x', flavor: 'paste', timeline: [{ t: 1, text: 'a' }] }).vars);
+ assert.match(clip, /If NOTHING here is clearly worth a clip[\s\S]*"t": null[\s\S]*Otherwise: Return STRICT JSON only/);
+ assert.ok(!/"t": null/.test(paste) && !/NOTHING here/.test(paste), 'no way out for a paste');
+ assert.match(paste, /Return STRICT JSON only, nothing else: \{"t": <seconds into the vod>/);
+ assert.ok(!/\{\{|\$\{/.test(clip + paste), 'nothing left unrendered');
+});
+
t.test('the answer is read like Live read it', () => {
t.test('the answer is read like Live read it', () => {
const post = POSTPROCESS['live.moments.pick'];
const post = POSTPROCESS['live.moments.pick'];
assert.deepStrictEqual(post({ text: 'Sure! {"t": 95.7, "title": "\\"It Compiles\\"", "desc": "He jumps."}' }), { t: 95, title: 'It Compiles', desc: 'He jumps.' });
assert.deepStrictEqual(post({ text: 'Sure! {"t": 95.7, "title": "\\"It Compiles\\"", "desc": "He jumps."}' }), { t: 95, title: 'It Compiles', desc: 'He jumps.' });