#!/usr/bin/python # # Language Learner with No Name - LLNN # V 3.0 # (c)2001 M.J.London # # Based on Joel Rosdahl's irclib # TODO: # db for actions # parsing questions # correction # weighted words import os import string import whrandom import shelve from ircbot import SingleServerIRCBot from irclib import nm_to_n, irc_lower class LLNN(SingleServerIRCBot): def __init__(self, channel, nickname, server, port=6667): SingleServerIRCBot.__init__(self, [(server, port)], nickname, nickname) self.channel = channel self.passwd = "password" self.words = [ ["Hi",[1]], ["there",[]] ] self.canstart = [0] self.canend = [0,1] try: self.dbase = shelve.open("llnn.dat") except: print "Error opening file" try: self.words = self.dbase['words'] self.canstart = self.dbase['canstart'] self.canend = self.dbase['canend'] except: print "Error reading stored data" try: self.dbase.close() except: print "Error closing file" self.updates = 0 self.start() def get_version(self): return "LLNN Version 3.0 (c)2001 M.London" def on_welcome(self, c, e): c.join(self.channel) def on_privmsg(self, c, e): print "<" + nm_to_n(e.source()) + "> [MSG]", e.arguments()[0] self.addressed(c, nm_to_n(e.source()), nm_to_n(e.source()), e.arguments()[0]) def on_pubmsg(self, c, e): print "<" + nm_to_n(e.source()) + ">", e.arguments()[0] a = string.split(e.arguments()[0], ":", 1) if len(a) < 2: a = string.split(e.arguments()[0], ",", 1) if len(a) < 2: a = string.split(e.arguments()[0], " ", 1) if len(a) > 1 and irc_lower(a[0]) == irc_lower(self.connection.get_nickname()): self.addressed(c, e.target(), nm_to_n(e.source()), string.strip(a[1])) else: self.process_string(e.arguments()[0]) return def on_ctcp(self, c, e): if len(e.arguments()) > 1: if e.arguments()[0] == "ACTION": print "*" + nm_to_n(e.source()), e.arguments()[1] else: print "[CTCP", e.arguments()[0] + "]", "<" + nm_to_n(e.source()) + ">", e.arguments()[1] else: print "[CTCP", e.arguments()[0] + "]", "<" + nm_to_n(e.source()) + ">" if e.arguments()[0] == "PING": if len(e.arguments()) > 1: response = e.arguments()[1] else: response = "" c.ctcp_reply(nm_to_n(e.source()), e.arguments()[0]+' '+response) elif e.arguments()[0] == "VERSION": print "[CTCP Reply]", self.get_version() c.ctcp_reply(nm_to_n(e.source()), e.arguments()[0]+' '+self.get_version()); def on_invite(self, c, e): print nm_to_n(e.source()),"invited me to",e.arguments()[0] print "Joining",e.arguments()[0] c.join(e.arguments()[0]) def command(self, nick, cmdstring): c = self.connection cmd = string.split(cmdstring) print "Command from",nick,":",cmd if cmd[0] == "die": self.save_data() self.die() elif cmd[0] == "join" and len(cmd) > 1: print "Joining",cmd[1] if len(cmd) > 2: c.join(cmd[1], cmd[2]) else: c.join(cmd[1]) elif cmd[0] == "part" and len(cmd) > 1: print "Leaving",cmd[1] c.part(cmd[1]) def addressed(self, c, source, nick, message): # print "Addressed by",nick,":",message p = string.split(message) if p[0] == self.passwd and len(p) > 1: self.command(nick, string.join(p[1:])) elif irc_lower(p[0]) == "speak": c.privmsg(source, self.create_sentence()) elif irc_lower(p[0]) == "stats": out = "I know "+`len(self.words)`+" words, "+`len(self.canstart)`+" can start a sentence and "+`len(self.canend)`+" can end a sentence" c.privmsg(source, out) elif nm_to_n(source) == nick: self.process_string(message) c.privmsg(source, self.create_sentence()) else: self.process_string(message) c.privmsg(source, self.create_sentence()) def process_string(self, strings): # print "Processing :",strings sentences = string.splitfields(strings, '. ') for s in sentences: words = string.split(strings) # print "words :",words if self.is_word(words[0]) == -1: newword = [ words[0], [] ] # print "Initial word: Adding",newword self.words.append(newword) windex = self.is_word(words[0]) if windex not in self.canstart: # print "Add to canstart" self.canstart.append(windex) for w in words: windex = self.is_word(w) # print w,"is",windex if windex != -1: if words.index(w) < len(words)-1: # print "is",words.index(w),"<",len(words),"for",w nextindex = self.is_word(words[words.index(w)+1]) if nextindex != -1: if nextindex not in self.words[windex][1]: # print "Add reference to next word",self.words[nextindex][1],nextindex self.words[windex][1].append(nextindex) # print "Result :",self.words[nextindex] else: newword = [ words[words.index(w)+1], [] ] # print "New word :",newword self.words.append(newword) nextindex = self.is_word(words[words.index(w)+1]) if nextindex not in self.words[windex][1]: # print "Add reference to next word",self.words[nextindex][1],nextindex self.words[windex][1].append(nextindex) # print "Result :",self.words[nextindex] else: if windex not in self.canend: # print "Add",w,"at",windex,"to canend" self.canend.append(windex) else: newword = [w,[]] self.words.append(newword) if windex not in self.canend: # print "Add",w,"at",windex,"to canend" self.canend.append(windex) # print self.words, self.canstart, self.canend self.updates = self.updates + 1 if self.updates > 5: self.save_data() updates = 0 def is_word(self, word): for w in self.words: if word in w: return self.words.index(w) return -1 def create_sentence(self): word = whrandom.choice(self.canstart) sentence = self.words[word][0] while len(self.words[word][1]) > 0: if word in self.canend and whrandom.randint(0,5) > 4: break word = whrandom.choice(self.words[word][1]) sentence = sentence + ' ' + self.words[word][0] print "<" + self.connection.get_nickname() + ">",sentence return sentence def save_data(self): try: os.unlink("llnn.dat") except: print "Error removing old file" try: self.dbase = shelve.open("llnn.dat") except: print "Error opening file" try: self.dbase['words'] = self.words self.dbase['canstart'] = self.canstart self.dbase['canend'] = self.canend except: print "Error writing data" try: self.dbase.close() except: print "Error closing file" def main(): import sys if len(sys.argv) == 1: server = "the-junction.net" port = 6667 channel = "#18-30" nick = "llnn" else: if len(sys.argv) != 4: print "Usage: llnn server[:port] channel nick" sys.exit(1) s = string.split(sys.argv[1], ":", 1) server = s[0] if len(s) == 2: try: port = int(s[1]) except ValueError: print "Error: Bad port" sys.exit(1) else: port = 6667 channel = sys.argv[2] nick = sys.argv[3] llnnbot = LLNN(channel, nick, server, port) llnnbot.start() if __name__ == "__main__": main()