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

!752

!include #1002268 // Slack Bot

static boolean actuallyPost = true;
static S botUserName = "eleu_learns_to_think";
static S actualBotUserName = "eleu"; // token user name

static boolean hotwire_over_bot = true;

static int maxAnswerLength = 1000, shortenTo = 200;

static L<S> botIDs;
static new L<Class> bots;
static new L<Class> privBots; // bots with an answerPriv method (privileged/private answering)
static new L<S> activeBots;
static Map<S, Class> botsByID = synchroTreeMap();

// information for "answer" functions
static new ThreadLocal<S> userName;
static new ThreadLocal<S> dialogID;
static new ThreadLocal<S> actualURI;

static volatile boolean loaded;

static int webServerPort = 80; // set to 0 for no web serving
static long hitCount;

static new L<Map> history; // stores all processed user questions (not whole chat log)

p {
  if (webServerPort != 0) {
    readLocally("hitCount");
    serveHttp(webServerPort);
  }
  
  initSlackBot();
  
  reload();
  readLog();
  
  loaded = true;
  slackBotLoop();
}

static S answerImpl(S s) {
  new Matches m;
  
  if (match("reboot", s)) {
    thread {
      sleepSeconds(1);
      nohupJavax(getProgramID());
      System.exit(100);
    }
    ret "Rebooting...";
  }
  
  if (match("reload", s)) {
    time { reload(); }
    ret l(bots) + "/" + l(botIDs) + " bots reloaded in "+ getLastTiming() + " ms.";
  }
  
  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<S> 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 synchronized S answer(S s) {
  long time = now();
  S a = "ERREUR";
  try {
    a = answerImpl(s);
  } finally {
    pcall {
      long x = now();
      // We should record which bot answered!
      Map map = litmap("startTime", time, "duration", x-time,
        "question", s, "answer", a, "botID", "?");
      printList(answerPriv(format("log timing *", structure(map))));
    }
  }
  ret a;
}

// can give multiple answers
static synchronized L<S> answerPriv(S s) {
  new L<S> l;
  for (Class bot : privBots) pcall {
    S a = cast callOpt(bot, "answerPriv", s);
    if (!empty(a))
      l.add(a);
  }
  ret l;
}

static void recordFeedback(S probableQuestion, S answer, S answerTime, S feedback, int score) {
  if (answer == null || probableQuestion == null) ret;

  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 reloadLists() {
  botIDs = or((L<S>) loadVariableDefinition("botIDs"), botIDs);
  generalReleaseBots = or((L<S>) loadVariableDefinition("generalReleaseBots"), generalReleaseBots);
  botIDs.addAll(generalReleaseBots);
}

static void reload() {
  reloadLists();
  
  cleanUp(bots);
  activeBots = new ArrayList();
  privBots = new ArrayList();
  botsByID.clear();
  for (S botID : botIDs)
    pcall {
      loadBot(botID);
    }
}

static void reload(S botID) {
  reloadLists();
  S parsedID = "" + parseSnippetID(botID);
  Class bot = botsByID.get(parsedID);
  if (bot != null) {
    cleanUp(bot);
    botsByID.remove(parsedID);
    activeBots.remove(formatSnippetID(botID));
    bots.remove(bot);
    privBots.remove(bot);
  }
  loadBot(botID);
}

static void loadBot(S botID) {
  print("Loading bot: " + botID);
  Class c = hotwire_over_bot ? hotwire_overBot(botID) : hotwire(botID);
  setOpt(c, "mainBot", getMainClass());
  callMain(c);
  bots.add(c);
  activeBots.add(formatSnippetID(botID)); // only if loading doesn't fail
  botsByID.put("" + parseSnippetID(botID), c);
  if (hasMethodNamed(c, "answerPriv"))
    privBots.add(c);
  print("Loaded bot: " + botID + ", bots now: " + l(activeBots));
}

static NanoHTTPD.Response serve(S uri, NanoHTTPD.Method method,
  Map<S,S> header, Map<S,S> parms, Map<S,S> files) {
  print("Serving HTTP " + quote(uri));
  ++hitCount;
  saveLocally("hitCount");
  actualURI.set(uri);
  uri = dropPrefixMandatory("/", uri);
  if (!loaded)
    ret serveHTML("LOADING, PLEASE TRY AGAIN. " + l(bots) + "/" + l(botIDs) + " bots loaded");
  if (eq(uri, ""))
    ret serveHomePage();
  if (eq(uri, "favicon.ico"))
    ret serve404();
    
  // count and set cookie
  O visitorsBot = getBot("#1002157");
  if (visitorsBot != null) {
    S visitorHTML = callHtmlMethod(visitorsBot, "/");
  }
  
  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, parms);
}

static NanoHTTPD.Response serveBot(S botID, S subUri, Map<S, S> params) {
  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) {
    print("Bot " + botID + " methods: " + structure(allMethodNames(bot)));
    S botHtml = callHtmlMethod(bot, subUri, params);
    if (raw) ret serveHTML(unnull(botHtml));
    if (botHtml == null)
      botHtml = "Bot has no HTML output.";
    S title = "Eleutheria Bot " + formatSnippetID(botID);
    S html = "<html><head><title>" + title + "</title></head>" +
      "<body><h3>Bot <a href=\"http://tinybrain.de/" + parseSnippetID(botID) + "\">" + formatSnippetID(botID) + "</a></h3>\n" + botHtml +
      "\n</body></html>";
    ret serveHTML(html);
  }
  
  ret serve404();
}

static NanoHTTPD.Response serveHomePage() {
  new StringBuilder buf;
  buf.append("<html>");
  buf.append("<head><title>Eleutheria Chat Bots</title></head>");
  buf.append("<body>");
  buf.append("<h3><a href=" + htmlQuote("http://tinybrain.de") + ">Eleutheria</a> Bots</h3>");
  buf.append("<ul>");
  for (S botID : concatLists(litlist(getProgramID()), activeBots)) {
    botID = formatSnippetID(botID);
    S parsedID = "" + parseSnippetID(botID);
    S title = "?";
    pcall { title = getSnippetTitle_overBot(botID); }
    S name = botID + " - " + htmlencode(title);
    buf.append("<li><a href=" + htmlQuote(parsedID) + ">" + name + "</a> (");
    buf.append("<a href=" + htmlQuote("http://tinybrain.de/" + parsedID) + ">source</a>)</li>");
  }
  buf.append("</ul>");
  buf.append("<p>Hit count: " + hitCount + "</p>");
  
  buf.append("<p>Last interactions:</p>");
  
  int maxInteractionsToPrint = 10;
  
  for (int i = l(history)-1; i >= 0 && i >= l(history)-maxInteractionsToPrint; i--) {
    Map m = history.get(i);
    buf.append("<p>" + htmlencode(m.get("question")) + "<br>&nbsp; &nbsp; " + htmlencode(m.get("answer")) + "</p>");
  }
  
  buf.append("</body>");
  buf.append("</html>");
  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 prog : litlist("#1001915", "#1002017"))
    for (S s : scanLog(prog, "memory-log")) pcall {
      history.add((Map) safeUnstructure(s));
    }
  print(l(history) + " history entries.");
}

// for current thread
static S getUserName() {
  ret userName.get();
}

// for current thread
static S getDialogID() {
  ret dialogID.get();
}

// for current thread
static S getActualURI() {
  ret actualURI.get();
}

// for sub-bots to call
static O getSession() {
  ret NanoHTTPD.currentSession.get();
}

// for sub-bots to call
static O getCookies() {
  NanoHTTPD.IHTTPSession session = NanoHTTPD.currentSession.get();
  NanoHTTPD.CookieHandler cookies = session.getCookies();
  ret cookies;
}

static O getBot(S botID) {
  ret botsByID.get("" + parseSnippetID(botID));
}

static synchronized void historyAdd(Map logEntry) {
  history.add(logEntry);
  logQuoted(new File(programDir(), "memory-log"), structure(logEntry));
}

static S webAnswer(S s) {
  O session = getSession();
  O cookieHandler = getCookies();
  S cookie = cast call(cookieHandler, "read", "cookie");
  print("Web answer cookie: " + cookie);
  print("Web answer question: " + quote(s));
  S dialogID = cookie;
  
  main.dialogID.set(dialogID);
  // user name is empty for now
        
  S a = null;
  pcall {
    a = answer(s, false); // generalRelease = false, all bots
    print("Web answer: " + quote(a));
    if (empty(a))
      a = "Hello :)";
  }
  if (empty(a)) a = "(no response)";
  Map logEntry = litmap("question", s, "user", "web", "answer", a, "realtime", now());
  historyAdd(logEntry);
  ret a;
}

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: 619 / 518
Referenced in: [show references]