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

325
LINES

< > BotCompany Repo | #1002278 // Eleutheria Main 2 (developing)

JavaX source code - run with: x30.jar

1  
!752
2  
3  
!include #1002268 // Slack Bot
4  
5  
static boolean actuallyPost = true;
6  
static S botUserName = "eleu_learns_to_think";
7  
static S actualBotUserName = "eleu"; // token user name
8  
9  
static boolean hotwire_over_bot = true;
10  
11  
static int maxAnswerLength = 1000, shortenTo = 200;
12  
13  
static L<S> botIDs;
14  
static new L<Class> bots;
15  
static new L<Class> privBots; // bots with an answerPriv method (privileged/private answering)
16  
static new L<S> activeBots;
17  
static Map<S, Class> botsByID = synchroTreeMap();
18  
19  
// information for "answer" functions
20  
static new ThreadLocal<S> userName;
21  
static new ThreadLocal<S> dialogID;
22  
static new ThreadLocal<S> actualURI;
23  
24  
static volatile boolean loaded;
25  
26  
static int webServerPort = 80; // set to 0 for no web serving
27  
static long hitCount;
28  
29  
static new L<Map> history; // stores all processed user questions (not whole chat log)
30  
31  
p {
32  
  if (webServerPort != 0) {
33  
    readLocally("hitCount");
34  
    serveHttp(webServerPort);
35  
  }
36  
  
37  
  initSlackBot();
38  
  
39  
  reload();
40  
  readLog();
41  
  
42  
  loaded = true;
43  
  slackBotLoop();
44  
}
45  
46  
static S answerImpl(S s) {
47  
  new Matches m;
48  
  
49  
  if (match("reboot", s)) {
50  
    thread {
51  
      sleepSeconds(1);
52  
      nohupJavax(getProgramID());
53  
      System.exit(100);
54  
    }
55  
    ret "Rebooting...";
56  
  }
57  
  
58  
  if (match("reload", s)) {
59  
    time { reload(); }
60  
    ret l(bots) + "/" + l(botIDs) + " bots reloaded in "+ getLastTiming() + " ms.";
61  
  }
62  
  
63  
  if (match("reload *", s, m)) {
64  
    reload(m.unq(0));
65  
    ret "Bot " + formatSnippetID(m.unq(0)) + " reloaded.";
66  
  }
67  
  
68  
  if (match("list bots", s)) {
69  
    S answer = "Active bots: " + structure(activeBots);
70  
    L<S> inactiveBots = diff(botIDs, activeBots);
71  
    if (!inactiveBots.isEmpty())
72  
      answer += ". Inactive bots: " + structure(inactiveBots);
73  
    ret answer;
74  
  }
75  
    
76  
  if (match("test", s))
77  
    ret "blah!";
78  
    
79  
  ret callStaticAnswerMethod(bots, s);
80  
}
81  
  
82  
static synchronized S answer(S s) {
83  
  long time = now();
84  
  S a = "ERREUR";
85  
  try {
86  
    a = answerImpl(s);
87  
  } finally {
88  
    pcall {
89  
      long x = now();
90  
      // We should record which bot answered!
91  
      Map map = litmap("startTime", time, "duration", x-time,
92  
        "question", s, "answer", a, "botID", "?");
93  
      printList(answerPriv(format("log timing *", structure(map))));
94  
    }
95  
  }
96  
  ret a;
97  
}
98  
99  
// can give multiple answers
100  
static synchronized L<S> answerPriv(S s) {
101  
  new L<S> l;
102  
  for (Class bot : privBots) pcall {
103  
    S a = cast callOpt(bot, "answerPriv", s);
104  
    if (!empty(a))
105  
      l.add(a);
106  
  }
107  
  ret l;
108  
}
109  
110  
static void recordFeedback(S probableQuestion, S answer, S answerTime, S feedback, int score) {
111  
  if (answer == null || probableQuestion == null) ret;
112  
113  
  Map data = litmap("realtime", now(), "question", probableQuestion, "answer", answer, "answertime", answerTime, "feedback", feedback, "score", score);
114  
  print("Recording feedback: " + data);
115  
  logQuoted(new File(programDir(), "feedback-log"), structure(data));
116  
  logQuoted(new File(programDir(), "memory-log"), structure(data));
117  
}
118  
119  
static void reloadLists() {
120  
  botIDs = or((L<S>) loadVariableDefinition("botIDs"), botIDs);
121  
  generalReleaseBots = or((L<S>) loadVariableDefinition("generalReleaseBots"), generalReleaseBots);
122  
  botIDs.addAll(generalReleaseBots);
123  
}
124  
125  
static void reload() {
126  
  reloadLists();
127  
  
128  
  cleanUp(bots);
129  
  activeBots = new ArrayList();
130  
  privBots = new ArrayList();
131  
  botsByID.clear();
132  
  for (S botID : botIDs)
133  
    pcall {
134  
      loadBot(botID);
135  
    }
136  
}
137  
138  
static void reload(S botID) {
139  
  reloadLists();
140  
  S parsedID = "" + parseSnippetID(botID);
141  
  Class bot = botsByID.get(parsedID);
142  
  if (bot != null) {
143  
    cleanUp(bot);
144  
    botsByID.remove(parsedID);
145  
    activeBots.remove(formatSnippetID(botID));
146  
    bots.remove(bot);
147  
    privBots.remove(bot);
148  
  }
149  
  loadBot(botID);
150  
}
151  
152  
static void loadBot(S botID) {
153  
  print("Loading bot: " + botID);
154  
  Class c = hotwire_over_bot ? hotwire_overBot(botID) : hotwire(botID);
155  
  setOpt(c, "mainBot", getMainClass());
156  
  callMain(c);
157  
  bots.add(c);
158  
  activeBots.add(formatSnippetID(botID)); // only if loading doesn't fail
159  
  botsByID.put("" + parseSnippetID(botID), c);
160  
  if (hasMethodNamed(c, "answerPriv"))
161  
    privBots.add(c);
162  
  print("Loaded bot: " + botID + ", bots now: " + l(activeBots));
163  
}
164  
165  
static NanoHTTPD.Response serve(S uri, NanoHTTPD.Method method,
166  
  Map<S,S> header, Map<S,S> parms, Map<S,S> files) {
167  
  print("Serving HTTP " + quote(uri));
168  
  ++hitCount;
169  
  saveLocally("hitCount");
170  
  actualURI.set(uri);
171  
  uri = dropPrefixMandatory("/", uri);
172  
  if (!loaded)
173  
    ret serveHTML("LOADING, PLEASE TRY AGAIN. " + l(bots) + "/" + l(botIDs) + " bots loaded");
174  
  if (eq(uri, ""))
175  
    ret serveHomePage();
176  
  if (eq(uri, "favicon.ico"))
177  
    ret serve404();
178  
    
179  
  // count and set cookie
180  
  O visitorsBot = getBot("#1002157");
181  
  if (visitorsBot != null) {
182  
    S visitorHTML = callHtmlMethod(visitorsBot, "/");
183  
  }
184  
  
185  
  int i = uri.indexOf('/');
186  
  S firstPart = i >= 0 ? uri.substring(0, i) : uri;
187  
  S rest = i >= 0 ? substr(uri, i) : "/"; // rest always starts with "/"
188  
  ret serveBot(firstPart, rest, parms);
189  
}
190  
191  
static NanoHTTPD.Response serveBot(S botID, S subUri, Map<S, S> params) {
192  
  Class bot = botsByID.get("" + parseSnippetID(botID));
193  
  boolean raw = subUri.equals("/raw") || subUri.startsWith("/raw/");
194  
  if (raw) {
195  
    subUri = substr(subUri, "/raw".length());
196  
    if (subUri.length() == 0) subUri = "/";
197  
  }
198  
  if (bot != null) {
199  
    print("Bot " + botID + " methods: " + structure(allMethodNames(bot)));
200  
    S botHtml = callHtmlMethod(bot, subUri, params);
201  
    if (raw) ret serveHTML(unnull(botHtml));
202  
    if (botHtml == null)
203  
      botHtml = "Bot has no HTML output.";
204  
    S title = "Eleutheria Bot " + formatSnippetID(botID);
205  
    S html = "<html><head><title>" + title + "</title></head>" +
206  
      "<body><h3>Bot <a href=\"http://tinybrain.de/" + parseSnippetID(botID) + "\">" + formatSnippetID(botID) + "</a></h3>\n" + botHtml +
207  
      "\n</body></html>";
208  
    ret serveHTML(html);
209  
  }
210  
  
211  
  ret serve404();
212  
}
213  
214  
static NanoHTTPD.Response serveHomePage() {
215  
  new StringBuilder buf;
216  
  buf.append("<html>");
217  
  buf.append("<head><title>Eleutheria Chat Bots</title></head>");
218  
  buf.append("<body>");
219  
  buf.append("<h3><a href=" + htmlQuote("http://tinybrain.de") + ">Eleutheria</a> Bots</h3>");
220  
  buf.append("<ul>");
221  
  for (S botID : concatLists(litlist(getProgramID()), activeBots)) {
222  
    botID = formatSnippetID(botID);
223  
    S parsedID = "" + parseSnippetID(botID);
224  
    S title = "?";
225  
    pcall { title = getSnippetTitle_overBot(botID); }
226  
    S name = botID + " - " + htmlencode(title);
227  
    buf.append("<li><a href=" + htmlQuote(parsedID) + ">" + name + "</a> (");
228  
    buf.append("<a href=" + htmlQuote("http://tinybrain.de/" + parsedID) + ">source</a>)</li>");
229  
  }
230  
  buf.append("</ul>");
231  
  buf.append("<p>Hit count: " + hitCount + "</p>");
232  
  
233  
  buf.append("<p>Last interactions:</p>");
234  
  
235  
  int maxInteractionsToPrint = 10;
236  
  
237  
  for (int i = l(history)-1; i >= 0 && i >= l(history)-maxInteractionsToPrint; i--) {
238  
    Map m = history.get(i);
239  
    buf.append("<p>" + htmlencode(m.get("question")) + "<br>&nbsp; &nbsp; " + htmlencode(m.get("answer")) + "</p>");
240  
  }
241  
  
242  
  buf.append("</body>");
243  
  buf.append("</html>");
244  
  ret serveHTML(buf);
245  
}
246  
247  
static S getSnippetTitle_overBot(S snippetID) {
248  
  startBot("Snippet Title Bot", "#1001747");
249  
  // Use local version
250  
  //S s = sendToLocalBot(getVMPort() + "/Snippet Title Bot", "what is the title of snippet *", snippetID);
251  
  // Use bot VM version
252  
  S s = sendToLocalBot_cached("Snippet Title Bot", "what is the title of snippet *", snippetID);
253  
  new Matches m;
254  
  if (match("The title of snippet * is *.", s, m))
255  
    ret m.unq(1);
256  
  throw fail("Bot said: " + s);
257  
}
258  
259  
static void readLog() {
260  
  for (S prog : litlist("#1001915", "#1002017"))
261  
    for (S s : scanLog(prog, "memory-log")) pcall {
262  
      history.add((Map) safeUnstructure(s));
263  
    }
264  
  print(l(history) + " history entries.");
265  
}
266  
267  
// for current thread
268  
static S getUserName() {
269  
  ret userName.get();
270  
}
271  
272  
// for current thread
273  
static S getDialogID() {
274  
  ret dialogID.get();
275  
}
276  
277  
// for current thread
278  
static S getActualURI() {
279  
  ret actualURI.get();
280  
}
281  
282  
// for sub-bots to call
283  
static O getSession() {
284  
  ret NanoHTTPD.currentSession.get();
285  
}
286  
287  
// for sub-bots to call
288  
static O getCookies() {
289  
  NanoHTTPD.IHTTPSession session = NanoHTTPD.currentSession.get();
290  
  NanoHTTPD.CookieHandler cookies = session.getCookies();
291  
  ret cookies;
292  
}
293  
294  
static O getBot(S botID) {
295  
  ret botsByID.get("" + parseSnippetID(botID));
296  
}
297  
298  
static synchronized void historyAdd(Map logEntry) {
299  
  history.add(logEntry);
300  
  logQuoted(new File(programDir(), "memory-log"), structure(logEntry));
301  
}
302  
303  
static S webAnswer(S s) {
304  
  O session = getSession();
305  
  O cookieHandler = getCookies();
306  
  S cookie = cast call(cookieHandler, "read", "cookie");
307  
  print("Web answer cookie: " + cookie);
308  
  print("Web answer question: " + quote(s));
309  
  S dialogID = cookie;
310  
  
311  
  main.dialogID.set(dialogID);
312  
  // user name is empty for now
313  
        
314  
  S a = null;
315  
  pcall {
316  
    a = answer(s, false); // generalRelease = false, all bots
317  
    print("Web answer: " + quote(a));
318  
    if (empty(a))
319  
      a = "Hello :)";
320  
  }
321  
  if (empty(a)) a = "(no response)";
322  
  Map logEntry = litmap("question", s, "user", "web", "answer", a, "realtime", now());
323  
  historyAdd(logEntry);
324  
  ret a;
325  
}

Author comment

Began life as a copy of #1002017

download  show line numbers  debug dex  old transpilations   

Travelled to 13 computer(s): aoiabmzegqzx, bhatertpkbcr, cbybwowwnfue, cfunsshuasjs, gwrvuhgaqvyk, ishqpsrjomds, lpdgvwnxivlt, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tslmcundralx, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1002278
Snippet name: Eleutheria Main 2 (developing)
Eternal ID of this version: #1002278/1
Text MD5: 95991e6dd66393f6ebaead41a71c3c77
Author: stefan
Category:
Type: JavaX source code
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-01-02 17:16:57
Source code size: 9518 bytes / 325 lines
Pitched / IR pitched: No / Yes
Views / Downloads: 545 / 442
Referenced in: [show references]