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

609
LINES

< > BotCompany Repo | #1004308 // Random Main v10

JavaX fragment (include)

set flag Matches_fsi.

sbool assisting;

sclass RandomMain {
  S generatorsID;
  
  JFrame frame;
  JTable table, chatTable;
  //JTextArea chat;
  JTextField input;
  L<S> log = synchroList();
  L<S> recommendations;
  L<Thread> thinkThreads = synchroList();
  JLabel status;
  S lastInput;
  Map matchingSuggestion;
  Map<S, ImmL<S>> allLogs = synchroMap();
  JFrame analyzersFrame;
  S dialogImageID;
  JFrame dialogImageFrame;
  
  int listDelay = 2000;
  int maxLineLength = 1000;
  int maxLongStringLength = 100*1000;
  
  Bool thinking;
  new Thinker thinker;
  bool showCPU = true;
  
  S systemPrefix = "[system]";
  
  S dialog = "new";
  
  void randomMain() {
    regularGC();
    //substanceLAF("EmeraldDusk"); // Too dark!
    //substanceLAF("ChallengerDeep"); // So purple!
    //substance("MistAqua");
    substance("Moderate");
  
    table = tableWithTooltips();
    //chat = autoScroll(wordWrapTextArea());
    chatTable = tableWithTooltips();
    input = new JTextField;
    status = jlabel("");
    
    S title = assisting ? "Assistance - " + autoFrameTitle() : autoFrameTitle();
    frame = showFrame(title, vgrid(centerAndSouth(
      //jtabs(1, "Chat", chat, "Details", chatTable),
      chatTable,
      input), centerAndSouth(table, jline(jMemoryInfo(), status))));
    if (!assisting) hideConsole();
    //setFrameIconLater(frame, "#1003593");
    
    addMenu(frame, "Random",
      "Pop up last line in window (!pop)", r { pop(); },
      "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();
    
    addMenu(frame, "Tools",
      "Show Logic List", r { nohupJavax("#1004419"); }
    );
    
    onEnter(input, r {
      post();
    });
    
    onDoubleClick(table, voidfunc(int row) {
      chooseSuggestionForEditing(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) {
      Map map = getTableLineAsMap(chatTable, row);
      if (map != null)
        setInput(getString(map, "Text"));
    });
    
    onUpdate(input, r { updateOnce(); });
    
    loadDialog();
    logEvent("Starting");
    
    updateOnce();
    
    input.requestFocus();
    
    makeBot("Chat.", this);
    
    veryQuickJava_optimize();
    
    S last = last(log);
    if (isAction(last) && confirmYesNo(input, "Run action? " + last(log)))
      action(last);
  }
  
  S getInput() {
    ret joinLines(" # ", input.getText().trim());
  }
  
  void post() {
    postAsUser(getInput(), null);
  }
  
  void postAsUser(S i, Map infos) {
    if (inputAllowedByUser(i))
      post(i, infos);
  }
  
  void 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);
  }
  
  void setInput(final S s) {
    awtIfNecessary {
      lastInput = input.getText();
      input.setText(s);
      input.selectAll();
      input.requestFocus();
    }
  }
  
  void rankToTop(Map map) {
    rankToTop(map, false);
  }
  
  void 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));
  }
  
  void 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));
  }
  
  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;
  }
  
  void logEvent(S type) {
    logEvent(type, litmap());
  }
  
  void logEvent(S type, Map map) {
    logStructure(new File(dialogDir(), "event.log"),
      ll(type, chatTime(), map));
  }
  
  bool inputAllowedByUser(S i) {
    ret !swic(i, systemPrefix);
  }
  
  // may be called from other thread
  void postSystemMessage(final S msg) {
    if (empty(msg)) ret;
    awtIfNecessary {
      post(systemPrefix + " " + msg, litmap("By", "System"));
    }
  }
  
  S post(S i) {
    ret post(i, null);
  }
  
  S post(S i, Map infos) {
    S chatTime = null;
    try {
      i = trim(i);
      if (empty(i)) null;
      //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");
    chatTime = chatTime();
    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));
    }
    ret chatTime;
  }
  
  S dropActionPrefix(S s) {
    if (s == null) null;
    s = dropBracketPrefix(s); // e.g. "[bot]"
    if (!s.startsWith("!")) null;
    ret s.substring(1);
  }
  
  bool isAction(S s) {
    ret dropActionPrefix(s) != null;
  }
  
  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, RandomMain.this);
      } catch e {
        printStackTrace(e);
        postSystemMessage("Error - " + exceptionToStringShort(e));
      } finally {
        genLog_clear();
        gOtherLogs_clear();
        disposeWindow(_loading_window);
      }
    }
  }
  
  volatile bool again;
  
  // This logic is bad...
  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();
    }
  }
  
  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);
    }
  }
  
  // data should be in the un-stringified form
  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"))) {
        Map m = data.get(i);
        matchingSuggestion = mapPlus(m, "Index", i+1);
        pcall {
          L suggesters = (L) m.get("Suggesters");
          if (allEndWith(suggesters, "/i")) { // << These cheat too much
            //print("Dropping matching suggestion from: " + struct(suggesters));
            matchingSuggestion = null;
          }
        }
        data.remove(i);
        ret;
      }
  }
  
  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(); }
      }
    }
  }
  
  void updateOnce() { fillList(true); }
  
  void againl8r() {
    swingAfter(table, listDelay, r { fillList(false); });
  }
  
  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
  L<S> loadLog() {
    log.clear();
    log.addAll(scanEventLogForText(dialogDir()));
    ret log;
  }
  
  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 L<S> getLastFromLog(int n) {
    ret cloneList(getLast(log, n));
  }
  
  synchronized L<S> getLog() {
    ret cloneList(log);
  }
  
  File dialogDir() {
    ret prepareProgramFile(dialog);
  }
  
  File logFile() {
    ret new File(dialogDir(), "log.txt");
  }
  
  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();
    });
  }
  
  void loadDialog() {
    loadLog();
    thinker = new Thinker;
    thinker.startUp(this, log);
    //chat.setText(joinLines(log));
    updateChatTable();
  }
  
  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));
    }
  }
  
  void showAnalyzers() {
    if (analyzersFrame == null)
      analyzersFrame = showFrame("Analyzers");
  }
  
  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(
            "#", "", // not known yet cause of !delete statements
            "Text", escapeNewLines(text),
            "Sugg." /* Suggestion Index */, idx));
        }
      }
      addNumbering(data);
      dataToTable_uneditable(chatTable, data);
      tableColumnMaxWidth(chatTable, 0, 30); // enough for 3 digits?
      tableColumnMaxWidth(chatTable, 2, 40); // enough for 2 digits and a "?"?
      scrollTableDownIn(chatTable, 50);
    }
  }
  
  void addNumbering(L<Map> data) {
    int n = 0;
    for (int i = l(data)-1; i >= 0; i--)
      data.get(i).put("#", ++n);
  }
  
  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;
  }
  
  O generators;
  
  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));
  }
  
  S rawDialog() {
    ret fromLines(log);
  }
  
  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);
  }
  
  L<ImmL<S>> getOtherLogs() {
    // TODO: sort by latest or smth?
    ret valuesList(mapMinus(allLogs, dialog));
  }      
  
  void hideDialogImage() {
    if (dialogImageFrame != null) {
      disposeFrame(dialogImageFrame);
      dialogImageFrame = null;
    }
  }
  
  void showDialogImage() {
    hideDialogImage();
    if (nempty(dialogImageID)) {
    S title = getSnippetTitle(dialogImageID) + " [" + fsI(dialogImageID) + "/" + dialog + "]";
      dialogImageFrame = getFrame(showImage(dialogImageID, title));
    }
  }
  
  S answer(S s) {
    print("answer: " + s);
    new Matches m;
    if "please post * to chat file *" {
      final S line = m.unq(0);
      File file = new File(m.unq(1));
      File myFile = new File(dialogDir(), "event.log");
      print("Comparing files: " + file + " / " + myFile);
      if (sameFile(file, myFile)) {
        print("Foreign-posting: " + quote(line));
        ret ok(swingAndWait(func { post(line) }));
      }
    }
    null;
  }
  
  void pop() {
    S text = last(log);
    if (nempty(text)) showText(text);
  }
}

Author comment

Began life as a copy of #1004031

download  show line numbers  debug dex  old transpilations   

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

No comments. add comment

Snippet ID: #1004308
Snippet name: Random Main v10
Eternal ID of this version: #1004308/2
Text MD5: 706da8b26d71ac5b611cf1bf27251849
Author: stefan
Category: javax / talking robots
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-07-02 11:52:57
Source code size: 16821 bytes / 609 lines
Pitched / IR pitched: No / No
Views / Downloads: 1096 / 1621
Version history: 1 change(s)
Referenced in: #1004309 - Eleutheria ["Random" v10]