Computational Poetry

From Wikicliki
Jump to: navigation, search

Welcome to the notes for a Computational Poetry Class by Debbie Ding, held at The Substation on 3 November 2016!

A short link to this page is:

Download example files:


This class is designed for people who do not have any programming background but who have an interest in generative poetry and have an open mind to learning some simple methods for non-coders to create their own textual mashups. In this 2 hour class we will try to cover:

  • A Very Brief And Random History of Bots, AI, and Spam
  • Introduction to RiTa + p5.js
  • Setting up a local web server on your computer (Mac/Win)
  • Generating a simple haiku
  • Generating a duologue
  • Generating a prose mashup

and hopefully, some time for experimentation!

Equipment required:

  • a working laptop (most modern laptops should work)
  • wifi connection (which will be available at the substation)
  • example files (will be available for download at the class - I'll also have it available on thumbdrives)
  • and you! the human input!

Skills required:

  • being able to type on a laptop
  • being a human

I first decided to make this when someone (a designer, not a programmer) asked me how to create a text mashup and I was trying to explain to her how simple it was to do with open source libraries such as RiTA. In today's class, I'd like to share with you the most simple way to create a text mashup from available open source tools, which will hopefully spark your further adventures into other aspects of natural language processing...

A Very Very Brief History of Bots, AI, and Spam

A very brief and random assortment of tales from the history of bots. See also BOTSRIGHTS

Iwanttobelieve.png Furbyban.png


  • Turing test - See Alan Turing's 1950 paper, Could a computer think?. Turing shifts the question from "Can machines think?" to "Can machines do what we (as thinking entities) can do?"


Turing suggests a test inspired by a party game known as the "Imitation Game" in which a man and woman go into separate rooms and guests try to tell them apart by writing them a series of questions and reading only the typewritten answers which are set back. What happens if a machine takes the part of one of the humans in this game? Will the interrogator decide wrongly on who is the actual human when this game is played as it is when played between two different humans? These questions replace the original question of "Can machines think?


  • ELIZA - an early natural language processing program designed at MIT's Artificial Intelligence Lab which was able to convince humans that it understood us, although it had no framework for actually contextualising or understanding events or speech. Considered one of the first programs to have passed the Turing test.


ELIZA is based on very simple pattern recognition, based on a stimulus-response model. ELIZA also introduced the personal pronoun transformations common to ALICE and many other programs. "Tell me what you think about me" is transformed by the robot into "You want me to tell you what I think about you?" creating a simple illusion of understanding.

Weizenbaum tells us that he was shocked by the experience of releasing ELIZA (also known as "Doctor") to the nontechnical staff at the MIT AI Lab. Secretaries and nontechnical administrative staff thought the machine was a "real" therapist, and spent hours revealing their personal problems to the program. When Weizenbaum informed his secretary that he, of course, had access to the logs of all the conversations, she reacted with outrage at this invasion of her privacy. Weizenbaum was shocked by this and similar incidents to find that such a simple program could so easily deceive a naive user into revealing personal information.

What Weizenbaum found specifically revolting was that the Doctor's patients actually believed the robot really understood their problems. They believed the robot therapist could help them in a constructive way. His reaction might be best understood like that of a western physician's disapproval of herbal medicines, or an astronomer's disdain for astrology. Obviously ELIZA touched something deep in the human experience, but not what its author intended.



From "How Bots were Born from Spam": The first commercial spam message was sent in 1994—at least that’s the general consensus. Lawrence Canter and Margaret Siegel had a program written that would post a copy of an advertisement for their law firm’s green card lottery paperwork service to every Usenet news group — about 6,000 of them.

Because of the way the messages were posted, Usenet clients couldn’t filter out duplicate copies, and users saw a copy of the same message in every group. At the time, commercial use of internet resources was rare (it had only recently become legal) and access to Usenet was expensive. Users considered these commercial-seeming messages to be crass—not only did they take up their time, but they also cost them money.

In reaction to the “green card” incident, Arnt Gulbrandsen created the concept of a “cancelbot,” which compared the content of messages to a list of known “spam” messages and then, masquerading as the original sender, sent a special kind of message to “cancel” the original message, hiding and deleting it. Two months after the original spam postings, Canter and Siegel did it again — upon which the combined load of spam and cancel messages crashed many Usenet servers. Anti-spam measures, it seems, had themselves become spam.



Between their big round eyes, they have an infrared transmitter and receiver of the kind found in television remote control sensors. As well as parroting what they overhear, they can recite a small repertoire of one-liners, sleep, giggle when tickled, or groan when they are swung by their ears.
Because of its ability to repeat what it hears, Security Agency officials were worried "that people would take them home and they'd start talking classified", according to one anonymous Capitol Hill source. Photographic, video and audio recording equipment are all prohibited items for employees at the NSA. "This includes toys, such as 'Furbys,' with built-in recorders that repeat the audio with synthesized sound to mimic the original signal," the Furby Alert read.


  • Then the internet progressed... Smartphones, Apps, Email spam, chatbots, and Internet spam. Things go mobile, people use a lot of instant messaging and other new social media services.


  • IoT, IFTTT, Apple Siri, Microsoft Cortana, Amazon Alexa
2015: Alexa - People Are Complaining That Amazon Echo Is Responding to Ads on TV: In June, Amazon made its always-listening personal assistant Echo available to all. It’s a neat little device—basically, Siri in a cylinder—but not without its quirks.

According to one couple on Twitter, their Amazon Echo lit up on Thursday night, not in response to their voice, but a voice the device heard on TV. Amazon apparently ran a holiday ad featuring Echo during last night’s NBC broadcast of The Wiz Live!, and during the commercial, an actor asked an Amazon Echo to “Play my holiday playlist”—which the couple’s Amazon Echo did as well.

2013: Xbox One - Xbox One TV ads featuring voice commands are interacting with consoles Microsoft has trumpeted the voice control capability of the Xbox One as it allows you to interact extensively with the console. With voice commands, you can do many things such as recording a short clip of your gameplay and saving it to the cloud by saying “Xbox, record that”. Another of the rather nifty commands is the ability to turn on your console by saying “Xbox On”.

But it seems there is a bit of a snag with this feature - and a rather amusing one, at that - because when Microsoft airs a commercial that says ‘Xbox On’, the ad is apparently turning on consoles in some consumers' homes.

(..) these observations do seem to suggest that Microsoft may have to be mindful of the speech it uses in its commercials as it could have the unintended affect of turning on millions of consoles while trying to pitch the product to other consumers.

Voiceerror 1.png Voiceerror 2.png


From Inceptionism: Going Deeper into Neural Networks:


Rita and p5.js

"Designed to support the creation of new works of computational literature, the RiTA library provides tools for artists and writers working with natural language in programmable media. The library is designed to be simple while still enabling a range of powerful features, from grammar and Markov-based generation to text-mining, to feature-analysis (part-of-speech, phonemes, stresses, etc). All RiTa functions are heuristic and do not require training data, thus making the core library quite compact. RiTa can also be integrated with its own user-customisable lexicon, or with the WordNet database. RiTa is implemented in both Java and JavaScript, is free/libre and open-source, and runs in a number of popular programming environments including Android, Processing, Node, and p5.js." - from RiTA's website

RiTa reference: p5.js: p5.js reference:

Setting up

Step 1 - Set up local web server

Easiest way for Mac and Win is to use MAMP -


  • Download the installer from (300MB) - will have copy on thumbdrive in the class
  • Install it, unchecking ‘Install MAMP PRO in addition to MAMP’
  • By default it will install to C:\MAMP
  • Now start MAMP from the window start menu
  • Click on Start Servers
  • Click on ‘Open start page’
  • The page http://localhost/MAMP/ should now open up in your browser.
  • Default documents folder is usually C:\MAMP\htdocs

MAC - Fastest way is to use Python SimpleHTTPServer

  • All new Macs have Python installed. First open Terminal (Which can be found inside Applications > Utilities). Check which version of python you have by typing "python" into Terminal. Then navigate to the folder with your files inside it.
cd /path/to/project/folder 

Use Python's built-in http server:

# Python 2.x
python -m SimpleHTTPServer

# Python 3.x
python -m http.server

Files from that directory will be served up at localhost under port 8000, so you can view the files from that directory if you type this into the browser:


Step 2 - Unzip example files into folder

  • Download (Alternative Link)
  • Move the 'poetry' folder into your localhost directory
  • Go to the index page of the localhost url - which will probably look like this

RiTA Examples



In this example, it generates specific "parts of speech" (POS) and also looks for rhyming words from within RiTA's Lexicon. (Read more about RiLexicon)

var lexicon;
function setup() {
	lexicon = new RiLexicon;
	document.getElementById("clickMe").onclick = processRita;
function processRita(){

	var word1 = lexicon.randomWord('nns');
	var rhymes = lexicon.rhymes(word1);
	var r1length = rhymes.length;
	var word2 = rhymes[Math.floor(Math.random() * r1length)];

	var verb1 = lexicon.randomWord('vb');
	var rhymes2 = lexicon.rhymes(verb1);
	var r2length = rhymes2.length;
	var verb2 = rhymes2[Math.floor(Math.random() * r2length)];

	if (rhymes.length != 0 && rhymes2.length != 0) {
		var output = 'don\'t anyhow ' + verb1 + ' ' + verb1 + ', <br>or else ' + word1 + ' will  ' + verb2 + ' your ' + word2 ;
		var div = document.getElementById('pckSays');
		div.innerHTML = output;


How does this work? Everything is inside rita_dict.js, which looks like this:


  • POS: Penn Treebank Tags (with Examples)
  • Try changing the "nns" to something else. Currently "nns" refers to "noun, plural". What happens if you substitute it with 'nnp' (Noun, Proper, Singular) or 'nnps' (Noun, Proper, Plural)?
  • Try editing "saying". You'll see that currently saying starts with 'don\'t anyhow '. Replace this with 'please anyhow ' and see what happens.
  • The backslash you see before the apostrophe mark is an escape - it indicates that this symbol ' shouldn't be read as part of the code. Therefore the line will appear as "don't".



This is based closely off the main example from RiTA.

In the folder 'data', there is a file called poem.yaml. YAML is a human-readable data serialisation language. As you will see in the file, you begin with defining what the poem is composed of. Every poem consists of a <5-line>, then <7-line>, and then <5-line>. A <5-line> is then defined. Every <5-line> has got 5 syllables in it, because the rest of the YAML defines <1> as words with one syllable, <2> as words with two syllables, and so on so forth.


<start>: <5-line> % <7-line> % <5-line>
<5-line>: <1> <4> |<1> <3> <end-1> |<1> <1> <3> | <1> <2> <2> | <1> <2> <1> <end-1> | <1> <1> <2> <end-1> | <1> <1> <1> <2> | <1> <1> <1> <1> <end-1> | <2> <3> | <2> <2> <end-1> | <2> <1> <2> | <2> <1> <1> <end-1> | <3> <2> | <3> <1> <end-1> | <4> <end-1> | <5>
<7-line>: <1> <1> <5-line> | <2> <5-line> | <5-line> <1> <end-1> | <5-line> <2>
<1>: how | say | he | she | sad | go | soon | you | ever | no | school | work | cab | can | win | run | why | time | day | night | late | play | don't | sian | say
<2>: jialat | basket | talk cock | steady | ponteng | your head | yah lah | so toot | buay sai | kan cheong | aiyoh | liddat | kaypoh | kiam chye | too much | see you | so blur | almost | happy | jungle | flower | very the | my boss | very chio | goondu | taxi | can die | kena | champion | super | power | challenge | girlfriend | boyfriend | ah beng | ah lian | mahjong | so cheem | cannot | confirm | die die | big big | drama | sabo | monday | friday | weekend | summon | happy | tiger | why you | never | only | gone case | better | skali | solid | swee-swee | tahan | my boss | my friend | listen | durian | upsize | stupid
<3>: eh sai bo | kena sai | government | feasible | singapore | beautiful | vegetable | also can | very what one | wah lau eh | acherly | serious | hospital | alreddy | merlion | city hall | orchard road | jio you come | so like that | sabo king | damn sia lan | siao ting tong | spoil market | sure can one | wait long long | terbalik | tio 4D | go fly kite | don't act blur
<4>: agaration | cannot make it | simply bo chup | si mi tai chi | influencer | cannot tahan | kena tekan
<5>: yaya papaya | unbelievable | understand or not? | siam one corner first | steady bom pi pi | why you so like that
<end-1>: lor | lah | liao | sia | wor | one | hor | leh | huh


var grammar, lines, yaml;

function preload() {
  yaml = loadStrings('data/poem.yaml');

function setup() {
	lines = ["loading", "a new", "singlish haiku"];

  // whenever you press clickMe, a new poem is generated
	document.getElementById("clickMe").onclick = processRita;

  // generate a new poem when page first loads

function processRita(){
	grammar = new RiGrammar(yaml.join('\n'));
	var result = grammar.expand();
  var haiku = result.split("%");
  for (var i = 0; i < lines.length; i++)
    lines[i] = haiku[i];

		var line1 = document.getElementById('line_1');
		var line2 = document.getElementById('line_2');
		var line3 = document.getElementById('line_3');

		line1.innerHTML = lines[0];
		line2.innerHTML = lines[1];
		line3.innerHTML = lines[2];

Because there are no % signs in most normal poems, we use it as a symbol at which we split the poem up into different lines, and then push the content of each of these 3 lines into different divs on the webpage.



var duologue, markov_belle, markov_didi, data1, data2, linespacing, lines0, lines1, lines2, lines3, lines4, lines5 ;

function preload() {
  data1 = loadStrings('./texts/belle.txt');
  data2 = loadStrings('./texts/didi.txt');

function setup() {

  line0 = "";
  line1 = "";
  line2 = "";
  line3 = "";
  line4 = "";
  line5 = "";
  var loadingprose = document.getElementById('prose');
  loadingprose.innerHTML = lines;

  markov_belle = new RiMarkov(4);
  markov_didi = new RiMarkov(4);

  // load text into the model
  markov_belle.loadText(data1.join(' '));
  markov_didi.loadText(data2.join(' '));

  // whenever you press clickMe, a new poem is generated
	document.getElementById("clickMe").onclick = processRita;

  // generate a new poem when page first loads

function processRita(){

  line0 = markov_belle.generateSentences(1) ;
  line1 = markov_didi.generateSentences(1) ;
  line2 = markov_belle.generateSentences(3) ;
  line3 = markov_didi.generateSentences(5) ;
  line4 = markov_belle.generateSentences(1) ;
  line5 = markov_didi.generateSentences(1) ;

  var character1 = "<b>Belle:</b> ";
  var character2 = "<b>Didi:</b> ";

  var duologue = character1 + line0.join(' ') + "<br><br>" + character2 + line1.join(' ') + "<br><br>" + character1 + line2.join(' ') + "<br><br>" + character2 + line3.join(' ') + "<br><br>" + character1 + line4.join(' ') + "<br><br>" + character2 + line5.join(' ');

		var prose = document.getElementById('prose');

    // push text into div
		prose.innerHTML = duologue;




var lines;
var markov, data1, data2;

function preload() {
  data1 = loadStrings('./texts/fiftyshades.txt');
  data2 = loadStrings('./texts/potter.txt');

function setup() {

  lines = ["Loading..."];
  var loadingprose = document.getElementById('prose');
  loadingprose.innerHTML = lines;

  markov = new RiMarkov(4);

  // load text into the model
  markov.loadText(data1.join(' '));
  markov.loadText(data2.join(' '));

  // whenever you press clickMe, a new poem is generated
	document.getElementById("clickMe").onclick = processRita;

  // generate a new poem when page first loads

function processRita(){

    lines = markov.generateSentences(25);
    lines = lines.join(' ');
		var prose = document.getElementById('prose');

    // push text into div
		prose.innerHTML = lines;


Its your turn!

Possible sources for texts:

More Info

Why do you need to set up a "local web server" to run these files?

If you open up a HTML page in your browser, most browsers restrict how that HTML page can access other resources. For example: A script on can only perform AJAX requests for other files on, but a file on your computer (which we would refer to a a "local file") has no domain, and therefore cannot perform any AJAX requests.

To get around this, you can either change your browser's security settings for local files, but this is generally inadvisable, as you would not want pages and scripts from the internet to be able to open or access local files on your computer - that would pose a great security risk. So, we have to set up a local web server in order for us to be able to run these scripts today.

There are many ways to run a local web server and the method listed on top is likely to be the simplest, although another good way is to simply use Apache on Mac OS X.

Since Windows doesn't have Apache or Python pre-installed, you may have to install many dependencies to run a local server environment. There is WAMPSERVER and XXAMP. You'll find a lot of them have AMP in their names because they run Apache, MySQL, and PHP.

Mac: How to Enable Apache and install PHP

First, open the Terminal app and switch to the root user so you can run the commands in this post without any permission issues:

sudo su -

Enable Apache on Mac OS X

apachectl start

Verify it works by accessing it at localhost under port 8080




The default DocumentRoot for Mac OS X is /Library/WebServer/Documents. Whatever is inside this folder will appear when you type into localhost.

Usually whilst doing this, it is also useful to enable PHP for Apache together at the same time in case you might use PHP.

First make a backup of the default Apache configuration before you edit it.

cd /etc/apache2/
cp httpd.conf httpd.conf.bak

Then edit the Apache configuration.

vi httpd.conf

Scroll down and uncomment the following line (remove #) - press X over the letter and save with :wq Currently, the # is actually "commenting out" this line and stopping it from running, but you just need to delete the # to enable PHP for Apache.

LoadModule php5_module libexec/apache2/

Restart Apache:

apachectl restart

Verify PHP is enabled by creating a phpinfo page in your DocumentRoot. The default DocumentRoot for Mac OS X El Capitan is /Library/WebServer/Documents. Create a file named phpinfo.php and save this snippet inside it.


Other alternatives:

Glossary of Terms used in this page


  • HTTP - Hypertext Transfer Protocol. This is the protocol used by the World Wide Web. It defines how messages are formatted and transmitted, and what actions Web servers and browsers are supposed to take in response to commands.
  • HTML - Hyper Text Markup Language. This is a Markup language, not a programming language, which means it is a language used to define the content in a webpage.
  • Javascript - This is a programming language commonly used with HTML. It is used to create functionality in a webpage.
  • Python - This is another programming language. It was designed to be very readable even to humans, by using more english words (as opposed to using punctuation).
  • AJAX - Asynchronous JavaScript and XML - which means to use the XMLHttpRequest object to communicate with other server-side scripts. It is "Asynchronous" because it can make new requests to the server without requiring the page to be reloaded, and thus it is used to update the page based on events. This is really useful and is often used to make pages 'responsive', allowing you to design a page that will change accordingly as you resize the browser window.

For more definitions: