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

268
LINES

< > BotCompany Repo | #1025775 // DynNLRulesBot

JavaX fragment (include) [tags: use-pretranspiled]

Uses 5614K of libraries. Click here for Pure Java version (20720L/155K).

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

Author comment

Began life as a copy of #1025348

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: #1025775
Snippet name: DynNLRulesBot
Eternal ID of this version: #1025775/5
Text MD5: 485469efc302f8276e2ff4739b2b964d
Transpilation MD5: 163fd6b258feb9476b38efaab7b0bc95
Author: stefan
Category: javax
Type: JavaX fragment (include)
Public (visible to everyone): Yes
Archived (hidden from active list): No
Created/modified: 2019-10-18 23:25:42
Source code size: 9086 bytes / 268 lines
Pitched / IR pitched: No / No
Views / Downloads: 158 / 485
Version history: 4 change(s)
Referenced in: [show references]