msgs) {
for (int i = l(msgs)-1; i >= 0; i--)
if (msgs.get(i).botName != null) ret i;
ret -1;
}
static synchronized S answer(S s) {
new Matches m;
if (match("reload", s)) {
reload();
ret l(bots) + "/" + l(botIDs) + " bots reloaded.";
}
if (match("reload *", s, m)) {
reload(m.unq(0));
ret "Bot " + formatSnippetID(m.unq(0)) + " reloaded.";
}
if (match("list bots", s)) {
S answer = "Active bots: " + structure(activeBots);
L inactiveBots = diff(botIDs, activeBots);
if (!inactiveBots.isEmpty())
answer += ". Inactive bots: " + structure(inactiveBots);
ret answer;
}
if (match("test", s))
ret "blah!";
ret callStaticAnswerMethod(bots, s);
}
static void recordFeedback(S probableQuestion, S answer, S answerTime, S feedback, int score) {
Map data = litmap("realtime", now(), "question", probableQuestion, "answer", answer, "answertime", answerTime, "feedback", feedback, "score", score);
print("Recording feedback: " + data);
logQuoted(new File(programDir(), "feedback-log"), structure(data));
logQuoted(new File(programDir(), "memory-log"), structure(data));
}
static void reload() {
botIDs = or((L) loadVariableDefinition("botIDs"), botIDs);
cleanUp(bots);
activeBots = new ArrayList();
botsByID.clear();
for (S botID : botIDs)
pcall {
loadBot(botID);
}
}
static void reload(S botID) {
S parsedID = "" + parseSnippetID(botID);
Class bot = botsByID.get(parsedID);
if (bot == null) ret;
cleanUp(bot);
botsByID.remove(parsedID);
activeBots.remove(bot);
loadBot(botID);
}
static void loadBot(S botID) {
print("Loading bot: " + botID);
Class c = run(botID);
bots.add(c);
activeBots.add(botID); // only if loading doesn't fail
botsByID.put("" + parseSnippetID(botID), c);
print("Loaded bot: " + botID + ", bots now: " + l(activeBots));
}
static S getUserName(S userID) {
if (userID == null) ret null;
S userName = userNames.get(userID);
if (userName == null) pcall {
userName = (S) slackGetUserInfo(token, userID).get("name");
userNames.put(userID, userName);
}
ret userName;
}
static NanoHTTPD.Response serve(S uri, NanoHTTPD.Method method,
Map header, Map parms, Map files) {
print("Serving HTTP " + quote(uri));
++hitCount;
saveLocally("hitCount");
uri = dropPrefixMandatory("/", uri);
if (eq(uri, ""))
ret serveHomePage();
if (eq(uri, "favicon.ico"))
ret serve404();
int i = uri.indexOf('/');
S firstPart = i >= 0 ? uri.substring(0, i) : uri;
S rest = i >= 0 ? substr(uri, i) : "/"; // rest always starts with "/"
ret serveBot(firstPart, rest);
}
static NanoHTTPD.Response serveBot(S botID, S subUri) {
Class bot = botsByID.get("" + parseSnippetID(botID));
boolean raw = subUri.equals("/raw") || subUri.startsWith("/raw/");
if (raw) {
subUri = substr(subUri, "/raw".length());
if (subUri.length() == 0) subUri = "/";
}
if (bot != null) {
S botHtml = callHtmlMethod(bot, subUri);
if (raw) ret serveHTML(unnull(botHtml));
if (botHtml == null)
botHtml = "Bot has no HTML output.";
S title = "TinyBrain Bot " + formatSnippetID(botID);
S html = "" + title + "" +
"\n" + botHtml +
"\n";
ret serveHTML(html);
}
ret serve404();
}
static NanoHTTPD.Response serveHomePage() {
new StringBuilder buf;
buf.append("");
buf.append("TinyBrain Chat Bots");
buf.append("");
buf.append("");
buf.append("");
for (S botID : activeBots) {
botID = formatSnippetID(botID);
S parsedID = "" + parseSnippetID(botID);
S title = "?";
pcall { title = getSnippetTitle_overBot(botID); }
S name = botID + " - " + htmlencode(title);
buf.append("- " + name + " (");
buf.append("source)
");
}
buf.append("
");
buf.append("Hit count: " + hitCount + "
");
buf.append("Last interactions:
");
int maxInteractionsToPrint = 10;
for (int i = l(history)-1; i >= 0 && i >= l(history)-maxInteractionsToPrint; i--) {
Map m = history.get(i);
buf.append("" + htmlencode(m.get("question")) + "
" + htmlencode(m.get("answer")) + "
");
}
buf.append("");
buf.append("");
ret serveHTML(buf);
}
static S getSnippetTitle_overBot(S snippetID) {
startBot("Snippet Title Bot", "#1001747");
// Use local version
//S s = sendToLocalBot(getVMPort() + "/Snippet Title Bot", "what is the title of snippet *", snippetID);
// Use bot VM version
S s = sendToLocalBot_cached("Snippet Title Bot", "what is the title of snippet *", snippetID);
new Matches m;
if (match("The title of snippet * is *.", s, m))
ret m.unq(1);
throw fail("Bot said: " + s);
}
static void readLog() {
for (S s : scanLog("#1001915", "memory-log")) pcall {
history.add((Map) safeUnstructure(s));
}
print(l(history) + " history entries.");
}