openvibers/openvibe.live Commits
PowerChat: forward relayed Twitch/Kick/YouTube/RS chat to the overlay; re-queue truncated AI overviews for regeneration
Changes
@@@ -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).@@@ -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 channeltry {const stream = db.getStreamById(bridge.streamId);@@@ -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', () => {
@@ -2808,8 +2808,12 @@ function getStreamMemoriesInRange(streamId, startSec, endSec) {
@@ -2808,8 +2808,12 @@ function getStreamMemoriesInRange(streamId, startSec, endSec) {
}
}
// Backfill queues (items still lacking AI output).
// Backfill queues (items still lacking AI output).
function getVodsNeedingOverview(limit = 4) {
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
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]);
ORDER BY vod_id DESC LIMIT ?`, [limit]);
}
}
// Finished VODs whose AI timeline has fewer than 2 points — used to backfill the
// Finished VODs whose AI timeline has fewer than 2 points — used to backfill the
@@ -2824,7 +2828,8 @@ function getVodsNeedingTimeline(limit = 1) {
@@ -2824,7 +2828,8 @@ function getVodsNeedingTimeline(limit = 1) {
}
}
function getClipsNeedingOverview(limit = 4) {
function getClipsNeedingOverview(limit = 4) {
return all(`SELECT clip_id AS id, s.* FROM clip_ai_state s
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]);
ORDER BY clip_id DESC LIMIT ?`, [limit]);
}
}
// Transcript backfill queues — driven by transcript_status (see the migration above).
// Transcript backfill queues — driven by transcript_status (see the migration above).
@@ -433,6 +433,22 @@ class ChatRelayService {
@@ -433,6 +433,22 @@ class ChatRelayService {
chatServer.synthesizeAndBroadcastTTS(bridge.streamId, prefixedUsername, chatMsg.message, null, bridge.platform, `${bridge.platform}:${prefixedUsername}`);
chatServer.synthesizeAndBroadcastTTS(bridge.streamId, prefixedUsername, chatMsg.message, null, bridge.platform, `${bridge.platform}:${prefixedUsername}`);
} catch { /* non-critical */ }
} 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
// Welcome first-time external chatters in this streamer's channel
try {
try {
const stream = db.getStreamById(bridge.streamId);
const stream = db.getStreamById(bridge.streamId);
@@ -742,6 +742,19 @@ class RobotStreamerService {
@@ -742,6 +742,19 @@ class RobotStreamerService {
try {
try {
chatServer.synthesizeAndBroadcastTTS(stream.id, username, mirrored.message, null, 'rs', `rs:${username}`);
chatServer.synthesizeAndBroadcastTTS(stream.id, username, mirrored.message, null, 'rs', `rs:${username}`);
} catch { /* non-critical */ }
} 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', () => {
bridge.ws.on('close', () => {