alexa-js / alexa-app

A framework for Alexa (Amazon Echo) apps using Node.js
https://www.youtube.com/watch?v=pzM4jv7k7Rg
MIT License
1.03k stars 212 forks source link

No definition in code for custom slots #222

Closed ericblade closed 7 years ago

ericblade commented 7 years ago

(update: this is related to #114 )

One of the things that my team really likes about the alexa-app kit vs the official alexa-sdk, is that the schema and utterances are packaged right along with the code, so it's a rather attractive, declarative sort of style.

We just noticed as we were working out good ways to deploy things, that there is a lack of any kind of definition for custom slot data.

This is something that I would be interested in working on, if the maintainers would be interested in it, but I'd also like to discuss what we would think would be the best way to handle doing it would be.

I think what we are thinking about doing, since Amazon is lacking any official way to update the "Interaction Model" page, is writing some code to automatically pull the schema, utterances, and slot definitions from the skill code, and then use curl or node or something to automatically push it to the Interaction Model page. (or at least generate some text files that we can copy/paste from in the meantime)

So, I'm thinking that we could define slots as objects or strings (to keep compatibility), if object of form

slots: {
    startDate: { type: 'AMAZON.DATE', },
    subject: { type: 'SUBJECTS', examples: [ 'discuss code', 'code design', 'implementation meeting', 'one-on-one meeting', 'all-hands meeting', 'meeting with boss', .... ] },
}

and then have slots() output something like:

slotName
(line-separated examples)
(blank line)
slotName2
(line-separated examples)
(blank line)
...

Also considering that we might want (a) function(s) that would return the schema, slots, and utterances as javascript objects, so that we can parse them directly from our build/deployment system.

What do the people with more experience with the app kit suggest?

dblock commented 7 years ago

I am very interested in this - I have a similar problem in https://github.com/artsy/elderfield/ where I have a custom slot called NAME and a set of instructions that say _Add a custom slot type called NAME. Paste the contents of artists.txt and lastnames.txt into the values box..

I think custom slots are reusable across the entire schema, so we need to find a way to declare them outside of a specific intent. So maybe we could leave the definition of slot inside an intent alone and make this simple a global thing?

app.custom_slot('NAME', {
  examples: [ 'andy warhol', ... ]
});

app.custom_slot('NAME', {
  examples: function() { fs.readFileSync('artist_names.txt') 
});

app.intent('AboutIntent', {
    "slots": {
      "VALUE": "NAME"
    },
    "utterances": [
      "about {-|VALUE}"
    ]
  },
 ...

This would allow us to validate the schema programmatically too when exporting, as all the custom slots could require to be declared.

dblock commented 7 years ago

Also, we currently deploy alexa our skills with apex, but it would be amazing to come up with a deployment system that doesn't require going to the Amazon UI at all. Note that clay is attempting something in those lines.

rickwargo commented 7 years ago

I have implemented this already - just trying to find the time to create a PR. I may have some time this weekend.

ericblade commented 7 years ago

So, in the new Alexa Skill Builder interface, you can directly edit using the "Code Editor" option. It provides the same thing as the "schema", but I see there is an added field called "samples" which contains an array of what was formerly known as "utterances".

It also contains all the slot data, both built-in and custom slots.

Therefore, going forward, we should just need to jam it all into ?schema .. maybe ?schema=v2 or something because i'm not sure if you can paste this into the old skill builder.. and i don't see a way to go back to it once i've enabled the old one..

Anyway, here's a sample of what the new skill builder gives me:

{
  "intents": [
    {
      "name": "AMAZON.CancelIntent",
      "samples": []
    },
    {
      "name": "AMAZON.HelpIntent",
      "samples": []
    },
    {
      "name": "AMAZON.NoIntent",
      "samples": []
    },
    {
      "name": "AMAZON.StopIntent",
      "samples": []
    },
    {
      "name": "AMAZON.YesIntent",
      "samples": []
    },
    {
      "name": "createMeeting",
      "samples": [
        "create meeting",
        "invite {guest} to a meeting",
        "invite {guest} a meeting",
        "invite {guest} to meeting",
        "invite {guest} meeting",
        "invite {guest} to a meeting on {forDate}",
        "invite {guest} a meeting on {forDate}",
        "invite {guest} to meeting on {forDate}",
        "invite {guest} meeting on {forDate}",
        "invite {guest} to a meeting at {startTime}",
        "invite {guest} a meeting at {startTime}",
        "invite {guest} to meeting at {startTime}",
        "invite {guest} meeting at {startTime}",
        "invite {guest} to a meeting on {forDate} at {startTime}",
        "invite {guest} a meeting on {forDate} at {startTime}",
        "invite {guest} to meeting on {forDate} at {startTime}",
        "invite {guest} meeting on {forDate} at {startTime}",
        "create meeting on {forDate}",
        "create meeting on {forDate} at {startTime}",
        "create meeting at {startTime}",
        "create meeting at {startTime} for {forDate}",
        "create {duration} meeting",
        "create meeting for {subject}",
        "create meeting at {location}",
        "create meeting for {forDate} at {startTime} in {location}",
        "create {duration} meeting for {forDate}",
        "change date {forDate}",
        "date {forDate}",
        "change {forDate}",
        "{forDate}",
        "change start {startTime}",
        "start {startTime}",
        "change start time {startTime}",
        "start time {startTime}",
        "change {startTime}",
        "{startTime}",
        "change duration {duration}",
        "duration {duration}",
        "change length {duration}",
        "length {duration}",
        "change {duration}",
        "{duration}",
        "change subject {subject}",
        "subject {subject}",
        "change topic {subject}",
        "topic {subject}",
        "change {subject}",
        "{subject}",
        "change location {location}",
        "location {location}",
        "change place {location}",
        "place {location}",
        "change {location}",
        "{location}",
        "change guest {guest}",
        "guest {guest}",
        "change invite {guest}",
        "invite {guest}",
        "change {guest}",
        "{guest}"
      ],
      "slots": [
        {
          "name": "forDate",
          "type": "AMAZON.DATE",
          "samples": []
        },
        {
          "name": "startTime",
          "type": "AMAZON.TIME",
          "samples": []
        },
        {
          "name": "duration",
          "type": "AMAZON.DURATION",
          "samples": []
        },
        {
          "name": "subject",
          "type": "SUBJECTS",
          "samples": []
        },
        {
          "name": "location",
          "type": "MEETING_ROOMS",
          "samples": []
        },
        {
          "name": "guest",
          "type": "AMAZON.US_FIRST_NAME",
          "samples": []
        }
      ]
    },
    {
      "name": "test",
      "samples": [
        "testing",
        "hello",
        "say hello"
      ],
      "slots": []
    }
  ],
  "types": [
    {
      "name": "MEETING_ROOMS",
      "values": [
        {
          "name": {
            "value": "q-bert"
          }
        },
        {
          "name": {
            "value": "space invaders"
          }
        },
        {
          "name": {
            "value": "spy hunter"
          }
        },
        {
          "name": {
            "value": "zelda"
          }
        },
        {
          "name": {
            "value": "breakout"
          }
        },
        {
          "name": {
            "value": "frogger"
          }
        },
        {
          "name": {
            "value": "hawaii"
          }
        },
        {
          "name": {
            "value": "interview room"
          }
        },
        {
          "name": {
            "value": "joust"
          }
        },
        {
          "name": {
            "value": "metroid"
          }
        },
        {
          "name": {
            "value": "pacman"
          }
        },
        {
          "name": {
            "value": "sonic"
          }
        },
        {
          "name": {
            "value": "tecmo bowl"
          }
        },
        {
          "name": {
            "value": "yoshi"
          }
        },
        {
          "name": {
            "value": "pathfinder"
          }
        },
        {
          "name": {
            "value": "pioneer"
          }
        },
        {
          "name": {
            "value": "voyager"
          }
        },
        {
          "name": {
            "value": "brosnan"
          }
        },
        {
          "name": {
            "value": "connery"
          }
        },
        {
          "name": {
            "value": "craig"
          }
        },
        {
          "name": {
            "value": "asteroids"
          }
        },
        {
          "name": {
            "value": "conferece room"
          }
        },
        {
          "name": {
            "value": "meeting room"
          }
        }
      ]
    },
    {
      "name": "SUBJECTS",
      "values": [
        {
          "name": {
            "value": "continues integration"
          }
        },
        {
          "name": {
            "value": "release "
          }
        },
        {
          "name": {
            "value": "test case coverage"
          }
        },
        {
          "name": {
            "value": "increased bug count"
          }
        },
        {
          "name": {
            "value": "team is in bug jail"
          }
        },
        {
          "name": {
            "value": "server failure"
          }
        },
        {
          "name": {
            "value": "build system failure"
          }
        },
        {
          "name": {
            "value": "deployment to production"
          }
        },
        {
          "name": {
            "value": "messed up logs"
          }
        },
        {
          "name": {
            "value": "kernel crash"
          }
        },
        {
          "name": {
            "value": "memory consumption"
          }
        },
        {
          "name": {
            "value": "rebase patches"
          }
        },
        {
          "name": {
            "value": "merge conflict"
          }
        },
        {
          "name": {
            "value": "pull latest changes"
          }
        },
        {
          "name": {
            "value": "project schedule"
          }
        },
        {
          "name": {
            "value": "deadline"
          }
        },
        {
          "name": {
            "value": "bugs per line"
          }
        },
        {
          "name": {
            "value": "network outage"
          }
        },
        {
          "name": {
            "value": "compiler errors"
          }
        },
        {
          "name": {
            "value": "test automation"
          }
        },
        {
          "name": {
            "value": "agile process"
          }
        },
        {
          "name": {
            "value": "scrum meeting"
          }
        },
        {
          "name": {
            "value": "product design"
          }
        },
        {
          "name": {
            "value": "code design"
          }
        },
        {
          "name": {
            "value": "alexa implementation"
          }
        },
        {
          "name": {
            "value": "github repositories"
          }
        },
        {
          "name": {
            "value": "one-on-one meeting"
          }
        },
        {
          "name": {
            "value": "all hands meeting"
          }
        },
        {
          "name": {
            "value": "benefits information"
          }
        },
        {
          "name": {
            "value": "the company is being sold to someone else"
          }
        },
        {
          "name": {
            "value": "the boss is coming, look busy"
          }
        },
        {
          "name": {
            "value": "pretending to be an engineer"
          }
        },
        {
          "name": {
            "value": "i want to rock and roll all night"
          }
        },
        {
          "name": {
            "value": "and party every day"
          }
        }
      ]
    }
  ]
}
ericblade commented 7 years ago

so.. if doing it the same way that Amazon takes it as input, it looks like

types: [
    { name: 'CUSTOM_SLOTNAME',
      values: [
          {    name: { value: 'sample1' } },
          {    name: { value: 'sample2' } },
           ....
      ]
    },
    { name: 'CUSTOM_SLOTNAME2',
        values: [
            { name: { ... } },
            { ... },
            ....
        ]
    }
]

i suspect that this could be simplified in alexa-app for declaring it, and then the code that outputs it can expand it to this format?

dblock commented 7 years ago

@ericblade If this is the way forward we should rewrite ?schema to do it the new way.

ericblade commented 7 years ago

Absolutely agree, but for one question that I'm not sure of the answer to:

Will the old interface accept this? If not, we probably should keep the current around until everyone is on the new interface over in the Skill configuration area.

So, the custom slots are on a level by themselves, which is good, so they are global to all intents. Unless there are additional fields that I'm not aware of after just looking at it in one sample skill .. (and i don't see any docs right off, maybe there are some) maybe it could be simplified to something like

customSlots: [
    { name: 'CUSTOM_SLOTNAME', values: [ 'sample1', 'sample2', ..., 'sampleN' ] },
    { name: 'CUSTOM_SLOTNAME2', values: [ ... ] },
    ...
    { name: 'CUSTOM_SLOTNAMEN', values: [ ... ] },
]
dblock commented 7 years ago

Let us know what you find @ericblade, looking forward to some PRs.

ericblade commented 7 years ago

i'm looking forward to eventually some day having time to do that instead of just talk about it :|

ericblade commented 7 years ago

Maybe anyone who has some skills with complex interactions could post some snips of what theirs looks like in the new interface, so we can see some more examples?

dblock commented 7 years ago

Closed via https://github.com/alexa-js/alexa-app/pull/275, please try it out!