From 132f6753efd3fbc071d19aa00b0eb2bdc9e06620 Mon Sep 17 00:00:00 2001 From: Thomas Hansen Date: Wed, 9 Aug 2023 15:24:12 +0300 Subject: [PATCH] Actions for questionnaires --- .../migrations/0038-add-name-to-questions.sql | 3 + .../0039-add-action-to-questionnaires.sql | 3 + .../files/system/magic/questionnaires.get.hl | 1 + .../files/system/magic/questionnaires.post.hl | 1 + .../files/system/magic/questionnaires.put.hl | 1 + backend/files/system/magic/questions.get.hl | 1 + backend/files/system/magic/questions.post.hl | 2 + backend/files/system/magic/questions.put.hl | 2 + .../system/openai/front.files/chat/default.js | 41 +++++++++++++- ...uestionnaires.action.sendgrid-subscribe.hl | 55 +++++++++++++++++++ .../openai/questionnaire-action.post.hl | 29 ++++++++++ .../files/system/openai/questionnaire.get.hl | 4 +- ...learning-edit-questionnaire.component.html | 21 +++++++ ...e-learning-edit-questionnaire.component.ts | 3 + ...chine-learning-edit-questions.component.ts | 9 +++ 15 files changed, 171 insertions(+), 5 deletions(-) create mode 100644 backend/files/misc/sqlite/migrations/0038-add-name-to-questions.sql create mode 100644 backend/files/misc/sqlite/migrations/0039-add-action-to-questionnaires.sql create mode 100644 backend/files/system/openai/magic.startup/magic.questionnaires.action.sendgrid-subscribe.hl create mode 100644 backend/files/system/openai/questionnaire-action.post.hl diff --git a/backend/files/misc/sqlite/migrations/0038-add-name-to-questions.sql b/backend/files/misc/sqlite/migrations/0038-add-name-to-questions.sql new file mode 100644 index 0000000000..af2946cf33 --- /dev/null +++ b/backend/files/misc/sqlite/migrations/0038-add-name-to-questions.sql @@ -0,0 +1,3 @@ + +alter table questions add column name varchar(40) null; + diff --git a/backend/files/misc/sqlite/migrations/0039-add-action-to-questionnaires.sql b/backend/files/misc/sqlite/migrations/0039-add-action-to-questionnaires.sql new file mode 100644 index 0000000000..3bcbf7ad6e --- /dev/null +++ b/backend/files/misc/sqlite/migrations/0039-add-action-to-questionnaires.sql @@ -0,0 +1,3 @@ + +alter table questionnaires add column action varchar(40) null; + diff --git a/backend/files/system/magic/questionnaires.get.hl b/backend/files/system/magic/questionnaires.get.hl index 038c107fe2..8e567b5040 100644 --- a/backend/files/system/magic/questionnaires.get.hl +++ b/backend/files/system/magic/questionnaires.get.hl @@ -44,6 +44,7 @@ data.connect:[generic|magic] columns questionnaires.name questionnaires.type + questionnaires.action where and diff --git a/backend/files/system/magic/questionnaires.post.hl b/backend/files/system/magic/questionnaires.post.hl index fb311228ea..8fe579f752 100644 --- a/backend/files/system/magic/questionnaires.post.hl +++ b/backend/files/system/magic/questionnaires.post.hl @@ -3,6 +3,7 @@ .arguments name:string type:string + action:string .description:CRUD create endpoint inserting one record into your questionnaires table in your magic database taking name with authentication and authorisation for root,admin roles .type:crud-create diff --git a/backend/files/system/magic/questionnaires.put.hl b/backend/files/system/magic/questionnaires.put.hl index f621dd3d8e..2f6fcfb0a8 100644 --- a/backend/files/system/magic/questionnaires.put.hl +++ b/backend/files/system/magic/questionnaires.put.hl @@ -3,6 +3,7 @@ .arguments name:string type:string + action:string .description:CRUD update endpoint updating one record in your questionnaires table in your magic database filtering which item to update with name updating type fields with authentication and authorisation for root roles .type:crud-update diff --git a/backend/files/system/magic/questions.get.hl b/backend/files/system/magic/questions.get.hl index 802c5e1b81..582c7b74e5 100644 --- a/backend/files/system/magic/questions.get.hl +++ b/backend/files/system/magic/questions.get.hl @@ -48,6 +48,7 @@ data.connect:[generic|magic] questions.questionnaire questions.type questions.context + questions.name where and diff --git a/backend/files/system/magic/questions.post.hl b/backend/files/system/magic/questions.post.hl index de8b7979b0..497b270768 100644 --- a/backend/files/system/magic/questions.post.hl +++ b/backend/files/system/magic/questions.post.hl @@ -3,6 +3,8 @@ .arguments question:string questionnaire:string + type:string + name:string .description:CRUD create endpoint inserting one record into your questions table in your magic database taking question, questionnaire with authentication and authorisation for root,admin roles .type:crud-create diff --git a/backend/files/system/magic/questions.put.hl b/backend/files/system/magic/questions.put.hl index 57e55c0c8d..e852ccceae 100644 --- a/backend/files/system/magic/questions.put.hl +++ b/backend/files/system/magic/questions.put.hl @@ -4,6 +4,8 @@ question_id:long question:string questionnaire:string + type:string + name:string .description:CRUD update endpoint updating one record in your questions table in your magic database filtering which item to update with question_id updating question, questionnaire fields with authentication and authorisation for root,admin roles .type:crud-update diff --git a/backend/files/system/openai/front.files/chat/default.js b/backend/files/system/openai/front.files/chat/default.js index 52a7330271..543e30a064 100644 --- a/backend/files/system/openai/front.files/chat/default.js +++ b/backend/files/system/openai/front.files/chat/default.js @@ -303,11 +303,14 @@ function ensureInitialQuestionnaireIsFetched() { }); } +// Contains all action values for questionnaire. +const questionnaireActionValues = {}; + /* * Function that loops through questionnaire asking questions until no more * questions remains in ainiroQuestionnaire array. */ -function askNextQuestion() { +function askNextQuestion(justAsked = false) { // Verifying we've got more questions remaining. if (!ainiroQuestionnaire.questions || ainiroQuestionnaire.questions?.length === 0) { @@ -316,6 +319,32 @@ function askNextQuestion() { // Storing the fact that user has taken this questionnaire in local storage. localStorage.setItem('ainiro-questionnaire.' + ainiroQuestionnaire.name, JSON.stringify(ainiroQuestionnaireAnswers)); } + if(justAsked === true && ainiroQuestionnaire.action) { + + // Done with questionnaire, invoking action on the server + const payload = { + action: ainiroQuestionnaire.action, + values: questionnaireActionValues, + }; + let url = `[[url]]/magic/system/openai/questionnaire-action`; + fetch(url, { + method: 'POST', + headers: { + "Content-Type": 'application/json' + }, + body: JSON.stringify(payload) + }) + .then(res => { + if (res.status >= 200 && res.status <= 299) { + return res.json(); + } else { + throw Error(res.statusText); + } + }) + .then(() => { + console.log('Successfully invoked action for questionnaire'); + }); + } return; } const row = window.document.createElement('div'); @@ -330,7 +359,7 @@ function askNextQuestion() { // Checking type of question. if (ainiroQuestionnaire.questions[0].type === 'message') { ainiroQuestionnaire.questions = ainiroQuestionnaire.questions.slice(1); - askNextQuestion(); + askNextQuestion(true); } } @@ -431,6 +460,11 @@ function aista_invoke_prompt(msg, token, speech) { // Checking if we're in a questionnaire loop. if (ainiroQuestionnaire.questions?.length > 0) { + // Checking if this is a "named" question. + if (ainiroQuestionnaire.questions[0].name) { + questionnaireActionValues[ainiroQuestionnaire.questions[0].name] = msg; + } + // Creating our URL. let url = `[[url]]/magic/system/openai/answer`; @@ -453,6 +487,7 @@ function aista_invoke_prompt(msg, token, speech) { question: ainiroQuestionnaire.questions[0].question, answer: msg, context: ainiroQuestionnaire.questions[0].context, + name: ainiroQuestionnaire.questions[0].name, }); ainiroQuestionnaire.questions = ainiroQuestionnaire.questions.slice(1); payload.answer = msg; @@ -491,7 +526,7 @@ function aista_invoke_prompt(msg, token, speech) { } // Asking next question, if we've got more questions in our questionnaire. - askNextQuestion(); + askNextQuestion(true); }); } else { diff --git a/backend/files/system/openai/magic.startup/magic.questionnaires.action.sendgrid-subscribe.hl b/backend/files/system/openai/magic.startup/magic.questionnaires.action.sendgrid-subscribe.hl new file mode 100644 index 0000000000..ba70427f81 --- /dev/null +++ b/backend/files/system/openai/magic.startup/magic.questionnaires.action.sendgrid-subscribe.hl @@ -0,0 +1,55 @@ + +/* + * Subscribes the specified [name] and [email] to a newsletter using SendGrid account. + */ +slots.create:magic.questionnaires.action.sendgrid-subscribe + + // Sanity checking invocation. + validators.mandatory:x:@.arguments/*/name + validators.mandatory:x:@.arguments/*/email + validators.email:x:@.arguments/*/email + + // Invoking SendGrid to create recipient. + .auth + set-value:x:@.auth + strings.concat + .:"Bearer " + config.get:"magic:sendgrid:api-key" + config.get:"magic:sendgrid:chatbot-list" + set-name:x:./*/http.put/**/full_name + config.get:"magic:sendgrid:full_name_id" + .:e1_T + unwrap:x:+/** + http.put:"https://api.sendgrid.com/v3/marketing/contacts" + convert:true + headers + Authorization:x:@.auth + Content-Type:application/json + payload + list_ids + .:x:@config.get + contacts + . + email:x:@.arguments/*/email + custom_fields + full_name:x:@.arguments/*/name + + // Sanity checking invocation. + if + neq:x:@http.put + .:int:202 + .lambda + + // Oops ...!! + lambda2hyper:x:@http.put/*/content + log.error:Could not add new contact to list + email:x:@.arguments/*/email + name:x:@.arguments/*/name + stack:x:@lambda2hyper + + else + + // Doing some basic logging + log.info:Successfully added contact to SendGrid automation + name:x:@.arguments/*/name + email:x:@.arguments/*/email diff --git a/backend/files/system/openai/questionnaire-action.post.hl b/backend/files/system/openai/questionnaire-action.post.hl new file mode 100644 index 0000000000..28ee959e0b --- /dev/null +++ b/backend/files/system/openai/questionnaire-action.post.hl @@ -0,0 +1,29 @@ + +/* + * Invokes the specified [action] with the specified [values]. + */ +.arguments + action:string + values:* +.description:Invokes the specified [action] with the specified [values] + +// Sanity checking invocation. +validators.mandatory:x:@.arguments/*/action + +// Figuring out what slot to invoke. +.slot +set-value:x:@.slot + strings.concat + .:magic.questionnaires.action. + get-value:x:@.arguments/*/action + +// Parametrising slot. +add:x:./*/signal + get-nodes:x:@.arguments/*/values/* + +// Invoking slot. +signal:x:@.slot + +// Returning success to caller. +return + result:success diff --git a/backend/files/system/openai/questionnaire.get.hl b/backend/files/system/openai/questionnaire.get.hl index 7c0ad46574..af9fa2d07f 100644 --- a/backend/files/system/openai/questionnaire.get.hl +++ b/backend/files/system/openai/questionnaire.get.hl @@ -14,7 +14,7 @@ data.connect:[generic|magic] // Retrieving all questions from database. data.select:@" -select q.question, q.type, q.context +select q.question, q.type, q.context, q.name from questions q inner join questionnaires qu on qu.name = q.questionnaire inner join ml_types t on t.initial_questionnaire = qu.name @@ -24,7 +24,7 @@ select q.question, q.type, q.context // Retrieving main questionnaire from database. data.select:@" -select q.name, q.type +select q.name, q.type, q.action from questionnaires q inner join ml_types t on t.initial_questionnaire = q.name where t.type = @type" diff --git a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.html b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.html index 960a5a115b..028c4c5452 100644 --- a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.html +++ b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.html @@ -30,6 +30,27 @@

+ +
+ + + + edit + | + + + + +
+
diff --git a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.ts b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.ts index b5ee06f5e7..29cbdf6fa4 100644 --- a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.ts +++ b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questionnaire/machine-learning-edit-questionnaire.component.ts @@ -19,6 +19,7 @@ export class MachineLearningEditQuestionnaireComponent { name: string = ''; type: string = 'single-shot'; + action: string = 'sendgrid-subscribe'; constructor( private generalService: GeneralService, @@ -28,6 +29,7 @@ export class MachineLearningEditQuestionnaireComponent { if (this.data) { this.name = this.data.name; this.type = this.data.type; + this.action = this.data.action; } } @@ -51,6 +53,7 @@ export class MachineLearningEditQuestionnaireComponent { const data: any = { name: this.name, type: this.type, + action: this.action, }; if (this.data) { data.id = this.data.id; diff --git a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questions/machine-learning-edit-questions.component.ts b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questions/machine-learning-edit-questions.component.ts index 1ec996d785..8d9675c434 100644 --- a/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questions/machine-learning-edit-questions.component.ts +++ b/frontend/src/app/_protected/pages/manage/machine-learning/components/machine-learning-edit-questions/machine-learning-edit-questions.component.ts @@ -59,6 +59,15 @@ export class MachineLearningEditQuestionsComponent implements OnInit { this.questions += 'context=' + idx.context; addedMeta = true; } + if (idx.name) { + if (!addedMeta) { + this.questions += ' => '; + } else { + this.questions += ', '; + } + this.questions += 'name=' + idx.name; + addedMeta = true; + } this.questions += '\r\n' } },