# -*- coding: utf-8 -*- """生成《三阶段软硬配置及使用指南.pptx》 核心:每个阶段 = 客户好处 + 具体工作流程 + 人操作/自动化分工 """ import os from pptx import Presentation from pptx.util import Inches, Pt, Emu from pptx.dml.color import RGBColor from pptx.enum.text import PP_ALIGN, MSO_ANCHOR from pptx.enum.shapes import MSO_SHAPE BASE = r"C:\Users\Administrator\Desktop\AI落地公司企划项目" ASSETS = os.path.join(BASE, "assets") OUT = os.path.join(BASE, "三阶段软硬配置及使用指南.pptx") BG_DARK = RGBColor(0x0B,0x25,0x45) PRIMARY = RGBColor(0x13,0x31,0x5C) ACCENT = RGBColor(0x2E,0x93,0xF7) HIGHLIGHT= RGBColor(0xFF,0x8A,0x3D) LIGHT = RGBColor(0xF4,0xF7,0xFB) GRAY = RGBColor(0x6B,0x7A,0x8F) WHITE = RGBColor(0xFF,0xFF,0xFF) TEXTDARK = RGBColor(0x1A,0x24,0x33) HUMAN_C = RGBColor(0xC8,0x6A,0x1B) AUTO_C = RGBColor(0x1E,0x6F,0xB8) prs = Presentation() SW, SH = Inches(13.333), Inches(7.5) prs.slide_width, prs.slide_height = SW, SH BLANK = prs.slide_layouts[6] def add_bg(slide, color=LIGHT): s = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,SW,SH) s.fill.solid(); s.fill.fore_color.rgb=color s.line.fill.background(); s.shadow.inherit=False def add_title(slide, title, page=None, subtitle=None): bar = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,SW,Inches(1.15)) bar.fill.solid(); bar.fill.fore_color.rgb=PRIMARY; bar.line.fill.background(); bar.shadow.inherit=False st = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,Inches(1.15),SW,Inches(0.06)) st.fill.solid(); st.fill.fore_color.rgb=ACCENT; st.line.fill.background(); st.shadow.inherit=False tb = slide.shapes.add_textbox(Inches(0.55),Inches(0.16),SW-Inches(1.1),Inches(0.95)) tf = tb.text_frame; tf.word_wrap=True p = tf.paragraphs[0]; r = p.add_run(); r.text=title r.font.size=Pt(25); r.font.bold=True; r.font.color.rgb=WHITE if subtitle: p2 = tf.add_paragraph(); r2=p2.add_run(); r2.text=subtitle r2.font.size=Pt(12); r2.font.color.rgb=RGBColor(0xBB,0xD6,0xF2) if page is not None: ft = slide.shapes.add_textbox(Inches(0.55),SH-Inches(0.4),SW-Inches(1.6),Inches(0.3)) fp = ft.text_frame.paragraphs[0]; fr=fp.add_run() fr.text="三阶段软硬配置及使用指南 · 【客户名称】"; fr.font.size=Pt(9); fr.font.color.rgb=GRAY pg = slide.shapes.add_textbox(SW-Inches(1.05),SH-Inches(0.4),Inches(0.6),Inches(0.3)) pp = pg.text_frame.paragraphs[0]; pr=pp.add_run(); pr.text=str(page) pr.font.size=Pt(9); pr.font.color.rgb=GRAY; pp.alignment=PP_ALIGN.RIGHT def add_bullets(slide, items, left, top, width, height, size=14, color=TEXTDARK): tb = slide.shapes.add_textbox(left,top,width,height) tf = tb.text_frame; tf.word_wrap=True first=True for it in items: text,lvl = it if isinstance(it,tuple) else (it,0) p = tf.paragraphs[0] if first else tf.add_paragraph() first=False; p.level=lvl; p.space_after=Pt(8) pre = "• " if lvl==0 else " – " r = p.add_run(); r.text = pre+text r.font.size = Pt(size if lvl==0 else size-2); r.font.color.rgb=color def add_table(slide, data, left, top, width, height, col_widths=None, tag_col=None): rows,cols = len(data), len(data[0]) gtbl = slide.shapes.add_table(rows,cols,left,top,width,height) table = gtbl.table if col_widths: tot=sum(col_widths) for i,cw in enumerate(col_widths): table.columns[i].width = Emu(int(width*cw/tot)) for ri,row in enumerate(data): for ci,val in enumerate(row): cell = table.cell(ri,ci) cell.margin_left=Inches(0.07); cell.margin_right=Inches(0.07) cell.margin_top=Inches(0.03); cell.margin_bottom=Inches(0.03) cell.vertical_anchor=MSO_ANCHOR.MIDDLE tf = cell.text_frame; tf.word_wrap=True p = tf.paragraphs[0] if tag_col and ci in tag_col and ri>0: c_left = gtbl.left + sum(table.columns[k].width for k in range(ci)) c_top = gtbl.top + sum(table.rows[k].height for k in range(ri)) c_w = table.columns[ci].width c_h = table.rows[ri].height badge = slide.shapes.add_shape(MSO_SHAPE.ROUNDED_RECTANGLE, c_left+Emu(int(c_w*0.08)), c_top+Emu(int(c_h*0.2)), Emu(int(c_w*0.84)), Emu(int(c_h*0.6))) badge.fill.solid() badge.fill.fore_color.rgb = HUMAN_C if "人" in val else AUTO_C badge.line.fill.background(); badge.shadow.inherit=False btf = badge.text_frame; btf.word_wrap=True bp = btf.paragraphs[0]; bp.alignment=PP_ALIGN.CENTER br = bp.add_run(); br.text=val br.font.size=Pt(10); br.font.bold=True; br.font.color.rgb=WHITE cell.text = "" continue r = p.add_run(); r.text=val; r.font.size=Pt(11) if ri==0: cell.fill.solid(); cell.fill.fore_color.rgb=PRIMARY r.font.color.rgb=WHITE; r.font.bold=True else: cell.fill.solid(); cell.fill.fore_color.rgb = WHITE if ri%2 else LIGHT r.font.color.rgb=TEXTDARK if ci==0: r.font.bold=True return table def add_image(slide, path, left, top, width): slide.shapes.add_picture(path,left,top,width=width) def notes(slide, text): slide.notes_slide.notes_text_frame.text = text def new_page(title, page, subtitle=None): s = prs.slides.add_slide(BLANK); add_bg(s); add_title(s,title,page,subtitle); return s # ============ 1 封面 ============ cov = prs.slides.add_slide(BLANK); add_bg(cov,BG_DARK) acc = cov.shapes.add_shape(MSO_SHAPE.RECTANGLE,0,0,Inches(0.22),SH) acc.fill.solid(); acc.fill.fore_color.rgb=ACCENT; acc.line.fill.background(); acc.shadow.inherit=False t = cov.shapes.add_textbox(Inches(0.9),Inches(1.8),Inches(11.5),Inches(1.7)) tf=t.text_frame; tf.word_wrap=True p=tf.paragraphs[0]; r=p.add_run(); r.text="三阶段软硬配置及使用指南" r.font.size=Pt(42); r.font.bold=True; r.font.color.rgb=WHITE p2=tf.add_paragraph(); r2=p2.add_run(); r2.text="数据底座 → 模型引擎 → 日常使用运维" r2.font.size=Pt(20); r2.font.color.rgb=ACCENT st = cov.shapes.add_textbox(Inches(0.9),Inches(3.6),Inches(11.5),Inches(0.6)) sp=st.text_frame.paragraphs[0]; sr=sp.add_run() sr.text="每一阶段:客户能得到什么好处 | 工作流程怎么跑 | 人操作还是自动化" sr.font.size=Pt(16); sr.font.color.rgb=RGBColor(0xBB,0xD6,0xF2) info = cov.shapes.add_textbox(Inches(0.9),Inches(5.6),Inches(11.5),Inches(1.0)) ip=info.text_frame for i,line in enumerate(["客户:【客户名称】 服务商:【您的公司】", "配套文档:商业闭环运营基板 v1.9 / 硬件与部署实现方案 v1.1 / 本地模型好用落地设计 v1.0"]): pp=ip.paragraphs[0] if i==0 else ip.add_paragraph() rr=pp.add_run(); rr.text=line; rr.font.size=Pt(12); rr.font.color.rgb=RGBColor(0x9F,0xB6,0xCE) notes(cov,"【讲解】这份指南解决三个问题:客户能得到什么、流程怎么跑、哪些自动化哪些要人。") # ============ 2 目录 ============ s = new_page("目录",1) add_bullets(s,[ "一、整体架构速览 + 人机分工总原则", "二、阶段一:数据底座 —— 好处 / 流程 / 人机分工", "三、阶段二:模型引擎 —— 好处 / 流程 / 人机分工", "四、阶段三:日常使用与运维 —— 好处 / 流程 / 人机分工", "五、人操作 vs 自动化 总表", "六、客户好处汇总 + 你的运维节奏", "七、心里有底 QA + 红线兜底", ], Inches(0.9),Inches(1.7),Inches(11.5),Inches(4.6),size=17) # ============ 3 架构总览 ============ s = new_page("一、整体架构速览",2) add_image(s, os.path.join(ASSETS,"architecture.png"), Inches(1.6),Inches(1.35),Inches(10.1)) add_bullets(s,[ "人机分工总原则:一次性配置靠人,日常运行靠自动;老板只做两件事——看报告、问数据", ], Inches(0.9),Inches(6.6),Inches(11.5),Inches(0.6),size=13,color=PRIMARY) notes(s,"最底下硬件是一次性装机(人);数据清洗建库是定时自动;模型常驻自动路由;最上面看板/微信推送全自动。") # ============ 4 阶段一 目标与好处 ============ s = new_page("二之一、阶段一 数据底座:目标与客户好处",3) add_bullets(s,[ ("客户好处",0), "① 数据收拢成「一本账」:老板随时查任何月份、任何 SKU,不再等财务做表", "② 免费工具先学会自己看数据(演示+教学,不依赖别人)", "③ 数据资产在自己厂里,不出厂、不上云,放心", ("本阶段做什么",0), "免费工具 + 数据清洗整理 + SQLite 建库 + Streamlit 看板", ("自动化程度",0), "清洗入库、看板更新 = 全自动(cron 定时);老板查数据 = 人操作(浏览器打开就看)", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15) notes(s,"阶段一对应基板阶段一/二。价值锚:让老板第一次体验到「数据看得清」。") # ============ 5 阶段一 工作流程 ============ s = new_page("二之二、阶段一 数据底座:具体工作流程",4) add_bullets(s,[ "① 【人·老板】每月从网店后台导出 Excel/CSV,丢进共享文件夹(教一次就会)", "② 【自动·cron】每月 1 号凌晨,清洗脚本自动运行:去重→统一格式→入库 SQLite", "③ 【自动】看板数据自动刷新(服务常驻,无需重启)", "④ 【人·老板】打开浏览器随时查:月度趋势 / SKU 排行 / 区域分布 / 断码热力图", "⑤ 【人·你】每月 1 次数据对账:抽 3–5 个关键数跟老板确认,口径不变", "⑥ 【人·你】指标口径随业务调整时维护(季度级)", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.0),size=15) notes(s,"老板的日常操作只有一件事:导数据丢文件夹。其余全自动。") # ============ 6 阶段一 人机分工表 ============ s = new_page("二之三、阶段一 人操作 vs 自动化",5) add_table(s,[ ["功能","实现方式","频率","分工"], ["安装/配置免费工具","一次性部署到你电脑/客户机","一次性","人"], ["老板导出数据丢文件夹","平台后台导出","每周/每月","人"], ["数据清洗+入库 SQLite","Python 脚本 + cron","每月1号自动","自动"], ["看板数据刷新","Streamlit 服务常驻","实时","自动"], ["老板查数据/看板","浏览器访问内网地址","随时","人"], ["数据对账确认","抽数核对","每月1次","人"], ["指标口径维护","文档+脚本更新","按需","人"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3]) notes(s,"阶段一自动化集中在「清洗入库+看板」,人只做配置和每月对账。") # ============ 7 阶段二 目标与好处 ============ s = new_page("三之一、阶段二 模型引擎:目标与客户好处",6) add_bullets(s,[ ("客户好处",0), "① 数据不出厂也能 AI 分析:周报、归因、问答全在本地跑(敏感数据安全)", "② 响应快:本地 30B MoE 推理 25–35 Token/s,不用等网络", "③ 成本固定:本地模型一次买断,不按次收费,越用越划算", ("本阶段做什么",0), "EVO-X2+NAS 装机 → Ubuntu/ROCm → Ollama 多模型常驻 → Hermes Agent → API 混用兜底", ("自动化程度",0), "模型加载、任务路由、云端兜底 = 全自动;装机配置 = 一次性人操作", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15) notes(s,"阶段二对应基板阶段三。核心卖点:敏感数据本地分析 + 固定成本。") # ============ 8 阶段二 部署流程 ============ s = new_page("三之二、阶段二 模型引擎:部署流程",7) add_bullets(s,[ "① 【人·你】POC 先行:先用云端 API 在客户真实数据上跑出周报样例,老板认可才买硬件", "② 【人·你】装机:EVO-X2 装 Ubuntu 24.04 + ROCm 驱动(最大坑,样机先跑通)+ NAS RAID5", "③ 【人·你】模型部署:Ollama 拉 35B MoE + 14B + bge-m3,设 keep_alive 常驻", "④ 【人·你】Agent 配置:Hermes Agent 注册工具(查库/发消息/生成报告)+ 任务路由规则", "⑤ 【人·你】API 混用配置:DeepSeek 兜底开关(置信度低自动转云端)", "⑥ 【自动】之后:模型常驻、路由、兜底全部自动运行,无需人工干预", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.0),size=15) notes(s,"阶段二是配置密集型:全部一次性配置做完,之后全自动。") # ============ 9 阶段二 人机分工表 ============ s = new_page("三之三、阶段二 人操作 vs 自动化",8) add_table(s,[ ["功能","实现方式","频率","分工"], ["POC 效果验证","云端 API 跑样例给老板看","客户掏钱前","人"], ["硬件装机","EVO-X2+NAS 安装调试","一次性","人"], ["ROCm/驱动/系统","Ubuntu 24.04 + ROCm 配置","一次性","人"], ["模型加载/常驻","Ollama keep_alive","自动运行","自动"], ["任务路由","Agent 按任务分模型","实时","自动"], ["云端 API 兜底","置信度低自动 fallback","实时","自动"], ["月度特调模型(QLoRA)","27B 特调训练","3个月后按需","人"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3]) notes(s,"阶段二 7 项里 5 项自动,人只做装机和 POC。") # ============ 10 阶段三 目标与好处 ============ s = new_page("四之一、阶段三 日常使用运维:目标与客户好处",9) add_bullets(s,[ ("客户好处",0), "① 每周一自动收《经营周报》:不用做表,微信直接看图文", "② 断码/库存预警自动推送:缺货出事前就知道,不等老板发现", "③ 随时问数据:像问助手一样「上月华东卖了多少」,秒回", "④ 每月 4 次到岗专属服务:特调模型、问答库整理、巡检、答疑", "⑤ 决策有依据:补货建议、现金流模拟、SKU 优化", ("自动化程度",0), "周报/预警/问答 = 全自动(定时任务+Agent);月度到岗 = 人操作(你)", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=15) notes(s,"阶段三对应基板阶段三运行期+阶段四。客户日常几乎零操作。") # ============ 11 阶段三 功能流程 ============ s = new_page("四之二、阶段三 日常功能工作流程",10) add_bullets(s,[ ("周报(全自动)",0), "① 每周一早 9 点 cron 触发 → ② Agent 读库 → ③ 35B MoE 生成图文简报 → ④ 微信推给老板", ("断码预警(全自动)",0), "① 每日 08:00 扫描库存 → ② 命中断码阈值 → ③ Agent 生成预警 → ④ 微信推送", ("数据问答(半自动)",0), "① 老板微信/看板提问 → ② Agent 查库 → ③ 本地模型组织答案 → ④ 秒回(复杂问题自动转云端)", ("月度到岗(人操作·你)",0), "每月 4 次:特调模型优化 / A&Q 问答库整理 / 巡检备份 / 老板答疑", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(5.2),size=14) notes(s,"周报、预警完全不需要人碰;问答是人问机答;到岗是你的服务承诺。") # ============ 12 阶段三 人机分工表 ============ s = new_page("四之三、阶段三 人操作 vs 自动化",11) add_table(s,[ ["功能","实现方式","频率","分工"], ["经营周报推送","cron + Agent + 微信","每周一早9点","自动"], ["断码/库存预警","每日库存扫描 + 阈值触发","每日08:00","自动"], ["数据问答","Agent 查库 + 本地模型回答","随时","人问/机答"], ["月度到岗(4次)","上门服务","每月4次","人"], ["备份快照","NAS 每日快照 + 异地","每日/每周","自动"], ["巡检与日志检查","远程巡检","每周1次","人"], ["备份还原演练","手动演练","每月1次","人"], ["模型效果抽查","抽查5条输出质量","每周1次","人"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.6),col_widths=[2.6,3.2,1.8,2.4],tag_col=[3]) notes(s,"核心功能全自动;人的动作集中在巡检、到岗、抽查。") # ============ 13 总表 ============ s = new_page("五、人操作 vs 自动化 总表(一页看全)",12) add_table(s,[ ["环节","自动化的","需要人操作的","老板日常动作"], ["阶段一 数据底座","清洗入库、看板刷新(cron)","安装配置、每月对账","导数据丢文件夹、看板查数"], ["阶段二 模型引擎","模型常驻、路由、API 兜底","POC、装机、特调","无(全自动)"], ["阶段三 使用运维","周报、断码预警、问答","月度到岗、巡检、抽查","看微信、问数据"], ["你(服务商)","—","到岗4次/月 + 远程巡检 + 维护","—"], ], Inches(0.7),Inches(1.8),Inches(11.9),Inches(3.8),col_widths=[2.2,3.4,3.6,2.8]) add_bullets(s,[ "结论:老板每周只花 10 分钟(看周报+导数据);你的日常是每周远程巡检 1 次 + 每月到岗 4 次", ], Inches(0.9),Inches(6.0),Inches(11.5),Inches(0.8),size=14,color=PRIMARY) notes(s,"这张表是给客户看「我买了什么服务」的总图。") # ============ 14 好处汇总 ============ s = new_page("六之一、客户得到的好处汇总(老板视角)",13) add_table(s,[ ["好处","对应功能","解决什么问题"], ["不再等财务做表","周报每周一自动推送","报表慢、人力耗"], ["数据随时看得清","看板+数据问答","看不清赚亏"], ["出事早知道","断码/异常预警","缺货、积压后知后觉"], ["敏感数据不出厂","本地模型+NAS","怕数据泄露"], ["决策有依据","补货/现金流/SKU 建议","拍脑袋备货"], ["有人全程管","月度到岗+远程运维","系统没人维护"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(3.6),col_widths=[3.0,4.2,3.4]) add_bullets(s,[ "一句话给老板:数据留在厂里,分析自动跑,报告送到手机,出事提前提醒,决策有人给依据", ], Inches(0.9),Inches(5.6),Inches(11.5),Inches(0.8),size=15,color=HIGHLIGHT) # ============ 15 运维节奏 ============ s = new_page("六之二、你的运维节奏(每天/每周/每月/每季)",14) add_table(s,[ ["频率","动作","耗时"], ["每天","看系统告警(模型/服务异常到你微信)","10 分钟"], ["每周","① 确认周一周报已发出 ② 抽查 5 条输出质量","20 分钟"], ["每月","4 次到岗(特调/A&Q/巡检/答疑)+ 备份还原演练 + API 用量核对","4 个半天"], ["每季度","模型效果评估 + 客户升档评估 + 特调需求评估","1 天"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(3.4),col_widths=[1.4,6.2,2.6]) add_bullets(s,[ "单人可承受:每周合计约 1 小时远程 + 每月 4 个半天到岗 —— 这是月维护费 2000/3000 的服务边界", ], Inches(0.9),Inches(5.4),Inches(11.5),Inches(0.8),size=14,color=PRIMARY) # ============ 16 QA ============ s = new_page("七之一、心里有底 QA(常见问题)",15) add_table(s,[ ["问题","答案"], ["机器挂了怎么办?","数据在 NAS(RAID+快照+异地),换机重装系统后还原,1 天内恢复(每月演练过)"], ["模型效果差怎么办?","按顺序调:查 RAG 检索 → 改提示词 → 换大模型 → 最后才微调;期间置信度低自动转云端,客户无感"], ["断电了怎么办?","UPS 兜底 10 分钟,来电自动恢复;NAS 有快照不怕掉盘"], ["客户要加新功能?","工具函数库加一个函数即可(模板化),半天内上线"], ["老板要查数据?","看板随时查 / 微信问一句秒回"], ["数据更新怎么进系统?","客户导出丢文件夹 → cron 自动清洗入库,不用你干预"], ["客户停缴维护费?","系统停更但已交付功能保留(威慑不撕破脸)"], ["你自己生病/忙不过来?","SOP 文档化 + 远程自动运维,关键操作留文档"], ], Inches(0.7),Inches(1.7),Inches(11.9),Inches(4.8),col_widths=[2.6,9.4]) # ============ 17 红线兜底 ============ s = new_page("七之二、红线与兜底机制",16) add_bullets(s,[ "① 数据不出厂:NAS 只在内网,Tailscale 只放行你;云端 API 只接可脱敏任务", "② POC 先行:客户掏钱前先用云端样例验证效果,效果好才买硬件", "③ 验收前置:合同写明「本地完成的任务验收 = 格式正确+规则正确」,主观好坏交云端", "④ 兜底开关:Agent 置信度低 → 自动转云端 API,客户无感切换", "⑤ 本地主力:35B MoE 承接 80–90% 任务,云端只是保险丝(月预算 <200)", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(4.6),size=15) # ============ 18 第一周清单 ============ s = new_page("七之三、交付后第一周清单",17) add_bullets(s,[ "☐ 免费工具装好,老板学会自己拖数据", "☐ 数据盘点拿到(含尺码维度,鞋类客户必查)", "☐ 清洗脚本跑通,老板点过关键数", "☐ 一页流程图交付(含退换货流程)", "☐ 备忘录签署(免费边界 + 3 个月保护期 + 案例转介绍)", "☐ 约好下周:教老板拖新数据 + 提阶段二(周报 300/次)", ], Inches(0.9),Inches(1.6),Inches(11.5),Inches(4.2),size=15) # ============ 19 封底 ============ s = prs.slides.add_slide(BLANK); add_bg(s,BG_DARK) t = s.shapes.add_textbox(Inches(0.9),Inches(3.0),Inches(11.5),Inches(1.5)) tf=t.text_frame; tf.word_wrap=True p=tf.paragraphs[0]; p.alignment=PP_ALIGN.CENTER r=p.add_run(); r.text="三阶段软硬配置及使用指南 · v1.0" r.font.size=Pt(30); r.font.bold=True; r.font.color.rgb=WHITE p2=tf.add_paragraph(); p2.alignment=PP_ALIGN.CENTER r2=p2.add_run(); r2.text="配置一次 · 运行自动 · 老板零操作 · 你只做维护" r2.font.size=Pt(16); r2.font.color.rgb=ACCENT prs.save(OUT) print("saved:", OUT, "slides:", len(prs.slides._sldIdLst))