How to add SFTranscriptionSegment data to Firebase Firestore?

Viewed 75

I'm using SFTranscription in Swift to transcribe voice notes. I then want to add this transcription data to Firebase Firestore, but this is triggering an error, since Firestore only accepts these data types.

My question is: How should I package up my array of SFTranscriptionSegments to be a data type that I can pass up to Firestore and then retrieve again?

This is the error message I get:

Terminating app due to uncaught exception 'FIRInvalidArgumentException', reason: 'Unsupported type: SFTranscriptionSegment'

I declare the segments variable like this

var segments: [SFTranscriptionSegment] = []

This is where I try to add the transcription segments to firestore

audioMessageRef.putFile(from: fileUrl, metadata: nil) { (metadata, error) in
            if error != nil {
                print(error ?? "error")
            }
            
            audioMessageRef.downloadURL { (url, error) in
                guard let downloadURL = url else {
                  // Uh-oh, an error occurred!
                  return
                }
                
                let data: [String: Any] = [
                    "audioURL": downloadURL.absoluteString,
                    "transcribedSegments": self.segments,
                    "id": messageID,
                    "fromId": currentUid,
                    "toId": self.user.id,
                    "timestamp": Timestamp(date: Date()),
                    "time": time
                ]
                                
                currentUserRef.setData(data)
                receivingUserRef.document(messageID).setData(data)
                DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) {
                    self.generateClips()
                }
            }
            
        }

This is what my array of SFTranscriptionSegments looks like:

[<SFTranscriptionSegment: 0x6000024656e0>, substringRange={0, 7}, timestamp=1.77, duration=-1.77, confidence=0.895, substring=Testing, alternativeSubstrings=(
), phoneSequence=, ipaPhoneSequence=, voiceAnalytics=(null), <SFTranscriptionSegment: 0x600002467d20>, substringRange={8, 7}, timestamp=2.61, duration=-2.61, confidence=0.908, substring=testing, alternativeSubstrings=(
), phoneSequence=, ipaPhoneSequence=, voiceAnalytics=(null), <SFTranscriptionSegment: 0x600002467c60>, substringRange={16, 1}, timestamp=3.42, duration=-3.42, confidence=0.912, substring=1, alternativeSubstrings=(
), phoneSequence=, ipaPhoneSequence=, voiceAnalytics=(null), <SFTranscriptionSegment: 0x600002465c80>, substringRange={17, 1}, timestamp=3.78, duration=-3.78, confidence=0.917, substring=2, alternativeSubstrings=(
), phoneSequence=, ipaPhoneSequence=, voiceAnalytics=(null), <SFTranscriptionSegment: 0x6000024654a0>, substringRange={18, 1}, timestamp=4.2, duration=-4.2, confidence=0.906, substring=3, alternativeSubstrings=(
), phoneSequence=, ipaPhoneSequence=, voiceAnalytics=(null)]
2 Answers

Thanks Rajeev. In the end I figured out that I needed to create my own Codable struct (TranscriptionSegment) that takes the values I need from the SFTranscriptionSegment. I then translate this into an array of maps in the Firestore backend, and back into a TranscriptionSegment when I draw it down from the server.

struct TranscriptionSegment: Codable, Equatable {
    let timestamp: Double
    let duration: Double
    var substring: String
}
let transcriptionSegments = self.segments.map {
    ["timestamp": $0.timestamp,
    "duration": $0.duration,
    "substring": $0.substring]
}
                
let data: [String: Any] = [
    ... 
    "transcribedSegments": transcriptionSegments,
    ...
]
Related