From: Jonathan H. <vha...@ru...> - 2004-08-03 16:07:39
|
> This is not always desirable. In some situations you want the bot to > respond to anything that looks like a question (like a support channel > which is not monitored continuously) or to respond to words (or actions, > a feature missing from the original, as I recall). The "speak when spoken to" thing is more the way I feel a well-designed bot should behave, otherwise it's irritating. I mentioned the rule merely to illustrate the architecture, actually. It precludes things like a cronbot ("every ten minutes, tell me to check my laundry", something which is useful, and which I've coded up in Python/Twisted), because the processing and replying only gets done when the Source receives input to trigger it off. With Knab, there is a per-module configuration option called "addressed", which specifies whether the bot needs to be directly addressed for the module to receive the input. For example, the "See" module needs to receive all input, regardless of whether it is addressed to the bot or not, because it needs to keep track of everything everybody said (for "bot: seen Vhata?"). The point is, however, that something still needs to actually BE SAID for the bot to react - it can't suddenly do something out of the blue. (There is an example module which causes the bot to say "Hooray!" every time anybody mentions the word "boobies" in any context, which illustrates this... ;-) > The things should be configurable, not hardwired one way simply > because of the way you want it to operate. That's good design. It > also reduces the chance of somebody forking the project because you > refuse to add stuff they want. Sorry, I should have made it clear. It's not obstinacy on my part - the bot is configurable to do everything you said. Each module can be given the following configuration options: addressed = true ; means the module will only process queries ; directed to the bot public = true ; means the module only processes public queries (e.g. ; for karma) postprocessor = true ; means the module will even receive queries that ; another module has marked as "processed" (e.g. ; for a module that rot13s all output) In this way, and with the right setting of priorities, you can order your modules to respond to pretty much any sort of IRC situation. The only thing you cannot do is have the bot suddenly pipe up out of nowhere. > ><Vhata> Spinach: foo is also bing > [...] > ><Spinach> foo =has= nothing on bar; and =is= bar|bing > > There are times when you want "also" to give bar|bing and times when you > want it to behave as the original with "foo is bar and also bing." I > hacked the original so that a different keyword gave the | behaviour. I'd > suggest "alternatively." I have implemented this, I forgot to demonstrate it, sorry ;-) <Vhata> Spinach: foo is bar <Spinach> Vhata: okay <Vhata> Spinach: foo += ry manilou <Spinach> Vhata: sure thing <Vhata> Spinach: foo? <Spinach> foo is barry manilou The "=~ s/search/replace/" syntax also works, although I have implemented it so that you can use s///g to do ALL search-and-replacements, and use s///r to use real perl regular expressions to search and replace. If there is more than one alternative for a factoid that matches the search term, you need to specify which one you are working on, unless you gave the 'g' flag, of course, in which case it works on all of them: <Vhata> Spinach: foo is bar <Spinach> Vhata: okay <Vhata> Spinach: foo is also baz <Spinach> Vhata: gotcha <Vhata> Spinach: foo =~ s/b/x/ <Spinach> Vhata: Factoid has too many alternatives that match, I don't know which to alter! <Vhata> Spinach: foo /z/ =~ s/b/x/ <Spinach> Vhata: okay <Vhata> Spinach: foo =~ s/a/v/g <Spinach> Vhata: gotcha <Vhata> Spinach: literal foo <Spinach> foo =is= xvz|bvr > People enjoyed the insult server. It's no longer running, but the sources > are still available, and it's a simple matter then to run it from the > command line. Spell checking is also good I actually made an inline version of the insult server: <Vhata> Spinach: insult NSync <Spinach> NSync, thou weedy, ill-breeding mammet <Vhata> Spinach: insult me <Spinach> Vhata, thou loggerheaded, hell-hated giglet <Vhata> Spinach: insult yourself <Spinach> Vhata is nothing but a puking half-mouthful of off-color cat hair. This uses data stored locally, and doesn't need to contact a server running somewhere else (or even running locally). Spell checking is done using the Dict module, which contacts a dict.org dictionary server. > You can also speed up the excuses module a lot I never got the excuses module working in the old infobot, and never tried to get it working in Knab. But Knab is a rewrite from scratch using ideas from infobot - you can't just import infobot code, you need to make perl modules which conform to the Knab API... > IIRC, there are other modules that pollute global namespace in order > to have static data which would be better off if converted to use > private data. Knab, of course, uses perl's sorry attempt at object-oriented programming, so each module keeps its data in the local namespace, so this isn't a problem. The only global variables are $::dumper and $::conf, which are used by all modules to access the data dumper and the configuration file. ;-) > Or maybe you've already done that in your rewrite. If so, I'll teach > you how to suck eggs instead. :) I'm always willing to learn new skills ;-) Here's some skeleton code for a Knab module that responds to queries that look like "XXXX [number]", and returns that number-plus-one. sub Match { my $this = shift; my $match = pop @_; my (%query) = @_; return undef if($query{input} !~ m/^\s*XXXX\s+(\d+)\s*$/i); return 1 if($match); return ($1); } sub Process { my $this = shift; my (%query) = (@_); my ($num) = $this->Match(%query,0); push @{$query{responses}}, { action => 0, target => $where, reply => $query{who}.": ".($num+1) }; $query{processed} = 1; return %query; } Match() is called from the Processor with the query hash and the second argument set to true. If this second argument is true, then Match() only needs to return true or false, to say whether this module is "interested" in that query or not. Later on, you see, in the Process() function (which gets called if the module *is* interested in the query), Match() gets called again, and passed a false second argument. This means that it must return an array containing the relevant "bits" of the query. So, if the query were "exchange 10 USD into GBP", the array would contain [ 10, "USD", "GBP" ], easily accessible by the Process() function without the need for more fancy regex. This structure can be used to code up whatever query-response module you want, and shoved into the Knab's modules directory, and then the bot can be told to load that module (even if the bot is currently running at the time), and away it goes. You see why the modular, hot-pluggable, local-namespace, per-module-configuration approach is easier to code than infobot's monolithic "shove everything into one big loop" way of doing things? Thanks for the input, Cheers, -Jonathan |