openvibers/openvibe.live Commits

PowerChat: forward relayed Twitch/Kick/YouTube/RS chat to the overlay; re-queue truncated AI overviews for regeneration

OP OpenVibers committed 26 Aug 2026 · 117a872b2d · 3 files, +36 −2


Changes

ddiff --git a/server/db/database.js b/server/db/database.js
iindex ef33a4e6..ee5eaf08 100644
---- a/server/db/database.js
++++ b/server/db/database.js
@@@ -2808,8 +2808,12 @@ function getStreamMemoriesInRange(streamId, startSec, endSec) {
}
// Backfill queues (items still lacking AI output).
function getVodsNeedingOverview(limit = 4) {
++ // Also re-queue rows whose short was truncated ('…') but whose full text was never
++ // stored (older builds threw it away) — once regenerated, ai_overview is set and the
++ // row drops out of the queue.
return all(`SELECT vod_id AS id, s.* FROM vod_ai_state s
-- WHERE ai_overview_short IS NULL OR ai_overview_short = ''
++ WHERE (ai_overview IS NULL OR ai_overview = '')
++ AND (ai_overview_short IS NULL OR ai_overview_short = '' OR ai_overview_short LIKE '%…')
ORDER BY vod_id DESC LIMIT ?`, [limit]);
}
// Finished VODs whose AI timeline has fewer than 2 points — used to backfill the
@@@ -2824,7 +2828,8 @@ function getVodsNeedingTimeline(limit = 1) {
}
function getClipsNeedingOverview(limit = 4) {
return all(`SELECT clip_id AS id, s.* FROM clip_ai_state s
-- WHERE ai_overview_short IS NULL OR ai_overview_short = ''
++ WHERE (ai_overview IS NULL OR ai_overview = '')
++ AND (ai_overview_short IS NULL OR ai_overview_short = '' OR ai_overview_short LIKE '%…')
ORDER BY clip_id DESC LIMIT ?`, [limit]);
}
// Transcript backfill queues — driven by transcript_status (see the migration above).
ddiff --git a/server/integrations/chat-relay-service.js b/server/integrations/chat-relay-service.js
iindex 68ab2002..ee47715b 100644
---- a/server/integrations/chat-relay-service.js
++++ b/server/integrations/chat-relay-service.js
@@@ -433,6 +433,22 @@ class ChatRelayService {
chatServer.synthesizeAndBroadcastTTS(bridge.streamId, prefixedUsername, chatMsg.message, null, bridge.platform, `${bridge.platform}:${prefixedUsername}`);
} catch { /* non-critical */ }
++ // Merge relayed chat into the streamer's PowerChat unified overlay too. Only
++ // native OpenVibe messages were forwarded before, so a streamer whose audience
++ // mostly chats on Twitch/Kick saw an empty overlay.
++ try {
++ const stream = db.getStreamById(bridge.streamId);
++ if (stream?.user_id) {
++ require('./powerchat-platform').forwardChat(stream.user_id, {
++ chatterName: prefixedUsername,
++ externalChatterId: `${bridge.platform}:${username}`,
++ message: chatMsg.message,
++ messageId: chatMsg.id ? `ov-${chatMsg.id}` : undefined,
++ avatarUrl: extras.avatar_url || undefined,
++ });
++ }
++ } catch { /* non-critical */ }
++
// Welcome first-time external chatters in this streamer's channel
try {
const stream = db.getStreamById(bridge.streamId);
ddiff --git a/server/integrations/robotstreamer-service.js b/server/integrations/robotstreamer-service.js
iindex 23fd4ffd..32db4b21 100644
---- a/server/integrations/robotstreamer-service.js
++++ b/server/integrations/robotstreamer-service.js
@@@ -742,6 +742,19 @@ class RobotStreamerService {
try {
chatServer.synthesizeAndBroadcastTTS(stream.id, username, mirrored.message, null, 'rs', `rs:${username}`);
} catch { /* non-critical */ }
++
++ // ...and into the streamer's PowerChat overlay (relayed chat was never forwarded).
++ try {
++ if (stream.user_id) {
++ require('./powerchat-platform').forwardChat(stream.user_id, {
++ chatterName: username,
++ externalChatterId: `rs:${username}`,
++ message: mirrored.message,
++ messageId: mirrored.id ? `ov-${mirrored.id}` : undefined,
++ avatarUrl: data.avatar || undefined,
++ });
++ }
++ } catch { /* non-critical */ }
});
bridge.ws.on('close', () => {