|
@@ -0,0 +1,446 @@
|
|
|
|
|
+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);
|
|
|
|
|
+});
|