diff --git a/.gitignore b/.gitignore index 85be072..4b104f3 100644 --- a/.gitignore +++ b/.gitignore @@ -28,6 +28,12 @@ temp/ # 大型设计源文件,不入库 new_feedback/第三轮反馈20261012/UI外发版10.09.psd +# 淘宝开放平台自动生成的 Java SDK(对应已废弃的 AppKey 35479221,当前架构不引 SDK) +/sdk-java-35479221/ + +# 提案 PPT 生成时用的截图素材(临时产物,可重新截取) +/temp/ppt_assets/ + # graphify 本地缓存与日期快照(可重建,无需入库) graphify-out/cache/ graphify-out/[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]/ diff --git a/tools/build_taobao_proposal_dark.py b/tools/build_taobao_proposal_dark.py new file mode 100644 index 0000000..add8117 --- /dev/null +++ b/tools/build_taobao_proposal_dark.py @@ -0,0 +1,328 @@ +# -*- coding: utf-8 -*- +"""AI智能测肤淘宝小程序产品方案 —— 深色版(内容与模板版一致,全新视觉)。 + +设计系统: +- 画布 26.67x15in(与模板一致,沿用已验证的版式坐标) +- BG 深墨蓝 0E1E29 / 卡片 162C3A / 强调 青绿 38CDB8(水润科技感) +- 文字 F2F6F9 / 次级 9FB1BF / 弱化 5E7482 +- 字体:标题正文 微软雅黑,大数字 Bahnschrift(Windows 自带 DIN 系) +- 浅色界面截图直接置于深底,形成强对比 +""" +from pathlib import Path + +from pptx import Presentation +from pptx.util import Inches, Pt +from pptx.dml.color import RGBColor +from pptx.enum.shapes import MSO_SHAPE +from pptx.enum.text import PP_ALIGN, MSO_ANCHOR +from pptx.oxml.ns import qn +from lxml import etree + +# 路径相对仓库根,换机器无需改(截图素材在 temp/ppt_assets,属于本地临时产物,不入库) +_ROOT = Path(__file__).resolve().parents[1] +OUT = str(_ROOT / "智能测肤-淘宝小程序产品方案-深色版.pptx") +AST = str(_ROOT / "temp" / "ppt_assets") + +BG = RGBColor(0x0E, 0x1E, 0x29) +CARD = RGBColor(0x16, 0x2C, 0x3A) +PANEL = RGBColor(0x13, 0x25, 0x33) +ACC = RGBColor(0x38, 0xCD, 0xB8) +TXT = RGBColor(0xF2, 0xF6, 0xF9) +MUT = RGBColor(0x9F, 0xB1, 0xBF) +FAINT = RGBColor(0x6E, 0x84, 0x93) +LINE = RGBColor(0x27, 0x42, 0x55) + +NUM_F = "Bahnschrift" + + +def set_font(run, size, bold=False, color=TXT, latin="Segoe UI", ea="微软雅黑"): + f = run.font + f.size = Pt(size) + f.bold = bold + f.color.rgb = color + f.name = latin + rPr = run._r.get_or_add_rPr() + for tag, face in ((qn("a:latin"), latin), (qn("a:ea"), ea)): + e = rPr.find(tag) + if e is None: + e = etree.SubElement(rPr, tag) + e.set("typeface", face) + + +def tb(slide, x, y, w, h, paras, anchor=MSO_ANCHOR.TOP): + box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) + tf = box.text_frame + tf.word_wrap = True + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = anchor + for i, pd in enumerate(paras): + p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() + p.alignment = pd.get("align", PP_ALIGN.LEFT) + if pd.get("sa"): + p.space_after = Pt(pd["sa"]) + r = p.add_run() + r.text = pd["t"] + set_font(r, pd.get("size", 26), pd.get("bold", False), pd.get("color", TXT), + pd.get("latin", "Segoe UI")) + return box + + +def rect(slide, x, y, w, h, fill, line=None, shape=MSO_SHAPE.RECTANGLE, radius=None): + sp = slide.shapes.add_shape(shape, Inches(x), Inches(y), Inches(w), Inches(h)) + if radius is not None: + sp.adjustments[0] = radius + sp.fill.solid() + sp.fill.fore_color.rgb = fill + if line: + sp.line.color.rgb = line + sp.line.width = Pt(1) + else: + sp.line.fill.background() + sp.shadow.inherit = False + return sp + + +def card(slide, x, y, w, h, fill=CARD, line=None): + return rect(slide, x, y, w, h, fill, line, MSO_SHAPE.ROUNDED_RECTANGLE, 0.055) + + +def glow(slide, x, y, d, hexv="38CDB8", alpha=13): + """低透明度圆形光晕(XML alpha 注入)""" + sp = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x), Inches(y), Inches(d), Inches(d)) + sp.fill.solid() + sp.fill.fore_color.rgb = RGBColor.from_string(hexv) + sp.line.fill.background() + sp.shadow.inherit = False + sf = sp.fill._xPr.find(qn("a:solidFill")) + clr = sf.find(qn("a:srgbClr")) + a = etree.SubElement(clr, qn("a:alpha")) + a.set("val", str(alpha * 1000)) + return sp + + +def circle(slide, x, y, d, label, fill=ACC, color=BG, size=26, latin=NUM_F): + sp = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x), Inches(y), Inches(d), Inches(d)) + sp.fill.solid() + sp.fill.fore_color.rgb = fill + sp.line.fill.background() + sp.shadow.inherit = False + tf = sp.text_frame + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = MSO_ANCHOR.MIDDLE + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + r = p.add_run() + r.text = label + set_font(r, size, True, color, latin) + return sp + + +def pic(slide, path, x, y, w, h): + p = slide.shapes.add_picture(path, Inches(x), Inches(y), Inches(w), Inches(h)) + p.line.color.rgb = LINE + p.line.width = Pt(1.25) + return p + + +def header(slide, num, title): + tb(slide, 0.55, 0.22, 2.2, 1.5, [dict(t=num, size=96, color=ACC, latin=NUM_F)]) + tb(slide, 2.75, 0.88, 18, 0.8, [dict(t=title, size=44, bold=True)]) + + +def build(): + prs = Presentation() + prs.slide_width = Inches(26.67) + prs.slide_height = Inches(15) + blank = prs.slide_layouts[6] + + def page(): + s = prs.slides.add_slide(blank) + rect(s, 0, 0, 26.67, 15, BG) + return s + + # ---- P1 封面 ---- + s = page() + glow(s, 18.5, 8.2, 14, alpha=12) + glow(s, -3.5, -3.5, 11, alpha=9) + tb(s, 2.42, 4.35, 22, 0.6, [dict(t="淘宝开放平台 · 小程序产品方案(自研类型)", size=28, color=ACC)]) + tb(s, 2.42, 5.25, 22.5, 1.7, [dict(t="AI 智能测肤小程序方案", size=96, bold=True)]) + tb(s, 2.42, 7.9, 20, 0.9, [dict(t="西安巨子生物基因技术股份有限公司", size=44, color=MUT)]) + tb(s, 2.42, 12.9, 20, 0.5, [dict(t="在线肌肤检测 · 个性化护理建议 · 精准商品推荐", size=24, color=FAINT)]) + + # ---- P2 公司背景与产品定位 ---- + s = page() + tb(s, 2.75, 0.88, 18, 0.8, [dict(t="公司背景与产品定位", size=44, bold=True)]) + glow(s, 20.5, -4, 10, alpha=8) + pic(s, f"{AST}\\report-full.png", 2.7, 2.45, 3.34, 10.29) + tb(s, 1.4, 12.95, 6.0, 0.5, [dict(t="AI 肌肤检测报告(界面示意)", size=24, color=FAINT, align=PP_ALIGN.CENTER)]) + tb(s, 7.6, 2.75, 18, 0.5, [dict(t="西安巨子生物基因技术股份有限公司 · 港交所上市 · 重组胶原蛋白", size=24, color=ACC)]) + tb(s, 7.6, 4.6, 18.5, 2.1, [dict(t="让每位消费者三分钟获得", size=40, bold=True, sa=6), + dict(t="一份可信赖的肌肤报告与护理方案", size=40, bold=True)]) + rows = [ + ("1", "测得准", "AI 图像分析输出综合评分、肌龄、七项分项与三维指标,可解释、可回看"), + ("2", "推得对", "按展示肌龄分档推荐适配精华,报告页直达商品,缩短决策路径"), + ("3", "留得住", "历史报告沉淀与复访提醒,支撑会员运营与复购"), + ] + for i, (n, lead, desc) in enumerate(rows): + y = 7.5 + i * 2.0 + circle(s, 7.6, y + 0.12, 0.72, n, color=BG, size=28) + tb(s, 8.8, y, 15.3, 1.8, [dict(t=lead, size=30, bold=True, sa=6), dict(t=desc, size=24, color=MUT)]) + + # ---- P3 目录 ---- + s = page() + glow(s, 20, 9.5, 11, alpha=8) + tb(s, 2.42, 2.6, 8, 1.3, [dict(t="目录", size=72, bold=True)]) + rect(s, 8.3, 2.6, 0.028, 10.2, LINE) + toc = [("01", "市场调研分析"), ("02", "小程序方案及价值"), ("03", "商业化运营规划及目标")] + for i, (n, t) in enumerate(toc): + y = 3.1 + i * 3.2 + circle(s, 9.6, y, 1.35, n, color=BG, size=40) + tb(s, 11.8, y + 0.22, 14, 0.9, [dict(t=t, size=44, bold=True)]) + + # ---- P4 01 市场调研分析 ---- + s = page() + header(s, "01", "市场调研分析") + cols = [ + ("商家痛点", "选品讲解靠经验,「适不适合我」难讲清;直播与详情页流量难沉淀为可复访的服务。"), + ("消费者诉求", "想先弄清肤质与肌龄再决策;怕踩雷、要依据,希望报告能看懂、直接告诉我买什么。"), + ] + xs = [1.5, 9.72, 17.94] + for i, (t, body) in enumerate(cols): + card(s, xs[i] - 0.35, 2.35, 7.9, 6.6) + tb(s, xs[i], 2.75, 7.2, 0.6, [dict(t=t, size=32, bold=True, color=ACC)]) + tb(s, xs[i], 3.6, 7.1, 5.0, [dict(t=body, size=26, color=MUT)]) + card(s, xs[2] - 0.35, 2.35, 7.9, 6.6, fill=PANEL, line=LINE) + tb(s, xs[2], 2.75, 7.2, 0.6, [dict(t="市场与商业化空间", size=32, bold=True, color=ACC)]) + tb(s, xs[2], 3.6, 7.2, 1.0, [dict(t="4357亿", size=54, bold=True, color=ACC, latin=NUM_F)]) + tb(s, xs[2], 4.65, 7.2, 0.5, [dict(t="2024 年全国化妆品类零售额", size=22, color=MUT)]) + tb(s, xs[2], 5.5, 7.2, 1.0, [dict(t="1069亿", size=54, bold=True, color=TXT, latin=NUM_F)]) + tb(s, xs[2], 6.55, 7.2, 0.5, [dict(t="抗衰护肤品细分市场规模(2024)", size=22, color=MUT)]) + tb(s, xs[2], 7.3, 7.1, 1.5, [dict(t="高客单、高复购;线上「可解释的决策工具」仍是缺口", size=24, color=MUT)]) + tb(s, 1.5, 9.55, 10, 0.5, [dict(t="需求原声", size=24, bold=True, color=FAINT)]) + rect(s, 0, 10.25, 26.67, 2.25, PANEL) + for i, q in enumerate(["「不知道自己适不适合这款抗老精华」", "「想先测一下再买,别乱试」", "「报告要能看懂,最好直接告诉我买什么」"]): + tb(s, 1.5 + i * 8.6, 10.25, 8.2, 2.25, [dict(t=q, size=26, bold=True)], anchor=MSO_ANCHOR.MIDDLE) + tb(s, 1.5, 12.9, 24, 0.5, [dict(t="数据来源:国家统计局社会消费品零售总额(化妆品类,2024);智研咨询《2024 年中国抗衰老行业研究》", size=22, color=FAINT)]) + + # ---- P5 02 方案与价值 ---- + s = page() + header(s, "02", "小程序方案及价值") + tb(s, 1.5, 2.55, 11.5, 0.6, [dict(t="产品价值与商业价值", size=32, bold=True, color=ACC)]) + vals = [ + ("检测可信", "AI 图像分析替代主观猜测,输出可解释的检测报告"), + ("决策提效", "报告直达适配商品,缩短「浏览—下单」路径,提升转化与客单匹配"), + ("服务资产", "历史报告沉淀,支撑复访召回、换季关怀与复购运营"), + ] + for i, (lead, desc) in enumerate(vals): + y = 3.45 + i * 1.95 + rect(s, 1.5, y + 0.16, 0.26, 0.26, ACC) + tb(s, 2.1, y, 10.6, 1.7, [dict(t=lead, size=30, bold=True, sa=6), dict(t=desc, size=24, color=MUT)]) + tb(s, 14.2, 2.55, 11, 0.6, [dict(t="适用行业与运用场景", size=32, bold=True, color=ACC)]) + for t, cx, cy in [("护肤", 14.2, 3.5), ("功效型美妆", 19.3, 3.5), ("抗老精华", 14.2, 4.55), ("品牌会员中心", 19.3, 4.55)]: + sp = card(s, cx, cy, 4.7, 0.85, fill=BG, line=ACC) + tf = sp.text_frame + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = MSO_ANCHOR.MIDDLE + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + r = p.add_run() + r.text = t + set_font(r, 26, False, ACC) + tb(s, 14.2, 5.95, 11, 3.4, [dict(t=t, size=26, sa=14) for t in + ["· 店铺首页服务入口", "· 商品详情页挂载", "· 直播间互动测肤", "· 会员日与换季活动"]]) + rect(s, 0, 10.1, 26.67, 2.8, PANEL) + tb(s, 1.5, 10.4, 10, 0.5, [dict(t="商业价值", size=24, bold=True, color=FAINT)]) + for i, (t, d) in enumerate([("提升转化", "把不确定变成可解释的购买理由"), + ("优化客单", "按肌龄匹配商品,减少试错退货"), + ("沉淀会员", "报告资产驱动复访与复购")]): + x = 1.5 + i * 8.6 + tb(s, x, 11.1, 7.8, 1.5, [dict(t=t, size=28, bold=True, sa=6), dict(t=d, size=22, color=MUT)]) + + # ---- P6 02 产品核心功能与链路 ---- + s = page() + header(s, "02", "产品核心功能与链路") + feats = [ + ("01", "授权登录", "淘宝账号授权,协议确认后进入服务"), + ("02", "基础档案", "出生年份、地区、肤质,一次填写本地缓存"), + ("03", "三步拍摄", "正脸 / 左脸 / 右脸拍摄或相册选图"), + ("04", "AI 检测报告", "综合评分、肌龄、七项分项与三维指标"), + ("05", "护理与推荐", "护理关注选三,按肌龄推荐适配精华"), + ("06", "历史报告", "最近多份完整报告,可回看对比"), + ] + for i, (n, t, d) in enumerate(feats): + y = 2.35 + i * 1.12 + circle(s, 1.5, y + 0.06, 0.6, n, color=BG, size=22) + tb(s, 2.4, y, 9.9, 1.05, [dict(t=t, size=28, bold=True, sa=3), dict(t=d, size=22, color=MUT)]) + for i, (f, cap) in enumerate([("phone-profile.png", "基础档案"), ("phone-camera.png", "正面拍摄引导"), ("phone-report.png", "AI 检测报告")]): + x = 13.3 + i * 3.85 + pic(s, f"{AST}\\{f}", x, 2.3, 3.3, 6.48) + tb(s, x, 8.95, 3.3, 0.5, [dict(t=cap, size=24, color=MUT, align=PP_ALIGN.CENTER)]) + for i, st in enumerate(["启动授权", "档案填写", "三步拍摄", "生成报告", "护理推荐", "商品转化"]): + x = 2.1 + i * 3.9 + circle(s, x + 1.1, 10.3, 0.8, str(i + 1), color=BG, size=24) + tb(s, x, 11.3, 3.0, 0.5, [dict(t=st, size=24, bold=True, align=PP_ALIGN.CENTER)]) + if i < 5: + tb(s, x + 2.95, 10.42, 0.9, 0.6, [dict(t="→", size=30, bold=True, color=FAINT, align=PP_ALIGN.CENTER)]) + tb(s, 1.5, 12.35, 24.5, 1.6, + [dict(t="七项分析:轮廓紧致 · 皱纹细纹 · 肤色色素 · 平滑细腻 · 水分水润 · 敏感泛红 · 痘痘皮损", size=22, color=MUT, sa=6), + dict(t="三维指标:紧塑力 / 活力感 / 稳定力,支撑综合评分与展示肌龄", size=22, color=MUT, sa=6), + dict(t="推荐逻辑:按展示肌龄分档匹配精华组别,报告页可跳转商品详情", size=22, color=MUT)]) + + # ---- P7 02 差异与互补 ---- + s = page() + header(s, "02", "与平台现有能力的差异与互补") + for t, x, w in [("对比维度", 1.4, 4.6), ("平台现有货架与内容", 6.2, 9.8), ("本小程序互补价值", 16.2, 9.8)]: + tb(s, x, 2.7, w, 0.6, [dict(t=t, size=28, bold=True, color=ACC)]) + for i, (lab, a, b) in enumerate([ + ("决策依据", "以图文、评价与直播讲解为主", "基于本人面部数据生成可解释报告"), + ("选品方式", "用户自行对比商品与参数", "按肌龄与肤质状态主动匹配商品"), + ("服务形态", "偏一次性浏览与成交", "报告沉淀可回看,支撑复访复购"), + ("商家价值", "流量与成交工具丰富", "新增「专业测肤」信任入口,提升转化")]): + y = 3.85 + i * 2.1 + tb(s, 1.4, y + 0.55, 4.6, 0.7, [dict(t=lab, size=28, bold=True)]) + card(s, 6.2, y, 9.8, 1.9) + tb(s, 6.65, y + 0.35, 8.9, 1.3, [dict(t=a, size=26, color=MUT)], anchor=MSO_ANCHOR.MIDDLE) + card(s, 16.2, y, 9.8, 1.9, fill=PANEL, line=ACC) + tb(s, 16.65, y + 0.35, 8.9, 1.3, [dict(t=b, size=26)], anchor=MSO_ANCHOR.MIDDLE) + tb(s, 1.4, 12.65, 24, 0.8, [dict(t="「不做货架的替代,补足『专业解释 → 信任 → 决策』的服务缺口」", size=30, bold=True, color=ACC)]) + + # ---- P8 03 商业化运营规划及目标 ---- + s = page() + header(s, "03", "商业化运营规划及目标") + tb(s, 2.75, 1.78, 14, 0.5, [dict(t="自研类型申请 · 西安巨子生物 · 首期服务自有旗舰店", size=22, color=FAINT)]) + tb(s, 1.5, 2.6, 10, 0.6, [dict(t="目标覆盖", size=32, bold=True, color=ACC)]) + for i, (t, d) in enumerate([("首期(0–6 个月)", "服务自有淘宝旗舰店与核心精华线,验证「测肤—推荐—购买」闭环"), + ("扩展(6 个月以上)", "复制至品牌矩阵店铺,沉淀为会员中心的标准服务能力")]): + x = 1.5 + i * 12.22 + card(s, x, 3.4, 11.45, 1.85) + tb(s, x + 0.45, 3.7, 10.6, 1.35, [dict(t=t, size=28, bold=True, sa=5), dict(t=d, size=24, color=MUT)]) + tb(s, 1.5, 5.65, 10, 0.6, [dict(t="上线后的运营节奏", size=32, bold=True, color=ACC)]) + for i, (t, d) in enumerate([("上线期(0–1 月)", "店铺首页与详情页入口曝光;引导完成首测;紧盯拍摄成功率与报告完成率。"), + ("成长期(1–3 月)", "大促与直播挂载测肤互动;会员专属复测提醒;持续优化推荐与话术转化。"), + ("沉淀期(3 月以上)", "历史报告召回与换季护理活动;A/B 优化推荐规则;提升复测率与连带购买。")]): + x = 1.5 + i * 8.13 + card(s, x, 6.45, 7.4, 3.2) + tb(s, x + 0.45, 6.8, 6.5, 2.5, [dict(t=t, size=28, bold=True, sa=8), dict(t=d, size=24, color=MUT)]) + tb(s, 1.5, 10.1, 10, 0.6, [dict(t="关键指标", size=32, bold=True, color=ACC)]) + for i, (t, d) in enumerate([("体验", "拍摄完成率 · 报告完成率 · 报告回访时长"), + ("转化", "推荐点击率 · 详情跳转率 · 测肤后下单转化"), + ("运营", "复测率 · 连带购买 · 会员渗透"), + ("合规", "数据按账号隔离 · 权限按需申请 · 不作医疗诊断承诺")]): + x = 1.5 + i * 5.99 + card(s, x, 10.9, 5.71, 2.35) + tb(s, x + 0.4, 11.2, 4.95, 1.8, [dict(t=t, size=28, bold=True, sa=6), dict(t=d, size=22, color=MUT)]) + + # ---- P9 致谢 ---- + s = page() + glow(s, 19, 8.5, 13, alpha=11) + glow(s, -3, -3, 10, alpha=8) + tb(s, 4.85, 5.6, 18, 1.6, [dict(t="THANK YOU", size=96, bold=True)]) + tb(s, 4.9, 8.35, 16, 0.6, [dict(t="西安巨子生物基因技术股份有限公司", size=30)]) + tb(s, 4.9, 9.25, 16, 0.5, [dict(t="AI 智能测肤 · 淘宝小程序产品方案", size=24, color=MUT)]) + + prs.save(OUT) + print("saved:", OUT, "slides:", len(prs.slides)) + + +if __name__ == "__main__": + build() diff --git a/tools/build_taobao_proposal_from_template.py b/tools/build_taobao_proposal_from_template.py new file mode 100644 index 0000000..501a130 --- /dev/null +++ b/tools/build_taobao_proposal_from_template.py @@ -0,0 +1,400 @@ +# -*- coding: utf-8 -*- +"""Clone 淘宝购物小程序方案模板 -> AI智能测肤淘宝小程序产品方案(不出现公司名)。 + +模板设计语言(继承): +- 画布 26.67x15in;封面/致谢 FF5500->3768E2 渐变(原样保留) +- 章节页:白底 + DIN Condensed 120pt 大数字 + FF6F00 橙色标题(Heiti SC Light) +- 目录页:FF644E 珊瑚红圆圈编号(accent5),原样保留 +新增元素仅使用:ORANGE 标题 / CORAL 强调 / 黑灰正文 / 浅灰卡片,保证视觉一致。 +截图统一裁掉顶部 220px 导航栏(去除品牌名与微信胶囊按钮)。 +""" +import copy +from pathlib import Path + +from pptx import Presentation +from pptx.util import Inches, Pt +from pptx.dml.color import RGBColor +from pptx.enum.shapes import MSO_SHAPE +from pptx.enum.text import PP_ALIGN, MSO_ANCHOR +from pptx.oxml.ns import qn + +# 路径相对仓库根,换机器无需改(截图素材在 temp/ppt_assets,属于本地临时产物,不入库) +_ROOT = Path(__file__).resolve().parents[1] +TPL = str(_ROOT / "购物小程序方案-模版.pptx") +OUT = str(_ROOT / "智能测肤-淘宝小程序产品方案.pptx") +AST = str(_ROOT / "temp" / "ppt_assets") + +ORANGE = RGBColor(0xFF, 0x6F, 0x00) +CORAL = RGBColor(0xFF, 0x64, 0x4E) +INK = RGBColor(0x1A, 0x1A, 0x1A) +GREY = RGBColor(0x5E, 0x5E, 0x5E) +LGREY = RGBColor(0xD5, 0xD5, 0xD5) +CARD = RGBColor(0xF7, 0xF7, 0xF7) +BAND = RGBColor(0xF2, 0xF2, 0xF2) +WHITE = RGBColor(0xFF, 0xFF, 0xFF) + +NUM_F = "DIN Condensed" # 与模板大数字一致(缺失时由查看端统一替换) + + +# ---------- 基础设施 ---------- +def set_font(run, size, bold=False, color=INK, latin="Helvetica Neue", ea="微软雅黑"): + f = run.font + f.size = Pt(size) + f.bold = bold + f.color.rgb = color + f.name = latin + rPr = run._r.get_or_add_rPr() + for tag, face in ((qn("a:latin"), latin), (qn("a:ea"), ea)): + e = rPr.find(tag) + if e is None: + e = rPr.makeelement(tag, {}) + rPr.append(e) + e.set("typeface", face) + + +def tb(slide, x, y, w, h, paras, anchor=MSO_ANCHOR.TOP): + """paras: list of dict(t,size,bold,color,latin,ea,sa,align)""" + box = slide.shapes.add_textbox(Inches(x), Inches(y), Inches(w), Inches(h)) + tf = box.text_frame + tf.word_wrap = True + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = anchor + for i, pd in enumerate(paras): + p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() + p.alignment = pd.get("align", PP_ALIGN.LEFT) + if pd.get("sa"): + p.space_after = Pt(pd["sa"]) + r = p.add_run() + r.text = pd["t"] + set_font(r, pd.get("size", 26), pd.get("bold", False), pd.get("color", INK), + pd.get("latin", "Helvetica Neue"), pd.get("ea", "微软雅黑")) + return box + + +def card(slide, x, y, w, h, fill=CARD, line=LGREY): + sp = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h)) + sp.adjustments[0] = 0.055 + sp.fill.solid() + sp.fill.fore_color.rgb = fill + if line: + sp.line.color.rgb = line + sp.line.width = Pt(1) + else: + sp.line.fill.background() + sp.shadow.inherit = False + return sp + + +def band(slide, x, y, w, h, fill=BAND): + sp = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(x), Inches(y), Inches(w), Inches(h)) + sp.fill.solid() + sp.fill.fore_color.rgb = fill + sp.line.fill.background() + sp.shadow.inherit = False + return sp + + +def circle(slide, x, y, d, label, fill=CORAL, color=WHITE, size=26, latin=NUM_F): + sp = slide.shapes.add_shape(MSO_SHAPE.OVAL, Inches(x), Inches(y), Inches(d), Inches(d)) + sp.fill.solid() + sp.fill.fore_color.rgb = fill + sp.line.fill.background() + sp.shadow.inherit = False + tf = sp.text_frame + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = MSO_ANCHOR.MIDDLE + p = tf.paragraphs[0] + p.alignment = PP_ALIGN.CENTER + r = p.add_run() + r.text = label + set_font(r, size, True, color, latin, "微软雅黑") + return sp + + +def pic(slide, path, x, y, w, h): + p = slide.shapes.add_picture(path, Inches(x), Inches(y), Inches(w), Inches(h)) + p.line.color.rgb = LGREY + p.line.width = Pt(1) + return p + + +def find(slide, needle): + for sh in slide.shapes: + if sh.has_text_frame and needle in sh.text_frame.text: + return sh + raise KeyError(needle) + + +def drop(shape): + shape._element.getparent().remove(shape._element) + + +def replace_text(shape, new, widen=None): + tf = shape.text_frame + for p in tf.paragraphs[1:]: + p._p.getparent().remove(p._p) + p = tf.paragraphs[0] + runs = p.runs + runs[0].text = new + for r in runs[1:]: + r._r.getparent().remove(r._r) + if widen: + shape.width = Inches(widen) + + +def clone_slide(prs, src): + new = prs.slides.add_slide(src.slide_layout) + spTree = new.shapes._spTree + for el in list(spTree): + if el.tag.split("}")[-1] in ("sp", "pic", "graphicFrame", "grpSp", "cxnSp"): + spTree.remove(el) + for shp in src.shapes: + spTree.append(copy.deepcopy(shp._element)) + return new + + +def move_slide(prs, from_idx, to_idx): + lst = prs.slides._sldIdLst + el = list(lst)[from_idx] + lst.remove(el) + lst.insert(to_idx, el) + + +# ---------- 构建 ---------- +def build(): + prs = Presentation(TPL) + s_cover, s_pos, s_toc, s_mkt, s_val, s_biz, s_thx = prs.slides + + # 第 02 章需要 3 页:克隆「小程序方案及价值」两份 + feat = clone_slide(prs, s_val) # 功能与链路(配截图) + diff = clone_slide(prs, s_val) # 差异与互补 + # 顺序 -> [封面,定位,目录,01,02价值,02功能,02差异,03,致谢] + move_slide(prs, 7, 5) + move_slide(prs, 8, 6) + + # 大数字框在字体替换后过窄导致竖排换行+顶部裁切:删除模板框,原位重画宽框数字 + for sl, num in ((s_mkt, "01"), (s_val, "02"), (feat, "02"), (diff, "02"), (s_biz, "03")): + for sh in list(sl.shapes): + if sh.has_text_frame and sh.text_frame.text.strip() == num: + drop(sh) + break + tb(sl, 0.51, 0.24, 3.2, 1.9, [dict(t=num, size=120, color=INK, latin=NUM_F)]) + # 字体替换后数字变宽,章节标题统一右移让出间距 + for sl, keys in ((s_mkt, ["市场调研分析"]), (s_val, ["小程序方案及价值"]), + (feat, ["小程序方案及价值"]), (diff, ["小程序方案及价值"]), + (s_biz, ["商业化运营规划及目标"])): + for k in keys: + find(sl, k).left = Inches(2.75) + + # ---- P1 封面 ---- + replace_text(find(s_cover, "XXXX小程序方案"), "AI智能测肤小程序方案") + comp = find(s_cover, "XXX公司") + replace_text(comp, "西安巨子生物基因技术股份有限公司", widen=17) + comp.text_frame.paragraphs[0].runs[0].font.size = Pt(64) + comp.text_frame.word_wrap = False + tb(s_cover, 7.6, 10.8, 14, 0.55, + [dict(t="淘宝开放平台小程序产品方案 · 自研类型申请", size=26, color=WHITE)]) + + # ---- P2 公司背景与产品定位 ---- + ttl = find(s_pos, "公司背景介绍") + replace_text(ttl, "公司背景与产品定位") + ttl.width = Inches(8.0) + tb(s_pos, 10.31, 3.2, 15.5, 0.5, + [dict(t="西安巨子生物基因技术股份有限公司 · 港交所上市 · 重组胶原蛋白", size=22, color=GREY)]) + drop(find(s_pos, "请一页提炼")) + # 左:完整报告长图(已裁导航栏) + pic(s_pos, f"{AST}\\report-full.png", 2.7, 2.45, 3.34, 10.29) + tb(s_pos, 1.4, 12.95, 6.0, 0.5, + [dict(t="AI 肌肤检测报告(界面示意)", size=24, color=GREY, align=PP_ALIGN.CENTER)]) + # 右:一句话定位 + 三条价值 + tb(s_pos, 8.1, 4.7, 16.4, 2.1, + [dict(t="让每位消费者三分钟获得", size=40, bold=True, sa=6), + dict(t="一份可信赖的肌肤报告与护理方案", size=40, bold=True)], + anchor=MSO_ANCHOR.TOP) + rows = [ + ("1", "测得准", "AI 图像分析输出综合评分、肌龄、七项分项与三维指标,可解释、可回看"), + ("2", "推得对", "按展示肌龄分档推荐适配精华,报告页直达商品,缩短决策路径"), + ("3", "留得住", "历史报告沉淀与复访提醒,支撑会员运营与复购"), + ] + for i, (n, lead, desc) in enumerate(rows): + y = 7.5 + i * 2.0 + circle(s_pos, 8.1, y + 0.12, 0.72, n, size=28) + tb(s_pos, 9.3, y, 15.3, 1.8, + [dict(t=lead, size=30, bold=True, sa=6), + dict(t=desc, size=24, color=GREY)]) + + # ---- P3 目录:模板即为目标结构,保留 ---- + + # ---- P4 01 市场调研分析 ---- + drop(find(s_mkt, "商家价值和痛点")) + cols = [ + ("商家痛点", "选品讲解靠经验,「适不适合我」难讲清;直播与详情页流量难沉淀为可复访的服务。"), + ("消费者诉求", "想先弄清肤质与肌龄再决策;怕踩雷、要依据,希望报告能看懂、直接告诉我买什么。"), + ] + xs = [1.5, 9.72, 17.94] + for i, (t, body) in enumerate(cols): + tb(s_mkt, xs[i], 2.6, 7.2, 0.6, [dict(t=t, size=32, bold=True, color=ORANGE)]) + tb(s_mkt, xs[i], 3.45, 7.2, 4.4, [dict(t=body, size=26, color=GREY)]) + tb(s_mkt, xs[2], 2.6, 7.2, 0.6, [dict(t="市场与商业化空间", size=32, bold=True, color=ORANGE)]) + tb(s_mkt, xs[2], 3.45, 7.2, 1.0, [dict(t="4357亿", size=54, bold=True, color=ORANGE, latin=NUM_F)]) + tb(s_mkt, xs[2], 4.5, 7.2, 0.5, [dict(t="2024 年全国化妆品类零售额", size=22, color=GREY)]) + tb(s_mkt, xs[2], 5.35, 7.2, 1.0, [dict(t="1069亿", size=54, bold=True, color=CORAL, latin=NUM_F)]) + tb(s_mkt, xs[2], 6.4, 7.2, 0.5, [dict(t="抗衰护肤品细分市场规模(2024)", size=22, color=GREY)]) + tb(s_mkt, xs[2], 7.15, 7.2, 1.5, + [dict(t="高客单、高复购;线上「可解释的决策工具」仍是缺口", size=24, color=GREY)]) + # 需求原声 + tb(s_mkt, 1.5, 9.55, 10, 0.5, [dict(t="需求原声", size=24, bold=True, color=GREY)]) + band(s_mkt, 0, 10.25, 26.67, 2.25) + quotes = ["「不知道自己适不适合这款抗老精华」", "「想先测一下再买,别乱试」", "「报告要能看懂,最好直接告诉我买什么」"] + for i, q in enumerate(quotes): + tb(s_mkt, 1.5 + i * 8.6, 10.25, 8.2, 2.25, + [dict(t=q, size=26, bold=True)], anchor=MSO_ANCHOR.MIDDLE) + tb(s_mkt, 1.5, 12.9, 24, 0.5, + [dict(t="数据来源:国家统计局社会消费品零售总额(化妆品类,2024);智研咨询《2024 年中国抗衰老行业研究》", + size=22, color=GREY)]) + + # ---- P5 02 方案与价值 ---- + drop(find(s_val, "产品价值和商业价值")) + tb(s_val, 1.5, 2.55, 11.5, 0.6, [dict(t="产品价值与商业价值", size=32, bold=True, color=ORANGE)]) + vals = [ + ("检测可信", "AI 图像分析替代主观猜测,输出可解释的检测报告"), + ("决策提效", "报告直达适配商品,缩短「浏览—下单」路径,提升转化与客单匹配"), + ("服务资产", "历史报告沉淀,支撑复访召回、换季关怀与复购运营"), + ] + for i, (lead, desc) in enumerate(vals): + y = 3.45 + i * 1.95 + sq = s_val.shapes.add_shape(MSO_SHAPE.RECTANGLE, Inches(1.5), Inches(y + 0.16), Inches(0.26), Inches(0.26)) + sq.fill.solid(); sq.fill.fore_color.rgb = CORAL; sq.line.fill.background(); sq.shadow.inherit = False + tb(s_val, 2.1, y, 10.6, 1.7, + [dict(t=lead, size=30, bold=True, sa=6), dict(t=desc, size=24, color=GREY)]) + tb(s_val, 14.2, 2.55, 11, 0.6, [dict(t="适用行业与运用场景", size=32, bold=True, color=ORANGE)]) + chips = [("护肤", 14.2, 3.5), ("功效型美妆", 19.3, 3.5), ("抗老精华", 14.2, 4.55), ("品牌会员中心", 19.3, 4.55)] + for t, cx, cy in chips: + sp = card(s_val, cx, cy, 4.7, 0.85, fill=WHITE, line=CORAL) + tf = sp.text_frame + tf.margin_left = tf.margin_right = tf.margin_top = tf.margin_bottom = 0 + tf.vertical_anchor = MSO_ANCHOR.MIDDLE + p = tf.paragraphs[0]; p.alignment = PP_ALIGN.CENTER + r = p.add_run(); r.text = t + set_font(r, 26, False, CORAL) + scenes = ["· 店铺首页服务入口", "· 商品详情页挂载", "· 直播间互动测肤", "· 会员日与换季活动"] + tb(s_val, 14.2, 5.95, 11, 3.4, + [dict(t=s, size=26, sa=14) for s in scenes]) + band(s_val, 0, 10.1, 26.67, 2.8) + tb(s_val, 1.5, 10.4, 10, 0.5, [dict(t="商业价值", size=24, bold=True, color=GREY)]) + biz = [("提升转化", "把不确定变成可解释的购买理由"), + ("优化客单", "按肌龄匹配商品,减少试错退货"), + ("沉淀会员", "报告资产驱动复访与复购")] + for i, (t, d) in enumerate(biz): + x = 1.5 + i * 8.6 + tb(s_val, x, 11.1, 7.8, 1.5, + [dict(t=t, size=28, bold=True, sa=6), dict(t=d, size=22, color=GREY)]) + + # ---- P6 02 产品核心功能与链路(配截图) ---- + replace_text(find(feat, "小程序方案及价值"), "产品核心功能与链路", widen=9.5) + drop(find(feat, "产品价值和商业价值")) + feats = [ + ("01", "授权登录", "淘宝账号授权,协议确认后进入服务"), + ("02", "基础档案", "出生年份、地区、肤质,一次填写本地缓存"), + ("03", "三步拍摄", "正脸 / 左脸 / 右脸拍摄或相册选图"), + ("04", "AI 检测报告", "综合评分、肌龄、七项分项与三维指标"), + ("05", "护理与推荐", "护理关注选三,按肌龄推荐适配精华"), + ("06", "历史报告", "最近多份完整报告,可回看对比"), + ] + for i, (n, t, d) in enumerate(feats): + y = 2.35 + i * 1.12 + circle(feat, 1.5, y + 0.06, 0.6, n, size=22) + tb(feat, 2.4, y, 9.9, 1.05, + [dict(t=t, size=28, bold=True, sa=3), dict(t=d, size=22, color=GREY)]) + phones = [("phone-profile.png", "基础档案"), ("phone-camera.png", "正面拍摄引导"), ("phone-report.png", "AI 检测报告")] + for i, (f, cap) in enumerate(phones): + x = 13.3 + i * 3.85 + pic(feat, f"{AST}\\{f}", x, 2.3, 3.3, 6.48) + tb(feat, x, 8.95, 3.3, 0.5, [dict(t=cap, size=24, color=GREY, align=PP_ALIGN.CENTER)]) + steps = ["启动授权", "档案填写", "三步拍摄", "生成报告", "护理推荐", "商品转化"] + for i, st in enumerate(steps): + x = 2.1 + i * 3.9 + circle(feat, x + 1.1, 10.3, 0.8, str(i + 1), size=24) + tb(feat, x, 11.3, 3.0, 0.5, [dict(t=st, size=24, bold=True, align=PP_ALIGN.CENTER)]) + if i < len(steps) - 1: + tb(feat, x + 2.95, 10.42, 0.9, 0.6, + [dict(t="→", size=30, bold=True, color=GREY, align=PP_ALIGN.CENTER)]) + tb(feat, 1.5, 12.35, 24.5, 1.6, + [dict(t="七项分析:轮廓紧致 · 皱纹细纹 · 肤色色素 · 平滑细腻 · 水分水润 · 敏感泛红 · 痘痘皮损", size=22, color=GREY, sa=6), + dict(t="三维指标:紧塑力 / 活力感 / 稳定力,支撑综合评分与展示肌龄", size=22, color=GREY, sa=6), + dict(t="推荐逻辑:按展示肌龄分档匹配精华组别,报告页可跳转商品详情", size=22, color=GREY)]) + + # ---- P7 02 与平台现有能力的差异与互补 ---- + replace_text(find(diff, "小程序方案及价值"), "与平台现有能力的差异与互补", widen=10.5) + drop(find(diff, "产品价值和商业价值")) + heads = [("对比维度", 1.4, 4.6), ("平台现有货架与内容", 6.2, 9.8), ("本小程序互补价值", 16.2, 9.8)] + for t, x, w in heads: + tb(diff, x, 2.7, w, 0.6, [dict(t=t, size=28, bold=True, color=CORAL)]) + table = [ + ("决策依据", "以图文、评价与直播讲解为主", "基于本人面部数据生成可解释报告"), + ("选品方式", "用户自行对比商品与参数", "按肌龄与肤质状态主动匹配商品"), + ("服务形态", "偏一次性浏览与成交", "报告沉淀可回看,支撑复访复购"), + ("商家价值", "流量与成交工具丰富", "新增「专业测肤」信任入口,提升转化"), + ] + for i, (lab, a, b) in enumerate(table): + y = 3.85 + i * 2.1 + tb(diff, 1.4, y + 0.55, 4.6, 0.7, [dict(t=lab, size=28, bold=True)]) + for txt, x in ((a, 6.2), (b, 16.2)): + card(diff, x, y, 9.8, 1.9, fill=CARD if x == 6.2 else WHITE, + line=LGREY if x == 6.2 else CORAL) + tb(diff, x + 0.45, y + 0.35, 8.9, 1.3, + [dict(t=txt, size=26, color=GREY if x == 6.2 else INK)], + anchor=MSO_ANCHOR.MIDDLE) + tb(diff, 1.4, 12.65, 24, 0.8, + [dict(t="「不做货架的替代,补足『专业解释 → 信任 → 决策』的服务缺口」", size=30, bold=True, color=ORANGE)]) + + # ---- P8 03 商业化运营规划及目标 ---- + replace_text(find(s_biz, "商业化运营规划及目标"), "商业化运营规划及目标") + drop(find(s_biz, "目标覆盖商家数")) + tb(s_biz, 2.75, 1.78, 14, 0.5, [dict(t="自研类型申请 · 西安巨子生物 · 首期服务自有旗舰店", size=22, color=GREY)]) + tb(s_biz, 1.5, 2.6, 10, 0.6, [dict(t="目标覆盖", size=32, bold=True, color=ORANGE)]) + goals = [ + ("首期(0–6 个月)", "服务自有淘宝旗舰店与核心精华线,验证「测肤—推荐—购买」闭环"), + ("扩展(6 个月以上)", "复制至品牌矩阵店铺,沉淀为会员中心的标准服务能力"), + ] + for i, (t, d) in enumerate(goals): + x = 1.5 + i * 12.22 + card(s_biz, x, 3.4, 11.45, 1.85) + tb(s_biz, x + 0.45, 3.7, 10.6, 1.35, + [dict(t=t, size=28, bold=True, sa=5), dict(t=d, size=24, color=GREY)]) + tb(s_biz, 1.5, 5.65, 10, 0.6, [dict(t="上线后的运营节奏", size=32, bold=True, color=ORANGE)]) + phases = [ + ("上线期(0–1 月)", "店铺首页与详情页入口曝光;引导完成首测;紧盯拍摄成功率与报告完成率。"), + ("成长期(1–3 月)", "大促与直播挂载测肤互动;会员专属复测提醒;持续优化推荐与话术转化。"), + ("沉淀期(3 月以上)", "历史报告召回与换季护理活动;A/B 优化推荐规则;提升复测率与连带购买。"), + ] + for i, (t, d) in enumerate(phases): + x = 1.5 + i * 8.13 + card(s_biz, x, 6.45, 7.4, 3.2) + tb(s_biz, x + 0.45, 6.8, 6.5, 2.5, + [dict(t=t, size=28, bold=True, sa=8), dict(t=d, size=24, color=GREY)]) + tb(s_biz, 1.5, 10.1, 10, 0.6, [dict(t="关键指标", size=32, bold=True, color=ORANGE)]) + kpis = [ + ("体验", "拍摄完成率 · 报告完成率 · 报告回访时长"), + ("转化", "推荐点击率 · 详情跳转率 · 测肤后下单转化"), + ("运营", "复测率 · 连带购买 · 会员渗透"), + ("合规", "数据按账号隔离 · 权限按需申请 · 不作医疗诊断承诺"), + ] + for i, (t, d) in enumerate(kpis): + x = 1.5 + i * 5.99 + card(s_biz, x, 10.9, 5.71, 2.35) + tb(s_biz, x + 0.4, 11.2, 4.95, 1.8, + [dict(t=t, size=28, bold=True, sa=6), dict(t=d, size=22, color=GREY)]) + + # ---- P9 致谢 ---- + tb(s_thx, 4.85, 8.35, 16, 0.6, + [dict(t="西安巨子生物基因技术股份有限公司", size=26, color=WHITE)]) + tb(s_thx, 4.85, 9.2, 16, 0.5, + [dict(t="AI 智能测肤 · 淘宝小程序产品方案", size=22, color=WHITE)]) + + prs.save(OUT) + print("saved:", OUT, "slides:", len(prs.slides)) + + +if __name__ == "__main__": + build() diff --git a/tools/build_taobao_proposal_pptx.py b/tools/build_taobao_proposal_pptx.py new file mode 100644 index 0000000..d9bc3f6 --- /dev/null +++ b/tools/build_taobao_proposal_pptx.py @@ -0,0 +1,367 @@ +# -*- coding: utf-8 -*- +"""Generate Taobao mini-program product proposal PPTX (no company name). + +注意:这一份是更早的版本(输出 AI智能测肤-淘宝小程序产品方案.pptx,当前仓库里没有该成品), +保留用于追溯版式。现行版本见 build_taobao_proposal_from_template.py / build_taobao_proposal_dark.py。 +""" +from pathlib import Path + +from pptx import Presentation +from pptx.util import Emu, Pt +from pptx.dml.color import RGBColor +from pptx.enum.shapes import MSO_SHAPE +from pptx.enum.text import PP_ALIGN +from pptx.oxml.ns import qn +from lxml import etree + +OUT = str(Path(__file__).resolve().parents[1] / "AI智能测肤-淘宝小程序产品方案.pptx") + +W, H = 24384000, 13716000 # 16:9 + +BG = RGBColor(0x0F, 0x1A, 0x26) +BG_CARD = RGBColor(0x18, 0x27, 0x38) +ACCENT = RGBColor(0x2E, 0xC4, 0xB6) +WHITE = RGBColor(0xFF, 0xFF, 0xFF) +MUTED = RGBColor(0xA8, 0xB4, 0xC0) +LINE = RGBColor(0x2A, 0x3B, 0x4F) +TITLE = RGBColor(0xF2, 0xF6, 0xFA) +PANEL = RGBColor(0x14, 0x2A, 0x3C) + + +def set_run(run, size=18, bold=False, color=WHITE, font="微软雅黑"): + run.font.size = Pt(size) + run.font.bold = bold + run.font.color.rgb = color + run.font.name = font + rPr = run._r.get_or_add_rPr() + ea = rPr.find(qn("a:ea")) + if ea is None: + ea = etree.SubElement(rPr, qn("a:ea")) + ea.set("typeface", font) + + +def add_bg(slide, color=BG): + shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, W, H) + shape.fill.solid() + shape.fill.fore_color.rgb = color + shape.line.fill.background() + spTree = slide.shapes._spTree + sp = shape._element + spTree.remove(sp) + spTree.insert(2, sp) + + +def add_bar(slide, left, top, width=Emu(457200), height=Emu(70000)): + bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height) + bar.fill.solid() + bar.fill.fore_color.rgb = ACCENT + bar.line.fill.background() + + +def add_text(slide, left, top, width, height, text, size=18, bold=False, color=WHITE, align=PP_ALIGN.LEFT): + box = slide.shapes.add_textbox(left, top, width, height) + tf = box.text_frame + tf.word_wrap = True + p = tf.paragraphs[0] + p.alignment = align + run = p.add_run() + run.text = text + set_run(run, size=size, bold=bold, color=color) + return box + + +def add_paras(slide, left, top, width, height, lines, size=15, color=MUTED, bold=False, gap=10): + box = slide.shapes.add_textbox(left, top, width, height) + tf = box.text_frame + tf.word_wrap = True + for i, line in enumerate(lines): + p = tf.paragraphs[0] if i == 0 else tf.add_paragraph() + p.alignment = PP_ALIGN.LEFT + p.space_after = Pt(gap) + run = p.add_run() + run.text = line + set_run(run, size=size, bold=bold, color=color) + return box + + +def add_card(slide, left, top, width, height): + card = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, left, top, width, height) + card.fill.solid() + card.fill.fore_color.rgb = BG_CARD + card.line.color.rgb = LINE + card.line.width = Pt(1) + return card + + +def blank(prs): + return prs.slides.add_slide(prs.slide_layouts[6]) + + +def section_title(slide, num, title): + add_bg(slide) + add_text(slide, Emu(914400), Emu(420000), Emu(2000000), Emu(450000), num, size=28, bold=True, color=ACCENT) + add_text(slide, Emu(1600200), Emu(450000), Emu(14000000), Emu(450000), title, size=28, bold=True, color=TITLE) + add_bar(slide, Emu(914400), Emu(950000)) + + +def build(): + prs = Presentation() + prs.slide_width = W + prs.slide_height = H + + # ---- 1 Cover ---- + s = blank(prs) + add_bg(s) + panel = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, Emu(3200400), H) + panel.fill.solid() + panel.fill.fore_color.rgb = PANEL + panel.line.fill.background() + add_bar(s, Emu(4000500), Emu(4200000), Emu(914400), Emu(90000)) + add_text(s, Emu(4000500), Emu(4500000), Emu(17000000), Emu(900000), + "AI 智能测肤", size=44, bold=True, color=TITLE) + add_text(s, Emu(4000500), Emu(5450000), Emu(17000000), Emu(700000), + "淘宝小程序产品方案", size=32, bold=True, color=ACCENT) + add_text(s, Emu(4000500), Emu(6350000), Emu(17000000), Emu(500000), + "在线肌肤检测 · 个性化护理建议 · 精准商品推荐", size=16, color=MUTED) + add_text(s, Emu(4000500), Emu(11000000), Emu(8000000), Emu(400000), + "自研类型申请材料", size=12, color=MUTED) + + # ---- 2 Product positioning (replaces company background) ---- + s = blank(prs) + add_bg(s) + add_bar(s, Emu(914400), Emu(685800)) + add_text(s, Emu(914400), Emu(420000), Emu(16000000), Emu(500000), + "产品定位", size=28, bold=True, color=TITLE) + add_text(s, Emu(914400), Emu(1200000), Emu(20000000), Emu(600000), + "面向淘宝美妆消费者的「检测—报告—推荐—购买」一站式肌肤服务小程序", size=18, color=MUTED) + + cards = [ + ("核心能力", "基于面部图像的 AI 肌肤分析,输出综合评分、肌龄、七项分项结论与护理建议。"), + ("转化路径", "报告结果直接关联店铺商品,按肌龄与肤质状态推荐适配精华,缩短决策路径。"), + ("适用场景", "品牌旗舰店导购、直播/详情页引流、会员复购关怀、线下到线上测肤体验延伸。"), + ("差异价值", "不是通用展示页,而是可闭环的「测肤服务 + 商品转化」能力,补足平台现有内容与货架之间的决策缺口。"), + ] + for i, (t, d) in enumerate(cards): + col = i % 2 + row = i // 2 + left = Emu(914400 + col * 11000000) + top = Emu(2100000 + row * 4200000) + add_card(s, left, top, Emu(10000000), Emu(3600000)) + add_text(s, left + Emu(400000), top + Emu(350000), Emu(9000000), Emu(500000), + t, size=18, bold=True, color=ACCENT) + add_text(s, left + Emu(400000), top + Emu(1000000), Emu(9000000), Emu(2200000), + d, size=15, color=MUTED) + + # ---- 3 TOC ---- + s = blank(prs) + add_bg(s) + add_text(s, Emu(914400), Emu(420000), Emu(8000000), Emu(500000), + "目录", size=32, bold=True, color=TITLE) + add_bar(s, Emu(914400), Emu(1000000)) + toc = [ + ("01", "市场调研分析"), + ("02", "小程序方案及价值"), + ("03", "商业化运营规划及目标"), + ] + for i, (num, name) in enumerate(toc): + top = Emu(2200000 + i * 2200000) + circle = s.shapes.add_shape(MSO_SHAPE.OVAL, Emu(914400), top, Emu(1100000), Emu(1100000)) + circle.fill.solid() + circle.fill.fore_color.rgb = ACCENT + circle.line.fill.background() + add_text(s, Emu(914400), top + Emu(280000), Emu(1100000), Emu(600000), + num, size=22, bold=True, color=BG, align=PP_ALIGN.CENTER) + add_text(s, Emu(2400000), top + Emu(300000), Emu(12000000), Emu(600000), + name, size=26, bold=True, color=TITLE) + + # ---- 4 Market research ---- + s = blank(prs) + section_title(s, "01", "市场调研分析") + add_paras(s, Emu(914400), Emu(1300000), Emu(22000000), Emu(11000000), [ + "1)商家价值与痛点 / 消费者诉求", + "· 商家痛点:美妆选品高度依赖经验,线上货架信息多、决策成本高,难以把「适合我」讲清楚;直播与详情页流量难沉淀为可复访服务。", + "· 消费者诉求:想知道自己肤质与肌龄、哪里需要改善、该买哪一支精华;希望少踩雷、有依据、可即时下单。", + "· 本方案以测肤报告建立信任,再以肌龄分档推荐商品,同时满足「专业解释」与「购买决策」两端诉求。", + "", + "2)市场规模与商业化空间", + "· 淘宝美妆护肤为高复购、高客单品类;「工具型服务」可提升停留、互动与转化,适配旗舰店与会员运营。", + "· 测肤完成后可沉淀历史报告,支撑复购提醒、换季护理与活动召回,形成服务型资产而非一次性流量。", + "", + "3)需求原声(典型)", + "· 「不知道自己适不适合这款抗老精华」 · 「想先测一下再买,别乱试」 · 「报告要能看懂,最好直接告诉我买什么」", + ], size=14, color=MUTED, gap=6) + + # ---- 5 Solution overview ---- + s = blank(prs) + section_title(s, "02", "小程序方案及价值") + add_paras(s, Emu(914400), Emu(1300000), Emu(22000000), Emu(4000000), [ + "1)产品价值与商业价值", + "· 产品价值:3 步拍摄即可完成 AI 检测,获得综合评分、展示肌龄、七项分析、护理建议与精华推荐。", + "· 商业价值:把「不确定」变成「可解释的购买理由」,提升详情页/店铺转化与客单匹配度;报告可复访,利于会员沉淀。", + "", + "2)商家运用场景与适用行业", + "· 适用行业:护肤 / 抗老精华 / 功效型美妆、医美周边护理(非诊疗)、品牌会员中心。", + "· 运用场景:店铺首页入口、商品详情页挂载、直播间互动测肤、会员日/换季活动、新客教育与老客复购。", + ], size=14, color=MUTED, gap=6) + + # three value cards at bottom + vals = [ + ("降低决策成本", "用检测数据替代主观猜测,减少试错与退货。"), + ("提升转化效率", "报告页直达适配商品,缩短浏览—下单路径。"), + ("沉淀服务资产", "历史报告可回看,支撑持续运营与复购。"), + ] + for i, (t, d) in enumerate(vals): + left = Emu(914400 + i * 7500000) + top = Emu(8200000) + add_card(s, left, top, Emu(7000000), Emu(3800000)) + add_text(s, left + Emu(350000), top + Emu(450000), Emu(6200000), Emu(600000), + t, size=16, bold=True, color=ACCENT) + add_text(s, left + Emu(350000), top + Emu(1300000), Emu(6200000), Emu(2000000), + d, size=14, color=MUTED) + + # ---- 6 Core features ---- + s = blank(prs) + section_title(s, "02", "产品核心功能") + feats = [ + ("授权登录", "淘宝账号授权登录,协议确认后进入服务;账号与报告隔离存储。"), + ("基础档案", "出生年月、地区、肤质等信息一次填写、本地缓存,用于个性化展示。"), + ("三步拍摄", "正脸 / 右脸 / 左脸手动拍摄或相册选图,压缩后上传检测。"), + ("AI 检测报告", "综合评分、肌龄、三维度(紧塑力 / 透亮感 / 稳韧力)与七项分项结论。"), + ("护理与推荐", "护理关注点选三、精华产品按肌龄分档推荐,并可跳转店铺商品。"), + ("历史报告", "保留本人最近多份完整报告,支持复访对比与复购触达。"), + ] + for i, (t, d) in enumerate(feats): + col = i % 3 + row = i // 3 + left = Emu(914400 + col * 7500000) + top = Emu(1400000 + row * 5200000) + add_card(s, left, top, Emu(7000000), Emu(4600000)) + add_text(s, left + Emu(350000), top + Emu(450000), Emu(6200000), Emu(700000), + t, size=17, bold=True, color=ACCENT) + add_text(s, left + Emu(350000), top + Emu(1400000), Emu(6200000), Emu(2800000), + d, size=14, color=MUTED) + + # ---- 7 Product flow ---- + s = blank(prs) + section_title(s, "02", "产品核心链路") + add_text(s, Emu(914400), Emu(1200000), Emu(22000000), Emu(400000), + "用户从进入到购买的主路径(交互链路)", size=15, color=MUTED) + + steps = [ + ("1", "启动页", "协议同意\n淘宝授权"), + ("2", "基础档案", "年龄地区\n肤质选择"), + ("3", "拍摄检测", "正/右/左脸\n上传分析"), + ("4", "肌肤报告", "评分肌龄\n七项结论"), + ("5", "护理推荐", "关注选三\n精华匹配"), + ("6", "商品转化", "跳转详情\n完成下单"), + ] + for i, (n, t, d) in enumerate(steps): + left = Emu(600000 + i * 3900000) + top = Emu(2200000) + circle = s.shapes.add_shape(MSO_SHAPE.OVAL, left + Emu(1100000), top, Emu(900000), Emu(900000)) + circle.fill.solid() + circle.fill.fore_color.rgb = ACCENT + circle.line.fill.background() + add_text(s, left + Emu(1100000), top + Emu(220000), Emu(900000), Emu(500000), + n, size=22, bold=True, color=BG, align=PP_ALIGN.CENTER) + add_text(s, left, top + Emu(1200000), Emu(3200000), Emu(500000), + t, size=16, bold=True, color=TITLE, align=PP_ALIGN.CENTER) + add_text(s, left, top + Emu(1800000), Emu(3200000), Emu(1200000), + d, size=13, color=MUTED, align=PP_ALIGN.CENTER) + if i < len(steps) - 1: + add_text(s, left + Emu(3000000), top + Emu(250000), Emu(800000), Emu(500000), + "→", size=22, bold=True, color=ACCENT, align=PP_ALIGN.CENTER) + + add_card(s, Emu(914400), Emu(6200000), Emu(22500000), Emu(5800000)) + add_paras(s, Emu(1300000), Emu(6600000), Emu(21000000), Emu(5000000), [ + "七项分析:轮廓紧致 · 皱纹细纹 · 肤色色素 · 平滑细腻 · 水分水润 · 敏感泛红 · 痘痘皮损", + "三维度评分:紧塑力 / 透亮感 / 稳韧力,支撑综合结论与商品分档推荐", + "推荐逻辑:以展示肌龄为主,结合维度评分在边界档位微调,匹配 25+ / 35+ / 50+ 精华组别", + "权限说明:拍摄需相机权限;拒绝后可走相册选图;相册权限独立申请,不循环弹窗", + ], size=14, color=MUTED, gap=12) + + # ---- 8 Differentiation ---- + s = blank(prs) + section_title(s, "02", "与平台现有能力的差异 / 互补") + rows = [ + ("对比点", "平台现有货架 / 内容能力", "本小程序互补价值"), + ("决策依据", "以图文、评价、直播讲解为主", "以本人面部检测数据生成可解释报告"), + ("选品方式", "用户自行对比商品参数", "按肌龄与肤质状态主动匹配商品"), + ("服务形态", "一次性浏览与成交", "可保存历史报告,支撑复访与复购"), + ("商家侧价值", "流量与成交工具丰富", "增加「专业测肤服务」入口,提升信任与转化"), + ] + for r, row in enumerate(rows): + top = Emu(1400000 + r * 1800000) + for c, cell in enumerate(row): + left = Emu(914400 + c * 7500000) + w = Emu(7000000) + add_card(s, left, top, w, Emu(1550000)) + color = ACCENT if r == 0 or c == 0 else MUTED + bold = r == 0 or c == 0 + add_text(s, left + Emu(250000), top + Emu(400000), Emu(6500000), Emu(900000), + cell, size=13, bold=bold, color=color) + + # ---- 9 Commercial plan ---- + s = blank(prs) + section_title(s, "03", "商业化运营规划及目标") + add_paras(s, Emu(914400), Emu(1300000), Emu(22000000), Emu(5000000), [ + "1)目标覆盖", + "· 首期:服务本品牌淘宝旗舰店及核心护肤线(自研自用),完成测肤—推荐—购买闭环验证。", + "· 扩展:在验证转化与体验后,可按品牌矩阵店铺复制,或作为会员中心标准服务能力输出。", + "", + "2)上线后运营策略与节奏", + ], size=14, color=MUTED, gap=6) + + phases = [ + ("上线期(0–1 月)", "店铺首页 / 详情页入口曝光;引导完成首测;监控拍摄成功率、报告完成率、推荐点击率。"), + ("成长期(1–3 月)", "结合大促与直播挂载测肤;会员专属复测提醒;优化推荐商品与话术转化。"), + ("沉淀期(3 月+)", "历史报告召回;换季护理活动;A/B 测推荐规则;持续提升复测率与连带购买。"), + ] + for i, (t, d) in enumerate(phases): + left = Emu(914400 + i * 7500000) + top = Emu(6200000) + add_card(s, left, top, Emu(7000000), Emu(5800000)) + add_text(s, left + Emu(350000), top + Emu(400000), Emu(6200000), Emu(900000), + t, size=15, bold=True, color=ACCENT) + add_text(s, left + Emu(350000), top + Emu(1500000), Emu(6200000), Emu(3800000), + d, size=13, color=MUTED) + + # ---- 10 KPI ---- + s = blank(prs) + section_title(s, "03", "关键指标与合规说明") + kpis = [ + ("体验指标", "拍摄完成率、检测成功率、报告打开时长、历史回访率"), + ("转化指标", "推荐位点击率、商品详情跳转率、测肤后下单转化、客单价"), + ("运营指标", "日活测肤次数、复测间隔、会员渗透、活动期增量"), + ("合规要点", "明示检测用途;相机/相册按需授权;人脸与报告按账号隔离;不做医疗诊断承诺"), + ] + for i, (t, d) in enumerate(kpis): + col = i % 2 + row = i // 2 + left = Emu(914400 + col * 11000000) + top = Emu(1400000 + row * 5200000) + add_card(s, left, top, Emu(10000000), Emu(4600000)) + add_text(s, left + Emu(400000), top + Emu(500000), Emu(9000000), Emu(700000), + t, size=18, bold=True, color=ACCENT) + add_text(s, left + Emu(400000), top + Emu(1500000), Emu(9000000), Emu(2600000), + d, size=15, color=MUTED) + + # ---- 11 Thank you ---- + s = blank(prs) + add_bg(s) + panel = s.shapes.add_shape(MSO_SHAPE.RECTANGLE, 0, 0, Emu(3200400), H) + panel.fill.solid() + panel.fill.fore_color.rgb = PANEL + panel.line.fill.background() + add_bar(s, Emu(4000500), Emu(5200000), Emu(914400), Emu(90000)) + add_text(s, Emu(4000500), Emu(5500000), Emu(16000000), Emu(900000), + "THANK YOU", size=44, bold=True, color=TITLE) + add_text(s, Emu(4000500), Emu(6500000), Emu(16000000), Emu(500000), + "AI 智能测肤 · 淘宝小程序产品方案", size=16, color=MUTED) + + prs.save(OUT) + print("saved", OUT, "slides", len(prs.slides)) + + +if __name__ == "__main__": + build() diff --git a/智能测肤-淘宝小程序产品方案-深色版.pptx b/智能测肤-淘宝小程序产品方案-深色版.pptx new file mode 100644 index 0000000..c87ec12 Binary files /dev/null and b/智能测肤-淘宝小程序产品方案-深色版.pptx differ diff --git a/智能测肤-淘宝小程序产品方案.pptx b/智能测肤-淘宝小程序产品方案.pptx new file mode 100644 index 0000000..e233ae4 Binary files /dev/null and b/智能测肤-淘宝小程序产品方案.pptx differ diff --git a/购物小程序方案-模版.pptx b/购物小程序方案-模版.pptx new file mode 100644 index 0000000..abe754d Binary files /dev/null and b/购物小程序方案-模版.pptx differ