Files
juzi/tools/build_taobao_proposal_pptx.py
T
xsl 2eb0d8e807 docs(proposal): add Taobao product proposal decks and their generators
产品方案 PPT 是交付物,之前只存在于本机,换开发机后会丢,所以入库。

- 3 份 pptx:智能测肤方案(正版 1.3MB / 深色版 1.3MB)+ 购物小程序方案模版(0.1MB);
  模版是 build_taobao_proposal_from_template.py 的输入,必须一起入库
- 3 个生成脚本:把硬编码的 D:\juzi\... 改为相对仓库根(Path(__file__).parents[1]),
  渲染用的截图素材 temp/ppt_assets 属临时产物,加进 .gitignore
- build_taobao_proposal_pptx.py 是更早的一版(产物 AI智能测肤...pptx 当前不在仓库),
  保留用于追溯版式
- 新增 .gitignore:/sdk-java-35479221/(淘宝开放平台自动生成的 Java SDK,
  对应已废弃的 AppKey 35479221,当前架构走 HTTP 透传,不引 SDK)
2026-11-01 23:37:38 +08:00

368 lines
18 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# -*- 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()