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)
This commit is contained in:
xsl
2026-11-01 23:37:38 +08:00
parent 43a5373233
commit 2eb0d8e807
7 changed files with 1101 additions and 0 deletions
+6
View File
@@ -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]/
+328
View File
@@ -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()
@@ -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()
+367
View File
@@ -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()
Binary file not shown.
Binary file not shown.