|
| 1 | +package net.b07z.sepia.sdk.services.uid1007; |
| 2 | + |
| 3 | +import java.util.TreeSet; |
| 4 | + |
| 5 | +import org.json.simple.JSONArray; |
| 6 | +import org.json.simple.JSONObject; |
| 7 | + |
| 8 | +import net.b07z.sepia.server.assist.answers.Answers; |
| 9 | +import net.b07z.sepia.server.assist.answers.ServiceAnswers; |
| 10 | +import net.b07z.sepia.server.assist.assistant.LANGUAGES; |
| 11 | +import net.b07z.sepia.server.assist.data.Parameter; |
| 12 | +import net.b07z.sepia.server.assist.interpreters.NluResult; |
| 13 | +import net.b07z.sepia.server.assist.interviews.InterviewData; |
| 14 | +import net.b07z.sepia.server.assist.services.ServiceAccessManager; |
| 15 | +import net.b07z.sepia.server.assist.services.ServiceBuilder; |
| 16 | +import net.b07z.sepia.server.assist.services.ServiceInfo; |
| 17 | +import net.b07z.sepia.server.assist.services.ServiceInterface; |
| 18 | +import net.b07z.sepia.server.assist.services.ServiceResult; |
| 19 | +import net.b07z.sepia.server.assist.services.ServiceInfo.Content; |
| 20 | +import net.b07z.sepia.server.assist.services.ServiceInfo.Type; |
| 21 | +import net.b07z.sepia.server.core.assistant.PARAMETERS; |
| 22 | +import net.b07z.sepia.server.core.data.Language; |
| 23 | +import net.b07z.sepia.server.core.tools.JSON; |
| 24 | +import net.b07z.sepia.server.core.tools.Sdk; |
| 25 | + |
| 26 | +/** |
| 27 | + * Demo of a workout helper service. This is mainly to demonstrate background follow-up messages and database access. |
| 28 | + * |
| 29 | + * @author Florian Quirin |
| 30 | + * |
| 31 | + */ |
| 32 | +public class WorkoutHelperDemo implements ServiceInterface { |
| 33 | + |
| 34 | + //Command name of your service (will be combined with userId to be unique) |
| 35 | + private static final String CMD_NAME = "workout_helper"; |
| 36 | + |
| 37 | + //Define some sentences for testing: |
| 38 | + |
| 39 | + @Override |
| 40 | + public TreeSet<String> getSampleSentences(String lang) { |
| 41 | + TreeSet<String> samples = new TreeSet<>(); |
| 42 | + //GERMAN |
| 43 | + if (lang.equals(Language.DE.toValue())){ |
| 44 | + samples.add("Ein einfaches Workout starten."); |
| 45 | + //OTHER |
| 46 | + }else{ |
| 47 | + samples.add("Start a simple workout."); |
| 48 | + } |
| 49 | + return samples; |
| 50 | + } |
| 51 | + |
| 52 | + //Basic service setup: |
| 53 | + |
| 54 | + //Overriding the 'getAnswersPool' methods enables you to define custom answers with more complex features. |
| 55 | + //You can build a pool of answers that can have multiple versions of the same answer used for different |
| 56 | + //situations like a repeated question (what was the time? -> sorry say again, what was the time? -> ...). |
| 57 | + |
| 58 | + @Override |
| 59 | + public ServiceAnswers getAnswersPool(String language) { |
| 60 | + ServiceAnswers answerPool = new ServiceAnswers(language); |
| 61 | + |
| 62 | + //Build German answers |
| 63 | + if (language.equals(LANGUAGES.DE)){ |
| 64 | + answerPool |
| 65 | + .addAnswer(successAnswer, 0, "Ok, <1> Minuten Workout in 3, 2, 1, los gehts!") |
| 66 | + .addAnswer(successAnswer, 0, "Ok <user_name>, <1> Minuten Workout in 3, 2, 1, los!") |
| 67 | + .addAnswer(successWithTimeAdjust, 0, "Hab die Zeit etwas angepasst <user_name>, <1> Minuten Workout in 3, 2, 1, los!") |
| 68 | + .addAnswer(okAnswer, 0, "Sorry aber das hat nicht geklappt. Ich weiß nicht warum.") |
| 69 | + .addAnswer(followUpFinish, 0, "Fertig mit dem Training! Gut gemacht!") |
| 70 | + .addAnswer(followUpIntervalMinutes, 0, "<1> Minuten noch! Weiter so!") |
| 71 | + .addAnswer(followUpIntervalSeconds, 0, "<1> Sekunden noch! Fast geschafft!") |
| 72 | + ; |
| 73 | + return answerPool; |
| 74 | + |
| 75 | + //Fall back to English |
| 76 | + }else{ |
| 77 | + answerPool |
| 78 | + .addAnswer(successAnswer, 0, "Ok, <1> minutes workout in 3, 2, 1, go!.") |
| 79 | + .addAnswer(successAnswer, 0, "Ok <user_name>, <1> minutes workout in 3, 2, 1, go!.") |
| 80 | + .addAnswer(successWithTimeAdjust, 0, "I've adjusted the time a bit <user_name>, <1> minutes workout in 3, 2, 1, go!.") |
| 81 | + .addAnswer(okAnswer, 0, "Sorry that did not work out. I don't know why.") |
| 82 | + .addAnswer(followUpIntervalMinutes, 0, "<1> minutes to go! Keep it up!") |
| 83 | + .addAnswer(followUpIntervalSeconds, 0, "<1> seconds to go! Almost there!") |
| 84 | + .addAnswer(followUpFinish, 0, "Done with the training! Good job!") |
| 85 | + ; |
| 86 | + return answerPool; |
| 87 | + } |
| 88 | + } |
| 89 | + //We keep a reference here for easy access in getResult - Note that custom answers need to start with a certain prefix |
| 90 | + private static final String failAnswer = "error_0a"; |
| 91 | + private static final String successAnswer = ServiceAnswers.ANS_PREFIX + "workout_helper_success_0a"; |
| 92 | + private static final String successWithTimeAdjust = ServiceAnswers.ANS_PREFIX + "workout_helper_success_0b"; |
| 93 | + private static final String okAnswer = ServiceAnswers.ANS_PREFIX + "workout_helper_ok_0a"; |
| 94 | + private static final String followUpFinish = ServiceAnswers.ANS_PREFIX + "workout_helper_fu_finish_0a"; |
| 95 | + private static final String followUpIntervalMinutes = ServiceAnswers.ANS_PREFIX + "workout_helper_fu_interval_0a"; |
| 96 | + private static final String followUpIntervalSeconds = ServiceAnswers.ANS_PREFIX + "workout_helper_fu_interval_0b"; |
| 97 | + |
| 98 | + @Override |
| 99 | + public ServiceInfo getInfo(String language) { |
| 100 | + //Type of service (for descriptions, choose what you think fits best) |
| 101 | + ServiceInfo info = new ServiceInfo(Type.plain, Content.data, false); |
| 102 | + |
| 103 | + //Should be available publicly or only for the developer? Set this when you are done with testing and want to release |
| 104 | + //info.makePublic(); |
| 105 | + |
| 106 | + //Command |
| 107 | + info.setIntendedCommand(Sdk.getMyCommandName(this, CMD_NAME)); |
| 108 | + |
| 109 | + //Direct-match trigger sentences in different languages: |
| 110 | + String EN = Language.EN.toValue(); |
| 111 | + info.addCustomTriggerSentence("Start a simple workout.", EN); |
| 112 | + String DE = Language.DE.toValue(); |
| 113 | + info.addCustomTriggerSentence("Ein einfaches Workout starten.", DE); |
| 114 | + |
| 115 | + //Regular expression triggers: |
| 116 | + info.setCustomTriggerRegX(".*\\b(" |
| 117 | + + "(start)\\b.* (training|work(-| |)out)" |
| 118 | + + ")\\b.*", EN); |
| 119 | + info.setCustomTriggerRegX(".*\\b(" |
| 120 | + + "(starte)\\b.* (training|work(-| |)out|uebung(en|))" + "|" |
| 121 | + + "(training|work(-| |)out|uebung(en|)) (starten)" |
| 122 | + + ")\\b.*", DE); |
| 123 | + info.setCustomTriggerRegXscoreBoost(5); //boost service a bit to increase priority over similar ones |
| 124 | + |
| 125 | + //Parameters: |
| 126 | + |
| 127 | + //This service has only an optional parameter to set the a training time. |
| 128 | + //Optional parameters will be extracted from initial sentence but not asked automatically but set to a default if not given. |
| 129 | + |
| 130 | + Parameter p1 = new Parameter(PARAMETERS.TIME) |
| 131 | + .setRequired(false); |
| 132 | + info.addParameter(p1); |
| 133 | + |
| 134 | + //Answers (these are the default answers, you can trigger a custom answer at any point in the module |
| 135 | + //with serviceBuilder.setCustomAnswer(..)): |
| 136 | + info.addSuccessAnswer(successAnswer) |
| 137 | + .addFailAnswer(failAnswer) |
| 138 | + .addOkayAnswer(okAnswer); |
| 139 | + //.addCustomAnswer("askTimeAndDate", askTimeAndDate); //optional, just for info |
| 140 | + |
| 141 | + //Add answer parameters that are used to replace <1>, <2>, ... in your answers. |
| 142 | + //The name is arbitrary but you need to use the same one in getResult(...) later for api.resultInfoPut(...) |
| 143 | + info.addAnswerParameters("time"); //<1>=time, ... |
| 144 | + |
| 145 | + return info; |
| 146 | + } |
| 147 | + |
| 148 | + @Override |
| 149 | + public ServiceResult getResult(NluResult nluResult) { |
| 150 | + //initialize result |
| 151 | + ServiceBuilder api = new ServiceBuilder(nluResult, |
| 152 | + getInfoFreshOrCache(nluResult.input, this.getClass().getCanonicalName()), |
| 153 | + getAnswersPool(nluResult.language)); |
| 154 | + |
| 155 | + //test-load stored data |
| 156 | + ServiceAccessManager sam0 = new ServiceAccessManager("demokey"); |
| 157 | + JSONObject userData = api.readServiceDataForUser(sam0, "tasks"); |
| 158 | + System.out.println("result: " + userData); |
| 159 | + |
| 160 | + //get optional parameters: |
| 161 | + |
| 162 | + //-time |
| 163 | + long timeMs = 1000 * 60 * 5; //5min |
| 164 | + long maxTimeMs = 1000 * 60 * 60; //60min |
| 165 | + long minTimeMs = 1000 * 60 * 2; //2min |
| 166 | + Parameter dateTimeParameter = nluResult.getOptionalParameter(PARAMETERS.TIME, timeMs); |
| 167 | + if (!dateTimeParameter.isDataEmpty()){ |
| 168 | + timeMs = JSON.getLongOrDefault((JSONObject) dateTimeParameter.getDataFieldOrDefault(InterviewData.TIME_DIFF), "total_ms", timeMs); |
| 169 | + } |
| 170 | + if (timeMs > maxTimeMs){ |
| 171 | + timeMs = maxTimeMs; |
| 172 | + api.setCustomAnswer(successWithTimeAdjust); |
| 173 | + }else if (timeMs < minTimeMs){ |
| 174 | + timeMs = minTimeMs; |
| 175 | + api.setCustomAnswer(successWithTimeAdjust); |
| 176 | + }else if (timeMs % 60000 > 0){ |
| 177 | + api.setCustomAnswer(successWithTimeAdjust); |
| 178 | + } |
| 179 | + //NOTE: I'm cheating a bit here to save some answer variations by allowing only full minutes as time ;-) |
| 180 | + long timeMinutes = Math.round(timeMs / 60000.0d); |
| 181 | + long halfTimeMinutes = (long) Math.floor(timeMinutes / 2.0d); |
| 182 | + |
| 183 | + //Set answer parameters as defined in getInfo(): |
| 184 | + api.resultInfoPut("time", timeMinutes); |
| 185 | + |
| 186 | + //Schedule intervals |
| 187 | + if (nluResult.input.isDuplexConnection()){ |
| 188 | + //Some info about the connection and message: |
| 189 | + //System.out.println(nluResult.input.connection); |
| 190 | + //System.out.println(nluResult.input.msgId); |
| 191 | + //System.out.println(nluResult.input.duplexData); |
| 192 | + |
| 193 | + //Collect tasks |
| 194 | + JSONArray tasksArray = new JSONArray(); |
| 195 | + //Finish |
| 196 | + JSON.add(tasksArray, api.runOnceInBackground(timeMinutes * 60 * 1000, () -> { |
| 197 | + //initialize follow-up result |
| 198 | + ServiceBuilder service = new ServiceBuilder(nluResult); |
| 199 | + service.answer = Answers.getAnswerString(nluResult, followUpFinish); |
| 200 | + service.status = "success"; |
| 201 | + /*boolean wasSent =*/ service.sendFollowUpMessage(nluResult.input, service.buildResult()); |
| 202 | + return; |
| 203 | + }).getJson()); |
| 204 | + //Interval minutes |
| 205 | + if (halfTimeMinutes >= 2){ |
| 206 | + JSON.add(tasksArray, api.runOnceInBackground(halfTimeMinutes * 60 * 1000, () -> { |
| 207 | + //initialize follow-up result |
| 208 | + ServiceBuilder service = new ServiceBuilder(nluResult); |
| 209 | + service.answer = Answers.getAnswerString(nluResult, followUpIntervalMinutes, halfTimeMinutes); |
| 210 | + service.status = "success"; |
| 211 | + /*boolean wasSent =*/ service.sendFollowUpMessage(nluResult.input, service.buildResult()); |
| 212 | + return; |
| 213 | + }).getJson()); |
| 214 | + } |
| 215 | + //Interval 30s seconds |
| 216 | + long seconds = 30; |
| 217 | + JSON.add(tasksArray, api.runOnceInBackground((timeMinutes * 60 * 1000) - (seconds * 1000), () -> { |
| 218 | + //initialize follow-up result |
| 219 | + ServiceBuilder service = new ServiceBuilder(nluResult); |
| 220 | + service.answer = Answers.getAnswerString(nluResult, followUpIntervalSeconds, seconds); |
| 221 | + service.status = "success"; |
| 222 | + /*boolean wasSent =*/ service.sendFollowUpMessage(nluResult.input, service.buildResult()); |
| 223 | + return; |
| 224 | + }).getJson()); |
| 225 | + |
| 226 | + //Store task info for later access in service-specific storage - overwrite old if any |
| 227 | + ServiceAccessManager sam = new ServiceAccessManager("demokey"); |
| 228 | + int resCode = api.writeServiceDataForUser(sam, JSON.make("tasks", tasksArray)); |
| 229 | + System.out.println("resCode: " + resCode); //DEBUG |
| 230 | + } |
| 231 | + |
| 232 | + //all good |
| 233 | + api.setStatusSuccess(); |
| 234 | + |
| 235 | + //build the API_Result |
| 236 | + ServiceResult result = api.buildResult(); |
| 237 | + return result; |
| 238 | + } |
| 239 | +} |
0 commit comments