From 628b681940fdee4258dc3fb47e2ad2d8be5d6e98 Mon Sep 17 00:00:00 2001
From: Gijs
Date: Fri, 4 Jun 2021 10:02:30 +0200
Subject: [PATCH] First version of Grafting a Tree book generator.
---
Readme.md | 4 +-
__pycache__/trees.cpython-38.pyc | Bin 8515 -> 0 bytes
app.py | 48 +++++++++
growing_a_tree_sketch.py => graft_a_tree.py | 112 +++++++++-----------
test.py => pagedjs.py | 2 +-
requirements.txt | 3 +
run.sh | 3 +
templates/book.html | 53 +++++++++
templates/index.html | 97 +++++++++++++++++
9 files changed, 259 insertions(+), 63 deletions(-)
delete mode 100644 __pycache__/trees.cpython-38.pyc
create mode 100644 app.py
rename growing_a_tree_sketch.py => graft_a_tree.py (54%)
rename test.py => pagedjs.py (97%)
create mode 100644 run.sh
create mode 100644 templates/book.html
create mode 100644 templates/index.html
diff --git a/Readme.md b/Readme.md
index 977382d..ddda4ce 100644
--- a/Readme.md
+++ b/Readme.md
@@ -3,4 +3,6 @@
# Installation
The prototype uses pagedjs-cli to convert the HTML into PDF. In a terminal `cd` into the cloned folder and run:
-`npm install pagedjs-cli`
\ No newline at end of file
+`npm install pagedjs-cli`
+
+*to do* Add instructions on installation of NLTK data
\ No newline at end of file
diff --git a/__pycache__/trees.cpython-38.pyc b/__pycache__/trees.cpython-38.pyc
deleted file mode 100644
index fa384c55b30b5e53ab26530e743e4851e0eb2cf2..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001
literal 8515
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
diff --git a/app.py b/app.py
new file mode 100644
index 0000000..dcbe4e5
--- /dev/null
+++ b/app.py
@@ -0,0 +1,48 @@
+#!/usr/bin/env/ python
+from sys import stdout
+from flask import Flask, Response, render_template, request
+from pagedjs import make_pdf
+from graft_a_tree import graft_a_tree
+from io import StringIO
+import sys
+import textwrap
+
+BASEURL = ''
+MIN_GROW_YEARS = 0
+MAX_GROW_YEARS = 25
+
+app = Flask(__name__)
+
+def wrap (text, width):
+ return'\n'.join([(' \\\n').join(textwrap.wrap(line, width=width - 2)) for line in text.splitlines()])
+
+with open('graft_a_tree.py', 'r') as script:
+ source_code = script.read()
+
+@app.route('{}/'.format(BASEURL))
+def index():
+ return render_template('index.html', BASEURL=BASEURL)
+
+@app.route('{}/graft'.format(BASEURL), methods=['POST'])
+def graft():
+ years = max(MIN_GROW_YEARS, min(MAX_GROW_YEARS, int(request.form['years'])))
+
+ with StringIO() as script_stdout:
+ default_stdout = sys.stdout
+ sys.stdout = script_stdout
+ graft_a_tree(years)
+ content = script_stdout.getvalue()
+ sys.stdout = default_stdout
+
+ html = render_template('book.html', content=content, source_code=wrap(source_code, 100).replace(' ', ' ').replace('\n', '
'))
+ # print(html)
+ print('html rendered')
+ pdf = make_pdf(html)
+ print('made pdf')
+ r = Response(pdf, mimetype='application/pdf')
+
+ r.headers.extend({
+ 'Content-Disposition': 'attachment; filename="grafted-tree.pdf"'
+ })
+
+ return r
\ No newline at end of file
diff --git a/growing_a_tree_sketch.py b/graft_a_tree.py
similarity index 54%
rename from growing_a_tree_sketch.py
rename to graft_a_tree.py
index 2d598cb..15ab48f 100644
--- a/growing_a_tree_sketch.py
+++ b/graft_a_tree.py
@@ -37,20 +37,8 @@ from trees import trees
import os
import os.path
-from colored import fg, attr
-
-## Text attributes
-bold = attr(1)
-underlined = (4)
-reset = attr(0)
-
-## Text colors
-black = fg(0)
-spring_green = fg(48)
-light_gray = fg(7)
-sky_blue = fg(109)
-yellow = fg(3)
-
+import sys
+from io import StringIO
def choose_a_tree(dict):
collection = random.choice(list(trees.items()))
@@ -77,7 +65,7 @@ def bio(gardener):
bio = wikipedia.page(gardener)
short_bio = bio.summary
except:
- short_bio = "{}There is no English Wikipedia page about this person.{}".format(sky_blue, reset)
+ short_bio = "There is no English Wikipedia page about this person."
return short_bio
def bio_offline(gardener):
@@ -87,7 +75,7 @@ def bio_offline(gardener):
with open(filename, 'r') as h:
return h.read()
- return "{}There is no English Wikipedia page about this person.{}".format(sky_blue, reset)
+ return "There is no English Wikipedia page about this person."
"""
@@ -106,52 +94,54 @@ def grow_new_branch (bud):
# Turn nltk tree back into a sentence
def trim_tree (branches):
tree = " ".join([branch[0] for branch in branches])
+ # Remove spaces in html tags
+ tree = re.sub(r'\<\s*(\/?\w+)\s*\>', '<\\1>', tree)
return re.sub(r'\s[\.,:;\(\)]', '', tree)
-def show (state, length=1):
- os.system('clear')
- # Optionally vertically align here
- print(state)
- time.sleep(length)
-
-def grow (tree, generation = 1):
- branches = nltk.pos_tag(word_tokenize(tree))
- # Filter out nouns, pick one
- position, bud = random.choice([(position, bud[0]) for position, bud in enumerate(branches) if bud[1] == 'NN'])
-
- # Make new tree placeholder for the bud show we can show it in two states and then grow out
- next_tree = '{} {{}} {}'.format(trim_tree(branches[:max(0, position)]), trim_tree(branches[position+1:]))
- new_branch = grow_new_branch(bud)
-
- show(tree, 3 if generation == 1 else 1)
- # Mark the bud, underlined and orange
- show(next_tree.format("{}{}{}{}{}".format(bold, yellow, bud, reset, black)), 2)
- # Mark the new branch green
- show(next_tree.format("{}{}{}".format(spring_green, new_branch, black)), 2)
- show(next_tree.format("{}{}{}".format(fg(82), new_branch, black)), 1)
- show(next_tree.format("{}{}{}".format(fg(120), new_branch, black)), 1)
- show(next_tree.format("{}{}{}".format(fg(157), new_branch, black)), 1)
- show(next_tree.format("{}{}{}".format(fg(195), new_branch, black)), 1)
- # Let it grow again
-
- return next_tree.format(new_branch)
+def graft_a_tree (years = 3):
+ gardener, source, tree = choose_a_tree(trees)
+ short_bio = bio_offline(gardener)
+
+ print(
+ ''
+ + 'Using a quote by {}
'.format(gardener) \
+ + short_bio
+ + ''
+ )
+
+ year = 1
+
+ print('{}
'.format(tree))
+
+ while year <= years:
+ branches = nltk.pos_tag(word_tokenize(tree))
+ # Filter out nouns, pick one
+ position, bud = random.choice([(position, bud[0]) for position, bud in enumerate(branches) if bud[1] == 'NN'])
+
+ tree_with_bud = '{} {} {}'.format(
+ trim_tree(branches[:max(0, position)]),
+ bud.strip(),
+ trim_tree(branches[position+1:]))
+
+ print('{}
'.format(year, tree_with_bud))
+
+ # Make new tree placeholder for the bud show we can show it in two states and then grow out
+ grown_tree = '{} {} {}'.format(
+ trim_tree(branches[:max(0, position)]),
+ grow_new_branch(bud).strip(),
+ trim_tree(branches[position+1:]))
+ # Let it grow again
+
+ print('{}
'.format(year, grown_tree))
+
+ grown_tree = re.sub(r'\<\/?\w+\>', '', grown_tree)
+
+ if grown_tree == tree:
+ break
+ else:
+ tree = grown_tree
+
+ year += 1
if __name__ == '__main__':
- while True:
- gardener, source, tree = choose_a_tree(trees)
- short_bio = bio_offline(gardener)
-
- show(
- 'Using a quote by {}{}{}\n\n'.format(bold, gardener, reset) \
- + short_bio, 3
- )
-
- generation = 1
-
- while len(tree) < 1500:
- next_tree = grow(tree, generation)
- if next_tree == tree:
- break
- else:
- tree = next_tree
- generation += 1
\ No newline at end of file
+ graft_a_tree(3)
\ No newline at end of file
diff --git a/test.py b/pagedjs.py
similarity index 97%
rename from test.py
rename to pagedjs.py
index adadee5..6fb6774 100644
--- a/test.py
+++ b/pagedjs.py
@@ -65,7 +65,7 @@ def make_pdf (html, path_out=None, extra_scripts=[]):
shutil.copy(name_out, path_out)
return path_out
else:
- with open(name_out) as generated_pdf:
+ with open(name_out, 'rb') as generated_pdf:
return generated_pdf.read()
if __name__ == '__main__':
diff --git a/requirements.txt b/requirements.txt
index e69de29..5ac81d0 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -0,0 +1,3 @@
+nltk
+wikipedia
+flask
\ No newline at end of file
diff --git a/run.sh b/run.sh
new file mode 100644
index 0000000..a1709d8
--- /dev/null
+++ b/run.sh
@@ -0,0 +1,3 @@
+export FLASK_APP=app.py
+export FLASK_ENV=development
+flask run
\ No newline at end of file
diff --git a/templates/book.html b/templates/book.html
new file mode 100644
index 0000000..1d41a42
--- /dev/null
+++ b/templates/book.html
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+ Document
+
+
+
+ Grafted tree
+
+ {% autoescape false %}
+ {{ content }}
+
+ {{ source_code }}
+ {% endautoescape %}
+
+
\ No newline at end of file
diff --git a/templates/index.html b/templates/index.html
new file mode 100644
index 0000000..dd0f0de
--- /dev/null
+++ b/templates/index.html
@@ -0,0 +1,97 @@
+
+
+
+
+
+
+ Document
+
+
+
+ Grafting a tree
+
+
+
+
+ Grafting your tree. This might take a while.
+
+
+ Something went wrong.
+
+
+
+
\ No newline at end of file