My final poetry-generating Python program is based on noun phrases, a markov chain, a recursive function, and a loose poetic structure. The vocabulary was sourced from three public domain source texts:
The Sailor’s Word Book, An Alphabetical Digest Of Nautical Terms, Including Some More Especially Military And Scientific, But Useful To Seamen; As Well As Archaisms Of Early Voyagers, Etc. By The Late Admiral W. H. Smyth (1867)
Emily Post’s Etiquette: In Society, In Business, In Politics And At Home (1922)
Fyodor Dostoevsky’s Notes From Underground (1864)
These texts make for interesting juxtapositions. For one thing, Post describes good manners for society, while Dostoevsky’s narrator is an outcast from society. The Sailor’s Word Book is a dictionary, but its definitions of sailor’s words are the most poetic of my three source texts—especially when taken out of context. The admiral who wrote this book in 1867 refers to ships as female (i.e. “her head”) and officers as male (i.e. “steersman”) which makes everything sound like an analogy. Likewise, Post and Dostoevsky use plenty of gendered pronouns. They also use proper nouns like “Mrs. Worldly” and “Simonov.” These texts refer to people—whether they are objects (such as a ship), individuals or society as a whole. As a result, when I feed these three texts into my program, they often seem to be talking about the same thing.
MARKOV CHAIN
My Markov object creates a dictionary of probabilities for transitioning from one word to the next, but I added some special features. Its “generate” function takes a starting word as an argument. If the starting word exists in the source text (Sailor’s Words + Dostoevsky), it will generate text based on its dictionary of probable transitions from that word to any other word.
def generate(self, start_word):
from random import choice
# If the start_word is in the text, generate a markov chain
if start_word in self.all_words:
current = choice([item for item in self.ngrams if item[0] == start_word])
output = list(current)
for i in range(self.max):
if current in self.ngrams:
possible_next = self.ngrams[current]
next = choice(possible_next)
output.append(next)
current = tuple(output[-self.n:])
else:
break
output_str = self.concatenate(output)
return output_str
else:
return ''
This allowed me to create a generate_question() function that starts a Markov chain with What When Where Why or How. The questions are part of my poetic structure.
next_line = underground.generate(random.choice(['What', 'How', 'Why', 'When', 'Where']))
return next_line
I felt it was important to feed sentences into the Markov chain, rather than lines. So I made an array of Strings and used TextBlob to parse the sentences which I fed into my Markov chain like this:
utext = []
for line in open('../texts/notesfromunderground.txt', 'r'):
utext.append(line + ' ')
utext_sentences = TextBlob(" ".join(utext).decode('ascii', errors='replace')).sentences
for sentence in utext_sentences:
underground.feed(sentence)
NOUN PHRASES
I used TextBlob to generate a list of noun phrases from Etiquette and Sailor’s Words.
Noun phrases are a very interesting way to parse a text. In fact, I could have stopped there and made a poem out of noun phrases like these:
dead men 's dust vulgar salutation long lewd lither loiterer moral elevation ensues float of a fishing-line conical tops of mountains
This is a series of noun phrases from Sailor’s Words:
barrel of small arms. barrel of the wheel. barrier of ice. ice olive oil. _yellow basilicon_ battening the hatches. securing battens of the hatches. beam of the anchor. synonymous land 's end bore before or abaft the beam. bend on the tack. berthing of the head. beset in ice. surrounded
This is a series of noun phrases from Etiquette:
politeness implies gentlemanly character social intercourse whole detail person shows respect time implies reciprocal respect gentlemanly character womanhood combined.
Originally, I created a Noun Phrase List object, but this was time consuming to generate every time, so I just saved them as a text file using the NPLC object I created in my nplc module.
npz = open("sailor_nouns.txt", "wb")
for i in post.noun_phrases:
npz.write(i.encode('utf-8', errors='replace').strip() + '\n')
npz.close()
I thought that these noun phrases could give my poems some rhythmic structure, especially if repeated. I sorted them by length:
nOne = random.choice(postnouns).strip()
nTwo = random.choice(postnouns).strip()
nThree = random.choice(sailornouns).strip()
print "nOne: " + nOne + ', nTwo: ' + nTwo + ', and Three: ' + nThree
# sort the noun phrases by length
if len(nOne) > len(nTwo):
nX = nOne
nOne = nTwo
nTwo = nX
if len(nTwo) > len(nThree):
nX = nTwo
nTwo = nThree
nThree = nX
I also created a function to prepend an appropriate preposition to a noun phrase
# a Noun Phrase based on whether it is plural and based on its starting letter.
def preposition(line):
first_letter = line[0]
for word in line.split():
tb = TextBlob(word)
for w, t in tb.tags:
if t == 'NN':
b = Word(word)
if word == str(b.singularize()):
# print word + " is probably singular like " + b.singularize()
if not_a_vowel(first_letter):
return random.choice(['The ', 'A ', '']) + line
else:
return random.choice(['The ', 'An ', '']) + line
elif word == str(b.pluralize()):
return random.choice(['The ', 'Some ', 'Many ', 'Of ', 'For all of the ', '']) + line
## if it gets to this point, we dont know if it is plural, so just figure out if 'a' or 'an'
if not_a_vowel(first_letter):
return random.choice(['A ', 'The ', '']) + line
else:
return random.choice(['An ', 'The ', '']) + line
That uses my not_a_vowel function:
for char_to_check in ["a", "e", "i", "o", "u"]:
if letter == char_to_check:
return False
return True
Which I originally wrote in order to approximate the number of syllables in a gibberish word. I did not deal with the complexities of “Y.”
RECURSION
The noun phrases, questions and markov chains help give my poems rhythm and space. I pick up the pace with a recursive function called redo_line:
## Sometimes, it also appends a random nounphrase
## rhyming_word is in a separate file, the rhymebot module.
def changeWord(word):
new_word = ''
# nounize(word)
if word.upper() in all_words:
new_word = rhyming_word(word, 1)
if new_word:
return new_word.lower()
else:
new_word = str(random.choice(syl_lookup[syl_bible[word.upper()]]))
# new_line = new_line + " " + new_word.lower()
else:
gibSyl = gib_syls(word)
new_word = str(random.choice(syl_lookup[gibSyl]))
# new_line = new_line + " " +
return new_word.lower() + " " + random.choice(postnouns + sailornouns).strip()
## This function iterates recursively through a line, three words at a time.
## It transforms the last word each time by calling the changeWord function.
def redo_line(line):
words = line.split()
if len(words) > 0:
w = words.pop()
y = changeWord(w)
if len(words) > 3: #crucial variable
new_line = ' '.join(words)
try:
print ' '.join(new_line.split()[-3:]) + " " +y.lower()
except:
print ' '.join(new_line.split()[-2:])
redo_line(new_line)
if len(words) == 3:
new_line = ' '.join(words)
try:
print ' '.join(new_line.split()[-2:]) + " " +y.lower()
except:
print ' '.join(new_line.split()[-1:])
redo_line(new_line)
if len(words) == 2:
new_line = ' '.join(words)
try:
print ' '.join(new_line.split()[-1:]) + " " +y.lower()
except:
print ' '.join(new_line.split()[-1:])
redo_line(new_line)
if len(words) == 1:
print words[0] + ' ' + y
print underground.generate(words[0])
print underground.generate(words[0])
print words[0] + w
return
I originally developed this function for my midterm project. Here, I use it towards the end of the poem to iterate through the poem’s three noun phrases and the poem’s opening line.
You can view the full code on my github and the two sample poems from my reading are excerpted below:
PHRASES & PRONUNCIATION
ABBLAST. young people How is enjoyment in this to be explained? An elderly guest phrases and pronunciation phrases and pronunciation pronunciation phrases and gillon and pronunciation phrases remodeled phrases and pronunciation Townsend's guest phrases and catamaran guest phrases liquefied guest amdahl's elderly simonette elderly As far as my personal opinion is concerned, to care only for well-being seems to me positively ill-bred. time by his sighed perfect little house that time by kerins at that time bly attention at that duhaime my attention at cooperate distracted my attention introduced Apollon distracted my ritalin that Apollon distractedly fact, that Apollon hausfeld in fact, that 'm chapter xxv thing, in fact, inhibit good thing, in aux telegraph pole a good thing, doron was a good er luncheon menu= was a wood was japonica It chides It would be to the interests of humanity and courtesy were it made indispensable. It was first devised for the service of mortars, and named after the inventor, Gomer, in the late wars. It The elderly guest The phrases and pronunciation The phrases and pronunciation
TRUE PURPOSE, SOCIAL WORLD
A true purpose A social world A senior officer 's signature A fore-and-aft sail, setting with a boom and gaff, in ships, synonymous with the spencers of brigs and schooners, and the spanker or driver of ships. The true purpose The social world The senior officer 's signature In size, as a ship's boat, smaller than the barge, and, like it, carvel-built. true purpose d��butante wears The senior officer 's signature true one--arising from lateral pressure and the effect of sea when close-hauled. purpose of firing signals, as the officer who commands her is particularly ordered to carry no cargo, ammunition, or implements of war. Why are we perverse and ask for something else? ask for something fu dining-room service. and ask for fudging perverse and ask reyer we perverse and hunk are we perverse duguid? are we britz are indri Why moondreamer? Why did I invite myself to this dinner yesterday? Why are you so cross? Why? A true purpose social world A senior officer 's signature
One thought on “The Phrases and Pronunciation”