#!/usr/bin/env python3 """Презентация о Казахстане — чистый PPTX без кривых XML-анимаций.""" from pptx import Presentation from pptx.util import Inches, Pt, Emu from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN, MSO_ANCHOR from pptx.enum.shapes import MSO_SHAPE from pptx.oxml.ns import qn import lxml.etree as etree # ── Colors ── INK = RGBColor(0x0F, 0x12, 0x18) CYAN = RGBColor(0x00, 0xE5, 0xFF) GOLD = RGBColor(0xE8, 0xB7, 0x30) WHITE = RGBColor(0xFF, 0xFF, 0xFF) GRAY = RGBColor(0x5B, 0x65, 0x73) BG_DARK = RGBColor(0x14, 0x1C, 0x28) prs = Presentation() prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) W = prs.slide_width H = prs.slide_height BLANK_LAYOUT = prs.slide_layouts[6] def set_slide_transition(slide, transition_type='push', speed='med', advance_ms=None): """Set slide transition effect.""" timing = slide._element.find(qn('p:transition')) if timing is None: timing = etree.SubElement(slide._element, qn('p:transition')) transitions = { 'push': ('push', {'advClick': '1'}), 'fade': ('fade', {'advClick': '1'}), 'wipe': ('wipe', {'dir': 'd', 'advClick': '1'}), 'cover': ('cover', {'dir': 'l', 'advClick': '1'}), 'cut': ('cut', {'advClick': '1'}), 'dissolve': ('dissolve', {'advClick': '1'}), 'zoom': ('zoom', {'advClick': '1'}), } tag_name, attrs = transitions.get(transition_type, transitions['push']) el = etree.SubElement(timing, qn(f'p:{tag_name}')) for k, v in attrs.items(): el.set(k, v) if advance_ms: timing.set('advTm', str(advance_ms)) def add_bg(slide, color): bg = slide.background fill = bg.fill fill.solid() fill.fore_color.rgb = color def add_text(slide, text, left, top, width, height, font_size=24, bold=False, color=INK, align=PP_ALIGN.LEFT, font_name='Calibri'): txBox = slide.shapes.add_textbox(left, top, width, height) tf = txBox.text_frame tf.word_wrap = True p = tf.paragraphs[0] p.text = text p.font.size = Pt(font_size) p.font.bold = bold p.font.color.rgb = color p.font.name = font_name p.alignment = align return txBox def add_box(slide, left, top, width, height, fill_color=BG_DARK, border_color=None): shape = slide.shapes.add_shape( MSO_SHAPE.ROUNDED_RECTANGLE, left, top, width, height ) shape.fill.solid() shape.fill.fore_color.rgb = fill_color if border_color: shape.line.color.rgb = border_color shape.line.width = Pt(2) else: shape.line.fill.background() return shape def add_circle(slide, left, top, size, color): c = slide.shapes.add_shape(MSO_SHAPE.OVAL, left, top, size, size) c.fill.solid() c.fill.fore_color.rgb = color c.line.fill.background() return c def add_rect(slide, left, top, width, height, color): r = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height) r.fill.solid() r.fill.fore_color.rgb = color r.line.fill.background() return r # ══════════════════════════════════════════════════════════════ # SLIDE 1 — Title # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, BG_DARK) set_slide_transition(s, 'zoom') add_circle(s, Inches(9.5), Inches(0.8), Inches(4.5), RGBColor(0x00, 0x3D, 0x5C)) add_circle(s, Inches(10.2), Inches(1.5), Inches(3), CYAN) add_circle(s, Inches(-0.5), Inches(5.5), Inches(3), RGBColor(0x00, 0x3D, 0x5C)) add_circle(s, Inches(0), Inches(6), Inches(2), GOLD) add_text(s, '🇰🇿', Inches(1), Inches(1.2), Inches(2), Inches(1.5), font_size=80, color=WHITE) add_text(s, 'КАЗАХСТАН', Inches(1), Inches(2.8), Inches(8), Inches(1.5), font_size=72, bold=True, color=WHITE) add_text(s, 'Сердце Евразии — девятая по территории страна мира', Inches(1), Inches(4.3), Inches(8), Inches(0.8), font_size=24, color=GRAY) stats = [('2.7 млн км²', 'Площадь'), ('20 млн', 'Население'), ('130+', 'Народов'), ('1 космодром', 'Байконур')] for i, (val, lbl) in enumerate(stats): x = Inches(1 + i * 3) y = Inches(5.6) add_box(s, x, y, Inches(2.7), Inches(1.2), RGBColor(0x1C, 0x26, 0x36)) add_text(s, val, x + Inches(0.2), y + Inches(0.1), Inches(2.3), Inches(0.6), font_size=24, bold=True, color=CYAN) add_text(s, lbl, x + Inches(0.2), y + Inches(0.65), Inches(2.3), Inches(0.4), font_size=13, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 2 — Geography # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, WHITE) set_slide_transition(s, 'push') add_rect(s, 0, 0, W, Inches(1.4), BG_DARK) add_text(s, 'ГЕОГРАФИЯ', Inches(0.8), Inches(0.3), Inches(8), Inches(0.8), font_size=36, bold=True, color=CYAN) add_text(s, 'От каспийских берегов до алтайских гор', Inches(0.8), Inches(1.4), Inches(8), Inches(0.5), font_size=16, color=GRAY) geo = [ ('🏔️', 'Горы', 'Тянь-Шань, Чу-Илийские горы, Алтай.\nВысшая точка — Хан-Тенгри (7010 м)'), ('🌊', 'Каспийское море', 'Крупнейшее озеро мира.\nПобережье тянется на 1894 км'), ('🏜️', 'Степи', 'Бескрайние равнины —\nисторическая родина кочевников'), ('🌾', 'Озёра', 'Балхаш, Алаколь, Маркаколь —\nболее 45 000 озёр'), ] for i, (em, nm, ds) in enumerate(geo): col, row = i % 2, i // 2 x = Inches(0.8 + col * 6.2) y = Inches(2.2 + row * 2.5) add_box(s, x, y, Inches(5.6), Inches(2.2), RGBColor(0xF5, 0xF7, 0xFA)) add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7), font_size=38) add_text(s, nm, x + Inches(1.3), y + Inches(0.2), Inches(4), Inches(0.5), font_size=22, bold=True, color=INK) add_text(s, ds, x + Inches(1.3), y + Inches(0.75), Inches(4), Inches(1.2), font_size=14, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 3 — Facts # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, BG_DARK) set_slide_transition(s, 'fade') add_text(s, 'ЦИФРЫ И ФАКТЫ', Inches(0.8), Inches(0.6), Inches(10), Inches(1), font_size=40, bold=True, color=WHITE) add_text(s, 'Казахстан в цифрах', Inches(0.8), Inches(1.4), Inches(6), Inches(0.5), font_size=18, color=GRAY) facts = [('9', 'по величине\nв мире'), ('1991', 'год\nнезависимости'), ('70+', 'тонн золота\nв год'), ('1', 'космодром\nБайконур'), ('3', 'столицы\nв истории')] for i, (num, txt) in enumerate(facts): x = Inches(0.5 + i * 2.5) add_box(s, x, Inches(2.5), Inches(2.2), Inches(3.5), RGBColor(0x1C, 0x26, 0x36), CYAN) add_text(s, num, x + Inches(0.2), Inches(2.9), Inches(1.8), Inches(1.2), font_size=52, bold=True, color=CYAN, align=PP_ALIGN.CENTER) add_text(s, txt, x + Inches(0.2), Inches(4.2), Inches(1.8), Inches(1.4), font_size=14, color=GRAY, align=PP_ALIGN.CENTER) add_rect(s, Inches(0.8), Inches(6.5), Inches(11.7), Inches(0.04), CYAN) # ══════════════════════════════════════════════════════════════ # SLIDE 4 — Culture # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, RGBColor(0xF0, 0xF4, 0xF8)) set_slide_transition(s, 'cover') add_rect(s, 0, 0, W, Inches(1.4), BG_DARK) add_text(s, 'КУЛЬТУРА И ТРАДИЦИИ', Inches(0.8), Inches(0.3), Inches(10), Inches(0.8), font_size=36, bold=True, color=GOLD) culture = [ ('🦅', 'Беркутчи', 'Соколиная охота с орлами — наследие ЮНЕСКО'), ('🎪', 'Юрта', 'Легко разборное жилище — символ свободы'), ('🎶', 'Домбра', 'Двухструнный инструмент — душа кюев'), ('🤼', 'Байге', 'Конные скачки на длинные дистанции'), ('🎭', 'Наурыз', 'Праздник весны — 7 блюд, 22 марта'), ('📖', 'Абай', 'Великий поэт, философ, мыслитель'), ] for i, (em, nm, ds) in enumerate(culture): col, row = i % 3, i // 3 x = Inches(0.8 + col * 4.1) y = Inches(1.8 + row * 2.6) add_box(s, x, y, Inches(3.7), Inches(2.2), WHITE) add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7), font_size=36) add_text(s, nm, x + Inches(1.2), y + Inches(0.2), Inches(2.2), Inches(0.5), font_size=20, bold=True, color=INK) add_text(s, ds, x + Inches(0.3), y + Inches(1), Inches(3.2), Inches(1), font_size=14, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 5 — Cities # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, WHITE) set_slide_transition(s, 'push') add_text(s, 'ГОРОДА', Inches(0.8), Inches(0.6), Inches(10), Inches(1), font_size=40, bold=True, color=INK) add_text(s, 'Мегаполисы Казахстана', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5), font_size=18, color=GRAY) cities = [ ('АСТАНА', 'Столица с 1997 г.\nБайтерек, Хан-Шатыр,\nфонтаны «Танкіри»', CYAN), ('АЛМАТЫ', 'Бывшая столица\nГоры, Медеу, Шымбулак,\nалматинские яблоки', GOLD), ('ШЫМКЕНТ', 'Третий город\nЮжные ворота,\nжаркий климат', RGBColor(0x2A, 0x9D, 0x8F)), ] for i, (nm, ds, clr) in enumerate(cities): x = Inches(0.8 + i * 4.1) add_box(s, x, Inches(2.2), Inches(3.7), Inches(4.5), RGBColor(0xF5, 0xF7, 0xFA)) add_rect(s, x, Inches(2.2), Inches(3.7), Inches(0.12), clr) add_text(s, nm, x + Inches(0.4), Inches(2.7), Inches(3), Inches(0.6), font_size=28, bold=True, color=INK) add_text(s, ds, x + Inches(0.4), Inches(3.5), Inches(3), Inches(2.5), font_size=15, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 6 — Food # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, RGBColor(0xFD, 0xF8, 0xEF)) set_slide_transition(s, 'wipe') add_text(s, 'КУХНЯ', Inches(0.8), Inches(0.6), Inches(10), Inches(1), font_size=40, bold=True, color=INK) add_text(s, 'Вкус степи — просто и сытно', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5), font_size=18, color=GRAY) foods = [ ('🥟', 'Бешбармак', 'Главное блюдо — мясо с лапшой.\n«Пять пальцев» — едят руками'), ('🫕', 'Кумыс', 'Ферментированное кобылье\nмолоко — тонизирующий напиток'), ('🫓', 'Баурсаки', 'Жареные тестовые шарики\nна каждом празднике'), ('🍵', 'Чай с молоком', 'С солью — гостям наливают\nпервым, знак уважения'), ] for i, (em, nm, ds) in enumerate(foods): col, row = i % 2, i // 2 x = Inches(0.8 + col * 6.2) y = Inches(2.2 + row * 2.4) add_box(s, x, y, Inches(5.6), Inches(2), WHITE, GOLD) add_text(s, em, x + Inches(0.3), y + Inches(0.15), Inches(1), Inches(0.7), font_size=38) add_text(s, nm, x + Inches(1.3), y + Inches(0.2), Inches(3.5), Inches(0.5), font_size=22, bold=True, color=INK) add_text(s, ds, x + Inches(1.3), y + Inches(0.8), Inches(3.8), Inches(1), font_size=14, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 7 — History # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, WHITE) set_slide_transition(s, 'dissolve') add_text(s, 'ИСТОРИЯ', Inches(0.8), Inches(0.6), Inches(10), Inches(1), font_size=40, bold=True, color=INK) add_text(s, 'От кочевников до космоса', Inches(0.8), Inches(1.3), Inches(6), Inches(0.5), font_size=18, color=GRAY) add_rect(s, Inches(1.6), Inches(2.2), Inches(0.06), Inches(4.8), CYAN) timeline = [ ('1465', 'Казахское ханство', 'Формирование народа и кочевого уклада'), ('XVIII', 'Российская империя', 'Присоединение, оседлый образ жизни'), ('1955', 'Байконур', 'Запуск первого космодрома в мире'), ('1961', 'Гагарин', 'Первый полёт в космос с Байконура'), ('1991', 'Независимость', '16 декабря — последняя республика СССР'), ('1997', 'Новая столица', 'Перенос столицы в Акмолу (Астану)'), ] for i, (yr, ttl, dsc) in enumerate(timeline): y = Inches(2.2 + i * 0.8) dot = add_circle(s, Inches(1.4), y + Inches(0.08), Inches(0.45), CYAN if i % 2 == 0 else GOLD) add_text(s, yr, Inches(2.2), y, Inches(1.2), Inches(0.6), font_size=16, bold=True, color=INK) add_text(s, f'{ttl} — {dsc}', Inches(3.5), y, Inches(9), Inches(0.6), font_size=14, color=GRAY) # ══════════════════════════════════════════════════════════════ # SLIDE 8 — Thank You # ══════════════════════════════════════════════════════════════ s = prs.slides.add_slide(BLANK_LAYOUT) add_bg(s, BG_DARK) set_slide_transition(s, 'zoom') add_circle(s, Inches(10), Inches(0.5), Inches(3), RGBColor(0x00, 0x3D, 0x5C)) add_circle(s, Inches(10.5), Inches(1), Inches(2), CYAN) add_circle(s, Inches(0.5), Inches(5), Inches(2.5), RGBColor(0x00, 0x3D, 0x5C)) add_circle(s, Inches(1), Inches(5.5), Inches(1.5), GOLD) add_text(s, '🇰🇿', Inches(5.5), Inches(1), Inches(2.5), Inches(1.5), font_size=80, color=WHITE, align=PP_ALIGN.CENTER) add_text(s, 'СПАСИБО ЗА ВНИМАНИЕ!', Inches(1), Inches(2.8), Inches(11.3), Inches(1.2), font_size=48, bold=True, color=WHITE, align=PP_ALIGN.CENTER) add_text(s, 'Казахстан — древние традиции и современные мегаполисы,\nбескрайние степи и высокие горы', Inches(2), Inches(4.2), Inches(9.3), Inches(1.2), font_size=18, color=GRAY, align=PP_ALIGN.CENTER) # ── Save ── out = '/srv/opencode/workspaces/users/literally.ww/kazakhstan/Казахстан_Презентация.pptx' prs.save(out) print(f'✅ Saved: {out}') print(f' Slides: {len(prs.slides)}')