vikashkrjha / alexa-app
一套类,使用Lumen(以及较少程度上Laravel)简化创建简单的亚马逊Echo Alexa应用程序
Requires
- php: >=5.5.9
- illuminate/routing: ~5.4
Requires (Dev)
- mockery/mockery: ^0.9.9
- phpunit/phpunit: ~5.7
README
一套类,使用Laravel和Lumen简化创建简单的亚马逊Echo Alexa应用程序(注意:5.2.x版本的Lumen存在一个需要解决的问题[5])
主要更新 - 0.2.0 - 可以称其为beta版
我最近重构了几乎所有的这个包,使其与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:自动加载框架的相应服务提供程序
需要将Develpr\AlexaApp\Provider\LaravelServiceProvider
添加到自动加载的服务提供程序数组中
Laravel
在config/app.php
配置文件中添加
'providers' => [
...snip...
\Develpr\AlexaApp\Provider\LaravelServiceProvider::class,
...snip...
],
Lumen
在你的应用程序的bootstrap/app.php
文件中添加
$app->register(\Develpr\AlexaApp\Provider\LumenServiceProvider::class);
2:为Alexa
和AlexaRoute
添加外观/别名(可选)
这不是必需的,但可能非常有用。你可以注入\Develpr\AlexaApp\Alexa
或\Develpr\AlexaApp\Routing\AlexaRouter
类的实例,或者使用$app['alexa']
或$app['alexa.router']分别获取它们。
Laravel
如果你想使用外观/别名,你需要在config/app.php
文件中添加两个单独的别名配置。
'aliases' => [
...
'AlexaRoute' => \Develpr\AlexaApp\Facades\AlexaRouter::class,
'Alexa' => \Develpr\AlexaApp\Facades\Alexa::class,
...
],
Lumen
实际上,我不确定是否有添加别名/外观的“官方”方法,我通常不使用Lumen的自定义外观,然而,如在StackExchange帖子中提到的那样,这应该可以工作
首先确保在bootstrap/app.php
文件中启用了外观/别名,通过取消注释$app->withFacades();
,然后添加以下内容
class_alias(\Develpr\AlexaApp\Facades\AlexaRouter::class, 'AlexaRoute');
class_alias(\Develpr\AlexaApp\Facades\Alexa::class, 'Alexa');
对于Lumen来说,使用$app['alexa.router']
或者将上述类之一的实例注入到你的类中可能更容易。
3:注册证书中间件以验证请求来自亚马逊/AlexaSkillsKit(可选)
对于任何生产应用程序,保护应用程序是重要的,并且Amazon实际上要求您按照其文档中所述进行保护。然而,您无需注册此中间件,在特定测试中也可以选择不注册。
此软件包通过提供满足Amazon提供的所有必需安全参数的中间件来简化此操作。目前,如果您想启用此功能,则需要根据Laravel/Lumen文档注册Certificate
中间件。
如果您想保护应用程序中的所有路由,可以简单地将Certificate
中间件添加到全局中间件,如下所示,否则您可以选择保护某些端点(即仅在/alexa-api-endpoint
处运行证书/安全检查)。
Laravel
要保护所有路由
,在您的app/Http/Kernal.php
文件中
protected $middleware = [
...
\Develpr\AlexaApp\Http\Middleware\Certificate::class,
...
];
Lumen
要保护所有路由
,在您的bootstrap/app.php
文件中
$app->middleware([
...snip...
\Develpr\AlexaApp\Http\Middleware\Certificate::class,
...snip...
]);
所有安装完成
到此为止,一切应该“工作”(有关更多信息,请参阅下面的使用说明),但有一些元素可能需要配置。
## 配置
根据您的应用程序,可以修改许多内容,或者甚至可能需要修改,最重要的是,您需要设置安全选项以匹配您的AppId等。如果使用Laravel或Lumen,这些修改大多以相同的方式进行,所有配置值都应在config/
文件中定义,或者通过使用.env
文件。
如果您使用Laravel,可以使用控制台Artisan命令通过artisan vendor:publish
将AlexaApp配置文件发布到应用程序配置目录,或者如果您愿意(或使用Lumen)可以手动从vendor/develpr/alexa-app/config/alexa.php
复制此文件。
在alexa.php
配置文件中有许多注释,因此请仔细阅读以获取有关特定选项的更多信息! - 我将仅介绍更重要、更广泛的选择。
证书/安全
需要设置一些简单的配置选项,以便AlexaApp能够成功验证请求是有效的/来自Amazon/AlexaSkillsKit。
Amazon / AlexaSkillsKit "applicationId"s
这是您的AlexaSkillsKit的应用程序ID,用于验证请求是否为您的应用程序。如果您不确定您的应用程序ID是什么,最简单的方法(对我来说至少)是查看您的应用程序从您的应用程序发送到Web服务器的示例请求。JSON主体的一部分将包括..."application":{"applicationId":"amzn1.echo-sdk-ams.app.9ec3744a-d1b2-48f2-8e08-3b2045c00616"},...
- 您希望在配置中输入的应用程序ID是此applicationId
。
可以在.env文件中使用ALEXA__APPLICATION_IDS
密钥设置applicationIds
配置值,或者在配置文件中直接设置。请注意,配置文件接受一个数组中的应用程序ID,以防您计划从一个Laravel/Lumen应用程序中为多个应用程序提供服务。.env文件方法只允许指定单个应用程序ID。
请求时间戳容差
截至本文撰写时,Amazon指定请求不应超过150秒以防止重放攻击。这是默认配置中设置的值,但如果您想更改此值,可以在此处进行更改。此外,请注意,如果您将此值设置为0,则不会检查请求年龄 - 这在测试您想重复测试的示例请求时很有用。
可以在配置文件('timestampTolerance'
)中或在.env文件中设置ALEXA_TIMESTAMP_TOLERANCE
进行更改。
证书提供者
默认情况下,AlexaApp将使用文件存储来本地缓存亚马逊的远程证书文件。其他提供商将很快得到支持,包括redis、数据库和eloquent。这些相关选项可以在配置文件中查看/配置。
Alexa 设备
如果您想使用设备功能(例如 Alexa::device()
),您可能需要配置一些选项。
基本上,您需要告诉Alexa应用程序您的持久化位置以及如何访问设备信息——目前提供了两种提供商,分别是eloquent
和database
。如果您使用eloquent提供商,请确保在Lumen中使用eloquent时已启用。
设备提供商
目前仅支持database
和eloquent
选项,但可以通过实现\Develpr\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");
实际上只是返回一个新的 \Develpr\AlexaApp\Response\AlexaResponse
对象,其中包含一个 \Develpr\AlexaApp\Response\Speech
对象。
使用Alexa外观/别名
向Amazon/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
有几个有用的类可用于生成符合亚马逊回声友好的JSON响应。这些类并没有什么特别复杂或神奇的地方,它们只是让创建有效响应变得更加容易。
主要类是 AlexaResponse
- 我打算每次都将此类的实例返回给Echo。您可以做一些有用的事情。
您可以在不执行其他任何操作的情况下返回此类的一个实例,这将是一个有效的响应(尽管相当无用!)
return new AlexaResponse;
您可以告诉Echo应该结束会话
$alexaResponse = new AlexaResponse;
$alexaResponse->endSession();
return $alexaResponse;
或者,您可以为语音/卡片/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
我认为这个目前还处于beta版本。随着我继续真正测试它,我确信会出现一些错误,我非常欢迎任何反馈、错误报告、功能请求或评论。还有一些方面我还不确定我不会做一点点改变(例如,如果您使用Alexa::
外观,它执行了大量的不同操作,我认为最好是将一些功能拆分。
找到一种不需要替换默认Application
的方法!- 在不需要用户返回
AlexaResponse
实例的情况下将会话添加到响应中 - 测试!!!!
为基于userIds的Echo设备/用户添加一些简单的身份验证选项找出验证请求是否来自亚马逊的最佳方法 - 不确定这是否可行或将会可行,但希望很快就会实现为解析来自Alexa的语音添加基本辅助工具- 并非“完成”,但我已经添加了一些选项来帮助。我非常期待您对如何实现这种帮助提出意见!