feat: 新增语音转文字(ASR)功能
- 后端:新增 /api/audio/transcribe 接口,调用 Ollama whisper 进行语音识别 - 前端:新增 AudioTranscribePage.vue 页面,支持 MP3/WAV/M4A/OGG/FLAC 等格式 - 注册路由、工具卡片、智能助手欢迎语更新 Co-Authored-By: Claude Code <noreply@anthropic.com>
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,261 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""博昇内部培训平台 —— 培训素材内容库(供 PDF / DOCX / MP4 生成脚本共用)"""
|
||||
|
||||
COMPANY_INTRO = {
|
||||
"title": "博昇公司介绍",
|
||||
"sections": [
|
||||
("关于博昇", [
|
||||
"博昇,聚焦企业增长与 AI 落地的综合服务商。",
|
||||
"我们围绕企业从「资本运作」到「资质认定」再到「AI 转型」的完整成长链路,提供四大板块服务,陪伴企业走通从融资到增长、再到智能化升级的全过程。",
|
||||
]),
|
||||
("四大业务板块", [
|
||||
"一、资本咨询:股权规划、融资顾问、IPO 辅导,陪伴企业走通资本路径。",
|
||||
"二、资质认定辅导:高新技术企业、专精特新、专精特新「小巨人」的申报陪跑。",
|
||||
"三、AI 咨询与实施:AI 公开课、落地诊断、软件与定制开发。",
|
||||
"四、企业级 AI 工具与平台:按行业匹配知识库、办公智能体、工业/医疗 AI、内容生成、电商运营等方案。",
|
||||
]),
|
||||
("我们的价值主张", [
|
||||
"以「资本 + AI」双引擎驱动企业成长:用资本咨询帮企业解决钱与路径的问题,用 AI 落地帮企业解决效率与竞争力的升级问题。",
|
||||
"本培训平台用于新员工入职培训与全员持续学习,涵盖公司认知、产品知识、销售能力训练与统一考试验收。",
|
||||
]),
|
||||
],
|
||||
}
|
||||
|
||||
PRODUCT_LINES = {
|
||||
"title": "产品线总览与销售地图",
|
||||
"lines": [
|
||||
("资本咨询类(1.x)", [
|
||||
"引流课、企业内训/定制咨询、企业长期资本顾问合作。",
|
||||
"面向有融资、股权规划、上市需求的企业;销售重点是识别客户所处阶段并匹配资本工具。",
|
||||
]),
|
||||
("资质认定辅导类(2.x)", [
|
||||
"辅导高新技术企业认定、辅导专精特新认定、辅导专精特新「小巨人」。",
|
||||
"面向有资质申报、税收优惠与政策奖补需求的企业;销售重点是帮客户算清「够不够格、能省多少钱」。",
|
||||
]),
|
||||
("AI 咨询类(3.x)", [
|
||||
"AI 公开课(WorkBuddy、企微智能表格)、企业 AI 落地诊断(线上/线下)、AI 软件(一次性授权)、定制软件开发。",
|
||||
"面向想用 AI 提效但不知道从哪下手的客户;销售重点是小步快跑、POC 验证。",
|
||||
]),
|
||||
("企业级 AI 工具与平台(4.x)", [
|
||||
"企业级知识库、多智能体集成工作台、工业检测、机器视觉、医疗多组学、AI 短视频、GEO 优化、电商管理等 16 款产品。",
|
||||
"面向有明确行业场景的客户;销售重点是方案匹配与 ROI 论证。",
|
||||
]),
|
||||
],
|
||||
}
|
||||
|
||||
# —— 资质认定知识(06) ——
|
||||
QUALIFICATION_KNOWLEDGE = {
|
||||
"高企认定八条件": [
|
||||
"高新技术企业(高企)认定须同时满足八项条件:",
|
||||
"1. 注册成立一年以上;",
|
||||
"2. 取得对主要产品(服务)起核心支持作用的知识产权所有权(中国境内授权);",
|
||||
"3. 核心技术属于《国家重点支持的高新技术领域》;",
|
||||
"4. 科技人员占职工总数比例不低于 10%;",
|
||||
"5. 近三个会计年度研发费用总额占销售收入总额比例达标;",
|
||||
"6. 近一年高新技术产品(服务)收入占总收入比例不低于 60%;",
|
||||
"7. 创新能力评价达标(70 分以上);",
|
||||
"8. 申请前一年内未发生重大安全、重大质量事故或严重环境违法。",
|
||||
],
|
||||
"高企研发费用占比": [
|
||||
"按最近一年销售收入分档:",
|
||||
"· 小于 5000 万元(含):不低于 5%;",
|
||||
"· 5000 万元至 2 亿元(含):不低于 4%;",
|
||||
"· 2 亿元以上:不低于 3%。",
|
||||
"其中中国境内研发费用占比不低于 60%。",
|
||||
],
|
||||
"高企知识产权与税收优惠": [
|
||||
"Ⅰ类知识产权:发明专利、植物新品种、国家新药、集成电路布图设计专有权等(权重高);",
|
||||
"Ⅱ类知识产权:实用新型、外观设计、软件著作权(权重低)。",
|
||||
"高企核心收益:企业所得税税率从 25% 降至 15%,并享受研发费用加计扣除。",
|
||||
],
|
||||
"专精特新梯度培育": [
|
||||
"优质中小企业按三级梯度逐级培育、逐级申报:",
|
||||
"创新型中小企业 → 专精特新中小企业 → 专精特新小巨人企业。",
|
||||
"专精特新中小企业是骨干力量(专业化、精细化、特色化、新颖化);小巨人是中坚力量(掌握核心技术、细分市场占有率高)。",
|
||||
],
|
||||
"专精特新小巨人门槛(2026)": [
|
||||
"2026 年新修订办法适当提高门槛:",
|
||||
"· 营业收入提升至 5000 万元以上;",
|
||||
"· 近两年研发费用合计不低于 1200 万元;",
|
||||
"· Ⅰ类知识产权 4 项以上(须为企业自主申请、排名前三)。",
|
||||
"有效期 3 年,到期复核通过后延长 3 年。",
|
||||
],
|
||||
"高企与专精特新的区别": [
|
||||
"高企:科技部门主导,侧重技术创新与研发投入,享 15% 所得税优惠;",
|
||||
"专精特新:工信部门主导,侧重专业化、精细化、特色化、新颖化,获得重点培育与资源倾斜。",
|
||||
"两者可叠加申报,部分地区同年度多项认定可叠加奖励。",
|
||||
],
|
||||
"常见资质认证与补贴": [
|
||||
"ISO 三体系:ISO9001(质量)、ISO14001(环境)、ISO45001(职业健康安全)。",
|
||||
"另有 ISO27001(信息安全)、AAA 信用企业、知识产权贯标、两化融合、CMMI 等。",
|
||||
"政府奖补多仅限首次认证,需保留证书、合同、发票原件,认证机构须经国家认监委认可。",
|
||||
],
|
||||
}
|
||||
|
||||
# —— 资本运作知识(07) ——
|
||||
CAPITAL_KNOWLEDGE = {
|
||||
"股权融资 vs 债权融资": [
|
||||
"股权融资:出让部分股权引入资金,无需偿还、无固定利息,但稀释控制权与分红;",
|
||||
"债权融资:按期还本付息,不稀释股权但增加财务杠杆与偿债压力。",
|
||||
"先判断客户是「缺钱但想保控制权」还是「愿稀释换成长」,再匹配工具。",
|
||||
],
|
||||
"融资轮次与估值方法": [
|
||||
"轮次:种子轮(验证想法)→ 天使轮(团队+原型)→ A 轮(产品跑通)→ B 轮(规模化)→ C 轮及以后 → Pre-IPO。",
|
||||
"估值方法:收益法(DCF 现金流折现)、市场法(可比公司/交易乘数)、资产法(净资产/重置成本)。",
|
||||
"常见乘数:P/E(市值/净利润)、P/S(市值/营收)、P/B(市值/净资产)、PEG(P/E÷增速)。",
|
||||
],
|
||||
"尽职调查与核心条款": [
|
||||
"尽调三维度:业务尽调(模式、客户、市场、收入真实性)、财务尽调(现金流、负债、税务、关联交易)、法律尽调(股权、历史、知识产权、诉讼)。",
|
||||
"核心条款:估值与金额、董事会席位与一票否决权、反稀释、对赌/回购、优先清算权、竞业禁止、期权池(ESOP)。",
|
||||
],
|
||||
"对赌协议与退出方式": [
|
||||
"对赌(VAM):就未来业绩(净利润、营收、上市时间)达成的估值调整,未达成则创始人补偿现金或股权。",
|
||||
"退出:IPO(回报最高但门槛高)、并购(M&A)、股权回购、老股转让。",
|
||||
],
|
||||
"融资材料与路演": [
|
||||
"BP(10–20 页)核心逻辑:一句话定位 → 市场空间 → 产品/模式 → 竞争壁垒 → 团队 → 财务预测与融资计划。",
|
||||
"路演讲清「为什么是你、为什么是现在、钱怎么花、回报是什么」。",
|
||||
],
|
||||
}
|
||||
|
||||
# —— AI 落地知识(08) ——
|
||||
AI_KNOWLEDGE = {
|
||||
"大模型选型": [
|
||||
"闭源(GPT、Claude、文心、通义):开箱即用、性能稳,但数据出域、按量付费、定制受限;",
|
||||
"开源(Llama、Qwen、DeepSeek、GLM):可本地私有化、数据不出域、可微调,但需自建算力与运维。",
|
||||
"7B/13B 可在单卡量化运行;70B 以上需多卡或数据中心。按「任务难度 vs 成本」选型。",
|
||||
],
|
||||
"RAG 构建五步": [
|
||||
"RAG(检索增强生成)让大模型带着企业私域知识作答:",
|
||||
"① 文档解析切块 → ② 文本向量化 → ③ 向量入库 → ④ 检索召回 → ⑤ 拼进提示词生成。",
|
||||
"解决知识过时、幻觉、缺乏私有数据三大痛点。",
|
||||
],
|
||||
"混合检索与提示词工程": [
|
||||
"混合检索 = 向量语义检索 + 关键词检索(BM25)+ 重排(Rerank),兼顾语义与精确。",
|
||||
"提示词技巧:角色设定、明确任务与格式、few-shot 示例、思维链 CoT、设定约束、自检再输出。",
|
||||
],
|
||||
"智能体与 POC 三阶段": [
|
||||
"Agent 能力:工具调用(Function Calling)、任务规划、记忆、多智能体协作;MCP 是连接模型与工具的标准化协议。",
|
||||
"POC 三阶段:数据准备 → 模型与流程搭建 → 效果评估(准确率、召回率、延迟、幻觉率、ROI)。",
|
||||
],
|
||||
"私有化三模式": [
|
||||
"纯私有化(数据不出域、成本高)→ 混合部署(敏感模块私有、通用走云)→ SaaS/公有云 API(快但数据出域)。",
|
||||
"按行业合规要求与预算推荐。",
|
||||
],
|
||||
}
|
||||
|
||||
# —— 销售方法论(09) ——
|
||||
SALES_KNOWLEDGE = {
|
||||
"FABE 法则": [
|
||||
"F(Features 特征):产品本身的特点;",
|
||||
"A(Advantages 优势):比竞品好在哪;",
|
||||
"B(Benefits 利益):给客户的具体价值;",
|
||||
"E(Evidence 证据):案例、数据、演示、证言。",
|
||||
"从客户需求倒推,把特征翻译成客户听得懂的利益,并用证据收尾。",
|
||||
],
|
||||
"SPIN 提问法": [
|
||||
"S(Situation 背景):了解客户现状;",
|
||||
"P(Problem 困难):挖掘现状中的问题;",
|
||||
"I(Implication 暗示):放大问题不解决的后果;",
|
||||
"N(Need-payoff 需求回报):引导客户认同解决方案的价值。",
|
||||
"核心:让客户自己说出痛点、自己意识到价值。",
|
||||
],
|
||||
"LSCPA 异议处理": [
|
||||
"L(Listen 倾听)→ S(Share 同理)→ C(Clarify 澄清)→ P(Present 呈现)→ A(Ask 请求行动)。",
|
||||
"切忌直接反驳,先接情绪再解问题。",
|
||||
],
|
||||
"顾问式销售五步": [
|
||||
"① 建立信任(专业+真诚)→ ② 诊断需求(SPIN)→ ③ 提出方案(FABE)→ ④ 处理异议(LSCPA)→ ⑤ 促成与跟进。",
|
||||
"核心:从「卖产品」转向「帮客户解决问题」。",
|
||||
],
|
||||
"成交信号与技巧": [
|
||||
"成交信号:反复问价格付款、问交付时间、问细节售后、索要方案、沉默思考。",
|
||||
"技巧:直接成交、假设成交、选择成交、稀缺成交(须真实)、从众成交、让步成交。",
|
||||
],
|
||||
}
|
||||
|
||||
# —— 清单 / 检查表(DOCX 用) ——
|
||||
CHECKLISTS = {
|
||||
"高企认定八条件自查清单": [
|
||||
"□ 注册成立满一年以上",
|
||||
"□ 拥有核心支持作用的知识产权(中国境内授权)",
|
||||
"□ 核心技术属于国家重点支持领域",
|
||||
"□ 科技人员占比 ≥ 10%",
|
||||
"□ 研发费用占比达标(按最近一年销售收入分档)",
|
||||
"□ 高新技术产品收入占比 ≥ 60%",
|
||||
"□ 创新能力评价 ≥ 70 分",
|
||||
"□ 前一年无重大安全/质量/环境事故",
|
||||
],
|
||||
"专精特新申报自查表": [
|
||||
"□ 属于优质中小企业梯度培育范围(创新型 → 专精特新 → 小巨人)",
|
||||
"□ 小巨人:营业收入 ≥ 5000 万元",
|
||||
"□ 小巨人:近两年研发费用合计 ≥ 1200 万元",
|
||||
"□ 小巨人:Ⅰ类知识产权 ≥ 4 项(自主申请、排名前三)",
|
||||
"□ 有效期 3 年,到期前复核通过可延长",
|
||||
"□ 每年 5 月 31 日前在培育平台更新信息",
|
||||
],
|
||||
"融资尽调资料清单": [
|
||||
"□ 营业执照、公司章程、股东名册",
|
||||
"□ 近三年财务报表与审计报告",
|
||||
"□ 银行流水、纳税申报表",
|
||||
"□ 核心合同、客户与供应商清单",
|
||||
"□ 知识产权清单与权属证明",
|
||||
"□ 重大诉讼、行政处罚情况",
|
||||
"□ 商业计划书(BP)与财务预测模型",
|
||||
],
|
||||
"AI 落地 POC 检查表": [
|
||||
"□ 明确业务场景与验收标准",
|
||||
"□ 数据准备(清洗、标注、切块)",
|
||||
"□ 模型与检索流程搭建",
|
||||
"□ 设定评估指标(准确率、召回率、延迟、幻觉率、ROI)",
|
||||
"□ 小范围试点与迭代优化",
|
||||
"□ 安全合规(数据脱敏、权限、幻觉控制)",
|
||||
"□ 成本预算与持续运营计划",
|
||||
],
|
||||
}
|
||||
|
||||
# —— 模板(DOCX 用) ——
|
||||
TEMPLATES = {
|
||||
"销售周报模板": [
|
||||
"【本周业绩】",
|
||||
"· 拜访客户数:",
|
||||
"· 有效商机数:",
|
||||
"· 报价/签约金额:",
|
||||
"【重点客户跟进】",
|
||||
"· 客户名称 / 阶段 / 下一步动作 / 预计金额:",
|
||||
"【问题与求助】",
|
||||
"· 遇到的异议 / 需要的支持:",
|
||||
"【下周计划】",
|
||||
"· 重点目标客户与拜访安排:",
|
||||
],
|
||||
"顾问式销售演练脚本": [
|
||||
"开场(建立信任):自我介绍 + 说明来意 + 表明以客户问题为中心。",
|
||||
"诊断(SPIN 提问):先问背景,再挖困难,放大后果,引导价值。",
|
||||
"呈现(FABE):讲利益不讲功能,配合证据。",
|
||||
"异议(LSCPA):先听、再同理、澄清、呈现方案、请求下一步。",
|
||||
"促成(试探成交):把「买不买」变成「怎么买」。",
|
||||
],
|
||||
}
|
||||
|
||||
# —— 考试复习提纲 ——
|
||||
EXAM_REVIEW = {
|
||||
"title": "考试题库复习提纲",
|
||||
"sections": [
|
||||
("公司知识", [
|
||||
"博昇是聚焦企业增长与 AI 落地的综合服务商,双主营:资本咨询 + AI 落地。",
|
||||
"四大板块:资本咨询、资质认定辅导、AI 咨询与实施、企业级 AI 工具与平台。",
|
||||
]),
|
||||
("产品知识", [
|
||||
"四大产品分类:资本咨询类、资质认定辅导类、AI 咨询类、AI 工具平台类。",
|
||||
"重点记忆各产品的收费结构、佣金比例(仅推荐 / 参与谈单)、公开课奖励与报备规则。",
|
||||
]),
|
||||
("销售知识", [
|
||||
"FABE(特征/优势/利益/证据)、SPIN(背景/困难/暗示/需求回报)、LSCPA(倾听/同理/澄清/呈现/请求行动)。",
|
||||
"顾问式销售五步与常见成交技巧、大客户决策链分析。",
|
||||
]),
|
||||
("行业知识", [
|
||||
"高企八条件、研发费用占比、知识产权分类;专精特新梯度与小巨人门槛。",
|
||||
"融资轮次、估值方法、尽调维度、对赌与退出;AI 选型、RAG、Agent、私有化部署。",
|
||||
]),
|
||||
],
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,289 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""生成 15 份 DOCX 培训文档(python-docx)"""
|
||||
import json, os, sys
|
||||
from docx import Document
|
||||
from docx.shared import Pt, RGBColor, Cm
|
||||
from docx.enum.text import WD_ALIGN_PARAGRAPH
|
||||
from docx.oxml.ns import qn
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(os.path.dirname(HERE), "word")
|
||||
sys.path.insert(0, HERE)
|
||||
import content as C
|
||||
|
||||
EAST = "宋体" # Word 兼容的中文字体
|
||||
|
||||
def set_font(run, size=11, bold=False, color=None):
|
||||
run.font.name = "Calibri"
|
||||
run.font.size = Pt(size)
|
||||
run.font.bold = bold
|
||||
if color:
|
||||
run.font.color.rgb = RGBColor(*color)
|
||||
r = run._element
|
||||
rPr = r.get_or_add_rPr()
|
||||
rFonts = rPr.get_or_add_rFonts()
|
||||
rFonts.set(qn("w:eastAsia"), EAST)
|
||||
|
||||
def add_para(doc, text, size=11, bold=False, color=None, align=None, space_after=6):
|
||||
p = doc.add_paragraph()
|
||||
if align:
|
||||
p.alignment = align
|
||||
p.paragraph_format.space_after = Pt(space_after)
|
||||
run = p.add_run(text)
|
||||
set_font(run, size, bold, color)
|
||||
return p
|
||||
|
||||
def add_heading(doc, text, level=1):
|
||||
p = doc.add_heading(level=level)
|
||||
run = p.add_run(text)
|
||||
size = {1: 16, 2: 13, 3: 11}[level]
|
||||
set_font(run, size, bold=True, color=(0x1f, 0x4e, 0x79))
|
||||
return p
|
||||
|
||||
def add_bullet(doc, text, size=11):
|
||||
p = doc.add_paragraph(style="List Bullet")
|
||||
p.paragraph_format.space_after = Pt(3)
|
||||
run = p.add_run(text)
|
||||
set_font(run, size)
|
||||
return p
|
||||
|
||||
def add_sections(doc, sections):
|
||||
for title, paras in sections:
|
||||
add_heading(doc, title, 2)
|
||||
for para in paras:
|
||||
add_para(doc, para)
|
||||
|
||||
def add_knowledge(doc, knowledge):
|
||||
for title, paras in knowledge.items():
|
||||
add_heading(doc, title, 2)
|
||||
for para in paras:
|
||||
add_para(doc, para)
|
||||
|
||||
def new_doc(title):
|
||||
doc = Document()
|
||||
add_para(doc, title, size=20, bold=True, color=(0x1f, 0x4e, 0x79), align=WD_ALIGN_PARAGRAPH.CENTER, space_after=4)
|
||||
add_para(doc, "博昇内部培训平台 · 学习资料", size=9, color=(0x80, 0x80, 0x80), align=WD_ALIGN_PARAGRAPH.CENTER, space_after=16)
|
||||
return doc
|
||||
|
||||
def save(doc, filename):
|
||||
doc.save(os.path.join(OUT, filename))
|
||||
print(" DOCX 生成:", filename)
|
||||
|
||||
def load_products():
|
||||
return json.load(open(os.path.join(HERE, "products.json")))["data"]
|
||||
|
||||
def load_courses():
|
||||
return json.load(open(os.path.join(HERE, "courses.json")))["data"]
|
||||
|
||||
def load_questions():
|
||||
data = json.load(open(os.path.join(HERE, "questions.json")))["data"]
|
||||
return data if isinstance(data, list) else data.get("items", [])
|
||||
|
||||
CAT_LABEL = {
|
||||
"capital_consulting": "资本咨询类",
|
||||
"qualification_counseling": "资质认定辅导类",
|
||||
"ai_consulting": "AI 咨询类",
|
||||
"ai_tools_platform": "企业级 AI 工具与平台",
|
||||
}
|
||||
|
||||
def products_table(doc, products, columns):
|
||||
"""生成产品速查表。columns: [(表头, 取值函数)]"""
|
||||
table = doc.add_table(rows=1, cols=len(columns))
|
||||
table.style = "Light Grid Accent 1"
|
||||
hdr = table.rows[0].cells
|
||||
for i, (h, _) in enumerate(columns):
|
||||
hdr[i].text = ""
|
||||
run = hdr[i].paragraphs[0].add_run(h)
|
||||
set_font(run, 10, bold=True)
|
||||
for p in products:
|
||||
row = table.add_row().cells
|
||||
for i, (_, fn) in enumerate(columns):
|
||||
row[i].text = ""
|
||||
run = row[i].paragraphs[0].add_run(fn(p))
|
||||
set_font(run, 9)
|
||||
doc.add_paragraph()
|
||||
|
||||
def main():
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
products = load_products()
|
||||
courses = load_courses()
|
||||
questions = load_questions()
|
||||
def cat(c): return [p for p in products if p["category"] == c]
|
||||
|
||||
# 01 新人入职学习计划
|
||||
doc = new_doc("新人入职学习计划")
|
||||
add_heading(doc, "第一阶段:公司认知(第 1 天)", 2)
|
||||
for t in ["阅读《公司介绍》PDF,了解博昇四大业务板块", "浏览公司介绍培训页,完成公司认知学习", "学习产品线总览,建立四大产品分类框架"]:
|
||||
add_bullet(doc, t)
|
||||
add_heading(doc, "第二阶段:产品知识(第 2-4 天)", 2)
|
||||
for t in ["精读四大产品手册:资本咨询 / 资质认定 / AI 咨询 / AI 工具平台", "重点记忆各产品收费、佣金(仅推荐 / 参与谈单)、报备规则", "完成产品知识自测题,目标正确率 90% 以上"]:
|
||||
add_bullet(doc, t)
|
||||
add_heading(doc, "第三阶段:销售能力(第 5-6 天)", 2)
|
||||
for t in ["学习 FABE / SPIN / LSCPA 三大方法论", "完成顾问式销售演练脚本练习", "观看销售技巧培训视频,记录话术要点"]:
|
||||
add_bullet(doc, t)
|
||||
add_heading(doc, "第四阶段:考试验收(第 7 天)", 2)
|
||||
for t in ["复习《考试题库复习提纲》", "完成正式考试,目标通过"]:
|
||||
add_bullet(doc, t)
|
||||
save(doc, "01_新人入职学习计划.docx")
|
||||
|
||||
# 02 产品佣金速查表
|
||||
doc = new_doc("产品佣金速查表")
|
||||
add_para(doc, "下表为全部在售产品的收费与佣金速查,销售谈单时对照使用。", size=10, color=(0x80,0x80,0x80))
|
||||
products_table(doc, products, [
|
||||
("编号", lambda p: p["code"]),
|
||||
("产品", lambda p: p["name"]),
|
||||
("分类", lambda p: CAT_LABEL.get(p["category"], p["category"])),
|
||||
("收费", lambda p: p.get("pricing") or "—"),
|
||||
("佣金(推荐)", lambda p: p.get("commission_recommend") or "—"),
|
||||
("佣金(谈单)", lambda p: p.get("commission_negotiate") or "—"),
|
||||
("公开课奖励", lambda p: p.get("public_course_bonus") or "—"),
|
||||
])
|
||||
save(doc, "02_产品佣金速查表.docx")
|
||||
|
||||
# 03 / 04 销售流程清单(从课程数据)
|
||||
def course_doc(filename, title, category):
|
||||
doc = new_doc(title)
|
||||
found = False
|
||||
for c in courses:
|
||||
if c["category"] != category:
|
||||
continue
|
||||
found = True
|
||||
add_heading(doc, c["name"], 1)
|
||||
field_map = [("目标客户", "target_customers"), ("禁区客户", "forbidden_customers"),
|
||||
("话术", "scripts"), ("销售流程", "sales_process"),
|
||||
("异议处理", "objection_handling"), ("避坑提醒", "delivery_pitfalls"),
|
||||
("报备规则", "report_rules")]
|
||||
for label, key in field_map:
|
||||
v = (c.get(key) or "").strip()
|
||||
if v:
|
||||
add_heading(doc, label, 2)
|
||||
for line in v.splitlines():
|
||||
if line.strip():
|
||||
add_bullet(doc, line.strip())
|
||||
if not found:
|
||||
add_para(doc, "(暂无该分类课程内容)")
|
||||
save(doc, filename)
|
||||
|
||||
course_doc("03_资本咨询销售流程清单.docx", "资本咨询销售流程清单", "capital_script")
|
||||
course_doc("04_资质认定销售流程清单.docx", "资质认定销售流程清单", "qualification_logic")
|
||||
|
||||
# 05-08 清单检查表
|
||||
def checklist_doc(filename, title, items):
|
||||
doc = new_doc(title)
|
||||
add_para(doc, "请逐项核对,完成打勾。", size=10, color=(0x80,0x80,0x80))
|
||||
for it in items:
|
||||
add_bullet(doc, it)
|
||||
save(doc, filename)
|
||||
|
||||
checklist_doc("05_高企认定八条件自查清单.docx", "高企认定八条件自查清单", C.CHECKLISTS["高企认定八条件自查清单"])
|
||||
checklist_doc("06_专精特新申报自查表.docx", "专精特新申报自查表", C.CHECKLISTS["专精特新申报自查表"])
|
||||
checklist_doc("07_融资尽调资料清单.docx", "融资尽调资料清单", C.CHECKLISTS["融资尽调资料清单"])
|
||||
checklist_doc("08_AI落地POC检查表.docx", "AI 落地 POC 检查表", C.CHECKLISTS["AI 落地 POC 检查表"])
|
||||
|
||||
# 09 顾问式销售演练脚本
|
||||
doc = new_doc("顾问式销售演练脚本")
|
||||
add_sections(doc, [(k, v) for k, v in C.SALES_KNOWLEDGE.items()])
|
||||
add_heading(doc, "演练任务", 2)
|
||||
for t in ["两人一组,一人扮演销售、一人扮演客户", "客户提出一个异议(如「价格太贵」),销售用 LSCPA 处理", "销售用 SPIN 挖掘客户 3 个痛点", "用 FABE 介绍一个本平台产品,含证据收尾"]:
|
||||
add_bullet(doc, t)
|
||||
save(doc, "09_顾问式销售演练脚本.docx")
|
||||
|
||||
# 10 SPIN 提问话术练习
|
||||
doc = new_doc("SPIN 提问话术练习")
|
||||
add_knowledge(doc, {"SPIN 提问法": C.SALES_KNOWLEDGE["SPIN 提问法"]})
|
||||
add_heading(doc, "练习:为下列场景设计 SPIN 问题", 2)
|
||||
for t in ["场景一:客户是制造业老板,想了解 AI 但担心成本", "场景二:客户有融资需求但不愿稀释股权", "场景三:客户想申报高企但不确定够不够格"]:
|
||||
add_heading(doc, t, 3)
|
||||
for q in ["背景问题 S:", "困难问题 P:", "暗示问题 I:", "需求回报问题 N:"]:
|
||||
add_bullet(doc, q + "________________________")
|
||||
save(doc, "10_SPIN提问话术练习.docx")
|
||||
|
||||
# 11 LSCPA 异议处理练习
|
||||
doc = new_doc("LSCPA 异议处理练习")
|
||||
add_knowledge(doc, {"LSCPA 异议处理": C.SALES_KNOWLEDGE["LSCPA 异议处理"]})
|
||||
add_heading(doc, "练习:用 LSCPA 处理下列异议", 2)
|
||||
for t in ["「你们收费太贵了」", "「我再考虑考虑」", "「别的公司报价更低」", "「资质认定能不能包过?」"]:
|
||||
add_heading(doc, t, 3)
|
||||
for step in ["倾听 L:", "同理 S:", "澄清 C:", "呈现 P:", "请求行动 A:"]:
|
||||
add_bullet(doc, step + "________________________")
|
||||
save(doc, "11_LSCPA异议处理练习.docx")
|
||||
|
||||
# 12 客户异议处理应对表
|
||||
doc = new_doc("客户异议处理应对表")
|
||||
objections = [
|
||||
("价格太贵", "先澄清:贵在哪(绝对值还是对比值),再讲 FABE 价值与 ROI,必要时让步非核心项。"),
|
||||
("再考虑考虑", "澄清犹豫的真实原因(预算/决策人/竞品),给出限时价值点或案例,约定下一步时间。"),
|
||||
("别的公司更便宜", "不贬低竞品,强调自身差异化优势与证据,帮客户算总拥有成本而非单价。"),
|
||||
("能不能包过", "诚实说明认定有客观标准,我们承诺专业陪跑与最大化通过率,不虚假承诺。"),
|
||||
("没预算", "挖掘隐性需求,讲清不做的后果(税负高/错过政策窗口),引导分期或组合方案。"),
|
||||
]
|
||||
table = doc.add_table(rows=1, cols=2)
|
||||
table.style = "Light Grid Accent 1"
|
||||
h = table.rows[0].cells
|
||||
for i, t in enumerate(["常见异议", "应对策略"]):
|
||||
h[i].text = ""
|
||||
run = h[i].paragraphs[0].add_run(t); set_font(run, 10, bold=True)
|
||||
for obj, resp in objections:
|
||||
row = table.add_row().cells
|
||||
for i, v in enumerate([obj, resp]):
|
||||
row[i].text = ""
|
||||
run = row[i].paragraphs[0].add_run(v); set_font(run, 9)
|
||||
save(doc, "12_客户异议处理应对表.docx")
|
||||
|
||||
# 13 销售周报模板
|
||||
doc = new_doc("销售周报模板")
|
||||
add_para(doc, "每周五下班前填写,提交给直属主管。", size=10, color=(0x80,0x80,0x80))
|
||||
for line in C.TEMPLATES["销售周报模板"]:
|
||||
add_para(doc, line)
|
||||
save(doc, "13_销售周报模板.docx")
|
||||
|
||||
# 14 考试模拟练习卷(取真实题库)
|
||||
doc = new_doc("考试模拟练习卷")
|
||||
add_para(doc, "本卷从平台题库抽取,共 %d 题,用于考前自测(答案与解析见末尾)。" % len(questions), size=10, color=(0x80,0x80,0x80))
|
||||
domain_label = {"company": "公司知识", "product": "产品知识", "sales": "销售知识"}
|
||||
type_label = {"single": "单选", "multiple": "多选", "judge": "判断"}
|
||||
for i, q in enumerate(questions, 1):
|
||||
stem = q["stem"]
|
||||
add_para(doc, "%d. [%s·%s] %s" % (i, type_label.get(q["type"], q["type"]), domain_label.get(q["domain"], q["domain"]), stem), bold=True)
|
||||
opts = q.get("options") or []
|
||||
if isinstance(opts, list):
|
||||
for o in opts:
|
||||
if isinstance(o, dict):
|
||||
add_para(doc, " %s. %s" % (o.get("key"), o.get("text")), size=10)
|
||||
else:
|
||||
add_para(doc, " - %s" % o, size=10)
|
||||
add_para(doc, "", size=6)
|
||||
add_heading(doc, "参考答案与解析", 1)
|
||||
for i, q in enumerate(questions, 1):
|
||||
ans = q.get("answer") or []
|
||||
ans_txt = "、".join(ans) if isinstance(ans, list) else str(ans)
|
||||
if q["type"] == "judge":
|
||||
ans_txt = "正确" if (ans and ans[0] in ("true", "正确")) else "错误"
|
||||
exp = q.get("explanation") or ""
|
||||
add_para(doc, "%d. 答案:%s" % (i, ans_txt), size=10)
|
||||
if exp:
|
||||
add_para(doc, " 解析:%s" % exp, size=9, color=(0x80,0x80,0x80))
|
||||
save(doc, "14_考试模拟练习卷.docx")
|
||||
|
||||
# 15 产品知识速查手册
|
||||
doc = new_doc("产品知识速查手册")
|
||||
add_para(doc, "全部 %d 个产品的完整字段速查,含说明、收费、佣金、规则。" % len(products), size=10, color=(0x80,0x80,0x80))
|
||||
for c in ["capital_consulting", "qualification_counseling", "ai_consulting", "ai_tools_platform"]:
|
||||
ps = cat(c)
|
||||
if not ps:
|
||||
continue
|
||||
add_heading(doc, CAT_LABEL[c], 1)
|
||||
for p in ps:
|
||||
add_heading(doc, "%s(%s)" % (p["name"], p["code"]), 2)
|
||||
for label, key in [("标签", "tags"), ("说明", "description"), ("收费", "pricing"),
|
||||
("佣金(推荐)", "commission_recommend"), ("佣金(谈单)", "commission_negotiate"),
|
||||
("公开课奖励", "public_course_bonus"), ("版本风险", "version_risk"), ("报备规则", "report_rules")]:
|
||||
v = (p.get(key) or "").strip()
|
||||
if v:
|
||||
add_bullet(doc, "%s:%s" % (label, v))
|
||||
save(doc, "15_产品知识速查手册.docx")
|
||||
|
||||
print("完成 15 份 DOCX")
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""生成 10 个 MP4 培训视频(Pillow 渲染幻灯片 + ffmpeg 合成)"""
|
||||
import os, sys, subprocess, textwrap
|
||||
from PIL import Image, ImageDraw, ImageFont
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(os.path.dirname(HERE), "mp4")
|
||||
WORK = os.path.join(HERE, "slides")
|
||||
sys.path.insert(0, HERE)
|
||||
import content as C
|
||||
|
||||
W, H = 1280, 720
|
||||
FONT_PATH = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
|
||||
FONT_BOLD = "/usr/share/fonts/opentype/noto/NotoSansCJK-Bold.ttc"
|
||||
|
||||
BG = (26, 60, 100) # 深蓝背景
|
||||
BG_TITLE = (15, 45, 80)
|
||||
ACCENT = (96, 165, 250) # 亮蓝
|
||||
WHITE = (255, 255, 255)
|
||||
GREY = (200, 210, 220)
|
||||
|
||||
def load_font(path, size, index=0):
|
||||
return ImageFont.truetype(path, size, index=index)
|
||||
|
||||
def wrap(text, width):
|
||||
# 按字符宽度折行(中文近似等宽)
|
||||
return textwrap.wrap(text, width=width)
|
||||
|
||||
def render_title_slide(path, title, subtitle):
|
||||
img = Image.new("RGB", (W, H), BG_TITLE)
|
||||
d = ImageDraw.Draw(img)
|
||||
# 顶部装饰条
|
||||
d.rectangle([0, 0, W, 10], fill=ACCENT)
|
||||
d.rectangle([0, H-10, W, H], fill=ACCENT)
|
||||
f_title = load_font(FONT_BOLD, 72)
|
||||
f_sub = load_font(FONT_PATH, 34)
|
||||
# 居中标题
|
||||
for i, line in enumerate(wrap(title, 14)):
|
||||
bbox = d.textbbox((0,0), line, font=f_title)
|
||||
tw = bbox[2]-bbox[0]
|
||||
d.text(((W-tw)//2, 250 + i*90), line, font=f_title, fill=WHITE)
|
||||
bbox = d.textbbox((0,0), subtitle, font=f_sub)
|
||||
sw = bbox[2]-bbox[0]
|
||||
d.text(((W-sw)//2, 470), subtitle, font=f_sub, fill=GREY)
|
||||
d.text((W-360, H-60), "博昇内部培训平台", font=load_font(FONT_PATH, 26), fill=GREY)
|
||||
img.save(path)
|
||||
|
||||
def render_slide(path, title, bullets, idx, total):
|
||||
img = Image.new("RGB", (W, H), BG)
|
||||
d = ImageDraw.Draw(img)
|
||||
d.rectangle([0, 0, W, 8], fill=ACCENT)
|
||||
f_title = load_font(FONT_BOLD, 52)
|
||||
f_bullet = load_font(FONT_PATH, 40)
|
||||
f_small = load_font(FONT_PATH, 24)
|
||||
# 标题
|
||||
d.text((60, 50), title, font=f_title, fill=WHITE)
|
||||
d.line([(60, 130), (W-60, 130)], fill=ACCENT, width=2)
|
||||
# 条目
|
||||
y = 170
|
||||
for b in bullets:
|
||||
lines = wrap(b, 24)
|
||||
for line in lines:
|
||||
if y > H - 100:
|
||||
break
|
||||
d.ellipse([60, y+16, 74, y+30], fill=ACCENT)
|
||||
d.text((92, y), line, font=f_bullet, fill=WHITE)
|
||||
y += 58
|
||||
# 页码 + 页脚
|
||||
d.text((W-220, H-60), "%d / %d" % (idx, total), font=f_small, fill=GREY)
|
||||
d.text((60, H-60), "博昇内部培训平台", font=f_small, fill=GREY)
|
||||
img.save(path)
|
||||
|
||||
def make_slides(title, items, max_bullets=6):
|
||||
"""items: list of (小标题, [要点]) → 拆分为多张幻灯片"""
|
||||
slides = []
|
||||
for sub, bullets in items:
|
||||
# 按 max_bullets 拆分
|
||||
for i in range(0, len(bullets), max_bullets):
|
||||
chunk = bullets[i:i+max_bullets]
|
||||
s_title = sub if i == 0 else sub + "(续)"
|
||||
slides.append((s_title, chunk))
|
||||
if not slides:
|
||||
slides = [("内容", ["(暂无内容)"])]
|
||||
return slides
|
||||
|
||||
def build_video(filename, title, items, title_dur=4, slide_dur=6):
|
||||
os.makedirs(WORK, exist_ok=True)
|
||||
slides = make_slides(title, items)
|
||||
total = len(slides) + 1
|
||||
# 渲染标题页 + 内容页
|
||||
render_title_slide(os.path.join(WORK, "s000.png"), title, "博昇内部培训平台 · 培训课程")
|
||||
for i, (sub, bullets) in enumerate(slides, 1):
|
||||
render_slide(os.path.join(WORK, "s%03d.png" % i), sub, bullets, i, total)
|
||||
# ffmpeg 合成
|
||||
n = total
|
||||
inputs = []
|
||||
for i in range(n):
|
||||
dur = title_dur if i == 0 else slide_dur
|
||||
inputs += ["-framerate", "25", "-loop", "1", "-t", str(dur), "-i", os.path.join(WORK, "s%03d.png" % i)]
|
||||
# 每个输入归一化后再 concat
|
||||
parts = []
|
||||
for i in range(n):
|
||||
parts.append("[%d:v]scale=1280:720,setsar=1,format=yuv420p[v%d]" % (i, i))
|
||||
concat = "".join("[v%d]" % i for i in range(n)) + "concat=n=%d:v=1:a=0[v]" % n
|
||||
fc = ";".join(parts) + ";" + concat
|
||||
out = os.path.join(OUT, filename)
|
||||
cmd = ["ffmpeg", "-y", *inputs,
|
||||
"-f", "lavfi", "-i", "anullsrc=channel_layout=stereo:sample_rate=44100",
|
||||
"-filter_complex", fc,
|
||||
"-map", "[v]", "-map", "%d:a" % n,
|
||||
"-c:v", "libx264", "-preset", "veryfast", "-crf", "23", "-pix_fmt", "yuv420p",
|
||||
"-r", "25", "-c:a", "aac", "-b:a", "64k", "-shortest",
|
||||
out]
|
||||
r = subprocess.run(cmd, capture_output=True, text=True)
|
||||
if r.returncode != 0:
|
||||
print(" MP4 失败:", filename, r.stderr[-300:])
|
||||
else:
|
||||
sz = os.path.getsize(out)
|
||||
print(" MP4 生成:", filename, "(%d 页, %.1f KB)" % (n, sz/1024))
|
||||
|
||||
def main():
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
videos = [
|
||||
("01_公司介绍.mp4", "公司介绍", C.COMPANY_INTRO["sections"]),
|
||||
("02_产品线总览.mp4", "产品线总览", C.PRODUCT_LINES["lines"]),
|
||||
("03_高企认定八大条件.mp4", "高企认定八大条件", [
|
||||
("八项条件", C.QUALIFICATION_KNOWLEDGE["高企认定八条件"]),
|
||||
("研发费用占比", C.QUALIFICATION_KNOWLEDGE["高企研发费用占比"]),
|
||||
]),
|
||||
("04_专精特新梯度培育.mp4", "专精特新梯度培育", [
|
||||
("梯度体系", C.QUALIFICATION_KNOWLEDGE["专精特新梯度培育"]),
|
||||
("小巨人门槛", C.QUALIFICATION_KNOWLEDGE["专精特新小巨人门槛(2026)"]),
|
||||
]),
|
||||
("05_资本咨询销售要点.mp4", "资本咨询销售要点", [
|
||||
("融资工具选择", C.CAPITAL_KNOWLEDGE["股权融资 vs 债权融资"]),
|
||||
("轮次与估值", C.CAPITAL_KNOWLEDGE["融资轮次与估值方法"]),
|
||||
("尽调与条款", C.CAPITAL_KNOWLEDGE["尽职调查与核心条款"]),
|
||||
]),
|
||||
("06_企业AI落地方法论.mp4", "企业 AI 落地方法论", [
|
||||
("大模型选型", C.AI_KNOWLEDGE["大模型选型"]),
|
||||
("RAG 构建五步", C.AI_KNOWLEDGE["RAG 构建五步"]),
|
||||
("私有化三模式", C.AI_KNOWLEDGE["私有化三模式"]),
|
||||
]),
|
||||
("07_顾问式销售FABE法则.mp4", "顾问式销售 · FABE 法则", [
|
||||
("FABE 法则", C.SALES_KNOWLEDGE["FABE 法则"]),
|
||||
("顾问式销售五步", C.SALES_KNOWLEDGE["顾问式销售五步"]),
|
||||
]),
|
||||
("08_SPIN提问技巧.mp4", "SPIN 提问技巧", [
|
||||
("SPIN 提问法", C.SALES_KNOWLEDGE["SPIN 提问法"]),
|
||||
]),
|
||||
("09_LSCPA异议处理.mp4", "LSCPA 异议处理", [
|
||||
("LSCPA 异议处理", C.SALES_KNOWLEDGE["LSCPA 异议处理"]),
|
||||
]),
|
||||
("10_销售成交技巧.mp4", "销售成交技巧", [
|
||||
("成交信号", C.SALES_KNOWLEDGE["成交信号与技巧"]),
|
||||
]),
|
||||
]
|
||||
for fn, title, items in videos:
|
||||
build_video(fn, title, items)
|
||||
print("完成 %d 个 MP4" % len(videos))
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,160 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""生成 15 份 PDF 培训文档(reportlab)"""
|
||||
import json, os, sys
|
||||
from reportlab.lib.pagesizes import A4
|
||||
from reportlab.lib.units import mm
|
||||
from reportlab.lib import colors
|
||||
from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle
|
||||
from reportlab.pdfbase import pdfmetrics
|
||||
from reportlab.pdfbase.cidfonts import UnicodeCIDFont
|
||||
from reportlab.platypus import SimpleDocTemplate, Paragraph, Spacer, PageBreak
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
OUT = os.path.join(os.path.dirname(HERE), "pdf")
|
||||
sys.path.insert(0, HERE)
|
||||
import content as C
|
||||
|
||||
pdfmetrics.registerFont(UnicodeCIDFont("STSong-Light"))
|
||||
FONT = "STSong-Light"
|
||||
|
||||
def esc(s):
|
||||
return (s or "").replace("&", "&").replace("<", "<").replace(">", ">")
|
||||
|
||||
def styles():
|
||||
ss = getSampleStyleSheet()
|
||||
ss["Title"].fontName = FONT
|
||||
ss["Heading1"].fontName = FONT
|
||||
ss["Heading1"].fontSize = 16
|
||||
ss["Heading1"].textColor = colors.HexColor("#1f4e79")
|
||||
body = ParagraphStyle("body", parent=ss["Normal"], fontName=FONT, fontSize=11, leading=18, spaceAfter=6)
|
||||
bullet = ParagraphStyle("bullet", parent=body, leftIndent=16, bulletIndent=4, spaceAfter=4)
|
||||
sub = ParagraphStyle("sub", parent=ss["Heading2"], fontName=FONT, fontSize=13, textColor=colors.HexColor("#2e6da4"), spaceBefore=10, spaceAfter=6)
|
||||
return ss, body, bullet, sub
|
||||
|
||||
def load_products():
|
||||
p = json.load(open(os.path.join(HERE, "products.json")))["data"]
|
||||
return p
|
||||
|
||||
def load_courses():
|
||||
return json.load(open(os.path.join(HERE, "courses.json")))["data"]
|
||||
|
||||
CAT_LABEL = {
|
||||
"capital_consulting": "资本咨询类",
|
||||
"qualification_counseling": "资质认定辅导类",
|
||||
"ai_consulting": "AI 咨询类",
|
||||
"ai_tools_platform": "企业级 AI 工具与平台",
|
||||
}
|
||||
|
||||
def add_products(story, products, body, sub, bullet):
|
||||
by_cat = {}
|
||||
for p in products:
|
||||
by_cat.setdefault(p["category"], []).append(p)
|
||||
order = ["capital_consulting", "qualification_counseling", "ai_consulting", "ai_tools_platform"]
|
||||
for cat in order:
|
||||
if cat not in by_cat:
|
||||
continue
|
||||
story.append(Paragraph(esc(CAT_LABEL.get(cat, cat)), sub))
|
||||
for p in by_cat[cat]:
|
||||
story.append(Paragraph("<b>%s(%s)</b>" % (esc(p["name"]), esc(p["code"])), body))
|
||||
fields = [
|
||||
("标签", p.get("tags")), ("说明", p.get("description")), ("收费", p.get("pricing")),
|
||||
("佣金(仅推荐)", p.get("commission_recommend")), ("佣金(参与谈单)", p.get("commission_negotiate")),
|
||||
("公开课奖励", p.get("public_course_bonus")), ("版本风险", p.get("version_risk")),
|
||||
("报备规则", p.get("report_rules")),
|
||||
]
|
||||
for k, v in fields:
|
||||
if v and str(v).strip():
|
||||
story.append(Paragraph("· %s:%s" % (k, esc(v)), bullet))
|
||||
|
||||
def add_sections(story, sections, body, sub):
|
||||
for title, paras in sections:
|
||||
story.append(Paragraph(esc(title), sub))
|
||||
for para in paras:
|
||||
story.append(Paragraph(esc(para), body))
|
||||
|
||||
def add_knowledge(story, knowledge, body, sub):
|
||||
for title, paras in knowledge.items():
|
||||
story.append(Paragraph(esc(title), sub))
|
||||
for para in paras:
|
||||
story.append(Paragraph(esc(para), body))
|
||||
|
||||
def build(filename, title, blocks):
|
||||
doc = SimpleDocTemplate(os.path.join(OUT, filename), pagesize=A4,
|
||||
topMargin=20*mm, bottomMargin=20*mm, leftMargin=20*mm, rightMargin=20*mm)
|
||||
ss, body, bullet, sub = styles()
|
||||
story = []
|
||||
story.append(Paragraph(esc(title), ss["Title"]))
|
||||
story.append(Spacer(1, 6*mm))
|
||||
story.append(Paragraph("博昇内部培训平台 · 学习资料", ParagraphStyle("tag", parent=body, fontSize=9, textColor=colors.grey)))
|
||||
story.append(Spacer(1, 6*mm))
|
||||
for kind, data in blocks:
|
||||
if kind == "sections":
|
||||
add_sections(story, data, body, sub)
|
||||
elif kind == "knowledge":
|
||||
add_knowledge(story, data, body, sub)
|
||||
elif kind == "products":
|
||||
add_products(story, data, body, sub, bullet)
|
||||
doc.build(story)
|
||||
print(" PDF 生成:", filename)
|
||||
|
||||
def main():
|
||||
os.makedirs(OUT, exist_ok=True)
|
||||
products = load_products()
|
||||
courses = load_courses()
|
||||
def cat(c): return [p for p in products if p["category"] == c]
|
||||
|
||||
jobs = [
|
||||
("01_公司介绍.pdf", "博昇公司介绍", [("sections", C.COMPANY_INTRO["sections"])]),
|
||||
("02_产品线总览与销售地图.pdf", "产品线总览与销售地图", [("sections", C.PRODUCT_LINES["lines"])]),
|
||||
("03_资本咨询类产品手册.pdf", "资本咨询类产品手册", [("products", cat("capital_consulting"))]),
|
||||
("04_资质认定辅导类产品手册.pdf", "资质认定辅导类产品手册", [("products", cat("qualification_counseling"))]),
|
||||
("05_AI咨询类产品手册.pdf", "AI 咨询类产品手册", [("products", cat("ai_consulting"))]),
|
||||
("06_企业级AI工具平台产品手册.pdf", "企业级 AI 工具与平台产品手册", [("products", cat("ai_tools_platform"))]),
|
||||
("07_高新技术企业认定政策解读.pdf", "高新技术企业认定政策解读", [("knowledge", {
|
||||
"高企认定八条件": C.QUALIFICATION_KNOWLEDGE["高企认定八条件"],
|
||||
"高企研发费用占比": C.QUALIFICATION_KNOWLEDGE["高企研发费用占比"],
|
||||
"知识产权与税收优惠": C.QUALIFICATION_KNOWLEDGE["高企知识产权与税收优惠"],
|
||||
})]),
|
||||
("08_专精特新企业认定政策解读.pdf", "专精特新企业认定政策解读", [("knowledge", {
|
||||
"梯度培育体系": C.QUALIFICATION_KNOWLEDGE["专精特新梯度培育"],
|
||||
"小巨人门槛(2026)": C.QUALIFICATION_KNOWLEDGE["专精特新小巨人门槛(2026)"],
|
||||
"高企与专精特新的区别": C.QUALIFICATION_KNOWLEDGE["高企与专精特新的区别"],
|
||||
"常见资质认证与补贴": C.QUALIFICATION_KNOWLEDGE["常见资质认证与补贴"],
|
||||
})]),
|
||||
("09_资本运作与股权融资基础讲义.pdf", "资本运作与股权融资基础讲义", [("knowledge", C.CAPITAL_KNOWLEDGE)]),
|
||||
("10_企业AI落地方法论讲义.pdf", "企业 AI 落地方法论讲义", [("knowledge", C.AI_KNOWLEDGE)]),
|
||||
("11_顾问式销售方法论讲义.pdf", "顾问式销售方法论讲义", [("knowledge", C.SALES_KNOWLEDGE)]),
|
||||
("12_销售话术手册_资本咨询.pdf", "销售话术手册:资本咨询", [("sections", course_sections(courses, "capital_script"))]),
|
||||
("13_销售话术手册_资质认定.pdf", "销售话术手册:资质认定", [("sections", course_sections(courses, "qualification_logic"))]),
|
||||
("14_新人入职培训手册.pdf", "新人入职培训手册", [
|
||||
("sections", C.COMPANY_INTRO["sections"]),
|
||||
("sections", C.PRODUCT_LINES["lines"]),
|
||||
("knowledge", C.SALES_KNOWLEDGE),
|
||||
]),
|
||||
("15_考试题库复习提纲.pdf", "考试题库复习提纲", [("sections", C.EXAM_REVIEW["sections"])]),
|
||||
]
|
||||
for fn, title, blocks in jobs:
|
||||
build(fn, title, blocks)
|
||||
print("完成 %d 份 PDF" % len(jobs))
|
||||
|
||||
def course_sections(courses, category):
|
||||
sections = []
|
||||
for c in courses:
|
||||
if c["category"] != category:
|
||||
continue
|
||||
paras = []
|
||||
field_map = [
|
||||
("目标客户", "target_customers"), ("禁区客户", "forbidden_customers"),
|
||||
("话术", "scripts"), ("销售流程", "sales_process"),
|
||||
("异议处理", "objection_handling"), ("避坑提醒", "delivery_pitfalls"),
|
||||
("报备规则", "report_rules"),
|
||||
]
|
||||
for label, key in field_map:
|
||||
v = c.get(key)
|
||||
if v and str(v).strip():
|
||||
paras.append("%s:%s" % (label, v.strip()))
|
||||
sections.append((c["name"], paras if paras else ["(暂无详细内容)"]))
|
||||
return sections
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user