1 | static S generatorsID; |
2 | |
3 | static JTable table, chatTable; |
4 | static JTextArea chat; |
5 | static JTextField input; |
6 | static L<S> log = synchroList(); |
7 | static L<S> recommendations; |
8 | static L<Thread> thinkThreads = synchroList(); |
9 | static JLabel status; |
10 | |
11 | static int listDelay = 2000; |
12 | static int maxLineLength = 1000; |
13 | static int maxLongStringLength = 100*1000; |
14 | |
15 | static Bool thinking; |
16 | static new Thinker thinker; |
17 | |
18 | static S systemPrefix = "[system]"; |
19 | |
20 | static S dialog = "new"; |
21 | |
22 | svoid randomMain { |
23 | //substanceLAF("EmeraldDusk"); // Too dark! |
24 | substanceLAF("ChallengerDeep"); |
25 | |
26 | table = tableWithTooltips(); |
27 | chat = autoScroll(wordWrapTextArea()); |
28 | chatTable = tableWithTooltips(); |
29 | input = new JTextField; |
30 | status = new JLabel(" "); |
31 | |
32 | JFrame frame = showFrame(vgrid(centerAndSouth( |
33 | jtabs(1, "Chat", chat, "Details", chatTable), |
34 | input), centerAndSouth(table, status))); |
35 | //setFrameIconLater(frame, "#1003593"); |
36 | |
37 | onEnter(input, r { |
38 | post(); |
39 | }); |
40 | |
41 | onDoubleClick(table, voidfunc(int row) { |
42 | chooseSuggestion(row); |
43 | }); |
44 | |
45 | for (int i = 1; i <= 12; i++) { |
46 | final int _i = i; |
47 | registerFunctionKey(frame, i, r { |
48 | chooseSuggestionForEditing(_i-1); |
49 | }); |
50 | registerShiftFunctionKey(frame, i, r { |
51 | chooseSuggestion(_i-1); |
52 | }); |
53 | } |
54 | |
55 | onUpdate(input, r { updateOnce(); }); |
56 | |
57 | loadDialog(); |
58 | logEvent("Starting"); |
59 | |
60 | updateOnce(); |
61 | |
62 | input.requestFocus(); |
63 | |
64 | if (isAction(last(log)) && confirmYesNo(input, "Run action? " + last(log))) |
65 | action(last(log)); |
66 | } |
67 | |
68 | static S getInput() { |
69 | ret joinLines(" # ", input.getText().trim()); |
70 | } |
71 | |
72 | sv post() { |
73 | postAsUser(getInput(), null); |
74 | } |
75 | |
76 | static void postAsUser(S i, Map infos) { |
77 | if (inputAllowedByUser(i)) |
78 | post(i, infos); |
79 | } |
80 | |
81 | svoid chooseSuggestionForEditing(int row) { |
82 | Map<S, S> map = getTableLineAsMap(table, row); |
83 | if (map == null) ret; |
84 | rankToTop(map); |
85 | S s = trim(unnull(map.get("Suggestion"))); |
86 | logEvent("Suggestion chosen for editing", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters())); |
87 | input.setText(s); |
88 | input.selectAll(); |
89 | input.requestFocus(); |
90 | } |
91 | |
92 | svoid rankToTop(Map map) { |
93 | // Table cells have been structure'd by dataToTable |
94 | thinker.rankToTop(first((L<S>) unstructure(getString(map, "Suggesters")))); |
95 | } |
96 | |
97 | svoid chooseSuggestion(int row) { |
98 | Map<S, S> map = getTableLineAsMap(table, row); |
99 | if (map == null) ret; |
100 | rankToTop(map); |
101 | S s = trim(unnull(map.get("Suggestion"))); |
102 | if (empty(s)) ret; |
103 | |
104 | //logEvent("Suggestion chosen", mapPlus(map, "Row", row+1, "Input", getInput(), "Top Suggesters", topSuggesters)); |
105 | input.setText(s); |
106 | postAsUser(s, mapPlus(map, "Index", row+1)); |
107 | } |
108 | |
109 | static L topSuggesters() { |
110 | int n = 20; |
111 | n = min(n, tableRows(table)); |
112 | new L topSuggesters; |
113 | for (int i = 0; i < n; i++) |
114 | topSuggesters.add(getTableLineAsMap(table, i)); |
115 | //if (empty(topSuggesters)) topSuggesters = null; |
116 | ret topSuggesters; |
117 | } |
118 | |
119 | svoid logEvent(S type) { |
120 | logEvent(type, litmap()); |
121 | } |
122 | |
123 | svoid logEvent(S type, Map map) { |
124 | logStructure(new File(dialogDir(), "event.log"), |
125 | ll(type, chatTime(), map)); |
126 | } |
127 | |
128 | static bool inputAllowedByUser(S i) { |
129 | ret !swic(i, systemPrefix); |
130 | } |
131 | |
132 | // may be called from other thread |
133 | static void postSystemMessage(final S msg) { |
134 | if (empty(msg)) ret; |
135 | awtIfNecessary { |
136 | post(systemPrefix + " " + msg, litmap("By", "System")); |
137 | } |
138 | } |
139 | |
140 | static void post(S i, Map infos) { |
141 | try { |
142 | i = trim(i); |
143 | if (empty(i)) ret; |
144 | //i = escapeNewLines(i); |
145 | infos = mapPlus(infos, "Top Suggesters", topSuggesters()); |
146 | |
147 | bool tooLong = l(i) > maxLongStringLength; |
148 | |
149 | if (l(i) > maxLineLength) { |
150 | S id = saveLongString(i); |
151 | i = substring(i, 0, maxLineLength) + "... [" + (tooLong ? "too " : "") + "long text " + id + "]"; |
152 | } |
153 | } catch e { |
154 | printStackTrace(e); |
155 | i = systemPrefix + " " + exceptionToStringShort(e); |
156 | } |
157 | |
158 | S s = i + "\n"; |
159 | chat.append(escapeNewLines(i) + "\n"); |
160 | appendToFile(logFile(), "[" + chatTime() + "] " + s); |
161 | logEvent("Posting", litmap("Text", i, "Infos", infos)); |
162 | log.add(i); |
163 | updateChatTable(); |
164 | input.selectAll(); |
165 | updateOnce(); |
166 | try { |
167 | action(i); |
168 | } catch e { |
169 | printStackTrace(e); |
170 | postSystemMessage(exceptionToStringShort(e)); |
171 | } |
172 | } |
173 | |
174 | static S dropActionPrefix(S s) { |
175 | if (s == null) null; |
176 | s = dropBracketPrefix(s); // e.g. "[bot]" |
177 | if (!s.startsWith("!")) null; |
178 | ret s.substring(1); |
179 | } |
180 | |
181 | static bool isAction(S s) { |
182 | ret dropActionPrefix(s) != null; |
183 | } |
184 | |
185 | static void action(S s) { |
186 | s = dropActionPrefix(s); |
187 | if (s == null) ret; |
188 | |
189 | final S _s = s; |
190 | thread "Action" { |
191 | loading { |
192 | try { |
193 | genLog_set(getLog()); // 'case user needs it |
194 | randomsOwnCmds(_s); |
195 | actionImpl(_s); // user must provide this |
196 | } catch e { |
197 | printStackTrace(e); |
198 | postSystemMessage("Error - " + exceptionToStringShort(e)); |
199 | } |
200 | } |
201 | } |
202 | } |
203 | |
204 | static volatile bool again; |
205 | |
206 | // This logic is bad... |
207 | static void fillList(bool force) { |
208 | bool t = force || shouldUpdateList(); |
209 | if (neq(t, thinking)) { |
210 | thinking = t; |
211 | setFrameIcon(table, t ? "#1003603" : "#1003593"); |
212 | } |
213 | |
214 | if (!t) { |
215 | if (!force) |
216 | againl8r(); |
217 | } else { |
218 | if (nempty(thinkThreads)) { again = true; ret; } |
219 | fillListImpl(); |
220 | } |
221 | } |
222 | |
223 | static void fillListImpl() { |
224 | thread "Fill List" { |
225 | try { |
226 | thinkThreads.add(currentThread()); |
227 | final new L<S> data; |
228 | thinker.makeListData(cloneList(log), getInput(), data); |
229 | |
230 | awt { |
231 | pcall { |
232 | dataToTable_uneditable(table, data); |
233 | tableColumnMaxWidth(table, 0, 30); // "Key" column |
234 | } |
235 | againl8r(); |
236 | } |
237 | } finally { |
238 | thinkThreads.remove(currentThread()); |
239 | if (again) { again = false; fillListImpl(); } |
240 | } |
241 | } |
242 | } |
243 | |
244 | static void updateOnce() { fillList(true); } |
245 | |
246 | static void againl8r() { |
247 | swingAfter(table, listDelay, r { fillList(false); }); |
248 | } |
249 | |
250 | static bool shouldUpdateList() { |
251 | bool result = false; |
252 | S text = " "; |
253 | if (getFrame(table).isFocused()) { |
254 | result = !mouseInComponent(table); |
255 | text = result ? " Thinking... " |
256 | : "Not thinking cause you got the mouse in there"; |
257 | } |
258 | status.setText(text); |
259 | ret result; |
260 | } |
261 | |
262 | // also called from outside |
263 | static L<S> loadLog() { |
264 | log.clear(); |
265 | log.addAll(collect(scanEventLogForPosts(dialogDir()), "text")); |
266 | ret log; |
267 | } |
268 | |
269 | synchronized static L<S> getLastFromLog(int n) { |
270 | ret cloneList(getLast(log, n)); |
271 | } |
272 | |
273 | synchronized static L<S> getLog() { |
274 | ret cloneList(log); |
275 | } |
276 | |
277 | static File dialogDir() { |
278 | ret prepareProgramFile(dialog); |
279 | } |
280 | |
281 | static File logFile() { |
282 | ret new File(dialogDir(), "log.txt"); |
283 | } |
284 | |
285 | static void switchDialog(final S name) { |
286 | swingAndWait(r { |
287 | dialog = name; |
288 | loadDialog(); |
289 | }); |
290 | } |
291 | |
292 | static void loadDialog() { |
293 | loadLog(); |
294 | thinker = new Thinker; |
295 | thinker.startUp(log); |
296 | chat.setText(joinLines(log)); |
297 | updateChatTable(); |
298 | } |
299 | |
300 | static void randomsOwnCmds(S s) { |
301 | new Matches m; |
302 | if "dialog *" { |
303 | switchDialog(m.unq(0)); |
304 | // TODO: show current dialog somewhere else |
305 | //postSystemMessage("OK, dialog switched to " + quote(dialog)); |
306 | } |
307 | |
308 | if "gen" |
309 | generators = null; |
310 | |
311 | if "delete" |
312 | updateChatTable(); |
313 | } |
314 | |
315 | static void updateChatTable() { |
316 | assertAWT(); |
317 | new L data; |
318 | L<L> l = scanLog_safeUnstructure(new File(dialogDir(), "event.log")); |
319 | for (int i = 0; i < l(l); i++) pcall { |
320 | L a = l.get(i), prev = get(l, i-1); |
321 | if (firstIs(a, "Posting")) { |
322 | Map map = cast get(a, 2); |
323 | S text = getString(map, "Text").trim(); |
324 | if (eq(text, "!delete")) { removeLast(data); continue; } |
325 | S idx = ""; |
326 | Map infos = cast map.get("Infos"); |
327 | if (infos != null && infos.containsKey("Index")) |
328 | idx = str(infos.get("Index")); |
329 | else pcall { |
330 | //printStruct("prev: ", prev); |
331 | if (prev != null && firstIs(prev, "Suggestion chosen for editing")) { |
332 | Map m = getMap(prev, 2); |
333 | S suggestion = getString(m, "Suggestion"); |
334 | //print("Suggestion: " + structure(suggestion)); |
335 | idx = str(get(m, "Row")); |
336 | if (neq(suggestion, text)) |
337 | idx += "?"; |
338 | } |
339 | } |
340 | data.add(litorderedmap("Text", escapeNewLines(text), "SI" /* Suggestion Index */, idx)); |
341 | } |
342 | } |
343 | dataToTable_uneditable(chatTable, data); |
344 | tableColumnMaxWidth(chatTable, 1, 40); // enough for 2 digits and a "?" |
345 | scrollTableDown(chatTable); |
346 | } |
347 | |
348 | static synchronized S saveLongString(S s) { |
349 | s = substring(s, 0, maxLongStringLength); |
350 | S id; |
351 | File f; |
352 | do { |
353 | id = randomID(10); |
354 | f = getProgramFile("long-strings/" + id); |
355 | } while (f.exists()); |
356 | |
357 | saveTextFile(f, s); |
358 | ret id; |
359 | } |
360 | |
361 | static O generators; |
362 | |
363 | static void makeGenerators(L<Gen> l, L<S> log) { |
364 | synchronized(main.class) { |
365 | if (!isSnippetID(generatorsID)) fail("No generators ID set"); |
366 | if (generators == null) |
367 | generators = hotwire(generatorsID); |
368 | } |
369 | new L l2; |
370 | call(generators, "makeGenerators", l2, log); |
371 | l.addAll((L) quickImport(l2)); |
372 | } |
Began life as a copy of #1003813
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: | #1003886 |
Snippet name: | Random Main (v8) |
Eternal ID of this version: | #1003886/1 |
Text MD5: | d3d0c7e391bfd4326bf51a6c9bc744a4 |
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-04 14:02:14 |
Source code size: | 9213 bytes / 372 lines |
Pitched / IR pitched: | No / No |
Views / Downloads: | 744 / 895 |
Referenced in: | [show references] |