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

548
LINES

< > BotCompany Repo | #1004031 // Random Main v9

JavaX fragment (include)

sbool assisting;
static S generatorsID;

static JFrame frame;
static JTable table, chatTable;
//static JTextArea chat;
static JTextField input;
static L<S> log = synchroList();
static L<S> recommendations;
static L<Thread> thinkThreads = synchroList();
static JLabel status;
static S lastInput;
static Map matchingSuggestion;
static Map<S, ImmL<S>> allLogs = synchroMap();
static JFrame analyzersFrame;
static S dialogImageID;
static JFrame dialogImageFrame;

static int listDelay = 2000;
static int maxLineLength = 1000;
static int maxLongStringLength = 100*1000;

static Bool thinking;
static new Thinker thinker;
static bool showCPU = true;

static S systemPrefix = "[system]";

static S dialog = "new";

svoid randomMain {
  //substanceLAF("EmeraldDusk"); // Too dark!
  //substanceLAF("ChallengerDeep"); // So purple!
  //substance("MistAqua");
  substance("Moderate");

  table = tableWithTooltips();
  //chat = autoScroll(wordWrapTextArea());
  chatTable = tableWithTooltips();
  input = new JTextField;
  status = new JLabel(" ");
  
  S title = assisting ? "Assistance - " + autoFrameTitle() : autoFrameTitle();
  frame = showFrame(title, vgrid(centerAndSouth(
    //jtabs(1, "Chat", chat, "Details", chatTable),
    chatTable,
    input), centerAndSouth(table, status)));
  //setFrameIconLater(frame, "#1003593");
  
  addMenu(frame, "Random",
    "Delete last line (!delete)", r { post("!delete"); },
    "Reload generators (!gen)", r { post("!gen"); },
    "Restart app (!restart)", r { post("!restart"); },
    "Restart Java engine (!fresh)", r { post("!fresh"); },
    "Execute Java code (!j ...)", r { setInput("!j 1+2"); },
    "Switch dialog (!dialog ...)", r { setInput("!dialog bla"); },
    "Restore last input", r { if (nempty(lastInput)) setInput(lastInput); },
    "Show raw dialog", r { showText("Raw Dialog", rawDialog()); },
  );
  
  makeDialogsMenu();
  
  onEnter(input, r {
    post();
  });
  
  onDoubleClick(table, voidfunc(int row) {
    chooseSuggestion(row);
  });
  
  for (int i = 1; i <= 12; i++) {
    final int _i = i;
    registerFunctionKey(frame, i, r {
      chooseSuggestionForEditing(_i-1);
    });
    registerShiftFunctionKey(frame, i, r {
      chooseSuggestion(_i-1);
    });
    registerCtrlFunctionKey(frame, i, r {
      // post user input and then choose suggestion for editing
      Map<S, S> map = getTableLineAsMap(table, _i-1);
      if (map == null) ret;
      rankToTop(map);
      S s = trim(unnull(map.get("Suggestion")));
      logEvent("Suggestion chosen for editing with pre-post", mapPlus(map, "Row", _i, "Input", getInput(), "Top Suggesters", topSuggesters()));
      post();
      setInput(s);
    });
  }
  
  onDoubleClickOrEnter(chatTable, voidfunc(int row) {
    L line = getTableLine(chatTable, row);
    if (line != null)
      setInput(getString(line, 0));
  });
  
  onUpdate(input, r { updateOnce(); });
  
  loadDialog();
  logEvent("Starting");
  
  updateOnce();
  
  input.requestFocus();
  
  if (isAction(last(log)) && confirmYesNo(input, "Run action? " + last(log)))
    action(last(log));
}

static S getInput() {
  ret joinLines(" # ", input.getText().trim());
}

sv post() {
  postAsUser(getInput(), null);
}

static void postAsUser(S i, Map infos) {
  if (inputAllowedByUser(i))
    post(i, infos);
}

svoid chooseSuggestionForEditing(int row) {
  Map<S, S> map = getTableLineAsMap(table, row);
  if (map == null) ret;
  rankToTop(map);
  S s = trim(unnull(map.get("Suggestion")));
  logEvent("Suggestion chosen for editing", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters()));
  setInput(s);
}

svoid setInput(final S s) {
  awtIfNecessary {
    lastInput = input.getText();
    input.setText(s);
    input.selectAll();
    input.requestFocus();
  }
}

svoid rankToTop(Map map) {
  rankToTop(map, false);
}

svoid rankToTop(Map map, bool removeISuggesters) {
  if (map == null) ret;
  O s = map.get("Suggesters");
  // Table cells have been structure'd by dataToTable
  L<S> sugg = s instanceof L ? (L) s : (L) unstructure((S) s);
  
  // These are cheaters!
  if (removeISuggesters)
    sugg = rejectWhere(func(S s) { s.endsWith("/i") }, sugg);
  
  thinker.rankToTop(first(sugg));
}

svoid chooseSuggestion(int row) {
  Map<S, S> map = getTableLineAsMap(table, row);
  if (map == null) ret;
  rankToTop(map);
  S s = trim(unnull(map.get("Suggestion")));
  if (empty(s)) ret;
  
  //logEvent("Suggestion chosen", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters));
  setInput(s);
  postAsUser(s, mapPlus(map, "Index", row+1));
}

static L topSuggesters() {
  int n = 20;
  n = min(n, tableRows(table));
  new L topSuggesters;
  for (int i = 0; i < n; i++)
    topSuggesters.add(getTableLineAsMap(table, i));
  //if (empty(topSuggesters)) topSuggesters = null;
  ret topSuggesters;
}

svoid logEvent(S type) {
  logEvent(type, litmap());
}

svoid logEvent(S type, Map map) {
  logStructure(new File(dialogDir(), "event.log"),
    ll(type, chatTime(), map));
}

static bool inputAllowedByUser(S i) {
  ret !swic(i, systemPrefix);
}

// may be called from other thread
static void postSystemMessage(final S msg) {
  if (empty(msg)) ret;
  awtIfNecessary {
    post(systemPrefix + " " + msg, litmap("By", "System"));
  }
}

static void post(S i) {
  post(i, null);
}

static void post(S i, Map infos) {
  try {
    i = trim(i);
    if (empty(i)) ret;
    //i = escapeNewLines(i);
    
    if (infos == null) {
      infos = matchingSuggestion;
      if (infos != null)
        print("Ranking to top: " + struct(infos));
      rankToTop(infos, true);
    }
    infos = mapPlus(infos, "Top Suggesters", topSuggesters());
    
    bool tooLong = l(i) > maxLongStringLength;
    
    if (l(i) > maxLineLength) {
      S id = saveLongString(i);
      i = substring(i, 0, maxLineLength) + "... [" + (tooLong ? "too " : "") + "long text " + id + "]";
    }
  } catch e {
    printStackTrace(e);
    i = systemPrefix + " " + exceptionToStringShort(e);
  }
  
  S s = i + "\n";
  //chat.append(escapeNewLines(i) + "\n");
  appendToFile(logFile(), "[" + chatTime() + "] " + s);
  logEvent("Posting", litmap("Text", i, "Infos", infos));
  log.add(i);
  updateChatTable();
  input.selectAll();
  updateOnce();
  try {
    action(i);
  } catch e {
    printStackTrace(e);
    postSystemMessage(exceptionToStringShort(e));
  }
}

static S dropActionPrefix(S s) {
  if (s == null) null;
  s = dropBracketPrefix(s); // e.g. "[bot]"
  if (!s.startsWith("!")) null;
  ret s.substring(1);
}

static bool isAction(S s) {
  ret dropActionPrefix(s) != null;
}

static void action(S s) {
  s = dropActionPrefix(s);
  if (s == null) ret;

  final S _s = s;
  thread "Action" {
    JWindow _loading_window = showLoadingAnimation();
    try {
      genLog_set(getLog()); // 'case user needs it
      gOtherLogs_set(getOtherLogs()); // ditto
      randomsOwnCmds(_s);
      systemCommands(_s, mc());
    } catch e {
      printStackTrace(e);
      postSystemMessage("Error - " + exceptionToStringShort(e));
    } finally {
      genLog_clear();
      gOtherLogs_clear();
      disposeWindow(_loading_window);
    }
  }
}

static volatile bool again;

// This logic is bad...
static void fillList(bool force) {
  bool t = force || shouldUpdateList();
  if (neq(t, thinking)) {
    thinking = t;
    setFrameIcon(table, t ? "#1003603" : "#1003593");
  }
  
  if (!t) {
    if (!force)
      againl8r();
  } else {
    if (nempty(thinkThreads)) { again = true; ret; }
    fillListImpl();
  }
}

static void addKeys(L<Map> data) {
  for (int i = 0; i < l(data); i++) {
    int k = i+1;
    S key = k <= 12 ? "F" + k : null;
    Map m = litorderedmap("Key", key);
    m.putAll(data.get(i));
    data.set(i, m);
  }
}

static void removeMatchingLine(L<Map> data) {
  S input = getInput();
  matchingSuggestion = null;
  for (int i = 0; i < l(data); i++)
    if (eq(input, data.get(i).get("Suggestion"))) {
      matchingSuggestion = mapPlus(data.get(i), "Index", i+1);
      data.remove(i);
      ret;
    }
}

static void fillListImpl() {
  thread "Fill List" {
    try {
      thinkThreads.add(currentThread());
      final new L<Map> data;
      
      thinker.makeListData(cloneList(log), getInput(), getOtherLogs(), data);
      
      awt {
        pcall {
          removeMatchingLine(data);
          addKeys(data);
          dataToTable_uneditable(table, data);
          tableColumnMaxWidth(table, 0, 30); // "Key" column
        }
        againl8r();
      }
    } finally {
      thinkThreads.remove(currentThread());
    if (again) { again = false; fillListImpl(); }
    }
  }
}

static void updateOnce() { fillList(true); }

static void againl8r() {
  swingAfter(table, listDelay, r { fillList(false); });
}

static bool shouldUpdateList() {
  bool result = false;
  S text = " ";
  if (getFrame(table).isFocused()) {
    result = !mouseInComponent(table);
    text = result ? " Thinking..." + (showCPU /*&& thinker.load != 0*/ ? " (" + thinker.load + "% CPU)" : "")
      : "Not thinking cause you got the mouse in there";
  }
  status.setText(text);
  ret result;
}

// also called from outside
static L<S> loadLog() {
  log.clear();
  log.addAll(scanEventLogForText(dialogDir()));
  ret log;
}

static void loadAllLogs() {
  allLogs.clear();
  for (File f : findAllFiles(getProgramDir()))
    if (f.getName().equals("event.log"))
      allLogs.put(f.getParentFile().getName(), new ImmL(scanEventLogForText(f)));
}

synchronized static L<S> getLastFromLog(int n) {
  ret cloneList(getLast(log, n));
}

synchronized static L<S> getLog() {
  ret cloneList(log);
}

static File dialogDir() {
  ret prepareProgramFile(dialog);
}

static File logFile() {
  ret new File(dialogDir(), "log.txt");
}

static void switchDialog(final S name) {
  swingAndWait(r {
    dialog = name;
    touchFile(new File(dialogDir(), "event.log"));
    loadDialog();
    loadAllLogs();
    makeDialogsMenu();
    setFrameTitle(dialog + " - " + getProgramTitle());

    // show special stuff for dialog, like an image
    dialogImageID = trim(readTextFile(new File(dialogDir(), "image-id.txt")));
    showDialogImage();
  });
}

static void loadDialog() {
  loadLog();
  thinker = new Thinker;
  thinker.startUp(log);
  //chat.setText(joinLines(log));
  updateChatTable();
}

static void randomsOwnCmds(S s) {
  new Matches m;
  
  if "dialog *" {
    switchDialog(m.unq(0));
    // TODO: show current dialog somewhere else
    //postSystemMessage("OK, dialog switched to " + quote(dialog));
  }
  
  if "gen"
    generators = null;
  
  if "delete"
    updateChatTable();
    
  if "analyzers"
    showAnalyzers();
    
  if (matchOneOf(s, m, "img *", "image *")) {
    S imageID = m.fsi(0);
    saveTextFile(new File(dialogDir(), "image-id.txt"), imageID);
    dialogImageID = imageID;
    showDialogImage();
  }
  
  if (matchOneOf(s, m, "img", "image")) {
    if (empty(dialogImageID))
      postSystemMessage("No image set for this dialog");
    else
      postSystemMessage("Image for this dialog: " + fsI(dialogImageID));
  }
}

static void showAnalyzers() {
  if (analyzersFrame == null)
    analyzersFrame = showFrame("Analyzers");
}

static void updateChatTable() {
  awtIfNecessary {
    new L data;
    L<L> l = scanLog_safeUnstructure(new File(dialogDir(), "event.log"));
    for (int i = 0; i < l(l); i++) pcall {
      L a = l.get(i), prev = get(l, i-1);
      if (firstIs(a, "Posting")) {
        Map map = cast get(a, 2);
        S text = getString(map, "Text").trim();
        if (eq(text, "!delete")) { removeLast(data); continue; }
        S idx = "";
        Map infos = cast map.get("Infos");
        if (infos != null && infos.containsKey("Index"))
          idx = str(infos.get("Index"));
        else pcall {
          //printStruct("prev: ", prev);
          if (prev != null && firstIs(prev, "Suggestion chosen for editing")) {
            Map m = getMap(prev, 2);
            S suggestion = getString(m, "Suggestion");
            //print("Suggestion: " + structure(suggestion));
            idx = str(get(m, "Row"));
            if (neq(suggestion, text))
              idx += "?";
          }
        }
        data.add(litorderedmap("Text", escapeNewLines(text), "Sugg." /* Suggestion Index */, idx));
      }
    }
    dataToTable_uneditable(chatTable, data);
    tableColumnMaxWidth(chatTable, 1, 40); // enough for 2 digits and a "?"
    scrollTableDownIn(chatTable, 50);
  }
}

static synchronized S saveLongString(S s) {
  s = substring(s, 0, maxLongStringLength);
  S id;
  File f;
  do {
    id = randomID(10);
    f = getProgramFile("long-strings/" + id);
  } while (f.exists());
  
  saveTextFile(f, s);
  ret id;
}

static O generators;

static void makeGenerators(L<Gen> l) {
  synchronized(main.class) {
    if (!isSnippetID(generatorsID)) fail("No generators ID set");
    if (generators == null)
      generators = hotwire(generatorsID);
  }
  new L l2;
  callOpt(generators, "makeGenerators", l2);
  callOpt(generators, "deterministicGenerators", l2);
  l.addAll((L) quickImport(l2));
}

static S rawDialog() {
  ret fromLines(log);
}

static void makeDialogsMenu() {
  new L items;
  for (File dir : listDirs(getProgramDir()))
    if (containsFile(dir, "event.log")) {
      fS dialog = dir.getName();
      items.add(dialog);
      items.add(r { switchDialog(dialog); });
    }
    
  addMenu(frame, "Dialogs", items);
}

static L<ImmL<S>> getOtherLogs() {
  // TODO: sort by latest or smth?
  ret valuesList(mapMinus(allLogs, dialog));
}      

static void hideDialogImage() {
  if (dialogImageFrame != null) {
    disposeFrame(dialogImageFrame);
    dialogImageFrame = null;
  }
}

static void showDialogImage() {
  hideDialogImage();
  if (nempty(dialogImageID)) {
  S title = getSnippetTitle(dialogImageID) + " [" + fsI(dialogImageID) + "/" + dialog + "]";
    dialogImageFrame = getFrame(showImage(dialogImageID, title));
  }
}

Author comment

Began life as a copy of #1003886

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1004031
Snippet name: Random Main v9
Eternal ID of this version: #1004031/1
Text MD5: c5e17d570973834cab9d8fa386574b8b
Author: stefan
Category: javax / talking robots
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2016-08-13 13:39:36
Source code size: 14436 bytes / 548 lines
Pitched / IR pitched: No / No
Views / Downloads: 685 / 1036
Referenced in: #1004032 - Eleutheria [Random v9]
#1004308 - Random Main v10