Swift-語音識別、翻譯

幸福的小木子發表於2019-03-20

#前言 可能很多人都沒去注意手機的語音識別功能,基本的鍵盤都具備了此功能,他的位置其實也很明顯,可是用的人不多。估計是因為中國人太喜歡那個雙手停不下來的打字的淋漓酣暢的感覺吧,再不然就是直接使用語音通話、語音訊息,視訊電話,所以這個功能在手機上的存在感很低。

image

圖中原話是:到達できないものはすべて存在するものを持っている必要があります

正宗翻譯是:凡不能人到的事物,必定有必能有將必存在

但是呢跟今天探討的語音識別功能自然也很成熟,但是作者想到了可以體驗一下說外國語識別出來的效果以及看下外國字,順便想到了翻譯的功能,就做了一個demo,實時識別-實時翻譯。聽起來很wanderfull是不是,但是呢,只是一個小把戲,系統提供了介面,翻譯介面使用的是詞霸的介面(僅僅學習,所以想玩的可以找個更好的介面),開始進入正題吧。

本地化

為啥玩語音識別還要附帶這個玩意,其實很簡單,就像之前在某音上看的。各個國家有各個國家的國歌,和某地的語言像極了鳥語。方言太多了,所以要統一語言,說出的話大家理解的都是同一份意思,這是小的,對於全球這麼多國家,需要的是尊重各個國家的文化和歷史,所以語言也是嘍。 語音識別就像是一個傾聽者,他工作的時候必須和你在同一個頻道上,才能正確識別的你的話語。Locale是一個本地化類,相信大家在很多地方都看到這個類的蹤影,其實也就是包含當地的語言,貨幣,貨幣符號,語言程式碼等等之類的。iOS系統支援的語言有目前797種,可以提供識別的語言有63種,其中分地區語言的,如zh_CNzh_HKzh_TW

/** 可用的識別符號*/
let identifiers = Locale.availableIdentifiers
let allLocales = identifiers.map { (identifier) -> OMLocale in
    let local = Locale(identifier: identifier)
    let languageName = Locale.current.localizedString(forLanguageCode: identifier)
    let currencySymbol = local.currencySymbol
    let currencyCode = local.currencyCode
    let languageIdentifier = "\(local.languageCode ?? "")-\(local.regionCode ?? "")"
    let detail = "貨幣代號:\(currencyCode ?? "")   貨幣符號:\(currencySymbol ?? "")"
    return OMLocale.init(title: languageName ?? "", detailTitle: detail, languageIdentifier: languageIdentifier)
}
tipLabel.text = "當前系統共支援\(allLocales.count)種語言,但是由於語音識別只支援\(supportRecognitionLanuages.count)種語言,故只展示支援識別語言"
locales = allLocales.filter({ (local) -> Bool in
    print(local.languageIdentifier)
    return supportRecognitionLanuages.contains(local.languageIdentifier)
})
複製程式碼

語音識別

我訴說心腸說系統聽並理解,那麼肯定需要兩個許可權,一個是耳朵(麥克風)、另一個是大腦(語音識別)。其中語音識別許可權欄位可能不是很清楚:Privacy - Speech Recognition Usage Description

private var speechRecognizer: SFSpeechRecognizer? = SFSpeechRecognizer.init(locale: Locale(identifier: "en-US"))
private var speechRecognitionRequest: SFSpeechAudioBufferRecognitionRequest?
private var speechRecognitionTask: SFSpeechRecognitionTask?
private var audioEngine: AVAudioEngine = AVAudioEngine.init()
複製程式碼

使用音訊引擎開始監聽輸入資料,並把資料新增到變化的識別請求中,語音識別通過識別任務來進行一個識別結果的回,就可以拿到識別的結果。聽起來很簡單,事實也就是這麼簡單。

let audioSession = AVAudioSession.sharedInstance()
try audioSession.setCategory(.record, mode: .measurement)
try audioSession.setActive(true, options: .notifyOthersOnDeactivation)
speechRecognitionRequest = SFSpeechAudioBufferRecognitionRequest.init()
guard let speechRecognitionRequest = speechRecognitionRequest else {
    fatalError("The Audio can't create SFSpeechAudioBufferRecognitionRequest object")
}
speechRecognitionRequest.shouldReportPartialResults = true
speechRecognitionTask = speechRecognizer?.recognitionTask(with: speechRecognitionRequest) { (result, error) in
    var isFinished = false
    if let result = result {
    /**  呼叫翻譯介面並把識別資料實時進行請求,來模擬實現實時翻譯*/
    self.translation(string: result.bestTranscription.formattedString, identifier: self.identifier, completion: { [weak self] (translationResult) in
        guard let `self` = self else { return }
        DispatchQueue.main.async {
            self.translationTextView?.text = translationResult
        }
    })
    self.inputTextView?.text = result.bestTranscription.formattedString
    isFinished = result.isFinal
    }

    if error != nil || isFinished{
        self.audioEngine.stop()
        self.audioEngine.inputNode.removeTap(onBus: 0)

        self.speechRecognitionRequest = nil
        self.speechRecognitionTask = nil

        self.recordButton?.setTitle("Start Record", for: .normal)
        self.recordButton?.isEnabled = true
    }
}
let recordFormat = self.audioEngine.inputNode.outputFormat(forBus: 0)
self.audioEngine.inputNode.installTap(onBus: 0, bufferSize: 1024, format: recordFormat, block: { (buffer, time) in
    self.speechRecognitionRequest?.append(buffer)
})

self.audioEngine.prepare()
try self.audioEngine.start()
複製程式碼

翻譯

在上面的程式碼裡已經使用了,之前提到用的是詞霸的,索性把介面說下吧:

引數-f:輸入語言的簡寫,預設為auto
引數-t:翻譯語言的簡寫,預設為auto
引數-w:需要翻譯的內容 
http://fy.iciba.com/ajax.php?a=fy&f=auto&t=auto&w=text
複製程式碼

結果返回的樣式大概是這樣的,為了簡單明瞭,手動調整的,其中out就是翻譯結果,ciba_use就是被翻譯的內容:

{
    "status":1,
    "content":{
        "from":"zh-CN",
        "to":"en",
        "vendor":"tencent",
        "out":"It's a nice day.",
        "ciba_use":"\u6765\u81ea\u673a\u5668\u7ffb\u8bd1\u3002",
        "ciba_out":"",
        "err_no":0
    }
}
複製程式碼

結語

這個demo呢,就是識別中文還是挺準的,英文也挺準的,其他的日語、俄羅斯語什麼的呀,一頓哈賽就行了,反正我也認不出來(翻譯也不一定靠譜的,畢竟這個翻譯不是很準的哦)。就是那個標點符號麼有,我不知道是我手機的問題,還是我的英語太爛了。

這篇文章就這麼結束了?作者水平也太low了吧,?結束了,這個呢只是一時興起寫的一個demo,記錄一下,客官不必太在意。

相關文章