openvibers/openvibe.live Commits

The Rundown: a stretch is at most 380 lines (the workflow takes 400; iZoR_One's short Greek lines were refused with 422), and a stretch the AI refuses three times is skipped instead of retried every tick (#253)

OP OpenVibers committed 25 days ago · 8dc86db3d1 · 2 files, +34 −3

Changes

ddiff --git a/server/rundown/desk.js b/server/rundown/desk.js
iindex 00d1d683..43eb8bf9 100644
---- a/server/rundown/desk.js
++++ b/server/rundown/desk.js
@@@ -28,6 +28,8 @@ const READ_SPAN_SEC = 10 * 60;
const MIN_WORDS = 150;
const TAIL_WORDS = 120;
const MAX_WORDS = 2400;
++const MAX_LINES = 380; // the workflow takes at most 400 lines (Greek and other short-line speech hit it first)
++const MAX_FAILS = 3; // a stretch the AI refused this often is skipped, not retried every tick
const BACKFILL_DAYS = 7;
const CALLS_PER_TICK = 4;
const CALLS_PER_HOUR = 40;
@@@ -36,6 +38,7 @@ const ANNOUNCE_PER_HOUR = 3;
const ANNOUNCE_WITHIN_H = 6;
let _calls = [];
++let _fails = new Map(); // stream id → { at: read_to_sec, n }
let _announced = [];
let _busy = false;
let _job = null;
@@@ -142,7 +145,7 @@ async function nextStretch(stream) {
const text = String(r.text || '').replace(/\s+/g, ' ').trim();
const w = words(text);
if (text && !filters.gameLine(text)) {
-- if (n + w > MAX_WORDS && lines.length) break;
++ if ((n + w > MAX_WORDS || lines.length >= MAX_LINES) && lines.length) break;
lines.push({ t: Math.round(Number(r.start_sec) * 10) / 10, text: text.slice(0, 1000), vod_id: r.vod_id });
n += w;
}
@@@ -203,7 +206,15 @@ async function readStretch(stream, user) {
streamer: user.display_name || user.username, title: String(stream.title || '').slice(0, 200), category: String(stream.category || '').slice(0, 80),
topics: await knownTopics(), earlier: earlier.slice(0, 800), lines: stretch.lines.map(({ t, text }) => ({ t, text })),
}, user.id);
-- if (!out || !Array.isArray(out.segments)) return { called: true, failed: true };
++ if (!out || !Array.isArray(out.segments)) {
++ // Refused or failed: try again next tick, but a stretch that keeps failing is skipped rather than retried forever.
++ const f = _fails.get(stream.id);
++ const n = f && f.at === stream.read_to_sec ? f.n + 1 : 1;
++ _fails.set(stream.id, { at: stream.read_to_sec, n });
++ if (n >= MAX_FAILS) { _fails.delete(stream.id); await setProgress(stream.id, stretch.lastSec); console.warn(`[Rundown] stream ${stream.id}: skipped a stretch the AI refused ${n} times`); }
++ return { called: true, failed: true };
++ }
++ _fails.delete(stream.id);
const kept = await keepSegments(stream, stretch, out.segments, user);
await setProgress(stream.id, stretch.lastSec);
return { called: true, kept };
@@@ -315,4 +326,4 @@ function start() {
}
function stop() { if (typeof _job === 'function') _job(); _job = null; }
--module.exports = { start, stop, tick, readStretch, writeEpisode, refreshTopic, keepSegments, topicFor, nextStretch, ready, optedOut, _test: { reset() { _calls = []; _announced = []; _people = { at: 0, entries: [] }; } } };
++module.exports = { start, stop, tick, readStretch, writeEpisode, refreshTopic, keepSegments, topicFor, nextStretch, ready, optedOut, MAX_LINES, _test: { reset() { _calls = []; _announced = []; _fails = new Map(); _people = { at: 0, entries: [] }; } } };
ddiff --git a/test/rundown.test.js b/test/rundown.test.js
iindex e64f1b1f..6dc2ac74 100644
---- a/test/rundown.test.js
++++ b/test/rundown.test.js
@@@ -195,6 +195,26 @@ try {
} finally { server.close(); }
console.log('✅ API: front page, topic, reactions as a signed-out reader; old /arena links');
++// ── Limits: a stretch is at most MAX_LINES lines; a stretch the AI keeps refusing is skipped after three tries ──
++{
++ const greek = await mk('greekline');
++ const sg = await stream(greek, { startedAgoMin: 400, endedAgoMin: 300, title: 'Short lines' });
++ await speak(sg, greek, Array.from({ length: 500 }, (_, i) => `Έλα ${i} τώρα`));
++ const refuse = answers['live.rundown.segment'];
++ answers['live.rundown.segment'] = () => null;
++ const seen = () => calls.filter((c) => c.workflow === 'live.rundown.segment' && c.input.streamer === 'greekline');
++ await desk.tick();
++ assert.ok(seen().length === 1 && seen()[0].input.lines.length <= desk.MAX_LINES, `at most ${desk.MAX_LINES} lines: ${seen()[0] && seen()[0].input.lines.length}`);
++ assert.ok(!await db.get('SELECT 1 FROM rundown_progress WHERE stream_id = ?', [sg]), 'a refused stretch is tried again');
++ await desk.tick();
++ await desk.tick();
++ assert.strictEqual(seen().length, 3);
++ const p = await db.get('SELECT read_to_sec FROM rundown_progress WHERE stream_id = ?', [sg]);
++ assert.ok(p && p.read_to_sec > 0, 'refused three times: the stretch is skipped');
++ answers['live.rundown.segment'] = refuse;
++ console.log('✅ limits: lines per stretch, refused stretches skipped after three tries');
++}
++
console.log('rundown: ok');
process.exit(0);
})().catch((err) => { console.error(err); process.exit(1); });