Files
juzi/tools/build_taobao_proposal_dark.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

329 lines
17 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 -*-
"""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()