1 | set flag Matches_fsi. |
2 | |
3 | sbool assisting; |
4 | |
5 | sclass RandomMain {
|
6 | S generatorsID; |
7 | |
8 | JFrame frame; |
9 | JTable table, chatTable; |
10 | //JTextArea chat; |
11 | JTextField input; |
12 | L<S> log = synchroList(); |
13 | L<S> recommendations; |
14 | L<Thread> thinkThreads = synchroList(); |
15 | JLabel status; |
16 | S lastInput; |
17 | Map matchingSuggestion; |
18 | Map<S, ImmL<S>> allLogs = synchroMap(); |
19 | JFrame analyzersFrame; |
20 | S dialogImageID; |
21 | JFrame dialogImageFrame; |
22 | |
23 | int listDelay = 2000; |
24 | int maxLineLength = 1000; |
25 | int maxLongStringLength = 100*1000; |
26 | |
27 | Bool thinking; |
28 | new Thinker thinker; |
29 | bool showCPU = true; |
30 | |
31 | S systemPrefix = "[system]"; |
32 | |
33 | S dialog = "new"; |
34 | |
35 | void randomMain() {
|
36 | regularGC(); |
37 | //substanceLAF("EmeraldDusk"); // Too dark!
|
38 | //substanceLAF("ChallengerDeep"); // So purple!
|
39 | //substance("MistAqua");
|
40 | substance("Moderate");
|
41 | |
42 | table = tableWithTooltips(); |
43 | //chat = autoScroll(wordWrapTextArea()); |
44 | chatTable = tableWithTooltips(); |
45 | input = new JTextField; |
46 | status = jlabel("");
|
47 | |
48 | S title = assisting ? "Assistance - " + autoFrameTitle() : autoFrameTitle(); |
49 | frame = showFrame(title, vgrid(centerAndSouth( |
50 | //jtabs(1, "Chat", chat, "Details", chatTable), |
51 | chatTable, |
52 | input), centerAndSouth(table, jline(jMemoryInfo(), status)))); |
53 | if (!assisting) hideConsole(); |
54 | //setFrameIconLater(frame, "#1003593"); |
55 | |
56 | addMenu(frame, "Random", |
57 | "Pop up last line in window (!pop)", r { pop(); },
|
58 | "Delete last line (!delete)", r { post("!delete"); },
|
59 | "Reload generators (!gen)", r { post("!gen"); },
|
60 | "Restart app (!restart)", r { post("!restart"); },
|
61 | "Restart Java engine (!fresh)", r { post("!fresh"); },
|
62 | "Execute Java code (!j ...)", r { setInput("!j 1+2"); },
|
63 | "Switch dialog (!dialog ...)", r { setInput("!dialog bla"); },
|
64 | "Restore last input", r { if (nempty(lastInput)) setInput(lastInput); },
|
65 | "Show raw dialog", r { showText("Raw Dialog", rawDialog()); },
|
66 | ); |
67 | |
68 | makeDialogsMenu(); |
69 | |
70 | addMenu(frame, "Tools", |
71 | "Show Logic List", r { nohupJavax("#1004419"); }
|
72 | ); |
73 | |
74 | onEnter(input, r {
|
75 | post(); |
76 | }); |
77 | |
78 | onDoubleClick(table, voidfunc(int row) {
|
79 | chooseSuggestionForEditing(row); |
80 | }); |
81 | |
82 | for (int i = 1; i <= 12; i++) {
|
83 | final int _i = i; |
84 | registerFunctionKey(frame, i, r {
|
85 | chooseSuggestionForEditing(_i-1); |
86 | }); |
87 | registerShiftFunctionKey(frame, i, r {
|
88 | chooseSuggestion(_i-1); |
89 | }); |
90 | registerCtrlFunctionKey(frame, i, r {
|
91 | // post user input and then choose suggestion for editing |
92 | Map<S, S> map = getTableLineAsMap(table, _i-1); |
93 | if (map == null) ret; |
94 | rankToTop(map); |
95 | S s = trim(unnull(map.get("Suggestion")));
|
96 | logEvent("Suggestion chosen for editing with pre-post", mapPlus(map, "Row", _i, "Input", getInput(), "Top Suggesters", topSuggesters()));
|
97 | post(); |
98 | setInput(s); |
99 | }); |
100 | } |
101 | |
102 | onDoubleClickOrEnter(chatTable, voidfunc(int row) {
|
103 | Map map = getTableLineAsMap(chatTable, row); |
104 | if (map != null) |
105 | setInput(getString(map, "Text")); |
106 | }); |
107 | |
108 | onUpdate(input, r { updateOnce(); });
|
109 | |
110 | loadDialog(); |
111 | logEvent("Starting");
|
112 | |
113 | updateOnce(); |
114 | |
115 | input.requestFocus(); |
116 | |
117 | makeBot("Chat.", this);
|
118 | |
119 | veryQuickJava_optimize(); |
120 | |
121 | S last = last(log); |
122 | if (isAction(last) && confirmYesNo(input, "Run action? " + last(log))) |
123 | action(last); |
124 | } |
125 | |
126 | S getInput() {
|
127 | ret joinLines(" # ", input.getText().trim());
|
128 | } |
129 | |
130 | void post() {
|
131 | postAsUser(getInput(), null); |
132 | } |
133 | |
134 | void postAsUser(S i, Map infos) {
|
135 | if (inputAllowedByUser(i)) |
136 | post(i, infos); |
137 | } |
138 | |
139 | void chooseSuggestionForEditing(int row) {
|
140 | Map<S, S> map = getTableLineAsMap(table, row); |
141 | if (map == null) ret; |
142 | rankToTop(map); |
143 | S s = trim(unnull(map.get("Suggestion")));
|
144 | logEvent("Suggestion chosen for editing", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters()));
|
145 | setInput(s); |
146 | } |
147 | |
148 | void setInput(final S s) {
|
149 | awtIfNecessary {
|
150 | lastInput = input.getText(); |
151 | input.setText(s); |
152 | input.selectAll(); |
153 | input.requestFocus(); |
154 | } |
155 | } |
156 | |
157 | void rankToTop(Map map) {
|
158 | rankToTop(map, false); |
159 | } |
160 | |
161 | void rankToTop(Map map, bool removeISuggesters) {
|
162 | if (map == null) ret; |
163 | O s = map.get("Suggesters");
|
164 | // Table cells have been structure'd by dataToTable |
165 | L<S> sugg = s instanceof L ? (L) s : (L) unstructure((S) s); |
166 | |
167 | // These are cheaters! |
168 | if (removeISuggesters) |
169 | sugg = rejectWhere(func(S s) { s.endsWith("/i") }, sugg);
|
170 | |
171 | thinker.rankToTop(first(sugg)); |
172 | } |
173 | |
174 | void chooseSuggestion(int row) {
|
175 | Map<S, S> map = getTableLineAsMap(table, row); |
176 | if (map == null) ret; |
177 | rankToTop(map); |
178 | S s = trim(unnull(map.get("Suggestion")));
|
179 | if (empty(s)) ret; |
180 | |
181 | //logEvent("Suggestion chosen", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters));
|
182 | setInput(s); |
183 | postAsUser(s, mapPlus(map, "Index", row+1)); |
184 | } |
185 | |
186 | L topSuggesters() {
|
187 | int n = 20; |
188 | n = min(n, tableRows(table)); |
189 | new L topSuggesters; |
190 | for (int i = 0; i < n; i++) |
191 | topSuggesters.add(getTableLineAsMap(table, i)); |
192 | //if (empty(topSuggesters)) topSuggesters = null; |
193 | ret topSuggesters; |
194 | } |
195 | |
196 | void logEvent(S type) {
|
197 | logEvent(type, litmap()); |
198 | } |
199 | |
200 | void logEvent(S type, Map map) {
|
201 | logStructure(new File(dialogDir(), "event.log"), |
202 | ll(type, chatTime(), map)); |
203 | } |
204 | |
205 | bool inputAllowedByUser(S i) {
|
206 | ret !swic(i, systemPrefix); |
207 | } |
208 | |
209 | // may be called from other thread |
210 | void postSystemMessage(final S msg) {
|
211 | if (empty(msg)) ret; |
212 | awtIfNecessary {
|
213 | post(systemPrefix + " " + msg, litmap("By", "System"));
|
214 | } |
215 | } |
216 | |
217 | S post(S i) {
|
218 | ret post(i, null); |
219 | } |
220 | |
221 | S post(S i, Map infos) {
|
222 | S chatTime = null; |
223 | try {
|
224 | i = trim(i); |
225 | if (empty(i)) null; |
226 | //i = escapeNewLines(i); |
227 | |
228 | if (infos == null) {
|
229 | infos = matchingSuggestion; |
230 | if (infos != null) |
231 | print("Ranking to top: " + struct(infos));
|
232 | rankToTop(infos, true); |
233 | } |
234 | infos = mapPlus(infos, "Top Suggesters", topSuggesters()); |
235 | |
236 | bool tooLong = l(i) > maxLongStringLength; |
237 | |
238 | if (l(i) > maxLineLength) {
|
239 | S id = saveLongString(i); |
240 | i = substring(i, 0, maxLineLength) + "... [" + (tooLong ? "too " : "") + "long text " + id + "]"; |
241 | } |
242 | } catch e {
|
243 | printStackTrace(e); |
244 | i = systemPrefix + " " + exceptionToStringShort(e); |
245 | } |
246 | |
247 | S s = i + "\n"; |
248 | //chat.append(escapeNewLines(i) + "\n"); |
249 | chatTime = chatTime(); |
250 | appendToFile(logFile(), "[" + chatTime + "] " + s); |
251 | logEvent("Posting", litmap("Text", i, "Infos", infos));
|
252 | log.add(i); |
253 | updateChatTable(); |
254 | input.selectAll(); |
255 | updateOnce(); |
256 | try {
|
257 | action(i); |
258 | } catch e {
|
259 | printStackTrace(e); |
260 | postSystemMessage(exceptionToStringShort(e)); |
261 | } |
262 | ret chatTime; |
263 | } |
264 | |
265 | S dropActionPrefix(S s) {
|
266 | if (s == null) null; |
267 | s = dropBracketPrefix(s); // e.g. "[bot]" |
268 | if (!s.startsWith("!")) null;
|
269 | ret s.substring(1); |
270 | } |
271 | |
272 | bool isAction(S s) {
|
273 | ret dropActionPrefix(s) != null; |
274 | } |
275 | |
276 | void action(S s) {
|
277 | s = dropActionPrefix(s); |
278 | if (s == null) ret; |
279 | |
280 | final S _s = s; |
281 | thread "Action" {
|
282 | JWindow _loading_window = showLoadingAnimation(); |
283 | try {
|
284 | genLog_set(getLog()); // 'case user needs it |
285 | gOtherLogs_set(getOtherLogs()); // ditto |
286 | randomsOwnCmds(_s); |
287 | systemCommands(_s, RandomMain.this); |
288 | } catch e {
|
289 | printStackTrace(e); |
290 | postSystemMessage("Error - " + exceptionToStringShort(e));
|
291 | } finally {
|
292 | genLog_clear(); |
293 | gOtherLogs_clear(); |
294 | disposeWindow(_loading_window); |
295 | } |
296 | } |
297 | } |
298 | |
299 | volatile bool again; |
300 | |
301 | // This logic is bad... |
302 | void fillList(bool force) {
|
303 | bool t = force || shouldUpdateList(); |
304 | if (neq(t, thinking)) {
|
305 | thinking = t; |
306 | setFrameIcon(table, t ? "#1003603" : "#1003593"); |
307 | } |
308 | |
309 | if (!t) {
|
310 | if (!force) |
311 | againl8r(); |
312 | } else {
|
313 | if (nempty(thinkThreads)) { again = true; ret; }
|
314 | fillListImpl(); |
315 | } |
316 | } |
317 | |
318 | void addKeys(L<Map> data) {
|
319 | for (int i = 0; i < l(data); i++) {
|
320 | int k = i+1; |
321 | S key = k <= 12 ? "F" + k : null; |
322 | Map m = litorderedmap("Key", key);
|
323 | m.putAll(data.get(i)); |
324 | data.set(i, m); |
325 | } |
326 | } |
327 | |
328 | // data should be in the un-stringified form |
329 | void removeMatchingLine(L<Map> data) {
|
330 | S input = getInput(); |
331 | matchingSuggestion = null; |
332 | for (int i = 0; i < l(data); i++) |
333 | if (eq(input, data.get(i).get("Suggestion"))) {
|
334 | Map m = data.get(i); |
335 | matchingSuggestion = mapPlus(m, "Index", i+1); |
336 | pcall {
|
337 | L suggesters = (L) m.get("Suggesters");
|
338 | if (allEndWith(suggesters, "/i")) { // << These cheat too much
|
339 | //print("Dropping matching suggestion from: " + struct(suggesters));
|
340 | matchingSuggestion = null; |
341 | } |
342 | } |
343 | data.remove(i); |
344 | ret; |
345 | } |
346 | } |
347 | |
348 | void fillListImpl() {
|
349 | thread "Fill List" {
|
350 | try {
|
351 | thinkThreads.add(currentThread()); |
352 | final new L<Map> data; |
353 | |
354 | thinker.makeListData(cloneList(log), getInput(), getOtherLogs(), data); |
355 | |
356 | awt {
|
357 | pcall {
|
358 | removeMatchingLine(data); |
359 | addKeys(data); |
360 | dataToTable_uneditable(table, data); |
361 | tableColumnMaxWidth(table, 0, 30); // "Key" column |
362 | } |
363 | againl8r(); |
364 | } |
365 | } finally {
|
366 | thinkThreads.remove(currentThread()); |
367 | if (again) { again = false; fillListImpl(); }
|
368 | } |
369 | } |
370 | } |
371 | |
372 | void updateOnce() { fillList(true); }
|
373 | |
374 | void againl8r() {
|
375 | swingAfter(table, listDelay, r { fillList(false); });
|
376 | } |
377 | |
378 | bool shouldUpdateList() {
|
379 | bool result = false; |
380 | S text = " "; |
381 | if (getFrame(table).isFocused()) {
|
382 | result = !mouseInComponent(table); |
383 | text = result ? " Thinking..." + (showCPU /*&& thinker.load != 0*/ ? " (" + thinker.load + "% CPU)" : "")
|
384 | : "Not thinking cause you got the mouse in there"; |
385 | } |
386 | status.setText(text); |
387 | ret result; |
388 | } |
389 | |
390 | // also called from outside |
391 | L<S> loadLog() {
|
392 | log.clear(); |
393 | log.addAll(scanEventLogForText(dialogDir())); |
394 | ret log; |
395 | } |
396 | |
397 | void loadAllLogs() {
|
398 | allLogs.clear(); |
399 | for (File f : findAllFiles(getProgramDir())) |
400 | if (f.getName().equals("event.log"))
|
401 | allLogs.put(f.getParentFile().getName(), new ImmL(scanEventLogForText(f))); |
402 | } |
403 | |
404 | synchronized L<S> getLastFromLog(int n) {
|
405 | ret cloneList(getLast(log, n)); |
406 | } |
407 | |
408 | synchronized L<S> getLog() {
|
409 | ret cloneList(log); |
410 | } |
411 | |
412 | File dialogDir() {
|
413 | ret prepareProgramFile(dialog); |
414 | } |
415 | |
416 | File logFile() {
|
417 | ret new File(dialogDir(), "log.txt"); |
418 | } |
419 | |
420 | void switchDialog(final S name) {
|
421 | swingAndWait(r {
|
422 | dialog = name; |
423 | touchFile(new File(dialogDir(), "event.log")); |
424 | loadDialog(); |
425 | loadAllLogs(); |
426 | makeDialogsMenu(); |
427 | setFrameTitle(dialog + " - " + getProgramTitle()); |
428 | |
429 | // show special stuff for dialog, like an image |
430 | dialogImageID = trim(readTextFile(new File(dialogDir(), "image-id.txt"))); |
431 | showDialogImage(); |
432 | }); |
433 | } |
434 | |
435 | void loadDialog() {
|
436 | loadLog(); |
437 | thinker = new Thinker; |
438 | thinker.startUp(this, log); |
439 | //chat.setText(joinLines(log)); |
440 | updateChatTable(); |
441 | } |
442 | |
443 | void randomsOwnCmds(S s) {
|
444 | new Matches m; |
445 | |
446 | if "dialog *" {
|
447 | switchDialog(m.unq(0)); |
448 | // TODO: show current dialog somewhere else |
449 | //postSystemMessage("OK, dialog switched to " + quote(dialog));
|
450 | } |
451 | |
452 | if "gen" |
453 | generators = null; |
454 | |
455 | if "delete" |
456 | updateChatTable(); |
457 | |
458 | if "analyzers" |
459 | showAnalyzers(); |
460 | |
461 | if (matchOneOf(s, m, "img *", "image *")) {
|
462 | S imageID = m.fsi(0); |
463 | saveTextFile(new File(dialogDir(), "image-id.txt"), imageID); |
464 | dialogImageID = imageID; |
465 | showDialogImage(); |
466 | } |
467 | |
468 | if (matchOneOf(s, m, "img", "image")) {
|
469 | if (empty(dialogImageID)) |
470 | postSystemMessage("No image set for this dialog");
|
471 | else |
472 | postSystemMessage("Image for this dialog: " + fsI(dialogImageID));
|
473 | } |
474 | } |
475 | |
476 | void showAnalyzers() {
|
477 | if (analyzersFrame == null) |
478 | analyzersFrame = showFrame("Analyzers");
|
479 | } |
480 | |
481 | void updateChatTable() {
|
482 | awtIfNecessary {
|
483 | new L data; |
484 | L<L> l = scanLog_safeUnstructure(new File(dialogDir(), "event.log")); |
485 | for (int i = 0; i < l(l); i++) pcall {
|
486 | L a = l.get(i), prev = get(l, i-1); |
487 | if (firstIs(a, "Posting")) {
|
488 | Map map = cast get(a, 2); |
489 | S text = getString(map, "Text").trim(); |
490 | if (eq(text, "!delete")) { removeLast(data); continue; }
|
491 | S idx = ""; |
492 | Map infos = cast map.get("Infos");
|
493 | if (infos != null && infos.containsKey("Index"))
|
494 | idx = str(infos.get("Index"));
|
495 | else pcall {
|
496 | //printStruct("prev: ", prev);
|
497 | if (prev != null && firstIs(prev, "Suggestion chosen for editing")) {
|
498 | Map m = getMap(prev, 2); |
499 | S suggestion = getString(m, "Suggestion"); |
500 | //print("Suggestion: " + structure(suggestion));
|
501 | idx = str(get(m, "Row")); |
502 | if (neq(suggestion, text)) |
503 | idx += "?"; |
504 | } |
505 | } |
506 | data.add(litorderedmap( |
507 | "#", "", // not known yet cause of !delete statements |
508 | "Text", escapeNewLines(text), |
509 | "Sugg." /* Suggestion Index */, idx)); |
510 | } |
511 | } |
512 | addNumbering(data); |
513 | dataToTable_uneditable(chatTable, data); |
514 | tableColumnMaxWidth(chatTable, 0, 30); // enough for 3 digits? |
515 | tableColumnMaxWidth(chatTable, 2, 40); // enough for 2 digits and a "?"? |
516 | scrollTableDownIn(chatTable, 50); |
517 | } |
518 | } |
519 | |
520 | void addNumbering(L<Map> data) {
|
521 | int n = 0; |
522 | for (int i = l(data)-1; i >= 0; i--) |
523 | data.get(i).put("#", ++n);
|
524 | } |
525 | |
526 | synchronized S saveLongString(S s) {
|
527 | s = substring(s, 0, maxLongStringLength); |
528 | S id; |
529 | File f; |
530 | do {
|
531 | id = randomID(10); |
532 | f = getProgramFile("long-strings/" + id);
|
533 | } while (f.exists()); |
534 | |
535 | saveTextFile(f, s); |
536 | ret id; |
537 | } |
538 | |
539 | O generators; |
540 | |
541 | void makeGenerators(L<Gen> l) {
|
542 | synchronized(main.class) {
|
543 | if (!isSnippetID(generatorsID)) fail("No generators ID set");
|
544 | if (generators == null) |
545 | generators = hotwire(generatorsID); |
546 | } |
547 | new L l2; |
548 | callOpt(generators, "makeGenerators", l2); |
549 | callOpt(generators, "deterministicGenerators", l2); |
550 | l.addAll((L) quickImport(l2)); |
551 | } |
552 | |
553 | S rawDialog() {
|
554 | ret fromLines(log); |
555 | } |
556 | |
557 | void makeDialogsMenu() {
|
558 | new L items; |
559 | for (File dir : listDirs(getProgramDir())) |
560 | if (containsFile(dir, "event.log")) {
|
561 | fS dialog = dir.getName(); |
562 | items.add(dialog); |
563 | items.add(r { switchDialog(dialog); });
|
564 | } |
565 | |
566 | addMenu(frame, "Dialogs", items); |
567 | } |
568 | |
569 | L<ImmL<S>> getOtherLogs() {
|
570 | // TODO: sort by latest or smth? |
571 | ret valuesList(mapMinus(allLogs, dialog)); |
572 | } |
573 | |
574 | void hideDialogImage() {
|
575 | if (dialogImageFrame != null) {
|
576 | disposeFrame(dialogImageFrame); |
577 | dialogImageFrame = null; |
578 | } |
579 | } |
580 | |
581 | void showDialogImage() {
|
582 | hideDialogImage(); |
583 | if (nempty(dialogImageID)) {
|
584 | S title = getSnippetTitle(dialogImageID) + " [" + fsI(dialogImageID) + "/" + dialog + "]"; |
585 | dialogImageFrame = getFrame(showImage(dialogImageID, title)); |
586 | } |
587 | } |
588 | |
589 | S answer(S s) {
|
590 | print("answer: " + s);
|
591 | new Matches m; |
592 | if "please post * to chat file *" {
|
593 | final S line = m.unq(0); |
594 | File file = new File(m.unq(1)); |
595 | File myFile = new File(dialogDir(), "event.log"); |
596 | print("Comparing files: " + file + " / " + myFile);
|
597 | if (sameFile(file, myFile)) {
|
598 | print("Foreign-posting: " + quote(line));
|
599 | ret ok(swingAndWait(func { post(line) }));
|
600 | } |
601 | } |
602 | null; |
603 | } |
604 | |
605 | void pop() {
|
606 | S text = last(log); |
607 | if (nempty(text)) showText(text); |
608 | } |
609 | } |
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: | 1331 / 1860 |
| Version history: | 1 change(s) |
| Referenced in: | [show references] |