Please create a colorful handbook pdf for the 2 files attached in that file please write 15 creative and logical interesting conversation questions along with answers and Russian translation under individual questions and answers for ESL 4th grade Cambridge exam preparation student ( use only present simple and present continuous and future simple easy variety tenses only)Also include vocabulary list from both files attached and similar extra vocabulary also add from the file attached with it's meaning.
~/
Create the handbook using both PDFs’ main topics
~/attachments
mkdir -p "/tmp/workspace/esl_handbook/src" "/tmp/workspace/esl_handbook/output" && python - <<'PY' from pypdf import PdfReader from pathlib import Path files=[Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261018-WA0009 (1).pdf'),Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261022-WA0000.pdf')] for f in files: print('\n###',f.name) r=PdfReader(str(f)); print('PAGES',len(r.pages)) for i,p in enumerate(r.pages): t=p.extract_text() or '' print(f'\n---PAGE {i+1}---\n{t[:10000]}') PY
python - <<'PY' from pathlib import Path import fitz from PIL import Image,ImageDraw files=[Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261018-WA0009 (1).pdf'),Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261022-WA0000.pdf')] out=Path('/tmp/workspace/esl_handbook/src') for f in files: d=fitz.open(f) ims=[] for i,p in enumerate(d): pix=p.get_pixmap(matrix=fitz.Matrix(1.8,1.8),alpha=False) fp=out/f'{f.stem}_page_{i+1}.png'; pix.save(fp) im=Image.open(fp).convert('RGB'); im.thumbnail((600,800)); ims.append(im.copy()) W=620; H=sum(x.height+45 for x in ims)+20 m=Image.new('RGB',(W,H),'white'); y=10; dr=ImageDraw.Draw(m) for i,im in enumerate(ims): dr.text((10,y),f'{f.name} - page {i+1}',fill='black') y+=25; m.paste(im,((W-im.width)//2,y)); y+=im.height+20 m.save(out/f'{f.stem}_montage.png') PY
python - <<'PY' from pathlib import Path from pypdf import PdfReader base=Path('/tmp/workspace/esl_handbook/src') files=[Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261018-WA0009 (1).pdf'),Path('/tmp/workspace/attachments/b2c0376a-b61a-4c56-b3c3-8ba39787d929/DOC-20261022-WA0000.pdf')] for fi,f in enumerate(files): r=PdfReader(str(f)) for pi,p in enumerate(r.pages): for ii,img in enumerate(p.images): ext=img.name.split('.')[-1] dest=base/f'source{fi+1}_p{pi+1}_img{ii+1}.{ext}' dest.write_bytes(img.data) print(dest, len(img.data)) PY ls -lh "/tmp/workspace/esl_handbook/src"
python - <<'PY' from PIL import Image from pathlib import Path for p in Path('/tmp/workspace/esl_handbook/src').glob('*.jpg'): im=Image.open(p) print(p.name,im.size,im.mode, im.getpixel((0,0))) try: import pytesseract print(pytesseract.image_to_string(im)[:3000]) except Exception as e: print('OCR ERROR',repr(e)) PY
python - <<'PY' import importlib.util for x in ['easyocr','keras_ocr','paddleocr','rapidocr_onnxruntime','cv2','transformers']: print(x,importlib.util.find_spec(x)) PY
pip install --user rapidocr_onnxruntime -q
pip install rapidocr_onnxruntime -q && python - <<'PY' from rapidocr_onnxruntime import RapidOCR from pathlib import Path engine=RapidOCR() for p in sorted(Path('/tmp/workspace/esl_handbook/src').glob('*.jpg')): result,elapse=engine(str(p)) print('\n###',p.name,'###') print('\n'.join(x[1] for x in (result or []))) PY
fc-list | grep -i 'DejaVuSans.ttf' | head -1
ls -la "/usr/share/fonts/truetype/dejavu/"; cat > "/tmp/workspace/esl_handbook/src/create_handbook.py" <<'PY' from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER, TA_LEFT from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.lib.units import cm from pathlib import Path OUT=Path('/tmp/workspace/esl_handbook/output/States_of_Matter_and_Hot_Springs_ESL_Handbook.pdf') font='/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf' font_b='/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf' pdfmetrics.registerFont(TTFont('DV',font)); pdfmetrics.registerFont(TTFont('DVB',font_b)) NAVY=colors.HexColor('#173F5F'); BLUE=colors.HexColor('#20639B'); TEAL=colors.HexColor('#3CAEA3'); YELLOW=colors.HexColor('#F6D55C'); CORAL=colors.HexColor('#ED553B'); PALE=colors.HexColor('#F2F8FB'); LILAC=colors.HexColor('#F2ECFF'); GREEN=colors.HexColor('#E8F7EE') styles=getSampleStyleSheet() styles.add(ParagraphStyle(name='TitleKid',fontName='DVB',fontSize=28,leading=34,textColor=NAVY,alignment=TA_CENTER,spaceAfter=12)) styles.add(ParagraphStyle(name='Sub',fontName='DV',fontSize=13,leading=18,textColor=BLUE,alignment=TA_CENTER)) styles.add(ParagraphStyle(name='H1Kid',fontName='DVB',fontSize=19,leading=24,textColor=NAVY,spaceBefore=4,spaceAfter=10)) styles.add(ParagraphStyle(name='H2Kid',fontName='DVB',fontSize=13,leading=17,textColor=NAVY,spaceBefore=5,spaceAfter=5)) styles.add(ParagraphStyle(name='BodyKid',fontName='DV',fontSize=10.3,leading=14,textColor=colors.HexColor('#203040'))) styles.add(ParagraphStyle(name='Small',fontName='DV',fontSize=8.7,leading=11.5,textColor=colors.HexColor('#203040'))) styles.add(ParagraphStyle(name='Q',fontName='DVB',fontSize=11.3,leading=15,textColor=NAVY)) styles.add(ParagraphStyle(name='RU',fontName='DV',fontSize=9.2,leading=12.5,textColor=colors.HexColor('#5B4375'))) styles.add(ParagraphStyle(name='A',fontName='DV',fontSize=10.3,leading=14,textColor=colors.HexColor('#1E4B45'))) def P(t,style='BodyKid'): return Paragraph(t, styles[style]) def page(canvas,doc): canvas.saveState(); w,h=A4 canvas.setFillColor(NAVY); canvas.rect(0,h-1.1*cm,w,1.1*cm,fill=1,stroke=0) canvas.setFillColor(colors.white); canvas.setFont('DVB',9); canvas.drawString(1.3*cm,h-.7*cm,'SCIENCE TALK • ESL GRADE 4') canvas.setFillColor(TEAL); canvas.circle(w-1.2*cm,h-.55*cm,.23*cm,fill=1,stroke=0) canvas.setFillColor(colors.HexColor('#6A7680')); canvas.setFont('DV',8); canvas.drawCentredString(w/2,.6*cm,f'Cambridge-style speaking practice • {doc.page}') canvas.restoreState() def card(contents,bg=PALE, pad=9): t=Table([[contents]], colWidths=[17.0*cm]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),0.7,colors.white),('LEFTPADDING',(0,0),(-1,-1),pad),('RIGHTPADDING',(0,0),(-1,-1),pad),('TOPPADDING',(0,0),(-1,-1),pad),('BOTTOMPADDING',(0,0),(-1,-1),pad)])) return t def qa(n,q,qr,a,ar): inner=[P(f'{n}. {q}','Q'),P(qr,'RU'),Spacer(1,3),P('<b>Model answer:</b> '+a,'A'),P(ar,'RU')] return KeepTogether([card(inner,LILAC if n%2 else GREEN),Spacer(1,7)]) story=[] story += [Spacer(1,1.2*cm),P('States of Matter<br/>and Hot Springs','TitleKid'),P('A colourful bilingual speaking handbook<br/>for Grade 4 Cambridge exam preparation','Sub'),Spacer(1,16)] story += [card([P('MAIN TOPICS','H2Kid'),P('<b>1. States of matter:</b> solids, liquids and gases. <br/><b>2. Changes:</b> freezing, melting and boiling. <br/><b>3. Hot springs:</b> hot rocks, water and steam. <br/><br/><b>Language focus:</b> Present Simple • Present Continuous • Future Simple','BodyKid')],colors.HexColor('#FFF5CF'),12),Spacer(1,17)] story += [P('How to use this book','H1Kid'),P('Read the question. Say the Russian translation. Read the model answer. Then change one idea and make your own answer. Speak in a full sentence.','BodyKid'),Spacer(1,10)] story += [card([P('Speaker tip','H2Kid'),P('Use <b>because</b> to give a reason: “I like steam because it is interesting.” Use <b>will</b> for a future plan: “I will make ice tomorrow.”','BodyKid')],colors.HexColor('#DDF4F1'))] story.append(PageBreak()) story += [P('1. Quick science notes','H1Kid'),card([P('Matter is everything around us. It can be a solid, a liquid or a gas. Heat and cold can change water from one state to another.','BodyKid')],PALE),Spacer(1,9)] science=[['State','What it is','Examples'],['Solid','It has a shape. It can be hard or soft.','ice, rock, tree, feather'],['Liquid','It flows. It can be thick or thin.','water, juice, milkshake'],['Gas','We usually cannot see it. Sometimes we can feel it.','air, wind, steam']] t=Table([[P(c,'H2Kid' if r==0 else 'Small') for c in row] for r,row in enumerate(science)],colWidths=[3.0*cm,7.0*cm,7.0*cm]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),TEAL),('TEXTCOLOR',(0,0),(-1,0),colors.white),('GRID',(0,0),(-1,-1),.4,colors.white),('BACKGROUND',(0,1),(-1,-1),colors.HexColor('#F1FAFB')),('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 += [t,Spacer(1,12)] story += [P('Water is changing!','H2Kid'),P('• When water is very cold, it <b>freezes</b> and changes to ice. <br/>• When ice or snow heats up, it <b>melts</b> and changes to water. <br/>• When water is very hot, it <b>boils</b> and changes to steam.','BodyKid'),Spacer(1,9)] story += [card([P('Hot springs','H2Kid'),P('Hot springs are small lakes with hot water. Hot rocks can heat the water. Some water can also heat up under the ground. When the water is very hot, some of it changes to steam. Hot water and steam can be dangerous.','BodyKid')],colors.HexColor('#FFE8DC'))] story.append(PageBreak()) story += [P('2. Vocabulary from the texts','H1Kid'),P('Read the word, say the meaning, and practise the Russian translation.','BodyKid'),Spacer(1,7)] vocab=[('solid','a thing with a shape; it can be hard or soft','твёрдое вещество'),('liquid','something that flows','жидкость'),('gas','air-like matter; we usually cannot see it','газ'),('state','a form of matter: solid, liquid or gas','состояние'),('flow','to move like water','течь'),('thick','not thin; for example, a thick milkshake','густой'),('thin','not thick; for example, a thin drink','жидкий, негустой'),('freeze','to change from water to ice','замерзать'),('melt','to change from ice or snow to water','таять'),('boil','to become very hot and change to steam','кипеть'),('steam','hot water gas','пар'),('heat up','to become hot','нагреваться'),('hot spring','a small lake with hot water','горячий источник'),('ground','the earth under our feet','земля, почва'),('rock','a hard piece of stone','камень, скала'),('dangerous','not safe','опасный')] for chunk_i in range(0,len(vocab),8): chunk=vocab[chunk_i:chunk_i+8] data=[[P('<b>Word</b>','Small'),P('<b>Easy meaning</b>','Small'),P('<b>Russian</b>','Small')]]+[[P(x[0],'Small'),P(x[1],'Small'),P(x[2],'Small')] for x in chunk] tb=Table(data,colWidths=[3.0*cm,8.7*cm,5.3*cm]) tb.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),BLUE),('TEXTCOLOR',(0,0),(-1,0),colors.white),('BACKGROUND',(0,1),(-1,-1),PALE),('GRID',(0,0),(-1,-1),.35,colors.white),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),5),('RIGHTPADDING',(0,0),(-1,-1),5),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)])); story += [tb,Spacer(1,9)] story.append(PageBreak()) story += [P('3. Extra useful vocabulary','H1Kid'),P('These related words will help you make new answers.','BodyKid'),Spacer(1,7)] extra=[('ice','frozen water','лёд'),('snow','soft white ice from the sky','снег'),('water','a clear liquid','вода'),('air','the gas around us','воздух'),('wind','moving air','ветер'),('warm','a little hot','тёплый'),('cold','not warm','холодный'),('temperature','how hot or cold something is','температура'),('change','to become different','меняться'),('cause','the thing that makes something happen','причина'),('effect','what happens because of a cause','результат, следствие'),('careful','thinking about safety','осторожный'),('safe','not dangerous','безопасный'),('lake','a large area of water with land around it','озеро'),('breathe','to take air into your body','дышать'),('weather','sun, rain, wind and temperature outside','погода')] data=[[P('<b>Word</b>','Small'),P('<b>Easy meaning</b>','Small'),P('<b>Russian</b>','Small')]]+[[P(x[0],'Small'),P(x[1],'Small'),P(x[2],'Small')] for x in extra] tb=Table(data,colWidths=[3.0*cm,8.7*cm,5.3*cm],repeatRows=1);tb.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,0),CORAL),('TEXTCOLOR',(0,0),(-1,0),colors.white),('BACKGROUND',(0,1),(-1,-1),colors.HexColor('#FFF3EE')),('GRID',(0,0),(-1,-1),.35,colors.white),('VALIGN',(0,0),(-1,-1),'TOP'),('LEFTPADDING',(0,0),(-1,-1),5),('RIGHTPADDING',(0,0),(-1,-1),5),('TOPPADDING',(0,0),(-1,-1),4),('BOTTOMPADDING',(0,0),(-1,-1),4)]));story += [tb,Spacer(1,10)] story += [card([P('Mini challenge','H2Kid'),P('Choose three words and make sentences: “Ice is a solid.” “Steam is rising.” “I will drink water.”','BodyKid')],colors.HexColor('#FFF5CF'))] story.append(PageBreak()) qas=[ ('What state is ice?','Какое состояние у льда?','Ice is a solid. It is cold and hard.','Лёд - твёрдое вещество. Он холодный и твёрдый.'), ('What state is juice?','Какое состояние у сока?','Juice is a liquid. It flows in a glass.','Сок - жидкость. Он течёт в стакане.'), ('Can you see the wind?','Ты можешь видеть ветер?','No, I cannot see the wind, but I can feel it.','Нет, я не могу видеть ветер, но я могу его чувствовать.'), ('What is happening to the snow in the sun?','Что происходит со снегом на солнце?','The snow is melting. It is changing to water.','Снег тает. Он превращается в воду.'), ('What happens when water is very cold?','Что происходит, когда вода очень холодная?','Water freezes and changes to ice.','Вода замерзает и превращается в лёд.'), ('What happens when water is very hot?','Что происходит, когда вода очень горячая?','Water boils and some water changes to steam.','Вода кипит, и часть воды превращается в пар.'), ('Why do you like ice or snow?','Почему тебе нравится лёд или снег?','I like snow because it is soft and white.','Мне нравится снег, потому что он мягкий и белый.'), ('What can you see in a hot spring?','Что ты можешь увидеть в горячем источнике?','I can see hot water, rocks and steam.','Я могу увидеть горячую воду, камни и пар.'), ('How does water in a hot spring get hot?','Как вода в горячем источнике становится горячей?','Hot rocks heat the water. The water can also heat up under the ground.','Горячие камни нагревают воду. Вода также может нагреваться под землёй.'), ('Why are hot springs dangerous?','Почему горячие источники опасны?','They are dangerous because the water and steam are hot.','Они опасны, потому что вода и пар горячие.'), ('What is your favourite liquid?','Какая твоя любимая жидкость?','My favourite liquid is milk. I drink it at breakfast.','Моя любимая жидкость - молоко. Я пью его на завтрак.'), ('What is changing in your kitchen now?','Что сейчас меняется на твоей кухне?','Water is boiling in a pot now. Steam is rising.','Вода сейчас кипит в кастрюле. Пар поднимается.'), ('What will you do with ice tomorrow?','Что ты сделаешь со льдом завтра?','I will put ice in my juice tomorrow.','Я положу лёд в свой сок завтра.'), ('What will happen if you heat ice?','Что произойдёт, если ты нагреешь лёд?','It will melt and change to water.','Он растает и превратится в воду.'), ('Will you be careful near hot water? Why?','Будешь ли ты осторожен рядом с горячей водой? Почему?','Yes, I will be careful because hot water can hurt me.','Да, я буду осторожен, потому что горячая вода может причинить мне боль.')] story += [P('4. Conversation practice','H1Kid'),P('Questions 1-8. Read aloud, then give your own answer.','BodyKid'),Spacer(1,8)] for i,x in enumerate(qas[:8],1): story.append(qa(i,*x)) story.append(PageBreak()) story += [P('Conversation practice','H1Kid'),P('Questions 9-15. Use a clear voice and full sentences.','BodyKid'),Spacer(1,8)] for i,x in enumerate(qas[8:],9): story.append(qa(i,*x)) story.append(PageBreak()) story += [P('5. My speaking checklist','H1Kid'),card([P('Before the exam, I can...','H2Kid'),P('□ name solids, liquids and gases.<br/>□ explain melting, freezing and boiling.<br/>□ say why hot springs are dangerous.<br/>□ use <b>because</b> to give a reason.<br/>□ use Present Simple: “Water freezes.”<br/>□ use Present Continuous: “Steam is rising.”<br/>□ use Future Simple: “I will be careful.”','BodyKid')],colors.HexColor('#E6F7F3'),12),Spacer(1,12)] story += [P('Make your own answers','H2Kid'),P('1. My favourite solid is ________________________________.<br/><br/>2. I can see steam when ________________________________.<br/><br/>3. Tomorrow, I will ________________________________.','BodyKid'),Spacer(1,15)] story += [card([P('Well done!','H2Kid'),P('Keep practising. Short, clear sentences are excellent speaking answers.','BodyKid')],colors.HexColor('#FFF5CF'))] doc=SimpleDocTemplate(str(OUT),pagesize=A4,rightMargin=1.7*cm,leftMargin=1.7*cm,topMargin=1.55*cm,bottomMargin=1.25*cm,title='States of Matter and Hot Springs - ESL Handbook',author='Orris') doc.build(story,onFirstPage=page,onLaterPages=page) print(OUT) PY python "/tmp/workspace/esl_handbook/src/create_handbook.py" ls -lh "/tmp/workspace/esl_handbook/output/States_of_Matter_and_Hot_Springs_ESL_Handbook.pdf"
/usr/share/fonts
/usr/share/fonts/google-noto-vf
~/esl_handbook/src/create_handbook.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/esl_handbook/src/create_handbook.py'
python "/tmp/workspace/esl_handbook/src/create_handbook.py" && python - <<'PY' from pypdf import PdfReader p='/tmp/workspace/esl_handbook/output/States_of_Matter_and_Hot_Springs_ESL_Handbook.pdf' r=PdfReader(p) print('pages',len(r.pages),'size',__import__('os').path.getsize(p)) text='\n'.join(x.extract_text() or '' for x in r.pages) print('chars',len(text),'questions',text.count('Model answer:')) print(text[:1000]) PY ls -lh "/tmp/workspace/esl_handbook/output/States_of_Matter_and_Hot_Springs_ESL_Handbook.pdf"
States of Matter and Hot Springs ESL Handbook
PDF Document · PDF
I changed my mind,now I want all 15 questions and answers from "hot springs"text only
~/
Cambridge English young learners speaking preparation present simple present continuous future simple questions
cat > "/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py" <<'PY' from reportlab.lib.pagesizes import A4 from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, Table, TableStyle, PageBreak, KeepTogether from reportlab.lib import colors from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle from reportlab.lib.enums import TA_CENTER from reportlab.pdfbase import pdfmetrics from reportlab.pdfbase.ttfonts import TTFont from reportlab.lib.units import cm from pathlib import Path OUT=Path('/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf') pdfmetrics.registerFont(TTFont('Noto','/usr/share/fonts/google-noto-vf/NotoSans[wght].ttf')) NAVY=colors.HexColor('#173F5F'); BLUE=colors.HexColor('#20639B'); TEAL=colors.HexColor('#2A9D8F'); GOLD=colors.HexColor('#F4A261'); CORAL=colors.HexColor('#E76F51'); LILAC=colors.HexColor('#F0EBFF'); MINT=colors.HexColor('#E6F7F3'); CREAM=colors.HexColor('#FFF6DF') S=getSampleStyleSheet() for name,size,lead,color,align in [('Title',27,33,NAVY,TA_CENTER),('Sub',12,17,BLUE,TA_CENTER),('H1',19,24,NAVY,0),('H2',13,17,NAVY,0),('Body',10.3,14,colors.HexColor('#233746'),0),('Q',11.1,15,NAVY,0),('RU',9.2,12.4,colors.HexColor('#594177'),0),('A',10.2,14,colors.HexColor('#205A50'),0),('Small',8.8,11.5,colors.HexColor('#233746'),0)]: S.add(ParagraphStyle(name=name,fontName='Noto',fontSize=size,leading=lead,textColor=color,alignment=align,spaceAfter=4)) def P(text,style='Body'): return Paragraph(text,S[style]) def card(items,bg): t=Table([[items]],colWidths=[17.0*cm]) t.setStyle(TableStyle([('BACKGROUND',(0,0),(-1,-1),bg),('BOX',(0,0),(-1,-1),.65,colors.white),('LEFTPADDING',(0,0),(-1,-1),9),('RIGHTPADDING',(0,0),(-1,-1),9),('TOPPADDING',(0,0),(-1,-1),8),('BOTTOMPADDING',(0,0),(-1,-1),8)])) return t def qa(n,q,qr,a,ar): return KeepTogether([card([P(f'{n}. {q}','Q'),P(qr,'RU'),Spacer(1,2),P('<b>Model answer:</b> '+a,'A'),P(ar,'RU')], LILAC if n%2 else MINT),Spacer(1,7)]) def header(c,doc): c.saveState(); w,h=A4 c.setFillColor(NAVY);c.rect(0,h-1.05*cm,w,1.05*cm,fill=1,stroke=0) c.setFont('Noto',9);c.setFillColor(colors.white);c.drawString(1.3*cm,h-.68*cm,'HOT SPRINGS • ESL GRADE 4') c.setFillColor(GOLD);c.circle(w-1.2*cm,h-.52*cm,.22*cm,fill=1,stroke=0) c.setFillColor(colors.HexColor('#61717C'));c.setFont('Noto',8);c.drawCentredString(w/2,.58*cm,f'Cambridge-style speaking practice • {doc.page}') c.restoreState() # Each prompt and answer uses only source information: hot springs, small lakes, hot water, hot rocks, underground heat, steam, warm/cold air, danger and household steam. qas=[ ('What are hot springs?','Что такое горячие источники?','Hot springs are small lakes with hot water.','Горячие источники - это небольшие озёра с горячей водой.'), ('What is the water like in a hot spring?','Какая вода в горячем источнике?','The water is hot.','Вода горячая.'), ('What can heat the water in some hot springs?','Что может нагревать воду в некоторых горячих источниках?','Hot rocks on the ground of the spring heat the water.','Горячие камни на дне источника нагревают воду.'), ('Where can water heat up in other hot springs?','Где вода может нагреваться в других горячих источниках?','The water can heat up under the ground.','Вода может нагреваться под землёй.'), ('What happens when the water is very hot?','Что происходит, когда вода очень горячая?','Some of the water changes to steam.','Часть воды превращается в пар.'), ('Is water in a hot spring a liquid or a gas?','Вода в горячем источнике - это жидкость или газ?','Water is a liquid.','Вода - это жидкость.'), ('Is steam a liquid or a gas?','Пар - это жидкость или газ?','Steam is a gas.','Пар - это газ.'), ('What is happening above very hot water?','Что происходит над очень горячей водой?','Steam is rising above the water.','Пар поднимается над водой.'), ('What happens when hot steam meets warm air?','Что происходит, когда горячий пар встречается с тёплым воздухом?','We cannot see a lot of steam.','Мы не можем увидеть много пара.'), ('What happens when hot steam meets very cold air?','Что происходит, когда горячий пар встречается с очень холодным воздухом?','We can see a lot of steam.','Мы можем увидеть много пара.'), ('Why can hot springs be dangerous?','Почему горячие источники могут быть опасными?','They can be dangerous because the water and steam are hot.','Они могут быть опасными, потому что вода и пар горячие.'), ('Will you be careful near a hot spring?','Будешь ли ты осторожен рядом с горячим источником?','Yes, I will be careful near a hot spring.','Да, я буду осторожен рядом с горячим источником.'), ('When do you see steam in your house?','Когда ты видишь пар дома?','I see steam when hot water is boiling.','Я вижу пар, когда горячая вода кипит.'), ('What causes steam in your house?','Что вызывает пар у тебя дома?','Very hot water causes steam in my house.','Очень горячая вода вызывает пар у меня дома.'), ('What will happen if hot steam meets very cold air?','Что произойдёт, если горячий пар встретится с очень холодным воздухом?','We will see a lot of steam.','Мы увидим много пара.')] story=[Spacer(1,1.15*cm),P('Hot Springs','Title'),P('15 bilingual speaking questions and model answers<br/>ESL Grade 4 • Cambridge exam preparation','Sub'),Spacer(1,16),card([P('THIS HANDBOOK USES ONLY THE “HOT SPRINGS” TEXT','H2'),P('Talk about hot water, rocks, steam, warm air, cold air, safety and steam at home. Language is limited to easy Present Simple, Present Continuous and Future Simple.','Body')],CREAM),Spacer(1,15),P('How to practise','H1'),P('1. Read the English question. 2. Read the Russian translation. 3. Say the model answer. 4. Say it again without looking.','Body'),Spacer(1,10),card([P('Speaking tip','H2'),P('Speak slowly and clearly. Give a full answer, for example: “Hot rocks heat the water.”','Body')],MINT),PageBreak(),P('Questions 1-8','H1'),P('The answers come from the Hot Springs text.','Body'),Spacer(1,6)] for i,x in enumerate(qas[:8],1): story.append(qa(i,*x)) story += [PageBreak(),P('Questions 9-15','H1'),P('Practise saying the answers with confidence.','Body'),Spacer(1,6)] for i,x in enumerate(qas[8:],9):story.append(qa(i,*x)) story += [Spacer(1,6),card([P('My speaking check','H2'),P('□ I can explain what hot springs are. □ I can talk about water and steam. □ I can explain why hot springs are dangerous. □ I can use “will” for the future.','Body')],CREAM)] doc=SimpleDocTemplate(str(OUT),pagesize=A4,leftMargin=1.7*cm,rightMargin=1.7*cm,topMargin=1.5*cm,bottomMargin=1.2*cm,title='Hot Springs Only ESL Speaking Handbook') doc.build(story,onFirstPage=header,onLaterPages=header) print(OUT) PY python "/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py" python - <<'PY' from pypdf import PdfReader from pathlib import Path p=Path('/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf') r=PdfReader(str(p)); text='\n'.join(pg.extract_text() or '' for pg in r.pages) print('pages=',len(r.pages),'bytes=',p.stat().st_size,'model_answers=',text.count('Model answer:')) print('hot_springs=',text.lower().count('hot springs')) assert text.count('Model answer:') == 15 assert len(r.pages)>=3 PY
python - <<'PY' p='/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py' s=open(p,encoding='utf-8').read() repls={'Title':'KTitle','Sub':'KSub','H1':'KH1','H2':'KH2','Body':'KBody','Small':'KSmall'} # Styles only referenced in strings, so token replace adequate for these exact style name literals and tuple values. for a,b in repls.items(): s=s.replace("'"+a+"'","'"+b+"'") open(p,'w',encoding='utf-8').write(s) PY python "/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py" && python - <<'PY' from pypdf import PdfReader from pathlib import Path p=Path('/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf') r=PdfReader(str(p)); text='\n'.join(pg.extract_text() or '' for pg in r.pages) print('pages=',len(r.pages),'bytes=',p.stat().st_size,'model_answers=',text.count('Model answer:')) assert text.count('Model answer:') == 15 assert 'Questions 1-8' in text and 'Questions 9-15' in text PY ls -lh "/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf"
Hot Springs Only ESL Speaking Handbook
PDF Document · PDF
Why have you repeated question 10 and 15 twice?
Replace Question 15 and regenerate the corrected PDF
~/
"What will happen if hot steam meets very…" in ~/esl_handbook/src
~/esl_handbook/src/create_hot_springs_handbook.py
Successfully replaced 1 instance(s) of the string in '/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py'
python "/tmp/workspace/esl_handbook/src/create_hot_springs_handbook.py" && python - <<'PY' from pypdf import PdfReader from pathlib import Path p=Path('/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf') r=PdfReader(str(p)); text='\n'.join(page.extract_text() or '' for page in r.pages) checks=['What will you do if you see very hot water and steam?','I will be careful and stay away from the hot water.'] print('pages:',len(r.pages),'answers:',text.count('Model answer:'),'size:',p.stat().st_size) for v in checks: print(v, v in text) assert len(r.pages)==5 and text.count('Model answer:')==15 and all(v in text for v in checks) assert 'What will happen if hot steam meets very cold air?' not in text PY ls -lh "/tmp/workspace/esl_handbook/output/Hot_Springs_Only_ESL_Speaking_Handbook.pdf"
Hot Springs Only ESL Speaking Handbook
PDF Document · PDF