Create a handbook colorful pdf from the files attached, try to summarize the article in 70-80 words using vocabulary list from the other file attached.
~/
~/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b
python -c "from pypdf import PdfReader; from pathlib import Path; files=list(Path('/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b').glob('*.pdf')); [(print('\n###',f.name,'pages',len(PdfReader(str(f)).pages)), [print('---page',i+1,'---\n'+(p.extract_text() or '')[:6000]) for i,p in enumerate(PdfReader(str(f)).pages)]) for f in files]"
mkdir -p "/tmp/workspace/heartache-handbook/src" "/tmp/workspace/heartache-handbook/output"
~/heartache-handbook/src/create_handbook.py
from reportlab.lib.pagesizes import A4
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER, TA_LEFT
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
from reportlab.pdfbase.pdfmetrics import stringWidth
OUT = '/tmp/workspace/heartache-handbook/output/Can_Science_Cure_Our_Heartache_Handbook.pdf'
FONT = '/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf'
FONT_B = '/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf'
pdfmetrics.registerFont(TTFont('DejaVu', FONT))
pdfmetrics.registerFont(TTFont('DejaVu-Bold', FONT_B))
NAVY=HexColor('#183B5B'); TEAL=HexColor('#0E8B8C'); CORAL=HexColor('#F06C64'); GOLD=HexColor('#F7C948')
MINT=HexColor('#EAF8F2'); BLUSH=HexColor('#FFF0EF'); SKY=HexColor('#EBF5FF'); INK=HexColor('#263238'); PURPLE=HexColor('#7656A6')
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='TitleHand', fontName='DejaVu-Bold', fontSize=28, leading=33, textColor=colors.white, alignment=TA_CENTER, spaceAfter=8))
styles.add(ParagraphStyle(name='SubHand', fontName='DejaVu', fontSize=12, leading=17, textColor=colors.white, alignment=TA_CENTER))
styles.add(ParagraphStyle(name='H1Hand', fontName='DejaVu-Bold', fontSize=19, leading=23, textColor=NAVY, spaceBefore=4, spaceAfter=9))
styles.add(ParagraphStyle(name='H2Hand', fontName='DejaVu-Bold', fontSize=12, leading=15, textColor=TEAL, spaceAfter=4))
styles.add(ParagraphStyle(name='BodyHand', fontName='DejaVu', fontSize=9.5, leading=14, textColor=INK))
styles.add(ParagraphStyle(name='SmallHand', fontName='DejaVu', fontSize=8.2, leading=11, textColor=INK))
styles.add(ParagraphStyle(name='PhraseHand', fontName='DejaVu-Bold', fontSize=10, leading=13, textColor=NAVY))
styles.add(ParagraphStyle(name='CenterHand', fontName='DejaVu', fontSize=9.4, leading=14, textColor=INK, alignment=TA_CENTER))
summary = ('Fred and Doreen show that couples can <b>go through rough times</b> without giving up. '
'Although many people <b>cling on to the dream</b> of a perfect partner, dating algorithms only '
'<b>narrow down users’ choices</b>. Scientists who <b>carried out scans</b> found that parts of the brain '
'<b>lit up</b> when people saw loved ones. Lasting love may <b>boil down to our willingness</b> to see good, '
'respect independence, and <b>talk through the issue</b>.')
phrases = [
('go through rough times','to experience a difficult period','переживать трудные времена'),
('cling on to the dream','to keep hoping strongly despite difficulty','держаться за мечту'),
('step in and guide us','to become involved and give help or direction','вмешаться и направить'),
('narrow down users’ choices','to reduce many options to a smaller number','сузить выбор пользователей'),
('carry out scans','to perform medical or technical scans','проводить сканирование'),
('parts of the brain lit up','areas of the brain became active in a scan','участки мозга активировались'),
('boil down to our willingness','to have one main cause: whether we are ready','сводиться к нашей готовности'),
('talk through the issue','to discuss a problem carefully until understood or solved','подробно обсудить проблему'),
('account for','to explain or be the reason for something','объяснять; быть причиной'),
('agree on','to share the same opinion about a plan or decision','договориться о'),
('back up','to support someone; also, to save a copy','поддерживать; создавать копию'),
('call off','to cancel something planned','отменить'),
('cater for','to provide what a person or group needs','учитывать потребности'),
('come between','to cause trouble between people or separate them','встать между; испортить отношения'),
('draw on','to use knowledge, support, or experience','использовать; опираться на'),
('fend for','to take care of yourself without help','заботиться о себе самостоятельно'),
('get into','to become involved in or interested in something','ввязываться; заинтересоваться'),
('go through with','to do a planned, often difficult, action','довести до конца'),
('keep from','to prevent someone from doing something','удерживать от; не давать'),
('move on','to continue with life or a new stage','двигаться дальше'),
('read up on','to read a lot to learn about a topic','почитать, чтобы узнать больше'),
('see through','to support someone during a difficult time','помочь пережить трудный период'),
('split up','to end a romantic relationship; separate','расстаться; разделиться'),
]
def P(text, style='BodyHand'): return Paragraph(text, styles[style])
def header(canvas, doc):
canvas.saveState(); w,h=A4
canvas.setFillColor(NAVY); canvas.rect(0,h-15*mm,w,15*mm,fill=1,stroke=0)
canvas.setFont('DejaVu-Bold',8); canvas.setFillColor(colors.white)
canvas.drawString(16*mm,h-9.4*mm,'CAN SCIENCE CURE OUR HEARTACHE? | LANGUAGE HANDBOOK')
canvas.drawRightString(w-16*mm,h-9.4*mm,str(doc.page))
canvas.setFillColor(CORAL); canvas.circle(w-18*mm, h-8.7*mm, 2.3*mm, fill=1, stroke=0)
canvas.restoreState()
def cover(canvas, doc):
canvas.saveState(); w,h=A4
canvas.setFillColor(NAVY); canvas.rect(0,0,w,h,fill=1,stroke=0)
for x,y,r,c in [(20,265,25,TEAL),(180,265,34,CORAL),(190,65,28,GOLD),(25,45,19,PURPLE),(107,210,12,HexColor('#A8E6CF'))]:
canvas.setFillColor(c); canvas.circle(x*mm,y*mm,r*mm,fill=1,stroke=0)
canvas.setFillColor(colors.white); canvas.setFont('DejaVu-Bold',7); canvas.drawCentredString(w/2,242*mm,'READING • VOCABULARY • SPEAKING')
canvas.restoreState()
story=[]
# cover
story += [Spacer(1,73*mm), P('Can Science<br/>Cure Our Heartache?', 'TitleHand'), P('A colorful English-Russian handbook for reading, vocabulary, and discussion', 'SubHand'), Spacer(1,23*mm), P('<b>Based on the article by Daria Karpenko</b><br/>Focus: long-term relationships, online dating, brain research, and phrasal verbs','SubHand'), Spacer(1,51*mm), P('Prepared from the supplied article and vocabulary list','SubHand'), PageBreak()]
# summary
story += [P('1. Article in one minute','H1Hand'), P('<b>70-80 word summary</b> • 77 words • Vocabulary phrases are highlighted', 'H2Hand')]
summary_box=Table([[P(summary)]], colWidths=[178*mm]); summary_box.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),MINT),('BOX',(0,0),(-1,-1),1.2,TEAL),('LEFTPADDING',(0,0),(-1,-1),10),('RIGHTPADDING',(0,0),(-1,-1),10),('TOPPADDING',(0,0),(-1,-1),10),('BOTTOMPADDING',(0,0),(-1,-1),10)])); story += [summary_box, Spacer(1,9*mm)]
story += [P('Big ideas from the article','H2Hand')]
ideas=[['75 years together','Fred and Doreen value respect, separate interests, and patience in difficult periods.'],['Technology and dating','Free apps are unpredictable. Paid services use questionnaires and algorithms to reduce options.'],['What brain scans suggest','Love activates reward and desire systems, while fear is less active. This can make faults easier to ignore.'],['How love lasts','Research points to respect, communication, shared joy, independence, and friendships outside the relationship.']]
t=Table([[P('<b>'+a+'</b>','SmallHand'),P(b,'SmallHand')] for a,b in ideas],colWidths=[45*mm,133*mm],rowHeights=[20*mm]*4)
t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),SKY),('BACKGROUND',(0,1),(-1,1),BLUSH),('BACKGROUND',(0,2),(-1,2),MINT),('BACKGROUND',(0,3),(-1,3),HexColor('#FFF8DE')),('GRID',(0,0),(-1,-1),0.4,colors.white),('VALIGN',(0,0),(-1,-1),'MIDDLE'),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7)])); story += [t, Spacer(1,7*mm), P('<b>Think:</b> Can science explain attraction, or can it only offer clues about it?', 'BodyHand'), PageBreak()]
# vocab pages
for page, subset, intro in [(2,phrases[:8],'Key expressions taken directly from the article'),(3,phrases[8:16],'Grammar extension: useful phrasal verbs for relationships'),(4,phrases[16:],'Grammar extension: useful phrasal verbs for relationships')]:
story += [P(f'{page}. Vocabulary bank','H1Hand'), P(intro+' • English meaning + Russian translation', 'H2Hand')]
rows=[]
for eng,meaning,ru in subset:
rows.append([P(eng,'PhraseHand'),P(meaning+'<br/><font color="#7656A6">'+ru+'</font>','SmallHand')])
vt=Table(rows,colWidths=[64*mm,114*mm],repeatRows=0)
bg=[SKY,BLUSH,MINT,HexColor('#FFF8DE')]
style=[('VALIGN',(0,0),(-1,-1),'TOP'),('GRID',(0,0),(-1,-1),0.6,colors.white),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)]
for i in range(len(rows)): style.append(('BACKGROUND',(0,i),(-1,i),bg[i%4]))
vt.setStyle(TableStyle(style)); story += [vt]
if page==2: story += [Spacer(1,7*mm), P('<b>Memory tip:</b> Learn a phrase as one unit. For example: <i>talk through the issue</i>, not only <i>talk</i>.', 'BodyHand')]
story += [PageBreak()]
# practice
story += [P('5. Practise and speak','H1Hand'), P('Use the vocabulary to make the article your own.', 'H2Hand')]
activities=[
('<b>A. Complete the sentences</b><br/>1. Good partners ______ problems calmly instead of texting angry messages.<br/>2. Dating apps can ______ many profiles to a few likely matches.<br/>3. During stressful periods, friends can ______ us.<br/>4. If a small misunderstanding starts to ______ a couple, they should discuss it.'),
('<b>B. Discuss</b><br/>• Do you agree that love should be built rather than found?<br/>• Should algorithms <i>step in and guide us</i> when we choose a partner?<br/>• What helps people <i>go through rough times</i> in a relationship?<br/>• Is independence important for a long-lasting partnership? Why?'),
('<b>C. Write</b><br/>Write 4-5 sentences about a healthy relationship. Use at least three expressions from this handbook. Underline each expression.')]
for i,a in enumerate(activities):
box=Table([[P(a)]],colWidths=[178*mm]); box.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),[SKY,BLUSH,MINT][i]),('BOX',(0,0),(-1,-1),1, [TEAL,CORAL,PURPLE][i]),('LEFTPADDING',(0,0),(-1,-1),9),('RIGHTPADDING',(0,0),(-1,-1),9),('TOPPADDING',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),8)])); story += [box,Spacer(1,6*mm)]
story += [P('Answers to A: 1 <i>talk through</i> 2 <i>narrow down</i> 3 <i>see through</i> 4 <i>come between</i>.', 'SmallHand'), Spacer(1,5*mm), P('<b>Final thought:</b> The article suggests that research can offer useful insights, but people still have to choose how they care for, communicate with, and respect each other.', 'BodyHand')]
doc=SimpleDocTemplate(OUT,pagesize=A4,rightMargin=16*mm,leftMargin=16*mm,topMargin=22*mm,bottomMargin=15*mm,title='Can Science Cure Our Heartache? Handbook',author='Orris')
doc.build(story,onFirstPage=cover,onLaterPages=header)
print(OUT)
python "/tmp/workspace/heartache-handbook/src/create_handbook.py" && python -c "from pypdf import PdfReader; p='/tmp/workspace/heartache-handbook/output/Can_Science_Cure_Our_Heartache_Handbook.pdf'; r=PdfReader(p); print('pages=',len(r.pages)); print('size=',__import__('os').path.getsize(p)); print('last=',r.pages[-1].extract_text()[:800])"
/usr/share/fonts
/usr/share/fonts/google-noto-vf
/usr/share/fonts/google-droid-sans-fonts
~/heartache-handbook/src/create_handbook.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/heartache-handbook/src/create_handbook.py'
python "/tmp/workspace/heartache-handbook/src/create_handbook.py" && python -c "from pypdf import PdfReader; import os; p='/tmp/workspace/heartache-handbook/output/Can_Science_Cure_Our_Heartache_Handbook.pdf'; r=PdfReader(p); print('pages=',len(r.pages)); print('size=',os.path.getsize(p)); print(r.pages[-1].extract_text()[:600])"
~/heartache-handbook/output
Can Science Cure Our Heartache Handbook
PDF Document · PDF
Please create a handbook colorful pdf from attached files , please answer individually exercise 1 and 5 by using vocabulary from other file attached.
~/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b
python -c "from pypdf import PdfReader; paths=['/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b/DOC-20260922-WA0006 (1).pdf','/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b/DOC-20260922-WA0007 (1).pdf']; [(print('###',p),[print('PAGE',i+1, (pg.extract_text() or '')[:12000]) for i,pg in enumerate(PdfReader(p).pages)]) for p in paths]"
/tmp/workspace
~/heartache-handbook/src/create_exercise_handbook.py
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.pagesizes import A4
from reportlab.lib.styles import ParagraphStyle, getSampleStyleSheet
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
OUT = '/tmp/workspace/heartache-handbook/output/Exercise_1_and_5_Answers_Heartache_Handbook.pdf'
font = '/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf'
pdfmetrics.registerFont(TTFont('Noto', font))
pdfmetrics.registerFont(TTFont('NotoBold', font))
NAVY=HexColor('#173B5D'); TEAL=HexColor('#137C8B'); CORAL=HexColor('#E96564'); GOLD=HexColor('#F4C95D')
MINT=HexColor('#E7F7F1'); BLUSH=HexColor('#FFF0EF'); SKY=HexColor('#EAF5FF'); INK=HexColor('#263238'); WHITE=colors.white
styles=getSampleStyleSheet()
styles.add(ParagraphStyle(name='TitleX', fontName='NotoBold', fontSize=27, leading=32, textColor=WHITE, alignment=TA_CENTER))
styles.add(ParagraphStyle(name='SubX', fontName='Noto', fontSize=11, leading=15, textColor=WHITE, alignment=TA_CENTER))
styles.add(ParagraphStyle(name='H1X', fontName='NotoBold', fontSize=19, leading=24, textColor=NAVY, spaceBefore=4, spaceAfter=9))
styles.add(ParagraphStyle(name='H2X', fontName='NotoBold', fontSize=12, leading=15, textColor=TEAL, spaceAfter=4))
styles.add(ParagraphStyle(name='BodyX', fontName='Noto', fontSize=9.5, leading=14, textColor=INK))
styles.add(ParagraphStyle(name='SmallX', fontName='Noto', fontSize=8.2, leading=11, textColor=INK))
styles.add(ParagraphStyle(name='PhraseX', fontName='NotoBold', fontSize=10, leading=13, textColor=NAVY))
styles.add(ParagraphStyle(name='QX', fontName='NotoBold', fontSize=10.5, leading=14, textColor=NAVY))
styles.add(ParagraphStyle(name='CenterX', fontName='Noto', fontSize=9, leading=13, textColor=INK, alignment=TA_CENTER))
P=lambda t, s='BodyX': Paragraph(t, styles[s])
def card(title, question, answer, bg):
data=[[P(title,'H2X')],[P('<b>Question:</b> '+question,'QX')],[P('<b>Model answer:</b> '+answer,'BodyX')]]
t=Table(data,colWidths=[170*mm])
t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),0.8,TEAL),('LINEBELOW',(0,0),(-1,0),1.2,TEAL),('LEFTPADDING',(0,0),(-1,-1),7),('RIGHTPADDING',(0,0),(-1,-1),7),('TOPPADDING',(0,0),(-1,-1),6),('BOTTOMPADDING',(0,0),(-1,-1),6)]))
return KeepTogether([t,Spacer(1,7)])
def footer(canvas, doc):
canvas.saveState(); w,h=A4
canvas.setFillColor(NAVY); canvas.rect(0,0,w,12*mm,fill=1,stroke=0)
canvas.setFont('Noto',7.7); canvas.setFillColor(WHITE)
canvas.drawString(18*mm,4.4*mm,'CAN SCIENCE CURE OUR HEARTACHE? | INDIVIDUAL SPEAKING ANSWERS')
canvas.drawRightString(w-18*mm,4.4*mm,str(doc.page))
canvas.restoreState()
story=[]
# Cover
cover=Table([[P('Can Science Cure<br/>Our Heartache?','TitleX')],[P('A colorful handbook with individual model answers for Exercises 1 and 5','SubX')],[P('Vocabulary used: <b>go through rough times · step in and guide us · narrow down choices · talk through the issue · draw on · fend for · see through · move on</b>','SubX')]],colWidths=[170*mm])
cover.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),NAVY),('BOX',(0,0),(-1,-1),2,GOLD),('TOPPADDING',(0,0),(-1,-1),14),('BOTTOMPADDING',(0,0),(-1,-1),14),('LEFTPADDING',(0,0),(-1,-1),13),('RIGHTPADDING',(0,0),(-1,-1),13)]))
story += [Spacer(1,45*mm),cover,Spacer(1,16*mm),P('How to use this handbook','H1X'),P('These are <b>individual sample answers</b>. They are not the only correct ideas. Notice the highlighted phrases from the vocabulary list, then personalise the answers with your own experience.','BodyX'),Spacer(1,6),P('<b>Key:</b> The vocabulary phrases are shown in bold.','SmallX'),PageBreak()]
# Ex 1
story += [P('Exercise 1: Meeting a partner','H1X'),P('The exercise asks for your opinion about the photo and for other ways of meeting a partner. The answers below are written as one person speaking.','BodyX'),Spacer(1,7)]
story.append(card('1.1 What do you think of this method?', 'Look at the photo. What do you think of this method of meeting a partner?', 'I think a matchmaking event can be useful because it helps people <b>narrow down their choices</b> and meet others who are also looking for a relationship. It may feel less natural than meeting through friends, but it can <b>step in and guide us</b> when we are too busy or shy to meet new people. I would try it, but I would not expect an algorithm to make every decision for me.', SKY))
story.append(card('1.2 Other ways of meeting a partner', 'Make a list of other ways of meeting a partner. What are the pros and cons of each?', '<b>Through friends:</b> This feels safe because friends can introduce people with similar interests and <b>back us up</b>. However, it can be awkward if the relationship does not work out.<br/><br/><b>At a class, club, or hobby:</b> People can get to know each other gradually while doing something they enjoy. The disadvantage is that it may take a long time to discover whether the other person is interested.<br/><br/><b>Online dating:</b> Apps can quickly <b>narrow down users’ choices</b>, but profiles may not show a person’s real character. A first meeting can also depend on mood and circumstances.<br/><br/><b>At work or university:</b> You already have things to talk about, but a breakup could <b>come between</b> people who must still see each other every day.', MINT))
story += [PageBreak()]
# Ex 5
story += [P('Exercise 5: Long relationships','H1X'),P('The article suggests that respect, communication, independence, and support matter in long-term partnerships. Here are individual responses that use the supplied phrasal verbs naturally.','BodyX'),Spacer(1,7)]
story.append(card('5.1 What may be missing?', 'Do you think there is anything missing from the list of why couples stay together? Why do you think couples without kids are more likely to stay together?', 'Yes. I think trust, shared values, and the ability to apologise are missing. Couples need to <b>talk through the issue</b> when they disagree instead of letting a small problem <b>come between</b> them. Couples without children may have more time, money, and energy for each other, but children do not automatically damage a relationship. Parents can <b>draw on</b> family and friends for support and still make time to connect.', BLUSH))
story.append(card('5.2 A long relationship', 'Do you know anyone who has had a long relationship? What do you think is their secret?', 'Yes, I know a couple who have been together for many years. Their secret seems to be respect and patience. They have learned to <b>go through rough times</b> without blaming each other. When they have a disagreement, they sit down and <b>talk through the issue</b> calmly. They also keep their own friends and interests, so neither partner expects the other person to provide all their happiness.', MINT))
story.append(card('5.3 Do you agree with the conclusion?', 'How far do you agree with the author’s conclusion? What might be a different view of love and marriage?', 'I partly agree. Science can explain some feelings and patterns, but love does not completely <b>boil down to our willingness</b> or to brain activity. Research can help people understand relationships, but it cannot tell everyone whom to marry. A different view is that love is something people build through daily choices, kindness, and commitment. If a relationship ends, people should support each other and eventually <b>move on</b> respectfully.', SKY))
story.append(card('5.4 What can governments do?', 'What can governments do to help people in their relationships? What policies may damage relationships?', 'Governments can <b>step in and guide us</b> by funding affordable counselling, parenting courses, childcare, and mental-health support. They can also make work policies more flexible, so couples have time to care for children and <b>fend for themselves</b> financially. Policies that create unemployment, unaffordable housing, or very long working hours may place pressure on families. During difficult periods, good public support can help couples <b>see each other through</b> stress.', BLUSH))
story += [PageBreak()]
# vocabulary
story += [P('Vocabulary used in the answers','H1X'),P('Use these phrases when you give your own response.','BodyX'),Spacer(1,6)]
vocab=[('go through rough times','experience a difficult period'),('step in and guide us','become involved and give help or direction'),('narrow down choices','reduce many options to a smaller number'),('talk through the issue','discuss a problem carefully until it is understood or solved'),('back someone up','support someone'),('come between','cause trouble between people or separate them'),('draw on','use support, knowledge, or experience'),('fend for yourself','take care of yourself without help'),('see someone through','support someone during a difficult time'),('move on','continue with life or begin a new stage'),('boil down to willingness','have one main cause: whether someone is ready to act')]
rows=[[P('Phrase','PhraseX'),P('Meaning','PhraseX')]]+[[P(a,'BodyX'),P(b,'BodyX')] for a,b in vocab]
t=Table(rows,colWidths=[64*mm,106*mm],repeatRows=1)
t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),GOLD),('BACKGROUND',(0,1),(-1,-1),SKY),('GRID',(0,0),(-1,-1),0.35,HexColor('#A9C7D8')),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),6),('RIGHTPADDING',(0,0),(-1,-1),6),('TOPPADDING',(0,0),(-1,-1),5),('BOTTOMPADDING',(0,0),(-1,-1),5)]))
story += [t,Spacer(1,9),P('Speaking tip','H2X'),P('Start with: <i>“In my opinion…”</i> or <i>“I think…”</i>. Give a reason, use one vocabulary phrase, and add a short example.','BodyX')]
doc=SimpleDocTemplate(OUT,pagesize=A4,rightMargin=20*mm,leftMargin=20*mm,topMargin=18*mm,bottomMargin=18*mm)
doc.build(story,onFirstPage=footer,onLaterPages=footer)
print(OUT)
python "/tmp/workspace/heartache-handbook/src/create_exercise_handbook.py" && python -c "from pypdf import PdfReader; import os; p='/tmp/workspace/heartache-handbook/output/Exercise_1_and_5_Answers_Heartache_Handbook.pdf'; r=PdfReader(p); text='\n'.join(x.extract_text() or '' for x in r.pages); print('pages=',len(r.pages)); print('size=',os.path.getsize(p)); print('found_ex1=', 'Exercise 1' in text, 'found_ex5=', 'Exercise 5' in text); print(text[:500])"
Exercise 1 and 5 Answers Heartache Handbook
PDF Document · PDF
Please create a handbook colorful pdf from the file attached, create handbook in following way as per my instructions.Firstly create some more similar combinations as given in exercise 1 and later create other extra combinations from relatives and family vocabulary all the English text must have Russian translation under it. Secondly write meaning and 3 examples from daily life of vocabulary words on page 20 with Russian translation under and also on page 21 from exercise 6 with meaning and 3 Daily life examples and Russian translation under it. Thirdly explain the grammar part in super easy way with 3 examples and explain them for specific situations. Fourthly please explain using C1 vocabulary what we have learnt in this unit so far , explain that bar chart in super easy way for speaking practice and write individual answers of all individual exercises on page 22
~/
~/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b
python -c "from pypdf import PdfReader; p='/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b/DOC-20260924-WA0002.pdf'; r=PdfReader(p); print('PAGES',len(r.pages)); [print('\\n\\n### PAGE',i+1,'###\\n',pg.extract_text() or '') for i,pg in enumerate(r.pages)]"
mkdir -p "/tmp/workspace/mixed-messages-handbook/src" "/tmp/workspace/mixed-messages-handbook/assets" "/tmp/workspace/mixed-messages-handbook/output" && python -c "import fitz; p='/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b/DOC-20260924-WA0002.pdf'; d=fitz.open(p); pix=d[2].get_pixmap(matrix=fitz.Matrix(2,2), alpha=False); pix.save('/tmp/workspace/mixed-messages-handbook/assets/page22.png')"
pip install --user pymupdf
python -c "import pymupdf; p='/tmp/workspace/attachments/6c8fec80-ed7f-46cd-9560-b5212845ff1b/DOC-20260924-WA0002.pdf'; d=pymupdf.open(p); pix=d[2].get_pixmap(matrix=pymupdf.Matrix(2,2), alpha=False); pix.save('/tmp/workspace/mixed-messages-handbook/assets/page22.png')"
~/mixed-messages-handbook/src/create_handbook.py
from reportlab.lib import colors
from reportlab.lib.colors import HexColor
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
from reportlab.lib.enums import TA_CENTER
from reportlab.lib.units import mm
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether
from reportlab.pdfbase import pdfmetrics
from reportlab.pdfbase.ttfonts import TTFont
OUT='/tmp/workspace/mixed-messages-handbook/output/Mixed_Messages_Bilingual_Handbook.pdf'
FONT='/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf'
pdfmetrics.registerFont(TTFont('Noto',FONT))
pdfmetrics.registerFont(TTFont('NotoBold',FONT))
NAVY=HexColor('#173B5D'); TEAL=HexColor('#008C8C'); CORAL=HexColor('#E75F67'); GOLD=HexColor('#F5C84C'); LILAC=HexColor('#F1EDFF'); MINT=HexColor('#E9F8F1'); SKY=HexColor('#EDF6FE'); INK=HexColor('#263238'); GREY=HexColor('#61717C')
ss=getSampleStyleSheet()
ss.add(ParagraphStyle(name='TitleX',fontName='NotoBold',fontSize=26,leading=31,textColor=colors.white,alignment=TA_CENTER))
ss.add(ParagraphStyle(name='SubX',fontName='Noto',fontSize=11,leading=15,textColor=colors.white,alignment=TA_CENTER))
ss.add(ParagraphStyle(name='H1X',fontName='NotoBold',fontSize=18,leading=23,textColor=NAVY,spaceBefore=4,spaceAfter=7))
ss.add(ParagraphStyle(name='H2X',fontName='NotoBold',fontSize=12.2,leading=15,textColor=TEAL,spaceBefore=5,spaceAfter=3))
ss.add(ParagraphStyle(name='EN',fontName='Noto',fontSize=9.1,leading=12.5,textColor=INK))
ss.add(ParagraphStyle(name='RU',fontName='Noto',fontSize=8.5,leading=11.5,textColor=GREY,spaceAfter=5))
ss.add(ParagraphStyle(name='SmallEN',fontName='Noto',fontSize=7.8,leading=10.2,textColor=INK))
ss.add(ParagraphStyle(name='SmallRU',fontName='Noto',fontSize=7.3,leading=9.6,textColor=GREY))
ss.add(ParagraphStyle(name='Foot',fontName='Noto',fontSize=7.5,textColor=GREY,alignment=TA_CENTER))
def bi(en,ru,style='EN'):
rstyle='RU' if style=='EN' else 'SmallRU'
return [Paragraph(en,ss[style]),Paragraph(ru,ss[rstyle])]
def card(en,ru,bg=SKY):
t=Table([[Paragraph(en,ss['EN'])],[Paragraph(ru,ss['RU'])]],colWidths=[170*mm])
t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),0.6,TEAL),('LEFTPADDING',(0,0),(-1,-1),5),('RIGHTPADDING',(0,0),(-1,-1),5),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),3)]))
return t
def vocab(title,ru,meaning,mru,examples):
rows=[]
rows+=bi('<b>'+title+'</b>',ru)
rows+=bi('<b>Meaning:</b> '+meaning,'<b>Значение:</b> '+mru,'SmallEN')
for i,(e,r) in enumerate(examples,1): rows+=bi(f'{i}. {e}',f'{i}. {r}','SmallEN')
t=Table([[x] for x in rows],colWidths=[170*mm])
t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),MINT),('BOX',(0,0),(-1,-1),0.5,TEAL),('LEFTPADDING',(0,0),(-1,-1),5),('RIGHTPADDING',(0,0),(-1,-1),5),('TOPPADDING',(0,0),(-1,-1),2),('BOTTOMPADDING',(0,0),(-1,-1),1)]))
return t
def header(canvas,doc):
canvas.saveState(); canvas.setStrokeColor(TEAL); canvas.setLineWidth(2); canvas.line(18*mm,14*mm,192*mm,14*mm)
canvas.setFont('Noto',7.5); canvas.setFillColor(GREY); canvas.drawString(18*mm,9*mm,'MIXED MESSAGES | ДВУЯЗЫЧНЫЙ СПРАВОЧНИК'); canvas.drawRightString(192*mm,9*mm,str(doc.page)); canvas.restoreState()
story=[]
# cover
story.append(Spacer(1,18*mm))
cover=Table([[Paragraph('MIXED MESSAGES',ss['TitleX'])],[Paragraph('СМЕШАННЫЕ СИГНАЛЫ',ss['SubX'])],[Paragraph('Relationships, vocabulary, grammar and visual-data speaking practice<br/>Отношения, лексика, грамматика и разговорная практика по визуальным данным',ss['SubX'])]],colWidths=[170*mm])
cover.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),NAVY),('BOX',(0,0),(-1,-1),1,TEAL),('TOPPADDING',(0,0),(-1,-1),14),('BOTTOMPADDING',(0,0),(-1,-1),14)])); story.append(cover); story.append(Spacer(1,10*mm))
story+=bi('<b>What is inside:</b> relationship combinations, two vocabulary banks, easy grammar with <i>would</i>, a C1 unit review, chart-speaking practice, and individual model answers for page 22.','<b>Что внутри:</b> сочетания по теме отношений, два словаря, простая грамматика с <i>would</i>, обзор темы на уровне C1, практика описания диаграммы и индивидуальные образцы ответов к странице 22.')
story.append(card('<b>Study rule:</b> Read the English aloud, then cover it and say the Russian meaning. Finally, make one sentence about your own life.','<b>Правило обучения:</b> Прочитайте английский текст вслух, затем закройте его и скажите значение по-русски. В конце составьте одно предложение о своей жизни.',LILAC)); story.append(PageBreak())
# combos
story.append(Paragraph('1. Relationship combinations | Сочетания по теме отношений',ss['H1X']))
story+=bi('The original task names relationships. The combinations below help you describe them naturally.','Исходное задание называет виды отношений. Сочетания ниже помогут естественно их описывать.')
orig=[('a supportive sibling relationship','поддерживающие отношения между братьями и сёстрами'),('a close grandparent-grandchild bond','тесная связь между бабушкой/дедушкой и внуком/внучкой'),('a committed life partnership','преданное партнёрство на всю жизнь'),('a nurturing parent-child relationship','заботливые отношения родителя и ребёнка'),('a collaborative colleague relationship','отношения коллег, основанные на сотрудничестве'),('a respectful teacher-pupil rapport','уважительный контакт учителя и ученика'),('a productive business partnership','продуктивное деловое партнёрство'),('a demanding coach-athlete dynamic','требовательная динамика тренера и спортсмена'),('a friendly neighbourly connection','доброжелательные отношения между соседями'),('a trusting doctor-patient relationship','доверительные отношения врача и пациента')]
for e,r in orig: story.append(card('<b>'+e+'</b><br/>Example: They have '+e+' and communicate openly.','<b>'+r+'</b><br/>Пример: У них '+r+', и они открыто общаются.',SKY))
story.append(PageBreak())
story.append(Paragraph('1A. Extra family and relatives combinations | Дополнительные сочетания: семья и родственники',ss['H1X']))
fam=[('a caring aunt and niece relationship','заботливые отношения тёти и племянницы'),('a protective older brother','заботливый, защищающий старший брат'),('a distant cousin','дальний родственник, с которым мало общаются'),('a blended family','смешанная семья, где есть дети от предыдущих отношений'),('a close-knit family','дружная, сплочённая семья'),('a strained relationship with an in-law','напряжённые отношения с родственником супруга/супруги'),('a reliable family support network','надёжная семейная сеть поддержки'),('a family disagreement that causes friction','семейное разногласие, вызывающее напряжение'),('to keep in touch with relatives','поддерживать связь с родственниками'),('to look after an elderly relative','ухаживать за пожилым родственником')]
for e,r in fam: story.append(card('<b>'+e+'</b><br/>Example: My family tries to '+(e if e.startswith('to ') else 'build '+e)+'.','<b>'+r+'</b><br/>Пример: Моя семья старается '+('поддерживать это' if e.startswith('to ') else 'строить такие отношения')+'.',LILAC))
story.append(PageBreak())
# page20 vocab
story.append(Paragraph('2. Vocabulary from page 20 | Лексика со страницы 20',ss['H1X']))
story+=bi('Learn the phrase as one meaningful unit, not as separate words.','Учите выражение как одну смысловую единицу, а не как отдельные слова.')
v20=[
('get someone through a difficult time','помочь кому-либо пережить трудный период','help someone survive or cope with a hard situation','помочь человеку справиться с тяжёлой ситуацией',[('Music got me through a difficult exam week.','Музыка помогла мне пережить трудную экзаменационную неделю.'),('My sister got me through my first days at a new school.','Моя сестра помогла мне пережить первые дни в новой школе.'),('His friends got him through the disappointment.','Друзья помогли ему пережить разочарование.')]),
('lose your form / bounce back','потерять форму / быстро восстановиться','perform less well for a time / return to your usual level','временно хуже выступать / вернуться к обычному уровню',[('The player lost her form after the injury.','Спортсменка потеряла форму после травмы.'),('After a short rest, she bounced back.','После короткого отдыха она быстро восстановилась.'),('Everyone can lose their form, but practice helps you bounce back.','Каждый может потерять форму, но практика помогает восстановиться.')]),
('keep an eye on someone','присматривать за кем-либо','watch someone carefully to make sure they are safe','внимательно следить за кем-либо, чтобы он был в безопасности',[('Please keep an eye on my bag.','Пожалуйста, присмотри за моей сумкой.'),('I keep an eye on my grandmother when she walks outside.','Я присматриваю за бабушкой, когда она гуляет на улице.'),('The teacher kept an eye on the children.','Учитель присматривал за детьми.')]),
('spark an interest in','пробудить интерес к','make someone begin to be interested in something','вызвать у кого-либо интерес к чему-либо',[('That documentary sparked my interest in history.','Этот документальный фильм пробудил мой интерес к истории.'),('My uncle sparked my interest in photography.','Мой дядя пробудил мой интерес к фотографии.'),('The lesson sparked an interest in science.','Урок вызвал интерес к науке.')]),
('collaborate with','сотрудничать с','work jointly with another person or group','работать совместно с человеком или группой',[('I collaborated with two classmates on the project.','Я сотрудничал с двумя одноклассниками над проектом.'),('The artist collaborated with a local designer.','Художник сотрудничал с местным дизайнером.'),('We often collaborate with other departments.','Мы часто сотрудничаем с другими отделами.')]),
('be on speaking terms','быть в отношениях, когда люди разговаривают друг с другом','be willing to speak to each other after a disagreement','быть готовыми разговаривать после конфликта',[('After the argument, they were not on speaking terms.','После ссоры они не разговаривали друг с другом.'),('They are on speaking terms again now.','Сейчас они снова общаются.'),('I hope the neighbours will soon be on speaking terms.','Я надеюсь, что соседи скоро снова будут общаться.')])]
for x in v20: story.append(vocab(*x)); story.append(Spacer(1,2*mm))
story.append(PageBreak())
# continue v20
story.append(Paragraph('2A. Vocabulary from page 20, continued | Лексика со страницы 20, продолжение',ss['H1X']))
v20b=[
('be on first-name terms','быть на «ты», обращаться по имени','know someone well enough to use their first name','знать человека достаточно хорошо, чтобы обращаться по имени',[('I am on first-name terms with my manager.','Я обращаюсь к своему менеджеру по имени.'),('After several visits, we were on first-name terms.','После нескольких визитов мы стали обращаться друг к другу по имени.'),('Doctors are not always on first-name terms with patients.','Врачи не всегда обращаются к пациентам по имени.')]),
('see eye to eye','сходиться во взглядах','agree about something important','соглашаться по важному вопросу',[('My parents do not always see eye to eye about money.','Мои родители не всегда сходятся во взглядах на деньги.'),('We see eye to eye on this plan.','Мы одинаково смотрим на этот план.'),('The partners rarely see eye to eye.','Партнёры редко приходят к согласию.')]),
('be at each other’s throats','постоянно яростно ссориться','argue with each other in an angry way','яростно спорить друг с другом',[('The siblings were at each other’s throats all morning.','Брат и сестра яростно ссорились всё утро.'),('They are usually friendly, but today they are at each other’s throats.','Обычно они дружелюбны, но сегодня они сильно ругаются.'),('Stress can leave colleagues at each other’s throats.','Стресс может заставить коллег постоянно конфликтовать.')]),
('put someone at ease','успокоить кого-либо, помочь расслабиться','make someone feel relaxed and less worried','помочь человеку расслабиться и меньше волноваться',[('Her smile put me at ease.','Её улыбка помогла мне расслабиться.'),('The nurse put the child at ease before the test.','Медсестра успокоила ребёнка перед анализом.'),('A friendly introduction puts everyone at ease.','Дружелюбное представление помогает всем расслабиться.')]),
('single someone out','выделить кого-либо, часто несправедливо','choose one person from a group for special attention','выделить одного человека из группы для особого внимания',[('The teacher did not single anyone out.','Учитель никого не выделил.'),('Why did he single me out for criticism?','Почему он выделил меня для критики?'),('She was singled out because of her good work.','Её выделили благодаря хорошей работе.')]),
('pull your weight','выполнять свою часть работы','do your fair share of work or responsibility','делать свою справедливую долю работы или обязанностей',[('Everyone must pull their weight at home.','Дома каждый должен выполнять свою часть обязанностей.'),('He pulls his weight in the team.','Он выполняет свою часть работы в команде.'),('She is not pulling her weight on this project.','Она не выполняет свою часть работы в этом проекте.')])]
for x in v20b: story.append(vocab(*x)); story.append(Spacer(1,2*mm))
story.append(PageBreak())
# ex6
story.append(Paragraph('3. Vocabulary from Exercise 6, page 21 | Лексика из упражнения 6, страница 21',ss['H1X']))
v21=[
('mixed messages','противоречивые сигналы','different messages that are confusing or inconsistent','разные сообщения, которые противоречат друг другу или сбивают с толку',[('The rules gave students mixed messages.','Правила посылали ученикам противоречивые сигналы.'),('His words and actions sent mixed messages.','Его слова и действия посылали смешанные сигналы.'),('Mixed messages can make a decision difficult.','Противоречивые сигналы могут затруднить решение.')]),
('get back on the straight and narrow','вернуться на правильный путь','return to sensible, honest or lawful behaviour','вернуться к разумному, честному или законному поведению',[('A new job helped him get back on the straight and narrow.','Новая работа помогла ему вернуться на правильный путь.'),('His family hopes he will get back on the straight and narrow.','Его семья надеется, что он вернётся на правильный путь.'),('Good support can help young people get back on the straight and narrow.','Хорошая поддержка может помочь молодым людям вернуться на правильный путь.')]),
('a confrontation','конфронтация, столкновение','an angry argument or conflict between people','острый спор или конфликт между людьми',[('There was a confrontation outside the shop.','Возле магазина произошло столкновение.'),('I try to avoid confrontation at work.','Я стараюсь избегать конфликтов на работе.'),('The confrontation began because of a misunderstanding.','Конфликт начался из-за недопонимания.')]),
('back down','уступить, отступить','admit that you cannot continue an argument or demand','признать, что нельзя продолжать спор или требование',[('Neither side wanted to back down.','Ни одна сторона не хотела уступать.'),('She backed down after hearing the facts.','Она уступила, услышав факты.'),('It is sometimes wise to back down.','Иногда разумно отступить.')]),
('come as a shock','стать шоком','surprise or upset someone very much','сильно удивить или расстроить кого-либо',[('The news came as a shock to us.','Эта новость стала для нас шоком.'),('His decision to leave came as a shock.','Его решение уйти стало шоком.'),('It did not come as a shock because we expected it.','Это не стало шоком, потому что мы этого ожидали.')])]
for x in v21: story.append(vocab(*x)); story.append(Spacer(1,2*mm))
story.append(PageBreak())
story.append(Paragraph('3A. Vocabulary from Exercise 6, continued | Лексика из упражнения 6, продолжение',ss['H1X']))
v21b=[
('confide in someone','довериться кому-либо','tell someone private information because you trust them','рассказать кому-то личную информацию, потому что вы доверяете',[('She confided in her best friend.','Она доверилась лучшей подруге.'),('Toby confided in his coach.','Тоби доверился своему тренеру.'),('It helps to confide in someone you trust.','Полезно довериться человеку, которому вы доверяете.')]),
('be in remarkably good health','быть на удивление в хорошем здоровье','be unusually healthy, especially for one’s age or situation','быть необычайно здоровым, особенно для своего возраста или ситуации',[('At 80, my grandfather is in remarkably good health.','В 80 лет мой дедушка на удивление здоров.'),('The doctor said she was in remarkably good health.','Врач сказал, что она на удивление здорова.'),('He exercises daily and remains in remarkably good health.','Он ежедневно занимается спортом и остаётся на удивление здоровым.')]),
('come to someone’s aid','прийти кому-либо на помощь','help someone when they need it','помочь человеку, когда ему нужна помощь',[('A neighbour came to my aid when my car stopped.','Сосед пришёл мне на помощь, когда машина остановилась.'),('Her brother came to her aid immediately.','Её брат сразу пришёл ей на помощь.'),('The teacher came to the student’s aid.','Учитель пришёл на помощь ученику.')]),
('when it comes down to it','в конечном итоге, если свести всё к главному','when the most important point is considered','когда рассматривается самое главное',[('When it comes down to it, trust matters most.','В конечном итоге доверие важнее всего.'),('When it comes down to it, we need more time.','Если свести всё к главному, нам нужно больше времени.'),('When it comes down to it, she made the right choice.','В конечном итоге она сделала правильный выбор.')]),
('make a scene','устроить сцену','behave loudly or emotionally in public','вести себя громко или эмоционально на публике',[('Please do not make a scene in the restaurant.','Пожалуйста, не устраивай сцену в ресторане.'),('He made a scene when he missed the train.','Он устроил сцену, когда опоздал на поезд.'),('They argued quietly instead of making a scene.','Они спорили тихо, вместо того чтобы устраивать сцену.')])]
for x in v21b: story.append(vocab(*x)); story.append(Spacer(1,2*mm))
story.append(PageBreak())
# grammar
story.append(Paragraph('4. Grammar: WOULD made easy | Грамматика: WOULD очень просто',ss['H1X']))
story+=bi('<b>Would</b> is a polite, softer way to give an opinion or advice. It makes you sound less absolute.','<b>Would</b> — это вежливый, более мягкий способ выразить мнение или дать совет. Он делает высказывание менее категоричным.')
story.append(card('<b>Useful patterns</b><br/>I’d say + opinion. | I’d imagine + clause. | I’d advise + person + to + verb. | I wouldn’t say + negative opinion.','<b>Полезные модели</b><br/>I’d say + мнение. | I’d imagine + придаточное предложение. | I’d advise + человек + to + глагол. | I wouldn’t say + отрицательное мнение.',GOLD))
examples=[('<b>Situation: You are unsure what happened to Toby.</b><br/><i>I’d say he reacted impulsively because he felt under pressure.</i><br/>Why: <i>I’d say</i> presents your interpretation politely, not as a proven fact.','<b>Ситуация: Вы не уверены, что произошло с Тоби.</b><br/><i>Я бы сказал, что он отреагировал импульсивно, потому что чувствовал давление.</i><br/>Почему: <i>I’d say</i> вежливо выражает вашу интерпретацию, а не доказанный факт.'),('<b>Situation: You give a friend relationship advice.</b><br/><i>I’d advise you to talk it over with your sister directly.</i><br/>Why: <i>I’d advise</i> gives calm, non-commanding advice.','<b>Ситуация: Вы даёте другу совет об отношениях.</b><br/><i>Я бы посоветовал тебе обсудить это с сестрой напрямую.</i><br/>Почему: <i>I’d advise</i> даёт спокойный совет без приказного тона.'),('<b>Situation: You want to reassure a worried parent.</b><br/><i>I wouldn’t imagine he’d be punished severely.</i><br/>Why: negative <i>would</i> makes your reassurance cautious and tactful.','<b>Ситуация: Вы хотите успокоить обеспокоенного родителя.</b><br/><i>Я бы не предположил, что его строго накажут.</i><br/>Почему: отрицательная форма <i>would</i> делает успокоение осторожным и тактичным.')]
for a,b in examples: story.append(card(a,b,LILAC)); story.append(Spacer(1,3*mm))
story+=bi('<b>Remember:</b> Say <i>I wouldn’t say it is serious</i>, not <i>I would say it is not serious</i>, when you want to soften the negative opinion.','<b>Запомните:</b> Говорите <i>I wouldn’t say it is serious</i>, а не <i>I would say it is not serious</i>, когда хотите смягчить отрицательное мнение.')
story.append(PageBreak())
# unit learning
story.append(Paragraph('5. What we have learned so far: C1 review | Что мы изучили: обзор уровня C1',ss['H1X']))
review=[('This unit develops the ability to discuss relationships with precision and tact. Rather than using basic words such as “good” or “bad”, we can describe rapport, friction, mutual support, professional boundaries and conflicting expectations.','Этот модуль развивает умение точно и тактично обсуждать отношения. Вместо простых слов «хороший» или «плохой» мы можем описывать контакт, напряжение, взаимную поддержку, профессиональные границы и противоречивые ожидания.'),('We have also learned to interpret interpersonal behaviour cautiously. Phrases such as <i>I’d say</i>, <i>I’d imagine</i> and <i>I wouldn’t say</i> allow us to speculate without presenting assumptions as facts. This is especially useful when discussing sensitive conflicts.','Мы также научились осторожно интерпретировать поведение людей. Фразы <i>I’d say</i>, <i>I’d imagine</i> и <i>I wouldn’t say</i> позволяют высказывать предположения, не представляя их как факты. Это особенно полезно при обсуждении деликатных конфликтов.'),('Finally, we can describe social and demographic change through data. We identify overarching trends, compare categories, select telling figures and make measured predictions. This turns a list of numbers into a coherent spoken summary.','Наконец, мы можем описывать социальные и демографические изменения с помощью данных. Мы выявляем общие тенденции, сравниваем категории, выбираем показательные цифры и делаем взвешенные прогнозы. Это превращает список чисел в связное устное резюме.')]
for a,b in review: story.append(card(a,b,MINT)); story.append(Spacer(1,4*mm))
story.append(PageBreak())
# chart
story.append(Paragraph('6. The bar chart: easy speaking practice | Столбчатая диаграмма: простая разговорная практика',ss['H1X']))
story+=bi('The chart compares the shares of people living in urban and rural areas in 2020 and 2035, worldwide and in more and less economically developed regions.','Диаграмма сравнивает доли людей, живущих в городских и сельских районах, в 2020 и 2035 годах в мире и в более и менее экономически развитых регионах.')
story.append(card('<b>Simple structure for speaking</b><br/>1. Say what the chart compares. 2. State the overall trend. 3. Compare developed and less developed regions. 4. Add one prediction.','<b>Простая структура для устной речи</b><br/>1. Скажите, что сравнивает диаграмма. 2. Назовите общую тенденцию. 3. Сравните развитые и менее развитые регионы. 4. Добавьте один прогноз.',GOLD))
story.append(Spacer(1,4*mm))
chart_text='<b>Model answer</b><br/>The bar chart shows that urbanisation is expected to continue between 2020 and 2035. Globally, the proportion of people living in cities rises, while the rural share declines. More economically developed regions are already predominantly urban, so their change is relatively modest. By contrast, less developed regions show the most pronounced shift towards city living. I think this trend may create more jobs and services, but it could also put pressure on housing, transport and the environment.'
chart_ru='<b>Образец ответа</b><br/>Диаграмма показывает, что урбанизация, как ожидается, продолжится в период с 2020 по 2035 год. Во всём мире доля людей, живущих в городах, растёт, а доля сельского населения снижается. В более экономически развитых регионах большинство людей уже живёт в городах, поэтому изменения там сравнительно небольшие. Напротив, в менее развитых регионах наблюдается наиболее заметный переход к городской жизни. Я думаю, что эта тенденция может создать больше рабочих мест и услуг, но также усилить давление на жильё, транспорт и окружающую среду.'
story.append(card(chart_text,chart_ru,SKY)); story.append(Spacer(1,4*mm))
story+=bi('<b>Useful C1 phrases:</b> a pronounced shift; predominantly urban; a modest increase; put pressure on infrastructure; a long-term demographic trend.','<b>Полезные фразы уровня C1:</b> заметный сдвиг; преимущественно городской; умеренное увеличение; создавать нагрузку на инфраструктуру; долгосрочная демографическая тенденция.')
story.append(PageBreak())
# page22 individual
story.append(Paragraph('7. Page 22: individual model answers | Страница 22: индивидуальные образцы ответов',ss['H1X']))
story.append(Paragraph('Exercise 1 | Упражнение 1',ss['H2X']))
ex1=[('1. Japan and the United States are more economically developed. India, Bangladesh, Egypt, Nigeria, Pakistan and the Democratic Republic of Congo are less economically developed. China, Brazil and Mexico are often described as emerging or middle-income economies.','1. Япония и Соединённые Штаты являются более экономически развитыми странами. Индия, Бангладеш, Египет, Нигерия, Пакистан и Демократическая Республика Конго являются менее экономически развитыми. Китай, Бразилию и Мексику часто описывают как развивающиеся страны или страны со средним доходом.'),('2. The main trend is urban growth. Delhi becomes the largest city, and several cities in Africa and Asia rise in the ranking. Tokyo is unusual because its population is predicted to fall slightly.','2. Главная тенденция — рост городов. Дели становится крупнейшим городом, а несколько городов Африки и Азии поднимаются в рейтинге. Токио необычен, потому что его население, как прогнозируется, немного сократится.'),('3. In my country, I can see a similar pattern: young people tend to move to large cities for education, employment and services. However, some people prefer smaller towns because they are quieter and less expensive.','3. В моей стране я вижу похожую картину: молодые люди обычно переезжают в крупные города ради образования, работы и услуг. Однако некоторые предпочитают небольшие города, потому что там тише и дешевле.'),('4. Urban growth can be positive because it may bring opportunity, cultural life and better healthcare. On the other hand, rapid growth can cause overcrowding, high rents and traffic congestion.','4. Рост городов может быть положительным, потому что он может приносить возможности, культурную жизнь и лучшее здравоохранение. С другой стороны, быстрый рост может вызвать перенаселённость, высокую аренду и пробки.')]
for a,b in ex1: story.append(card(a,b,LILAC)); story.append(Spacer(1,2*mm))
story.append(PageBreak())
story.append(Paragraph('7A. Page 22: exercises 2 and 3 | Страница 22: упражнения 2 и 3',ss['H1X']))
story.append(Paragraph('Exercise 2: completed summary | Упражнение 2: заполненное резюме',ss['H2X']))
comp=('The table shows the twelve largest cities in the world by population in 2020 and projected figures for <b>2035</b>, while the chart shows the relative size of urban and rural populations in the same years. As can be seen, with the exception of <b>Tokyo</b>, all the top nine cities are predicted to grow. Delhi and Dhaka are set to have some of the biggest rises, increasing by <b>13</b> and <b>10</b> million respectively. In more economically developed countries, nearly <b>four</b> out of every five people already live in cities. By 2035, the global urban population is expected to rise by just over <b>five percentage points</b>, the bulk of which will occur in <b>less</b> developed countries. Two African cities, <b>Lagos</b> and Kinshasa, are forecast to have entered the top twelve for the first time.')
comp_ru=('В таблице показаны двенадцать крупнейших городов мира по населению в 2020 году и прогнозные данные на <b>2035</b> год, а диаграмма показывает относительный размер городского и сельского населения в те же годы. Как видно, за исключением <b>Токио</b>, прогнозируется рост всех девяти крупнейших городов. Ожидается, что население Дели и Дакки вырастет сильнее всего — на <b>13</b> и <b>10</b> миллионов соответственно. В более экономически развитых странах почти <b>четыре</b> человека из каждых пяти уже живут в городах. К 2035 году ожидается, что доля мирового городского населения увеличится чуть более чем на <b>пять процентных пунктов</b>, причём основная часть роста произойдёт в <b>менее</b> развитых странах. Прогнозируется, что два африканских города, <b>Лагос</b> и Киншаса, впервые войдут в двенадцать крупнейших городов.')
story.append(card(comp,comp_ru,MINT)); story.append(Spacer(1,4*mm))
story.append(Paragraph('Exercise 3 | Упражнение 3',ss['H2X']))
ex3=[('1. The summary starts by paraphrasing what the table and chart show.','1. Резюме начинается с перефразирования того, что показывают таблица и диаграмма.'),('2. Paragraph 1 focuses on city rankings and population growth. Paragraph 2 focuses on urbanisation in different development groups. Paragraph 3 notes the coastal and river location pattern. The information is linked, not treated as completely separate visuals.','2. Первый абзац посвящён рейтингу городов и росту населения. Второй абзац посвящён урбанизации в разных группах стран. Третий абзац отмечает закономерность расположения у побережья и рек. Информация связана, а не рассматривается как полностью отдельные визуальные материалы.'),('3. Delhi is mentioned because it has the largest forecast increase and overtakes Tokyo as the largest city.','3. Дели упоминается потому, что у него самый большой прогнозируемый рост и он обгоняет Токио как крупнейший город.'),('4. New York and Kinshasa illustrate the changing ranking: New York falls, while Kinshasa enters the top group.','4. Нью-Йорк и Киншаса иллюстрируют изменение рейтинга: Нью-Йорк опускается, а Киншаса входит в ведущую группу.'),('5. A useful statistic is that Tokyo declines from 37 million to 36 million, while Delhi rises from 30 million to 43 million.','5. Полезная статистика: население Токио сокращается с 37 до 36 миллионов, а население Дели увеличивается с 30 до 43 миллионов.')]
for a,b in ex3: story.append(card(a,b,SKY)); story.append(Spacer(1,2*mm))
doc=SimpleDocTemplate(OUT,pagesize=(210*mm,297*mm),rightMargin=20*mm,leftMargin=20*mm,topMargin=18*mm,bottomMargin=19*mm,title='Mixed Messages Bilingual Handbook')
doc.build(story,onFirstPage=header,onLaterPages=header)
print(OUT)
python "/tmp/workspace/mixed-messages-handbook/src/create_handbook.py" && python -c "from pypdf import PdfReader; import os; p='/tmp/workspace/mixed-messages-handbook/output/Mixed_Messages_Bilingual_Handbook.pdf'; r=PdfReader(p); txt='\n'.join((q.extract_text() or '') for q in r.pages); print('pages=',len(r.pages),'bytes=',os.path.getsize(p)); print('key=',all(x in txt for x in ['get someone through a difficult time','mixed messages','WOULD made easy','individual model answers','13'])); print(txt[-700:])"
"v20b=[" in ~/mixed-messages-handbook/src
~/mixed-messages-handbook/src/create_handbook.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/mixed-messages-handbook/src/create_handbook.py'
python "/tmp/workspace/mixed-messages-handbook/src/create_handbook.py" && python -c "from pypdf import PdfReader; import os; p='/tmp/workspace/mixed-messages-handbook/output/Mixed_Messages_Bilingual_Handbook.pdf'; r=PdfReader(p); txt='\n'.join(x.extract_text() or '' for x in r.pages); print('pages=',len(r.pages),'bytes=',os.path.getsize(p)); print('all_page20=',all(z in txt for z in ['maintain a professional relationship','a losing streak','cause friction'])); print('all_sections=',all(z in txt for z in ['Vocabulary from Exercise 6','WOULD made easy','The bar chart','Page 22']))"
~/mixed-messages-handbook/output
Mixed Messages Bilingual Handbook
PDF Document · PDF