Below is the file 'poetweb.py' from this revision. You can also download the file.

#!/usr/bin/env python

import datetime
import urlparse
import web
from poet3 import Poet3
from forms import haiku
import cPickle
import config

site_id_re = r'[A-Za-z\.]+'
# specific to livejournal-based sites
username_re = r'[A-Za-z0-9\_\-]+'

def newstyle_lj_address(site, username):
    if username.startswith('-') or username.startswith('_') or \
                username.endswith('-') or username.endswith('_'):
        base_uri = 'http://users.livejournal.com/%s/' % username
    else:
        base_uri = 'http://%s.livejournal.com/' % username
    return base_uri + 'data/rss'

def test_address(site, username):
    return "http://glamdring.local/~grahame/rss"

rss_lookup = {
    'livejournal.com' : newstyle_lj_address,
    'test' : test_address,
}

urls = (
    '/(' + site_id_re + ')/(' + username_re + ')' + '/haiku', 'view',
)

def gen_haiku(rss_uri):
    poet = Poet3(rss_uri)
    last_update = poet.storage.mtime('last_update')
    if datetime.datetime.now() - last_update > config.update_interval:
        web.debug("calling poet.update()")
        poet.update()
        # FIXME this doesn't work..
        poet.storage.open('last_update', 'w').write('')
    poet.build_state()
    web.debug("debug: poet.upwritten_seqs=%s" % (poet.upwritten_seqs))

    # if there has been no upwriting yet, then let's do some now.
    # we save the resulting combined tokens, so the code uses those
    # when adding new tokens to the corpus from now on
    if not poet.upwritten_seqs:
        to_upwrite = poet.symbol_state.chunkable()
        cPickle.dump(to_upwrite, poet.storage.open('upwritten.txt', 'w'))
        poet.upwrite(to_upwrite)

    for attempt in xrange(config.haiku_attempts):
        poem = haiku(poet)
        if poem != None:
            break

    return attempt, poem

class Renderer:
    def __init__(self):
        # any templates that can be inherited from, should be added to the list here
        self.templates = [ ('base.html', 'base') ]
        self._templates_loaded = False

        # these variables will be available to any template
        self.terms = {
                'context' : web.context, # fugly
                'dynamic_uri_path' : config.dynamic_uri_path,
                'dynamic_join' : lambda path: urlparse.urljoin(config.dynamic_uri_path, path),
                'static_uri_path' : config.static_uri_path,
                'static_join' : lambda path: urlparse.urljoin(config.static_uri_path, path),
                }

    def load_templates(self):
        if self._templates_loaded: return
        for template, mod_name in self.templates:
            web.render(template, None, True, mod_name)
        self._templates_loaded = True

    def render(self, template, **kwargs):
        self.load_templates()
        terms = self.terms.copy()
        terms.update(kwargs)
        web.render(template, terms)

renderer = Renderer()

class view:
    def GET(self, site, username):
        if not rss_lookup.has_key(site):
            ## fixme; this is a site we don't know about; let's return a friendly
            ## page suggesting the user might want to ask about adding it
            return web.notfound()
        uri = rss_lookup[site](site, username)
        attempts, haiku = gen_haiku(uri)
        renderer.render("haiku.html",
                        attempts=attempts,
                        haiku=(' '.join(t) for t in haiku),
                        page_title="your haiku",
                        username=username)

if __name__ == '__main__':
    web.internalerror = web.debugerror
    web.run(urls, web.reloader)