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: | 1076 / 1598 |
Version history: | 1 change(s) |
Referenced in: | [show references] |