feat: enhance transcript handling with collapsed chunks

This commit is contained in:
Owen Gretzinger
2025-07-10 17:34:59 -04:00
parent dfb1b79f0c
commit 619223fa1e
3 changed files with 119 additions and 80 deletions
+105 -2
View File
@@ -7,9 +7,18 @@ enum AudioSource: String, Codable, CaseIterable {
var displayName: String {
switch self {
case .mic:
return "Microphone"
return "Me"
case .system:
return "System Audio"
return "Them"
}
}
var copyPrefix: String {
switch self {
case .mic:
return "Me"
case .system:
return "Them"
}
}
@@ -39,6 +48,20 @@ struct TranscriptChunk: Codable, Identifiable, Hashable {
}
}
struct CollapsedTranscriptChunk: Identifiable {
let id: UUID
let timestamp: Date
let source: AudioSource
let combinedText: String
init(id: UUID = UUID(), timestamp: Date, source: AudioSource, combinedText: String) {
self.id = id
self.timestamp = timestamp
self.source = source
self.combinedText = combinedText
}
}
struct Meeting: Codable, Identifiable, Hashable {
let id: UUID
let date: Date
@@ -66,6 +89,86 @@ struct Meeting: Codable, Identifiable, Hashable {
.joined(separator: " ")
}
// Formatted transcript for copying with collapsed sequential chunks
var formattedTranscript: String {
let finalChunks = transcriptChunks.filter { $0.isFinal }
guard !finalChunks.isEmpty else { return "" }
var result: [String] = []
var currentSource: AudioSource?
var currentTexts: [String] = []
for chunk in finalChunks {
if chunk.source != currentSource {
// Finish previous section if exists
if let source = currentSource, !currentTexts.isEmpty {
let combinedText = currentTexts.joined(separator: " ")
result.append("\(source.copyPrefix): \(combinedText)")
}
// Start new section
currentSource = chunk.source
currentTexts = [chunk.text]
} else {
// Same source, add to current section
currentTexts.append(chunk.text)
}
}
// Finish last section
if let source = currentSource, !currentTexts.isEmpty {
let combinedText = currentTexts.joined(separator: " ")
result.append("\(source.copyPrefix): \(combinedText)")
}
return result.joined(separator: " \n")
}
// Collapsed chunks for UI display
var collapsedTranscriptChunks: [CollapsedTranscriptChunk] {
guard !transcriptChunks.isEmpty else { return [] }
var result: [CollapsedTranscriptChunk] = []
var currentSource: AudioSource?
var currentTexts: [String] = []
var currentTimestamp: Date?
for chunk in transcriptChunks {
if chunk.source != currentSource {
// Finish previous section if exists
if let source = currentSource, !currentTexts.isEmpty, let timestamp = currentTimestamp {
let combinedText = currentTexts.joined(separator: " ")
result.append(CollapsedTranscriptChunk(
timestamp: timestamp,
source: source,
combinedText: combinedText
))
}
// Start new section
currentSource = chunk.source
currentTexts = [chunk.text]
currentTimestamp = chunk.timestamp
} else {
// Same source, add to current section
currentTexts.append(chunk.text)
}
}
// Finish last section
if let source = currentSource, !currentTexts.isEmpty, let timestamp = currentTimestamp {
let combinedText = currentTexts.joined(separator: " ")
result.append(CollapsedTranscriptChunk(
timestamp: timestamp,
source: source,
combinedText: combinedText
))
}
return result
}
// Separate computed properties for mic and system transcripts
var micTranscript: String {
return transcriptChunks