-
Notifications
You must be signed in to change notification settings - Fork 2
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[DRAFT] Version 2 Features Implementation #4
base: main
Are you sure you want to change the base?
Conversation
WalkthroughThe changes involve updates to several interaction model files for different languages, focusing on adding new intents related to adhaan recitation, modifying existing intents, and refining sample phrases. New intents such as Changes
Poem
Tip CodeRabbit's docstrings feature is now available as part of our Early Access Program! Simply use the command Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media? 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 17
🧹 Outside diff range and nitpick comments (12)
lambda/interceptors.js (4)
91-97
: Unnecessary use of 'async' in 'LocalizationInterceptor'The
process
method is declared asasync
but does not contain anyawait
statements. Consider removing theasync
keyword if asynchronous operations are not utilized within the method.
94-96
: Clarify conditional logic in 'LocalizationInterceptor'The condition
if(isValidRequestType(requestType))
checks for request types where localization should be skipped. Consider renaming the functionisValidRequestType
toshouldSkipLocalization
or inverting the condition to improve code readability.
134-140
: Update comment to reflect interceptor's purposeThe comment inside the
if
block mentions localization, which may not align with the purpose of theSavePersistenceAttributesToSession
interceptor. Update the comment to accurately reflect that persistence attributes should not be saved when the skill is disabled.
190-192
: Function name 'isValidRequestType' may be misleadingThe function
isValidRequestType
returnstrue
for request types where processing should be skipped. Consider renaming it toshouldSkipProcessing
orisExcludedRequestType
to better convey its purpose.lambda/handlers/intentHandler.js (1)
659-659
: Specify radix parameter inparseInt
to avoid unexpected resultsWhen using
parseInt
, it's best practice to specify the radix parameter to prevent unexpected behavior due to different number bases.Apply this diff:
-const adhaanReciter = adhaanRecitation[parseInt(favouriteReciter) - 1]; +const adhaanReciter = adhaanRecitation[parseInt(favouriteReciter, 10) - 1];lambda/handlers/audioPlayerHandler.js (1)
15-18
: Fix operator precedence in canHandle methodThe parentheses around the startsWith check are unnecessary and might be confusing.
canHandle(handlerInput) { - return ( - Alexa.getRequestType(handlerInput.requestEnvelope).startsWith("PlaybackController") - ); + return Alexa.getRequestType(handlerInput.requestEnvelope).startsWith("PlaybackController"); },lambda/datasources.js (2)
114-138
: Add input validation in getMetadataThe function assumes all required attributes exist and are valid.
const getMetadata = (handlerInput, title) => { + if (!handlerInput || !title) { + throw new Error("Missing required parameters in getMetadata"); + } const requestAttributes = handlerInput.attributesManager.getRequestAttributes(); + if (!requestAttributes) { + throw new Error("Request attributes not available"); + } let albumArtImage = requestAttributes.t("logoUrl"); + if (!albumArtImage) { + albumArtImage = "default_logo_url"; // Add a default fallback + } let metadata = { title: title, subtitle: requestAttributes.t("skillName"),
110-112
: Add JSDoc documentation for getDataSourceForAdhaanReciterThe function lacks documentation about its parameters and return value.
+/** + * Generates data source for adhaan reciter list + * @param {Object} handlerInput - The Alexa skill handler input + * @param {Array} adhaanRecitation - List of available adhaan recitations + * @returns {Promise<Object>} Data source for the APL template + */ const getDataSourceForAdhaanReciter = async (handlerInput, adhaanRecitation) => { return getDataSourceforMosqueList(handlerInput, adhaanRecitation, "titleForAdhaanReciterList"); };lambda/prompts/en_US.js (1)
49-53
: Ensure consistent user experience across touch and voice interactions.The prompts effectively guide users through both voice and touch interactions for selecting adhan recitations. However, consider adding validation feedback when users make their selection to confirm their choice before finalizing it.
adhanReciterPrompt: `Which recitation would you like to set as favourite for the adhan? You can choose between %s. You can choose by saying the number associated with the recitation `, +adhanReciterConfirmationPrompt: `You've selected %s. Is this correct? Say yes to confirm or no to choose again.`, adhanReciterErrorPrompt: `Sorry, I couldn't find any recitations for the adhan. Please try again.`, adhanReciterSuccessPrompt: `Perfect, %s is now your favorite recitation for the adhan! `,
lambda/index.js (1)
46-54
: Enhance error handling for directive service failuresWhile logging the error is good, consider providing a graceful fallback for users when the directive service fails.
async handle(handlerInput) { const { attributesManager } = handlerInput; const requestAttributes = attributesManager.getRequestAttributes(); await helperFunctions .callDirectiveService(handlerInput, requestAttributes.t("welcomePrompt")) .catch((error) => { console.log("Error while calling directive service: ", error); + // Provide a graceful fallback response + handlerInput.responseBuilder.speak(requestAttributes.t("welcomePrompt")); }); return await helperFunctions.checkForPersistenceData(handlerInput); }interactionModels/de-DE.json (1)
243-250
: Add sample utterances for audio control intentsConsider adding German sample utterances for AMAZON.ResumeIntent and AMAZON.PauseIntent to improve voice interaction.
{ "name": "AMAZON.ResumeIntent", - "samples": [] + "samples": [ + "weiter", + "fortsetzen", + "weitermachen", + "fortfahren" + ] }, { "name": "AMAZON.PauseIntent", - "samples": [] + "samples": [ + "pause", + "pausieren", + "anhalten", + "unterbrechen" + ] }interactionModels/en-US.json (1)
293-298
: Add sample utterances for audio control intentsConsider adding sample utterances for AMAZON.PauseIntent and AMAZON.ResumeIntent to improve voice interaction.
{ "name": "AMAZON.PauseIntent", - "samples": [] + "samples": [ + "pause", + "pause the audio", + "stop playing", + "pause playback" + ] }, { "name": "AMAZON.ResumeIntent", - "samples": [] + "samples": [ + "resume", + "continue", + "continue playing", + "resume playback" + ] }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (20)
interactionModels/de-DE.json
(4 hunks)interactionModels/en-AU.json
(0 hunks)interactionModels/en-CA.json
(0 hunks)interactionModels/en-GB.json
(0 hunks)interactionModels/en-IN.json
(0 hunks)interactionModels/en-US.json
(6 hunks)interactionModels/fr-CA.json
(0 hunks)interactionModels/fr-FR.json
(17 hunks)lambda/aplDocuments/mosqueListApl.json
(1 hunks)lambda/datasources.js
(3 hunks)lambda/handlers/audioPlayerHandler.js
(1 hunks)lambda/handlers/intentHandler.js
(4 hunks)lambda/handlers/touchHandler.js
(3 hunks)lambda/helperFunctions.js
(3 hunks)lambda/index.js
(3 hunks)lambda/interceptors.js
(6 hunks)lambda/languageStrings.js
(2 hunks)lambda/prompts/de_DE.js
(1 hunks)lambda/prompts/en_US.js
(1 hunks)lambda/prompts/fr_FR.js
(1 hunks)
💤 Files with no reviewable changes (5)
- interactionModels/en-CA.json
- interactionModels/en-IN.json
- interactionModels/fr-CA.json
- interactionModels/en-AU.json
- interactionModels/en-GB.json
🧰 Additional context used
🪛 Biome (1.9.4)
lambda/handlers/intentHandler.js
[error] 319-319: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
lambda/interceptors.js
[error] 40-40: Change to an optional chain.
Unsafe fix: Change to an optional chain.
(lint/complexity/useOptionalChain)
🔇 Additional comments (13)
lambda/interceptors.js (1)
30-31
: Approve addition of async and response check in 'AddDirectiveResponseInterceptor'
The change to make the process
method asynchronous and to add a check for undefined response
improves the robustness of the code by preventing potential runtime errors.
lambda/languageStrings.js (2)
3-3
: Addition of German language support
The import statement for de_DE
is correctly added, enabling German language prompts.
13-13
: Exporting 'de-DE' mapping
The mapping for 'de-DE'
is correctly added to the exports, enabling language support for German users.
lambda/aplDocuments/mosqueListApl.json (1)
32-32
: Addition of title to 'SendEvent' arguments
Including "${payload.imageListData.title}"
in the arguments
array provides additional context to the event handler, which can enhance user interaction handling.
lambda/prompts/en_US.js (1)
48-48
: LGTM!
The formatting change maintains consistency with other prompts.
lambda/index.js (3)
24-36
: LGTM: Import statements are properly structured
The new imports for audio-related handlers and favorite adhaan reciter functionality are well-organized and align with the Version 2 feature requirements.
Line range hint 192-208
: LGTM: Handler chain is properly ordered
The new audio and adhaan reciter handlers are correctly positioned in the chain, with audio handlers having appropriate precedence.
216-219
: LGTM: Interceptors are properly ordered
The interceptor chain is well-organized with logging, localization, and persistence interceptors in the correct order.
interactionModels/de-DE.json (1)
281-283
: LGTM: Prayer name formatting is consistent
The apostrophe usage in prayer names has been standardized correctly.
Also applies to: 292-294
interactionModels/en-US.json (1)
162-165
: LGTM: Sample utterances are well-defined
The new sample utterances for NextPrayerTimeIntent provide good coverage of natural language variations.
interactionModels/fr-FR.json (2)
323-328
: LGTM: Built-in Alexa intents
The addition of AMAZON.ResumeIntent and AMAZON.PauseIntent with empty samples is correct as these are built-in Alexa intents that handle standard pause/resume commands.
390-390
: Verify apostrophe handling in "isha'a"
While adding this synonym improves voice recognition, verify that the apostrophe in "isha'a" is properly handled by Alexa's speech recognition system.
✅ Verification successful
Apostrophe in "isha'a" is safe to use
The search results show that apostrophes are already successfully used throughout the interaction models:
- In French (fr-FR) for contractions like "l'heure", "d'aujourd'hui"
- In English (en-US) for contractions like "I'm", "don't" and prayer name "Jumu'ah"
- In German (de-DE) for prayer names including "Isha'a" itself
The apostrophe in "isha'a" follows the same pattern as other prayer names and contractions that are already working in the interaction models, making it a safe addition.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check if other intents in the model use apostrophes successfully
rg -l "'" interactionModels/
Length of output: 116
Script:
#!/bin/bash
# Check actual usage of apostrophes in interaction models
rg -A 2 -B 2 "'" interactionModels/*.json
Length of output: 10494
lambda/helperFunctions.js (1)
85-87
: Verify impact of removing welcome prompt
The removal of the welcome prompt parameter might affect the user experience. Ensure this change aligns with the intended interaction flow.
✅ Verification successful
Removal of welcome prompt parameter is safe
The welcome message is still properly handled through the main index.js using callDirectiveService
with the localized welcome prompt. The removal of the welcome prompt parameter from getPrayerTimingsForMosque
and getListOfMosque
functions doesn't impact the user experience as the welcome message is delivered separately through the directive service.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Check usage of welcome prompts across the codebase
rg "welcomePrompt|welcome_prompt" --type js
Length of output: 332
Script:
#!/bin/bash
# Check the implementation of getPrayerTimingsForMosque and getListOfMosque functions
ast-grep --pattern 'function getPrayerTimingsForMosque($_,$_,$_) { $$$ }'
ast-grep --pattern 'function getListOfMosque($_,$_) { $$$ }'
# Check for any other welcome message handling
rg "welcomePrompt" -B 2 -A 2 --type js
Length of output: 2035
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (2)
lambda/handlers/audioPlayerHandler.js (1)
6-9
: Add logging toAudioPlayerEventHandler
for better debuggingCurrently, the
AudioPlayerEventHandler
returns a response without any logging. Adding logging statements can help in debugging audio player events.Consider adding a console log in the
handle
method:async handle(handlerInput) { + const audioPlayerEvent = Alexa.getRequestType(handlerInput.requestEnvelope); + console.log("Audio Player Event:", audioPlayerEvent); return handlerInput.responseBuilder.getResponse(); },lambda/handlers/intentHandler.js (1)
562-640
: Handle potential errors in translation serviceIn
FavoriteAdhaanReciterStartedHandler
, the translation ofadhaan.primaryText
may fail if the translation service encounters an error. This could break the skill's flow.Consider adding error handling for the translation calls:
try { adhaan.primaryText = await helperFunctions.translateText( adhaan.primaryText, locale ); } catch (translationError) { console.log("Translation error:", translationError); // Fallback to original text if translation fails adhaan.primaryText = adhaan.primaryText; }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (8)
interactionModels/en-US.json
(6 hunks)interactionModels/fr-FR.json
(17 hunks)lambda/handlers/audioPlayerHandler.js
(1 hunks)lambda/handlers/intentHandler.js
(4 hunks)lambda/helperFunctions.js
(3 hunks)lambda/interceptors.js
(6 hunks)lambda/prompts/de_DE.js
(1 hunks)lambda/prompts/fr_FR.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lambda/prompts/de_DE.js
🔇 Additional comments (16)
lambda/handlers/audioPlayerHandler.js (3)
47-55
: Add handling for AMAZON.PauseIntent
The PauseIntent
currently falls through to the default case. Consider adding specific handling to properly manage the pause action.
As previously suggested, apply this diff:
switch (intent) {
case "AMAZON.ResumeIntent":
return await intentHandler.PlayAdhanIntentHandler.handle(handlerInput);
+ case "AMAZON.PauseIntent":
+ return handlerInput.responseBuilder
+ .addAudioPlayerStopDirective()
+ .withShouldEndSession(false) // Allow resuming later
+ .getResponse();
default:
return handlerInput.responseBuilder
.addAudioPlayerStopDirective()
.withShouldEndSession(true)
.getResponse();
}
21-32
: 🛠️ Refactor suggestion
Add error handling for PlayAdhanIntentHandler
In PlaybackCommandHandler
, the playback commands delegate to PlayAdhanIntentHandler
without error handling. Wrapping the call in a try-catch block can handle unexpected errors gracefully.
Apply this diff to add error handling:
switch (playback) {
case "PlaybackController.PlayCommandIssued":
case "PlaybackController.NextCommandIssued":
case "PlaybackController.PreviousCommandIssued":
- return await intentHandler.PlayAdhanIntentHandler.handle(handlerInput);
+ try {
+ return await intentHandler.PlayAdhanIntentHandler.handle(handlerInput);
+ } catch (error) {
+ console.error("Error in PlayAdhanIntentHandler:", error);
+ return handlerInput.responseBuilder
+ .speak("Sorry, there was an error playing the adhaan.")
+ .withShouldEndSession(true)
+ .getResponse();
+ }
default:
return handlerInput.responseBuilder
.addAudioPlayerStopDirective()
.withShouldEndSession(true)
.getResponse();
}
38-42
:
Fix logical operator precedence in canHandle
method
In AudioIntentHandler
, the condition in the canHandle
method may produce unexpected results due to operator precedence. Enclosing the ||
conditions within parentheses ensures correct evaluation.
Apply this diff to fix the logical operator precedence:
return (
Alexa.getRequestType(handlerInput.requestEnvelope) === "IntentRequest" &&
- Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.ResumeIntent" ||
- Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.PauseIntent"
+ (Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.ResumeIntent" ||
+ Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.PauseIntent")
);
lambda/handlers/intentHandler.js (2)
666-668
:
Initialize persistentAttributes
before assignment
Ensure that sessionAttributes.persistentAttributes
is initialized before assigning favouriteAdhaan
to prevent potential runtime errors.
Apply this diff to initialize persistentAttributes
if undefined:
+ if (!sessionAttributes.persistentAttributes) {
+ sessionAttributes.persistentAttributes = {};
+ }
sessionAttributes.persistentAttributes.favouriteAdhaan = adhaanReciter;
314-336
:
Ensure persistentAttributes
is defined before use
In PlayAdhanIntentHandler
, persistentAttributes
may be undefined if not previously set. Accessing properties on an undefined object can cause runtime errors.
Modify the code to check if persistentAttributes
and persistentAttributes.favouriteAdhaan
are defined:
const { persistentAttributes } = sessionAttributes;
let audioName = "Adhaan";
let audioUrl = prayerName === "0" ? adhaanRecitation[0].fajrUrl : adhaanRecitation[0].otherUrl;
- if(persistentAttributes?.favouriteAdhaan){
+ if (persistentAttributes && persistentAttributes.favouriteAdhaan) {
const { primaryText } = persistentAttributes.favouriteAdhaan;
audioName = primaryText;
audioUrl = prayerName === "0" ? persistentAttributes.favouriteAdhaan.fajrUrl : persistentAttributes.favouriteAdhaan.otherUrl;
}
Likely invalid or redundant comment.
lambda/prompts/fr_FR.js (1)
52-57
: Verify the accuracy and naturalness of French translations
Please ensure that the French translations for the new prompts accurately reflect the intended meanings and are idiomatic.
Consider consulting a native French speaker or a professional translator to review the following prompts:
adhanReciterPrompt
adhanReciterErrorPrompt
adhanReciterSuccessPrompt
chooseAdhaanByTouchPrompt
lambda/interceptors.js (1)
189-193
:
Correct typo in function name SetApiKeysAsEnvironmentVaraibleFromAwsSsm
The function name contains a typo: "Varaible" should be "Variable". Ensure all references are updated accordingly.
Apply this diff to fix the typo:
- const SetApiKeysAsEnvironmentVaraibleFromAwsSsm = {
+ const SetApiKeysAsEnvironmentVariableFromAwsSsm = {
And update the export statement:
module.exports = {
LogResponseInterceptor,
LogRequestInterceptor,
LocalizationInterceptor,
SavePersistenceAttributesToSession,
AddDirectiveResponseInterceptor,
- SetApiKeysAsEnvironmentVaraibleFromAwsSsm
+ SetApiKeysAsEnvironmentVariableFromAwsSsm
};
interactionModels/en-US.json (4)
Line range hint 162-177
: LGTM! Good variety of sample utterances
The sample utterances provide comprehensive coverage of different ways users might ask about prayer times.
451-459
: LGTM! Clear elicitation prompt
The prompt is clear and appropriate for number input.
292-298
: Verify audio player implementation
The addition of AMAZON.PauseIntent and AMAZON.ResumeIntent suggests audio playback functionality.
Let's verify the audio player implementation:
✅ Verification successful
Audio player implementation is properly implemented
The codebase has a complete audio player implementation with:
- Dedicated
AudioPlayerEventHandler
for handling audio player events AudioIntentHandler
specifically handling AMAZON.PauseIntent and AMAZON.ResumeIntent- Proper audio playback directives (.addAudioPlayerPlayDirective and .addAudioPlayerStopDirective)
- Integration with the skill's main functionality for playing Adhan (call to prayer)
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Search for audio player handler implementation
ast-grep --pattern 'class $_ {
$$$
handle$_(handlerInput) {
$$$
AMAZON.$_Intent
$$$
}
$$$
}'
Length of output: 114
Script:
#!/bin/bash
# Search for audio player related handlers and implementations
rg -i "pause|resume|audioplayer" -A 5 -B 5
# Also check for audio player interface declaration
rg -i "audioPlayer" -A 2 -B 2
Length of output: 11014
38-54
: 🛠️ Refactor suggestion
Add input validation for reciter selection
The favouriteReciter
slot uses AMAZON.NUMBER without bounds checking, which could allow invalid selections.
Let's verify the available reciter options:
Consider adding validation in the handler to ensure the selected number corresponds to a valid reciter option.
interactionModels/fr-FR.json (2)
331-343
: LGTM! Well-localized French utterances
The French sample utterances are properly localized and provide good coverage.
522-525
: LGTM! Properly translated prompt
The elicitation prompt is correctly translated to French.
lambda/helperFunctions.js (3)
466-489
: LGTM! Well-implemented progressive response handling
The implementation includes proper error handling and follows best practices.
491-493
: LGTM! Correct Promise implementation
The sleep function is properly implemented using Promise and setTimeout.
85-87
: Consider user experience impact
Removing the welcome prompt might affect the user experience for first-time users.
Let's check if the welcome prompt is handled elsewhere:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 2
🧹 Outside diff range and nitpick comments (1)
lambda/handlers/intentHandler.js (1)
317-323
: Add fallback handling for audio URL selectionThe logic for selecting the audio URL is correct but could be more robust with default values and destructuring.
Consider this refactor:
-let audioName = "Adhaan"; -let audioUrl = prayerName === "0"? adhaanRecitation[0].fajrUrl : adhaanRecitation[0].otherUrl; -if(persistentAttributes?.favouriteAdhaan){ - const { primaryText } = persistentAttributes.favouriteAdhaan; - audioName = primaryText; - audioUrl = prayerName === "0"? persistentAttributes.favouriteAdhaan.fajrUrl : persistentAttributes.favouriteAdhaan.otherUrl; -} +const defaultReciter = adhaanRecitation[0]; +const favoriteReciter = persistentAttributes?.favouriteAdhaan; +const selectedReciter = favoriteReciter || defaultReciter; +const audioName = selectedReciter.primaryText || "Adhaan"; +const audioUrl = prayerName === "0" ? selectedReciter.fajrUrl : selectedReciter.otherUrl;
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (1)
lambda/handlers/intentHandler.js
(4 hunks)
🧰 Additional context used
🪛 Biome (1.9.4)
lambda/handlers/intentHandler.js
[error] 660-660: isNaN is unsafe. It attempts a type coercion. Use Number.isNaN instead.
See the MDN documentation for more details.
Unsafe fix: Use Number.isNaN instead.
(lint/suspicious/noGlobalIsNan)
🔇 Additional comments (1)
lambda/handlers/intentHandler.js (1)
671-673
:
Initialize persistentAttributes before assignment
This is a duplicate of a previously identified issue where persistentAttributes
needs to be initialized before use.
Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 7
🧹 Outside diff range and nitpick comments (4)
lambda/handlers/intentHandler.js (1)
658-658
: Specify radix parameter inparseInt
When using
parseInt
, it's recommended to specify the radix to avoid unexpected results due to different number formats.Suggested fix:
- const reciterIndex = parseInt(favouriteReciter) - 1; + const reciterIndex = parseInt(favouriteReciter, 10) - 1;lambda/handlers/apiHandler.js (1)
73-90
: LGTM with suggestions for error handling enhancement.The implementation follows the established pattern in the codebase for API calls. However, consider enhancing the error handling to provide more specific error messages for different failure scenarios.
const getRandomHadith = async (lang = "ar") => { const config = getConfig("get", `/hadith/random?lang=${lang}`, "2.0"); console.log("Config: ", JSON.stringify(config, null, 2).replace(/Bearer \w+/g, "Bearer ****")); return await axios .request(config) .then((response) => { console.log("Hadith: ", JSON.stringify(response.data)); if (!response || !response.data || !response.data.text) { - throw "Received Empty Response"; + throw new Error("No hadith text found in response"); } return response.data.text; }) .catch((error) => { console.log("Error while fetching Hadith: ", error); + if (error.response) { + switch (error.response.status) { + case 404: + throw new Error("No hadith found for the specified language"); + case 429: + throw new Error("Rate limit exceeded"); + default: + throw new Error(`API error: ${error.response.status}`); + } + } throw error; }); }lambda/helperFunctions.js (1)
466-489
: Consider enhancing error handling with specific error types.While the implementation is good, error handling could be more specific.
Consider this enhancement:
async function callDirectiveService(handlerInput, speakOutput) { console.log("Call Directive Service"); try { const requestEnvelope = handlerInput.requestEnvelope; const directiveServiceClient = handlerInput.serviceClientFactory.getDirectiveServiceClient(); const requestId = requestEnvelope.request.requestId; const directive = { header: { requestId, }, directive: { type: 'VoicePlayer.Speak', speech: speakOutput, }, }; return await directiveServiceClient.enqueue(directive); } catch (error) { - console.error('Error calling directive service:', error); + if (error.name === 'ServiceError') { + console.error('Service error in directive service:', error.message); + } else if (error.name === 'DirectiveServiceError') { + console.error('Directive service error:', error.message); + } else { + console.error('Unexpected error in directive service:', error); + } // Continue skill flow without progressive response return Promise.resolve(); } }lambda/index.js (1)
218-221
: Consider the order of request interceptorsThe sequence of request interceptors can affect their functionality. It might be beneficial to place
SetApiKeysAsEnvironmentVariableFromAwsSsm
beforeLocalizationInterceptor
if localization depends on environment variables set by it.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (12)
interactionModels/de-DE.json
(4 hunks)interactionModels/en-US.json
(6 hunks)interactionModels/fr-FR.json
(17 hunks)lambda/handlers/apiHandler.js
(3 hunks)lambda/handlers/audioPlayerHandler.js
(1 hunks)lambda/handlers/intentHandler.js
(4 hunks)lambda/helperFunctions.js
(4 hunks)lambda/index.js
(3 hunks)lambda/interceptors.js
(5 hunks)lambda/prompts/de_DE.js
(1 hunks)lambda/prompts/en_US.js
(1 hunks)lambda/prompts/fr_FR.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- lambda/prompts/en_US.js
- interactionModels/de-DE.json
🧰 Additional context used
📓 Learnings (1)
lambda/handlers/audioPlayerHandler.js (1)
Learnt from: ijaz26
PR: mawaqit/alexa#4
File: lambda/handlers/audioPlayerHandler.js:22-27
Timestamp: 2024-12-12T13:46:45.984Z
Learning: In the file `lambda/handlers/audioPlayerHandler.js`, the `PlaybackCommandHandler` delegates to `PlayAdhanIntentHandler` without additional error handling, and this is acceptable.
🪛 Biome (1.9.4)
lambda/handlers/intentHandler.js
[error] 695-698: This block statement doesn't serve any purpose and can be safely removed.
Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.
(lint/complexity/noUselessLoneBlockStatements)
🔇 Additional comments (19)
lambda/prompts/de_DE.js (1)
54-54
:
Translate 'hadithErrorPrompt' to German
The prompt for 'hadithErrorPrompt' is in English. Please translate it to German to maintain consistency and provide a seamless user experience.
Suggested fix:
- hadithErrorPrompt: `Sorry, I couldn't find any hadiths. Please try again.`,
+ hadithErrorPrompt: `Entschuldigung, ich konnte keine Hadithe finden. Bitte versuchen Sie es erneut.`,
lambda/handlers/intentHandler.js (1)
670-672
:
Initialize 'persistentAttributes' before assignment
Ensure that sessionAttributes.persistentAttributes
is initialized before assigning favouriteAdhaan
to prevent potential runtime errors.
Suggested fix:
+ sessionAttributes.persistentAttributes = sessionAttributes.persistentAttributes || {};
sessionAttributes.persistentAttributes.favouriteAdhaan = adhaanReciter;
lambda/handlers/audioPlayerHandler.js (1)
40-44
:
Fix logical operator precedence in canHandle
method
The current condition may not behave as intended due to operator precedence. To correctly check if the request is an IntentRequest
and the intent name is either AMAZON.ResumeIntent
or AMAZON.PauseIntent
, we should adjust the parentheses.
Suggested fix:
return (
Alexa.getRequestType(handlerInput.requestEnvelope) === "IntentRequest" &&
- Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.ResumeIntent" ||
- Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.PauseIntent"
+ (
+ Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.ResumeIntent" ||
+ Alexa.getIntentName(handlerInput.requestEnvelope) === "AMAZON.PauseIntent"
+ )
);
lambda/interceptors.js (2)
30-31
: LGTM! Improved code robustness.
Good improvements:
- Added null check for response
- Updated to use optional chaining for safer property access
Also applies to: 40-40
190-192
: LGTM! Good function extraction.
The isValidRequestType
function effectively consolidates the request type validation logic.
interactionModels/en-US.json (3)
109-111
: LGTM! Natural language samples.
The fallback samples are well-chosen and follow natural conversation patterns.
162-165
: LGTM! Comprehensive prayer time query samples.
The new samples provide good coverage for different ways users might ask about prayer times.
292-299
: LGTM! Proper implementation of media control intents.
The AMAZON.PauseIntent and AMAZON.ResumeIntent are correctly implemented as built-in intents.
interactionModels/fr-FR.json (2)
73-78
: LGTM! Natural French translations.
The French samples are well-translated and maintain natural language patterns.
Also applies to: 97-101
331-344
: LGTM! Well-localized reciter selection intent.
The French implementation provides good coverage with natural language samples.
lambda/helperFunctions.js (2)
85-87
: LGTM! Simplified persistence check flow.
The changes streamline the function by removing unnecessary parameters.
Line range hint 452-465
: LGTM! Improved language handling.
The function now properly handles language codes with better error management.
lambda/index.js (7)
193-195
: Ensure correct ordering of audio handlers
The AudioPlayerEventHandler
, PlaybackCommandHandler
, and AudioIntentHandler
have been added. Verify that these handlers are ordered correctly in the handler chain to prioritize specific intent handling and prevent conflicts.
202-202
: Verify the placement of HadithIntentHandler
Confirm that the HadithIntentHandler
is correctly placed in the request handler chain to ensure it processes HadithIntent
without interference from other handlers.
210-210
: Ensure AdhaanRecitationTouchEventHandler
is correctly implemented
The AdhaanRecitationTouchEventHandler
has been added to handle touch events. Verify that it is properly implemented and integrated with the skill's touch interface.
42-44
: Verify the necessity of handling "LaunchIntent"
In the LaunchRequestHandler
, you are checking for an IntentRequest
with the intent name "LaunchIntent"
. Typically, the skill launch is handled by "LaunchRequest"
. Ensure that "LaunchIntent"
is defined in your interaction model and that this check is required.
Run the following script to confirm if "LaunchIntent"
exists in your interaction models:
✅ Verification successful
Let me check the interaction model files to understand how this LaunchIntent
is defined and used.
The handling of "LaunchIntent" is correctly implemented
The LaunchIntent
is properly defined in all interaction models with appropriate utterances for launching the skill in different languages (e.g., "open mawaqit", "launch mawaqit", etc.). The code's dual handling of both LaunchRequest
and LaunchIntent
is intentional and correct, allowing users to start the skill either through the default launch phrase or through these custom launch utterances.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Search for "LaunchIntent" in the interaction model files.
# Test: Check for the definition of "LaunchIntent".
# Expect: Find intent definitions if it exists.
rg '"name":\s*"LaunchIntent"' interactionModels/
Length of output: 680
Script:
#!/bin/bash
# Get a sample of the LaunchIntent definition from one of the interaction models
cat interactionModels/en-US.json | jq '.interactionModel.languageModel.intents[] | select(.name == "LaunchIntent")'
# Check if there are any sample utterances or other handlers using LaunchIntent
rg -A 5 '"LaunchIntent"' interactionModels/
Length of output: 3880
47-54
: Unnecessary await
with checkForPersistenceData
You're using await
with helperFunctions.checkForPersistenceData(handlerInput);
. If checkForPersistenceData
is not an asynchronous function returning a promise, the await
keyword is unnecessary and should be removed to avoid potential delays.
Run the following script to verify if checkForPersistenceData
is asynchronous:
205-207
: Confirm the addition of new intent handlers
The handlers SelectMosqueIntentAfterSelectingMosqueHandler
, FavoriteAdhaanReciterStartedHandler
, and FavoriteAdhaanReciterIntentHandler
have been added. Ensure these handlers are properly implemented and their corresponding intents are defined in the interaction model.
Run the following script to check for the intents:
✅ Verification successful
Let me verify the implementation of these handlers.
Let me check if these handlers are properly registered in the skill builder.
Let me check the rest of the skill builder registration to see if our new handlers are included.
All handlers are properly implemented and registered
Based on the verification results:
- All three handlers (
SelectMosqueIntentAfterSelectingMosqueHandler
,FavoriteAdhaanReciterStartedHandler
, andFavoriteAdhaanReciterIntentHandler
) are fully implemented inlambda/handlers/intentHandler.js
- The handlers are properly registered in the skill builder
- The
FavoriteAdhaanReciterIntent
is defined in both en-US and fr-FR interaction models - While
SelectMosqueIntentAfterSelectingMosque
intent is not found in interaction models, it's because it reuses the existingSelectMosqueIntent
with a specific slot value condition in itscanHandle
method
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that the new intents are defined.
# Test: Search for intent definitions.
# Expect: Find definitions of the intents.
rg '"name":\s*"SelectMosqueIntentAfterSelectingMosque"' interactionModels/
rg '"name":\s*"FavoriteAdhaanReciterStartedIntent"' interactionModels/
rg '"name":\s*"FavoriteAdhaanReciterIntent"' interactionModels/
Length of output: 527
Script:
#!/bin/bash
# Check for handler implementations
ast-grep --pattern 'const SelectMosqueIntentAfterSelectingMosqueHandler = {
$$$
}'
ast-grep --pattern 'const FavoriteAdhaanReciterStartedHandler = {
$$$
}'
ast-grep --pattern 'const FavoriteAdhaanReciterIntentHandler = {
$$$
}'
# Also check if these handlers are properly registered
rg -A 5 "exports.handler = Alexa.SkillBuilders" lambda/
Length of output: 14602
Script:
#!/bin/bash
# Check if the new handlers are registered in the skill builder
rg -B 5 -A 15 'exports.handler = Alexa.SkillBuilders' lambda/index.js
Length of output: 830
Script:
#!/bin/bash
# Get more lines of the skill builder registration
rg -B 5 -A 30 'exports.handler = Alexa.SkillBuilders' lambda/index.js
Length of output: 1304
10-10
: Verify the correct import of SetApiKeysAsEnvironmentVariableFromAwsSsm
Ensure that SetApiKeysAsEnvironmentVariableFromAwsSsm
is correctly exported and spelled consistently across the codebase.
Run the following script to check its export:
✅ Verification successful
SetApiKeysAsEnvironmentVariableFromAwsSsm
is correctly defined and used
The interceptor is properly defined in lambda/interceptors.js
as an object and is correctly imported and used in lambda/index.js
. The naming is consistent across all occurrences in the codebase.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify that `SetApiKeysAsEnvironmentVariableFromAwsSsm` is exported from 'interceptors.js'.
# Test: Search for the export statement. Expect: Find the export of the interceptor.
rg 'exports\.SetApiKeysAsEnvironmentVariableFromAwsSsm' lambda/interceptors.js
Length of output: 80
Script:
#!/bin/bash
# Let's try different search patterns to find this function/class
# Search for the exact name in all files
rg "SetApiKeysAsEnvironmentVariableFromAwsSsm" -A 3
# Search for similar names (in case of typos)
rg -i "set.*api.*keys.*environment.*ssm"
# Look for exports containing similar patterns
rg "exports\.(Set|set).*SSM"
# Use ast-grep to find function/class declarations with similar name
ast-grep --pattern 'function SetApiKeysAsEnvironmentVariableFromAwsSsm($_) { $$$ }'
ast-grep --pattern 'class SetApiKeysAsEnvironmentVariableFromAwsSsm { $$$ }'
Length of output: 1696
lambda/handlers/intentHandler.js
Outdated
const hadith = await getRandomHadith(locale).catch((error) => {{ | ||
console.log("Error in fetching hadith: ", error); | ||
return requestAttributes.t("hadithErrorPrompt"); | ||
}}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Remove redundant block statement
There is an unnecessary block statement in the catch
block that can be safely removed to simplify the code.
Suggested fix:
- const hadith = await getRandomHadith(locale).catch((error) => {{
+ const hadith = await getRandomHadith(locale).catch((error) => {
console.log("Error in fetching hadith: ", error);
return requestAttributes.t("hadithErrorPrompt");
- }});
+ });
📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
const hadith = await getRandomHadith(locale).catch((error) => {{ | |
console.log("Error in fetching hadith: ", error); | |
return requestAttributes.t("hadithErrorPrompt"); | |
}}); | |
const hadith = await getRandomHadith(locale).catch((error) => { | |
console.log("Error in fetching hadith: ", error); | |
return requestAttributes.t("hadithErrorPrompt"); | |
}); |
🧰 Tools
🪛 Biome (1.9.4)
[error] 695-698: This block statement doesn't serve any purpose and can be safely removed.
Standalone block statements without any block-level declarations are redundant in JavaScript and can be removed to simplify the code.
Safe fix: Remove redundant block.
(lint/complexity/noUselessLoneBlockStatements)
lambda/handlers/apiHandler.js
Outdated
@@ -1,4 +1,5 @@ | |||
const axios = require("axios"); | |||
const { lang } = require("moment"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove unused import.
The lang
import from moment
is not used in the code.
-const { lang } = require("moment");
}, | ||
{ | ||
"slots": [ | ||
{ | ||
"name": "favouriteReciter", | ||
"elicitationRequired": true, | ||
"type": "AMAZON.NUMBER", | ||
"confirmationRequired": false, | ||
"prompts": { | ||
"elicitation": "Elicit.Slot.102046521153.828952134948" | ||
} | ||
} | ||
], | ||
"name": "FavoriteAdhaanReciterIntent", | ||
"delegationStrategy": "SKILL_RESPONSE", | ||
"confirmationRequired": false, | ||
"prompts": {} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
💡 Codebase verification
Slot elicitation prompt is missing variations
The elicitation prompt ID "Elicit.Slot.102046521153.828952134948" is referenced in the intent but lacks corresponding prompt variations in the prompts section. This will cause the slot elicitation to fail.
- Add prompt variations for ID "Elicit.Slot.102046521153.828952134948" in the prompts section with appropriate messages for asking users to select their favorite reciter number.
🔗 Analysis chain
LGTM! Verify slot elicitation behavior.
The intent structure follows best practices with proper slot configuration and elicitation setup.
🏁 Scripts executed
The following scripts were executed for the analysis:
Script:
#!/bin/bash
# Description: Verify elicitation prompt ID exists in prompts section
rg -A 5 "Elicit.Slot.102046521153.828952134948" interactionModels/
Length of output: 675
Script:
#!/bin/bash
# Description: Check if the elicitation prompt ID has associated variations/content
rg -B 2 -A 5 '"id": "Elicit.Slot.102046521153.828952134948"' interactionModels/en-US.json
Length of output: 188
Script:
#!/bin/bash
# Description: Get more context around the prompts section to check for variations
rg -B 10 -A 10 '"prompts": {' interactionModels/en-US.json
Length of output: 148
Script:
#!/bin/bash
# Description: Get more context around the prompts section to check for variations
rg -B 10 -A 10 '"prompts"' interactionModels/en-US.json
Length of output: 2349
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Outside diff range and nitpick comments (7)
lambda/prompts/fr_FR.js (1)
51-51
: Use non-breaking space before question markIn French typography, a non-breaking space should be used before question marks. Consider using
\u00A0
(non-breaking space) instead of a regular space.- doYouNeedAnythingElsePrompt: " Voulez-vous autre chose ?", + doYouNeedAnythingElsePrompt: " Voulez-vous autre chose\u00A0?",lambda/handlers/apiHandler.js (1)
72-89
: Enhance error handling for specific HTTP status codes.While the implementation is solid, consider adding specific error handling for common HTTP status codes (e.g., 404, 429) to provide more informative error messages.
const getRandomHadith = async (lang = "ar") => { const config = getConfig("get", `/hadith/random?lang=${lang}`, "2.0"); console.log("Config: ", JSON.stringify(config, null, 2).replace(/Bearer \w+/g, "Bearer ****")); return await axios .request(config) .then((response) => { console.log("Hadith: ", JSON.stringify(response.data)); if (!response || !response.data || !response.data.text) { throw "Received Empty Response"; } return response.data.text; }) .catch((error) => { console.log("Error while fetching Hadith: ", error); + if (error.response) { + switch (error.response.status) { + case 404: + throw "Hadith not found"; + case 429: + throw "Rate limit exceeded"; + default: + throw error; + } + } throw error; }); }lambda/helperFunctions.js (2)
Line range hint
32-38
: Consider type validation for createDirectivePayload parameters.The function could benefit from basic type validation for its parameters.
const createDirectivePayload = (aplDocument, dataSources = {}, type = "Alexa.Presentation.APL.RenderDocument") => { + if (!aplDocument || typeof aplDocument !== 'object') { + throw new Error('Invalid APL document'); + } + if (typeof dataSources !== 'object') { + throw new Error('Invalid dataSources'); + } return { type: type, token: uuidv4(), document: aplDocument, datasources: dataSources, }; };
506-512
: Consider adding validation for time parameter.The function should validate the time parameter format.
const createDataSourceForPrayerTiming = (time) => { + if (!/^\d{2}:\d{2}$/.test(time)) { + console.warn('Invalid time format:', time); + return { "data": { "text": "00:00" } }; + } return { "data": { "text": time } } }lambda/handlers/intentHandler.js (3)
317-339
: Add error handling for audio URLsWhile the implementation looks good, consider adding validation for audio URLs to handle potential undefined or invalid URLs gracefully.
let audioUrl = prayerName === "0"? adhaanRecitation[0].fajrUrl : adhaanRecitation[0].otherUrl; +if (!audioUrl) { + console.error("Audio URL is undefined"); + return handlerInput.responseBuilder + .speak(requestAttributes.t("audioErrorPrompt")) + .withShouldEndSession(false) + .getResponse(); +}
565-643
: Consider caching translated adhaan reciter namesThe translation of adhaan reciter names is performed every time the handler is called. Consider caching these translations to improve performance.
Consider implementing a translation cache:
const translationCache = new Map(); const getTranslatedText = async (text, locale) => { const cacheKey = `${text}_${locale}`; if (translationCache.has(cacheKey)) { return translationCache.get(cacheKey); } const translated = await helperFunctions.translateText(text, locale); translationCache.set(cacheKey, translated); return translated; };
645-686
: Add persistence validation before savingConsider adding validation to ensure the persistence layer is available before attempting to save.
- await attributesManager.savePersistentAttributes(); + try { + await attributesManager.savePersistentAttributes(); + } catch (error) { + console.error("Failed to save persistent attributes:", error); + return responseBuilder + .speak(requestAttributes.t("saveErrorPrompt")) + .withShouldEndSession(false) + .getResponse(); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (6)
lambda/aplDocuments/characterDisplayApl.json
(1 hunks)lambda/handlers/apiHandler.js
(2 hunks)lambda/handlers/intentHandler.js
(8 hunks)lambda/helperFunctions.js
(9 hunks)lambda/interceptors.js
(5 hunks)lambda/prompts/fr_FR.js
(1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
- lambda/interceptors.js
🧰 Additional context used
📓 Learnings (1)
lambda/helperFunctions.js (1)
Learnt from: ijaz26
PR: mawaqit/alexa#4
File: lambda/helperFunctions.js:491-493
Timestamp: 2024-12-14T15:39:02.019Z
Learning: In `lambda/helperFunctions.js`, the `locale` parameter in the `splitLanguage` function will never be null, so input validation for `locale` is unnecessary.
🔇 Additional comments (12)
lambda/prompts/fr_FR.js (2)
52-56
: LGTM! Well-implemented French translations
The new adhan reciter prompts are properly translated and maintain consistency with the existing localization style. The translations are natural and preserve the required format strings.
57-57
: Translation looks good
The hadith error prompt is now properly translated to French, addressing the previous review comment.
lambda/aplDocuments/characterDisplayApl.json (1)
1-15
: LGTM! Well-structured APL document.
The APL document is correctly configured for character display using APLT, with proper parameterization and a clean, minimalist design.
lambda/handlers/apiHandler.js (1)
107-107
: LGTM! Export added correctly.
The new function is properly exported alongside existing functions.
lambda/helperFunctions.js (5)
9-9
: LGTM! Required import added.
The APL document import is correctly added for character display functionality.
299-305
: LGTM! Well-implemented character display check.
The function correctly checks for APLT support and adds the directive when available.
477-500
: LGTM! Robust directive service implementation.
The implementation includes proper error handling and follows the progressive response pattern.
502-504
: LGTM! Simple and effective language code extraction.
Based on the learnings from previous reviews, input validation is not required as the locale parameter will never be null.
530-534
: LGTM! New functions properly exported.
All new functions are correctly added to the exports object.
lambda/handlers/intentHandler.js (3)
3-3
: LGTM: Import statements are properly structured
The new imports align well with the added functionality for adhaan recitation and hadith features.
Also applies to: 5-10
699-702
: Remove redundant block statement in catch block
The catch block contains a redundant block statement that should be removed.
721-724
: LGTM: Exports are properly updated
All new handlers are correctly included in the module exports.
Summary by CodeRabbit
New Features
AMAZON.ResumeIntent
,AMAZON.PauseIntent
,FavoriteAdhaanReciterIntent
, andHadithIntent
.Bug Fixes
Chores