Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Branch: master
Fetching contributors…

Cannot retrieve contributors at this time

268 lines (227 sloc) 8.003 kB
#!/usr/bin/python
# Copyright (c) 2002 Sean R. Lynch <seanl@chaosring.org>
#
# This file is part of PythonVerse.
#
# PythonVerse is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# PythonVerse is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with PythonVerse; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# -*-Python-*-
import sys, os, string, re, asyncore, codecs, traceback, whrandom, time
import OpenVerse, client
import webutil, microhal
#os.environ['WNHOME'] = '/usr/share/wordnet'
#os.environ['WNSEARCHDIR'] = '/usr/share/wordnet'
#from wordnet import *
#from wntools import *
languages = {'e': 'en',
'f': 'fr',
'i': 'it',
'g': 'de',
'p': 'pt',
's': 'es',
'j': 'ja'}
utf8_decode = codecs.lookup('UTF8')[1]
latin1_decode = codecs.lookup('ISO-8859-1')[1]
euc_jp_decode = codecs.lookup('japanese.euc-jp')[1]
unicode_re = re.compile('#([0-9a-fA-F]{4})')
def fromlatin1(s):
"""Translate a string from latin1 and convert "#xxxx" to unicode
characters"""
l = unicode_re.split(latin1_decode(s)[0])
for i in range(1, len(l), 2): l[i] = unichr(int(l[i], 16))
return u''.join(l)
def fromutf8(s): return utf8_decode(s)[0]
def fromeuc(s): return euc_jp_decode(s)[0]
def pipe(c, s):
"""Pass a string to a pipe and return the result."""
stdin, stdout = os.popen2(c)
stdin.write(s)
stdin.close()
output = stdout.read()
stdout.close()
return output
class HalClient(client.Client):
commands = [('([efigpsj])((2[efigpsj])+)\s+(.+)$',
'self.do_babel(m[1], m[2], m[4])', 0, 0),
('identify (\w+)$', 'self.do_identify(nick, m[1])', 0, 2),
('unidentify$', 'self.do_unidentify()', 2, 1),
('move (\d+) (\d+)$',
'self.do_move(int(m[1]), int(m[2]))', 1, 1),
('(jump|shiver)', 'self.server.effect(m[1])', 1, 1),
('avatar (\S+)$', 'self.server.set_avatar(m[1])', 1, 1),
('die', 'self.server.close()', 1, 1),
('google (.+)$', 'self.do_google(m[1])', 0, 0),
('groups (.+)$', 'self.do_google(m[1], 1)', 0, 0),
('image (.+)$', 'self.do_image(nick, m[1])', 0, 0),
('say (.+)', 'self.server.chat(m[1])', 1, 1),
('wx (\w+)$', 'webutil.metar(m[1]) or "No weather information available for " + m[1]', 0, 0),
('weather (\d\d\d\d\d)$', 'webutil.weather(m[1])', 0, 0),
('follow (\S+)$', 'self.do_follow(m[1])', 1, 1),
# Catch all semidirect statements
('.*', 'self.do_reply(m[0])', 0, 1),
# Send everything else to megahal without replying
('.*', 'self.do_random(m[0])', 0, 0)]
def __init__(self, nick):
self.image_time = 0
self.nick = nick
self.master = None
self.nicks = {}
self.pos = None
self.following = None
self.brain = microhal.load_brain('microhal.brn')
def save(self):
print >> sys.stderr, 'Saving brain...'
self.brain.save('microhal.brn')
print >> sys.stderr, 'Done.'
# commands.
def do_reply(self, sentence):
avg_logprob, reply = self.brain.reply(sentence)
self.brain.train(sentence)
return reply
def do_follow(self, nick):
self.following = nick
if self.nicks.has_key(nick):
x, y = self.nicks[nick]
self.do_move(x, y)
def do_identify(self, nick, arg):
if arg == 'Rumpelstiltskin':
self.master = nick
return 'Your wish is my command.'
else: return 'Nice try.'
def do_unidentify(self):
self.master = None
return 'Your wish is no longer my command'
def do_babel(self, lang1, langs, phrase):
lang1 = languages[lang1]
phrase = fromlatin1(phrase)
if lang1 == 'ja':
# Convert romaji to kana
phrase = fromeuc(pipe('./romkan.rb', phrase.encode('japanese.euc-jp', 'ignore')))
r = phrase.encode('UTF8')
for l in langs[1:].split('2'):
lang2 = languages[l]
try: r = webutil.translate(r, lang1, lang2)
except:
exception, info = sys.exc_info()[:2]
r = ' '.join(traceback.format_exception_only(exception, info))
traceback.print_exc()
break
else:
print r
lang1 = lang2
#r = fromeuc(pipe('kakasi -Ea -Ha -Ka -Ja', fromutf8(r).encode('japanese.euc-jp', 'replace')))
return fromutf8(r).encode('ISO-8859-1', 'replace')
def do_google(self, phrase, groups=0):
hits = webutil.google(phrase, groups)
if not hits: return "Sorry, couldn't find anything."
hit = whrandom.choice(hits)
text = hit[2]
title = hit[1]
return '%s: %s' % (title, text)
def do_image(self, nick, phrase):
now = time.time()
if now - self.image_time < 30:
self.server.privmsg(nick, 'Please wait at least %d seconds.' % (31-now+self.image_time))
return
images = webutil.google_image(phrase)
# Filter out banners.
images = filter(lambda im: float(im[1]) / float(im[2]) < 3 and im[1] >= 20 and im[2] >= 20, images)
if not images: return 'Nothing found.'
imageurl = whrandom.choice(images)[0]
filename = os.path.expanduser('~/.OpenVerse/images/google.gif')
webutil.image(imageurl, filename)
self.server.set_avatar('google')
self.image_time = time.time()
def do_random(self, phrase):
if whrandom.randint(1, 5) == 1:
p, r = self.brain.reply(phrase)
print p, r
# Only send it if it's 'interesting'
if p > 5: self.server.chat(r)
self.brain.train(phrase)
def do_move(self, x, y):
self.pos = (x, y)
self.server.move((x, y))
# Parse stuff
def parse(self, nick, s, private=0):
m = re.match('(\w+)[,:;]+\W*(.+)', s)
if m:
mynick = m.group(1)
s = m.group(2)
else:
mynick = None
if self.master:
if nick == self.master: secure = 2
else: secure = 0
else: secure = 1
if private: direct = 2
elif mynick and string.lower(mynick) == string.lower(self.nick):
direct = 1
else: direct = 0
for regex, cmd, priv, d in self.commands:
if priv > secure: continue
if d > direct: continue
m = re.match(regex, s)
if m:
match = (m.group(0),) + tuple(m.groups())
vars = {'self': self, 'nick': nick, 'm': match}
vars.update(m.groupdict())
try: r = eval(cmd, globals(), vars)
except SystemExit:
sys.exit()
except:
exception, info = sys.exc_info()[:2]
r = ' '.join(traceback.format_exception_only(exception, info))
traceback.print_exc()
break
else: r = None
if r:
if private: self.server.privmsg(nick, r)
else: self.server.chat(r)
# Client methods
#def new_avatar(self, nick, pos, image, noffset, boffset):
# self.nicks[nick] = pos
# r = self.brain.reply(nick)
# self.server.chat(r)
#
def del_avatar(self, nick):
"""Unbind from my master if s/he leaves."""
if nick == self.master: self.master = None
try: del self.nicks[nick]
except KeyError: pass
def move_avatar(self, nick, x, y, speed):
self.nicks[nick] = x, y
if self.following == nick: self.do_move(x, y)
def privmsg(self, nick, s):
if self.master and nick != self.master:
self.server.privmsg([self.master], "<%s> %s" % (nick, s))
self.parse(nick, s, private=1)
def chat(self, nick, s):
if nick == self.nick: return
self.parse(nick, s)
def push(self, x, y, speed):
if self.pos: self.server.move(self.pos)
def main(argv, env):
nick = argv[1]
host = argv[2]
port = int(argv[3])
avatar = argv[4]
c = HalClient(nick)
server = OpenVerse.ServerConnection(host, port, c, nick, avatar)
c.set_server(server)
try: asyncore.loop()
finally: c.save()
if __name__ == '__main__':
main(sys.argv, os.environ)
Jump to Line
Something went wrong with that request. Please try again.