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

318
LINES

< > BotCompany Repo | #1025818 // Katherine with synonyms [dev.]

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

Uses 6525K of libraries. Click here for Pure Java version (23565L/135K).

1  
!7
2  
3  
cmodule NLRulesBot extends DynTalkBot2<.ByServer> {
4  
  void init {
5  
    super.init();
6  
    makeByServer = () -> new ByServer;
7  
    useAGIBlueForDropPunctuation = false;
8  
    preprocessAtSelfToMyName = false;
9  
    dropPunctuation = false;
10  
    print("Total rules in all guilds: " + totalRuleCount());
11  
  }
12  
  
13  
  sclass Rule {
14  
    GlobalID globalID = aGlobalIDObj();
15  
    S text;
16  
    
17  
    *() {} *(S *text) {}
18  
  }
19  
  
20  
  S renderRule(Rule r) {
21  
    ret r == null ? null : "Rule " + r.globalID + ": " + r.text;
22  
  }
23  
24  
  class ByServer extends DynTalkBot2<NLRulesBot.ByServer>.ByServer {
25  
    new L<Rule> rules;
26  
    new Set<Long> priorityChannels; // where we always respond
27  
    bool enableMagicQuotes = true;
28  
    
29  
    new SimpleFactStore factStore;
30  
    new StringClustersWithIDs synonyms;
31  
    
32  
    delegate Cluster to StringClustersWithIDs.
33  
    
34  
    void _doneLoading { synonyms.onChange(r change); }
35  
    
36  
    synchronized S processSimplifiedLine(S s, O... _) {
37  
      try answer super.processSimplifiedLine(s, _);
38  
      
39  
      try answer factStore_cmds(factStore, s, authed(_));
40  
      try answer philosophyBotWithFactStore_discordAnswer(
41  
      ai_weightChangeBot_theory(), factStore, s, _);
42  
      
43  
      long channelID = longPar channelID(_);
44  
      
45  
      new Matches m;
46  
      S s2 = dropMyPrefixOrNull(s);
47  
      if (s2 != null) s = s2;
48  
      else if (!contains(priorityChannels, channelID)) null;
49  
      optPar Message msg;
50  
      Message.Attachment attachment = msg == null ? null : first(msg.getAttachments());
51  
      if (attachment != null) {
52  
        long guildID = idForByServer(this);
53  
        File file = prepareCacheProgramFile(guildID + "/" + attachment.getFileName());
54  
        print("Downloading attachment: " + file);
55  
        deleteFile(file);
56  
        if (!attachment.download(file)) ret "Couldn't download attachment";
57  
        LS lines = tlft(loadTextFile(file));
58  
        print("First line: " + first(lines));
59  
        if (!swic(first(lines), "rule ")) print("Ignoring attachment");
60  
        else {
61  
          new LPairS toImport; // (globalID, text)
62  
          for (S line : lines) {
63  
            LS l = regexpICFullMatch_groups("Rule ([a-z]+):(.*)$", line);
64  
            if (nempty(l))
65  
              toImport.add(listToPair(l));
66  
          }
67  
          S found = "Found " + nRules(toImport) + " in attachment";
68  
          
69  
          int oldCount = l(rules);
70  
          Map<GlobalID, Rule> existing = indexByField globalID(rules);
71  
          int updated = 0, added = 0;
72  
          for (PairS rule : toImport) {
73  
            GlobalID id = GlobalID(rule.a);
74  
            S text = trim(rule.b);
75  
            Rule r = existing.get(id);
76  
            if (r == null) {
77  
              r = new Rule(text);
78  
              r.globalID = id;
79  
              rules.add(r);
80  
              existing.put(id, r);
81  
              ++added;
82  
            } else if (neq(r.text, text)) {
83  
              r.text = text;
84  
              ++updated;
85  
            }
86  
          }
87  
          
88  
          if (added+updated > 0) change();
89  
          ret found + ". Had: " + oldCount + ". Added: " + added + ". Updated: " + updated + ". New count: " + l(rules);
90  
        }
91  
      }
92  
93  
      // duplicated patterns go here
94  
      if "on * say *|on * or * say *|on keyword * and * say *|on keyword * or * say *|on keyword * say *|on *, image-google X|on *, google X|when <*> comes online, say *|on bot keyword * and keyword *, say *" {
95  
        Rule r = firstWhereIC(rules, text := s);
96  
        if (r != null) ret "Rule exists: " + r.globalID;
97  
        rules.add(r = new Rule(s));
98  
        change();
99  
        ret "Rule added with ID " + r.globalID;
100  
      }
101  
      
102  
      if "rules"
103  
        ret or2(lines(map(r -> renderRule(r), rules)), "No rules defined yet");
104  
        
105  
      if "rules as file" {
106  
        uploadFileInChannel(channelID,
107  
          toUtf8(lines(map(r -> renderRule(r), rules))),
108  
          genericTextFileName(), null, null);
109  
        null;
110  
      }
111  
112  
      if "delete rule *|delete rule with id *" {
113  
        try answer checkAuth(_);
114  
        Rule r = firstWhere(rules, globalID := GlobalID($1));
115  
        if (r == null) ret "Rule " + $1 + " not found";
116  
        rules.remove(r);
117  
        change();
118  
        ret "Rule deleted, " + nRule(rules) + " remain";
119  
      }
120  
      
121  
      if "delete all rules" {
122  
        appendToTextFile(programFile("backups.txt"), guildStructure());
123  
        try answer checkAuth(_);
124  
        rules.clear();
125  
        change();
126  
        ret "All rules deleted";
127  
      }
128  
      
129  
      if "priority channel on" {
130  
        try answer checkAuth(_);
131  
        priorityChannels.add(channelID); change();
132  
        ret "OK";
133  
      }
134  
135  
      if "priority channel off" {
136  
        try answer checkAuth(_);
137  
        priorityChannels.remove(channelID); change();
138  
        ret "OK";
139  
      }
140  
      
141  
      if "disable magic quotes" {
142  
        try answer checkAuth(_);
143  
        enableMagicQuotes = false; change();
144  
        ret "OK";
145  
      }
146  
      
147  
      if "add synonym ...|add synonyms ..." {
148  
        LS tok = wordTokC(m.rest());
149  
        if (l(tok) <= 1) ret "Give me at least 2 synonyms, dude";
150  
        for (int i = 1; i < l(tok); i++)
151  
          synonyms.addPair(first(tok), tok.get(i));
152  
        ret "OK:" + synonyms.clusterWith(first(tok)).synonyms;
153  
      }
154  
      
155  
      if "delete synonym cluster *" {
156  
        Cluster c = synonyms.clusterWith($1);
157  
        if (c == null) ret "Cluster not found";
158  
        synonyms.remove(c);
159  
        ret "Synonym cluster deleted: " + c.synonyms;
160  
      }
161  
      
162  
      if "delete synonym * from cluster *" {
163  
        Cluster c = synonyms.clusterWith($1);
164  
        if (c == null) ret "Cluster not found";
165  
        if (!c.synonyms.remove($1)) ret format("Synonym * not found in " + c.synonyms);
166  
        change();
167  
        if (l(c.synonyms) <= 1) synonyms.remove(c);
168  
        ret "OK";
169  
      }
170  
      
171  
      if "list synonyms"
172  
        ret lines(map(synonyms.clusters, c -> join(" = ", c.synonyms)));
173  
174  
      if (eqic(s, "help"))
175  
        ret ltrim([[
176  
I execute simple English rules.
177  
178  
Stuff to say.
179  
@me `on "hello bot" say "who are you"`
180  
@me `on keyword "time" say "it is always time for a tea"`
181  
@me `on "what is X" google X`
182  
@me `on "show me X" image-google X`
183  
@me `on bot keyword "game" and keyword "sure" say "let's play tic tac toe"`
184  
@me `when @user comes online, say "hello friend"`
185  
@me `rules` / `rules as file` - list rules
186  
@me `delete rule abcdefghijkl` - delete rule with ID
187  
@me `priority channel on` - respond to every msg
188  
@me `priority channel off` - respond to msgs with my name only
189  
@me `masters` / `add master <username>` / `delete master <username>`
190  
@me `help` / `support` / `source code`
191  
@me `download` - download my brain for this guild
192  
193  
To fill me with rules, just upload the file you got from `rules as file` to the channel.
194  
195  
[Bot made by https://BotCompany.de]
196  
  ]]).replace("@me", atSelf());
197  
  
198  
      // find rule to execute
199  
      
200  
      new LinkedHashSet<S> outs;
201  
      
202  
      for (Rule r : rules) pcall {
203  
        // IMPORTANT: patterns are duplicated above
204  
        
205  
        if (match("on * say *", r.text, m)) {
206  
          S in = $1, out = $2;
207  
          if (match(in, s))
208  
            outs.add(rewrite(out, _));
209  
        }
210  
        
211  
        if (match("on * or * say *", r.text, m)) {
212  
          S in1 = $1, in2 = $2, out = $3;
213  
          if (match(in1, s) || match(in2, s))
214  
            outs.add(rewrite(out, _));
215  
        }
216  
        
217  
        if (match("on keyword * and * say *", r.text, m)) {
218  
          S in1 = $1, in2 = $2, out = $3;
219  
          if (find3(in1, s) && find3(in2, s))
220  
            outs.add(rewrite(out, _));
221  
        }
222  
        
223  
        if (match("on keyword * or * say *", r.text, m)) {
224  
          S in1 = $1, in2 = $2, out = $3;
225  
          if (find3(in1, s) || find3(in2, s))
226  
            outs.add(rewrite(out, _));
227  
        }
228  
        
229  
        if (match("on bot keyword * and keyword *, say *", r.text, m)) {
230  
          ISaid lastSaid = lastSaidInChannel.get(channelID);
231  
          if (lastSaid != null) {
232  
            S in1 = $1, in2 = $2, out = $3;
233  
            if (find3(in1, lastSaid.text) && find3(in2, s))
234  
              outs.add(rewrite(out, _));
235  
          }
236  
        }
237  
238  
        if (match("on keyword * say *", r.text, m)) {
239  
          S in = $1, out = $2;
240  
          if (find3(in, s))
241  
            outs.add(rewrite(out, _));
242  
        }
243  
        
244  
        if (match("on *, image-google X", r.text, m))
245  
          if (flexMatchIC(replaceWord($1, "X", "*"), s, m)) {
246  
            bool nsfw = discord_isNSFWChannel_gen(optPar channel(_));
247  
            print(+nsfw);
248  
            BufferedImage img = nsfw ? quickVisualize_nsfw($1) : quickVisualize($1);
249  
            if (img == null) ret "No image found, sorry!";
250  
            postImage(paramsToMap(_), uploadToImageServer(img, $1));
251  
          }
252  
          
253  
        if (match("on *, google X", r.text, m))
254  
          if (flexMatchIC(replaceWord($1, "X", "*"), s, m)) {
255  
            bool nsfw = discord_isNSFWChannel_gen(optPar channel(_));
256  
            print(+nsfw);
257  
            ret discord_google($1, results := 1, safeSearch := !nsfw);
258  
          }
259  
      }
260  
      
261  
      if "download" {
262  
        optPar Guild guild;
263  
        optPar MessageChannel channel;
264  
        ret serveGuildBackup(channel, guild,
265  
          structure_nullingInstancesOfClass(_getClass(module()), ByServer.this));
266  
      }
267  
      
268  
      if "stats"
269  
        ret "I have " + nRules(rules);
270  
      
271  
      try answer random(outs);
272  
      
273  
      if (enableMagicQuotes)
274  
        try answer answer_magicQuoteInput(s, useTranspiled := true);
275  
      null;
276  
    }
277  
    
278  
    S rewrite(S answer, O... _) {
279  
      if (containsIC(answer, "<user>")) {
280  
        optPar S name;
281  
        if (empty(name)) name = discord_optParUserName(_);
282  
        if (nempty(name))
283  
          answer = replaceIC(answer, "<user>", name);
284  
      }
285  
      ret answer;
286  
    }
287  
    
288  
    void onOnlineStatusChange(UserUpdateOnlineStatusEvent e) {
289  
      User user = e.getMember().getUser();
290  
      print("User status change: " + user + " " + e.getOldValue() + " -> " + e.getNewValue());
291  
      
292  
      // only react to user coming online
293  
      if (e.getOldValue() != OnlineStatus.OFFLINE) ret;
294  
      
295  
      long id = user.getIdLong();
296  
      
297  
      new LinkedHashSet<S> outs;
298  
      new Matches m;
299  
300  
      for (Rule r : rules) pcall {
301  
        // IMPORTANT: patterns are duplicated above
302  
        
303  
        if (match("when <*> comes online, say *", r.text, m)) {
304  
          long _id = parseLongOpt($1);
305  
          S out = $2;
306  
          if (id == _id)
307  
            outs.add(rewrite(out, name := user.getName()));
308  
        }
309  
      }
310  
      
311  
      postInChannel(preferredChannelID, random(outs));
312  
    }
313  
  }
314  
  
315  
  long totalRuleCount() {
316  
    ret intSumAsLong(map(syncCloneValues(dataByServer), bs -> l(bs.rules)));
317  
  }
318  
}

download  show line numbers  debug dex  old transpilations   

Travelled to 6 computer(s): bhatertpkbcr, mqqgnosmbjvj, pyentgdyhuwx, pzhvpgtvlbxg, tvejysmllsmz, vouqrxazstgt

No comments. add comment

Snippet ID: #1025818
Snippet name: Katherine with synonyms [dev.]
Eternal ID of this version: #1025818/3
Text MD5: e7bca3c95556867a8d70ae8c9c9d7ebd
Transpilation MD5: a296430ee9b4591816eee6e77ecb854c
Author: stefan
Category: javax
Type: JavaX source code (Dynamic Module)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-10-22 22:14:37
Source code size: 10914 bytes / 318 lines
Pitched / IR pitched: No / No
Views / Downloads: 191 / 301
Version history: 2 change(s)
Referenced in: [show references]