Refactor chat message formatting and enhance subtitle settings

This commit is contained in:
Nikita 2025-12-09 11:03:32 -08:00
parent dafdba11cf
commit c4bb9aec12
5 changed files with 59 additions and 18 deletions

View File

@ -1,6 +1,7 @@
'use client';
import { formatChatMessageLinks, RoomContext, VideoConference } from '@livekit/components-react';
import { RoomContext, VideoConference } from '@livekit/components-react';
import { formatChatMessage } from '@/lib/chat-utils';
import {
ExternalE2EEKeyProvider,
LogLevel,
@ -86,7 +87,7 @@ export function VideoConferenceClientImpl(props: {
<RoomContext.Provider value={room}>
<KeyboardShortcuts />
<VideoConference
chatMessageFormatter={formatChatMessageLinks}
chatMessageFormatter={formatChatMessage}
SettingsComponent={
process.env.NEXT_PUBLIC_SHOW_SETTINGS_MENU === 'true' ? SettingsMenu : undefined
}

View File

@ -2,19 +2,14 @@
import React from 'react';
import { decodePassphrase } from '@/lib/client-utils';
import { formatChatMessage } from '@/lib/chat-utils';
import { DebugMode } from '@/lib/Debug';
import { KeyboardShortcuts } from '@/lib/KeyboardShortcuts';
import { RecordingIndicator } from '@/lib/RecordingIndicator';
import { SettingsMenu } from '@/lib/SettingsMenu';
import { ConnectionDetails } from '@/lib/types';
import { SubtitlesOverlay, SubtitleProvider } from '@/lib/SubtitlesOverlay';
import {
formatChatMessageLinks,
LocalUserChoices,
PreJoin,
RoomContext,
VideoConference,
} from '@livekit/components-react';
import { LocalUserChoices, PreJoin, RoomContext, VideoConference } from '@livekit/components-react';
import {
ExternalE2EEKeyProvider,
RoomOptions,
@ -33,7 +28,6 @@ import { useLowCPUOptimizer } from '@/lib/usePerfomanceOptimiser';
const CONN_DETAILS_ENDPOINT =
process.env.NEXT_PUBLIC_CONN_DETAILS_ENDPOINT ?? '/api/connection-details';
const SHOW_SETTINGS_MENU = process.env.NEXT_PUBLIC_SHOW_SETTINGS_MENU == 'true';
export function PageClientImpl(props: {
roomName: string;
@ -224,7 +218,7 @@ function VideoConferenceComponent(props: {
<SubtitleProvider>
<KeyboardShortcuts />
<VideoConference
chatMessageFormatter={formatChatMessageLinks}
chatMessageFormatter={formatChatMessage}
SettingsComponent={SettingsMenu}
/>
<SubtitlesOverlay />

View File

@ -24,6 +24,7 @@ interface SubtitleContextType {
updateSettings: (settings: SubtitleSettings) => void;
hasAgent: boolean;
summaryEmail: string | null;
setSummaryEmail: (email: string | null) => void;
}
const SubtitleContext = React.createContext<SubtitleContextType | null>(null);
@ -109,8 +110,29 @@ export function SubtitleProvider({ children }: { children: React.ReactNode }) {
}
}, []);
const updateSummaryEmail = React.useCallback((email: string | null) => {
setSummaryEmail(email);
try {
if (email) {
localStorage.setItem('summary-email', email);
} else {
localStorage.removeItem('summary-email');
}
} catch (e) {
console.error('Failed to save summary email:', e);
}
}, []);
return (
<SubtitleContext.Provider value={{ settings, updateSettings, hasAgent, summaryEmail }}>
<SubtitleContext.Provider
value={{
settings,
updateSettings,
hasAgent,
summaryEmail,
setSummaryEmail: updateSummaryEmail,
}}
>
{children}
</SubtitleContext.Provider>
);

View File

@ -102,7 +102,8 @@ function EmailPopup({
export function SubtitlesSettings() {
const room = useRoomContext();
const { settings, updateSettings, hasAgent, summaryEmail } = useSubtitleSettings();
const { settings, updateSettings, hasAgent, summaryEmail, setSummaryEmail } =
useSubtitleSettings();
const [showPopup, setShowPopup] = React.useState(false);
const [isSpawning, setIsSpawning] = React.useState(false);
const [spawnError, setSpawnError] = React.useState<string | null>(null);
@ -125,14 +126,17 @@ export function SubtitlesSettings() {
setSpawnError(null);
try {
const payload = {
roomName: room.name,
email: email || undefined,
e2eePassphrase: getPassphrase(),
};
console.log('[SubtitlesSettings] Spawning agent with:', payload);
const response = await fetch('/api/agent/spawn', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
roomName: room.name,
email: email || undefined,
e2eePassphrase: getPassphrase(),
}),
body: JSON.stringify(payload),
});
if (!response.ok) {
@ -160,6 +164,7 @@ export function SubtitlesSettings() {
const handleSkip = async () => {
if (await spawnAgent()) {
setSummaryEmail(null);
updateSettings({ ...settings, enabled: true });
setShowPopup(false);
}
@ -167,6 +172,7 @@ export function SubtitlesSettings() {
const handleSubscribe = async (email: string) => {
if (await spawnAgent(email)) {
setSummaryEmail(email);
updateSettings({ ...settings, enabled: true });
setShowPopup(false);
}

18
lib/chat-utils.ts Normal file
View File

@ -0,0 +1,18 @@
'use client';
import React from 'react';
import { formatChatMessageLinks } from '@livekit/components-react';
/**
* Chat message formatter with newline support.
* Wraps LiveKit's formatChatMessageLinks and adds <br/> for line breaks.
*/
export function formatChatMessage(message: string): React.ReactNode {
return message
.split('\n')
.flatMap((line, i) =>
i === 0
? [formatChatMessageLinks(line)]
: [React.createElement('br', { key: `br-${i}` }), formatChatMessageLinks(line)],
);
}