Please create a colorful handbook pdf with 20 logical creative questions for intensive speaking practice from file attached with using same vocabulary and answers I'm end.

Reading File
Browsing Directory

~/

Reading File
Browsing Directory

~/attachments

Searching the Web

intensive speaking practice creative questions vocabulary activities

Browsing Directory

~/attachments/033b3707-f819-4355-aa33-9f155f359d29

Running Command

python -c "import pdfplumber, os; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; pdf=pdfplumber.open(p); print('PAGES',len(pdf.pages)); [print('---PAGE',i+1,'---\n'+(page.extract_text() or '')) for i,page in enumerate(pdf.pages)]"

Running Command

python -c "from pypdf import PdfReader; import hashlib; paths=['/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf','/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1) (1).pdf']; [print(p, hashlib.sha256(open(p,'rb').read()).hexdigest(), len(PdfReader(p).pages)) for p in paths]"; mkdir -p "/tmp/workspace/speaking-handbook/assets" "/tmp/workspace/speaking-handbook/output" "/tmp/workspace/speaking-handbook/src" && python -c "import fitz; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; d=fitz.open(p); [d[i].get_pixmap(matrix=fitz.Matrix(1.5,1.5),alpha=False).save(f'/tmp/workspace/speaking-handbook/assets/source_page_{i+1}.png') for i in range(min(5,len(d)))]; print('rendered')"

Reading File
Running Command

python -c "from pypdf import PdfReader; from PIL import Image; import io, os; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; r=PdfReader(p); out='/tmp/workspace/speaking-handbook/assets'; os.makedirs(out,exist_ok=True); n=0; \nfor pi,page in enumerate(r.pages):\n for im in page.images:\n n+=1; open(f'{out}/p{pi+1}_{n}.{im.name.split(".")[-1]}','wb').write(im.data)\nprint('extracted',n)"

Running Command

python -c "from pypdf import PdfReader; import os; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; r=PdfReader(p); out='/tmp/workspace/speaking-handbook/assets'; os.makedirs(out,exist_ok=True); imgs=[(i,j,im) for i,page in enumerate(r.pages) for j,im in enumerate(page.images)]; [open(out+'/page_%02d_img_%02d.bin'%(i+1,j+1),'wb').write(im.data) for i,j,im in imgs]; print(len(imgs), [(i+1,j+1,im.name,len(im.data)) for i,j,im in imgs[:10]])"

Running Command

python -c "import os, shutil; src='/tmp/workspace/speaking-handbook/assets'; fs=[f for f in os.listdir(src) if f.endswith('.bin')]; [shutil.copyfile(src+'/'+f, src+'/'+f.replace('.bin','.jpg')) for f in fs]; print('jpgs',len(fs))"

Reading File
Running Command

python -c "from PIL import Image; import os; p='/tmp/workspace/speaking-handbook/assets/page_01_img_01.jpg'; im=Image.open(p); print(im.size,im.mode); print('mean',__import__('numpy').array(im).mean(axis=(0,1)))"; python -c "import importlib.util; print('easyocr',importlib.util.find_spec('easyocr')); print('pytesseract',importlib.util.find_spec('pytesseract')); print('keras_ocr',importlib.util.find_spec('keras_ocr'))"

Running Command

python -c "import importlib.util; mods=['cv2','paddleocr','rapidocr_onnxruntime','doctr','surya','transformers']; print({m:bool(importlib.util.find_spec(m)) for m in mods})"; command -v tesseract || true

Running Command

python -c "from PIL import Image; import os; d='/tmp/workspace/speaking-handbook/assets'; [Image.open(d+'/page_%02d_img_01.jpg'%i).resize((827,1170)).save(d+'/preview_%02d.png'%i) for i in range(1,26)]; print('done')"

Running Command

pip install --user easyocr -q

Reading File
Running Command

pip install --user --ignore-installed easyocr -q

Running Command

python -c "import easyocr, os; r=easyocr.Reader(['en'],gpu=False,verbose=False); d='/tmp/workspace/speaking-handbook/assets'; out='';\nfor i in range(1,26):\n p=d+'/page_%02d_img_01.jpg'%i; rs=r.readtext(p,detail=0,paragraph=True); out+='\\n\\n=== PAGE %d ===\\n'%i+'\\n'.join(rs)\nopen('/tmp/workspace/speaking-handbook/assets/ocr.txt','w').write(out); print(out[:5000])"

Running Command

printf '%s\n' "import easyocr, os" "r=easyocr.Reader(['en'],gpu=False,verbose=False)" "d='/tmp/workspace/speaking-handbook/assets'" "out=[]" "for i in range(1,26):" " rs=r.readtext(d+'/page_%02d_img_01.jpg'%i,detail=0,paragraph=True)" " out.append('=== PAGE %d ===\\n'%i+'\\n'.join(rs))" "open(d+'/ocr.txt','w').write('\\n\\n'.join(out))" > "/tmp/workspace/speaking-handbook/src/ocr.py" && python "/tmp/workspace/speaking-handbook/src/ocr.py"

Running Command

sed -i "s/r.readtext(d+'\/page_%02d_img_01.jpg'%i,detail=0,paragraph=True)/r.readtext(d+'\/preview_%02d.png'%i,detail=0,paragraph=True,canvas_size=1280,mag_ratio=1)/" "/tmp/workspace/speaking-handbook/src/ocr.py" && python "/tmp/workspace/speaking-handbook/src/ocr.py"

I’m sorry, but I could not complete and generate the handbook PDF within this run. The attached PDFs are image-only scans, so their vocabulary could not be extracted through normal text reading, and the OCR process did not finish before the processing limit.
I confirmed both uploads are identical 25-page PDFs. To produce an accurate 20-question colorful speaking handbook with the same vocabulary and an answer section at the end, please reply “continue” and I’ll resume by extracting the scanned vocabulary and create the downloadable PDF.

Continue

Browsing Directory

~/

Browsing Directory

~/speaking-handbook

Reading File
Running Command

printf '%s\n' "import easyocr" "r=easyocr.Reader(['en'],gpu=False,verbose=False,detector=True,recognizer=True)" "d='/tmp/workspace/speaking-handbook/assets'" "out=[]" "for i in range(1,26):" " print('page',i,flush=True)" " rs=r.readtext(d+'/preview_%02d.png'%i,detail=0,paragraph=True,canvas_size=640,mag_ratio=0.5,decoder='greedy')" " out.append('=== PAGE %d ===\\n'%i+'\\n'.join(rs))" "open(d+'/ocr.txt','w').write('\\n\\n'.join(out))" > "/tmp/workspace/speaking-handbook/src/ocr_fast.py" && python "/tmp/workspace/speaking-handbook/src/ocr_fast.py"

Running Command

python -c "import sys,site; print(sys.executable); print(sys.path); print(site.getusersitepackages())"; /opt/amazon/genesis1p-tools/venv/bin/python -c "import easyocr; print('easyocr available')"

Running Command

PYTHONPATH="/opt/amazon/genesis1p-tools/var/.local/lib/python3.12/site-packages" python -c "import easyocr; print(easyocr.__version__)"

Browsing Directory

.../python3.12/site-packages

Reading File
Browsing Directory

.../python3.12/site-packages

Running Command

python -c "import os; print([p for p,ds,fs in os.walk('/opt/amazon/genesis1p-tools') if p.endswith('site-packages') and ('easyocr' in ds or any('easyocr' in f for f in fs))][:10]); print([p for p,ds,fs in os.walk('/root/.local') if p.endswith('site-packages')][:10])"

Running Command

mkdir -p "/tmp/workspace/speaking-handbook/deps" && pip install --target "/tmp/workspace/speaking-handbook/deps" easyocr -q

general-purpose

Analyze the attached scanned PDF at /tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf and recover as much of the vocabulary content as possible. It is an image-only scan. Use any efficient available tools or visual capabilities. Return a concise numbered vocabulary list with categories or page references if possible. Do not create files.

Reading File
Browsing Directory

~/attachments/033b3707-f819-4355-aa33-9f155f359d29

Running Command

python -c "from pypdf import PdfReader; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; r=PdfReader(p); print(len(r.pages)); print([(x.mediabox.width,x.mediabox.height,len(x.extract_text() or '')) for x in r.pages])"

Running Command

python -c "import fitz,os; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; d=fitz.open(p); out='/tmp/workspace/pdfpages'; os.makedirs(out,exist_ok=True); [d[i].get_pixmap(matrix=fitz.Matrix(1.5,1.5),alpha=False).save(f'{out}/p{i+1:02}.png') for i in range(len(d))]; print('done')" && python -c "import importlib.util; print('ocr libs',[(x,importlib.util.find_spec(x) is not None) for x in ['pytesseract','easyocr','keras_ocr','cv2']])"

Running Command

python -c "import importlib.util; print([(x,importlib.util.find_spec(x) is not None) for x in ['pytesseract','easyocr','cv2','pdf2image','PIL']])"; which tesseract || true; python -c "from pypdf import PdfReader; p='/tmp/workspace/attachments/033b3707-f819-4355-aa33-9f155f359d29/DOC-20261019-WA0021 (1).pdf'; r=PdfReader(p); print([len(x.images) for x in r.pages]); import os; os.makedirs('/tmp/workspace/pdf_extract',exist_ok=True); [(open('/tmp/workspace/pdf_extract/p%02d_%d.%s'%(i+1,j,im.name.split('.')[-1]),'wb').write(im.data)) for i,page in enumerate(r.pages) for j,im in enumerate(page.images)]; print('extracted')"

Running Command

python -c "from PIL import Image; import os; fs=sorted(os.listdir('/tmp/workspace/pdf_extract')); print([(f,Image.open('/tmp/workspace/pdf_extract/'+f).size) for f in fs[:3]])"

Reading File
Running Command

python -c "from PIL import Image,ImageDraw; import os,math; fs=sorted(os.listdir('/tmp/workspace/pdf_extract')); thumbs=[] for f in fs: im=Image.open('/tmp/workspace/pdf_extract/'+f).convert('RGB'); im.thumbnail((250,354)); thumbs.append((f,im.copy())) out=Image.new('RGB',(1250,math.ceil(len(thumbs)/5)*390),'white'); d=ImageDraw.Draw(out) for n,(f,im) in enumerate(thumbs): x=n%5*250;y=n//5*390;out.paste(im,(x,y+20));d.text((x+5,y+2),f,fill='black') out.save('/tmp/workspace/contact.jpg')"

Running Command

python -m pip install -q rapidocr_onnxruntime

Running Command

python -c "from rapidocr_onnxruntime import RapidOCR; import os ocr=RapidOCR(); fs=sorted(os.listdir('/tmp/workspace/pdf_extract')); out=[] for n,f in enumerate(fs,1): r,_=ocr('/tmp/workspace/pdf_extract/'+f); tx='\n'.join(x[1] for x in (r or [])); open('/tmp/workspace/ocr.txt','a').write(f'\n\n===== PAGE {n} =====\n'+tx); print(n,len(r or []),len(tx))"

Reading File
Reading File
Running Command

python -c "s=open('/tmp/workspace/ocr.txt').read().split('===== PAGE ')[1:] for x in s: a=x.splitlines(); p=a[0].split()[0]; i=a.index('Vocabularycard'); word=a[i+1] if i+1<len(a) else '?'; j=a.index('ENGLISHMEANING'); k=a.index('RUSSIANTRANSLATION'); print(p,word,' — ',' '.join(a[j+1:k]))"

Running Command

python -c "s=open('/tmp/workspace/ocr.txt').read().split('===== PAGE 10 =====')[1].split('===== PAGE 11 =====')[0];print(s)"

Running Command

df -h /tmp/workspace; rm -rf "/tmp/workspace/speaking-handbook/deps"; mkdir -p "/tmp/workspace/speaking-handbook/output"; df -h /tmp/workspace

Writing File

~/speaking-handbook/src/create_handbook.py

from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak, Table, TableStyle, KeepTogether
from reportlab.lib.units import cm
from reportlab.pdfbase.pdfmetrics import stringWidth
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
import os

OUT = '/tmp/workspace/speaking-handbook/output/Politics_Consequences_Speaking_Handbook.pdf'

# Color palette
NAVY = colors.HexColor('#183153')
TEAL = colors.HexColor('#0F9D94')
ORANGE = colors.HexColor('#FF8A3D')
YELLOW = colors.HexColor('#FFD166')
PINK = colors.HexColor('#EF5DA8')
LAVENDER = colors.HexColor('#E9E3FF')
MINT = colors.HexColor('#DCF6EE')
CREAM = colors.HexColor('#FFF8E8')
INK = colors.HexColor('#263238')
GREY = colors.HexColor('#5B6870')
WHITE = colors.white

styles = getSampleStyleSheet()
styles.add(ParagraphStyle(name='CoverTitle', parent=styles['Title'], fontName='Helvetica-Bold', fontSize=31, leading=35, textColor=WHITE, alignment=TA_CENTER, spaceAfter=10))
styles.add(ParagraphStyle(name='CoverSub', parent=styles['BodyText'], fontName='Helvetica', fontSize=13, leading=18, textColor=WHITE, alignment=TA_CENTER))
styles.add(ParagraphStyle(name='SectionTitle', parent=styles['Heading1'], fontName='Helvetica-Bold', fontSize=22, leading=27, textColor=NAVY, spaceAfter=8))
styles.add(ParagraphStyle(name='QuestionTitle', parent=styles['Heading2'], fontName='Helvetica-Bold', fontSize=14.5, leading=18, textColor=NAVY, spaceAfter=4))
styles.add(ParagraphStyle(name='Body', parent=styles['BodyText'], fontName='Helvetica', fontSize=10.4, leading=14.2, textColor=INK))
styles.add(ParagraphStyle(name='Small', parent=styles['BodyText'], fontName='Helvetica', fontSize=8.7, leading=11.3, textColor=GREY))
styles.add(ParagraphStyle(name='Vocab', parent=styles['BodyText'], fontName='Helvetica-Bold', fontSize=9.4, leading=12, textColor=TEAL))
styles.add(ParagraphStyle(name='AnswerTitle', parent=styles['Heading2'], fontName='Helvetica-Bold', fontSize=12, leading=15, textColor=NAVY, spaceAfter=3))
styles.add(ParagraphStyle(name='Answer', parent=styles['BodyText'], fontName='Helvetica', fontSize=9.4, leading=12.7, textColor=INK))

vocab = [
('transition','a change from one situation or system to another'),('benefit','an advantage; to help'),('trigger','to cause something to begin'),('devastate','to damage very badly'),('bankrupt','unable to pay debts; to ruin financially'),('compound','to make a problem worse'),('revolutionize','to change completely in a new way'),('undermine','to weaken gradually'),('backfire','to have the opposite or unwanted result'),('overwhelm','to burden so strongly that coping is difficult'),
('voter turnout','the percentage of eligible people who vote'),('referendum','a direct public vote on one issue'),('poll','a survey of public opinion'),('consensus','general agreement in a group'),('scandal','a shocking event involving wrongdoing'),('coalition','a group joining to work together'),('vote','a choice in an election or decision'),('parliament','the national elected law-making body'),('public assembly','a citizens\' meeting about public matters'),('suffrage','the legal right to vote'),('vested interests','groups with a personal advantage in a decision'),('devolution of power','transfer of power to regional or local bodies'),('federal law','a law applying across a whole country'),('petition','a signed written request for action'),('proportional representation','seats reflect each party\'s share of votes')]

questions = [
('01', 'The First 100 Days', 'A city is making a transition from private cars to public transport. You are the mayor. Explain three benefits, predict one problem that could overwhelm residents, and give a practical solution.', ['transition','benefit','overwhelm']),
('02', 'The Hidden Cost', 'A factory closure may devastate a small town and bankrupt local shops. Give a logical chain of consequences. Which action should the council take first, and why?', ['devastate','bankrupt','trigger']),
('03', 'Helpful or Harmful?', 'A government app is designed to revolutionize voting. Describe how it works, then argue how it could backfire if some citizens cannot use it.', ['revolutionize','vote','backfire']),
('04', 'The Rumour Test', 'A poll says that 80% of people support a new law. What questions would you ask before trusting the result? Explain how a misleading poll could undermine public confidence.', ['poll','undermine','public confidence']),
('05', 'One Town, Two Voices', 'At a public assembly, residents disagree about building a sports centre. Speak as the chairperson: summarize both sides and lead them towards a consensus.', ['public assembly','consensus','vested interests']),
('06', 'The Emergency Referendum', 'After a major flood, a referendum is proposed to fund stronger flood defences. Should this urgent decision be made by referendum or parliament? Defend your view.', ['referendum','parliament','devastate']),
('07', 'A Coalition Deal', 'Two rival parties need to form a coalition. Invent three promises that each side must make. Which promise is most likely to cause the deal to backfire?', ['coalition','backfire','consensus']),
('08', 'The Right to Be Heard', 'A group of 16-year-olds launches a petition asking for suffrage at 16. Give a 90-second speech either supporting or opposing them. Address one counterargument.', ['petition','suffrage','vote']),
('09', 'Power Closer to Home', 'Your country is considering devolution of power to regions. Describe one decision that should be local, one that should remain federal law, and explain your logic.', ['devolution of power','federal law','benefit']),
('10', 'The Scandal Response', 'A political scandal has reduced voter turnout. You are an adviser. Create a three-step plan to rebuild trust without making unrealistic promises.', ['scandal','voter turnout','undermine']),
('11', 'When Interests Collide', 'A company offers jobs, but environmental groups oppose its new project. Identify the vested interests. How can the decision-makers avoid a policy that compounds the conflict?', ['vested interests','compound','benefit']),
('12', 'The Budget Puzzle', 'Parliament must choose between free university tuition and new hospitals. Explain your priorities, name who benefits, and say which group might feel overwhelmed by the decision.', ['parliament','benefit','overwhelm']),
('13', 'The Surprise Result', 'A referendum result is very close. One side demands another vote; the other side says the result is final. What process could create consensus while respecting the first vote?', ['referendum','vote','consensus']),
('14', 'A Campaign That Went Wrong', 'Invent a campaign designed to increase voter turnout. Explain how one message or action could trigger a backlash and make the campaign backfire.', ['voter turnout','trigger','backfire']),
('15', 'Rebuild or Rethink?', 'After an earthquake devastates a district, officials want to rebuild exactly as before. Propose a plan that could revolutionize the area instead. Mention one risk.', ['devastate','revolutionize','transition']),
('16', 'The Local Debate Show', 'Host a short debate on whether devolution of power makes democracy stronger. Ask two challenging questions: one for a local leader and one for a federal law-maker.', ['devolution of power','federal law','public assembly']),
('17', 'The Fair Seats Challenge', 'Explain proportional representation to a friend using a simple imaginary election. Then say whether it would improve consensus or make coalitions more difficult.', ['proportional representation','coalition','consensus']),
('18', 'Too Much, Too Fast', 'A new federal law changes taxes, schools, and healthcare in one month. Explain why citizens may feel overwhelmed. Which change should happen first in a gradual transition?', ['federal law','overwhelm','transition']),
('19', 'Fact, Feeling, or Fiction?', 'A scandal spreads online before anyone checks the facts. Describe how it could undermine parliament. What should journalists, citizens, and politicians do before reacting?', ['scandal','undermine','parliament']),
('20', 'Your People\'s Plan', 'Design a public assembly that ends with a petition to parliament. State the issue, the people invited, the final request, and how you will prevent vested interests from dominating.', ['public assembly','petition','vested interests'])]

answers = [
('01','Model answer: “The transition should begin with reliable buses and safe cycle lanes. The main benefit is cleaner air and lower travel costs. Some residents may feel overwhelmed because they need their cars for work, so the city should offer a gradual timetable and affordable travel passes.”'),
('02','Model answer: “The closure could trigger unemployment. Families would spend less, which could devastate local cafés and shops; some might become bankrupt. First, the council should support jobs and temporary income, because this stops the damage spreading.”'),
('03','Model answer: “The app could revolutionize voting by letting people vote securely from home. However, it may backfire if older people or rural citizens lack internet access. Paper voting and digital support centres should remain available.”'),
('04','Model answer: “I would ask who was surveyed, how many people answered, and how the questions were worded. A poll can undermine confidence when it looks scientific but excludes important groups.”'),
('05','Model answer: “At this public assembly, one side wants health and youth activities, while the other fears higher taxes. We need a consensus: a smaller centre, shared funding, and a public report on who benefits.”'),
('06','Model answer: “Parliament should make the immediate flood decision because the danger is urgent. A referendum is valuable for long-term funding choices, but it takes time while the damage may devastate more communities.”'),
('07','Model answer: “The coalition could agree on housing, transparent budgets, and a review after one year. A promise to cancel every tax may backfire because public services still need funding.”'),
('08','Model answer: “I support suffrage at 16 because young people are affected by education, work, and climate decisions. Critics say they lack experience, but people learn responsibility by using it. A vote should be supported by good civic education.”'),
('09','Model answer: “Transport routes should be decided locally because regions know their needs. National security should remain federal law because it requires one standard. Devolution of power can benefit citizens when responsibilities are clear.”'),
('10','Model answer: “First, publish the facts about the scandal. Second, create an independent investigation. Third, hold open meetings with candidates. This can improve voter turnout because people see that wrongdoing is not being hidden.”'),
('11','Model answer: “The company has an interest in profit and jobs; environmental groups have an interest in clean water and safety. Officials should require an independent impact study so that the policy does not compound mistrust.”'),
('12','Model answer: “I would fund hospitals first because urgent care benefits everyone. Students may feel disappointed, and some families may feel overwhelmed by tuition costs, so grants should protect those with low incomes.”'),
('13','Model answer: “The first vote should be respected, but a citizens’ panel could examine the narrow result and propose detailed options. A later vote on those options may create consensus without pretending the first vote did not matter.”'),
('14','Model answer: “The campaign could offer transport to polling stations and simple explanations of candidates. But insulting non-voters might trigger anger and backfire. Respectful messages are more likely to increase voter turnout.”'),
('15','Model answer: “Instead of rebuilding the same vulnerable streets, the city could revolutionize the district with flood-resistant homes, parks that absorb water, and local energy. The transition is costly, so residents must help plan it.”'),
('16','Model answer: “To the local leader: Which decisions can your region manage better than the capital? To the federal law-maker: How will you protect equal services across all regions? This debate tests whether devolution of power is fair.”'),
('17','Model answer: “With proportional representation, a party winning 30% of votes receives roughly 30% of seats. It may improve representation, but parties may need a coalition, which can make decisions slower even when consensus improves.”'),
('18','Model answer: “Citizens may feel overwhelmed because three major systems change at once. Healthcare should change first if services are at risk, followed by schools and taxes. A staged transition gives people time to understand each step.”'),
('19','Model answer: “An unverified scandal can undermine parliament because people may assume all representatives are dishonest. Journalists should verify evidence, citizens should check sources, and politicians should respond with facts rather than attacks.”'),
('20','Model answer: “Our public assembly will discuss safe routes to school. Parents, students, bus drivers, and disability groups will attend. We will send a petition to parliament for safer crossings. A neutral chair and published funding records will limit vested interests.”')]

def footer(canvas, doc):
    canvas.saveState()
    canvas.setStrokeColor(colors.HexColor('#D9E5EA')); canvas.setLineWidth(.6)
    canvas.line(1.5*cm, 1.35*cm, A4[0]-1.5*cm, 1.35*cm)
    canvas.setFont('Helvetica',8); canvas.setFillColor(GREY)
    canvas.drawString(1.5*cm, .9*cm, 'Politics & Consequences | Intensive Speaking Practice')
    canvas.drawRightString(A4[0]-1.5*cm, .9*cm, str(doc.page))
    canvas.restoreState()

def pill(text, bg, fg=WHITE):
    p = Paragraph('<b>'+text+'</b>', ParagraphStyle('pill', fontName='Helvetica', fontSize=8.6, leading=11, textColor=fg, alignment=TA_CENTER))
    t=Table([[p]], colWidths=[3.0*cm]); t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),0,bg),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4),('VALIGN',(0,0),(-1,-1),'MIDDLE')]))
    return t

def question_card(q, color):
    num,title,prompt,words=q
    header=Table([[Paragraph('SPEAKING MISSION '+num, ParagraphStyle('h',fontName='Helvetica-Bold',fontSize=9,textColor=WHITE,leading=11)), Paragraph('<b>Use all 3 target words</b>',ParagraphStyle('h2',fontName='Helvetica',fontSize=8.5,textColor=WHITE,leading=11,alignment=TA_CENTER))]], colWidths=[11.5*cm,5.0*cm])
    header.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),color),('LEFTPADDING',(0,0),(-1,-1),9),('RIGHTPADDING',(0,0),(-1,-1),9),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)]))
    vocabline=' • '.join(words)
    body=[Paragraph(title,styles['QuestionTitle']), Paragraph(prompt,styles['Body']), Spacer(1,5), Paragraph('TARGET VOCABULARY: '+vocabline,styles['Vocab']), Spacer(1,6), Paragraph('<b>Speaking frame:</b> In my view... / The main reason is... / However... / As a result...',styles['Small']), Spacer(1,7)]
    b=Table([[body]],colWidths=[16.5*cm]); b.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),CREAM),('BOX',(0,0),(-1,-1),0.75,colors.HexColor('#E6D6B6')),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),6)]))
    return KeepTogether([header,b,Spacer(1,13)])

story=[]
# Cover
story.append(Spacer(1,2.6*cm))
cover_content=[[Paragraph('POLITICS &<br/>CONSEQUENCES',styles['CoverTitle'])],[Paragraph('20 logical, creative speaking missions<br/>for intensive vocabulary practice',styles['CoverSub'])],[Spacer(1,0.55*cm)],[Paragraph('<b>Speak. Reason. Persuade.</b><br/>Use the target vocabulary naturally and support every opinion with a reason.',styles['CoverSub'])]]
ct=Table(cover_content,colWidths=[16.5*cm],rowHeights=[3.4*cm,1.3*cm,.5*cm,1.5*cm]); ct.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),NAVY),('BOX',(0,0),(-1,-1),0,NAVY),('VALIGN',(0,0),(-1,-1),'MIDDLE'),('LEFTPADDING',(0,0),(-1,-1),25),('RIGHTPADDING',(0,0),(-1,-1),25),('TOPPADDING',(0,0),(-1,-1),15),('BOTTOMPADDING',(0,0),(-1,-1),15)]))
story += [ct, Spacer(1,1.1*cm), Paragraph('Vocabulary focus: consequences, public decisions, elections, power, and participation.',ParagraphStyle('covernote',fontName='Helvetica-Bold',fontSize=11,leading=16,textColor=TEAL,alignment=TA_CENTER)), PageBreak()]
# How to
story += [Paragraph('How to use this handbook',styles['SectionTitle']), Paragraph('Each mission asks you to solve a problem, defend a position, or imagine a realistic public situation. Speak for 60-90 seconds. Use every target word accurately, then add at least one reason, example, or consequence.',styles['Body']), Spacer(1,10)]
tips=[['1. PLAN','Read the task. Choose a clear position.'],['2. SPEAK','Use the three target words and linking phrases.'],['3. EXTEND','Add an example, a counterargument, or a solution.'],['4. CHECK','Compare your ideas with the model answer at the end.']]
t=Table([[Paragraph('<b>'+a+'</b><br/>'+b,ParagraphStyle('tip',fontName='Helvetica',fontSize=10,leading=14,textColor=INK)) for a,b in tips[:2]],[Paragraph('<b>'+a+'</b><br/>'+b,ParagraphStyle('tip',fontName='Helvetica',fontSize=10,leading=14,textColor=INK)) for a,b in tips[2:]]],colWidths=[8.1*cm,8.1*cm],rowHeights=[2.1*cm,2.1*cm])
t.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),MINT),('BACKGROUND',(1,0),(1,0),LAVENDER),('BACKGROUND',(0,1),(0,1),CREAM),('BACKGROUND',(1,1),(1,1),colors.HexColor('#FFE5F1')),('BOX',(0,0),(-1,-1),.5,WHITE),('INNERGRID',(0,0),(-1,-1),5,WHITE),('LEFTPADDING',(0,0),(-1,-1),12),('RIGHTPADDING',(0,0),(-1,-1),12),('TOPPADDING',(0,0),(-1,-1),11),('BOTTOMPADDING',(0,0),(-1,-1),11)]))
story += [t,Spacer(1,18),Paragraph('Vocabulary bank',styles['SectionTitle'])]
rows=[]
for i in range(0,len(vocab),2):
    row=[]
    for term,definition in vocab[i:i+2]: row.append(Paragraph('<b>'+term+'</b><br/><font color="#5B6870">'+definition+'</font>',ParagraphStyle('bank',fontName='Helvetica',fontSize=8.5,leading=10.8,textColor=INK)))
    if len(row)==1: row.append('')
    rows.append(row)
bank=Table(rows,colWidths=[8.1*cm,8.1*cm])
bank.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),colors.HexColor('#F4F8FA')),('GRID',(0,0),(-1,-1),.4,colors.HexColor('#D7E1E6')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),8),('RIGHTPADDING',(0,0),(-1,-1),8),('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5)]))
story += [bank,PageBreak()]
# Missions
palette=[TEAL,PINK,ORANGE,colors.HexColor('#6C63B5')]
for i in range(0,20,2):
    story.append(Paragraph('Speaking missions '+str(i+1)+'-'+str(i+2),styles['SectionTitle']))
    story.append(Paragraph('Aim for 60-90 seconds per mission. Your answer can differ from the model if your reasoning is clear and the vocabulary is accurate.',styles['Small']))
    story.append(Spacer(1,7))
    story.append(question_card(questions[i],palette[(i//2)%4]))
    story.append(question_card(questions[i+1],palette[(i//2+1)%4]))
    if i<18: story.append(PageBreak())
story.append(PageBreak())
# Answers
story += [Paragraph('Model answers',styles['SectionTitle']), Paragraph('These are examples, not the only correct responses. Highlight useful phrases, then say the answer again in your own words.',styles['Body']), Spacer(1,9)]
for i,(num,ans) in enumerate(answers):
    block=Table([[Paragraph('MISSION '+num,ParagraphStyle('an',fontName='Helvetica-Bold',fontSize=8.5,textColor=WHITE,alignment=TA_CENTER)),Paragraph(ans,styles['Answer'])]], colWidths=[2.1*cm,14.1*cm])
    block.setStyle(TableStyle([('BACKGROUND',(0,0),(0,0),palette[i%4]),('BACKGROUND',(1,0),(1,0),colors.HexColor('#F6F9FA')),('BOX',(0,0),(-1,-1),.45,colors.HexColor('#D5E1E5')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)]))
    story.append(block); story.append(Spacer(1,6))

doc=SimpleDocTemplate(OUT,pagesize=A4,rightMargin=1.55*cm,leftMargin=1.55*cm,topMargin=1.45*cm,bottomMargin=1.8*cm,title='Politics & Consequences: Intensive Speaking Practice')
doc.build(story,onFirstPage=footer,onLaterPages=footer)
print(OUT)
Running Command

python "/tmp/workspace/speaking-handbook/src/create_handbook.py" && python -c "from pypdf import PdfReader; p='/tmp/workspace/speaking-handbook/output/Politics_Consequences_Speaking_Handbook.pdf'; r=PdfReader(p); print('pages',len(r.pages),'bytes',__import__('os').path.getsize(p)); print('last page text:',r.pages[-1].extract_text()[:700])"

Running Command

python -c "from pypdf import PdfReader; p='/tmp/workspace/speaking-handbook/output/Politics_Consequences_Speaking_Handbook.pdf'; r=PdfReader(p); text='\n'.join(x.extract_text() or '' for x in r.pages); checks=['SPEAKING MISSION 01','SPEAKING MISSION 20','MISSION 20','proportional representation','Model answers']; print({x:(x in text) for x in checks}); print('missions',sum(('SPEAKING MISSION %02d'%i) in text for i in range(1,21))); print('model_answers',sum(('MISSION\n %02d'%i) in text or ('MISSION\n '+str(i)) in text for i in range(1,21)))"

Browsing Directory

~/speaking-handbook/output

Created the colorful 14-page speaking-practice handbook with:
  • 20 logical, creative speaking missions
  • Source vocabulary from the uploaded PDF
  • Vocabulary bank with definitions
  • Speaking frames and target-word prompts
  • Model answers collected at the end

Politics Consequences Speaking Handbook

PDF Document · PDF

This is a shared conversation. Sign in to Orris to start your own chat.