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