Skip to content

Commit 2b800f5

Browse files
author
Anish Sarangi
committed
Fix skip to work properly and updated dialouge
1 parent eeb099b commit 2b800f5

25 files changed

Lines changed: 388 additions & 1180 deletions

File tree

functions/package-lock.json

Lines changed: 36 additions & 924 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

functions/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "audio-interface-of-internet-archive",
33
"description": "Audio Interface of Internet Archive",
4-
"version": "2.5.21",
4+
"version": "2.5.30",
55
"private": true,
66
"author": "Internet Archive",
77
"license": "AGPL-3.0",
@@ -52,4 +52,4 @@
5252
"sinon-chai": "^3.7.0",
5353
"virtual-alexa": "^0.7.3"
5454
}
55-
}
55+
}

functions/src/actions/_middlewares/ask.js

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,11 @@ const { debug, error } = require('../../utils/logger/index')('ia:actions:hoh:ask
22
const dialog = require('../../dialog/index');
33
const strings = require('../../strings');
44

5+
const stripSSML = (text) => text
6+
.replace(/<[^>]+>/g, ' ')
7+
.replace(/\s+/g, ' ')
8+
.trim();
9+
510
/**
611
* Middleware
712
*
@@ -22,14 +27,20 @@ module.exports = () => (ctx) => {
2227
const { app, reprompt, speech, suggestions } = ctx;
2328

2429
if (speech && speech.length > 0) {
30+
const spoken = speech.join(' ');
2531
dialog.ask(app, {
26-
speech: speech.join(' '),
32+
speech: spoken,
33+
text: stripSSML(spoken),
2734
suggestions: suggestions && suggestions.filter(s => s).slice(0, 3),
2835
reprompt,
2936
});
3037
} else {
3138
error('hm... we don\'t have anything to say.');
32-
dialog.ask(app, strings.events.nothingToSay);
39+
const fallback = strings.events.nothingToSay;
40+
dialog.ask(app, {
41+
...fallback,
42+
text: stripSSML(fallback.speech),
43+
});
3344
}
3445

3546
return Promise.resolve(ctx);

functions/src/actions/_middlewares/find-repair-scheme.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,16 @@ module.exports = () => (ctx) => {
4848

4949
if (!repairScheme) {
5050
warning('we don\'t have any repair phrase in this slot scheme', slotScheme);
51-
return Promise.resolve(ctx);
51+
// Provide a default repair scheme so findRepairPhrase doesn't crash
52+
return Promise.resolve({
53+
...ctx,
54+
repairScheme: {
55+
speech: [
56+
'I couldn\'t find a match for that. Could you try something else?',
57+
],
58+
},
59+
suggestionsScheme: repairSlotScheme,
60+
});
5261
}
5362

5463
return Promise.resolve({
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/**
2+
* Handle Alexa PlaybackController.NextCommandIssued
3+
*/
4+
const playbackNext = require('./playback/next');
5+
6+
module.exports = {
7+
handler: playbackNext.handler,
8+
};

functions/src/actions/next.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,14 @@
11
const strings = require('../strings');
2+
const playlist = require('../state/playlist');
23

34
const helpers = require('./_helpers');
5+
const playbackNext = require('./playback/next');
46

57
function handler (app) {
8+
if (playlist.getCurrentSong(app)) {
9+
return playbackNext.handler(app);
10+
}
11+
612
return helpers.simpleResponseAndResume(app, strings.intents.next.default);
713
}
814

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
const dialog = require('../../dialog');
2+
const query = require('../../state/query');
3+
const strings = require('../../strings').intents.exit;
4+
const selectors = require('../../configurator/selectors');
5+
6+
/**
7+
* Handle exit intent during playback state.
8+
* Stops audio playback AND says goodbye, clearing the AudioPlayer screen.
9+
*
10+
* Without this, exit during playback falls back to the top-level exit handler
11+
* which only closes the session with speech but doesn't send AudioPlayer.Stop,
12+
* leaving the display card on screen.
13+
*/
14+
function handler (app) {
15+
// Stop the AudioPlayer (sends AudioPlayer.Stop directive + shouldEndSession:true)
16+
app.stopPlayback();
17+
// Say goodbye speech
18+
dialog.close(app, selectors.find(strings, query.getSlots(app)));
19+
}
20+
21+
module.exports = {
22+
handler,
23+
};

functions/src/actions/playback/next.js

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,31 @@ const helpers = require('./_helpers');
1111
*
1212
* @param app
1313
*/
14-
function handler (app) {
15-
return helpers.playSong({ app, skip: 'forward' })
16-
.then(({ currentSongData }) => {
17-
if (!currentSongData) {
14+
function handler(app) {
15+
const requestType = app.params.getByName('type');
16+
const playerActivity = app.handlerInput &&
17+
app.handlerInput.requestEnvelope &&
18+
app.handlerInput.requestEnvelope.context &&
19+
app.handlerInput.requestEnvelope.context.AudioPlayer &&
20+
app.handlerInput.requestEnvelope.context.AudioPlayer.playerActivity;
21+
const isPlaybackController = typeof requestType === 'string' &&
22+
requestType.startsWith('PlaybackController.');
23+
// Only suppress speech for PlaybackController events (where speech is forbidden).
24+
// For voice intents (AMAZON.NextIntent), include speech to keep the session alive
25+
// so subsequent "Alexa next/skip" commands continue routing to the skill.
26+
const mediaResponseOnly = isPlaybackController;
27+
28+
debug('Request type:', requestType);
29+
debug('Is PlaybackController:', isPlaybackController);
30+
debug('mediaResponseOnly:', mediaResponseOnly);
31+
debug('Player activity:', playerActivity);
32+
33+
return helpers.playSong({ app, skip: 'forward', mediaResponseOnly })
34+
.then((res) => {
35+
const { currentSongData } = res || {};
36+
if (res && !currentSongData) {
1837
error('We do not have any data for previous song');
19-
} else {
38+
} else if (res) {
2039
return skippedSong(app, {
2140
albumId: currentSongData.album.id,
2241
filename: currentSongData.filename
@@ -25,6 +44,10 @@ function handler (app) {
2544
})
2645
.catch(e => {
2746
debug('It could be an error:', e);
47+
if (mediaResponseOnly) {
48+
app.stopPlayback();
49+
return null;
50+
}
2851
return dialog.ask(app, strings.events.playlistIsEnded);
2952
});
3053
}

functions/src/actions/playback/previous.js

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,21 @@ const helpers = require('./_helpers');
1010
* @param app
1111
*/
1212
function handler (app) {
13-
return helpers.playSong({ app, skip: 'back' })
13+
const requestType = app.params.getByName('type');
14+
const isPlaybackController = typeof requestType === 'string' &&
15+
requestType.startsWith('PlaybackController.');
16+
// Only suppress speech for PlaybackController events (where speech is forbidden).
17+
// For voice intents (AMAZON.PreviousIntent), include speech to keep the session alive
18+
// so subsequent voice commands continue routing to the skill.
19+
const mediaResponseOnly = isPlaybackController;
20+
21+
return helpers.playSong({ app, skip: 'back', mediaResponseOnly })
1422
.catch(e => {
1523
debug('It could be an error:', e);
24+
if (mediaResponseOnly) {
25+
app.stopPlayback();
26+
return null;
27+
}
1628
return dialog.ask(app, strings.events.playlistIsEnded);
1729
});
1830
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
/**
2+
* Handle stop intent during playback state.
3+
* Stop and exit are synonymous intents.
4+
*
5+
* @type {{handler: handler}}
6+
*/
7+
module.exports = Object.assign({}, require('./exit'));

0 commit comments

Comments
 (0)