Vikram Vaswani,开发人员倡导者
本教程最初于2022年9月8日在https://docs.rev.ai/resources/tutorials/build-speech-to-text-web-application-php-2/发表。
介绍
Rev AI的automatic speech recognition (ASR) APIs使开发人员能够将快速准确的语音到文本功能集成到其应用中。本教程的第一部分向您介绍了Rev AI的Asynchronous Speech-to-Text API。它解释了如何通过Web浏览器录制音频,并使用Guzlezle PHP HTTP客户端将音频提交给Rev AI进行转录。
在first part of this tutorial末尾,示例应用程序能够向AI提交音频,但是您仍然必须使用Rev AI仪表板来手动检索您的成绩单。这个结论段关闭了循环,解释了如何使用Webhook从Rev AI检索成绩单并在示例应用程序中显示它们。它还将解释如何在Web应用程序中添加成绩单删除和搜索功能。
注意:complete source code for the example application is available on GitHub,因此您可以立即下载并尝试。
假设
本教程假设:
- 您有一个Rev AI帐户和访问令牌。如果没有,sign up for a free account和generate an access token。
- 您已经安装了Docker。如果不是,则为您的操作系统的download and install Docker。
- 您已经安装了Docker。如果不是,则为您的操作系统install Docker Compose。
- 您将在公共网址部署应用程序的网络钩。如果没有,或者您希望在本地开发和测试,download and install koude0和obtain an koude0 authentication token。您将需要它为Webhook生成临时公共URL。
任何使用Rev AI API的应用程序也必须遵守Rev AI的API limits和terms of service。在继续之前,请查看这些文件并确保您与它们达成协议。
注意:本教程使用基于Docker的Apache/PHP/MongoDB开发环境。如果您已经与Apache 2.x,PHP 8.1.x和MongoDB extension和Composer具有正确配置的开发环境,则可以使用它。您可能需要用等效替换一些docker命令。
步骤1:使用Webhook从Rev AI接收成绩单
一旦将作业提交给Rev AI进行异步转录的Rev AI,就有三种方法可以知道何时完成转录。您可以通过Rev AI Web仪表板检查工作状态;您可以反复对API进行调查;或者,您可以让Rev AI通过Webhook自动通知您。在这三个选项中,使用Webhook是最有效的方法。
注意:如果您不熟悉Webhooks,请参阅我们在getting started with Rev AI webhooks上的教程,以获取更多信息。您还可以学习如何使用Rev AI Webhooks到automatically send email notifications when a job completes或如何使用retrieve final transcripts via the API and save them to a MongoDB database。
让Rev AI知道它应该使用webhook,包括请求在https://api.rev.ai/speechtotext/v1/jobs
上的异步语音到文本API端点的notification_config
参数,如下所示:
curl -X POST "https://api.rev.ai/speechtotext/v1/jobs" \
-H "Authorization: Bearer <REVAI_ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"source_config": {"url": "https://www.rev.ai/FTC_Sample_1.mp3"},
"notification_config": {"url": "https://example.com/my/webhook"}
}'
作业完成后,API将向指定的URL提出HTTP POST请求,并在POST请求正文中使用JSON文档。这是邮政请求主体的示例:
{
"job": {
"id": "8xBckmk6rAqu",
"created_on": "2022-08-16T14:26:14.151Z",
"completed_on": "2022-08-16T14:26:53.601Z",
"name": "FTC_Sample_1.mp3",
"notification_config": {"url": "https://example.com/my/webhook"},
"source_config": {"url": "https://www.rev.ai/FTC_Sample_1.mp3"},
"status": "transcribed",
"duration_seconds": 107,
"type": "async",
"language": "en"
}
}
从上面的讨论中,应该清楚地表明,将Rev AI Webhook集成到应用程序中时涉及两个步骤:
- 在工作提交时间,在工作请求的
notification_config
参数中包括一个Webhook URL。 - 定义能够接收HTTP POST请求的Webhook URL处理程序,解析请求主体并根据收到的数据采取进一步的措施(例如检索成绩单)。
注意:为了从Rev AI接收通知,Webhook URL必须是公开访问的URL。在本地开发和测试时,这可能并非总是可能的。对于这种情况,请使用koude0创建一个临时公共URL,将用作Webhook URL。
进行更改如下所述:
-
使用Webhook URL的附加配置键更新
config/settings.php
文件。
<?php return [ 'rev' => [ 'token' => '<REVAI_ACCESS_TOKEN>', 'callback' => '<CALLBACK_PREFIX>/hook', ], 'mongo' => [ 'uri' => '<MONGODB_URI>' ] ];
如果您将应用程序部署在现有的公共URL中,请用应用程序URL替换
<CALLBACK_PREFIX>
占位符。如果您在本地开发和测试没有公开访问的URL,请首先使用
ngrok
创建并获得临时的Webhook URL,然后用该临时URL替换config/settings.php
文件中的<CALLBACK_PREFIX>
占位符。 -
在
public\index.php
上更新前控制器,并进行以下更改:
-
更新
/add
URL端点的邮路处理程序以在作业请求中包括notification_config
参数。
<?php // ... // POST request handler for /add page $app->post( '/add', function (Request $request, Response $response) { // get MongoDB service // insert a record in the database for the audio upload // get MongoDB document ID $mongoClient = $this->get('mongo'); try { $insertResult = $mongoClient->mydb->notes->insertOne( [ 'status' => 'JOB_RECORDED', 'ts' => time(), 'jid' => false, 'error' => false, 'data' => false, ] ); $id = (string) $insertResult->getInsertedId(); // get uploaded file // if no upload errors, change status in database record $uploadedFiles = $request->getUploadedFiles(); $uploadedFile = $uploadedFiles['file']; if ($uploadedFile->getError() === UPLOAD_ERR_OK) { $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => ['status' => 'JOB_UPLOADED'], ] ); // get Rev AI API client // submit audio to API as POST request $revClient = $this->get('guzzle'); $revResponse = $revClient->request( 'POST', 'jobs', [ 'multipart' => [ [ 'name' => 'media', 'contents' => fopen($uploadedFile->getFilePath(), 'r'), ], [ 'name' => 'options', 'contents' => json_encode( [ 'metadata' => $id, 'skip_diarization' => 'true', 'notification_config' => [ 'url' => $this->get('settings')['rev']['callback'] ], ] ), ], ], ] )->getBody()->getContents(); // get API response // if no API error, update status in database record // send 200 response code to client $json = json_decode($revResponse); $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => [ 'status' => 'JOB_TRANSCRIPTION_IN_PROGRESS', 'jid' => $json->id, ], ] ); $response->getBody()->write(json_encode(['success' => true])); return $response->withHeader('Content-Type', 'application/json')->withStatus(200); } } catch (\GuzzleHttp\Exception\RequestException $e) { // in case of API error // update status in database record // send error code to client with error message as payload $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => [ 'status' => 'JOB_TRANSCRIPTION_FAILURE', 'error' => $e->getMessage(), ], ] ); $response->getBody()->write(json_encode(['success' => false])); return $response->withHeader('Content-Type', 'application/json')->withStatus($e->getResponse()->getStatusCode()); } } ); // ...
-
将一个新的处理程序添加到
/hook
Webhook URL端点,该端点接受并处理从Rev AI API收到的邮政请求。
<?php // ... // POST request handler for /hook webhook URL $app->post( '/hook', function (Request $request, Response $response) { try { // get MongoDB service $mongoClient = $this->get('mongo'); // decode JSON request body // obtain identifiers and status $json = json_decode($request->getBody()); $jid = $json->job->id; $id = $json->job->metadata; // if job successful if ($json->job->status === 'transcribed') { // update status in database $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => ['status' => 'JOB_TRANSCRIPTION_SUCCESS'], ] ); // get transcript from API $revClient = $this->get('guzzle'); $revResponse = $revClient->request( 'GET', "jobs/$jid/transcript", [ 'headers' => ['Accept' => 'text/plain'], ] )->getBody()->getContents(); $transcript = explode(' ', $revResponse)[2]; // save transcript to database $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => ['data' => $transcript], ] ); // if job unsuccesful } else { // update status in database // save problem detail error message $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => [ 'status' => 'JOB_TRANSCRIPTION_FAILURE', 'error' => $json->job->failure_detail, ], ] ); } } catch (\GuzzleHttp\Exception\RequestException $e) { $mongoClient->mydb->notes->updateOne( [ '_id' => new ObjectID($id), ], [ '$set' => [ 'status' => 'JOB_TRANSCRIPTION_FAILURE', 'error' => $e->getMessage(), ], ] ); } return $response->withStatus(200); } ); // ...
此路由处理程序包含很多代码,所以让我们浏览它:
当使用HTTP POST请求调用此端点时,处理程序首先检查收到的JSON文档并从中提取三个关键信息:
- Rev AI作业标识符,将用于检索最终成绩单;
- MongoDB文档标识符,该标识符用于标识应用程序数据库中的相应记录。回忆起,该作业最初提交时,该MongoDB文档标识符包括在
metadata
参数中; - Rev AI工作状态,指示转录是成功还是失败。
如果工作成功,则处理程序将文档status
更新为JOB_TRANSCRIPTION_SUCCESS
。然后,它使用Guzlezz Rev AI API客户端来准备并将HTTP获取请求发送到https://api.rev.ai/speechtotext/v1/jobs/<ID>/transcript
,以以明文格式检索最终成绩单。然后更新MongoDB文档,并将成绩单内容保存到文档的data
字段中。
如果工作不成功,则处理程序将文档status
更新为JOB_TRANSCRIPTION_FAILURE
。在这种情况下,JSON文档还包括一个问题描述,该文档将保存在MongoDB数据库中的文档的error
字段中。
完成上述操作后,处理程序将200
响应代码返回到Rev AI API服务器。
步骤2:列出应用程序中的成绩单
一旦webhook到位,检索并将成绩单保存到mongoDB数据库,下一步就是在应用程序用户界面中显示它们。
-
更新
/index
端点的Get Route处理程序,以执行MongoDB查询并返回应用程序数据库中的所有记录。在public/index.php
的前控制器中进行此更改。
<?php // ... // GET request handler for index page $app->get( '/[index[/]]', function (Request $request, Response $response, $args) { $params = $request->getQueryParams(); $mongoClient = $this->get('mongo'); return $this->get('view')->render( $response, 'index.twig', [ 'status' => !empty($params['status']) ? $params['status'] : null, 'data' => $mongoClient->mydb->notes->find( [], [ 'sort' => [ 'ts' => -1, ], ] ) ] ); } )->setName('index'); // ...
MongoDB结果集通过
data
Twig模板变量返回。 -
更新
public/index.twig
页面模板以循环到结果集,并将MongoDB结果集作为HTML表,包括成绩单内容,时间戳,状态和Rev AI工作标识符。作为此更新的一部分,在页面上添加“刷新”按钮,该按钮为用户重新加载页面提供了一种方法。
{% extends "layout.twig" %} {% block content %} <header class="d-flex justify-content-center py-3"> <h1>My Notes</h1> </header> {% if status == 'submitted' %} <div class="alert alert-success text-center" role="alert">Audio sent for transcription.</div> {% endif %} {% if status == 'error' %} <div class="alert alert-danger text-center" role="alert">Audio transcription failed.</div> {% endif %} <table class="table"> <thead class="thead-light"> <tr> <th scope="col">#</th> <th scope="col">Date</th> <th scope="col">Contents</th> <th scope="col">Status</th> <th scope="col">Rev AI Job ID</th> <th scope="col"><a class="btn btn-primary" href="{{ url_for('index') }}" role="button">Refresh</a></th> </tr> </thead> <tbody> {% for item in data %} <tr> <td>{{ loop.index }}</td> <td>{{ item.ts|date("d M Y h:i e") }}</td> <td class="text-wrap" style="max-width: 150px;">{{ item.data }}</td> {% if item.status in ['JOB_UPLOADED', 'JOB_TRANSCRIPTION_IN_PROGRESS'] %} <td>In progress</td> {% elseif item.status == 'JOB_RECORDED' %} <td>Recorded</td> {% elseif item.status == 'JOB_TRANSCRIPTION_SUCCESS' %} <td>Transcribed</td> {% elseif item.status == 'JOB_TRANSCRIPTION_FAILURE' %} <td class="text-wrap" style="max-width: 150px;">Failed <br/> {{ item.error }}</td> {% endif %} <td>{{ item.jid }}</td> <td></td> </tr> {% endfor %} </tbody> </table> {% endblock %}
此模板循环在
。data
模板变量上,对于每个记录,将显示格式的日期和时间,成绩单数据,作业状态和Rev AI作业标识符。请注意,该模板检查文档的status
字段,这可能是JOB_RECORDED
,JOB_UPLOADED
,JOB_TRANSCRIPTION_IN_PROGRESS
,JOB_TRANSCRIPTION_IN_PROGRESS
,JOB_TRANSCRIPTION_SUCCESS
或JOB_TRANSCRIPTION_FAILURE
的任何一个,并显示每个人的可读消息,包括失败的作业的错误消息。
步骤3:在应用程序中搜索成绩单
现在您已经拥有基础知识了,现在该为应用程序添加进一步的功能了。例如,用户应该能够快速搜索生成的成绩单并找到那些匹配的特定术语。
这可以通过使用mongoDB正则表达式来过滤存储的成绩单并返回匹配的书本,如下所述:
:-
在
views/index.twig
上更新索引页模板以包含一个简单的搜索表格,如下:
{% extends "layout.twig" %} {% block content %} <!-- ... --> <div class="col-sm-4"> <form class="form-inline"> <div class="input-group"> <input class="form-control" name="term" value="{{ term }}" placeholder="Search"> <div class="input-group-append"> <button class="btn btn-outline-secondary" type="submit">Go</button> </div> </div> </form> </div> <!-- ... --> {% endblock %}
当提交此搜索表格时,用户输入的搜索词将作为查询参数添加到URL中。
-
更新前控制器脚本中的
/index
端点的Get Route处理程序public/index.php
读取提交的搜索词,并使用附加的正则表达式过滤器修改默认的mongoDB查询。此更改可确保仅返回匹配搜索词的结果并显示在索引页模板中。
<?php // ... // GET request handler for index page $app->get( '/[index[/]]', function (Request $request, Response $response, $args) { $params = $request->getQueryParams(); $condition = !empty($params['term']) ? [ 'data' => new MongoDB\BSON\Regex(filter_var($params['term'], FILTER_UNSAFE_RAW), 'i') ] : []; $mongoClient = $this->get('mongo'); return $this->get('view')->render( $response, 'index.twig', [ 'status' => !empty($params['status']) ? $params['status'] : null, 'data' => $mongoClient->mydb->notes->find( $condition, [ 'sort' => [ 'ts' => -1, ], ] ), 'term' => !empty($params['term']) ? $params['term'] : null, ] ); } )->setName('index'); // ...
路由处理程序使用请求对象的
getQueryParams()
方法检索搜索词,然后将正则表达条件添加到默认的mongoDB搜索查询中。此条件可确保仅通过查询返回包含正则表达式的成绩单。然后将结果集插入到索引页模板中以照常显示。
步骤4:从应用程序删除成绩单
用户还应该选择删除不再通过Web应用程序接口相关的语音注释。
实现以下功能:
-
在
views/index.twig
上更新索引页模板,以支持每个显示的成绩单和一个新的deleted
状态消息,如下所示。
{% extends "layout.twig" %} {% block content %} <!-- ... --> {% if status == 'deleted' %} <div class="alert alert-success text-center" role="alert">Note deleted.</div> {% endif %} <!-- ... --> <table class="table"> <!-- ... --> <tbody> {% for item in data %} <tr> <td>{{ loop.index }}</td> <td>{{ item.ts|date("d M Y h:i e") }}</td> <td class="text-wrap" style="max-width: 150px;">{{ item.data }}</td> {% if item.status in ['JOB_UPLOADED', 'JOB_TRANSCRIPTION_IN_PROGRESS'] %} <td>In progress</td> {% elseif item.status == 'JOB_RECORDED' %} <td>Recorded</td> {% elseif item.status == 'JOB_TRANSCRIPTION_SUCCESS' %} <td>Transcribed</td> {% elseif item.status == 'JOB_TRANSCRIPTION_FAILURE' %} <td class="text-wrap" style="max-width: 150px;">Failed <br/> {{ item.error }}</td> {% endif %} <td>{{ item.jid }}</td> <td><a class="btn btn-danger" href="{{ url_for('delete', { 'id': item._id }) }}" role="button">Delete</a></td> </tr> {% endfor %} </tbody> </table> {% endblock %}
请注意,每个“删除”按钮的生成的超链接将指向一个名为
delete
的路由,并将MongoDB文档标识符包括为URL参数。 -
为新的
/delete
端点创建一个Get Route处理程序,该端点接受MongoDB文档标识符作为URL参数。将此路线添加到前控制器脚本public/index.php
。
<?php // ... // GET request handler for /delete page $app->get( '/delete/{id}', function (Request $request, Response $response, $args) use ($app) { $id = filter_var($args['id'], FILTER_UNSAFE_RAW); $mongoClient = $this->get('mongo'); $mongoClient->mydb->notes->deleteOne( [ '_id' => new ObjectID($id), ] ); $routeParser = $app->getRouteCollector()->getRouteParser(); return $response->withHeader('Location', $routeParser->urlFor('index', [], ['status' => 'deleted']))->withStatus(302); } )->setName('delete'); // ...
此路由处理程序读取MongoDB文档标识符,使用MongoDB客户端的
> >deleteOne
方法从应用程序数据库中删除相应的成绩单,然后将用户重定向回到/index
url,并获得成功通知。
注意:删除本节所述的语音注释将其从应用程序数据库中删除,但不会从Rev AI的服务器中删除。为此,您必须通过API提交单独的DELETE
请求,或在初始作业请求中包含delete_after_seconds
参数。要了解更多信息,请参阅Rev AI中删除用户数据的教程。
供参考,这是最终的前控制器脚本。用此版本替换public\index.php
文件。
<?php
use Psr\Http\Message\ResponseInterface as Response;
use Psr\Http\Message\ServerRequestInterface as Request;
use Slim\Factory\AppFactory;
use Slim\Views\Twig;
use Slim\Views\TwigMiddleware;
use Slim\Routing\RouteContext;
use GuzzleHttp\Client;
use GuzzleHttp\Psr7;
use DI\ContainerBuilder;
use MongoDB\BSON\ObjectID;
// load dependencies
require __DIR__ . '/https://docs.rev.ai/resources/tutorials/vendor/autoload.php';
// create DI container
$containerBuilder = new ContainerBuilder();
// define services
$containerBuilder->addDefinitions(
[
'settings' => function () {
return include __DIR__ . '/https://docs.rev.ai/resources/tutorials/config/settings.php';
},
'view' => function () {
return Twig::create(__DIR__ . '/https://docs.rev.ai/resources/tutorials/views');
},
'mongo' => function ($c) {
return new MongoDB\Client($c->get('settings')['mongo']['uri']);
},
'guzzle' => function ($c) {
$token = $c->get('settings')['rev']['token'];
return new Client(
[
'base_uri' => 'https://api.rev.ai/speechtotext/v1/jobs',
'headers' => ['Authorization' => "Bearer $token"],
]
);
},
]
);
$container = $containerBuilder->build();
AppFactory::setContainer($container);
// create application with DI container
$app = AppFactory::create();
// add Twig middleware
$app->add(TwigMiddleware::createFromContainer($app));
// add error handling middleware
$app->addErrorMiddleware(true, true, true);
// GET request handler for index page
$app->get(
'/[index[/]]',
function (Request $request, Response $response, $args) {
$params = $request->getQueryParams();
$condition = !empty($params['term']) ?
[
'data' => new MongoDB\BSON\Regex(filter_var($params['term'], FILTER_UNSAFE_RAW), 'i')
] :
[];
$mongoClient = $this->get('mongo');
return $this->get('view')->render(
$response,
'index.twig',
[
'status' => !empty($params['status']) ? $params['status'] : null,
'data' => $mongoClient->mydb->notes->find(
$condition,
[
'sort' => [
'ts' => -1,
],
]
),
'term' => !empty($params['term']) ? $params['term'] : null,
]
);
}
)->setName('index');
// GET request handler for /add page
$app->get(
'/add',
function (Request $request, Response $response, $args) {
return $this->get('view')->render(
$response,
'add.twig',
[]
);
}
)->setName('add');
// POST request handler for /add page
$app->post(
'/add',
function (Request $request, Response $response) {
// get MongoDB service
// insert a record in the database for the audio upload
// get MongoDB document ID
$mongoClient = $this->get('mongo');
try {
$insertResult = $mongoClient->mydb->notes->insertOne(
[
'status' => 'JOB_RECORDED',
'ts' => time(),
'jid' => false,
'error' => false,
'data' => false,
]
);
$id = (string) $insertResult->getInsertedId();
// get uploaded file
// if no upload errors, change status in database record
$uploadedFiles = $request->getUploadedFiles();
$uploadedFile = $uploadedFiles['file'];
if ($uploadedFile->getError() === UPLOAD_ERR_OK) {
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => ['status' => 'JOB_UPLOADED'],
]
);
// get Rev AI API client
// submit audio to API as POST request
$revClient = $this->get('guzzle');
$revResponse = $revClient->request(
'POST',
'jobs',
[
'multipart' => [
[
'name' => 'media',
'contents' => fopen($uploadedFile->getFilePath(), 'r'),
],
[
'name' => 'options',
'contents' => json_encode(
[
'metadata' => $id,
'notification_config' => [
'url' => $this->get('settings')['rev']['callback']
],
'skip_diarization' => 'true',
]
),
],
],
]
)->getBody()->getContents();
// get API response
// if no API error, update status in database record
// send 200 response code to client
$json = json_decode($revResponse);
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => [
'status' => 'JOB_TRANSCRIPTION_IN_PROGRESS',
'jid' => $json->id,
],
]
);
$response->getBody()->write(json_encode(['success' => true]));
return $response->withHeader('Content-Type', 'application/json')->withStatus(200);
}
} catch (\GuzzleHttp\Exception\RequestException $e) {
// in case of API error
// update status in database record
// send error code to client with error message as payload
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => [
'status' => 'JOB_TRANSCRIPTION_FAILURE',
'error' => $e->getMessage(),
],
]
);
$response->getBody()->write(json_encode(['success' => false]));
return $response->withHeader('Content-Type', 'application/json')->withStatus($e->getResponse()->getStatusCode());
}
}
);
// GET request handler for /delete page
$app->get(
'/delete/{id}',
function (Request $request, Response $response, $args) use ($app) {
$id = filter_var($args['id'], FILTER_UNSAFE_RAW);
$mongoClient = $this->get('mongo');
$mongoClient->mydb->notes->deleteOne(
[
'_id' => new ObjectID($id),
]
);
$routeParser = $app->getRouteCollector()->getRouteParser();
return $response->withHeader('Location', $routeParser->urlFor('index', [], ['status' => 'deleted']))->withStatus(302);
}
)->setName('delete');
// POST request handler for /hook webhook URL
$app->post(
'/hook',
function (Request $request, Response $response) {
try {
// get MongoDB service
$mongoClient = $this->get('mongo');
// decode JSON request body
// obtain identifiers and status
$json = json_decode($request->getBody());
$jid = $json->job->id;
$id = $json->job->metadata;
// if job successful
if ($json->job->status === 'transcribed') {
// update status in database
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => ['status' => 'JOB_TRANSCRIPTION_SUCCESS'],
]
);
// get transcript from API
$revClient = $this->get('guzzle');
$revResponse = $revClient->request(
'GET',
"jobs/$jid/transcript",
[
'headers' => ['Accept' => 'text/plain'],
]
)->getBody()->getContents();
$transcript = explode(' ', $revResponse)[2];
// save transcript to database
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => ['data' => $transcript],
]
);
// if job unsuccesful
} else {
// update status in database
// save problem detail error message
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => [
'status' => 'JOB_TRANSCRIPTION_FAILURE',
'error' => $json->job->failure_detail,
],
]
);
}
} catch (\GuzzleHttp\Exception\RequestException $e) {
$mongoClient->mydb->notes->updateOne(
[
'_id' => new ObjectID($id),
],
[
'$set' => [
'status' => 'JOB_TRANSCRIPTION_FAILURE',
'error' => $e->getMessage(),
],
]
);
}
return $response->withStatus(200);
}
);
$app->run();
步骤5:测试示例应用程序
通过浏览http://<DOCKER_HOST>
来测试示例应用程序。您应该看到下面的页面。
单击右上角的“添加”按钮。您将被重定向到新页面,浏览器将提示访问系统麦克风。授予此权限,然后单击“开始录制”按钮。说话并单击完成后单击“停止录制”。您的音频将被上传,您应该重定向到索引页面,您应该在其中看到列出的语音注释,并带有“正在进行中的状态”。
成绩单准备就绪时,Rev AI将通知Webhook URL。如果您使用的是公共URL,则可以在Web服务器日志中看到此活动。另外,如果您使用的是ngrok
,则可以在ngrok
仪表板中看到此活动,如下所示:
当您在Web服务器日志或ngrok
监视器中查看传入的Webhook请求,或者大约1分钟后,如果您无法访问监视,请单击“刷新”按钮。语音笔记列表现在应反映更新的状态以及成绩单,如下所示:
如果由于错误而无法生成笔录,则该列表也应在列表中看到:
在搜索框中输入搜索词,然后单击“ GO”按钮。现在,应过滤语音笔记列表以显示包含您的搜索词的语音列表,如下所示:
单击语音笔记旁边的“删除”按钮。该注释将从数据库中删除,并将从可用注释的列表中消失。
下一步
在这个结论段中,您了解了如何使用Webhook从Rev AI检索最终成绩单并将其显示在Web应用程序中。您还使用基本搜索和删除功能改进了Web应用程序。
这样,示例语音到文本Web应用程序已完成。通过浏览器收到和记录音频,并通过Rev AI和Php生成,返回并集成到应用程序中。
。通过访问以下链接,了解有关使用Rev AI和PHP开发语音到文本应用程序的更多信息:
- 文档:异步语音到文本API job submission,transcript retrieval和job deletion
- 代码样本:Asynchronous Speech-To-Text API
- 教程:Get Started with Rev AI API Webhooks
- Tutorial: Use Webhooks to Trigger Job Email Notifications with Node.js, SendGrid and Express
- Tutorial: Save Transcripts to MongoDB with a Node.js Webhook
- Tutorial: Delete User Files from Rev AI
- 教程:Asynchronous Speech-To-Text API best practices
- 文档:Slim framework
- 文档:Guzzle PHP HTTP client
- 文档:MongoDB PHP driver