SSMLのマークアップ効率化のためにTypeScriptとJSXに手を出した話/aajug-202005

 SSMLのマークアップ効率化のためにTypeScriptとJSXに手を出した話/aajug-202005

75486cbfd37125f121cf4a6c5614601c?s=128

Hidetaka Okamoto

May 29, 2020
Tweet

Transcript

  1. SSMLͷϚʔΫΞοϓΛ ޮ཰Խ͢ΔͨΊʹ TypeScriptͱJSXʹखΛग़ͨ͠࿩ AAJUG Online 2020/05/29 Hidetaka Okamoto #aajug

  2. ֓ཁ • SSMLͷϚʔΫΞοϓΛจࣈྻͰ΍Δͷ͸ΩπΠ • JSXΛ͔ͭ͑͹ɺReactͷΑ͏ʹSSML͕ॻ͚Δ • TypeScript (TSX)ͳΒ͹ɺϓϩύςΟͷݕূ·Ͱ͍͚Δ • ask-sdk޲͚ͷϥούʔΛ࡞ͬͯΈͨ

  3. ֓ཁ • SSMLͷϚʔΫΞοϓΛจࣈྻͰ΍Δͷ͸ΩπΠ • JSXΛ͔ͭ͑͹ɺReactͷΑ͏ʹSSML͕ॻ͚Δ • TypeScript (TSX)ͳΒ͹ɺϓϩύςΟͷݕূ·Ͱ͍͚Δ • ask-sdk޲͚ͷϥούʔΛ࡞ͬͯΈͨ

  4. Α͋͘ΔSSMLͷॻ͖ํ handlerInput.responseBuilder .speak( [ “<p>͜Ε͸SSMLͷαϯϓϧͰ͢ɻ</p>”, “<break strength=\"weak\" />”, “࣍͸ԿΛ͠·͔͢ʁ</p>” ].join(‘’))

    .getResponse();
  5. จࣈྻͰMarkup LanguageΛॻ͘ͱ͍͏͜ͱ • จࣈྻͷதʹɺSSMLλάΛهड़͢Δ • ASK SDKΛͦͷ··࢖͏৔߹ͷఆੴ • speakλά͸ASK SDK͕ࣗಈͰηοτͯ͘͠ΕΔ

    • λάͷ਺͕૿͑Δͱϛε͕ੜ͡΍͍͢
  6. ؒҧ͍୳͠ handlerInput.responseBuilder .speak( [ “<p>͜Ε͸SSMLͷαϯϓϧͰ͢ɻ</p>”, “<break strength=\"weak\" />”, “࣍͸ԿΛ͠·͔͢ʁ</p>” ].join(‘’))

    .getResponse();
  7. ਖ਼ղɿ։࢝λά͕ͳ͍ handlerInput.responseBuilder .speak( [ “<p>͜Ε͸SSMLͷαϯϓϧͰ͢ɻ</p>”, “<break strength=\"weak\" />”, “࣍͸ԿΛ͠·͔͢ʁ</p>” ].join(‘’))

    .getResponse();
  8. SSMLΛ͍͔ʹޮ཰Α͘ॻ͚ΔΑ͏ʹ͢Δ͔ʁ • SSMLΛจࣈྻͱͯ͠ѻ͏͜ͱ͕໰୊ • จࣈྻҎ֎Ͱهड़Ͱ͖ΔΑ͏ʹ͢Δ • Solution A: SSML BuilderΫϥε

    • Solution B: MarkdownͳͲͷϑΥʔϚοτΛ࢖͏
  9. npm i -S ssml-builder var Speech = require('ssml-builder'); var speech

    = new Speech(); speech.say('Hello') .pause('1s') .say('fellow Alexa developers') .pause('500ms') .say('Testing phone numbers') .sayAs({ word: "+1-377-777-1888", interpret: "telephone" }); var speechOutput = speech.ssml(true); • ϝιουܗࣜͰSSMLΛදݱ • ม׵݁ՌΛϨεϙϯε΁ ௥ՃͰ͖Δ • ϝιουνΣʔϯͰ ॊೈʹ௥ՃՄೳ
  10. npm i -S speechmarkdow n-js const smd = require('speechmarkdown-js'); const

    markdown = `Sample [3s] speech [250ms] markdown`; const options = { platform: 'amazon-alexa' }; const speech = new smd.SpeechMarkdown(); const ssml = speech.toSSML(markdown, options); === RESULT === <speak> Sample <break time="3s"/> speech <break time="250ms"/> markdown </speak> • MarkdownͰSSMLΛهड़ • ϚϧνϓϥοτϑΥʔϜରԠ • fsͳͲΛ૊Έ߹Θͤͯ .mdϑΝΠϧʹهड़΋Մೳ
  11. One more things…

  12. None
  13. ֓ཁ • SSMLͷϚʔΫΞοϓΛจࣈྻͰ΍Δͷ͸ΩπΠ • JSXΛ͔ͭ͑͹ɺReactͷΑ͏ʹSSML͕ॻ͚Δ • TypeScript (TSX)ͳΒ͹ɺϓϩύςΟͷݕূ·Ͱ͍͚Δ • ask-sdk޲͚ͷϥούʔΛ࡞ͬͯΈͨ

  14. ReactͷΑ͏ʹ SSMLΛॻ͖͍ͨ import React from 'react'; import { CopyToClipboard }

    from 'react-copy-to- clipboard'; const CopyLink = ({param}: {param: string}) => ( <CopyToClipboard text={param}> <span> {param} <i className="fa fa-copy ml-1" style={{ cursor: 'pointer' }} /> </span> </CopyToClipboard> ); export default () => { return <CopyLink param={`https://google.com`} /> } • ॻ͖׳ΕͨϑΥʔϚοτ • View (Speech)΁ͷϑΥʔΧε Λڧ੍Ͱ͖Δ • JSΒ͍͠ಈతͳॲཧ΋Մೳ
  15. ϥΠϒϥϦ͸͋Δ ߟ͑Δ͜ͱ͸օಉ͡ JSXΛstringʹม׵͢Δπʔϧ ϝϯς͞Ε͍ͯͳ͍΋ͷଟΊ ssml-tsxҰ୒ঢ়ଶ

  16. npm i -S ssml-tsx /** @jsx ssml */ import ssml,

    { rendetToString, FC } from "ssml-tsx"; const Foo= ({ name }) => ( <speak> <say-as interpret-as="characters">{name}</say-as> <break time="2s" /> <p>What would you like to do today?</p> </speak> ); console.log(renderToString(<Foo name="bar" />)); • SSMLΛJSXͰॻ͚Δ • from TimeTree • GitHubͷϨεϙϯε΋ૣ͍ • ݱঢ়͜ΕҰ୒
  17. JSX / TSX͸ ม׵ඞਢ // Example for Babel { "plugins":

    [ ["transform-jsx", { "function": "ssml", "useVariables": true }] ] } • JSX / TSX͸JSͰಈ͔ͳ͍ • BabelͰͷม׵͕Ұൠత • ४උͷҰखؒΛڐ༰Ͱ͖Δ͔ ͕෼ਫྮ • Ͳ͏ͤ΍ΔͳΒTypeScript
  18. ֓ཁ • SSMLͷϚʔΫΞοϓΛจࣈྻͰ΍Δͷ͸ΩπΠ • JSXΛ͔ͭ͑͹ɺReactͷΑ͏ʹSSML͕ॻ͚Δ • TypeScript (TSX)ͳΒ͹ɺϓϩύςΟͷݕূ·Ͱ͍͚Δ • ask-sdk޲͚ͷϥούʔΛ࡞ͬͯΈͨ

  19. JSX΍ΔͳΒ TypeScript { "compilerOptions": { ..., + "jsx": "react", }

    } • tscίϚϯυͰ·ͱΊͯ ίϯύΠϧ • ܕݕূͷԸܙ͸େ͖͍ • ASK SDK΋TypeScriptରԠ
  20. IDEͰϛε͕Θ͔Γ΍͍͢

  21. ֓ཁ • SSMLͷϚʔΫΞοϓΛจࣈྻͰ΍Δͷ͸ΩπΠ • JSXΛ͔ͭ͑͹ɺReactͷΑ͏ʹSSML͕ॻ͚Δ • TypeScript (TSX)ͳΒ͹ɺϓϩύςΟͷݕূ·Ͱ͍͚Δ • ask-sdk޲͚ͷϥούʔΛ࡞ͬͯΈͨ

  22. @ask-utils/speech- script ssml-tsxͷϥούʔ ASK SDKͰͷར༻ʹಛԽ ஋ͷऔΓճ͠Λޮ཰Խ

  23. ࣮૷αϯϓϧ ʢSSMLʣ /** @jsx ssml */ import { ssml, SpeechScriptJSX

    } from '@ask-utils/speech-script' class LaunchRequestScriptForEnglish extends SpeechScriptJSX { speech() { return ( <speak> Hello! <break time="0.5s"/>How are you? </speak> ) } reprompt() { return ( <speak> How are you?<break time="0.5s"/> <amazon-effect name="whispered">I hope you to have a good day.</amazon-effect> </speak> ) } } • speech / repromptͦΕͧΕʹ JSXͰϚʔΫΞοϓ • this.props͔ΒϦΫΤετ಺༰ ͕ͱΕΔ • ReactϥΠΫʹهड़Մೳ
  24. ࣮૷αϯϓϧ ʢHandlerʣ const handler = { canHandle(handlerInput) { return handlerInput.requestEnvelope.request.type

    === 'LaunchRequest' }, handle(handlerInput) { const Speech = new LaunchRequestScript(handlerInput) return Speech.createResponse() } } • SSMLΛॻ͍ͨΫϥεΛར༻͢ Δ • responseBuilder಺ଂͳͷͰɺ ͦͷ··return͢Ε͹OK
  25. SSML-TSX Λಋೖͯ͠มΘͬͨ͜ͱ • RequestHandlerͷਆΦϒδΣΫτԽΛ્ࢭ • View (SSML)ͱσʔλͷॲཧͷ੹຿Λ෼཭͠ɺςελϒϧʹ • ࢠίϯϙʔωϯτΛར༻ͨ͠࠶ར༻ੑͷ޲্ •

    ReactͰॻ͍ͯΔϊϦͰAlexaͷൃ࿩Λॻ͚Δ
  26. ViewΛ੾Γ཭ͨ͠RequestHandler

  27. ΑΓॊೈͳ Viewͷදݱʹ

  28. Next Step: Localization class LaunchRequestScriptForJapanse extends LaunchRequestScript { speech() {

    return ( <speak>͜Μʹͪ͸</speak> ) } } class LaunchRequestScriptForEnglish extends LaunchRequestScript { speech() { return ( <speak>Hello! <break time="0.5s"/>How are you?</speak> ) } } export const createLaunchRequestScript = (handlerInput: HandlerInput, options?: LaunchRequestProps): SpeechScriptJSX => { const factory = new L11NSpeechScriptJSXFactory({ allowLanguageMatcher: true }).putLocales({ locale: 'ja-JP', script: new LaunchRequestScriptForJapanese(handlerInput, options) }, { locale: 'en-US', script: new LaunchRequestScriptForEnglish(handlerInput, options) }) return factory.create(handlerInput) } • ݴޠ͝ͱʹSSMLΛهड़͢Δ • en-USͳͲͷݫີͳ੔߹ͱɺ en͚ͩͰ·ΔΊΔ؇͍੔߹ ྆ํΛαϙʔτʢ༧ఆʣ
  29. ͓ΘΓʹ • RequestHandler͸ͦͷ··࢖͏ʹ͸ॏ͗͢Δ • MVC΍FluxͳͲͷ֓೦͕ͳ͍ੈքͰઓ͏ʹ͸ɺձ࿩͸ෳࡶ͗͢Δ • ͤΊͯSSMLͱAPL͸ந৅Խ͠Α͏ • speechmarkdown-js /

    ssml-tsx͕ݸਓతʹ͸͓͢͢Ί • ͩΕ͔ASK SDK on Railsͭͬͯ͘͘Εʢ੾࣮ʣ