ask-sdk / ssml-tsx と Serverless Frameworkを使ってReactライクに発話を定義する

ask-sdkを使うことで、Alexaの会話内容をスクリプタブルに定義できます。 簡単なユースケースであればこれで事足りるのですが、SSMLを駆使した表現を目指すとなるとstringでSSMLを書かないといけない部分など […]

広告ここから
広告ここまで

目次

    ask-sdkを使うことで、Alexaの会話内容をスクリプタブルに定義できます。

    input.responseBuilder.speak([
        'Hello world!',
        'This is a example sppech content from the skill',
        'The cardinal number is  <say-as interpret-as="cardinal">12345</say-as>''
      ].join(' ')).getResponse()
    
    -> "<speak>Hello world! This is a example sppech content from the skill The cardinal number is  <say-as interpret-as="cardinal">12345</say-as></speak>"

    簡単なユースケースであればこれで事足りるのですが、SSMLを駆使した表現を目指すとなるとstringでSSMLを書かないといけない部分などが断端辛くなってきます。

    ssml-tsxを使ってReactライクに記述する

    ReactなどのJSXを書いたことがある人であれば、ssml-tsx を使うのが良さげです。

    $ yarn add ssml-tsx
    $ vim tsconfig.json
    {
      "compilerOptions": {
        "lib": ["es2017"],
        "jsx": "react", // この行を追記する

    もしServerless FrameworkでLambdaを管理してる場合は webpack.config.jsも触りましょう。

    ...
    module.exports = {
    ...
      resolve: {
        // `.tsx` を追加する
        extensions: ['.mjs', '.json', '.ts', '.tsx'],
        symlinks: false,

    するとSSMLをTSXで定義できるようになります。

    $ vim example.tsx
    /** @jsx ssml */
    import ssml, { renderToString } from "ssml-tsx";
    
    export const speak = renderToString(
        <speak>
            Hello world! This is a example sppech content from the skill .
            The cardinal number is <say-as interpret-as="cardinal">12345</say-as>
        </speak>
    );
    
    $ vim index.ts
    import {speak } from './example'
    input.responseBuilder.speak(speak).getResponse()
    
    -> <speak>Hello world! This is a example sppech content from the skill . The cardinal number is <say-as interpret-as="cardinal">12345</say-as></speak>"

    Advanced usage

    JSX / TSXなので、Reactのようにプロパティを渡すこともできます。カスタムコンポーネントを使う場合はFCをインポートして型をつけてやりましょう。

    // example.tsx
    /** @jsx ssml */
    import ssml, { renderToString, FC } from "ssml-tsx";
    
    type GreetingComponent = FC<{name?: string}>
    
    const WelcomeMessage: GreetingComponent = ({name}) => {
        if (!name) return <p>Hello!</p>
        return <p>Hello {name} san!</p>
    }
    
    const GreetingMessage: GreetingComponent= ({name}) => (
        <speak>
            <WelcomeMessage name={name} />
            This is a example component to use ssml-tsx.
        </speak>
    )
    
    export const getGreetingPrompt = (name?: string) => renderToString(
        <GreetingMessage name={name} />
    )
    
    // index.ts
    import { getGreetingPrompt } from './example'
    input.responseBuilder.speak(getGreetingPrompt('John')).getResponse()
    
    -> "<speak><p>Hello John san!</p>This is a example component to use ssml-tsx.</speak>"

    こうなると条件分岐のある発話も結構楽にかけます。

    既知の問題 (in Apr. 9)

    今のところ amazon:domain / amazon:effect / amazon:emotion のタグはうまく動かない様子です。原因の検討はついたのでレポートとPR作成までやってありますので、遠からず解決するとは思います。

    Apr. 10: the issue has been resolved

    amazon:XXXタグについて、version 1.0.9にて解決されました。

    https://github.com/jubilee-works/ssml-tsx/releases/tag/v1.0.9

    <XXX:YYY>のようにコロンで区切るマークアップがJSXではできないため、<amazon-domain><amazon-effect>のようにハイフンで区切って実装する形となっています。

    まとめ

    結構こういう周辺ライブラリ入れると実装楽になるので、「おれの思う最強のAlexaスキル開発環境話」が増えてくるとうれしいなと思います。

    広告ここから
    広告ここまで
    Home
    Search
    Bookmark