@8btc/ppt-generator-mcp 0.0.31 → 0.0.32-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -86,18 +86,36 @@ declare const t: z.ZodObject<{
86
86
  title: string;
87
87
  text: string;
88
88
  }>, "many">;
89
+ images: z.ZodArray<z.ZodObject<{
90
+ imageType: z.ZodEnum<["pageFigure", "itemFigure", "background"]>;
91
+ src: z.ZodString;
92
+ }, "strip", z.ZodTypeAny, {
93
+ src: string;
94
+ imageType: "pageFigure" | "itemFigure" | "background";
95
+ }, {
96
+ src: string;
97
+ imageType: "pageFigure" | "itemFigure" | "background";
98
+ }>, "many">;
89
99
  }, "strip", z.ZodTypeAny, {
90
100
  title: string;
91
101
  items: {
92
102
  title: string;
93
103
  text: string;
94
104
  }[];
105
+ images: {
106
+ src: string;
107
+ imageType: "pageFigure" | "itemFigure" | "background";
108
+ }[];
95
109
  }, {
96
110
  title: string;
97
111
  items: {
98
112
  title: string;
99
113
  text: string;
100
114
  }[];
115
+ images: {
116
+ src: string;
117
+ imageType: "pageFigure" | "itemFigure" | "background";
118
+ }[];
101
119
  }>;
102
120
  }, "strip", z.ZodTypeAny, {
103
121
  type: "content";
@@ -107,6 +125,10 @@ declare const t: z.ZodObject<{
107
125
  title: string;
108
126
  text: string;
109
127
  }[];
128
+ images: {
129
+ src: string;
130
+ imageType: "pageFigure" | "itemFigure" | "background";
131
+ }[];
110
132
  };
111
133
  }, {
112
134
  type: "content";
@@ -116,6 +138,10 @@ declare const t: z.ZodObject<{
116
138
  title: string;
117
139
  text: string;
118
140
  }[];
141
+ images: {
142
+ src: string;
143
+ imageType: "pageFigure" | "itemFigure" | "background";
144
+ }[];
119
145
  };
120
146
  }>, z.ZodObject<{
121
147
  type: z.ZodLiteral<"end">;
@@ -151,6 +177,10 @@ declare const t: z.ZodObject<{
151
177
  title: string;
152
178
  text: string;
153
179
  }[];
180
+ images: {
181
+ src: string;
182
+ imageType: "pageFigure" | "itemFigure" | "background";
183
+ }[];
154
184
  };
155
185
  } | {
156
186
  type: "end";
@@ -184,6 +214,10 @@ declare const t: z.ZodObject<{
184
214
  title: string;
185
215
  text: string;
186
216
  }[];
217
+ images: {
218
+ src: string;
219
+ imageType: "pageFigure" | "itemFigure" | "background";
220
+ }[];
187
221
  };
188
222
  } | {
189
223
  type: "end";
@@ -47,6 +47,10 @@ const inputSchema = {
47
47
  title: zod_1.z.string(),
48
48
  text: zod_1.z.string(),
49
49
  })),
50
+ images: zod_1.z.array(zod_1.z.object({
51
+ imageType: zod_1.z.enum(["pageFigure", "itemFigure", "background"]),
52
+ src: zod_1.z.string(),
53
+ })),
50
54
  }),
51
55
  }),
52
56
  zod_1.z.object({
@@ -23,30 +23,30 @@ const toolHandler = async () => {
23
23
  {
24
24
  type: "text",
25
25
  text: JSON.stringify([
26
- {
27
- name: "清新风格模板-图标比较多",
28
- path: node_path_1.default.join(__dirname, "..", "tpls", "tpl-3.json"),
29
- },
30
- {
31
- name: "研究报告风格模板-紫色系",
32
- path: node_path_1.default.join(__dirname, "..", "tpls", "tpl-4.json"),
33
- },
34
- {
35
- name: "简约风格模板-莫兰迪色系",
36
- path: node_path_1.default.join(__dirname, "..", "tpls", "tpl-2.json"),
37
- },
38
- {
39
- name: "简单模板-蓝色调",
40
- path: node_path_1.default.join(__dirname, "..", "tpls", "tpl-1.json"),
41
- },
26
+ // {
27
+ // name: "清新风格模板-图标比较多",
28
+ // path: path.join(__dirname, "..", "tpls", "tpl-3.json"),
29
+ // },
30
+ // {
31
+ // name: "研究报告风格模板-紫色系",
32
+ // path: path.join(__dirname, "..", "tpls", "tpl-4.json"),
33
+ // },
34
+ // {
35
+ // name: "简约风格模板-莫兰迪色系",
36
+ // path: path.join(__dirname, "..", "tpls", "tpl-2.json"),
37
+ // },
38
+ // {
39
+ // name: "简单模板-蓝色调",
40
+ // path: path.join(__dirname, "..", "tpls", "tpl-1.json"),
41
+ // },
42
42
  {
43
43
  name: "通用模板-商务风格",
44
44
  path: node_path_1.default.join(__dirname, "..", "tpls", "custom-1.json"),
45
45
  },
46
- {
47
- name: "通用模板-报告风格",
48
- path: node_path_1.default.join(__dirname, "..", "tpls", "custom-2.json"),
49
- },
46
+ // {
47
+ // name: "通用模板-报告风格",
48
+ // path: path.join(__dirname, "..", "tpls", "custom-2.json"),
49
+ // },
50
50
  ]),
51
51
  },
52
52
  ],
@@ -1,2 +1,3 @@
1
1
  export { get_ppt_template_list } from "./get-ppt-template-list";
2
2
  export { generate_ppt } from "./generate-ppt";
3
+ export { update_ppt_outline } from "./update-ppt-outline";
@@ -1,7 +1,9 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generate_ppt = exports.get_ppt_template_list = void 0;
3
+ exports.update_ppt_outline = exports.generate_ppt = exports.get_ppt_template_list = void 0;
4
4
  var get_ppt_template_list_1 = require("./get-ppt-template-list");
5
5
  Object.defineProperty(exports, "get_ppt_template_list", { enumerable: true, get: function () { return get_ppt_template_list_1.get_ppt_template_list; } });
6
6
  var generate_ppt_1 = require("./generate-ppt");
7
7
  Object.defineProperty(exports, "generate_ppt", { enumerable: true, get: function () { return generate_ppt_1.generate_ppt; } });
8
+ var update_ppt_outline_1 = require("./update-ppt-outline");
9
+ Object.defineProperty(exports, "update_ppt_outline", { enumerable: true, get: function () { return update_ppt_outline_1.update_ppt_outline; } });
@@ -137,6 +137,13 @@ const exportPPTX = (_slides, ignoreMedia, options) => {
137
137
  w: el.width / ratioPx2Inch(viewportSize),
138
138
  h: el.height / ratioPx2Inch(viewportSize),
139
139
  };
140
+ if (el.imageType) {
141
+ options.sizing = {
142
+ type: "contain",
143
+ w: el.width / ratioPx2Inch(viewportSize),
144
+ h: el.height / ratioPx2Inch(viewportSize),
145
+ };
146
+ }
140
147
  if (isBase64Image(el.src))
141
148
  options.data = el.src;
142
149
  else
@@ -6,5 +6,5 @@ interface ImgPoolItem {
6
6
  width: number;
7
7
  height: number;
8
8
  }
9
- export declare const generatePPTSlides: (templateSlides: Slide[], outlineList: Outline[], imgs?: ImgPoolItem[]) => Slide[];
9
+ export declare const generatePPTSlides: (templateSlides: Slide[], outlineList: Outline[], imgs?: ImgPoolItem[]) => Promise<Slide[]>;
10
10
  export {};
@@ -1,6 +1,12 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
6
  exports.generatePPTSlides = void 0;
7
+ const logger_1 = __importDefault(require("../../utils/logger"));
8
+ const loadImage_1 = require("../../utils/loadImage");
9
+ const slides_util_1 = require("./slides-util");
4
10
  class CanvasBrowser {
5
11
  constructor(width, height) {
6
12
  this.el = document.createElement("canvas");
@@ -18,7 +24,7 @@ if (!globalThis.CanvasImpl) {
18
24
  const nanoid = (length = 10) => {
19
25
  return Math.random().toString(16).slice(0, length);
20
26
  };
21
- const generatePPTSlides = (templateSlides, outlineList, imgs = []) => {
27
+ const generatePPTSlides = async (templateSlides, outlineList, imgs = []) => {
22
28
  const slides = [];
23
29
  const coverTemplates = [];
24
30
  const contentsTemplates = [];
@@ -56,7 +62,7 @@ const generatePPTSlides = (templateSlides, outlineList, imgs = []) => {
56
62
  transitionIndex += 1;
57
63
  }
58
64
  else if (outlineItem.type === "content") {
59
- const contentSlide = generateContent(outlineItem, imgs, contentTemplates);
65
+ const contentSlide = await generateContent(outlineItem, contentTemplates);
60
66
  slides.push(contentSlide);
61
67
  }
62
68
  else if (outlineItem.type === "end") {
@@ -70,7 +76,7 @@ exports.generatePPTSlides = generatePPTSlides;
70
76
  const formatOutlineList = (outlineList, contentsTemplates) => {
71
77
  const normalizedOutlineList = [];
72
78
  const maxContentsCount = contentsTemplates.reduce((acc, cur) => {
73
- const count = cur.elements.filter((el) => checkTextType(el, "item")).length;
79
+ const count = cur.elements.filter((el) => (0, slides_util_1.checkTextType)(el, "item")).length;
74
80
  acc = Math.max(acc, count);
75
81
  return acc;
76
82
  }, 1);
@@ -174,14 +180,21 @@ const generateCover = (outlineItem, imgs, coverTemplates) => {
174
180
  return getNewImgElement(el, imgs);
175
181
  if (el.type !== "text" && el.type !== "shape")
176
182
  return el;
177
- if (checkTextType(el, "title") && outlineItem.data.title) {
183
+ if ((0, slides_util_1.checkTextType)(el, "title") && outlineItem.data.title) {
178
184
  return getNewTextElement({
179
185
  el,
180
186
  text: outlineItem.data.title,
181
187
  maxLine: 1,
182
188
  });
183
189
  }
184
- if (checkTextType(el, "content") && outlineItem.data.text) {
190
+ if ((0, slides_util_1.checkTextType)(el, "subtitle") && outlineItem.data.subtitle) {
191
+ return getNewTextElement({
192
+ el,
193
+ text: outlineItem.data.subtitle,
194
+ maxLine: 1,
195
+ });
196
+ }
197
+ if ((0, slides_util_1.checkTextType)(el, "content") && outlineItem.data.text) {
185
198
  return getNewTextElement({
186
199
  el,
187
200
  text: outlineItem.data.text,
@@ -197,9 +210,9 @@ const generateCover = (outlineItem, imgs, coverTemplates) => {
197
210
  };
198
211
  };
199
212
  const generateContents = (outlineItem, imgs, contentsTemplates) => {
200
- const _contentsTemplates = getUseableTemplates(contentsTemplates, outlineItem.data.items.length, "item");
213
+ const _contentsTemplates = (0, slides_util_1.getUseableTemplates)(contentsTemplates, outlineItem.data.items.length, "item");
201
214
  const contentsTemplate = _contentsTemplates[Math.floor(Math.random() * _contentsTemplates.length)];
202
- const sortedNumberItems = contentsTemplate.elements.filter((el) => checkTextType(el, "itemNumber"));
215
+ const sortedNumberItems = contentsTemplate.elements.filter((el) => (0, slides_util_1.checkTextType)(el, "itemNumber"));
203
216
  const sortedNumberItemIds = sortedNumberItems
204
217
  .sort((a, b) => {
205
218
  if (sortedNumberItems.length > 6) {
@@ -224,7 +237,7 @@ const generateContents = (outlineItem, imgs, contentsTemplates) => {
224
237
  return aIndex - bIndex;
225
238
  })
226
239
  .map((el) => el.id);
227
- const sortedItems = contentsTemplate.elements.filter((el) => checkTextType(el, "item"));
240
+ const sortedItems = contentsTemplate.elements.filter((el) => (0, slides_util_1.checkTextType)(el, "item"));
228
241
  const sortedItemIds = sortedItems
229
242
  .sort((a, b) => {
230
243
  if (sortedItems.length > 6) {
@@ -249,7 +262,7 @@ const generateContents = (outlineItem, imgs, contentsTemplates) => {
249
262
  return getNewImgElement(el, imgs);
250
263
  if (el.type !== "text" && el.type !== "shape")
251
264
  return el;
252
- if (checkTextType(el, "item")) {
265
+ if ((0, slides_util_1.checkTextType)(el, "item")) {
253
266
  const index = sortedItemIds.findIndex((id) => id === el.id);
254
267
  const itemTitle = outlineItem.data.items[index];
255
268
  if (itemTitle)
@@ -263,7 +276,7 @@ const generateContents = (outlineItem, imgs, contentsTemplates) => {
263
276
  if (el.groupId)
264
277
  unusedGroupIds.push(el.groupId);
265
278
  }
266
- if (checkTextType(el, "itemNumber")) {
279
+ if ((0, slides_util_1.checkTextType)(el, "itemNumber")) {
267
280
  const index = sortedNumberItemIds.findIndex((id) => id === el.id);
268
281
  const offset = outlineItem.offset || 0;
269
282
  return getNewTextElement({
@@ -289,21 +302,21 @@ const generateTransition = (outlineItem, imgs, transitionTemplate, transitionInd
289
302
  return getNewImgElement(el, imgs);
290
303
  if (el.type !== "text" && el.type !== "shape")
291
304
  return el;
292
- if (checkTextType(el, "title") && outlineItem.data.title) {
305
+ if ((0, slides_util_1.checkTextType)(el, "title") && outlineItem.data.title) {
293
306
  return getNewTextElement({
294
307
  el,
295
308
  text: outlineItem.data.title,
296
309
  maxLine: 1,
297
310
  });
298
311
  }
299
- if (checkTextType(el, "content") && outlineItem.data.text) {
312
+ if ((0, slides_util_1.checkTextType)(el, "content") && outlineItem.data.text) {
300
313
  return getNewTextElement({
301
314
  el,
302
315
  text: outlineItem.data.text,
303
316
  maxLine: 3,
304
317
  });
305
318
  }
306
- if (checkTextType(el, "partNumber")) {
319
+ if ((0, slides_util_1.checkTextType)(el, "partNumber")) {
307
320
  return getNewTextElement({
308
321
  el,
309
322
  text: transitionIndex + "",
@@ -319,11 +332,11 @@ const generateTransition = (outlineItem, imgs, transitionTemplate, transitionInd
319
332
  elements,
320
333
  };
321
334
  };
322
- const generateContent = (outlineItem, imgs, contentTemplates) => {
323
- const _contentTemplates = getUseableTemplates(contentTemplates, outlineItem.data.items.length, "item");
335
+ const generateContent = async (outlineItem, contentTemplates) => {
336
+ const _contentTemplates = (0, slides_util_1.getUseableContentTemplates)(contentTemplates, outlineItem);
324
337
  const contentTemplate = _contentTemplates[Math.floor(Math.random() * _contentTemplates.length)];
325
338
  const sortedTitleItemIds = contentTemplate.elements
326
- .filter((el) => checkTextType(el, "itemTitle"))
339
+ .filter((el) => (0, slides_util_1.checkTextType)(el, "itemTitle"))
327
340
  .sort((a, b) => {
328
341
  const aIndex = a.left + a.top * 2;
329
342
  const bIndex = b.left + b.top * 2;
@@ -331,7 +344,7 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
331
344
  })
332
345
  .map((el) => el.id);
333
346
  const sortedTextItemIds = contentTemplate.elements
334
- .filter((el) => checkTextType(el, "item"))
347
+ .filter((el) => (0, slides_util_1.checkTextType)(el, "item"))
335
348
  .sort((a, b) => {
336
349
  const aIndex = a.left + a.top * 2;
337
350
  const bIndex = b.left + b.top * 2;
@@ -339,7 +352,15 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
339
352
  })
340
353
  .map((el) => el.id);
341
354
  const sortedNumberItemIds = contentTemplate.elements
342
- .filter((el) => checkTextType(el, "itemNumber"))
355
+ .filter((el) => (0, slides_util_1.checkTextType)(el, "itemNumber"))
356
+ .sort((a, b) => {
357
+ const aIndex = a.left + a.top * 2;
358
+ const bIndex = b.left + b.top * 2;
359
+ return aIndex - bIndex;
360
+ })
361
+ .map((el) => el.id);
362
+ const sortedImageItemIds = contentTemplate.elements
363
+ .filter((el) => el.type === "image" && el.imageType)
343
364
  .sort((a, b) => {
344
365
  const aIndex = a.left + a.top * 2;
345
366
  const bIndex = b.left + b.top * 2;
@@ -356,14 +377,17 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
356
377
  }
357
378
  const longestTitle = itemTitles.reduce((longest, current) => (current.length > longest.length ? current : longest), "");
358
379
  const longestText = itemTexts.reduce((longest, current) => (current.length > longest.length ? current : longest), "");
359
- const elements = contentTemplate.elements.map((el) => {
360
- if (el.type === "image" && el.imageType)
361
- return getNewImgElement(el, imgs);
380
+ const getEl = async (el) => {
381
+ if (el.type === "image" && el.imageType) {
382
+ const index = sortedImageItemIds.findIndex((id) => id === el.id);
383
+ const imageItem = outlineItem.data.images?.[index];
384
+ return await updateImgElement(el, imageItem);
385
+ }
362
386
  if (el.type !== "text" && el.type !== "shape")
363
387
  return el;
364
388
  if (outlineItem.data.items.length === 1) {
365
389
  const contentItem = outlineItem.data.items[0];
366
- if (checkTextType(el, "content") && contentItem.text) {
390
+ if ((0, slides_util_1.checkTextType)(el, "content") && contentItem.text) {
367
391
  return getNewTextElement({
368
392
  el,
369
393
  text: contentItem.text,
@@ -372,7 +396,7 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
372
396
  }
373
397
  }
374
398
  else {
375
- if (checkTextType(el, "itemTitle")) {
399
+ if ((0, slides_util_1.checkTextType)(el, "itemTitle")) {
376
400
  const index = sortedTitleItemIds.findIndex((id) => id === el.id);
377
401
  const contentItem = outlineItem.data.items[index];
378
402
  if (contentItem && contentItem.title) {
@@ -384,7 +408,7 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
384
408
  });
385
409
  }
386
410
  }
387
- if (checkTextType(el, "item")) {
411
+ if ((0, slides_util_1.checkTextType)(el, "item")) {
388
412
  const index = sortedTextItemIds.findIndex((id) => id === el.id);
389
413
  const contentItem = outlineItem.data.items[index];
390
414
  if (contentItem && contentItem.text) {
@@ -396,7 +420,7 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
396
420
  });
397
421
  }
398
422
  }
399
- if (checkTextType(el, "itemNumber")) {
423
+ if ((0, slides_util_1.checkTextType)(el, "itemNumber")) {
400
424
  const index = sortedNumberItemIds.findIndex((id) => id === el.id);
401
425
  const offset = outlineItem.offset || 0;
402
426
  return getNewTextElement({
@@ -407,15 +431,26 @@ const generateContent = (outlineItem, imgs, contentTemplates) => {
407
431
  });
408
432
  }
409
433
  }
410
- if (checkTextType(el, "title") && outlineItem.data.title) {
434
+ if ((0, slides_util_1.checkTextType)(el, "title") && outlineItem.data.title) {
411
435
  return getNewTextElement({
412
436
  el,
413
437
  text: outlineItem.data.title,
414
438
  maxLine: 1,
415
439
  });
416
440
  }
441
+ if ((0, slides_util_1.checkTextType)(el, "subtitle") && outlineItem.data.subtitle) {
442
+ return getNewTextElement({
443
+ el,
444
+ text: outlineItem.data.subtitle,
445
+ maxLine: 1,
446
+ });
447
+ }
417
448
  return el;
418
- });
449
+ };
450
+ const elements = [];
451
+ for (const el of contentTemplate.elements) {
452
+ elements.push(await getEl(el));
453
+ }
419
454
  return {
420
455
  ...contentTemplate,
421
456
  id: `${contentTemplate.id}-${nanoid(10)}`,
@@ -486,46 +521,28 @@ const getNewImgElement = (el, imgs) => {
486
521
  height: randomImg.height,
487
522
  };
488
523
  };
489
- const checkTextType = (el, type) => {
490
- return ((el.type === "text" && el.textType === type) ||
491
- (el.type === "shape" && el.text && el.text.type === type));
492
- };
493
- const getUseableTemplates = (templates, n, type) => {
494
- if (n === 1) {
495
- const list = templates.filter((slide) => {
496
- const items = slide.elements.filter((el) => checkTextType(el, type));
497
- const titles = slide.elements.filter((el) => checkTextType(el, "title"));
498
- const texts = slide.elements.filter((el) => checkTextType(el, "content"));
499
- return !items.length && titles.length === 1 && texts.length === 1;
500
- });
501
- if (list.length)
502
- return list;
503
- }
504
- let target = null;
505
- const list = templates.filter((slide) => {
506
- const len = slide.elements.filter((el) => checkTextType(el, type)).length;
507
- return len >= n;
508
- });
509
- if (list.length === 0) {
510
- const sorted = templates.sort((a, b) => {
511
- const aLen = a.elements.filter((el) => checkTextType(el, type)).length;
512
- const bLen = b.elements.filter((el) => checkTextType(el, type)).length;
513
- return aLen - bLen;
514
- });
515
- target = sorted[sorted.length - 1];
524
+ // 替换图片元素
525
+ const updateImgElement = async (el, imageItem) => {
526
+ if (!imageItem)
527
+ return el;
528
+ try {
529
+ if (imageItem.src.startsWith("http")) {
530
+ const result = await (0, loadImage_1.imageToBase64)(imageItem.src);
531
+ return {
532
+ ...el,
533
+ src: result.dataUrl,
534
+ };
535
+ }
536
+ return {
537
+ ...el,
538
+ src: imageItem.src,
539
+ };
516
540
  }
517
- else {
518
- target = list.reduce((closest, current) => {
519
- const currentLen = current.elements.filter((el) => checkTextType(el, type)).length;
520
- const closestLen = closest.elements.filter((el) => checkTextType(el, type)).length;
521
- return currentLen - n <= closestLen - n ? current : closest;
522
- });
541
+ catch (e) {
542
+ logger_1.default.error("imageToBase64: " + e);
543
+ logger_1.default.error("imageItem.src: " + imageItem.src);
523
544
  }
524
- return templates.filter((slide) => {
525
- const len = slide.elements.filter((el) => checkTextType(el, type)).length;
526
- const targetLen = target.elements.filter((el) => checkTextType(el, type)).length;
527
- return len === targetLen;
528
- });
545
+ return el;
529
546
  };
530
547
  const getNewTextElement = ({ el, text, maxLine, longestText, digitPadding, }) => {
531
548
  const padding = 10;
@@ -11,7 +11,7 @@ class PPTGenerator {
11
11
  try {
12
12
  const { outline, templateData } = params;
13
13
  // 使用AIPPT函数生成slides
14
- const generatedSlides = (0, generate_ppt_slides_1.generatePPTSlides)(templateData.slides, outline);
14
+ const generatedSlides = await (0, generate_ppt_slides_1.generatePPTSlides)(templateData.slides, outline);
15
15
  // 构建完整的result对象,包含模板的其他属性
16
16
  const resultData = {
17
17
  width: templateData.width,
@@ -1,7 +1,12 @@
1
+ export interface IImage {
2
+ imageType: "pageFigure" | "itemFigure" | "background";
3
+ src: string;
4
+ }
1
5
  export interface OutlineCover {
2
6
  type: "cover";
3
7
  data: {
4
8
  title: string;
9
+ subtitle?: string;
5
10
  text: string;
6
11
  };
7
12
  }
@@ -9,6 +14,7 @@ export interface OutlineContents {
9
14
  type: "contents";
10
15
  data: {
11
16
  items: string[];
17
+ images?: IImage[];
12
18
  };
13
19
  offset?: number;
14
20
  }
@@ -17,16 +23,19 @@ export interface OutlineTransition {
17
23
  data: {
18
24
  title: string;
19
25
  text: string;
26
+ images?: IImage[];
20
27
  };
21
28
  }
22
29
  export interface OutlineContent {
23
30
  type: "content";
24
31
  data: {
25
32
  title: string;
33
+ subtitle?: string;
26
34
  items: {
27
35
  title: string;
28
36
  text: string;
29
37
  }[];
38
+ images?: IImage[];
30
39
  };
31
40
  offset?: number;
32
41
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@8btc/ppt-generator-mcp",
3
- "version": "0.0.31",
3
+ "version": "0.0.32-beta.1",
4
4
  "description": "MCP service for generating PPT files from AI-generated outlines and templates",
5
5
  "main": "dist/index.js",
6
6
  "scripts": {