diff --git a/03_卡木(木)/木果_项目模板/PPT制作/脚本/天恩乖乖绘本.py b/03_卡木(木)/木果_项目模板/PPT制作/脚本/天恩乖乖绘本.py index 730c8245..117983d8 100644 --- a/03_卡木(木)/木果_项目模板/PPT制作/脚本/天恩乖乖绘本.py +++ b/03_卡木(木)/木果_项目模板/PPT制作/脚本/天恩乖乖绘本.py @@ -1,102 +1,152 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- """ -天恩和乖乖 - 二年级绘本风格 PPT 生成脚本 -参考格式:我的植物故事:花草和胡萝卜.pptx +天恩和乖乖 - 二年级绘本风格 PPT(优化版) +参考:我的植物故事、我的水果拼盘之旅 - 黄色底、图片有边框、每图配文字 """ import os from pathlib import Path from pptx import Presentation -from pptx.util import Inches, Pt +from pptx.util import Inches, Pt, Emu from pptx.dml.color import RGBColor +from pptx.enum.dml import MSO_THEME_COLOR DIR_BASE = Path("/Users/karuo/Library/Mobile Documents/com~apple~CloudDocs/Documents/婼瑄/天恩/ppt 202060223") OUT_PATH = DIR_BASE / "我和乖乖的故事.pptx" +# 风格配色(参考黄色底绘本) +BG_YELLOW = RGBColor(255, 250, 230) # 暖黄背景 #FFFAE6 +TITLE_BROWN = RGBColor(139, 90, 43) # 标题棕色 +TEXT_DARK = RGBColor(60, 45, 30) # 正文深色 +BORDER_BROWN = RGBColor(180, 140, 100) # 图片边框暖棕 +ACCENT = RGBColor(218, 165, 32) # 强调色金黄 + + +def set_slide_background(slide, color): + """设置幻灯片背景色""" + background = slide.background + fill = background.fill + fill.solid() + fill.fore_color.rgb = color + + +def add_picture_with_border(slide, img_path, left, top, width, caption=None): + """添加带边框和说明的图片""" + pic = slide.shapes.add_picture(str(img_path), left, top, width=width) + pic.line.color.rgb = BORDER_BROWN + pic.line.width = Pt(3) + if caption: + cap_top = top + pic.height + Pt(6) # 图片下方留小间距 + tb = slide.shapes.add_textbox(left, cap_top, width, Inches(0.4)) + tf = tb.text_frame + tf.word_wrap = True + p = tf.paragraphs[0] + p.text = f"📷 {caption}" + p.font.size = Pt(12) + p.font.color.rgb = TEXT_DARK + p.alignment = 1 + return pic + def ensure_images(): - """获取目录下所有 JPG,按文件名排序""" imgs = sorted(DIR_BASE.glob("*.jpg")) return [str(p) for p in imgs] def add_title_slide(prs): - """第1页:封面""" - layout = prs.slide_layouts[6] # 空白 + """第1页:封面 - 黄色底""" + layout = prs.slide_layouts[6] slide = prs.slides.add_slide(layout) - # 主标题 + set_slide_background(slide, BG_YELLOW) tb = slide.shapes.add_textbox(Inches(0.5), Inches(2), Inches(12.3), Inches(1.2)) - tf = tb.text_frame - p = tf.paragraphs[0] + p = tb.text_frame.paragraphs[0] p.text = "我和乖乖的故事" p.font.size = Pt(44) p.font.bold = True - p.font.color.rgb = RGBColor(60, 120, 180) - p.alignment = 1 # 居中 - # 副标题 + p.font.color.rgb = TITLE_BROWN + p.alignment = 1 tb2 = slide.shapes.add_textbox(Inches(0.5), Inches(3.5), Inches(12.3), Inches(1)) tf2 = tb2.text_frame p2 = tf2.paragraphs[0] p2.text = "汇报人:天恩" p2.font.size = Pt(24) + p2.font.color.rgb = TEXT_DARK p2.alignment = 1 p3 = tf2.add_paragraph() p3.text = "班级:二年级4班" p3.font.size = Pt(24) + p3.font.color.rgb = TEXT_DARK p3.alignment = 1 -def add_content_slide(prs, title, body_lines, img_path=None, img_path2=None): - """通用内容页:标题+正文,可选1-2张图""" +def add_content_slide(prs, title, body_lines, img_info=None): + """内容页:标题+正文+带边框图片+图片说明 + img_info: [(path, caption), ...] 或 [(path, caption)] + """ layout = prs.slide_layouts[6] slide = prs.slides.add_slide(layout) + set_slide_background(slide, BG_YELLOW) left = Inches(0.5) top = Inches(0.4) - tb = slide.shapes.add_textbox(left, top, Inches(12.3), Inches(0.8)) + tb = slide.shapes.add_textbox(left, top, Inches(12.3), Inches(0.75)) p = tb.text_frame.paragraphs[0] p.text = title p.font.size = Pt(28) p.font.bold = True - p.font.color.rgb = RGBColor(60, 120, 180) - body_top = Inches(1.3) - txt_width = Inches(6) if (img_path or img_path2) else Inches(12.3) - tb2 = slide.shapes.add_textbox(left, body_top, txt_width, Inches(5)) + p.font.color.rgb = TITLE_BROWN + body_top = Inches(1.2) + if img_info and len(img_info) > 0: + txt_width = Inches(6) + else: + txt_width = Inches(12.3) + tb2 = slide.shapes.add_textbox(left, body_top, txt_width, Inches(5.2)) tf = tb2.text_frame tf.word_wrap = True for i, line in enumerate(body_lines): p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() p.text = line - p.font.size = Pt(20) - p.space_after = Pt(8) - if img_path2 and os.path.exists(img_path2): - slide.shapes.add_picture(img_path, Inches(6.8), Inches(1.5), width=Inches(2.7)) - slide.shapes.add_picture(img_path2, Inches(9.8), Inches(1.5), width=Inches(2.7)) - elif img_path and os.path.exists(img_path): - slide.shapes.add_picture(img_path, Inches(6.8), Inches(1.5), width=Inches(5.8)) + p.font.size = Pt(19) + p.font.color.rgb = TEXT_DARK + p.space_after = Pt(6) + if img_info and len(img_info) >= 1: + first = img_info[0] + img_path, caption = (first[0], first[1]) if isinstance(first, (list, tuple)) else (first, "") + if os.path.exists(img_path): + if len(img_info) == 2: + add_picture_with_border(slide, img_path, Inches(6.6), Inches(1.2), Inches(2.8), caption) + sec = img_info[1] + img_path2, caption2 = (sec[0], sec[1]) if isinstance(sec, (list, tuple)) else (sec, "") + if os.path.exists(img_path2): + add_picture_with_border(slide, img_path2, Inches(9.6), Inches(1.2), Inches(2.8), caption2) + else: + add_picture_with_border(slide, img_path, Inches(6.6), Inches(1.2), Inches(5.8), caption) -def add_story_slide(prs, title, story_text, img_path=None): - """故事页:左文右图""" +def add_story_slide(prs, title, story_lines, img_info=None): + """故事页:左文右图,图带边框和说明""" layout = prs.slide_layouts[6] slide = prs.slides.add_slide(layout) + set_slide_background(slide, BG_YELLOW) tb = slide.shapes.add_textbox(Inches(0.5), Inches(0.4), Inches(12.3), Inches(0.7)) tb.text_frame.paragraphs[0].text = title tb.text_frame.paragraphs[0].font.size = Pt(26) tb.text_frame.paragraphs[0].font.bold = True - tb.text_frame.paragraphs[0].font.color.rgb = RGBColor(60, 120, 180) - txt_width = Inches(6) if img_path else Inches(12.3) - tb2 = slide.shapes.add_textbox(Inches(0.5), Inches(1.2), txt_width, Inches(5)) + tb.text_frame.paragraphs[0].font.color.rgb = TITLE_BROWN + txt_width = Inches(6) if img_info else Inches(12.3) + tb2 = slide.shapes.add_textbox(Inches(0.5), Inches(1.15), txt_width, Inches(5.5)) tf = tb2.text_frame tf.word_wrap = True - lines = [x.strip() for x in story_text.split("\n") if x.strip()] - for i, line in enumerate(lines): + for i, line in enumerate(story_lines): p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() p.text = line - p.font.size = Pt(20) - p.space_after = Pt(6) - if img_path and os.path.exists(img_path): - slide.shapes.add_picture(img_path, Inches(6.8), Inches(1.5), width=Inches(5.8)) + p.font.size = Pt(19) + p.font.color.rgb = TEXT_DARK + p.space_after = Pt(5) + if img_info: + img_path, caption = img_info + if os.path.exists(img_path): + add_picture_with_border(slide, img_path, Inches(6.6), Inches(1.2), Inches(5.8), caption) def main(): @@ -105,7 +155,8 @@ def main(): prs.slide_width = Inches(13.333) prs.slide_height = Inches(7.5) add_title_slide(prs) - # 第2页 + + # 第2页:这是我和乖乖! add_content_slide( prs, "这是我和乖乖!", @@ -114,23 +165,35 @@ def main(): "每天放学回家,乖乖都会在门口等我,摇着尾巴欢迎我。", "我们一起玩耍、一起散步,乖乖让我的生活变得更快乐!", ], - imgs[0] if len(imgs) > 0 else None, + [(imgs[0], "这张图:我和乖乖的合影")] if imgs else None, ) - # 第3页 + + # 第3页:乖乖是怎么来到我家的? add_story_slide( prs, "乖乖是怎么来到我家的?", - "乖乖是爸爸妈妈送给我的惊喜。\n第一次见到它的时候,它小小的、毛茸茸的,一双黑溜溜的眼睛望着我。\n从那天起,我们就成了形影不离的好伙伴!", - imgs[1] if len(imgs) > 1 else None, + [ + "乖乖是爸爸妈妈送给我的惊喜。", + "第一次见到它的时候,它小小的、毛茸茸的,一双黑溜溜的眼睛望着我。", + "从那天起,我们就成了形影不离的好伙伴!", + ], + (imgs[1], "乖乖刚来我家的样子") if len(imgs) > 1 else None, # 单图用元组 ) - # 第4页 + + # 第4页:我和乖乖每天做什么? add_story_slide( prs, "我和乖乖每天做什么?", - "早上,乖乖会叫醒我起床。\n放学后,我们一起在小区里跑步、追球。\n乖乖最喜欢我摸它的脑袋,每次摸它,它都会舒服地眯起眼睛。\n我们还会一起看绘本,乖乖趴在我身边,好像在听故事呢!", - imgs[2] if len(imgs) > 2 else None, + [ + "早上,乖乖会叫醒我起床。", + "放学后,我们一起在小区里跑步、追球。", + "乖乖最喜欢我摸它的脑袋,每次摸它,它都会舒服地眯起眼睛。", + "我们还会一起看绘本,乖乖趴在我身边,好像在听故事呢!", + ], + (imgs[2], "我和乖乖一起玩") if len(imgs) > 2 else None, # 单图用元组 ) - # 第5页 + + # 第5页:乖乖最可爱的地方 add_content_slide( prs, "乖乖最可爱的地方", @@ -139,10 +202,25 @@ def main(): "它特别聪明,听得懂「坐下」「握手」这些口令。", "乖乖还很懂事,我写作业的时候它会安静地陪着我。", ], - imgs[3] if len(imgs) > 3 else None, - imgs[4] if len(imgs) > 4 else None, + [ + (imgs[3], "乖乖的可爱瞬间"), + (imgs[4], "乖乖在等我"), + ] if len(imgs) > 4 else ([(imgs[3], "乖乖的可爱瞬间")] if len(imgs) > 3 else None), ) - # 第6页 - 小诗 + + # 第6页:更多和乖乖的快乐时光 + add_content_slide( + prs, + "更多和乖乖的快乐时光", + [ + "我们一起出门散步,乖乖总是跑在我前面。", + "下雨天,乖乖会趴在窗边陪我一起看雨。", + "乖乖是我最好的朋友,有它陪伴的每一天都很开心!", + ], + [(imgs[5], "散步时光")] if len(imgs) > 5 else None, + ) + + # 第7页:我为乖乖写了一首小诗 add_content_slide( prs, "我为乖乖写了一首小诗", @@ -153,28 +231,49 @@ def main(): "一起奔跑,一起玩耍,", "有乖乖的日子,每天都很快乐!", ], - imgs[5] if len(imgs) > 5 else None, + [(imgs[6], "乖乖和我的日常")] if len(imgs) > 6 else None, ) - # 第7页 - 结尾 + + # 第8页:更多图片展示 + if len(imgs) > 7: + add_content_slide( + prs, + "我们的珍贵回忆", + [ + "这些照片记录了我和乖乖在一起的美好时光。", + "每一张都是我们友谊的见证!", + ], + [ + (imgs[7], "回忆一"), + (imgs[8], "回忆二"), + ] if len(imgs) > 8 else [(imgs[7], "珍贵回忆")], + ) + + # 结尾页 layout = prs.slide_layouts[6] slide = prs.slides.add_slide(layout) - tb = slide.shapes.add_textbox(Inches(0.5), Inches(2.2), Inches(12.3), Inches(2)) + set_slide_background(slide, BG_YELLOW) + tb = slide.shapes.add_textbox(Inches(0.5), Inches(2), Inches(12.3), Inches(2.5)) tf = tb.text_frame tf.paragraphs[0].text = "我的故事讲完啦,希望大家喜欢!" tf.paragraphs[0].font.size = Pt(28) tf.paragraphs[0].font.bold = True + tf.paragraphs[0].font.color.rgb = TITLE_BROWN tf.paragraphs[0].alignment = 1 p2 = tf.add_paragraph() p2.text = "你们家里也有小动物好朋友吗?" p2.font.size = Pt(22) + p2.font.color.rgb = TEXT_DARK p2.alignment = 1 p3 = tf.add_paragraph() p3.text = "谢谢大家!" p3.font.size = Pt(26) p3.font.bold = True + p3.font.color.rgb = TITLE_BROWN p3.alignment = 1 + prs.save(str(OUT_PATH)) - print("✅ PPT 已生成:", OUT_PATH) + print("✅ PPT 已优化生成:", OUT_PATH) if __name__ == "__main__": diff --git a/运营中枢/工作台/gitea_push_log.md b/运营中枢/工作台/gitea_push_log.md index 785ac85c..acd631aa 100644 --- a/运营中枢/工作台/gitea_push_log.md +++ b/运营中枢/工作台/gitea_push_log.md @@ -105,3 +105,4 @@ | 2026-02-23 07:18:01 | 🔄 卡若AI 同步 2026-02-23 07:17 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-23 10:25:20 | 🔄 卡若AI 同步 2026-02-23 10:25 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 8 个 | | 2026-02-23 14:51:49 | 🔄 卡若AI 同步 2026-02-23 14:51 | 更新:卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 8 个 | +| 2026-02-23 14:56:38 | 🔄 卡若AI 同步 2026-02-23 14:56 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 8 个 | diff --git a/运营中枢/工作台/代码管理.md b/运营中枢/工作台/代码管理.md index 69ecf873..7cc81796 100644 --- a/运营中枢/工作台/代码管理.md +++ b/运营中枢/工作台/代码管理.md @@ -108,3 +108,4 @@ | 2026-02-23 07:18:01 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-23 07:17 | 更新:金仓、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-23 10:25:20 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-23 10:25 | 更新:水桥平台对接、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | | 2026-02-23 14:51:49 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-23 14:51 | 更新:卡木、总索引与入口、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) | +| 2026-02-23 14:56:38 | 成功 | 成功 | 🔄 卡若AI 同步 2026-02-23 14:56 | 更新:卡木、运营中枢工作台 | 排除 >20MB: 8 个 | [仓库](http://open.quwanzhi.com:3000/fnvtk/karuo-ai) [百科](http://open.quwanzhi.com:3000/fnvtk/karuo-ai/wiki) |