用 Python 將音頻內(nèi)容轉(zhuǎn)換為文本格式

/文章源自:Python中文社區(qū)/
當(dāng)對(duì)一個(gè)或多個(gè)人的談話進(jìn)行記錄時(shí),采用一種高度準(zhǔn)確和自動(dòng)化的方式將口語(yǔ)提取為文本非常有用。轉(zhuǎn)換成文字后,便可以將其用于進(jìn)一步分析或用作其他功能。
在本教程中,我們將使用稱為AssemblyAI(https://www.assemblyai.com/)的高精度語(yǔ)音轉(zhuǎn)文本W(wǎng)eb API從MP3錄音中提取文本(也支持許多其他格式)。
在本教程中,音頻文件示例下載地址請(qǐng)掃描本文下方二維碼添加Python小助手獲取,下面是音頻輸出如下所示的高精度文本轉(zhuǎn)錄內(nèi)容:
An?object?relational?mapper?is?a?code?library?that?automates?the?transfer?of?
data?stored?in?relational,?databases?into?objects?that?are?more?commonly?used
in?application?code?or?EMS?are?useful?because?they?provide?a?high?level?
abstraction?upon?a?relational?database?that?allows?developers?to?write?Python?
code?instead?of?sequel?to?create?read?update?and?delete,?data?and?schemas?in?
their?database.?Developers?can?use?the?programming?language.?They?are?
comfortable?with?to?work?with?a?database?instead?of?writing?SQL...
教程要求
在本教程中,我們將使用以下依賴項(xiàng),稍后將安裝它們。請(qǐng)確保您的環(huán)境中還安裝了Python 3,最好安裝3.6或更高版本:
我們將使用以下依賴關(guān)系來(lái)完成本教程:
requests 2.24.0 ?來(lái)向AssemblyAI語(yǔ)音文本API發(fā)出HTTP請(qǐng)求
一個(gè) AssemblyAI 帳戶,您可以在此處(
https://app.assemblyai.com/login/)注冊(cè)免費(fèi)的API訪問(wèn)密鑰
本文所有代碼下載地址請(qǐng)掃描本文下方二維碼添加Python小助手獲取。
搭建開(kāi)發(fā)環(huán)境
轉(zhuǎn)到保存Python虛擬環(huán)境的目錄。我將我的目錄保存在用戶主目錄下的venvs子目錄中。使用以下命令為此項(xiàng)目創(chuàng)建一個(gè)新的virtualenv。
python3?-m?venv?~/venvs/pytranscribe
用 shell 命令激活?virtualenv:
source?~/venvs/pytranscribe/bin/activate
執(zhí)行上述命令后,命令提示符將發(fā)生更改,因此virtualenv的名稱將以原始命令提示符格式開(kāi)頭,如果您的提示符只是$,則其外觀如下所示:
(pytranscribe)?$
請(qǐng)記住,您必須在每個(gè) virtualenv 中使用依賴項(xiàng)的新終端窗口中激活您的 virtualenv 。
現(xiàn)在,我們可以將請(qǐng)求包安裝到已激活但為空的 virtualenv 中。
pip?install?requests==2.24.0
查找類似于以下內(nèi)容的輸出,以確認(rèn)從PyPI正確安裝了相應(yīng)的軟件包。
(pytranscribe)?$?pip?install?requests==2.24.0
Collecting?requests==2.24.0
??Using?cached?https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl
Collecting?certifi>=2017.4.17?(from?requests==2.24.0)
??Using?cached?https://files.pythonhosted.org/packages/5e/c4/6c4fe722df5343c33226f0b4e0bb042e4dc13483228b4718baf286f86d87/certifi-2020.6.20-py2.py3-none-any.whl
Collecting?urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1?(from?requests==2.24.0)
??Using?cached?https://files.pythonhosted.org/packages/9f/f0/a391d1463ebb1b233795cabfc0ef38d3db4442339de68f847026199e69d7/urllib3-1.25.10-py2.py3-none-any.whl
Collecting?chardet<4,>=3.0.2?(from?requests==2.24.0)
??Using?cached?https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
Collecting?idna<3,>=2.5?(from?requests==2.24.0)
??Using?cached?https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl
Installing?collected?packages:?certifi,?urllib3,?chardet,?idna,?requests
Successfully?installed?certifi-2020.6.20?chardet-3.0.4?idna-2.10?requests-2.24.0?urllib3-1.25.10
我們已經(jīng)安裝了所有必需的依賴項(xiàng),因此我們可以開(kāi)始對(duì)應(yīng)用程序進(jìn)行編碼。
上傳、啟動(dòng)和轉(zhuǎn)錄音頻
我們已完成開(kāi)始構(gòu)建應(yīng)用程序所需的一切,該應(yīng)用程序會(huì)將音頻轉(zhuǎn)換為文本。我們將在三個(gè)文件中構(gòu)建此應(yīng)用程序:
1、upload_audio_file.py:將您的音頻文件上傳到AssemblyAI服務(wù)上的安全位置,以便可以進(jìn)行處理。如果您的音頻文件已經(jīng)可以通過(guò)公共URL訪問(wèn),則無(wú)需執(zhí)行此步驟,只需按照此快速入門(mén)(https://docs.assemblyai.com/overview/getting-started)
2、initial_transcription.py:告訴API要轉(zhuǎn)錄并立即啟動(dòng)的文件
3、get_transcription.py:如果仍在處理轉(zhuǎn)錄,則顯示轉(zhuǎn)錄狀態(tài),或者在處理完成后顯示轉(zhuǎn)錄結(jié)果
創(chuàng)建一個(gè)名為pytranscribe的新目錄,以在我們編寫(xiě)文件時(shí)存儲(chǔ)這些文件。然后轉(zhuǎn)到新的項(xiàng)目目錄。
mkdir?pytranscibe
cd?pytranscribe
我們還需要將 AssemblyAI API 密鑰導(dǎo)出為環(huán)境變量。注冊(cè) AssemblyAI 帳戶并登錄 AssemblyAI 儀表板,然后復(fù)制“您的API token”,如以下屏幕截圖所示:

export?ASSEMBLYAI_KEY=your-api-key-here
請(qǐng)注意,必須每個(gè)命令行窗口中使用?export?命令以保證此密鑰可訪問(wèn)。如果您沒(méi)有在運(yùn)行腳本的環(huán)境中將標(biāo)記導(dǎo)出為?ASSEMBLYAI_KEY,則我們正在編寫(xiě)的腳本將無(wú)法訪問(wèn)API。
現(xiàn)在我們已經(jīng)創(chuàng)建了項(xiàng)目目錄并將API密鑰設(shè)置為環(huán)境變量,讓我們繼續(xù)編寫(xiě)第一個(gè)文件的代碼,該文件會(huì)將音頻文件上傳到AssemblyAI服務(wù)。
上傳音頻文件并進(jìn)行轉(zhuǎn)錄
創(chuàng)建一個(gè)名為upload_audio_file.py的新文件,并將以下代碼放入其中:
import?argparse
import?os
import?requests
API_URL?=?"https://api.assemblyai.com/v2/"
def?upload_file_to_api(filename):
????"""Checks?for?a?valid?file?and?then?uploads?it?to?AssemblyAI
????so?it?can?be?saved?to?a?secure?URL?that?only?that?service?can?access.
????When?the?upload?is?complete?we?can?then?initiate?the?transcription
????API?call.
????Returns?the?API?JSON?if?successful,?or?None?if?file?does?not?exist.
????"""
????if?not?os.path.exists(filename):
????????return?None
????def?read_file(filename,?chunk_size=5242880):
????????with?open(filename,?'rb')?as?_file:
????????????while?True:
????????????????data?=?_file.read(chunk_size)
????????????????if?not?data:
????????????????????break
????????????????yield?data
????headers?=?{'authorization':?os.getenv("ASSEMBLYAI_KEY")}
????response?=?requests.post("".join([API_URL,?"upload"]),?headers=headers,
?????????????????????????????data=read_file(filename))
????return?response.json()
上面的代碼導(dǎo)入了argparse,os和request軟件包,以便我們可以在此腳本中使用它們。API_URL是一個(gè)常量,具有AssemblyAI服務(wù)的基本URL。我們使用單個(gè)參數(shù)定義upload_file_to_api函數(shù),filename應(yīng)該是一個(gè)字符串,其中包含文件及其文件名的絕對(duì)路徑。
在函數(shù)中,我們檢查文件是否存在,然后使用Request的分塊傳輸編碼將大文件流式傳輸?shù)紸ssemblyAI API。
os模塊的getenv函數(shù)讀取使用帶有g(shù)etenv的export命令在命令行上設(shè)置的API。確保在運(yùn)行此腳本的終端中使用該導(dǎo)出命令,否則ASSEMBLYAI_KEY值將為空白。如有疑問(wèn),請(qǐng)使用echo $ ASSEMBLY_AI查看該值是否與您的API密鑰匹配。
要使用upload_file_to_api函數(shù),請(qǐng)將以下代碼行添加到upload_audio_file.py文件中,以便我們可以正確地將此代碼作為使用python命令調(diào)用的腳本執(zhí)行:
if?__name__?==?"__main__":
????parser?=?argparse.ArgumentParser()
????parser.add_argument("filename")
????args?=?parser.parse_args()
????upload_filename?=?args.filename
????response_json?=?upload_file_to_api(upload_filename)
????if?not?response_json:
????????print("file?does?not?exist")
????else:
????????print("File?uploaded?to?URL:?{}".format(response_json['upload_url']))
上面的代碼創(chuàng)建了一個(gè)ArgumentParser對(duì)象,它允許應(yīng)用程序從命令行獲取單個(gè)參數(shù)來(lái)指定我們要訪問(wèn)的對(duì)象,讀取并上傳到AssmeblyAI服務(wù)的文件。
如果文件不存在,腳本將顯示一條消息,提示找不到該文件。在路徑中,我們確實(shí)找到了正確的文件,然后使用upload_file_to_api函數(shù)中的代碼上傳了文件。
通過(guò)使用python命令在命令行上運(yùn)行完整的upload_audio_file.py腳本,以執(zhí)行該腳本。將FULL_PATH_TO_FILE替換為您要上傳的文件的絕對(duì)路徑,例如/Users/matt/devel/audio.mp3。
python?upload_audio_file.py?FULL_PATH_TO_FILE
假設(shè)在您指定的位置找到文件,當(dāng)腳本完成文件的上傳后,它將打印一條帶有唯一URL的消息:
File?uploaded?to?URL:?https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638
該URL不是公開(kāi)的,只能由AssemblyAI服務(wù)使用,因此除您及其轉(zhuǎn)錄的API外,其他任何人都無(wú)法訪問(wèn)您的文件及其內(nèi)容。
重要的部分是URL的最后一部分,在此示例中為463ce27f-0922-4ea9-9ce4-3353d84b5638。保存該唯一標(biāo)識(shí)符,因?yàn)槲覀冃枰獙⑵鋫鬟f給下一個(gè)啟動(dòng)轉(zhuǎn)錄服務(wù)的腳本。
啟動(dòng)轉(zhuǎn)錄
接下來(lái),我們將編寫(xiě)一些代碼來(lái)開(kāi)始轉(zhuǎn)錄。創(chuàng)建一個(gè)名為initial_transcription.py的新文件。將以下代碼添加到新文件中。
import?argparse
import?os
import?requests
API_URL?=?"https://api.assemblyai.com/v2/"
CDN_URL?=?"https://cdn.assemblyai.com/"
def?initiate_transcription(file_id):
????"""Sends?a?request?to?the?API?to?transcribe?a?specific
????file?that?was?previously?uploaded?to?the?API.?This?will
????not?immediately?return?the?transcription?because?it?takes
????a?moment?for?the?service?to?analyze?and?perform?the
????transcription,?so?there?is?a?different?function?to?retrieve
????the?results.
????"""
????endpoint?=?"".join([API_URL,?"transcript"])
????json?=?{"audio_url":?"".join([CDN_URL,?"upload/{}".format(file_id)])}
????headers?=?{
????????"authorization":?os.getenv("ASSEMBLYAI_KEY"),
????????"content-type":?"application/json"
????}
????response?=?requests.post(endpoint,?json=json,?headers=headers)
????return?response.json()
我們具有與先前腳本相同的導(dǎo)入,并添加了一個(gè)新常量CDN_URL,該常量與AssemblyAI存儲(chǔ)上傳的音頻文件的單獨(dú)URL匹配。
initiate_transcription函數(shù)本質(zhì)上只是向AssemblyAI API設(shè)置了一個(gè)HTTP請(qǐng)求,以傳入的特定URL對(duì)音頻文件啟動(dòng)轉(zhuǎn)錄過(guò)程。這就是為什么file_id傳遞很重要的原因:完成音頻文件的URL 我們告訴AssemblyAI進(jìn)行檢索。
通過(guò)附加此代碼來(lái)完成文件,以便可以從命令行輕松地使用參數(shù)調(diào)用它。
if?__name__?==?"__main__":
????parser?=?argparse.ArgumentParser()
????parser.add_argument("file_id")
????args?=?parser.parse_args()
????file_id?=?args.file_id
????response_json?=?initiate_transcription(file_id)
????print(response_json)
通過(guò)在initiate_transcription文件上運(yùn)行python命令來(lái)啟動(dòng)腳本,并傳入您在上一步中保存的唯一文件標(biāo)識(shí)符。
#?the?FILE_IDENTIFIER?is?returned?in?the?previous?step?and?will
#?look?something?like?this:?463ce27f-0922-4ea9-9ce4-3353d84b5638
python?initiate_transcription.py?FILE_IDENTIFIER
API將發(fā)回該腳本打印到命令行的JSON響應(yīng)。
{'audio_end_at':?None,?'acoustic_model':?'assemblyai_default',?'text':?None,?
?'audio_url':?'https://cdn.assemblyai.com/upload/463ce27f-0922-4ea9-9ce4-3353d84b5638',?
?'speed_boost':?False,?'language_model':?'assemblyai_default',?'redact_pii':?False,?
?'confidence':?None,?'webhook_status_code':?None,?
?'id':?'gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067',?'status':?'queued',?'boost_param':?None,?
?'words':?None,?'format_text':?True,?'webhook_url':?None,?'punctuate':?True,?
?'utterances':?None,?'audio_duration':?None,?'auto_highlights':?False,?
?'word_boost':?[],?'dual_channel':?None,?'audio_start_from':?None}
記下JSON響應(yīng)中id鍵的值。這是我們需要用來(lái)檢索轉(zhuǎn)錄結(jié)果的轉(zhuǎn)錄標(biāo)識(shí)符。在此示例中,它是gkuu2krb1-8c7f-4fe3-bb69-6b14a2cac067。復(fù)制轉(zhuǎn)錄標(biāo)識(shí)符到您自己的響應(yīng)中,因?yàn)樵谙乱徊街形覀儗⑿枰鼇?lái)檢查轉(zhuǎn)錄過(guò)程何時(shí)完成。
檢索轉(zhuǎn)錄結(jié)果
我們已經(jīng)上傳并開(kāi)始了轉(zhuǎn)錄過(guò)程,因此,準(zhǔn)備就緒后,我們將盡快獲得結(jié)果。
返回結(jié)果所需的時(shí)間取決于文件的大小,因此下一個(gè)腳本將向HTTP發(fā)送一個(gè)HTTP請(qǐng)求,并報(bào)告轉(zhuǎn)錄狀態(tài),或者在完成后打印輸出。
創(chuàng)建一個(gè)名為?get_transcription.py?的第三個(gè)Python文件,并將以下代碼放入其中。
import?argparse
import?os
import?requests
API_URL?=?"https://api.assemblyai.com/v2/"
def?get_transcription(transcription_id):
????"""Requests?the?transcription?from?the?API?and?returns?the?JSON
????response."""
????endpoint?=?"".join([API_URL,?"transcript/{}".format(transcription_id)])
????headers?=?{"authorization":?os.getenv('ASSEMBLYAI_KEY')}
????response?=?requests.get(endpoint,?headers=headers)
????return?response.json()
if?__name__?==?"__main__":
????parser?=?argparse.ArgumentParser()
????parser.add_argument("transcription_id")
????args?=?parser.parse_args()
????transcription_id?=?args.transcription_id
????response_json?=?get_transcription(transcription_id)
????if?response_json['status']?==?"completed":
????????for?word?in?response_json['words']:
????????????print(word['text'],?end="?")
????else:
????????print("current?status?of?transcription?request:?{}".format(
??????????????response_json['status']))
上面的代碼與其他腳本具有相同的 imports 對(duì)象。在這個(gè)新的get_transcription函數(shù)中,我們只需使用我們的API密鑰和上一步中的轉(zhuǎn)錄標(biāo)識(shí)符(而不是文件標(biāo)識(shí)符)調(diào)用AssemblyAI API。我們檢索JSON響應(yīng)并將其返回。
在main函數(shù)中,我們處理作為命令行參數(shù)傳入的轉(zhuǎn)錄標(biāo)識(shí)符,并將其傳遞給get_transcription函數(shù)。如果來(lái)自get_transcription函數(shù)的響應(yīng)JSON包含completed狀態(tài),則我們將打印轉(zhuǎn)錄結(jié)果。否則,請(qǐng)?jiān)?code style="margin-right: 2px;margin-left: 2px;padding: 2px 4px;font-size: 14px;border-radius: 4px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.047);font-family: 'Operator Mono', Consolas, Monaco, Menlo, monospace;word-break: break-all;">completed之前打印當(dāng)前狀態(tài)如queued或processing。
使用命令行和上一節(jié)中的轉(zhuǎn)錄標(biāo)識(shí)符調(diào)用腳本:
python?get_transcription.py?TRANSCRIPTION_ID
如果該服務(wù)尚未開(kāi)始處理腳本,則它將返回queued,如下所示:
current?status?of?transcription?request:?queued
當(dāng)服務(wù)當(dāng)前正在處理音頻文件時(shí),它將返回processing:
current?status?of?transcription?request:?processing
該過(guò)程完成后,我們的腳本將返回轉(zhuǎn)錄文本,如您在此處看到的那樣:
An?object?relational?mapper?is?a?code?library?that?automates?the?transfer?of?
data?stored?in?relational,?databases?into?objects?that?are?more?commonly?used
in?application?code?or?EMS?are?useful?because?they?provide?a?high?level?
...(output?abbreviated)
就是這樣,我們已經(jīng)轉(zhuǎn)錄完成了!
您可能想知道如果精度不適合您的情況該怎么辦。這就是需要用到提高關(guān)鍵字或短語(yǔ)的準(zhǔn)確性方法(https://docs.assemblyai.com/guides/boosting-accuracy-for-keywords-or-phrases)和選擇與數(shù)據(jù)更匹配的模型方法(https://docs.assemblyai.com/guides/transcribing-with-a-different-acoustic-or-custom-language-model)的地方。您可以使用這兩種方法中的任一種,將記錄的準(zhǔn)確性提高到適合您情況的水平。
下一步是什么?
我們剛剛完成了一些腳本,這些腳本調(diào)用AssemblyAI API來(lái)將帶有語(yǔ)音的錄音轉(zhuǎn)錄為文本輸出。您可以查閱文檔(https://docs.assemblyai.com/overview/getting-started)來(lái)增加一些更高級(jí)功能:
支持不同的文件格式
轉(zhuǎn)錄雙通道/立體聲錄音
獲取揚(yáng)聲器標(biāo)簽(揚(yáng)聲器隔離)
由于微信平臺(tái)算法改版,公號(hào)內(nèi)容將不再以時(shí)間排序展示,如果大家想第一時(shí)間看到我們的推送,強(qiáng)烈建議星標(biāo)我們和給我們多點(diǎn)點(diǎn)【在看】。星標(biāo)具體步驟為:
(1)點(diǎn)擊頁(yè)面最上方“小詹學(xué)Python”,進(jìn)入公眾號(hào)主頁(yè)。
(2)點(diǎn)擊右上角的小點(diǎn)點(diǎn),在彈出頁(yè)面點(diǎn)擊“設(shè)為星標(biāo)”,就可以啦。
感謝支持,比心。

