234 lines
6.4 KiB
TypeScript
234 lines
6.4 KiB
TypeScript
/**
|
|
* Utility functions and selectors for Meeting Intelligence feature.
|
|
*/
|
|
|
|
import { IReduxState } from '../app/types';
|
|
|
|
import { SPEAKER_COLORS, STATUS_COLORS, STATUS_LABELS } from './constants';
|
|
import { IMeetingIntelligenceState, ISpeakerStats, ITranscriptSegment } from './types';
|
|
|
|
/**
|
|
* Get the meeting intelligence state.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {IMeetingIntelligenceState} The meeting intelligence state.
|
|
*/
|
|
export function getMeetingIntelligenceState(state: IReduxState): IMeetingIntelligenceState {
|
|
return state['features/meeting-intelligence'];
|
|
}
|
|
|
|
/**
|
|
* Check if the dashboard is open.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {boolean} True if the dashboard is open.
|
|
*/
|
|
export function isDashboardOpen(state: IReduxState): boolean {
|
|
return getMeetingIntelligenceState(state)?.isOpen ?? false;
|
|
}
|
|
|
|
/**
|
|
* Get the active tab.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {string} The active tab name.
|
|
*/
|
|
export function getActiveTab(state: IReduxState): string {
|
|
return getMeetingIntelligenceState(state)?.activeTab ?? 'recordings';
|
|
}
|
|
|
|
/**
|
|
* Get the selected meeting.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {IMeeting|undefined} The selected meeting or undefined.
|
|
*/
|
|
export function getSelectedMeeting(state: IReduxState) {
|
|
return getMeetingIntelligenceState(state)?.selectedMeeting;
|
|
}
|
|
|
|
/**
|
|
* Get the current transcript.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {ITranscriptSegment[]} The transcript segments.
|
|
*/
|
|
export function getTranscript(state: IReduxState): ITranscriptSegment[] {
|
|
return getMeetingIntelligenceState(state)?.transcript ?? [];
|
|
}
|
|
|
|
/**
|
|
* Get the current summary.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {IMeetingSummary|undefined} The meeting summary or undefined.
|
|
*/
|
|
export function getSummary(state: IReduxState) {
|
|
return getMeetingIntelligenceState(state)?.summary;
|
|
}
|
|
|
|
/**
|
|
* Get speaker statistics.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {ISpeakerStats[]} The speaker statistics array.
|
|
*/
|
|
export function getSpeakerStats(state: IReduxState): ISpeakerStats[] {
|
|
return getMeetingIntelligenceState(state)?.speakerStats ?? [];
|
|
}
|
|
|
|
/**
|
|
* Format time in seconds to MM:SS or HH:MM:SS.
|
|
*
|
|
* @param {number} seconds - Time in seconds.
|
|
* @returns {string} Formatted time string.
|
|
*/
|
|
export function formatTime(seconds: number): string {
|
|
const totalSeconds = Math.floor(seconds);
|
|
const hours = Math.floor(totalSeconds / 3600);
|
|
const minutes = Math.floor((totalSeconds % 3600) / 60);
|
|
const secs = totalSeconds % 60;
|
|
|
|
if (hours > 0) {
|
|
return `${hours}:${minutes.toString().padStart(2, '0')}:${secs.toString().padStart(2, '0')}`;
|
|
}
|
|
|
|
return `${minutes}:${secs.toString().padStart(2, '0')}`;
|
|
}
|
|
|
|
/**
|
|
* Format duration in seconds to human readable.
|
|
*
|
|
* @param {number} seconds - Duration in seconds.
|
|
* @returns {string} Human readable duration.
|
|
*/
|
|
export function formatDuration(seconds: number): string {
|
|
const hours = Math.floor(seconds / 3600);
|
|
const minutes = Math.floor((seconds % 3600) / 60);
|
|
|
|
if (hours > 0) {
|
|
return `${hours}h ${minutes}m`;
|
|
}
|
|
|
|
return `${minutes}m`;
|
|
}
|
|
|
|
/**
|
|
* Format date to display string.
|
|
*
|
|
* @param {string} dateString - ISO date string.
|
|
* @returns {string} Formatted date string.
|
|
*/
|
|
export function formatDate(dateString: string): string {
|
|
const date = new Date(dateString);
|
|
|
|
return date.toLocaleDateString(undefined, {
|
|
year: 'numeric',
|
|
month: 'short',
|
|
day: 'numeric',
|
|
hour: '2-digit',
|
|
minute: '2-digit'
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Get color for a speaker based on label.
|
|
*
|
|
* @param {string} speakerLabel - The speaker label.
|
|
* @param {string[]} speakerLabels - All speaker labels.
|
|
* @returns {string} The color for the speaker.
|
|
*/
|
|
export function getSpeakerColor(speakerLabel: string, speakerLabels: string[]): string {
|
|
const index = speakerLabels.indexOf(speakerLabel);
|
|
|
|
return SPEAKER_COLORS[index % SPEAKER_COLORS.length];
|
|
}
|
|
|
|
/**
|
|
* Get unique speaker labels from transcript.
|
|
*
|
|
* @param {ITranscriptSegment[]} transcript - The transcript segments.
|
|
* @returns {string[]} Unique speaker labels.
|
|
*/
|
|
export function getUniqueSpeakers(transcript: ITranscriptSegment[]): string[] {
|
|
const speakers = new Set<string>();
|
|
|
|
transcript.forEach(segment => {
|
|
if (segment.speaker_label) {
|
|
speakers.add(segment.speaker_label);
|
|
}
|
|
});
|
|
|
|
return Array.from(speakers);
|
|
}
|
|
|
|
/**
|
|
* Get status label.
|
|
*
|
|
* @param {string} status - The status key.
|
|
* @returns {string} Human readable status label.
|
|
*/
|
|
export function getStatusLabel(status: string): string {
|
|
return STATUS_LABELS[status] ?? status;
|
|
}
|
|
|
|
/**
|
|
* Get status color.
|
|
*
|
|
* @param {string} status - The status key.
|
|
* @returns {string} The color hex code.
|
|
*/
|
|
export function getStatusColor(status: string): string {
|
|
return STATUS_COLORS[status] ?? '#9E9E9E';
|
|
}
|
|
|
|
/**
|
|
* Group transcript segments by speaker.
|
|
*
|
|
* @param {ITranscriptSegment[]} transcript - The transcript segments.
|
|
* @returns {Array<{segments: ITranscriptSegment[], speaker: string}>} Grouped segments.
|
|
*/
|
|
export function groupSegmentsBySpeaker(
|
|
transcript: ITranscriptSegment[]
|
|
): Array<{ segments: ITranscriptSegment[]; speaker: string; }> {
|
|
const groups: Array<{ segments: ITranscriptSegment[]; speaker: string; }> = [];
|
|
let currentGroup: { segments: ITranscriptSegment[]; speaker: string; } | null = null;
|
|
|
|
transcript.forEach(segment => {
|
|
const speaker = segment.speaker_label || 'Speaker';
|
|
|
|
if (!currentGroup || currentGroup.speaker !== speaker) {
|
|
currentGroup = { speaker, segments: [] };
|
|
groups.push(currentGroup);
|
|
}
|
|
|
|
currentGroup.segments.push(segment);
|
|
});
|
|
|
|
return groups;
|
|
}
|
|
|
|
/**
|
|
* Check if meeting intelligence is enabled in config.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {boolean} True if meeting intelligence is enabled.
|
|
*/
|
|
export function isMeetingIntelligenceEnabled(state: IReduxState): boolean {
|
|
const config = state['features/base/config'];
|
|
|
|
return config?.meetingIntelligence?.enabled ?? true;
|
|
}
|
|
|
|
/**
|
|
* Get the API URL from config or use default.
|
|
*
|
|
* @param {IReduxState} state - The Redux state.
|
|
* @returns {string} The API URL.
|
|
*/
|
|
export function getApiUrl(state: IReduxState): string {
|
|
const config = state['features/base/config'];
|
|
|
|
return config?.meetingIntelligence?.apiUrl ?? '/api/intelligence';
|
|
}
|