feat: enhance transcript handling with collapsed chunks
This commit is contained in:
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user