openvibers/openvibe.live Commits
A declined paste falls back to the signals; only a clip may come back empty (#588)
Changes
@@@ -264,11 +264,13 @@ async function _findBestMoment(vod, { flavor = 'paste', avoid = [] } = {}) {};try {const j = await aiService.structured('live.moments.pick', input, { target: { service: 'live', type: 'vod', id: String(vod.vod_id) }, meter: { kind: 'moment_pick', role: 'legacy' } });-- // The AI may say nothing here is worth it (C08/C09): that is an answer, not a failure, so no weaker signal-- // is tried in its place.++ // The AI may say nothing here is worth a clip (C08/C09): that is an answer, not a failure, so no weaker++ // signal is tried in its place. A paste needs only one good frame: if the AI declines one anyway, the++ // objective signals below pick it (11-03: twelve declined pastes left the home with none).if (j && (j.abstain === true || (Object.prototype.hasOwnProperty.call(j, 't') && j.t === null))) {-- console.log(`[AI-Moments] VOD ${vod.vod_id}: the AI found nothing worth a ${flavor === 'clip' ? 'clip' : 'paste'}${j.why ? ` (${_cleanText(j.why, 120)})` : ''}`);-- return null;++ console.log(`[AI-Moments] VOD ${vod.vod_id}: the AI found nothing worth a ${flavor === 'clip' ? 'clip' : 'paste'}${j.why ? ` (${_cleanText(j.why, 120)})` : ''}${flavor === 'clip' ? '' : ': the signals pick the frame'}`);++ if (flavor === 'clip') return null;++ throw new Error('declined paste');}let t = j ? Number(j.t) : NaN;if (!isNaN(t)) {@@@ -110,6 +110,11 @@ console.warn = () => {};assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 'the AI said nothing is worth it');aiService.structured = async () => ({ t: null });assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 't: null is an abstention too');++ // A paste is never left empty by a declined pick: the signals choose its frame (11-03).++ aiService.structured = async () => ({ abstain: true, why: 'nothing stands out' });++ const pasteBack = await moments.findBestMoment(v, { flavor: 'paste' });++ assert.ok(pasteBack && Number.isFinite(pasteBack.offset), 'a declined paste falls back to the signals');++ assert.notStrictEqual(pasteBack.evidence.picked_by, 'ai');let asked = null;aiService.structured = async (_name, input) => { asked = input; return { t: 1500, title: 'Lost it', desc: 'The streamer laughs at a clip on the second monitor' }; };const picked = await moments.findBestMoment(v, { flavor: 'clip' });
@@ -264,11 +264,13 @@ async function _findBestMoment(vod, { flavor = 'paste', avoid = [] } = {}) {
@@ -264,11 +264,13 @@ async function _findBestMoment(vod, { flavor = 'paste', avoid = [] } = {}) {
};
};
try {
try {
const j = await aiService.structured('live.moments.pick', input, { target: { service: 'live', type: 'vod', id: String(vod.vod_id) }, meter: { kind: 'moment_pick', role: 'legacy' } });
const j = await aiService.structured('live.moments.pick', input, { target: { service: 'live', type: 'vod', id: String(vod.vod_id) }, meter: { kind: 'moment_pick', role: 'legacy' } });
- // The AI may say nothing here is worth it (C08/C09): that is an answer, not a failure, so no weaker signal
- // is tried in its place.
+ // The AI may say nothing here is worth a clip (C08/C09): that is an answer, not a failure, so no weaker
+ // signal is tried in its place. A paste needs only one good frame: if the AI declines one anyway, the
+ // objective signals below pick it (11-03: twelve declined pastes left the home with none).
if (j && (j.abstain === true || (Object.prototype.hasOwnProperty.call(j, 't') && j.t === null))) {
if (j && (j.abstain === true || (Object.prototype.hasOwnProperty.call(j, 't') && j.t === null))) {
- console.log(`[AI-Moments] VOD ${vod.vod_id}: the AI found nothing worth a ${flavor === 'clip' ? 'clip' : 'paste'}${j.why ? ` (${_cleanText(j.why, 120)})` : ''}`);
- return null;
+ console.log(`[AI-Moments] VOD ${vod.vod_id}: the AI found nothing worth a ${flavor === 'clip' ? 'clip' : 'paste'}${j.why ? ` (${_cleanText(j.why, 120)})` : ''}${flavor === 'clip' ? '' : ': the signals pick the frame'}`);
+ if (flavor === 'clip') return null;
+ throw new Error('declined paste');
}
}
let t = j ? Number(j.t) : NaN;
let t = j ? Number(j.t) : NaN;
if (!isNaN(t)) {
if (!isNaN(t)) {
@@ -110,6 +110,11 @@ console.warn = () => {};
@@ -110,6 +110,11 @@ console.warn = () => {};
assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 'the AI said nothing is worth it');
assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 'the AI said nothing is worth it');
aiService.structured = async () => ({ t: null });
aiService.structured = async () => ({ t: null });
assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 't: null is an abstention too');
assert.strictEqual(await moments.findBestMoment(v, { flavor: 'clip' }), null, 't: null is an abstention too');
+ // A paste is never left empty by a declined pick: the signals choose its frame (11-03).
+ aiService.structured = async () => ({ abstain: true, why: 'nothing stands out' });
+ const pasteBack = await moments.findBestMoment(v, { flavor: 'paste' });
+ assert.ok(pasteBack && Number.isFinite(pasteBack.offset), 'a declined paste falls back to the signals');
+ assert.notStrictEqual(pasteBack.evidence.picked_by, 'ai');
let asked = null;
let asked = null;
aiService.structured = async (_name, input) => { asked = input; return { t: 1500, title: 'Lost it', desc: 'The streamer laughs at a clip on the second monitor' }; };
aiService.structured = async (_name, input) => { asked = input; return { t: 1500, title: 'Lost it', desc: 'The streamer laughs at a clip on the second monitor' }; };
const picked = await moments.findBestMoment(v, { flavor: 'clip' });
const picked = await moments.findBestMoment(v, { flavor: 'clip' });