byrontudhope / alexa-app
一组类,通过Lumen和Laravel(程度较小)简化创建简单的亚马逊Echo Alexa应用程序
Requires
- php: >=5.5.9
- illuminate/routing: ~5.2
Requires (Dev)
- mockery/mockery: ^0.9.9
- phpunit/phpunit: ~5.7
This package is not auto-updated.
Last update: 2024-09-15 05:08:06 UTC
README
这是develpr/alexa-app的分支,用于解决与较旧版本的Laravel的兼容性问题。请使用develpr/alexa-app。
一组类,通过Laravel和Lumen简化创建简单的亚马逊Echo Alexa应用程序(注意:5.2.x版本的Lumen存在一个需要解决的问题[5])
主要更新 - 0.2.0 - 叫我测试版
我最近重构了此包的大部分内容,使其与Laravel兼容,并避免完全替换默认Lumen Application的强硬方案。我还进行了一些我认为是最佳的改变,例如,我解耦了Laravel/Lumen会话与Alexa AlexaSkillsKit特定的会话数据,并创建了一个单一生成器接口,以便通过单个外观处理大多数Alexa交互。但这主要是与重构相关 - 还有很多新功能,最重要的是支持亚马逊的AlexaSkillsKit安全要求。
主要功能
- 允许Laravel/Lumen风格的路由,用于意向、启动和会话结束请求。
- 处理亚马逊提出的所有安全要求,包括证书/签名验证、时间戳验证等。
- 通过熟悉的Laravel风格接口提供对Alexa AlexaSkillsKit会话数据的访问。
- 使用Laravel会话数据填充响应,以保持Lumen和Alexa之间的1:1会话数据集。
- 提供类,可以轻松返回Alexa友好的响应,包括
Speech、Card和Re-prompt响应。 - 可选地提供一种轻松检索连接的Echo设备信息的方法(
$device = Alexa::device();)。
快速示例
AlexaRoute::intent('/alexa-end-point', 'GetAntiJoke', function(){
Alexa::say("Why was the little boy crying? Because he had a frog stapled to his face!");
});
演示
我很快会录制一系列新的教程视频。
安装
先决条件
对于AlexaApp,唯一需要的只是Laravel或Lumen(基于5.2的版本)框架。
通过composer安装后(即composer require develpr/alexa-app)
1 : 自动加载您框架的相应服务提供程序
ByronTudhope\AlexaApp\Provider\LaravelServiceProvider需要添加到自动加载的服务提供程序数组中
Laravel
在config/app.php配置文件中添加
'providers' => [
...snip...
\ByronTudhope\AlexaApp\Provider\LaravelServiceProvider::class,
...snip...
],
Lumen
在您的应用程序的bootstrap/app.php文件中添加
$app->register(\ByronTudhope\AlexaApp\Provider\LumenServiceProvider::class);
2: 为Alexa和AlexaRoute添加外观/别名(可选)
这不是必需的,但可能非常有用。如果您愿意,可以注入\ByronTudhope\AlexaApp\Alexa或\ByronTudhope\AlexaApp\Routing\AlexaRouter类的实例,或使用$app['alexa']或$app['alexa.router']分别获取它们。
Laravel
如果您想使用外观/别名,您需要在config/app.php文件中添加两个单独的别名配置。
'aliases' => [
...
'AlexaRoute' => \ByronTudhope\AlexaApp\Facades\AlexaRouter::class,
'Alexa' => \ByronTudhope\AlexaApp\Facades\Alexa::class,
...
],
Lumen
实际上,我并不完全确定是否有在Lumen中添加别名/外观的“官方”方法,我通常不会在Lumen中使用自定义外观,然而,如此StackExchange帖子中所述,这应该可以工作
首先确保在bootstrap/app.php文件中启用外观/别名,通过取消注释$app->withFacades();,然后添加以下内容
class_alias(\ByronTudhope\AlexaApp\Facades\AlexaRouter::class, 'AlexaRoute');
class_alias(\ByronTudhope\AlexaApp\Facades\Alexa::class, 'Alexa');
对于流明来说,可能更简单的方法是直接使用 $app['alexa.router'] 或将上述类之一的一个实例注入到你的类中。
3: 注册证书中间件以验证请求是否来自亚马逊/AlexaSkillsKit(可选)
对于任何生产应用程序,保护你的应用程序非常重要,并且亚马逊确实要求你按照他们文档中所述的方式进行保护(见此处)。但是,你不需要注册这个中间件,在某些测试中可以选择不注册。
此包通过提供满足亚马逊提供所有所需安全参数的中间件来简化这一点。目前,如果你想启用此功能,你需要注册 Certificate 中间件,如Laravel/Lumen 文档中所述。
如果你想要保护应用程序中的所有路由,你可以简单地将 Certificate 中间件添加到你的全局中间件,如下所示,否则你可以保护某些端点(例如,只在 /alexa-api-endpoint 上运行证书/安全检查)。
Laravel
要保护 所有路由,在你的 app/Http/Kernal.php 文件中
protected $middleware = [
...
\ByronTudhope\AlexaApp\Http\Middleware\Certificate::class,
...
];
Lumen
要保护 所有路由,在你的 bootstrap/app.php 文件中
$app->middleware([
...snip...
\ByronTudhope\AlexaApp\Http\Middleware\Certificate::class,
...snip...
]);
一切已安装
到目前为止,一切都应该“工作”(见下文了解更多关于使用的详细信息),但是有一些元素可能需要配置。
#配置
根据你的应用程序,有许多事情可以修改,或者甚至可能需要修改,最重要的是,安全选项将需要设置以匹配你的 AppId 等。如果使用 Laravel 或 Lumen,大多数修改方式相同,所有配置值都应可在 config/ 文件中定义,或使用 .env 文件。
如果你使用 Laravel,可以使用 artisan 命令行工具将 AlexaApp 配置文件发布到应用程序配置目录,使用 artisan vendor:publish,或者如果你更喜欢(或使用 Lumen),你可以手动将此文件从 vendor/develpr/alexa-app/config/alexa.php 复制过来。
在 alexa.php 配置文件中有许多注释,所以请阅读这些以获取有关特定选项的更多信息! - 我只会覆盖更重要、更广泛的选择。
证书/安全
需要设置一些简单的配置选项,以便 AlexaApp 成功验证请求是有效的/来自亚马逊/AlexaSkillsKit。
亚马逊 / AlexaSkillsKit "应用程序ID"(applicationId)
这是你的 AlexaSkillsKit 的应用程序 ID,用于验证请求是否为你的应用程序。如果你不确定应用程序 ID 是什么,最简单的方法(至少对我来说)是查看从你的应用程序发送到你的 Web 服务器的示例请求。json 主体的一部分将包括 ..."application":{"applicationId":"amzn1.echo-sdk-ams.app.9ec3744a-d1b2-48f2-8e08-3b2045c00616"},... - 你需要在配置中输入的 applicationId 就是这个。
可以在 .env 文件中通过 ALEXA__APPLICATION_IDS 键设置 applicationIds 配置值,或者直接在配置文件中设置。请注意,配置文件接受一个 数组 应用程序 ID,以防你计划从一个 Laravel/Lumen 应用程序中提供多个应用程序。.env 文件方法只能指定一个应用程序 ID。
请求时间戳容差
在撰写本文时,亚马逊指定请求不应超过150秒,以防止重放攻击。这是默认配置中的设置,但如果您想更改此设置,可以在此处进行更改。请注意,如果将此值设置为0,则不会检查请求年龄——这在测试您想要持续测试的样本请求时很有用。
可以在配置文件中更改此设置('timestampTolerance')或通过在.env文件中设置ALEXA_TIMESTAMP_TOLERANCE。
证书提供者
默认情况下,AlexaApp将使用文件存储来本地缓存亚马逊的远程证书文件。很快将支持其他提供者,包括redis、数据库和eloquent。这些相关选项可以在配置文件中查看/配置。
Alexa设备
如果您想使用设备功能(例如Alexa::device()),您可能需要配置一些选项。
基本上,您需要告诉Alexa应用您在哪里持久化以及如何访问设备信息——目前提供了两个提供者,eloquent和database。如果您使用eloquent提供者,请确保在使用Lumen时eloquent已启用。
设备提供者
目前仅支持database和eloquent选项,但可以通过实现\ByronTudhope\AlexaApp\Contracts\DeviceProvider合同轻松支持更多提供者。
默认设备提供者是Eloquent,并且在/vendor/develpr/alexa-app/Device/Device.php中有一个示例设备,可以复制到您的app目录中并修改以满足您的需求。这个模型可以被认为是与Laravel基础安装中提供的User模型类似。
示例迁移
与AlexaApp一起提供了一个示例迁移,可以复制到您的迁移文件夹中(手动或使用Laravel的控制台命令php artisan vendor:publish --tag="migrations"),迁移后将与提供的DeviceProvider一起“开箱即用”。如果您不想使用此迁移,完全可以,但您需要查看配置文件,以确保您修改/理解了您可能需要更新的任何存储架构选项。
用法
在下文中,您可以了解如何使用此包。请注意,尽管以下大多数示例中可能使用了外观/别名,但您绝对不需要这样做!如果您想了解更多信息,请查看安装部分 -> facades/aliases。
路由
来自亚马逊AlexaApp中间件到您的应用程序将有三种类型的请求。这些是
- LaunchRequest(当您的应用程序“打开”时发生)
- SessionEndedRequest(在应用程序关闭时发送到您的应用程序)
- IntentRequest(这些都是上述所有请求之外的所有请求——很可能是您的应用程序的“面包和黄油”——最有意义的交互)
这三种类型的请求可以在您的应用程序中像正常的LaravelLumen请求一样进行路由!所有这些示例都可能在您的app/Http/routes.php中。
LaunchRequest
AlexaRoute::launch('/your-app-uri', 'App\Http\Controllers\AnyController@anyMethod');
或
$app['alexa.router']->launch('/your-app-uri', 'App\Http\Controllers\AnyController@anyMethod');
SessionEndedRequest
AlexaRoute::sessionEnded('/your-app-uri', function() use ($app) {
return '{"version":"1.0","response":{"shouldEndSession":true}}';
});
或
$app['alexa.router']->sessionEnded('/your-app-uri', function() use ($app) {
return '{"version":"1.0","response":{"shouldEndSession":true}}';
});
IntentRequest
AlexaRoute::intent('/your-app-uri', 'GetZodiacHoroscopeIntent', 'App\Http\Controllers\AnyController@anyMethod');
或
$app['alexa.router']->intent('/your-app-uri', 'GetZodiacHoroscopeIntent', 'App\Http\Controllers\AnyController@anyMethod');
请注意,在这些示例中,既使用了闭包也使用了控制器来处理请求,但没有具体要求根据请求类型使用其中之一。
请注意,其他get、post、put、patch、delete等选项仍然可用且未更改。
会话
会话值通过亚马逊 / AlexaSkillsKit 的 JSON 负载传递到您的应用程序。这些值可在 AlexaRequest 中访问,或使用 Alexa 外观/别名。
检索会话值
$previousChoice = Alexa::session('previousChoice');
检索所有会话值
Alexa::session();
设置会话值
Alexa::session('previousChoice', "Pizza");
或
Alexa::setSession('previousChoice', "Pizza");
取消设置会话值
Alexa::unsetSession('previousChoice');
会话值也将包含在响应的 JSON 中,但 仅当您使用 AlexaResponse 类时!。
槽位
您可以检索槽位的值(目前仅适用于 IntentRequests)
$usersChoice = Alexa::slot('choice');
如果槽位为空,则返回 null。您可以通过传递首选默认值作为第二个参数来更改此默认值
$usersChoice = Alexa::slot('choice', 'foo');
响应
您可以使用此包和 Alexa 外观轻松从您的应用程序创建有效响应,但了解外观背后的类也很重要。最重要的是要知道,Alexa::say("Hello"); 简单地返回一个包含 \ByronTudhope\AlexaApp\Response\Speech 对象的新 \ByronTudhope\AlexaApp\Response\AlexaResponse 对象。
使用 Alexa 外观/别名
向亚马逊/AlexaSkillsKit/最终用户发送有效响应的最简单方法是
return Alexa::say("Oh hi Denny");
如上所述,最终会生成并返回 AlexaResponse,因此您可以链式调用其他方法以添加其他响应功能。例如...
return Alexa::say("Oh hi Denny")>withCard(new Card("Hello message"))>endSession();
...将返回一个语音消息 ("Oh hi Denny"),一个标题为 "Hello message" 的卡片,并将结束会话。
AlexaResponse
有一些有用的类可以用于生成适合亚马逊 Echo 的有效 JSON 响应。这些类并没有什么特别复杂或神奇的地方,它们只是使创建有效响应变得更容易,而不必太多思考。
主要类是 AlexaResponse - 我打算让 Echo 在所有时候都返回此类的实例。您可以做一些有用的事情。
您可以在不执行任何其他操作的情况下返回此类的实例,这将是一个有效的响应(尽管相当无用!)
return new AlexaResponse;
您可以告诉 Echo 应该结束会话
$alexaResponse = new AlexaResponse;
$alexaResponse->endSession();
return $alexaResponse;
或者,您可以添加一个(或两个)Speech/Card/Reprompt 对象,以便向最终 Echo 用户发送语音文本或卡片(注意,您不需要返回两者!)。
$alexaResponse = new AlexaResponse;
$alexaResponse->withSpeech(new Speech("Hello!!"));
$alexaResponse->withCard(new Card("Hello Title", "Hello Subtitle", "Hello content here!"));
return $alexaResponse;
您始终可以单行返回此操作
return new AlexaResponse(new Speech("Hello!!"), new Card("Hello Title", "Hello Subtitle", "Hello content here!"), true);
在这里,当第三个参数设置为 true 时,将结束会话。
测试
$ phpunit --configuration phpunit.xml
感谢
感谢 @jasonlewis - 我从他 ding/api 包中重新使用了大量关于路由片段的想法。
感谢所有来检查这个的人。我猜在接下来的几周/几个月/一年中,亚马逊 Echo 开发者社区、开发者 API 等等,许多事情都会改变(很快),但我将尽力跟上,并肯定会查看和欣赏任何拉取请求、功能请求等。
##//todo
我认为这目前处于测试阶段。我毫不怀疑,随着我继续真正测试这个,肯定会冒出一些错误,我非常感谢任何反馈、错误报告、功能请求或评论。我仍然不确定我是否会改变一些方面(例如,如果您使用 Alexa:: 外观,它会做很多不同的事情,我正在考虑明智地分割一些功能)。
找到一种方法,不必替换默认的Application!- 将会话添加到响应中,而无需用户返回
AlexaResponse实例 - 测试!!!!
为Echo设备和用户基于userIds添加一种简单的认证选项找出验证请求是否来自亚马逊的最佳方式 - 不确定这是否可能,但希望不久后可以实现添加解析Alexa语音的基本辅助工具- 并非完全“完成”,但我已添加了一些选项以帮助实现。我非常感兴趣地想听听您对此可能如何帮助的看法!