利用百度語音識別接口將語音轉換成文字教程


一、說明

如果有一個工具能識別音視中的語音並轉換成文字輸出,由於可以復制粘貼而不需要逐字逐句地打,那我們進行為音頻配字幕工作時將會事半功倍。

其中的關鍵點是音文轉換,音文轉換其實在很多地方都可以看到比如qq,百度搜索,訊飛輸入法等等,具體到技術而言前述的三個場景其背后的技術都是一樣的,都是利用AI進行語音識別。而且騰訊、百度、訊飛當前都開放了自家的語音識別接口免費使用,本文就是利用的百度語音識別接口實現的轉換。

其實就配字幕這種工作而言,當前應該可以實現通過寫代碼自動給音頻文件配上字幕,復制粘貼這步都可以省了,當然這不在本文的實現范圍。

另外AI識別有一定的錯誤率,在我們自己使用qq、百度、訊飛時應該都有體會,更何況開放出來的接口一般都不會是公司產品百分百的能力,所以肯定還是要人工介入修正。

 

二、音文轉換程序

2.1 程序說明

官方文檔:http://ai.baidu.com/docs#/ASR-API/top

語音識別接口:http://vop.baidu.com/server_api

接口要求:只接受pcm格式音頻,請求次數不限但每個音視不能超過60秒

系統環境:Windows-7 X64、Python-3.6.5 X64(miniconda)。minicoda安裝可參見“PyCharm+Miniconda3安裝配置教程”第二大點,如果直接安裝python網上搜搜教程即可。另外需要requests模塊所以裝完python后需要執行pip install requests安裝一下。

gihub地址:https://github.com/PrettyUp/BaiduAI。這里將程序和之前寫的程序都放在了BaiduAI項目錄,只管其中的vtt目錄即可。

程序支持:僅支持mp3格式文件,僅支持英語(要支持普通話將post的dev_pid參數修改為1536即可,參見官方文檔)

程序流程:獲取video目錄下的所有mp3文件並逐個進行處理----將當前要處理的mp3文件使用ffmpeg轉換成pcm格式----將生成的pcm文件使用speech-vad-demo切割----將切割后的pcm文件逐個進行音文轉換

運行操作:安裝好系統環境----將壓縮包解壓到任意目錄----將要轉換的mp3文件復制到video文件夾下----使用python運行baiduvi.py文件----程序執行完后在video文件夾下會為各mp3文件生成其同名.srt文件其中即是語音轉換成的文字。(首版代碼生成的是txt文件,按建議改為直接生成.srt格式字幕文件,操作等使用方式都沒改變)如下所示

 

2.2 程序代碼

程序自己寫的只有一個文件,我這里命名為baiduvi.py

import base64
import json
import os
import time
import shutil
import requests

class BaiduVoiceToTxt():
    # 初始化函數
    def __init__(self):
        # 定義要進行切割的pcm文件的位置。speech-vad-demo固定好的,沒的選
        self.pcm_path = ".\\speech-vad-demo\\pcm\\16k_1.pcm"
        # 定義pcm文件被切割后,分割成的文件輸出到的目錄。speech-vad-demo固定好的,沒的選
        self.output_pcm_path = ".\\speech-vad-demo\\output_pcm\\"

    # 百度AI接口只接受pcm格式,所以需要轉換格式
    # 此函數用於將要識別的mp3文件轉換成pcm格式,並輸出為.\speech-vad-demo\pcm\16k_1.pcm
    def change_file_format(self,filepath):
        file_name = filepath
        # 如果.\speech-vad-demo\pcm\16k_1.pcm文件已存在,則先將其刪除
        if os.path.isfile(f"{self.pcm_path}"):
            os.remove(f"{self.pcm_path}")
        # 調用系統命令,將文件轉換成pcm格式,並輸出為.\speech-vad-demo\pcm\16k_1.pcm
        change_file_format_command = f".\\ffmpeg\\bin\\ffmpeg.exe -y  -i {file_name}  -acodec pcm_s16le -f s16le -ac 1 -ar 16000 {self.pcm_path}"
        os.system(change_file_format_command)

    # 百度AI接口最長只接受60秒的音視,所以需要切割
    # 此函數用於將.\speech-vad-demo\pcm\16k_1.pcm切割
    def devide_video(self):
        # 如果切割輸出目錄.\speech-vad-demo\output_pcm\已存在,那其中很可能已有文件,先將其清空
        # 清空目錄的文件是先刪除,再創建
        if os.path.isdir(f"{self.output_pcm_path}"):
            shutil.rmtree(f"{self.output_pcm_path}")
        time.sleep(1)
        os.mkdir(f"{self.output_pcm_path}")
        # vad-demo.exe使用相對路徑.\pcm和.\output_pcm,所以先要將當前工作目錄切換到.\speech-vad-demo下不然vad-demo.exe找不到文件
        os.chdir(".\\speech-vad-demo\\")
        # 直接執行.\vad-demo.exe,其默認會將.\pcm\16k_1.pcm文件切割並輸出到.\output_pcm目錄下
        devide_video_command = ".\\vad-demo.exe"
        os.system(devide_video_command)
        # 切換回工作目錄
        os.chdir("..\\")

    # 此函數用於將.\speech-vad-demo\output_pcm\下的文件的文件名的時間格式化成0:00:00,000形式
    def format_time(self, msecs):
        # 一個小時毫秒數
        hour_msecs = 60 * 60 * 1000
        # 一分鍾對應毫秒數
        minute_msecs = 60 * 1000
        # 一秒鍾對應毫秒數
        second_msecs = 1000
        # 文件名的時間是毫秒需要先轉成秒。+500是為了四舍五入,//是整除
        # msecs = (msecs + 500) // 1000
        # 小時
        hour = msecs // hour_msecs
        if hour < 10:
            hour = f"0{hour}"
        # 扣除小時后剩余毫秒數
        hour_left_msecs = msecs % hour_msecs
        # 分鍾
        minute = hour_left_msecs // minute_msecs
        # 如果不足10分鍾那在其前補0湊成兩位數格式
        if minute < 10:
            minute = f"0{minute}"
        # 扣除分鍾后剩余毫秒數
        minute_left_msecs = hour_left_msecs % minute_msecs
        #
        second = minute_left_msecs // second_msecs
        # 如果秒數不足10秒,一樣在其前補0湊足兩位數格式
        if second < 10:
            second = f"0{second}"
        # 扣除秒后剩余毫秒數
        second_left_msecs = minute_left_msecs % second_msecs
        # 如果不足10毫秒或100毫秒,在其前補0湊足三位數格式
        if second_left_msecs < 10:
            second_left_msecs = f"00{second_left_msecs}"
        elif second_left_msecs < 100:
            second_left_msecs = f"0{second_left_msecs}"
        # 格式化成00:00:00,000形式,並返回
        time_format = f"{hour}:{minute}:{second},{second_left_msecs}"
        return time_format

    # 此函數用於申請訪問ai接口的access_token
    def get_access_token(self):
        # 此變量賦值成自己API Key的值
        client_id = 'f3wT23Otc8jXlDZ4HGtS4jfT'
        # 此變量賦值成自己Secret Key的值
        client_secret = 'YPPjW3E0VGPUOfZwhjNGVn7LTu3hwssj'
        auth_url = 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=' + client_id + '&client_secret=' + client_secret

        response_at = requests.get(auth_url)
        # 以json格式讀取響應結果
        json_result = json.loads(response_at.text)
        # 獲取access_token
        access_token = json_result['access_token']
        return access_token

    # 此函數用於將.\speech-vad-demo\output_pcm\下的單個文件由語音轉成文件
    def transfer_voice_to_srt(self,access_token,filepath):
        # 百度語音識別接口
        url_voice_ident = "http://vop.baidu.com/server_api"
        # 接口規范,以json格式post數據
        headers = {
            'Content-Type': 'application/json'
        }
        # 打開pcm文件並讀取文件內容
        pcm_obj = open(filepath,'rb')
        pcm_content_base64 = base64.b64encode(pcm_obj.read())
        pcm_obj.close()
        # 獲取pcm文件大小
        pcm_content_len = os.path.getsize(filepath)

        # 接口規范,則體函義見官方文件,值得注意的是cuid和speech兩個參數的寫法
        post_data = {
            "format": "pcm",
            "rate": 16000,
            "dev_pid": 1737,
            "channel": 1,
            "token": access_token,
            "cuid": "1111111111",
            "len": pcm_content_len,
            "speech": pcm_content_base64.decode(),
        }
        proxies = {
            'http':"127.0.0.1:8080"
        }
        # 調用接口,進行音文轉換
        response = requests.post(url_voice_ident, headers=headers, data=json.dumps(post_data))
        # response = requests.post(url_voice_ident,headers=headers,data=json.dumps(post_data),proxies=proxies)
        return response.text

if __name__ == "__main__":
    # 實例化
    baidu_voice_to_srt_obj = BaiduVoiceToTxt()
    # 自己要進行音文轉換的音視存放的文件夾
    video_dir = ".\\video\\"
    all_video_file =[]
    all_file = os.listdir(video_dir)
    subtitle_format = "{\\fscx75\\fscy75}"
    # 只接受.mp3格式文件。因為其他格式沒研究怎么轉成pcm才是符合接口要求的
    for filename in all_file:
        if ".mp3" in filename:
            all_video_file.append(filename)
    all_video_file.sort()
    i = 0
    video_file_num = len(all_video_file)
    print(f"當前共有{video_file_num}個音頻文件需要轉換,即將進行處理請稍等...")
    # 此層for循環是逐個mp3文件進行處理
    for video_file_name in all_video_file:
        i += 1
        print(f"當前轉換{video_file_name}({i}/{video_file_num})")
        # 將音視翻譯成的內容輸出到同目錄下同名.txt文件中
        video_file_srt_path = f".\\video\\{video_file_name[:-4]}.srt"
        # 以覆蓋形式打開.txt文件
        video_file_srt_obj = open(video_file_srt_path,'w+')

        filepath = os.path.join(video_dir, video_file_name)
        # 調用change_file_format將mp3轉成pcm格式
        baidu_voice_to_srt_obj.change_file_format(filepath)
        # 將轉換成的pcm文件切割成多個小於60秒的pcm文件
        baidu_voice_to_srt_obj.devide_video()
        # 獲取token
        access_token = baidu_voice_to_srt_obj.get_access_token()
        # 獲取.\speech-vad-demo\output_pcm\目錄下的文件列表
        file_dir = baidu_voice_to_srt_obj.output_pcm_path
        all_pcm_file = os.listdir(file_dir)
        all_pcm_file.sort()
        j = 0
        pcm_file_num = len(all_pcm_file)
        print(f"當前所轉文件{video_file_name}({i}/{video_file_num})被切分成{pcm_file_num}塊,即將逐塊進行音文轉換請稍等...")
        # 此層for是將.\speech-vad-demo\output_pcm\目錄下的所有文件逐個進行音文轉換
        for filename in all_pcm_file:
            j += 1
            filepath = os.path.join(file_dir, filename)
            if (os.path.isfile(filepath)):
                # 獲取文件名上的時間
                time_str = filename[10:-6]
                time_str_dict = time_str.split("-")
                time_start_str = baidu_voice_to_srt_obj.format_time(int(time_str_dict[0]))
                time_end_str = baidu_voice_to_srt_obj.format_time(int(time_str_dict[1]))
                print(f"當前轉換{video_file_name}({i}/{video_file_num})-{time_start_str}-{time_end_str}({j}/{pcm_file_num})")
                response_text = baidu_voice_to_srt_obj.transfer_voice_to_srt(access_token, filepath)
                # 以json形式讀取返回結果
                json_result = json.loads(response_text)
                # 將音文轉換結果寫入.srt文件
                video_file_srt_obj.writelines(f"{j}\r\n")
                video_file_srt_obj.writelines(f"{time_start_str} --> {time_end_str}\r\n")
                if json_result['err_no'] == 0:
                    print(f"{time_start_str}-{time_end_str}({j}/{pcm_file_num})轉換成功:{json_result['result'][0]}")
                    video_file_srt_obj.writelines(f"{subtitle_format}{json_result['result'][0]}\r\n")
                elif json_result['err_no'] == 3301:
                    print(f"{time_start_str}-{time_end_str}({j}/{pcm_file_num})音頻質量過差無法識別")
                    video_file_srt_obj.writelines(f"{subtitle_format}音頻質量過差無法識別\r\n")
                else:
                    print(f"{time_start_str}-{time_end_str}({j}/{pcm_file_num})轉換過程遇到其他錯誤")
                    video_file_srt_obj.writelines(f"{subtitle_format}轉換過程遇到其他錯誤\r\n")
                video_file_srt_obj.writelines(f"\r\n")
        video_file_srt_obj.close()

 

參考:

http://ai.baidu.com/docs#/ASR-API/top

http://ai.baidu.com/forum/topic/show/495449


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM