使用 Python 和 Flask 进行更高精度的 Twilio 语音转录

Twilio 的可编程语音 API 通常用于发起和接听电话,但录音的转录准确性通常有很多不足之处。在本教程中,我们将了解如何将由 Twilio Voice API 提供支持的出站电话与 AssemblyAI 的深度学习转录 API 连接起来,以获得更准确的语音到文本输出。

此应用程序所需的工具

确保您安装了 Python 3,因为 Python 2 在 2020 年初达到了生命周期的尽头,不再受支持。最好在您的开发环境中安装 Python 3.6 或更新版本。本教程还将使用:

我们将使用以下依赖项来完成本教程:

  • requests, version2.24.0, for accessing theAssemblyAI transcription API
  • Flask, version1.1.2, to respond to Twilio’s webhooks
  • 一个Twilio账户,其中免费试用版足以测试本教程
  • Twilio Python 帮助程序库,版本 6.45.4 或更新版本,用于与 REST API 交互
  • 一个 AssemblyAI 帐户,您可以注册该帐户此处提供免费密钥 API 访问密钥
  • 如果您需要本地主机隧道来公开 Webhook 可以向其发送 POST 请求的公共 URL,请使用 Ngrok

这篇博文中的所有代码都可以在 GitHub 上的 blog-code-examples 存储库的 accurate-twilio-voice-call-recording-transcriptions-assemblyai 目录下的 MIT 许可证下获得开源。根据需要使用源代码你自己的项目。

配置我们的开发环境

切换到您保存 Python 虚拟环境的目录。使用以下命令为此项目创建一个新的虚拟环境。

通过使用以下命令创建一个新的虚拟环境来启动这个 Python 项目。我建议使用一个单独的目录,例如 ~/venvs/(波浪号是您用户的 home 目录的快捷方式),以便您始终知道所有 virtualenvs 的位置。

python3 -m venv ~/venvs/record-transcribe

使用 activate shell 脚本激活 virtualenv:

source ~/venvs/record-transcribe/bin/activate

执行上述命令后,命令提示符会发生变化,virtualenv 的名称会被添加到原始命令提示符格式的前面,因此如果您的提示符只是$,它现在看起来像下面这样:

(record-transcribe) $

请记住,您必须在每个要在 virtualenv 中使用依赖项的新终端窗口中激活您的 virtualenv。

我们现在可以将所需的软件包安装到已激活但为空的 virtualenv 中。

pip install Flask==1.1.2 requests==2.24.0 twilio==6.45.4

查找类似于以下内容的输出以确认已从 PyPI 正确安装了适当的包。

(recordtranscribe) $ pip install Flask==1.1.2 requests==2.24.0 twilio=6.45.4
Collecting Flask
  Using cached https://files.pythonhosted.org/packages/f2/28/2a03252dfb9ebf377f40fba6a7841b47083260bf8bd8e737b0c6952df83f/Flask-1.1.2-py2.py3-none-any.whl
Collecting requests
  Using cached https://files.pythonhosted.org/packages/45/1e/0c169c6a5381e241ba7404532c16a21d86ab872c9bed8bdcd4c423954103/requests-2.24.0-py2.py3-none-any.whl
Collecting twilio
  Using cached https://files.pythonhosted.org/packages/d0/4e/7c377eb1a1d57f011dc1bee2fee77cf1e9a08407b8d44ea25a187a30c78d/twilio-6.45.4.tar.gz
Collecting Werkzeug>=0.15 (from Flask)
  Using cached https://files.pythonhosted.org/packages/cc/94/5f7079a0e00bd6863ef8f1da638721e9da21e5bacee597595b318f71d62e/Werkzeug-1.0.1-py2.py3-none-any.whl
Collecting itsdangerous>=0.24 (from Flask)
  Using cached https://files.pythonhosted.org/packages/76/ae/44b03b253d6fade317f32c24d100b3b35c2239807046a4c953c7b89fa49e/itsdangerous-1.1.0-py2.py3-none-any.whl
Collecting click>=5.1 (from Flask)
  Using cached https://files.pythonhosted.org/packages/d2/3d/fa76db83bf75c4f8d338c2fd15c8d33fdd7ad23a9b5e57eb6c5de26b430e/click-7.1.2-py2.py3-none-any.whl
Collecting Jinja2>=2.10.1 (from Flask)
  Using cached https://files.pythonhosted.org/packages/30/9e/f663a2aa66a09d838042ae1a2c5659828bb9b41ea3a6efa20a20fd92b121/Jinja2-2.11.2-py2.py3-none-any.whl
Collecting urllib3!=1.25.0,!=1.25.1,<1.26,>=1.21.1 (from requests)
  Using cached https://files.pythonhosted.org/packages/9f/f0/a391d1463ebb1b233795cabfc0ef38d3db4442339de68f847026199e69d7/urllib3-1.25.10-py2.py3-none-any.whl
Collecting idna<3,>=2.5 (from requests)
  Using cached https://files.pythonhosted.org/packages/a2/38/928ddce2273eaa564f6f50de919327bf3a00f091b5baba8dfa9460f3a8a8/idna-2.10-py2.py3-none-any.whl
Collecting certifi>=2017.4.17 (from requests)
  Using cached https://files.pythonhosted.org/packages/5e/c4/6c4fe722df5343c33226f0b4e0bb042e4dc13483228b4718baf286f86d87/certifi-2020.6.20-py2.py3-none-any.whl
Collecting chardet<4,>=3.0.2 (from requests)
  Using cached https://files.pythonhosted.org/packages/bc/a9/01ffebfb562e4274b6487b4bb1ddec7ca55ec7510b22e4c51f14098443b8/chardet-3.0.4-py2.py3-none-any.whl
Collecting six (from twilio)
  Using cached https://files.pythonhosted.org/packages/ee/ff/48bde5c0f013094d729fe4b0316ba2a24774b3ff1c52d924a8a4cb04078a/six-1.15.0-py2.py3-none-any.whl
Collecting pytz (from twilio)
  Using cached https://files.pythonhosted.org/packages/4f/a4/879454d49688e2fad93e59d7d4efda580b783c745fd2ec2a3adf87b0808d/pytz-2020.1-py2.py3-none-any.whl
Collecting PyJWT>=1.4.2 (from twilio)
  Using cached https://files.pythonhosted.org/packages/87/8b/6a9f14b5f781697e51259d81657e6048fd31a113229cf346880bb7545565/PyJWT-1.7.1-py2.py3-none-any.whl
Collecting MarkupSafe>=0.23 (from Jinja2>=2.10.1->Flask)
  Using cached https://files.pythonhosted.org/packages/0c/12/37f68957526d1ec0883b521934b4e1b8ff3dd8e4fab858a5bf3e487bcee9/MarkupSafe-1.1.1-cp38-cp38-macosx_10_9_x86_64.whl
Installing collected packages: Werkzeug, itsdangerous, click, MarkupSafe, Jinja2, Flask, urllib3, idna, certifi, chardet, requests, six, pytz, PyJWT, twilio
  Running setup.py install for twilio ... done
Successfully installed Flask-1.1.2 Jinja2-2.11.2 MarkupSafe-1.1.1 PyJWT-1.7.1 Werkzeug-1.0.1 certifi-2020.6.20 chardet-3.0.4 click-7.1.2 idna-2.10 itsdangerous-1.1.0 pytz-2020.1 requests-2.24.0 six-1.15.0 twilio-6.45.4 urllib3-1.25.10

现在我们已经安装了所有必需的依赖项,我们可以开始编写应用程序了。

构建我们的应用程序

是时候深入研究代码了!我们将在此应用程序中编写三个源文件:

  • app.py:将处理电话呼叫和录音的 Flask 应用
  • transcribe.py:一个简短的 Python 脚本通过录制调用 AssemblyAI 并开始转录过程
  • print_transcription.py:一个用于将转录输出打印到终端的脚本

请记住,如果您不想从博文本身键入或复制,您可以访问 blog-code-examplesGit 存储库的 accurate-twilio-voice-call-recording-transcriptions-assemblyai 目录中的所有三个已完成文件。

创建一个名为record-transcribe 的新目录来存储您的源文件并切换到新目录。

mkdir record-transcribe
cd record-transcribe

使用以下代码创建名为 app.py 的新文件:

import os                                                                                                                                                                                                                                     
from flask import Flask, request
from twilio.twiml.voice_response import VoiceResponse
from twilio.rest import Client


app = Flask(__name__)

# pulls credentials from environment variables
client = Client()

BASE_URL = os.getenv("BASE_URL")
twiml_instructions_url = "{}/record".format(BASE_URL)
recording_callback_url = "{}/callback".format(BASE_URL)
twilio_phone_number = os.getenv("TWILIO_PHONE_NUMBER")


@app.route("/record", methods=["GET", "POST"])
def record():
    """Returns TwiML which prompts the caller to record a message"""
    # Start our TwiML response
    response = VoiceResponse()

    # Use <Say> to give the caller some instructions
    response.say('Ahoy! Call recording starts now.')

    # Use <Record> to record the caller's message
    response.record()

    # End the call with <Hangup>
    response.hangup()

    return str(response)

我们需要向 app.py 添加更多的函数,但首先让我们看一下上面的代码做了什么。

我们导入了 Flask 和 Twilio 帮助程序库的部分内容,这将使我们能够以编程方式创建和控制 Twiliore 记录的电话呼叫。请注意,当我们使用空的 Client() 构造函数实例化 Twilio 帮助程序库时,它会自动查找读取两个环境变量,TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKEN 以获得对您的 Twilio 帐户的适当权限。如果这两个环境变量未使用这些确切的名称进行设置,那么您将需要将您帐户的帐户 SID 和授权令牌显式传递给构造函数。

导入之后是 Flask 和 Twilio 库实例化。然后我们通过读取环境变量来配置 BASE_URL。在本教程中,BASE_URL 将来自 Ngrok,但它也可以是您部署应用程序的域,例如“https://www.twilio.com”。我们还没有设置这些环境变量,但我们会在写完 app.py 后不久。

在设置BASE_URL 和环境变量设置的其他三个变量之后,我们就有了record 函数。此函数是生成 TwiML 的 Flask 路由,它告诉 Twilio 如何处理电话呼叫。首先,自动语音提醒接听者电话正在被录音。然后录音开始。通话中的人说的任何话都将由 Twilio 记录和存储。

通过在app.py 函数之后添加以下两个函数来完成record

@app.route("/dial/<int:phone_number>")
def dial(phone_number):
    """Dials an outbound phone call to the number in the URL. Just
    as a heads up you will never want to leave a URL like this exposed
    without authentication and further phone number format verification.
    phone_number should be just the digits with the country code first,
    for example 14155559812."""
    call = client.calls.create(
            to='+{}'.format(phone_number),
            from_=twilio_phone_number,
            url=twiml_instructions_url,
    )
    print(call.sid)
    return "dialing +{}. call SID is: {}".format(phone_number, call.sid)


@app.route("/get-recording-url/<call_sid>")
def get_recording_url(call_sid):
    recording_urls = ""
    call = client.calls.get(call_sid)
    for r in call.recordings.list():
        recording_urls="\n".join([recording_urls, r.uri])
    return str(recording_urls)

dial 函数创建一个 Flask 路由,它将电话号码输入作为二级路径的一部分。请注意,在生产应用程序中,您必须有更好的电话号码验证,否则您将遇到未过滤输入的安全问题。我们在这里这样做是为了轻松获取电话号码作为输入,而不是为了获取电话号码而必须使用 HTML 表单构建整个用户界面。 dial 使用我们的 Twilio 帐户凭据调用 Twilio Voice API,以便我们可以向通过 URL 发送的号码拨打出站电话。 twiml_instructions_url 应设置为 record 函数 URL,以便它可以为 Twilio 的服务应如何处理拨打电话提供正确的拨号和录音 TwiML 说明.

一旦我们拨打了出站电话,呼叫 SID 就会打印到终端。通话结束后,我们将需要该通话 SID 以获取录音。

我们的app.py 文件就全部完成了。我们只需要为我们的 Twilio 凭据导出我们的环境变量。

注册 Twilio 或登录您现有的帐户。进入 Twilio 控制台后,您可以在右侧获取 TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKEN页面:

Twilio 控制台。

当您注册时,您应该为您的帐户分配了一个电话号码。您可以使用它或购买一个新的电话号码来使用。

使用 ## 设置三个环境变量,名称分别为 TWILIO_ACCOUNT_SIDTWILIO_AUTH_TOKENTWILIO_PHONE_NUMBER # 命令在你的终端。请确保将这些值替换为您自己的帐户 SID、授权令牌和 Twilio 电话号码。

export TWILIO_ACCOUNT_SID=xxxxxxxxxxxxx    # found in twilio.com/console
export TWILIO_AUTH_TOKEN=yyyyyyyyyyyyyy    # found in twilio.com/console
export TWILIO_PHONE_NUMBER=+17166382453    # replace with your Twilio number

请注意,您必须在每个命令行窗口中使用 export 命令来确保可以访问此键。如果您没有在运行脚本的环境中导出令牌,我们正在编写的脚本将无法访问 Twilio API。

在我们运行app.py之前还有一个环境变量需要设置。我们需要使用 Ngrok 作为本地主机隧道,以便 Twilio 的 webhook 可以向我们的 # 发送 HTTP POST 请求## Flask 应用程序在我们的本地开发环境中运行。

在新的终端窗口中运行 Ngrok,因为在我们运行其他 Python 代码时您需要保持它运行:

./ngrok http 5000

Ngrok 使用本地主机隧道运行。

复制“转发”URL 的 HTTPS 版本并为其设置 BASE_URL 环境变量值。例如,在此屏幕截图中,您可以使用以下命令将 BASE_URL 设置为 https://7f9139eaf445.ngrok.io

export BASE_URL=https://7f9139eaf445.ngrok.io    # use your ngrok URL, or domain. no trailing slash

好的,我们终于可以运行app.py了。确保您仍在另一个窗口运行 Ngrokin,您的 virtualenv 处于活动状态并且在此终端中您设置了四个环境变量,然后运行 ​​flask run 命令:

flask run

您应该看到 Flask 输出类似于以下文本的内容:

 * Environment: production
   WARNING: This is a development server. Do not use it in a production deployment.
   Use a production WSGI server instead.
 * Debug mode: off
 * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)

这是一个合理的警告:仅将此命令用于开发目的,当您想要部署到生产环境时,您需要使用真正的 WSGI 服务器,如 Gunicorn。

是时候测试我们的应用程序了。

测试 Twilio 可编程语音录制

我们可以通过访问端口 5000 上的本地主机来测试我们的应用程序。在您的 Web 浏览器中访问此 URL,将“14155551234”替换为您要拨打的电话号码,在线人员将记录在该电话号码中:http: //localhost:5000/dial/14155551234.

该号码现在应该会收到来自您的 Twilionumber 的电话。拿起并录制一条您要用于测试转录的消息,然后挂断。

如果出现错误,请确保设置了所有环境变量。您可以使用 echo 命令检查这些值,如下所示:

echo $BASE_URL

通话结束后,复制网页上显示的通话SID,方便我们查找录音文件的存放位置。

Twilio 调用 SID。

转到“localhost:5000/get-recording-url/”,最后调用 SID。例如,“localhost:5000/get-recording-url/CAda3f2f49ff4e8ef2be6b726edb998c92”。

Twilio 通话录音 URL。

复制除末尾“.json”之外的整个输出,然后将其粘贴到 Web 浏览器的 URL 栏中,以“api.twilio.com”为前缀。例如,“https://api.twilio.com” /2010-04-01/Accounts/ACe3737affa0d2e17561ad44c9d190e70c/Recordings/RE3b42cf470bef829c3680ded961a09300”。这将调出录音。复制整个 URL,我们将使用它作为 AssemblyAI 服务的输入。

使用 AssemblyAI API 转录

我们现在可以使用 AssemblyAI API 对刚刚制作的通话录音进行语音到文本的转录。

注册一个 AssemblyAI 帐户并登录到 AssemblyAI 仪表板,然后复制“您的 API 令牌”,如屏幕截图所示:

AssemblyAI 仪表板。

我们需要将我们的 AssemblyAI API 密钥导出为环境变量,以便我们的 Python 应用程序可以使用它来对他们的 API 进行身份验证。我们还需要为录制传递可公开访问的 URL,因此我们也将其设置为环境变量。

# make sure to replace this URL with the one for your recording
export ASSEMBLYAI_KEY=your-api-key-here
export RECORDING_URL=https://api.twilio.com/2010-04-01/Accounts/ACe3737affa0d2e17561ad44c9d190e70c/Recordings/RE3b42cf470bef829c3680ded961a09300

创建一个名为transcribe.py的新文件,并在其中写入以下代码:

import os
import requests

endpoint = "https://api.assemblyai.com/v2/transcript"

json = {
  "audio_url": os.getenv("RECORDING_URL")
}

headers = {
    "authorization": os.getenv("ASSEMBLYAI_KEY"),
    "content-type": "application/json"
}

response = requests.post(endpoint, json=json, headers=headers)

print(response.json())

上面的代码使用密钥调用 AssemblyAI 转录服务,并将带有文件记录的 URL 传递给它。脚本打印出服务的 JSON 响应,其中将包含一个转录 ID,我们将使用它来访问之后的结果他们完成处理。

使用python 命令运行脚本:

python transcribe.py

你会得到一些 JSON 作为输出,类似于你在这里看到的:

{'audio_end_at': None, 'acoustic_model': 'assemblyai_default', 'text': None, 'audio_url': 'https://api.twilio.com/2010-04-01/Accounts/ACe3737affa0d2e17561ad44c9d190e70c/Recordings/RE3b42cf470bef829c3680ded961a09300', 'speed_boost': False, 'language_model': 'assemblyai_default', 'redact_pii': False, 'confidence': None, 'webhook_status_code': None, 'id': 'zibe9vwmx-82ce-476c-85a7-e82c09c67daf', '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 响应的 id 字段中的值。我们需要该值来查找转录的最终结果。复制转录 ID 并将其设置为环境变量以用作最终脚本的输入:

# replace with what's found within `id` from the JSON response
export TRANSCRIPTION_ID=aksd19vwmx-82ce-476c-85a7-e82c09c67daf

我们只需要更多的 Python 来查找结果,我们就完成了。

检索 AssemblyAI 转录

AssemblyAI 将忙于转录录音。根据文件的大小,完成作业可能需要几秒到几分钟不等。我们可以使用以下代码来查看作业是仍在进行中还是已经完成。如果转录完成,它会将结果打印到终端。

使用以下代码创建名为 print_transcription.py 的新文件:

import os
import requests

endpoint = "https://api.assemblyai.com/v2/transcript/{}".format(os.getenv("TRANSCRIPTION_ID"))

headers = {
    "authorization": os.getenv("ASSEMBLYAI_KEY"),
}

response = requests.get(endpoint, headers=headers)

print(response.json())
print("\n\n")
print(response.json()['text'])

print_transcription.py 中的代码与前面的transcribe.py 源文件中的代码非常相似。从 Python 标准库中导入 os(操作系统),就像我们在前两个文件中所做的那样,以获取 TRANSCRIPTION_ID### 环境变量值。

endpoint 只是用于检索转录的 AssemblyAI API 端点。我们设置适当的 authorization 标头并使用 requests.get 函数进行 API 调用。然后我们打印出 JSON 响应以及转录的文本。

是时候测试这第三个文件了。在终端中执行以下命令:

python print_transcription.py

您的输出将根据您的记录而有所不同,但您应该在终端中看到类似于以下内容的结果:

{'audio_end_at': None, 'acoustic_model': 'assemblyai_default', 'auto_highlights_result': None, 'text': 'An object relational mapper is a code library that automates the transfer of data stored in a relational database tables into objects that are more commonly used in application. Code or MS provide a high level abstraction upon a relational database that allows the developer 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 that they are comfortable with comfortable to work with the database instead of writing sequel statements or short procedures.', 'audio_url': 'https://api.twilio.com/2010-04-01/Accounts/ACe3737affa0d2e17561ad44c9d190e70c/Recordings/RE3b42cf470bef829c3680ded961a09300', 'speed_boost': False, 'language_model': 'assemblyai_default', 'id': 'zibe9vwmx-82ce-476c-85a7-e82c09c67daf', 'confidence': 0.931797752808989, 'webhook_status_code': None, 'status': 'completed', 'boost_param': None, 'redact_pii': False, 'words': [{'text': 'An', 'confidence': 1.0, 'end': 90, 'start': 0}, {'text': 'object', 'confidence': 0.94, 'end': 570, 'start': 210}, {'text': 'relational', 'confidence': 0.89, 'end': 1080, 'start': 510}, {'text': 'mapper', 'confidence': 0.97, 'end': 1380, 'start': 1020}, {'text': 'is', 'confidence': 0.88, 'end': 1560, 'start': 1350}, {'text': 'a', 'confidence': 0.99, 'end': 1620, 'start': 1500}, {'text': 'code', 'confidence': 0.93, 'end': 1920, 'start': 1620}, {'text': 'library', 'confidence': 0.94, 'end': 2250, 'start': 1860}, {'text': 'that', 'confidence': 0.99, 'end': 2490, 'start': 2220}, {'text': 'automates', 'confidence': 0.93, 'end': 2940, 'start': 2430}, {'text': 'the', 'confidence': 0.95, 'end': 3150, 'start': 2910}, {'text': 'transfer', 'confidence': 0.98, 'end': 3510, 'start': 3090}, {'text': 'of', 'confidence':
0.99, 'end': 3660, 'start': 3480}, {'text': 'data', 'confidence': 0.84, 'end': 3960, 'start': 3630}, {'text': 'stored', 'confidence': 0.89, 'end': 4350, 'start': 3900}, {'text': 'in', 'confidence': 0.98, 'end': 4500, 'start': 4290}, {'text': 'a', 'confidence': 0.85, 'end': 4560, 'start': 4440}, {'text': 'relational', 'confidence': 0.87, 'end': 5580, 'start': 4500}, {'text': 'database', 'confidence': 0.92, 'end':
6030, 'start': 5520}, {'text': 'tables', 'confidence': 0.93, 'end': 6330, 'start': 5970}, {'text': 'into', 'confidence': 0.92, 'end': 7130, 'start': 6560}, {'text': 'objects', 'confidence': 0.96, 'end': 7490, 'start': 7100}, {'text': 'that', 'confidence': 0.97, 'end': 7700, 'start': 7430}, {'text': 'are', 'confidence': 0.9, 'end': 7850, 'start': 7640}, {'text': 'more', 'confidence': 0.97, 'end': 8030, 'start': 7790}, {'text': 'commonly', 'confidence': 0.92, 'end': 8480, 'start': 7970}, {'text': 'used', 'confidence': 0.86, 'end': 8750, 'start': 8420}, {'text': 'in', 'confidence': 0.94, 'end': 9050, 'start': 8840}, {'text': 'application.', 'confidence': 0.98, 'end': 9860, 'start': 9110}, {'text': 'Code', 'confidence': 0.93, 'end': 10040, 'start': 9830}, {'text': 'or', 'confidence': 1.0, 'end': 11210, 'start': 10220}, {'text': 'MS', 'confidence': 0.83, 'end': 11480, 'start': 11180}, {'text': 'provide', 'confidence': 0.94, 'end': 11870, 'start': 11510}, {'text': 'a', 'confidence': 1.0, 'end': 11960, 'start': 11840}, {'text': 'high', 'confidence': 1.0, 'end': 12200, 'start': 11930}, {'text': 'level', 'confidence': 0.94, 'end': 12440, 'start': 12170}, {'text': 'abstraction', 'confidence': 0.95, 'end': 12980, 'start': 12410}, {'text':
'upon', 'confidence': 0.94, 'end': 13220, 'start': 12950}, {'text': 'a', 'confidence': 1.0, 'end': 13280, 'start': 13160}, {'text': 'relational', 'confidence': 0.94, 'end': 13820, 'start': 13280}, {'text': 'database', 'confidence': 0.95, 'end': 14210, 'start': 13790}, {'text': 'that', 'confidence': 0.96, 'end': 14420, 'start': 14150}, {'text': 'allows', 'confidence': 0.99, 'end': 14720, 'start': 14360}, {'text':
'the', 'confidence': 0.56, 'end': 14870, 'start': 14690}, {'text': 'developer', 'confidence': 0.98, 'end': 15290, 'start': 14810}, {'text': 'to', 'confidence': 0.94, 'end': 15410, 'start': 15230}, {'text': 'write', 'confidence': 0.96, 'end': 15680, 'start': 15380}, {'text': 'Python', 'confidence': 0.94, 'end': 16070, 'start': 15620}, {'text': 'code.', 'confidence': 0.98, 'end': 16310, 'start': 16070}, {'text': 'Instead', 'confidence': 0.97, 'end': 17160, 'start': 16500}, {'text': 'of', 'confidence': 0.93, 'end': 17340, 'start': 17130}, {'text': 'sequel', 'confidence': 0.86, 'end': 17820, 'start': 17280}, {'text': 'to', 'confidence': 0.91, 'end': 18090, 'start': 17880}, {'text': 'create', 'confidence': 0.89, 'end': 18450, 'start': 18090}, {'text': 'read', 'confidence': 0.88, 'end': 18840, 'start': 18480}, {'text': 'update', 'confidence': 0.92, 'end': 19290, 'start': 18870}, {'text': 'and', 'confidence': 0.94, 'end': 19590, 'start': 19230}, {'text': 'delete', 'confidence': 0.89, 'end': 19920, 'start': 19530}, {'text': 'data',
'confidence': 0.95, 'end': 20190, 'start': 19890}, {'text': 'and', 'confidence': 0.92, 'end': 20490, 'start': 20250}, {'text': 'schemas', 'confidence': 0.86, 'end': 21000, 'start': 20430}, {'text': 'in', 'confidence': 0.94, 'end': 21210, 'start': 21000}, {'text': 'their', 'confidence': 0.98, 'end': 21510, 'start': 21150}, {'text': 'database', 'confidence': 0.97, 'end': 21900, 'start': 21450}, {'text': 'developers', 'confidence': 0.83, 'end': 23200, 'start': 22420}, {'text': 'can', 'confidence': 0.95, 'end': 23440, 'start': 23200}, {'text': 'use', 'confidence': 0.97, 'end': 23650, 'start': 23410}, {'text': 'the', 'confidence': 0.99, 'end': 23890, 'start': 23590}, {'text': 'programming', 'confidence': 0.97, 'end': 24370, 'start': 23830}, {'text': 'language', 'confidence': 1.0, 'end': 24700, 'start': 24310}, {'text': 'that', 'confidence': 1.0, 'end': 24880, 'start': 24640}, {'text': 'they', 'confidence': 0.99, 'end': 25060, 'start': 24820}, {'text': 'are', 'confidence': 0.85, 'end': 25210, 'start': 25000}, {'text': 'comfortable', 'confidence': 0.92, 'end': 25780, 'start': 25180}, {'text': 'with', 'confidence': 1.0, 'end': 25960, 'start': 25720}, {'text': 'comfortable', 'confidence': 0.94, 'end': 29090, 'start': 28090}, {'text': 'to', 'confidence': 0.84, 'end': 29840, 'start': 29180}, {'text': 'work', 'confidence': 0.95, 'end': 30050, 'start': 29780}, {'text': 'with', 'confidence': 0.98, 'end': 30290, 'start': 30020}, {'text': 'the', 'confidence': 0.69, 'end': 30440, 'start': 30230}, {'text': 'database', 'confidence': 0.98, 'end': 30860, 'start': 30380}, {'text': 'instead', 'confidence': 1.0, 'end': 32780, 'start': 31780}, {'text': 'of', 'confidence': 0.98, 'end': 32900, 'start': 32720}, {'text': 'writing', 'confidence': 0.87, 'end': 33320, 'start': 32870}, {'text': 'sequel', 'confidence': 0.88, 'end': 33860, 'start': 33290}, {'text': 'statements', 'confidence': 0.95, 'end': 34310, 'start': 33800}, {'text': 'or', 'confidence': 0.9, 'end': 34460, 'start': 34250}, {'text': 'short', 'confidence': 0.9, 'end': 34790, 'start': 34430}, {'text': 'procedures.', 'confidence': 0.98, 'end': 35270, 'start': 34760}], 'format_text': True, 'webhook_url': None, 'punctuate': True, 'utterances': None, 'audio_duration': 36.288, 'auto_highlights': False, 'word_boost': [],
'dual_channel': None, 'audio_start_from': None}


An object relational mapper is a code library that automates the transfer of data stored in a relational database tables into objects that are more commonly used in application. Code or MS provide a high level abstraction upon a relational database that allows the developer 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 that they are comfortable with comfortable to work with the database instead of writing sequel statements or short procedures.

这是很多输出。第一部分包含转录结果和对每个转录单词准确性的置信度。第二部分只是转录的纯文本输出。

您现在可以使用此基本代码并将其添加到需要高质量文本到语音转录的任何应用程序中。如果结果对您来说不够好,请查看本教程,了解如何提高关键字或短语的准确性以及更好地将您的数据与主题检测相匹配。

现在怎么办?

我们刚刚构建了一个高度准确的录音转录应用程序。

接下来,尝试一些其他相关的 Python 教程:

  • 如何使用 Python 将语音录音转录为文本
  • 使用 Sentry 报告 Python 脚本中的异常
  • Python 中的基本数据类型:字符串

有问题吗?通过在 Twitter@fullstackpython 或@mattmakai 上的 Full Stack Python 存储库上的 GitHub 问题单让我知道。如果您在本教程中发现问题或错误,请在 GitHub 上创建源存储库并提交包含修复的拉取请求。

赞(0) 打赏

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏