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

430
LINES

< > BotCompany Repo | #1030204 // Gazelle.rocks Multi-Bot [working backup before "auto-bots"]

JavaX source code (Dynamic Module) [tags: use-pretranspiled] - run with: Stefan's OS

Uses 3098K of libraries. Click here for Pure Java version (20601L/117K).

1  
!7
2  
3  
set flag DynModule. // for transpilation
4  
5  
//set flag dm_evalJava_withModule_debug.
6  
//set flag veryQuickJava3_debug.
7  
8  
// store bot data per conversation
9  
concept Conversation {
10  
  S cookie;
11  
  S dataStruct;
12  
}
13  
14  
cmodule2 GazelleMultiBot > DynGazelleBot {
15  
  switchable int maxEvalResultLength = oneMegabyte_int();
16  
  switchable double evalTimeout = 30.0;
17  
  switchable long botProcessed; // timestamp of last post processed by bots
18  
  switchable int maxBotAnswerLength = 100000;
19  
  transient new L<Bot> bots;
20  
  Map<Long, GazellePost> allPosts = syncTreeMap();
21  
  transient Map<Long, O> loadedCodePosts = syncTreeMap();
22  
  transient new O couldntLoadCode;
23  
24  
  transient Lock codeLoadLock = lock();
25  
26  
  set flag NoNanoHTTPD.
27  
  !include #1029545 // API for Eleu
28  
29  
  class Bot {
30  
    S name;
31  
    
32  
    *() {}
33  
    *(S *name) {}
34  
    *(S *name, IVF1<GazellePost> *handlePost) {}
35  
    
36  
    swappable void handlePost(GazellePost post) {}
37  
    
38  
    GazelleBotCred cred() { ret GazelleBotCred(_user, _botToken, name); }
39  
    
40  
    void postReply(GazellePost post, S text, S type, S title default null) {
41  
      if (empty(text) && empty(title))
42  
        text = "<no output>";
43  
      gazelle_createPost(cred(), text, type, refs := post.id, +title);
44  
    }
45  
  }
46  
47  
  srecord CreatePost(L params) {}
48  
  
49  
  start {
50  
    dm_useLocalMechListCopies();
51  
    dbIndexing(Conversation, "cookie");
52  
    
53  
    grabLoop.handlePosts = posts -> {
54  
      dm_mediumRefreshTranspiler();
55  
      
56  
      grabLoop.handlePosts_base(posts);
57  
      
58  
      for (GazellePost post : posts)
59  
        setField(botProcessed := max(botProcessed, post.modified));
60  
    };
61  
    
62  
    // legacy conversion to sort allPosts
63  
    setField_noCheck(allPosts := asSyncTreeMap(allPosts));
64  
65  
    bots.add(new Bot("Math Bot", post -> {
66  
      if (post.creating) ret;
67  
      gazelle_mathBot1_handlePost_2(_user, _botToken, post);
68  
    }));
69  
    
70  
    bots.add(new Bot("Code Safety Checker") {
71  
      void handlePost(GazellePost post) {
72  
        if (post.creating) ret;
73  
        if (post.isJavaXCode())
74  
          gazelle_createPost(cred(), codeSafetyCheckResult(post.text), "Code Safety", refs := post.id);
75  
      }
76  
    });
77  
    
78  
    bots.add(new Bot("Safe Code Runner") {
79  
      void handlePost(GazellePost post) {
80  
        if (post.creating) ret;
81  
        if (post.isJavaXCode()) {
82  
          S code = post.text;
83  
          if (isCodeSafe(code)) {
84  
            code = prepareCode(code, post);
85  
            //S out = shorten(maxEvalResultLength, runCode(code));
86  
            S text, type = "Code Result", title = "";
87  
            try {
88  
              O result = evalCode(code, post);
89  
              if (result cast CreatePost) {
90  
                O[] params = toObjectArray(result.params);
91  
                text = (S) optPar text(params);
92  
                type = (S) optPar type(params, type);
93  
                title = (S) optPar title(params);
94  
              } else
95  
                text = str_shortenSyntheticAndStandardToString(result);
96  
            } catch print e {
97  
              text = getStackTrace(e);
98  
            }
99  
            if (empty(text) && empty(title))
100  
              text = "<no output>";
101  
            gazelle_createPost(cred(), text, type, +title, refs := post.id);
102  
          }
103  
        }
104  
      }
105  
    });
106  
    
107  
    bots.add(new Bot("Run Code On All Posts") {
108  
      void handlePost(GazellePost post) {
109  
        if (post.creating) ret;
110  
        if (eqic(post.type, "Instruction") && match("Please run this code on all posts", post.text)) {
111  
          long ref = gazelle_firstPostRef(post.id);
112  
          if (ref == 0) ret;
113  
          
114  
          S code = gazelle_text(ref);
115  
          if (!isCodeSafe(code)) ret;
116  
          
117  
          S code2 = "ret func(S post) { " + code + " };";
118  
          O function = evalCode(code2);
119  
          
120  
          new LS lines;
121  
          S out = shorten(maxEvalResultLength, runCode(code));
122  
          for (GazellePost post2 : cloneValues(allPosts)) {
123  
            lines.add("Post " + post2.id + " (" + quote(shorten(20, post2.text)) + "): " + shorten(80, runFunc(() -> callF(function, post2.text))));
124  
          }
125  
126  
          gazelle_createPost(cred(), lines(lines), "Code Result", refs := post.id);
127  
        }
128  
      }
129  
    });
130  
    
131  
    bots.add(new Bot("Mark identifiers safe") {
132  
      void handlePost(GazellePost post) {
133  
        if (post.creating) ret;
134  
        if (/*eqic(post.type, "Instruction")
135  
          &&*/ post.creator.isMaster
136  
          && match("Mark safe", post.text)) {
137  
          S text = getPost(first(post.postRefs)).text;
138  
          LS ids = tok_identifiersInOrder(regexpFirstGroupIC("Unknown identifiers: (.+)", text));
139  
          print("Marking safe: " + ids);
140  
          postReply(post, markSafe(ids), "Marked safe");
141  
        }
142  
      }
143  
    });
144  
    
145  
    bots.add(new Bot("Post Deleter") {
146  
      void handlePost(GazellePost post) {
147  
        if (post.creating) ret;
148  
        if (/*eqic(post.type, "Instruction")
149  
          &&*/ post.creator.isMaster
150  
          && match("Delete posts", post.text)) {
151  
            long ref = gazelle_firstPostRef(post.id);
152  
            if (ref == 0) ret;
153  
            S text = gazelle_text(ref);
154  
            L<Long> postIDs = allToLong(regexpAllFirstGroups(gazelle_deletePostRegexp(), text));
155  
            print("Deleting posts: " + postIDs);
156  
            if (nempty(postIDs)) {
157  
              Map result = gazelle_deletePosts(cred(), postIDs);
158  
              postReply(post, str(result), "Deletion result");
159  
            } else
160  
              postReply(post, "No mentioned posts found", "Deletion result");
161  
        }
162  
      }
163  
    });
164  
    
165  
    bots.add(new Bot("Detector Runner") {
166  
      void handlePost(GazellePost post) {
167  
        if (post.creating) ret;
168  
        ret unless eqic(post.type, "Instruction")
169  
          && match("Please run detector", post.text);
170  
          
171  
        try {
172  
          long detectorID = post.refWithTagOrFail("detector");
173  
          long posExamplesID = post.refWithTagOrFail("positive examples");
174  
          long negExamplesID = post.refWithTagOrFail("negative examples");
175  
        
176  
          S code = getPost(detectorID).text;
177  
          LS posExamples = tlft(getPost(posExamplesID).text);
178  
          LS negExamples = tlft(getPost(negExamplesID).text);
179  
          LPair<S, Bool> examples = trueFalseBPairs(posExamples, negExamples);
180  
          if (!isCodeSafe(code)) fail("Detector code not safe");
181  
  
182  
          IF1<S, O> detector = proxy IF1(evalCode(code));
183  
          new LS good;
184  
          new LS bad;
185  
          new Scorer scorer;
186  
          long time = sysNow();
187  
          evalWithTimeoutOrFail(evalTimeout, r {
188  
            for (Pair<S, Bool> example : examples) {
189  
              S result = runFunc(() -> detector.get(example.a));
190  
              bool ok = eq(result, str(example.b));
191  
              scorer.add(ok);
192  
              S line = (ok ? "OK" : example.b ? "False negative" : "False positive")
193  
                  + " (" + shorten(10, result) + "): " + example.a;
194  
              (ok ? good : bad).add(line);
195  
            }
196  
          });            
197  
          time = sysNow()-time;
198  
199  
          S text = "Detector code:\n\n" + indentx(code) + "\n\n"
200  
            + n2(good, "correct answer") + ", " + n2(bad, "bad answer") + ". Runtime: " + n2(time) + " ms\n\n"
201  
            + or2(trim(lines(concatLists(bad, ll(""), good))), "No errors");
202  
          S title = "Score for detector " + detectorID + ": " + scorer;
203  
          
204  
          gazelle_createPost(cred(), text, "Detector Score", +title,
205  
            refs := joinWithSpace(ll(post.id, detectorID, posExamplesID, negExamplesID)),
206  
            refTags := linesLL_rtrim("", "detector", "positive examples", "negative examples"));
207  
        } catch e {
208  
          postReply(post, getStackTrace(e), "Error");
209  
        }
210  
      }
211  
    });
212  
  }
213  
  
214  
  void handlePost(GazellePost post) {
215  
    allPosts.put(post.id, post);
216  
    change();
217  
    loadedCodePosts.remove(post.id);
218  
    if (post.modified > botProcessed) {
219  
      print("modified: " + post.modified + "/" + botProcessed);
220  
      for (Bot bot : bots) pcall {
221  
        bot.handlePost(post);
222  
      }
223  
    }
224  
  }
225  
226  
  // if post != null, store transpilation
227  
  O evalCode(S code, GazellePost post default null) {
228  
    printWithIndent("CODE> ", code);
229  
    veryQuickJava_transpiled.set(post != null ? "" : null); // request transpilation
230  
    try {
231  
      ret dm_javaEvalWithTimeout(evalTimeout, code);
232  
    } finally {
233  
      if (post != null) {
234  
        S java = veryQuickJava_transpiled!;
235  
        print("Transpilation for " + post.id + ": " + shorten(java));
236  
        saveTextFile(transpilationFile(post.id), nullOnEmpty(java));
237  
      }
238  
    }
239  
  }
240  
241  
  // assumes code is safety-checked
242  
  S runCode(S code) {
243  
    printWithIndent("CODE> ", code);
244  
    ret runFunc(() -> str_shortenSyntheticAndStandardToString(dm_javaEval(code)));
245  
  }
246  
247  
  // run IF0 with timeout, exception to string, convert result to string
248  
  S runFunc(IF0 f) {
249  
    ret str_shortenSyntheticAndStandardToString(evalWithTimeoutOrException(evalTimeout, func {
250  
      try {
251  
        ret str_shortenSyntheticAndStandardToString(f!);
252  
      } catch e {
253  
        ret getStackTrace(e);
254  
      }
255  
    }));
256  
  }
257  
  
258  
  L<GazellePost> repliesTo(GazellePost post) {
259  
    ret filter(values(allPosts), p -> contains(p.postRefs, post.id));
260  
  }
261  
  
262  
  L<GazellePost> repliesWithTag(GazellePost post, S tag) {
263  
    Pair<Long, S> pair = pair(post.id, upper(tag));
264  
    ret filter(repliesTo(post), p -> contains(mapPairsB toUpper(p.taggedRefs()), pair));
265  
  }
266  
  
267  
  GazellePost getPost(long id) {
268  
    ret allPosts.get(id);
269  
  }
270  
  
271  
  S getPostText(long id) {
272  
    ret getPost(id).text;
273  
  }
274  
  
275  
  Cl<GazellePost> getAllPosts() {
276  
    ret values(allPosts);
277  
  }
278  
279  
  CreatePost createPost(O... _) {
280  
    ret new CreatePost(asList(_));
281  
  }
282  
  
283  
  CodeSafetyChecker codeSafetyChecker() {
284  
    new CodeSafetyChecker checker;
285  
    checker.init();
286  
    checker.markSafe("getAllPosts");
287  
    ret checker;
288  
  }
289  
  
290  
  S codeSafetyCheckResult(S code) {
291  
    CodeSafetyChecker checker = codeSafetyChecker();
292  
    checker.checkCode(code);
293  
    ret checker.verbalCheckResult();
294  
  }
295  
  
296  
  bool isCodeSafe(S code) {
297  
    CodeSafetyChecker checker = codeSafetyChecker();
298  
    checker.checkCode(code);
299  
    ret checker.isSafe();
300  
  }
301  
302  
  S prepareCode(S code, GazellePost post) {
303  
    code = tok_addReturn(code);
304  
    
305  
    // define implicit vars and functions
306  
307  
    // post = text of parent post
308  
    if (containsJavaToken(code, "post")) {
309  
      long ref = gazelle_firstPostRef(post.id);
310  
      if (ref != 0)
311  
        code = "S post = " + quote(gazelle_text(ref)) + ";\n" + code;
312  
    }
313  
    
314  
    // post = text of grandparent post
315  
    if (containsJavaToken(code, "post2")) {
316  
      long ref = gazelle_firstPostRef(gazelle_firstPostRef(post.id));
317  
      if (ref != 0)
318  
        code = "S post2 = " + quote(gazelle_text(ref)) + ";\n" + code;
319  
    }
320  
    
321  
    if (containsJavaToken(code, "getAllPosts"))
322  
      code = [[
323  
        embedded Cl<GazellePost> getAllPosts() {
324  
          ret (Cl) quickImport(dm_call(dm_current_generic(), "getAllPosts"));
325  
        }
326  
      ]] + code;
327  
328  
    if (containsJavaToken(code, "createPost"))
329  
      code = [[
330  
        embedded O createPost(O... _) {
331  
          ret dm_call(dm_current_generic(), "createPost", _);
332  
        }
333  
      ]] + code;
334  
335  
    // optimize gazelle_text
336  
    if (containsJavaToken(code, "gazelle_text")) {
337  
      code = [[
338  
        embedded S gazelle_text(long id) {
339  
          ret (S) dm_call(dm_current_generic(), "getPostText", id);
340  
        }
341  
      ]] + code;
342  
    }
343  
    
344  
    ret code;
345  
  }
346  
347  
  O html(IWebRequest req) {
348  
    new Matches m;
349  
    
350  
    if (eqic(req.uri(), "/favicon.ico"))
351  
      ret serveFile(loadLibrary(#1400439), faviconMimeType());
352  
353  
    if (startsWith(req.uri(), "/chatBotReply/", m) && isInteger(m.rest())) {
354  
      req.noSpam();
355  
      long postID = parseLong(m.rest());
356  
      GazellePost post = getPost(postID);
357  
      if (post == null) ret serve404("Post " + postID + " not found");
358  
      O code = codeForPost(post);
359  
      if (code == couldntLoadCode) ret withHeader(serve500("Couldn't load code for post"));
360  
      S q = req.params().get("q"); // user input
361  
      S cookie = req.params().get("cookie");
362  
      if (empty(q)) ret withHeader(serveText(""));
363  
364  
      S answer;
365  
      if (implementsInterfaceShortNamed IF1(code)) // stateless bot
366  
        answer = evalWithTimeoutOrFail(evalTimeout, () -> strOrEmpty(callF(code, q)));
367  
      else {
368  
        print("Stateful bot. cookie: " + cookie);
369  
        if (empty(cookie)) ret withHeader(serve500("Need cookie for stateful bot"));
370  
        Conversation conv = uniq(Conversation, +cookie);
371  
        O instance = code;
372  
        if (instance == null) ret withHeader(serve500("No bot instance"));
373  
        print("Stateful bot instance: " + instance);
374  
        if (nempty(conv.dataStruct)) {
375  
          O data = unstructureInRealm(conv.dataStruct, instance); // hopefully this is safe
376  
          print("Unstructured: " + data);
377  
          copyAllThisDollarFields(instance, data); // probably not needed anymore
378  
          instance = data;
379  
        }
380  
        O _instance = instance;
381  
        answer = evalWithTimeoutOrFail(evalTimeout, () -> strOrEmpty(call(_instance, "answer", q)));
382  
        cset(conv, dataStruct := structure(instance));
383  
        print("Structured: " + conv.dataStruct);
384  
      }
385  
      
386  
      ret withHeader(serveJSON(litorderedmap(answer := shorten(maxBotAnswerLength, answer))));
387  
    }
388  
    
389  
    if (startsWith(req.uri(), "/transpilation/", m) && isInteger(m.rest())) {
390  
      long postID = parseLong(m.rest());
391  
      GazellePost post = getPost(postID);
392  
      if (post == null) ret serve404("Post " + postID + " not found");
393  
      S src = loadTextFile(transpilationFile(post.id));
394  
      if (empty(src))
395  
        src = "No transpilation found for post " + postID + "." + 
396  
          (!post.isJavaXCode() ? " Code is not a code post." : " Please try \"Touch post\" and wait a few seconds");
397  
      else pcall {
398  
        src = javaPrettyPrint(src);
399  
      }
400  
      ret serveText(src);
401  
    }
402  
    ret "Bot here";
403  
  }
404  
405  
  O codeForPost(GazellePost post) {
406  
    lock codeLoadLock;
407  
    O code = loadedCodePosts.get(post.id);
408  
    if (code == null) {
409  
      try {
410  
        S codeText = post.text;
411  
        if (!isCodeSafe(codeText)) fail("Code is not safe: " + codeSafetyCheckResult(codeText));
412  
        codeText = prepareCode(codeText, null);
413  
        code = evalCode(codeText, post);
414  
      } catch print e {
415  
        code = couldntLoadCode;
416  
      }
417  
      loadedCodePosts.put(post.id, code);
418  
    }
419  
    ret code;
420  
  }
421  
422  
  File transpilationFile(long postID) {
423  
    ret programFile("Post-Transpilations/" + postID + ".java");
424  
  }
425  
426  
  O withHeader(O response) {
427  
    call(response, 'addHeader, "Access-Control-Allow-Origin", "*");
428  
    ret response;
429  
  }
430  
}

Author comment

Began life as a copy of #1029997

download  show line numbers  debug dex  old transpilations   

Travelled to 4 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, vouqrxazstgt

No comments. add comment

Snippet ID: #1030204
Snippet name: Gazelle.rocks Multi-Bot [working backup before "auto-bots"]
Eternal ID of this version: #1030204/1
Text MD5: 7f540a9c6f19da7f179d540abc00fb62
Transpilation MD5: 4a0ea6a63483a9ccd943345bb5c6a6d9
Author: stefan
Category: javax / gazelle.rocks
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2020-11-16 14:28:06
Source code size: 14947 bytes / 430 lines
Pitched / IR pitched: No / No
Views / Downloads: 164 / 217
Referenced in: [show references]