mirror of
https://github.com/Memo-2023/mana-monorepo.git
synced 2026-05-15 13:01:09 +02:00
Projects included: - maerchenzauber (NestJS backend + Expo mobile + SvelteKit web + Astro landing) - manacore (Expo mobile + SvelteKit web + Astro landing) - manadeck (NestJS backend + Expo mobile + SvelteKit web) - memoro (Expo mobile + SvelteKit web + Astro landing) This commit preserves the current state before monorepo restructuring. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
168 lines
No EOL
4.8 KiB
TypeScript
168 lines
No EOL
4.8 KiB
TypeScript
/**
|
|
* Utility functions for handling transcript generation from utterances
|
|
*/
|
|
|
|
/**
|
|
* Generate a plain text transcript from utterances array
|
|
* @param utterances - Array of utterance objects with text property
|
|
* @returns Plain text transcript string
|
|
*/
|
|
export function generateTranscriptFromUtterances(
|
|
utterances?: Array<{ text: string; speakerId?: string; offset?: number; duration?: number }> | null
|
|
): string {
|
|
if (!utterances || utterances.length === 0) {
|
|
return '';
|
|
}
|
|
|
|
// Sort utterances by offset if available
|
|
const sortedUtterances = [...utterances].sort((a, b) => {
|
|
const offsetA = a.offset || 0;
|
|
const offsetB = b.offset || 0;
|
|
return offsetA - offsetB;
|
|
});
|
|
|
|
// Concatenate all utterance texts with spaces
|
|
return sortedUtterances
|
|
.map(utterance => utterance.text)
|
|
.filter(text => text && text.trim() !== '')
|
|
.join(' ');
|
|
}
|
|
|
|
/**
|
|
* Check if transcript data exists (either in utterances or legacy transcript fields)
|
|
* @param memo - The memo object to check
|
|
* @returns Boolean indicating if transcript exists
|
|
*/
|
|
export function hasTranscript(memo: any): boolean {
|
|
// Check utterances first (new structure)
|
|
if (memo?.source?.utterances && memo.source.utterances.length > 0) {
|
|
return true;
|
|
}
|
|
|
|
// Check legacy fields for backward compatibility
|
|
return !!(
|
|
memo?.transcript ||
|
|
memo?.source?.transcript ||
|
|
memo?.source?.content ||
|
|
memo?.source?.transcription ||
|
|
memo?.metadata?.transcript
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get transcript text from memo (generates from utterances or returns legacy transcript)
|
|
* @param memo - The memo object
|
|
* @returns The transcript text
|
|
*/
|
|
export function getTranscriptText(memo: any): string {
|
|
// If utterances exist, generate transcript from them
|
|
if (memo?.source?.utterances && memo.source.utterances.length > 0) {
|
|
return generateTranscriptFromUtterances(memo.source.utterances);
|
|
}
|
|
|
|
// Fall back to legacy transcript fields
|
|
return (
|
|
memo?.transcript ||
|
|
memo?.source?.transcript ||
|
|
memo?.source?.content ||
|
|
memo?.source?.transcription ||
|
|
memo?.metadata?.transcript ||
|
|
''
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Get utterances from various possible locations in memo
|
|
* @param memo - The memo object
|
|
* @returns Array of utterances or null
|
|
*/
|
|
export function getUtterances(memo: any): Array<{ text: string; speakerId?: string; offset?: number; duration?: number }> | null {
|
|
// Check primary location
|
|
if (memo?.source?.utterances && Array.isArray(memo.source.utterances)) {
|
|
return memo.source.utterances;
|
|
}
|
|
|
|
// Check metadata location (for backward compatibility)
|
|
if (memo?.metadata?.utterances && Array.isArray(memo.metadata.utterances)) {
|
|
return memo.metadata.utterances;
|
|
}
|
|
|
|
// If only transcript exists, create a single utterance
|
|
const transcriptText = memo?.transcript ||
|
|
memo?.source?.transcript ||
|
|
memo?.source?.content ||
|
|
memo?.source?.transcription ||
|
|
memo?.metadata?.transcript;
|
|
|
|
if (transcriptText) {
|
|
return [{
|
|
text: transcriptText,
|
|
speakerId: 'default',
|
|
offset: 0,
|
|
duration: 0
|
|
}];
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
/**
|
|
* Check if a memo is a combined memo
|
|
* @param memo - The memo object
|
|
* @returns Boolean indicating if it's a combined memo
|
|
*/
|
|
export function isCombinedMemo(memo: any): boolean {
|
|
return memo?.source?.type === 'combined';
|
|
}
|
|
|
|
/**
|
|
* Get combined memo recordings with their transcripts
|
|
* @param memo - The memo object
|
|
* @returns Array of recordings with transcript data or empty array
|
|
*/
|
|
export function getCombinedMemoRecordings(memo: any): Array<{
|
|
title: string;
|
|
transcript: string;
|
|
utterances: Array<{ text: string; speakerId: string; offset: number; duration: number }>;
|
|
speakers: Record<string, string>;
|
|
timestamp: string;
|
|
index: number;
|
|
}> {
|
|
if (!isCombinedMemo(memo) || !memo?.source?.additional_recordings) {
|
|
return [];
|
|
}
|
|
|
|
return memo.source.additional_recordings.map((recording: any, index: number) => {
|
|
const memoMetadata = recording.memo_metadata || {};
|
|
|
|
return {
|
|
title: memoMetadata.original_title || memoMetadata.display_title || `Recording ${index + 1}`,
|
|
transcript: recording.transcript || '',
|
|
utterances: recording.utterances || [],
|
|
speakers: recording.speakers || {},
|
|
timestamp: recording.timestamp || memoMetadata.original_created_at || '',
|
|
index: memoMetadata.combine_index ?? index,
|
|
};
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Calculate total audio duration for combined memos
|
|
* @param memo - The memo object
|
|
* @returns Total duration in seconds or 0
|
|
*/
|
|
export function getCombinedMemoDuration(memo: any): number {
|
|
if (!isCombinedMemo(memo) || !memo?.source?.additional_recordings) {
|
|
return 0;
|
|
}
|
|
|
|
let totalDuration = 0;
|
|
|
|
memo.source.additional_recordings.forEach((recording: any) => {
|
|
if (recording.duration) {
|
|
totalDuration += recording.duration;
|
|
}
|
|
});
|
|
|
|
return totalDuration;
|
|
} |