import { Document, Packer, Paragraph, TextRun, Table, TableRow, TableCell, AlignmentType, HeadingLevel, BorderStyle, WidthType, ShadingType, VerticalAlign, LevelFormat, ExternalHyperlink, Header, Footer, PageNumber } from "docx"; import { writeFileSync } from "fs"; // ── Colors ─────────────────────────────────────────────────────────────────── const CLAUDE_ORANGE = "E8834B"; const HEADER_BG = "2C3E50"; const ROW_ALT = "F8F9FA"; const ROW_HIGHLIGHT = "FFF3CD"; const BORDER_COLOR = "CCCCCC"; const WHITE = "FFFFFF"; const border = (color = BORDER_COLOR) => ({ style: BorderStyle.SINGLE, size: 1, color }); const allBorders = (color = BORDER_COLOR) => ({ top: border(color), bottom: border(color), left: border(color), right: border(color), }); // ── Helper: table cell ──────────────────────────────────────────────────────── function cell(text, { bold = false, bg = WHITE, width, align = AlignmentType.LEFT, color = "000000", fontSize = 20 } = {}) { return new TableCell({ borders: allBorders(), width: { size: width, type: WidthType.DXA }, shading: { fill: bg, type: ShadingType.CLEAR }, verticalAlign: VerticalAlign.CENTER, margins: { top: 80, bottom: 80, left: 120, right: 120 }, children: [new Paragraph({ alignment: align, children: [new TextRun({ text, bold, color, size: fontSize, font: "Arial" })], })], }); } // ── Helper: header cell (dark bg, white text) ───────────────────────────────── function headerCell(text, width) { return cell(text, { bold: true, bg: HEADER_BG, color: WHITE, width, fontSize: 20 }); } // ── Helper: section heading ─────────────────────────────────────────────────── function sectionHeading(text) { return new Paragraph({ spacing: { before: 320, after: 160 }, children: [new TextRun({ text, bold: true, size: 28, color: "2C3E50", font: "Arial" })], border: { bottom: { style: BorderStyle.SINGLE, size: 4, color: CLAUDE_ORANGE, space: 4 } }, }); } // ── Helper: normal paragraph ───────────────────────────────────────────────── function para(text, { bold = false, size = 20, spacing = { after: 120 } } = {}) { return new Paragraph({ spacing, children: [new TextRun({ text, bold, size, font: "Arial", color: "333333" })], }); } // ── Helper: bullet ──────────────────────────────────────────────────────────── function bullet(text) { return new Paragraph({ numbering: { reference: "bullets", level: 0 }, spacing: { after: 80 }, children: [new TextRun({ text, size: 20, font: "Arial", color: "333333" })], }); } // ── Helper: note paragraph ─────────────────────────────────────────────────── function note(text) { return new Paragraph({ spacing: { before: 100, after: 160 }, children: [new TextRun({ text: `📌 ${text}`, size: 18, italics: true, color: "555555", font: "Arial" })], }); } // ── Section 1: Core pricing table (6 columns) ───────────────────────────────── // Content width: A4 9026, use 9000 for slight breathing room const COL1 = 1500; // 层级 const COL2 = 2000; // Claude model const COL3 = 1500; // Claude price const COL4 = 2000; // OpenAI model const COL5 = 1500; // OpenAI price const TABLE1_WIDTH = COL1 + COL2 + COL3 + COL4 + COL5; // 8500 function pricingTable() { const rows = [ ["旗舰", "Claude Opus 4.6", "$5 / $25", "GPT-4o", "$2.50 / $10", false], ["标准(推荐)", "Claude Sonnet 4.6", "$3 / $15", "GPT-4o", "$2.50 / $10", true ], ["轻量", "Claude Haiku 4.5", "$1 / $5", "GPT-4o mini", "$0.15 / $0.60", false], ]; return new Table({ width: { size: TABLE1_WIDTH, type: WidthType.DXA }, columnWidths: [COL1, COL2, COL3, COL4, COL5], rows: [ new TableRow({ tableHeader: true, children: [ headerCell("层级", COL1), headerCell("Claude(Anthropic)", COL2), headerCell("价格(输入/输出)", COL3), headerCell("ChatGPT(OpenAI)", COL4), headerCell("价格(输入/输出)", COL5), ], }), ...rows.map(([tier, claude, cp, oai, op, highlight]) => new TableRow({ children: [ cell(tier, { width: COL1, bg: highlight ? ROW_HIGHLIGHT : WHITE, bold: highlight }), cell(claude, { width: COL2, bg: highlight ? ROW_HIGHLIGHT : WHITE, bold: highlight, color: highlight ? "C0392B" : "000000" }), cell(cp, { width: COL3, bg: highlight ? ROW_HIGHLIGHT : WHITE, bold: highlight, align: AlignmentType.CENTER }), cell(oai, { width: COL4, bg: highlight ? ROW_HIGHLIGHT : WHITE }), cell(op, { width: COL5, bg: highlight ? ROW_HIGHLIGHT : WHITE, align: AlignmentType.CENTER }), ], }) ), ], }); } // ── Section 2: Cost estimate table ─────────────────────────────────────────── const E_COL1 = 2200; const E_COL2 = 3200; const E_COL3 = 3200; const TABLE2_WIDTH = E_COL1 + E_COL2 + E_COL3; // 8600 function costTable() { const rows = [ ["每次对话成本", "~$0.0037", "~$0.0027"], ["1,000 次对话/月", "$3.70", "$2.70"], ["10,000 次对话/月", "$37", "$27"], ["100,000 次对话/月", "$370", "$270"], ]; return new Table({ width: { size: TABLE2_WIDTH, type: WidthType.DXA }, columnWidths: [E_COL1, E_COL2, E_COL3], rows: [ new TableRow({ tableHeader: true, children: [ headerCell("", E_COL1), headerCell("Claude Sonnet 4.6", E_COL2), headerCell("GPT-4o", E_COL3), ], }), ...rows.map(([label, claude, oai], i) => new TableRow({ children: [ cell(label, { width: E_COL1, bg: i % 2 === 0 ? WHITE : ROW_ALT, bold: true }), cell(claude, { width: E_COL2, bg: i % 2 === 0 ? WHITE : ROW_ALT, align: AlignmentType.CENTER, color: "C0392B", bold: true }), cell(oai, { width: E_COL3, bg: i % 2 === 0 ? WHITE : ROW_ALT, align: AlignmentType.CENTER }), ], }) ), ], }); } // ── Section 3: Feature comparison ──────────────────────────────────────────── const F_COL1 = 2400; const F_COL2 = 3000; const F_COL3 = 3000; const TABLE3_WIDTH = F_COL1 + F_COL2 + F_COL3; // 8400 function featureTable(rows) { return new Table({ width: { size: TABLE3_WIDTH, type: WidthType.DXA }, columnWidths: [F_COL1, F_COL2, F_COL3], rows: [ new TableRow({ tableHeader: true, children: [ headerCell("功能", F_COL1), headerCell("Claude API", F_COL2), headerCell("ChatGPT API", F_COL3), ], }), ...rows.map(([feat, claude, oai], i) => new TableRow({ children: [ cell(feat, { width: F_COL1, bg: i % 2 === 0 ? WHITE : ROW_ALT, bold: true }), cell(claude, { width: F_COL2, bg: i % 2 === 0 ? WHITE : ROW_ALT, color: "1A6B2A" }), cell(oai, { width: F_COL3, bg: i % 2 === 0 ? WHITE : ROW_ALT }), ], }) ), ], }); } // ── Section 4: Capability comparison ───────────────────────────────────────── const C_COL1 = 2200; const C_COL2 = 3200; const C_COL3 = 3200; const TABLE4_WIDTH = C_COL1 + C_COL2 + C_COL3; function capabilityTable(rows) { return new Table({ width: { size: TABLE4_WIDTH, type: WidthType.DXA }, columnWidths: [C_COL1, C_COL2, C_COL3], rows: [ new TableRow({ tableHeader: true, children: [ headerCell("维度", C_COL1), headerCell("Claude Sonnet 4.6", C_COL2), headerCell("GPT-4o", C_COL3), ], }), ...rows.map(([dim, claude, oai], i) => new TableRow({ children: [ cell(dim, { width: C_COL1, bg: i % 2 === 0 ? WHITE : ROW_ALT, bold: true }), cell(claude, { width: C_COL2, bg: i % 2 === 0 ? WHITE : ROW_ALT }), cell(oai, { width: C_COL3, bg: i % 2 === 0 ? WHITE : ROW_ALT }), ], }) ), ], }); } // ── Section 6: Annual forecast ──────────────────────────────────────────────── const Y_COL1 = 2200; const Y_COL2 = 3200; const Y_COL3 = 3200; const TABLE5_WIDTH = Y_COL1 + Y_COL2 + Y_COL3; function yearlyTable() { const rows = [ ["月费估算", "~$30 – $50", "~$25 – $40"], ["年费估算", "~$360 – $600", "~$300 – $480"], ]; return new Table({ width: { size: TABLE5_WIDTH, type: WidthType.DXA }, columnWidths: [Y_COL1, Y_COL2, Y_COL3], rows: [ new TableRow({ tableHeader: true, children: [ headerCell("", Y_COL1), headerCell("Claude Sonnet 4.6(含缓存)", Y_COL2), headerCell("GPT-4o(含缓存)", Y_COL3), ], }), ...rows.map(([label, claude, oai], i) => new TableRow({ children: [ cell(label, { width: Y_COL1, bg: i % 2 === 0 ? WHITE : ROW_ALT, bold: true }), cell(claude, { width: Y_COL2, bg: i % 2 === 0 ? WHITE : ROW_ALT, align: AlignmentType.CENTER, bold: true, color: "C0392B" }), cell(oai, { width: Y_COL3, bg: i % 2 === 0 ? WHITE : ROW_ALT, align: AlignmentType.CENTER }), ], }) ), ], }); } // ── Build document ──────────────────────────────────────────────────────────── const doc = new Document({ numbering: { config: [ { reference: "bullets", levels: [{ level: 0, format: LevelFormat.BULLET, text: "\u2022", alignment: AlignmentType.LEFT, style: { paragraph: { indent: { left: 720, hanging: 360 } } }, }], }, ], }, styles: { default: { document: { run: { font: "Arial", size: 20, color: "333333" } }, }, }, sections: [{ properties: { page: { size: { width: 11906, height: 16838 }, // A4 margin: { top: 1080, right: 1080, bottom: 1080, left: 1080 }, }, }, headers: { default: new Header({ children: [new Paragraph({ alignment: AlignmentType.RIGHT, border: { bottom: { style: BorderStyle.SINGLE, size: 4, color: CLAUDE_ORANGE, space: 4 } }, spacing: { after: 200 }, children: [new TextRun({ text: "Claude API vs ChatGPT API — 价格对比报告", size: 16, color: "888888", font: "Arial", })], })], }), }, footers: { default: new Footer({ children: [new Paragraph({ alignment: AlignmentType.CENTER, border: { top: { style: BorderStyle.SINGLE, size: 2, color: BORDER_COLOR, space: 4 } }, spacing: { before: 100 }, children: [ new TextRun({ text: "数据来源:platform.claude.com / openai.com/api/pricing | 第 ", size: 16, color: "888888", font: "Arial" }), new TextRun({ children: [PageNumber.CURRENT], size: 16, color: "888888", font: "Arial" }), new TextRun({ text: " 页", size: 16, color: "888888", font: "Arial" }), ], })], }), }, children: [ // ── Title block ────────────────────────────────────────────────────── new Paragraph({ spacing: { before: 0, after: 80 }, children: [new TextRun({ text: "Claude API vs ChatGPT API", bold: true, size: 52, color: "2C3E50", font: "Arial", })], }), new Paragraph({ spacing: { before: 0, after: 60 }, children: [new TextRun({ text: "价格对比报告", bold: true, size: 36, color: CLAUDE_ORANGE, font: "Arial", })], }), new Paragraph({ spacing: { after: 320 }, border: { bottom: { style: BorderStyle.SINGLE, size: 6, color: CLAUDE_ORANGE, space: 6 } }, children: [new TextRun({ text: "制作日期:2026年4月", size: 18, color: "888888", font: "Arial" })], }), // ── Section 1 ──────────────────────────────────────────────────────── sectionHeading("一、核心模型价格对比(每百万 Token)"), pricingTable(), note("本项目 chatbot 使用 Claude Sonnet 4.6,对标 OpenAI 的 GPT-4o 层级。"), // ── Section 2 ──────────────────────────────────────────────────────── sectionHeading("二、实际对话成本估算"), para("以 chatbot 典型对话为例:"), bullet("输入:~500 tokens(系统提示 + 对话历史)"), bullet("输出:~150 tokens(Bot 回复)"), new Paragraph({ spacing: { after: 120 } }), costTable(), note("月差额约 $10–$100,对企业级系统而言可忽略不计。"), // ── Section 3 ──────────────────────────────────────────────────────── sectionHeading("三、成本优化功能对比"), featureTable([ ["Batch 批处理折扣", "标准价 5折", "标准价 5折"], ["Prompt Caching", "命中缓存仅需原价 10%", "命中缓存 50%"], ["Context 窗口", "200K tokens", "128K tokens"], ["最长单次输入", "更适合长文档/历史记录", "受限于 128K"], ]), note("Prompt Caching:本项目系统提示词(Ellie 角色设定)每次对话都会重复发送,Claude 缓存命中价格仅 $0.30/百万 tokens(原价 $3 的 10%),长期运行下成本优势显著。"), // ── Section 4 ──────────────────────────────────────────────────────── sectionHeading("四、功能与定位对比"), capabilityTable([ ["中文理解质量", "优秀", "优秀"], ["长上下文处理", "200K tokens(领先)", "128K tokens"], ["代码生成", "优秀", "优秀"], ["内容安全合规", "Constitutional AI,策略更严谨", "中等"], ["响应稳定性", "更一致", "中等"], ["企业 SLA", "有", "有"], ["数据隐私", "不用于模型训练", "不用于模型训练"], ["API 成熟度", "成熟", "成熟"], ]), // ── Section 5 ──────────────────────────────────────────────────────── sectionHeading("五、推荐选择 Claude API 的理由"), para("1. 成本差异极小,价值更高", { bold: true }), para("对于本项目规模(B2B dealer chatbot),两者月费差额通常在 $10–$50 以内,而 Claude 在长文档处理和一致性上表现更好。"), para("2. Prompt Caching 优势明显", { bold: true }), para("本项目系统提示词固定(Ellie 角色设定 + ERP 数据上下文),每次对话都能命中缓存,实际输入成本可降至标准价的 10%,有效抵消价格差。"), para("3. 200K 上下文窗口", { bold: true }), para("随着 ERP 数据集成(订单详情、产品目录),注入 LLM 的 context 数据量会增加。200K 窗口提供更大余量,无需担心超出限制。"), para("4. 技术栈已完成集成", { bold: true }), para("项目代码已使用 claude-sonnet-4-6 完成集成,切换到 ChatGPT API 需要额外改造工作和测试成本。"), para("5. 内容安全合规", { bold: true }), para("Anthropic 的 Constitutional AI 在拒绝不适当请求、保持回复边界方面更可靠,适合面向 dealer 的 B2B 场景。"), // ── Section 6 ──────────────────────────────────────────────────────── sectionHeading("六、费用预测(年度)"), para("假设每月 20,000 次对话,启用 Prompt Caching:"), yearlyTable(), note("两者年费差额约 $60–$120,可忽略不计。"), // ── Conclusion ─────────────────────────────────────────────────────── new Paragraph({ spacing: { before: 320, after: 160 }, shading: { fill: "EBF5FB", type: ShadingType.CLEAR }, border: { top: { style: BorderStyle.SINGLE, size: 4, color: CLAUDE_ORANGE }, bottom: { style: BorderStyle.SINGLE, size: 4, color: CLAUDE_ORANGE }, left: { style: BorderStyle.THICK, size: 12, color: CLAUDE_ORANGE }, right: { style: BorderStyle.SINGLE, size: 4, color: CLAUDE_ORANGE }, }, children: [new TextRun({ text: "结论:推荐使用 Claude API(Anthropic)", bold: true, size: 26, color: "2C3E50", font: "Arial", })], }), para("在价格接近的前提下,Claude 提供更大的 Context 窗口、更优的 Prompt Caching 折扣,且代码已完成集成,综合性价比更高,是本项目的最优选择。"), // ── Sources ────────────────────────────────────────────────────────── new Paragraph({ spacing: { before: 400, after: 80 }, border: { top: { style: BorderStyle.SINGLE, size: 2, color: BORDER_COLOR, space: 6 } }, children: [new TextRun({ text: "数据来源", bold: true, size: 18, color: "888888", font: "Arial" })], }), new Paragraph({ spacing: { after: 60 }, children: [ new TextRun({ text: "Anthropic Claude API Pricing: ", size: 16, color: "888888", font: "Arial" }), new ExternalHyperlink({ link: "https://platform.claude.com/docs/en/about-claude/pricing", children: [new TextRun({ text: "platform.claude.com/docs/en/about-claude/pricing", size: 16, style: "Hyperlink", font: "Arial" })], }), ], }), new Paragraph({ spacing: { after: 60 }, children: [ new TextRun({ text: "OpenAI API Pricing: ", size: 16, color: "888888", font: "Arial" }), new ExternalHyperlink({ link: "https://openai.com/api/pricing/", children: [new TextRun({ text: "openai.com/api/pricing", size: 16, style: "Hyperlink", font: "Arial" })], }), ], }), ], }], }); const outPath = "C:\\Codes\\homelegance-chatbot\\deploy\\Claude_vs_ChatGPT_API价格对比.docx"; Packer.toBuffer(doc).then(buf => { writeFileSync(outPath, buf); console.log("Created:", outPath); });