TextTranslatorOpenSource-文本翻譯器開源版

TextTranslatorOpenSource-文本翻譯器開源版

僅用于學(xué)習(xí)研究之用纲缓,請(qǐng)勿商用

介紹

【文本翻譯器】是一款免費(fèi)的簡(jiǎn)潔實(shí)用的翻譯軟件募胃。文本翻譯器應(yīng)用程序完全免費(fèi)驾荣,可以非城垂快速翻譯您的單詞框喳,幫助您與外國(guó)人交流唇兑。文本翻譯器適用于旅行者坎弯、學(xué)生纺涤、商人和其他語(yǔ)言愛好者,使用文本翻譯器可以輕松了解其他語(yǔ)言抠忘。文本翻譯器支持多國(guó)語(yǔ)言撩炊,全新領(lǐng)先的翻譯引擎,讓各種變得更加可靠有保證崎脉。界面設(shè)計(jì)簡(jiǎn)潔衰抑、優(yōu)雅,體積小巧荧嵌,但是功能很強(qiáng)大哦呛踊。趕快下載來(lái)試試吧~

功能特點(diǎn):

*【詞典解析】除了基本的翻譯外砾淌,提供更詳細(xì)的詞典功能,詞性分類
*【多語(yǔ)言】目前支持主流語(yǔ)言:中文谭网,中文繁體汪厨,英語(yǔ),日語(yǔ)愉择,法語(yǔ)劫乱,德語(yǔ)
*【單詞本】收藏喜歡的單詞
*【歷史記錄】記錄翻譯記錄
*【離線翻譯】如果已經(jīng)翻譯過(guò)的即使沒(méi)有網(wǎng)絡(luò)也能翻譯
*【數(shù)據(jù)備份和恢復(fù)】備份歷史翻譯記錄和恢復(fù)記錄
*【自動(dòng)朗讀】翻譯后為您朗讀
*【自動(dòng)復(fù)制】將翻譯文本自動(dòng)復(fù)制到剪貼板
*【全局復(fù)制查詞】在任何界面點(diǎn)復(fù)制就能查單詞
*【免費(fèi)】使用功能過(guò)程中完全免費(fèi)
*【界面簡(jiǎn)潔】界面設(shè)計(jì)優(yōu)雅、簡(jiǎn)潔

展示

如果無(wú)法顯示圖片锥涕,請(qǐng)移步到這里

下載

Google Play

https://play.google.com/store/apps/details?id=com.allever.app.translation.text

Baidu

https://shouji.baidu.com/software/26838949.html

項(xiàng)目地址

https://github.com/devallever/TranslationTextOpenSource

項(xiàng)目架構(gòu)

項(xiàng)目采用多組件 + MVP 架構(gòu)

項(xiàng)目組件架構(gòu)圖

  • common:通用模塊衷戈,包括基類和通用工具類,基本上所有模塊都依賴此模塊
  • commont:評(píng)分模塊
  • permission:申請(qǐng)權(quán)限模塊
  • recomend:推廣模塊
  • umeng:友盟統(tǒng)計(jì)
  • widget:通用UI組件模塊

項(xiàng)目包圖

  • app:基類和全局類
  • bean:實(shí)體類和EventBus事件類
  • function:功能類
  • ui:界面层坠,包括mvp
  • util:工具類

其中主要代碼是在ui和function這兩個(gè)包

如何使用

  • 項(xiàng)目需要依賴AndroidDependencyLib中的一個(gè)或多個(gè)模塊殖妇,請(qǐng)預(yù)先配置

https://github.com/devallever/AndroidDependencyLib

  • 把AndroidDependencyLib項(xiàng)目和本項(xiàng)目放同一個(gè)目錄下

  • 項(xiàng)目需要依賴AndroidUIKit中的一個(gè)或多個(gè)模塊,請(qǐng)預(yù)先配置

https://github.com/devallever/AndroidUIKit

接口

https://translate.google.cn/

翻譯接口

https://translate.google.cn/translate_a/single?client=gtx&dt=t&dt=bd&dt=rm&dj=1&ie=UTF-8&oe=UTF-8&sl=auto&tl=zh-CN&hl=zh-CN&tk=&q=cat

可以參考以下默認(rèn)值

    @GET("translate_a/single")
    fun translate(
        @Query("q") q: String,
        @Query("client") content: String = "gtx",
        @Query("dt") dt: String = "t",
        @Query("dt") dt1: String = "bd",
        @Query("dt") dt2: String = "rm",
        @Query("dj") dj: String = "1",
        @Query("ie") ie: String = "UTF-8",
        @Query("oe") oe: String = "UTF-8",
        @Query("sl") sl: String = "auto",
        @Query("tl") tl: String = "en",
        @Query("hl") hl: String = "zh-CN",
        @Query("tk") tk: String = ""

    ): Observable<TranslationBean>

主要用到sl破花、tl和q這幾個(gè)參數(shù)

  • sl:原語(yǔ)種
  • tl:翻譯語(yǔ)種
  • q:翻譯文本

關(guān)于語(yǔ)種可以參考項(xiàng)目中Languages這個(gè)類伞租,包含了100多個(gè)語(yǔ)種代碼

  • Languages

返回json對(duì)應(yīng)TranslationBean.kt這個(gè)實(shí)體類

/***
 * {"sentences":[{"trans":"串","orig":"string","backend":2},{"translit":"Chuàn","src_translit":"striNG"}],"dict":[{"pos":"名詞","terms":["串","弦","線","繩","繩子","細(xì)線","鞭","緄"],"entry":[{"word":"串","reverse_translation":["string"],"score":0.13323711},{"word":"弦","reverse_translation":["string","chord","bowstring","hypotenuse","subtense","string of musical instrument"],"score":0.016418032},{"word":"線","reverse_translation":["line","wire","thread","string","route","filament"],"score":0.0058540297},{"word":"繩","reverse_translation":["rope","cord","string"],"score":0.00477792},{"word":"繩子","reverse_translation":["rope","string","cord"],"score":0.0023652418},{"word":"細(xì)線","reverse_translation":["thread","string"],"score":2.2698537E-4},{"word":"鞭","reverse_translation":["whip","lash","string","firecracker","iron staff used as a weapon"],"score":8.139759E-6},{"word":"緄","reverse_translation":["cord","embroidered sash","string"],"score":2.4439987E-6}],"base_form":"string","pos_enum":1},{"pos":"動(dòng)詞","terms":["紉"],"entry":[{"word":"紉","reverse_translation":["thread","string"],"score":4.860472E-6}],"base_form":"string","pos_enum":2}],"src":"en","confidence":0.9488189,"ld_result":{"srclangs":["en"],"srclangs_confidences":[0.9488189],"extended_srclangs":["en"]}}
 */
@Keep
class TranslationBean {
    /**
     * sentences : [{"trans":"串","orig":"string","backend":2},{"translit":"Chuàn","src_translit":"striNG"}]
     * dict : [{"pos":"名詞","terms":["串","弦","線","繩","繩子","細(xì)線","鞭","緄"],"entry":[{"word":"串","reverse_translation":["string"],"score":0.13323711},{"word":"弦","reverse_translation":["string","chord","bowstring","hypotenuse","subtense","string of musical instrument"],"score":0.016418032},{"word":"線","reverse_translation":["line","wire","thread","string","route","filament"],"score":0.0058540297},{"word":"繩","reverse_translation":["rope","cord","string"],"score":0.00477792},{"word":"繩子","reverse_translation":["rope","string","cord"],"score":0.0023652418},{"word":"細(xì)線","reverse_translation":["thread","string"],"score":2.2698537E-4},{"word":"鞭","reverse_translation":["whip","lash","string","firecracker","iron staff used as a weapon"],"score":8.139759E-6},{"word":"緄","reverse_translation":["cord","embroidered sash","string"],"score":2.4439987E-6}],"base_form":"string","pos_enum":1},{"pos":"動(dòng)詞","terms":["紉"],"entry":[{"word":"紉","reverse_translation":["thread","string"],"score":4.860472E-6}],"base_form":"string","pos_enum":2}]
     * src : en
     * confidence : 0.9488189
     * ld_result : {"srclangs":["en"],"srclangs_confidences":[0.9488189],"extended_srclangs":["en"]}
     */

    var src: String? = null
    var confidence: Double = 0.toDouble()
    var ld_result: LdResultBean? = null
    var sentences: List<SentencesBean>? = null
    var dict: List<DictBean>? = null

    @Keep
    class LdResultBean {
        var srclangs: List<String>? = null
        var srclangs_confidences: List<Double>? = null
        var extended_srclangs: List<String>? = null
    }

    @Keep
    class SentencesBean {
        /**
         * trans : 串
         * orig : string
         * backend : 2
         * translit : Chuàn
         * src_translit : striNG
         */

        var trans: String? = null
        var orig: String? = null
        var backend: Int = 0
        var translit: String? = null
        var src_translit: String? = null
    }

    @Keep
    class DictBean {
        /**
         * pos : 名詞
         * terms : ["串","弦","線","繩","繩子","細(xì)線","鞭","緄"]
         * entry : [{"word":"串","reverse_translation":["string"],"score":0.13323711},{"word":"弦","reverse_translation":["string","chord","bowstring","hypotenuse","subtense","string of musical instrument"],"score":0.016418032},{"word":"線","reverse_translation":["line","wire","thread","string","route","filament"],"score":0.0058540297},{"word":"繩","reverse_translation":["rope","cord","string"],"score":0.00477792},{"word":"繩子","reverse_translation":["rope","string","cord"],"score":0.0023652418},{"word":"細(xì)線","reverse_translation":["thread","string"],"score":2.2698537E-4},{"word":"鞭","reverse_translation":["whip","lash","string","firecracker","iron staff used as a weapon"],"score":8.139759E-6},{"word":"緄","reverse_translation":["cord","embroidered sash","string"],"score":2.4439987E-6}]
         * base_form : string
         * pos_enum : 1
         */

        var pos: String? = null
        var base_form: String? = null
        var pos_enum: Int = 0
        var terms: List<String>? = null
        var entry: List<EntryBean>? = null

        @Keep
        class EntryBean {
            /**
             * word : 串
             * reverse_translation : ["string"]
             * score : 0.13323711
             */

            var word: String? = null
            var score: Double = 0.toDouble()
            var reverse_translation: List<String>? = null
        }
    }
}

  • sentences 字段含原文本和翻譯文本
  • dict 字段包含詞典信息
  • 解析獲取對(duì)應(yīng)字段的內(nèi)容在 TranslationHelper 中

語(yǔ)音接口

https://translate.google.cn/translate_tts?client=gtx&ie=UTF-8&tl=zh-CN&total=1&idx=0&textlen=2&tk=&q=setting

其中主要用到 tl 和 q 參數(shù)休里,同上

可以參考以下默認(rèn)值

    @GET("translate_tts")
    fun requestTTS(
        @Query("q") q: String,
        @Query("client") content: String = "gtx",
        @Query("ie") ie: String = "UTF-8",
        @Query("tl") tl: String = "en",
        @Query("hl") hl: String = "zh-CN",
        @Query("total") total: String = "1",
        @Query("idx") idx: String = "0",
        @Query("textlen") textlen: String = "0",
        @Query("tk") tk: String = ""
    ): Call<ResponseBody>

翻譯基本流程

項(xiàng)目采用MVP架構(gòu)

  • TranslationFragment:調(diào)用presenter接口進(jìn)行請(qǐng)求翻譯
mPresenter.translate(content, sl, tl)
  • TranslationPresenter:調(diào)用RetrofitUtil進(jìn)行網(wǎng)絡(luò)請(qǐng)求逆屡,并回調(diào)TranslationView的接口刷新界面
  • DBHelper:負(fù)責(zé)存取翻譯記錄
   fun translate(content: String, sl: String = Lang.AUTO.CODE, translateLanguage: String) {
       if (content.isEmpty()) {
           toast(R.string.please_input_content)
           return
       }

       val history = DBHelper.getHistory(content, sl, translateLanguage)
       val translationBean =
           JsonHelper.json2Object(history?.result ?: "", TranslationBean::class.java)
       if (translationBean != null) {
           parse(translationBean)
           mViewRef?.get()?.refreshLiked(history?.liked == 1)
           val translateText = TranslationHelper.getTranslateText(translationBean)
           if (translateText.isNotEmpty()) {
               play(translateText, translateLanguage)
               copyToClipBoard(translateText)
           }
           log("獲取到數(shù)據(jù)庫(kù)翻譯內(nèi)容")
           DBHelper.updateHistoryTime(history)
           EventBus.getDefault().post(UpdateRecordEvent())
           return
       }

       RetrofitUtil.translate(object : Subscriber<TranslationBean>() {
           override fun onCompleted() {}
           override fun onError(e: Throwable) {
               e.printStackTrace()
               log("失敗")
           }

           override fun onNext(bean: TranslationBean) {
               parse(bean)
               val translateText = TranslationHelper.getTranslateText(bean)

               mViewRef?.get()?.refreshLiked(false)

               play(translateText, translateLanguage)

               copyToClipBoard(translateText)

               DBHelper.addHistory(content, sl, translateLanguage, bean)

               EventBus.getDefault().post(UpdateRecordEvent())

           }
       }, content, sl, translateLanguage)
   }
  • TranslationHelper:負(fù)責(zé)解析數(shù)據(jù)
  • TranslationView:刷新界面
    private fun parse(bean: TranslationBean) {

        val srcSymbol = TranslationHelper.getSrcSymbol(bean)
        val translateSymbol = TranslationHelper.getTranslateSymbol(bean)
        //音標(biāo)顯示邏輯
        if (srcSymbol.isNotEmpty()) {
            mViewRef?.get()?.showOrHideSoundSrcSymbol(true)
        } else {
            mViewRef?.get()?.showOrHideSoundSrcSymbol(false)
        }
        if (translateSymbol.isNotEmpty()) {
            mViewRef?.get()?.showOrHideSoundTranslateSymbol(true)
        } else {
            mViewRef?.get()?.showOrHideSoundTranslateSymbol(false)
        }

        if (TranslationHelper.getDictText(bean).isNotEmpty()) {
            mViewRef?.get()?.showOrHideDictInfo(true)
        } else {
            mViewRef?.get()?.showOrHideDictInfo(false)
        }

        mViewRef?.get()?.updateResult(
            bean,
            TranslationHelper.getSrcLang(bean),
            TranslationHelper.getSrcText(bean),
            TranslationHelper.getSrcSymbol(bean),
            TranslationHelper.getTranslateText(bean),
            TranslationHelper.getTranslateSymbol(bean),
            TranslationHelper.getDictText(bean)
        )
    }

以上就是翻譯的基本流程

復(fù)制查詞功能實(shí)現(xiàn)

  • 監(jiān)聽粘貼板變化并彈出Dialog風(fēng)格的Activity高诺,當(dāng)在應(yīng)用內(nèi)復(fù)制時(shí)候,不彈出峭梳。
        val clipBoardManager = getSystemService(Context.CLIPBOARD_SERVICE) as ClipboardManager
        clipBoardManager.addPrimaryClipChangedListener {
            log("剪貼板變化")
            if (ActivityCollector.size() == 0 && SettingHelper.getAutoTranslate()) {
                val srcText = clipBoardManager.primaryClip?.getItemAt(0)?.text.toString()
                DialogTranslateActivity.start(this, srcText)
            }
        }

通知欄常駐

  • 啟動(dòng)一個(gè)前臺(tái)服務(wù) TranslationService 苯⒒妫活
    override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
        log("啟動(dòng)服務(wù)")
        val paddingFlag = 1
        val pendingIntent = PendingIntent.getActivity(
            this,
            0,
            Intent(this, MainDrawerActivity::class.java),
            PendingIntent.FLAG_UPDATE_CURRENT,
            null
        )
        val notificationBuilder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            val channelId = "translation"
            val channelName = "翻譯"
            val importance = NotificationManager.IMPORTANCE_HIGH
            createNotificationChannel(channelId, channelName, importance)
            NotificationCompat.Builder(this, channelId)
                .setNumber(paddingFlag)
        } else {
            NotificationCompat.Builder(this)
        }
        notificationBuilder
            .setContentTitle(getString(R.string.app_name))
            .setContentText(getString(R.string.notification_msg, getString(R.string.app_name)))
            .setSmallIcon(R.drawable.ic_logo)
            .setLargeIcon(BitmapFactory.decodeResource(resources, R.drawable.ic_logo))
            .setContentIntent(pendingIntent)
        startForeground(1, notificationBuilder.build())
        return super.onStartCommand(intent, flags, startId)
    }

離線翻譯功能

將翻譯過(guò)的記錄保存下來(lái),即每次請(qǐng)求網(wǎng)絡(luò)翻譯時(shí)候就保存記錄

//sl:原語(yǔ)種代碼
//translateLanguage:翻譯語(yǔ)種代碼
//bean:TranslationBean請(qǐng)求翻譯的實(shí)體類
DBHelper.addHistory(content, sl, translateLanguage, bean)

通過(guò)History這個(gè)實(shí)體類保存翻譯記錄

    fun addHistory(content: String, sl: String, tl: String, bean: TranslationBean) {
        run {
            try {
                val history = History()
                history.srcText = content
                history.sl = sl
                history.tl = tl
                history.time = System.currentTimeMillis()
                history.liked = 0
                history.result = Gson().toJson(bean)
                history.ttsPath = MD5.getMD5StrToLowerCase("$content$tl.mp3")
                val saveResult = history.save()
                if (saveResult) {
                    log("保存翻譯成功")
                } else {
                    loge("保存翻譯失敗")
                }
            } catch (e: Exception) {
                e.printStackTrace()
                loge("保存翻譯失敗")
            }
        }
    }

History實(shí)體類

@Keep
class History : LitePalSupport() {
    var srcText: String = ""
    var sl: String = "en"
    var tl: String = "en"
    var time: Long = 0
    var liked: Int = 0
    //全路徑
    var ttsPath: String = ""
    var result: String = ""
}

每次請(qǐng)求就先獲取本地記錄

        val history = DBHelper.getHistory(content, sl, translateLanguage)
        val translationBean =
            JsonHelper.json2Object(history?.result ?: "", TranslationBean::class.java)
        if (translationBean != null) {
            parse(translationBean)
            mViewRef?.get()?.refreshLiked(history?.liked == 1)
            val translateText = TranslationHelper.getTranslateText(translationBean)
            if (translateText.isNotEmpty()) {
                play(translateText, translateLanguage)
                copyToClipBoard(translateText)
            }
            log("獲取到數(shù)據(jù)庫(kù)翻譯內(nèi)容")
            DBHelper.updateHistoryTime(history)
            EventBus.getDefault().post(UpdateRecordEvent())
            return
        }

歷史記錄和單詞本

  • 單詞本從數(shù)據(jù)庫(kù)中按條件查找like = 1 的記錄葱椭,除盏,四種情況就是選中所要查找的語(yǔ)言
    fun getLikedHistory(sl: String, tl: String) {
        run {
            try {
                //四種情況
                var historyList = mutableListOf<History>()
                if (sl.isEmpty() && tl.isEmpty()) {
                    //查所有
                    historyList =
                        LitePal.where("liked = ?", "1").order("time desc").find(History::class.java)
                }

                if (sl.isNotEmpty() && tl.isNotEmpty()) {
                    historyList = LitePal
                        .where("sl = ? and tl = ? and liked = ?", sl, tl, "1")
                        .order("time desc")
                        .find(History::class.java)
                }

                if (sl.isEmpty() && tl.isNotEmpty()) {
                    historyList = LitePal
                        .where("tl = ? and liked = ?", tl, "1")
                        .order("time desc")
                        .find(History::class.java)
                }

                if (sl.isNotEmpty() && tl.isEmpty()) {
                    historyList = LitePal
                        .where("sl = ? and liked = ?", sl, "1")
                        .order("time desc")
                        .find(History::class.java)
                }
                val wordItemList = mutableListOf<WordItem>()
                historyList.map {
                    val wordItem = WordItem()
                    wordItem.history = it
                    wordItem.checked = false
                    wordItemList.add(wordItem)
                }
                mViewRef?.get()?.updateWordList(wordItemList)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }
  • 歷史記錄就是全部記錄,四種情況就是選中所要查找的語(yǔ)言
    fun getHistory(sl: String, tl: String) {
        run {
            try {
                //四種情況
                var historyList = mutableListOf<History>()
                if (sl.isEmpty() && tl.isEmpty()) {
                    //查所有
                    historyList = (LitePal.order("time desc").find(History::class.java))
                }

                if (sl.isNotEmpty() && tl.isNotEmpty()) {
                    historyList = LitePal
                        .where("sl = ? and tl = ?", sl, tl)
                        .order("time desc")
                        .find(History::class.java)
                }

                if (sl.isEmpty() && tl.isNotEmpty()) {
                    historyList = LitePal
                        .where("tl = ?", tl)
                        .order("time desc")
                        .find(History::class.java)
                }

                if (sl.isNotEmpty() && tl.isEmpty()) {
                    historyList = LitePal
                        .where("sl = ?", sl)
                        .order("time desc")
                        .find(History::class.java)
                }
                val wordItemList = mutableListOf<WordItem>()
                historyList.map {
                    val wordItem = WordItem()
                    wordItem.history = it
                    wordItem.checked = false
                    wordItemList.add(wordItem)
                }
                mViewRef?.get()?.updateWordList(wordItemList)
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

數(shù)據(jù)備份和恢復(fù)功能

將所有History記錄取出來(lái)挫以,封裝成BackupBean者蠕,再轉(zhuǎn)成json保存到文件中

val historyList = DBHelper.getAllHistory()
if (historyList.isEmpty()) {
  toast(R.string.no_backup_data)
  task.run()
  return
}
val backupBean = BackupBean()
backupBean.data = historyList
val result = Gson().toJson(backupBean)
log("backupResult = $result")
val success = FileUtil.saveStringToFile(result, BACKUP_FILE_PATH)
if (success) {
  toast(R.string.backup_success)
} else {
  toast(R.string.backup_fail)
}
...

最后一個(gè)是百度的語(yǔ)音識(shí)別功能

項(xiàng)目中集成了百度語(yǔ)音識(shí)別,但控件被隱藏掐松,邏輯還是有的踱侣,通過(guò)一個(gè)ImageView觸發(fā)。
識(shí)別功能封裝在baiduvoice模塊中的BaiduVoiceHelper

object BaiduVoiceHelper : EventListener {

    private var mEventManager: EventManager? = null
    private var mRecognizedListenerList = mutableListOf<RecognizedListener>()
    private var mRecognizedType: RecognizedType = RecognizedType.CHINESE
//    private var mListener: RecognizedListener? = null

    //重新識(shí)別
    private var mNeedReRecognized = true

    fun init() {
        mEventManager = EventManagerFactory.create(App.context, "asr")
        mEventManager?.registerListener(this)
    }

    fun setRecognizedListener(recognizedListener: RecognizedListener) {
        mRecognizedListenerList.add(recognizedListener)
    }

    fun removeRecognised(recognizedListener: RecognizedListener) {
        mRecognizedListenerList.remove(recognizedListener)
    }

    fun startRecognize(type: RecognizedType = mRecognizedType) {
        mNeedReRecognized = true
        mRecognizedType = type
        val params = LinkedHashMap<String, Any>()
        var event: String? = null
        event = SpeechConstant.ASR_START // 替換成測(cè)試的event

        // 基于SDK集成2.1 設(shè)置識(shí)別參數(shù)
        params[SpeechConstant.ACCEPT_AUDIO_VOLUME] = false
        // params.put(SpeechConstant.NLU, "enable");
        // params.put(SpeechConstant.VAD_ENDPOINT_TIMEOUT, 0); // 長(zhǎng)語(yǔ)音
        // params.put(SpeechConstant.IN_FILE, "res:///com/baidu/android/voicedemo/16k_test.pcm");
        // params.put(SpeechConstant.VAD, SpeechConstant.VAD_DNN);
        if (mRecognizedType == RecognizedType.ENGLISH) {
            params[SpeechConstant.PID] = 1737 //英語(yǔ)
        } else {
            params[SpeechConstant.PID] = 15362 //普通話搜索模型, 默認(rèn)
        }


        /* 語(yǔ)音自訓(xùn)練平臺(tái)特有參數(shù) */
        // params.put(SpeechConstant.PID, 8002);
        // 語(yǔ)音自訓(xùn)練平臺(tái)特殊pid大磺,8002:搜索模型類似開放平臺(tái) 1537  具體是8001還是8002抡句,看自訓(xùn)練平臺(tái)頁(yè)面上的顯示
        // params.put(SpeechConstant.LMID,1068); // 語(yǔ)音自訓(xùn)練平臺(tái)已上線的模型ID,https://ai.baidu.com/smartasr/model
        // 注意模型ID必須在你的appId所在的百度賬號(hào)下
        /* 語(yǔ)音自訓(xùn)練平臺(tái)特有參數(shù) */

        // 請(qǐng)先使用如‘在線識(shí)別’界面測(cè)試和生成識(shí)別參數(shù)杠愧。 params同ActivityRecog類中myRecognizer.start(params);
        // 復(fù)制此段可以自動(dòng)檢測(cè)錯(cuò)誤
        AutoCheck(App.context, @SuppressLint("HandlerLeak")
        object : Handler() {
            override fun handleMessage(msg: Message) {
                if (msg.what == 100) {
                    val autoCheck = msg.obj as AutoCheck
                    synchronized(autoCheck) {
                        val message =
                            autoCheck.obtainErrorMessage() // autoCheck.obtainAllMessage();
//                        txtLog.append(message + "\n")
                        log(message)
                        // Log.w("AutoCheckMessage", message);
                    }// 可以用下面一行替代待榔,在logcat中查看代碼
                }
            }
        }, false).checkAsr(params)
        var json: String? = null // 可以替換成自己的json
        json = JSONObject(params as Map<*, *>).toString() // 這里可以替換成你需要測(cè)試的json
        mEventManager?.send(event, json, null, 0, 0)
        log("開始識(shí)別: 輸入?yún)?shù):$json")
    }

    fun stopRecognize() {
        mNeedReRecognized = false
        log("停止識(shí)別:ASR_STOP")
        mEventManager?.send(SpeechConstant.ASR_STOP, null, null, 0, 0) //
    }

    fun destroy() {
        stopRecognize()
        mEventManager?.unregisterListener(this)
    }

    // 基于sdk集成1.2 自定義輸出事件類 EventListener 回調(diào)方法
    // 基于SDK集成3.1 開始回調(diào)事件
    override fun onEvent(
        name: String,
        params: String?,
        data: ByteArray?,
        offset: Int,
        length: Int
    ) {
        var logTxt = "name: $name"


        if (params != null && !params.isEmpty()) {
            logTxt += " ;params :$params"
        }
        if (data != null) {
            logTxt += " ;data length=" + data.size
        }
        log(logTxt)

        if (params?.contains("final_result") == true) {
            loge("最后識(shí)別結(jié)果: $logTxt")
            try {
                val jsonObject = JSONObject(params)
                val result = jsonObject.getString("best_result")?:""
                mRecognizedListenerList.map {
                    it.onResult(params, result)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }

        if (name == "asr.exit" && mNeedReRecognized) {
            startRecognize()
            //重新識(shí)別
        }
    }
}

用到的開源項(xiàng)目

  • Eventbus
  • LitePal: 數(shù)據(jù)庫(kù)
  • RxJava/RxAndroid
  • Retrofit/Okhttp
  • Glide

更多項(xiàng)目

VirtualCallOpenSource-虛擬來(lái)電開源版

LoseWeight-減肥健身App開源版

最后

如果喜歡,請(qǐng)star
最重要一點(diǎn),請(qǐng)勿商用锐锣。
如非必要腌闯,請(qǐng)更改包名,類名雕憔,包結(jié)構(gòu)姿骏。
謝謝。

我的Github

https://github.com/devallever

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末斤彼,一起剝皮案震驚了整個(gè)濱河市分瘦,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌琉苇,老刑警劉巖嘲玫,帶你破解...
    沈念sama閱讀 221,548評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異并扇,居然都是意外死亡去团,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,497評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門拜马,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)渗勘,“玉大人沐绒,你說(shuō)我怎么就攤上這事俩莽。” “怎么了乔遮?”我有些...
    開封第一講書人閱讀 167,990評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵扮超,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我蹋肮,道長(zhǎng)出刷,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,618評(píng)論 1 296
  • 正文 為了忘掉前任坯辩,我火速辦了婚禮馁龟,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘漆魔。我一直安慰自己坷檩,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,618評(píng)論 6 397
  • 文/花漫 我一把揭開白布改抡。 她就那樣靜靜地躺著矢炼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪阿纤。 梳的紋絲不亂的頭發(fā)上句灌,一...
    開封第一講書人閱讀 52,246評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音欠拾,去河邊找鬼胰锌。 笑死骗绕,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的匕荸。 我是一名探鬼主播爹谭,決...
    沈念sama閱讀 40,819評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼榛搔!你這毒婦竟也來(lái)了诺凡?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,725評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤践惑,失蹤者是張志新(化名)和其女友劉穎腹泌,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體尔觉,經(jīng)...
    沈念sama閱讀 46,268評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡凉袱,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,356評(píng)論 3 340
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了侦铜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片专甩。...
    茶點(diǎn)故事閱讀 40,488評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖钉稍,靈堂內(nèi)的尸體忽然破棺而出涤躲,到底是詐尸還是另有隱情,我是刑警寧澤贡未,帶...
    沈念sama閱讀 36,181評(píng)論 5 350
  • 正文 年R本政府宣布种樱,位于F島的核電站,受9級(jí)特大地震影響俊卤,放射性物質(zhì)發(fā)生泄漏嫩挤。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,862評(píng)論 3 333
  • 文/蒙蒙 一消恍、第九天 我趴在偏房一處隱蔽的房頂上張望岂昭。 院中可真熱鬧,春花似錦狠怨、人聲如沸约啊。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,331評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棍苹。三九已至,卻和暖如春茵汰,著一層夾襖步出監(jiān)牢的瞬間枢里,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,445評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留栏豺,地道東北人彬碱。 一個(gè)月前我還...
    沈念sama閱讀 48,897評(píng)論 3 376
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像奥洼,于是被迫代替她去往敵國(guó)和親巷疼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,500評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 蝌蚪 騎天大勝 焦點(diǎn)少年班堅(jiān)持分享第289天 星期二 2018.5.8 其實(shí)我早已經(jīng)不想寫幾篇文章灵奖,但是因?yàn)槊刻?..
    騎天大勝閱讀 169評(píng)論 0 0
  • 今日中秋嚼沿,只見秋雨不見月。 秋雨平添了蕭瑟和戚傷瓷患。剎那間骡尽,想起2004年的中秋。重慶擅编,抹不掉的熱攀细,假期的林蔭道,來(lái)...
    卓犖_11閱讀 160評(píng)論 0 0
  • 那大坪場(chǎng)上的,孤寂的孩子锦担,一個(gè)人靜靜地站在那兒 突然之間俭识,他哭了起來(lái),斷斷續(xù)續(xù)的吆豹,喉嚨似乎有點(diǎn)抽搐鱼的,帶有“嗯”的哭...
    昆悠閱讀 114評(píng)論 0 4
  • 今日水果理盆,蘋果痘煤。 晚上下班有點(diǎn)事情,沒(méi)來(lái)的急走猿规,待公司測(cè)試問(wèn)題衷快,一天忙的不可開交。 感覺(jué)頭都沒(méi)抬姨俩,就過(guò)去了蘸拔。碌碌無(wú)...
    Time煮雨閱讀 88評(píng)論 0 1