Skip to content

Commit e404af3

Browse files
authored
Merge pull request #2 from SEPIA-Framework/dev
added new WorkoutHelperDemo with background tasks and database access
2 parents acc86bc + 9f84689 commit e404af3

File tree

2 files changed

+244
-0
lines changed

2 files changed

+244
-0
lines changed
Lines changed: 239 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,239 @@
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+
}

smart-services/smart-services.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
"cmd": "restaurant_reservation",
1111
"path": "java/RestaurantDemo.java",
1212
"version": "0.9.0"
13+
},{
14+
"name": "WorkoutHelperDemo",
15+
"cmd": "workout_helper",
16+
"path": "java/WorkoutHelperDemo.java",
17+
"version": "0.9.0"
1318
}
1419
]
1520
}

0 commit comments

Comments
 (0)