From e1a48a985a71678694cc35b0f1b05673fd0991e5 Mon Sep 17 00:00:00 2001 From: legop3 Date: Thu, 14 May 2026 21:41:37 -0400 Subject: [PATCH] promp and replay tweaks --- server/prompts/overseer_control_system.txt | 2 +- .../src/services/replayEngineV2/constants.js | 2 +- server/src/services/replayEngineV2/index.js | 7 +++++- .../services/replayEngineV2/replayBuilder.js | 24 +++++++++++++++++-- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/server/prompts/overseer_control_system.txt b/server/prompts/overseer_control_system.txt index ec965933..f4ef6d34 100644 --- a/server/prompts/overseer_control_system.txt +++ b/server/prompts/overseer_control_system.txt @@ -20,7 +20,7 @@ Rules: - Ignore obvious bot commands and responses in chat. Chat style: -- Always use English. +- Only send messages in English. Do not use other languages. - If speaking, send one short live-chat line. - Keep it concise and informal (roughly 3-14 words). - Chat output must be spoken text only. diff --git a/server/src/services/replayEngineV2/constants.js b/server/src/services/replayEngineV2/constants.js index 10e0cf8e..21e0e36b 100644 --- a/server/src/services/replayEngineV2/constants.js +++ b/server/src/services/replayEngineV2/constants.js @@ -8,7 +8,7 @@ const FFMPEG_BIN = process.env.FFMPEG_BIN || 'ffmpeg'; const SEGMENT_ROOT = path.join(resolveDataDir(), 'replay-segments'); const SEGMENT_SECONDS = Math.max(1, Number.parseInt(process.env.REPLAY_SEGMENT_SECONDS || '1', 10)); const BUFFER_SECONDS = Math.max(20, Number.parseInt(process.env.REPLAY_BUFFER_SECONDS || '45', 10)); -const CLEANUP_INTERVAL_MS = 10_000; +const CLEANUP_INTERVAL_MS = Math.max(500, Number.parseInt(process.env.REPLAY_TICK_MS || '2000', 10)); const BUILD_DURATION_MS = Math.max(5000, Number.parseInt(process.env.REPLAY_DURATION_MS || '35000', 10)); const BUILD_GUARD_MS = Math.max(200, Number.parseInt(process.env.REPLAY_GUARD_MS || '1200', 10)); const TARGET_FPS = Math.max(10, Number.parseInt(process.env.REPLAY_TARGET_FPS || '30', 10)); diff --git a/server/src/services/replayEngineV2/index.js b/server/src/services/replayEngineV2/index.js index cf12b09f..a297478d 100644 --- a/server/src/services/replayEngineV2/index.js +++ b/server/src/services/replayEngineV2/index.js @@ -54,6 +54,11 @@ const replayBuilder = createReplayBuilder({ }); registerReplaySocketHooks({ tryTriggerReplay, validateSources, getDefaultWebSources }); +async function buildReplayVideoFresh(options = {}) { + await tick(); + return replayBuilder.buildReplayVideo(options); +} + function getReplayHealthSnapshot() { return segmentStore.getReplayHealthSnapshot({ BUILD_DURATION_MS, roverManager, getRoomCameras }); } @@ -98,7 +103,7 @@ start().catch((err) => { }); module.exports = { - buildReplayVideo: replayBuilder.buildReplayVideo, + buildReplayVideo: buildReplayVideoFresh, tryTriggerReplay, getReplayState, replayEvents, diff --git a/server/src/services/replayEngineV2/replayBuilder.js b/server/src/services/replayEngineV2/replayBuilder.js index 16cc6514..df9b48bb 100644 --- a/server/src/services/replayEngineV2/replayBuilder.js +++ b/server/src/services/replayEngineV2/replayBuilder.js @@ -52,6 +52,22 @@ function buildChatEventsForWindow(startMs, endMs, limit = 22, preWindowCount = 1 } function createReplayBuilder({ execFileAsync, fsp, ensureDir, renderSidebarVideo, getVideoEntriesForSource, getAudioEntriesForRover, overlapping }) { + function resolveReplayWindow({ sources = [], nowMs, guardMs, durationMs }) { + const tentativeEnd = nowMs - guardMs; + const sourceEnds = []; + for (const source of sources) { + const sourceId = String(source.id); + const allEntries = getVideoEntriesForSource({ type: String(source.type), id: sourceId }); + if (!Array.isArray(allEntries) || !allEntries.length) continue; + const bounded = allEntries.filter((entry) => Number.isFinite(entry?.endMs) && entry.endMs <= tentativeEnd); + if (!bounded.length) continue; + const latest = bounded.reduce((best, entry) => (entry.endMs > best.endMs ? entry : best), bounded[0]); + sourceEnds.push(latest.endMs); + } + const alignedEnd = sourceEnds.length ? Math.min(...sourceEnds) : tentativeEnd; + return { tEnd: alignedEnd, tStart: alignedEnd - durationMs }; + } + async function concatFiles(inputPaths, outPath) { const listPath = `${outPath}.concat.txt`; const body = inputPaths.map((file) => `file '${file.replace(/'/g, "'\\''")}'`).join('\n'); @@ -74,8 +90,12 @@ function createReplayBuilder({ execFileAsync, fsp, ensureDir, renderSidebarVideo async function buildReplayVideo({ sources = [], title = '', requester = '', includeSidebar = true } = {}) { if (!Array.isArray(sources) || !sources.length) throw new Error('No replay sources selected'); - const tEnd = Date.now() - BUILD_GUARD_MS; - const tStart = tEnd - BUILD_DURATION_MS; + const { tEnd, tStart } = resolveReplayWindow({ + sources, + nowMs: Date.now(), + guardMs: BUILD_GUARD_MS, + durationMs: BUILD_DURATION_MS, + }); const resolvedTitle = sanitizeReplayTitle(title, resolveDefaultReplayTitle(requester, sources)); const tmpDir = await fsp.mkdtemp(path.join(os.tmpdir(), 'mrr-replay-v2-'));