Not logged in.  Login/Logout/Register | List snippets | | Create snippet | Upload image | Upload data

321
LINES

< > BotCompany Repo | #1026410 // Tomii Boi Thought Bot [LIVE]

JavaX source code (desktop) [tags: use-pretranspiled] - run with: x30.jar

Download Jar. Libraryless. Click here for Pure Java version (14003L/99K).

1  
!7
2  
3  
sS dbBotID = #1026409;
4  
5  
static Env env;
6  
static new ThreadLocal<Session> session;
7  
static new ThreadLocal<Out> out;
8  
9  
sclass Out {
10  
  S buttonsIntro;
11  
  LS buttons;
12  
  S placeholder;
13  
  S defaultInput;
14  
}
15  
16  
sbool testFunctions = false;
17  
18  
static interface Env {
19  
  void sayAsync(S session, S msg);
20  
}
21  
22  
concept Session {
23  
  S cookie;
24  
  S language;
25  
  S lastQuestion;
26  
  FormInFlight form, lastForm;
27  
  
28  
  void cancelForm {
29  
    cset(this, lastForm := form, form := null);
30  
  }
31  
  
32  
  S language() { ret or2(language, 'en); }
33  
}
34  
35  
sclass FormStep {
36  
  S key;
37  
  S displayText, desc;
38  
  S defaultValue;
39  
  S placeholder; // null for same as displayText, "" for none
40  
  LS buttons;
41  
  bool allowFreeText; // only matters when there are buttons
42  
  S value;
43  
  
44  
  // called before data entry
45  
  void update(Runnable onChange) {}
46  
47  
  // called after data entry
48  
  // return error message or null
49  
  // call session->cancelForm(); to cancel the form (and make sure to return a text)
50  
  S verifyData(S s) { null; }
51  
}
52  
53  
sclass FormInFlight {
54  
  S hashTag;
55  
  new L<FormStep> steps;
56  
  int stepIndex; // in steps list
57  
  
58  
  FormStep currentStep() {
59  
    ret get(steps, stepIndex);
60  
  }
61  
  
62  
  void update(Runnable onChange) {
63  
    if (currentStep() != null) currentStep().update(onChange);
64  
  }
65  
  
66  
  S complete() { ret "Form complete"; }
67  
  S cancel() { ret "Request cancelled"; }
68  
}
69  
70  
sclass MainForm > FormInFlight {
71  
  FormStep stepInterested, stepMailAddress, stepDevice, stepConfirm;
72  
  
73  
  *() {
74  
    hashTag = "#mainForm";
75  
    
76  
    steps.add(stepInterested = setAll(new StepInterested,
77  
      key := "interested",
78  
      desc := "Interested in free trial",
79  
      displayText := "Are you after a free trial of our IPTV services?",
80  
      buttons := ll("Yes, please!", "No, thanks."),
81  
      allowFreeText := true));
82  
      
83  
    steps.add(stepMailAddress = setAll(new StepMail,
84  
      key := "mailAddress",
85  
      desc := "E-mail address",
86  
      displayText := "Please provide your e-mail address so we can contact you!",
87  
      placeholder := "What is your e-mail address?",));
88  
      
89  
    steps.add(stepDevice = nu FormStep(
90  
      key := "device",
91  
      desc := "Device",
92  
      displayText := "Which IPTV-capable device do you own?",
93  
      buttons := ll("Android box", "Android phone", "Android tablet", "Firestick", "Smart TV", "None/Unsure"),
94  
      allowFreeText := true));
95  
      
96  
    steps.add(stepConfirm = setAll(new StepConfirm,
97  
      key := "confirm",
98  
      placeholder := "",
99  
      buttons := ll("Yes")
100  
    ));
101  
  }
102  
  
103  
  class StepInterested extends FormStep {
104  
    S verifyData(S s) {
105  
      s = trim(s);
106  
      if (isNo(s) || matchStart("not", s)) {
107  
        session->cancelForm();
108  
        ret answer("#notInterestedInTrial");
109  
      }
110  
      if (!isYes(s)) {
111  
        // cancel form, interpret as normal input
112  
        session->cancelForm();
113  
        ret answer(s);
114  
      }
115  
      null;
116  
    }
117  
  }
118  
  
119  
  class StepMail extends FormStep {
120  
    @Override
121  
    S verifyData(S s) {
122  
      ret callPrint1x isValidEmailAddress_simple('isValidEmailAddress_simple, trim(s)) ? null : "Please enter a valid email address.";
123  
    }
124  
  }
125  
  
126  
  class StepConfirm extends FormStep {
127  
    void update(Runnable onChange) {
128  
      if (set_trueIfChanged(this, displayText :=
129  
        summary() + "\n\n" + "Submit contact request?")) callF(onChange);
130  
    }
131  
  }
132  
  
133  
  S summary() {
134  
    print("Will send to: " + sendToViberIDs());
135  
    ret mapToLines_rtrim(listMinus(steps, stepConfirm), step ->
136  
      (nempty(step.desc)
137  
        ? addSuffix(step.desc, ":") : step.displayText)
138  
      + " " + step.value);
139  
  }
140  
141  
  LS sendToViberIDs() {
142  
    ret llNempties(loadTextFileTrim(javaxSecretDir("iptv-viber-id.txt")),
143  
      stefanViberID());
144  
  }
145  
  
146  
  S complete() {
147  
    LS viberIDs = sendToViberIDs();
148  
    S text = joinWithEmptyLines(
149  
      "Contact request over smart-iptv-solutions.co.uk (" + timeInTimeZoneWithDate_24(ukTimeZone_string()) + ")",
150  
      summary());
151  
    pcall {
152  
      for (S viberID : sendToViberIDs())
153  
        viber_sendMessage(mandatoryViberToken(),
154  
          /*"BotCompany"*/"smart-iptv-solutions.co.uk",
155  
          viberID,
156  
          text);
157  
      
158  
      ret "Thank you, your contact request was sent!";
159  
    }
160  
    ret "Sorry, an error occurred sending the message.";
161  
  }
162  
  
163  
  S cancel() { ret "Contact request cancelled"; }
164  
}
165  
166  
sbool debug;
167  
168  
svoid setSession(S cookie, SS params) {
169  
  session.set(uniq_sync(Session, +cookie));
170  
  S lang = mapGet(params, 'language);
171  
  if (nempty(lang))
172  
    cset(session!, language := lang);
173  
  S lang_default = mapGet(params, 'language_default);
174  
  if (nempty(lang_default)) {
175  
    print("lang_default=" + lang_default + ", have: " + session->language);
176  
    if (empty(session->language)) {
177  
      print("Setting language.");
178  
      cset(session!, language := lang_default);
179  
    }
180  
  }
181  
}
182  
183  
svoid clearSession(S cookie) {
184  
  deleteConcepts(Session, +cookie);
185  
}
186  
187  
p {
188  
  db();
189  
  
190  
  // for testing on desktop
191  
  if (isMain()) { veryBigConsole(); bot(); }
192  
}
193  
194  
sS returnQuestion(S q) {
195  
  cset(session!, lastQuestion := q);
196  
  ret q;
197  
}
198  
199  
sS answer(S s) {
200  
  if (session! == null) setSession("default", new Map);
201  
  out.set(new Out);
202  
  if (creator() == null) if "debug" set debug;
203  
  
204  
  S lq = session->lastQuestion;
205  
  cset(session!, lastQuestion := null);
206  
  
207  
  FormInFlight form = session->form;
208  
  if (form != null && form.currentStep() != null) {
209  
    if (eqicOneOf(s, "cancel", "Abbrechen", unicode_crossProduct())) {
210  
      S answer = form.cancel();
211  
      session->cancelForm();
212  
      ret answer;
213  
    }
214  
    else if (eqicOneOf(s, "back", "zurück", unicode_undoArrow()) && form.stepIndex > 0) {
215  
      --form.stepIndex;
216  
      session->change();
217  
      ret deliverAnswerAndFormStep("");
218  
    } else {
219  
      FormStep step = form.currentStep();
220  
      if (!step.allowFreeText && nempty(step.buttons) && !cic(step.buttons, s))
221  
        ret deliverAnswerAndFormStep(de() ? "Bitte wählen Sie eine Option!" : "Please choose an option.");
222  
      print("Verifying data " + quote(s) + " in step " + step);
223  
      S error = step.verifyData(s);
224  
      if (error != null)
225  
        ret deliverAnswerAndFormStep(error);
226  
227  
      step.value = s;
228  
      ++form.stepIndex;
229  
      session->change();
230  
      if (form.currentStep() == null) {
231  
        S answer = form.complete();
232  
        session->cancelForm();
233  
        ret answer;
234  
      }
235  
      ret deliverAnswerAndFormStep("");
236  
    }
237  
  }
238  
  
239  
  if (testFunctions) {
240  
    if (eq(lq, "Would you like some tea?")) {
241  
      if "yes" ret "Here's your tea.";
242  
      if "no" ret "Very well then.";
243  
    }
244  
    
245  
    if "test buttons" {
246  
      out->buttons = ll("Yes", "No");
247  
      ret returnQuestion("Would you like some tea?");
248  
    }
249  
    
250  
    if "say something later" {
251  
      if (env == null) ret("No env");
252  
      final S mySession = session->cookie;
253  
      thread {
254  
        sleepSeconds(5);
255  
        env.sayAsync(mySession, "Here it is.");
256  
      }
257  
      ret "OK, will do it in 5 seconds";
258  
    }
259  
  }
260  
261  
  // get answer from bot, switch language
262  
  
263  
  O bot = dbBot();
264  
  S a = (S) call(bot, 'answer, s, session->language());
265  
  S lang = cast getThreadLocal(((ThreadLocal) get(bot, 'language_out)));
266  
  if (nempty(lang)) cset(session!, language := lang);
267  
  
268  
  S a2 = replaceAll(a, "\\s*#mainForm\\b", "");
269  
  if (neq(a, a2)) {
270  
    form = new MainForm;
271  
    print("Made form for cookie " + session->cookie + ": " + sfu(form));
272  
    cset(session!, +form);
273  
  }
274  
  
275  
  ret deliverAnswerAndFormStep(a2);
276  
}
277  
278  
sS deliverAnswerAndFormStep(S answer) {
279  
  if (session->form != null) session->form.update(r { session->change() });
280  
  /*if (form.shouldCancel()) {
281  
    session->cancelForm();
282  
    ret answer;
283  
  }
284  
*/
285  
  FormInFlight form = session->form; // form may have cancelled itself in update
286  
  if (form == null || form.currentStep() == null)  ret answer;
287  
  
288  
  FormStep step = form.currentStep();
289  
  if (empty(answer))
290  
    answer = step.displayText;
291  
  else
292  
    out->buttonsIntro = step.displayText;
293  
  out->placeholder = or(step.placeholder, step.displayText);
294  
  print("Step " + form.stepIndex + ": " + sfu(step));
295  
  out->defaultInput = or2(step.value, step.defaultValue);
296  
  out->buttons = cloneList(step.buttons);
297  
  if (form.stepIndex > 0) out->buttons.add(de() ? "Zurück" : "Back");
298  
  out->buttons.add(de() ? "Abbrechen" : "Cancel");
299  
  ret answer;
300  
}
301  
302  
sS initialMessage() {
303  
  print("initialMessage, lang=" + session->language());
304  
  ret or2(answer("#greeting"), "Hello");
305  
}
306  
307  
sO dbBot() {
308  
  ret getBot(dbBotID);
309  
}
310  
311  
sbool de() {
312  
  ret eqic(session->language(), "de");
313  
}
314  
315  
sbool botOn() {
316  
  ret isTrue(call(dbBot(), "botOn"));
317  
}
318  
319  
sbool botAutoOpen() {
320  
  ret isTrue(call(dbBot(), "botAutoOpen"));
321  
}

Author comment

Began life as a copy of #1026222

download  show line numbers  debug dex  old transpilations   

Travelled to 7 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt, xrpafgyirdlv

No comments. add comment

Snippet ID: #1026410
Snippet name: Tomii Boi Thought Bot [LIVE]
Eternal ID of this version: #1026410/1
Text MD5: 018d79e4f3780dffc7dd2095d188c62b
Transpilation MD5: 4050651961a71c7af1b9c4af2da71a81
Author: stefan
Category: javax / a.i.
Type: JavaX source code (desktop)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-01-03 00:55:44
Source code size: 8803 bytes / 321 lines
Pitched / IR pitched: No / No
Views / Downloads: 144 / 744
Referenced in: [show references]