slotdeck 0.1.1 → 0.2.0
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.
- package/README.md +94 -8
- package/dist/deck/alternatives.d.ts +34 -0
- package/dist/deck/alternatives.js +370 -0
- package/dist/deck/alternatives.js.map +1 -0
- package/dist/deck/design.d.ts +40 -0
- package/dist/deck/design.js +112 -0
- package/dist/deck/design.js.map +1 -0
- package/dist/deck/validate.d.ts +18 -0
- package/dist/deck/validate.js +44 -6
- package/dist/deck/validate.js.map +1 -1
- package/dist/index.d.ts +23 -1
- package/dist/index.js +14 -0
- package/dist/index.js.map +1 -1
- package/dist/llm/gemini.d.ts +4 -0
- package/dist/llm/gemini.js +43 -7
- package/dist/llm/gemini.js.map +1 -1
- package/dist/llm/provider.d.ts +12 -0
- package/dist/node.d.ts +7 -0
- package/dist/node.js +29 -0
- package/dist/node.js.map +1 -1
- package/dist/plan/catalog.d.ts +11 -1
- package/dist/plan/catalog.js +23 -8
- package/dist/plan/catalog.js.map +1 -1
- package/dist/plan/edit.js +14 -6
- package/dist/plan/edit.js.map +1 -1
- package/dist/plan/plan.d.ts +26 -2
- package/dist/plan/plan.js +58 -17
- package/dist/plan/plan.js.map +1 -1
- package/dist/plan/review.d.ts +43 -0
- package/dist/plan/review.js +141 -0
- package/dist/plan/review.js.map +1 -0
- package/dist/plan/write.d.ts +13 -1
- package/dist/plan/write.js +40 -7
- package/dist/plan/write.js.map +1 -1
- package/dist/preview/pagus.d.ts +30 -0
- package/dist/preview/pagus.js +45 -0
- package/dist/preview/pagus.js.map +1 -0
- package/dist/preview/patterns.d.ts +27 -0
- package/dist/preview/patterns.js +35 -0
- package/dist/preview/patterns.js.map +1 -0
- package/dist/preview/provider.d.ts +30 -0
- package/dist/preview/provider.js +11 -0
- package/dist/preview/provider.js.map +1 -0
- package/dist/render/render.d.ts +18 -1
- package/dist/render/render.js +32 -12
- package/dist/render/render.js.map +1 -1
- package/dist/render/repeat.d.ts +17 -2
- package/dist/render/repeat.js +150 -4
- package/dist/render/repeat.js.map +1 -1
- package/dist/render/text.d.ts +6 -0
- package/dist/render/text.js +24 -0
- package/dist/render/text.js.map +1 -1
- package/dist/template/budgets.d.ts +33 -0
- package/dist/template/budgets.js +38 -0
- package/dist/template/budgets.js.map +1 -0
- package/dist/template/change.d.ts +19 -1
- package/dist/template/change.js +45 -3
- package/dist/template/change.js.map +1 -1
- package/dist/template/check.d.ts +3 -0
- package/dist/template/check.js +53 -3
- package/dist/template/check.js.map +1 -1
- package/dist/template/derive.d.ts +54 -0
- package/dist/template/derive.js +402 -0
- package/dist/template/derive.js.map +1 -0
- package/dist/template/draft.d.ts +7 -0
- package/dist/template/draft.js +17 -1
- package/dist/template/draft.js.map +1 -1
- package/dist/template/instruct.js +15 -7
- package/dist/template/instruct.js.map +1 -1
- package/dist/template/manifest.d.ts +38 -0
- package/dist/template/manifest.js +43 -1
- package/dist/template/manifest.js.map +1 -1
- package/dist/template/sample.d.ts +17 -0
- package/dist/template/sample.js +31 -5
- package/dist/template/sample.js.map +1 -1
- package/dist/text/fontkit.d.ts +18 -0
- package/dist/text/fontkit.js +91 -0
- package/dist/text/fontkit.js.map +1 -0
- package/dist/text/fonts.d.ts +45 -0
- package/dist/text/fonts.js +59 -0
- package/dist/text/fonts.js.map +1 -0
- package/dist/text/layout.d.ts +12 -0
- package/dist/text/layout.js +104 -0
- package/dist/text/layout.js.map +1 -0
- package/dist/text/measure.d.ts +85 -0
- package/dist/text/measure.js +369 -0
- package/dist/text/measure.js.map +1 -0
- package/dist/text/styles.d.ts +123 -0
- package/dist/text/styles.js +417 -0
- package/dist/text/styles.js.map +1 -0
- package/dist/tools.d.ts +12 -0
- package/dist/tools.js +38 -6
- package/dist/tools.js.map +1 -1
- package/docs/README.md +16 -5
- package/docs/api-reference.md +291 -9
- package/docs/changelog.md +242 -0
- package/docs/chat-tools.md +26 -5
- package/docs/deck-format.md +6 -0
- package/docs/design-checks.md +216 -0
- package/docs/generating.md +43 -4
- package/docs/layout-freedom.md +278 -3
- package/docs/manifest-format.md +20 -3
- package/docs/preview.md +217 -0
- package/docs/providers.md +49 -4
- package/docs/rendering.md +8 -0
- package/docs/template-studio.md +121 -12
- package/docs/text-fit.md +456 -0
- package/docs/troubleshooting.md +21 -2
- package/package.json +7 -1
package/docs/chat-tools.md
CHANGED
|
@@ -38,7 +38,9 @@ const tools = presentationTools({
|
|
|
38
38
|
layout: 'adaptive', // optional; default 'strict'
|
|
39
39
|
fields: { organizationDepartment: 'Acme | Operations' }, // optional deck-level values every deck gets
|
|
40
40
|
numberPatterns: 'from-brief', // optional
|
|
41
|
+
review, // optional DeckReview: a second look at every draft (design-checks.md)
|
|
41
42
|
thumbnail: (patternId) => `/static/thumbnails/${patternId}.png`, // optional address of a picture of each layout
|
|
43
|
+
preview, // optional PreviewProvider: draws every presentation the tools make
|
|
42
44
|
newId: (kind) => `${kind}_${crypto.randomUUID()}`, // optional; default is a short random id
|
|
43
45
|
onProgress: (event, tool) => console.log(tool, event.stage), // optional
|
|
44
46
|
});
|
|
@@ -86,6 +88,7 @@ Arguments:
|
|
|
86
88
|
| `language` | string | no | BCP 47 tag, such as `he` or `en`. Defaults to the template's language. |
|
|
87
89
|
| `image_density` | `none`, `low`, `medium`, `high` | no | How many slides carry a photo. Default `medium`. Forced to `none` when no photos can be made. |
|
|
88
90
|
| `text_size` | `normal`, `large`, `x-large` | no | Size of body text. Default `normal`. |
|
|
91
|
+
| `text_only` | boolean | no | `true` when the person asks for a presentation of text only. Every slide is then plain text: a title with paragraphs or a list, with no pictures, icons, cards, figures, tables or charts. Only the template's plain text layouts are used. |
|
|
89
92
|
| `instructions` | string | no | Audience, tone and anything else to respect. |
|
|
90
93
|
|
|
91
94
|
Output:
|
|
@@ -140,6 +143,10 @@ Output:
|
|
|
140
143
|
|
|
141
144
|
`file` is the store key of the rendered pptx. `warnings` is present only when there are any.
|
|
142
145
|
|
|
146
|
+
With the `preview` option set, the output also has `"previews"`: the store keys of the pictures of the slides,
|
|
147
|
+
such as `["preview/deck_851fbb9677/slide-01.svg", ...]`. If the pictures could not be made, it has
|
|
148
|
+
`"preview_error"` with the reason instead, and the presentation is created all the same.
|
|
149
|
+
|
|
143
150
|
### `edit_presentation`
|
|
144
151
|
|
|
145
152
|
Arguments: `presentation_id` (string, required), `instruction` (string, required).
|
|
@@ -176,9 +183,10 @@ interface BlobStore {
|
|
|
176
183
|
| `deck/<id>.json` | A deck: all text, and for each picture its id and description | 4 KB |
|
|
177
184
|
| `asset/<id>` | One generated picture | tens of KB to 1 MB |
|
|
178
185
|
| `pptx/<id>.pptx` | The rendered file | hundreds of KB and up |
|
|
186
|
+
| `preview/<id>/slide-01.svg` | A picture of one slide, when the tools have a `preview` provider. The extension follows the provider: `svg`, `png` | tens of KB each |
|
|
179
187
|
|
|
180
|
-
`storeKeys.plan(id)`, `storeKeys.deck(id)`, `storeKeys.asset(id)
|
|
181
|
-
your app can read what the tools saved:
|
|
188
|
+
`storeKeys.plan(id)`, `storeKeys.deck(id)`, `storeKeys.asset(id)`, `storeKeys.pptx(id)` and
|
|
189
|
+
`storeKeys.preview(id, slide, extension)` build these keys, so your app can read what the tools saved:
|
|
182
190
|
|
|
183
191
|
```ts
|
|
184
192
|
const pptx = await store.get(storeKeys.pptx(presentationId)); // to serve a download later
|
|
@@ -218,9 +226,19 @@ const store: BlobStore = {
|
|
|
218
226
|
|
|
219
227
|
## Showing a plan visually
|
|
220
228
|
|
|
221
|
-
A plan lists a layout per slide. To show layouts as pictures,
|
|
222
|
-
|
|
223
|
-
|
|
229
|
+
A plan lists a layout per slide. To show layouts as pictures, make one picture for each pattern once, name it
|
|
230
|
+
after the pattern, and return its address from the `thumbnail` option. The address is passed through to the
|
|
231
|
+
chat model's output and is not fetched by slotdeck.
|
|
232
|
+
|
|
233
|
+
`patternPreviews(template, preview)` makes those pictures without PowerPoint, through a preview provider; see
|
|
234
|
+
[preview.md](preview.md). Pictures of the template's own slides from any other tool work as well.
|
|
235
|
+
|
|
236
|
+
## Showing a presentation
|
|
237
|
+
|
|
238
|
+
Set the `preview` option to a `PreviewProvider` and every presentation the tools create or change is drawn.
|
|
239
|
+
The pictures go to the store under `preview/<presentation id>/`, their keys are in the tool's output, and the
|
|
240
|
+
`ToolResult` carries the pictures themselves in `previews` for your app to show. How to get a provider, and how
|
|
241
|
+
close its pictures are to PowerPoint, is in [preview.md](preview.md).
|
|
224
242
|
|
|
225
243
|
## A complete loop
|
|
226
244
|
|
|
@@ -247,6 +265,9 @@ async function runTurn(messages) {
|
|
|
247
265
|
The tool descriptions already tell the model the order to work in. It helps to add, in your own system prompt:
|
|
248
266
|
|
|
249
267
|
- Put every fact, figure and name the person gave into `topic`. Numbers that are not in `topic` will not be used.
|
|
268
|
+
- Pass wishes about the kind of slides on, in the person's words ("no tables", "only cards"), in `topic` or
|
|
269
|
+
`instructions`. For a presentation of text only, set `text_only: true`: "no pictures" alone
|
|
270
|
+
(`image_density: "none"`) still allows cards, tables and charts.
|
|
250
271
|
- Show the plan and wait for approval before calling `create_presentation`.
|
|
251
272
|
- For a change to a finished presentation, call `edit_presentation` with the person's words; do not plan again
|
|
252
273
|
from scratch.
|
package/docs/deck-format.md
CHANGED
|
@@ -223,3 +223,9 @@ const issues = validateDeck(manifest, deck, { layout: 'adaptive', assets: ['phot
|
|
|
223
223
|
|
|
224
224
|
Errors make `renderDeck` throw. Warnings do not. Every message is listed in
|
|
225
225
|
[troubleshooting.md](troubleshooting.md).
|
|
226
|
+
|
|
227
|
+
## Another pattern for a slide
|
|
228
|
+
|
|
229
|
+
`slideAlternatives(manifest, deck, slideNumber)` lists the other patterns that can hold what a slide says, and
|
|
230
|
+
returns the slide written for each: cards as a list, a slide as its mirror image. It changes no words and
|
|
231
|
+
calls no model. See "Another layout for the same slide" in [layout-freedom.md](layout-freedom.md).
|
|
@@ -0,0 +1,216 @@
|
|
|
1
|
+
# Design checks and reviews
|
|
2
|
+
|
|
3
|
+
Validation (`validateDeck`) says whether a deck can be rendered and whether its text fits. This page is about
|
|
4
|
+
what comes after that: a deck that renders and fits can still look wrong. A body of two words in a box drawn
|
|
5
|
+
for a paragraph, one short card in a row of full ones, a title whose last word sits alone on a second line.
|
|
6
|
+
|
|
7
|
+
There are two tools:
|
|
8
|
+
|
|
9
|
+
- **`checkDesign`** finds such problems by measurement alone. No picture is made and no model is called.
|
|
10
|
+
- **A review** is a second look at each draft while a deck is being written. What it finds goes back to the
|
|
11
|
+
writing model in the same repair round as the limits the draft broke. A review can be the design checks, a
|
|
12
|
+
model that looks at pictures of the slides, or a function of your own. Nothing reviews a draft unless you ask.
|
|
13
|
+
|
|
14
|
+
Both need a template loaded with its fonts: see [text-fit.md](text-fit.md).
|
|
15
|
+
|
|
16
|
+
## `checkDesign(template, deck, options?)`
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { checkDesign } from 'slotdeck';
|
|
20
|
+
|
|
21
|
+
const problems = checkDesign(template, deck, { layout: 'adaptive' });
|
|
22
|
+
// [
|
|
23
|
+
// { severity: 'warning', slide: 1, slot: 'title', kind: 'orphan',
|
|
24
|
+
// message: 'the last of its 2 lines holds one word, "Share". Text of about 24 characters ends a line sooner; a few words more fill the line.' },
|
|
25
|
+
// ]
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
It is synchronous and takes a fraction of a second for a deck. It throws when the template has no fonts.
|
|
29
|
+
|
|
30
|
+
### What it finds
|
|
31
|
+
|
|
32
|
+
| `kind` | Problem | Message |
|
|
33
|
+
| --- | --- | --- |
|
|
34
|
+
| `overflow` | Text runs over its box. The same finding, with the same words, as the warning of `validateDeck` with fonts. | `text takes 7 lines at 18 pt; the box holds 5 (2 lines too many). Text of about 290 characters fits.` |
|
|
35
|
+
| `empty` | Text takes a third or less of the lines the template's own text takes in that box, so the box looks empty. | `text takes 1 line where the template's own text takes 5, so its box will look empty. Text of about 45 characters fills it as designed.` |
|
|
36
|
+
| `uneven` | In a row of cards, one card's text takes a third or less of the lines of its fullest neighbour. | `text takes 1 line where "card1Text" beside it takes 5, so the row will look uneven. Text of about 66 characters or more evens it out.` |
|
|
37
|
+
| `orphan` | A heading ends with one word on a line of its own. | `the last of its 2 lines holds one word, "Share". Text of about 24 characters ends a line sooner; a few words more fill the line.` |
|
|
38
|
+
|
|
39
|
+
Every message says what to do about it, with a length in characters. That is what the writing model can act
|
|
40
|
+
on, so a message can be sent to it as it is.
|
|
41
|
+
|
|
42
|
+
### The result
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
interface DesignIssue {
|
|
46
|
+
severity: 'warning';
|
|
47
|
+
slide: number; // 1-based
|
|
48
|
+
slot: string; // the slot name as the deck uses it
|
|
49
|
+
kind: 'overflow' | 'empty' | 'uneven' | 'orphan';
|
|
50
|
+
message: string;
|
|
51
|
+
}
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
A `DesignIssue` is an `Issue` with a `kind`, so the list can be shown or stored together with the warnings of
|
|
55
|
+
`validateDeck` and `renderDeck`.
|
|
56
|
+
|
|
57
|
+
### Options
|
|
58
|
+
|
|
59
|
+
| Option | Default | Meaning |
|
|
60
|
+
| --- | --- | --- |
|
|
61
|
+
| `layout` | `'strict'` | As for `renderDeck`: with `'adaptive'`, optional slots may be left out. |
|
|
62
|
+
| `kinds` | all four | Which problems to look for, e.g. `['empty', 'orphan']`. |
|
|
63
|
+
| `emptyBelow` | `1/3` | A text is `empty` when it takes this share or less of the lines the template's own text takes; a card is `uneven` at this share or less of its fullest neighbour. |
|
|
64
|
+
| `headingSize` | `20` | The font size in points from which a single paragraph counts as a heading, for `orphan`. |
|
|
65
|
+
|
|
66
|
+
### How each check decides
|
|
67
|
+
|
|
68
|
+
**`overflow`.** The measured text needs more height than its box gives. If the manifest has `shrinkText`, a
|
|
69
|
+
text that fits once it is set smaller is not reported.
|
|
70
|
+
|
|
71
|
+
**`empty`.** The reference is the template itself: the lines its own sample text takes in the slot. A slot is
|
|
72
|
+
looked at only when that is three lines or more, so a title or a one-line caption is never "empty". A slot that
|
|
73
|
+
the manifest resized (`box`, `fontSize`: a derived pattern) has no sample to compare with; its box is
|
|
74
|
+
then taken to be meant half full. A `box` that only moves the shape, as in a mirrored pattern, keeps the
|
|
75
|
+
comparison. In a row that widens its items, the reference is the item as drawn: a short text in a wide card
|
|
76
|
+
takes fewer lines, so it is reported sooner, with the length that fills the wider card. A slot fed by a deck field is not checked, because that text is the app's.
|
|
77
|
+
|
|
78
|
+
**`uneven`.** The slots of one kind across a row are compared: every card's text with every other card's text,
|
|
79
|
+
every heading with every heading. Rows come from the pattern's `repeat` or its `sequences`. A row is looked at
|
|
80
|
+
only when its fullest item takes three lines or more. Items whose text overflows are left out of the
|
|
81
|
+
comparison.
|
|
82
|
+
|
|
83
|
+
**`orphan`.** A text of one paragraph, set at `headingSize` or larger, on two lines or more, whose last line
|
|
84
|
+
is a single word no wider than two fifths of the widest line. An address (`name@example.org`, a web address)
|
|
85
|
+
on its own line is not reported: it is meant to stand there.
|
|
86
|
+
|
|
87
|
+
### What it does not see
|
|
88
|
+
|
|
89
|
+
- Tables, charts and pictures. Only text slots are measured.
|
|
90
|
+
- Slots set in a typeface that was not supplied. They are passed over (see `missingFonts` in
|
|
91
|
+
[text-fit.md](text-fit.md)).
|
|
92
|
+
- Anything that needs a picture to judge: colours, contrast, a photo that does not suit the text.
|
|
93
|
+
- Whether a line break looks good in the middle of a heading. Only the last line is looked at.
|
|
94
|
+
|
|
95
|
+
On this project's hand-written example deck the checks report two things, both real: the cover title ends with
|
|
96
|
+
"Share" on a second line, and the title of slide 4 with "trip". PowerPoint's own picture of the deck shows
|
|
97
|
+
both.
|
|
98
|
+
|
|
99
|
+
## Reviews: a second look while a deck is written
|
|
100
|
+
|
|
101
|
+
The planner writes a draft, validates it, and sends a draft that breaks the template's limits back to the
|
|
102
|
+
model (see "How planning works" in [generating.md](generating.md)). A review adds its own findings to that
|
|
103
|
+
round.
|
|
104
|
+
|
|
105
|
+
```ts
|
|
106
|
+
import { designReview, planDeck } from 'slotdeck';
|
|
107
|
+
|
|
108
|
+
const { deck, warnings } = await planDeck(template, brief, {
|
|
109
|
+
llm,
|
|
110
|
+
review: designReview(template), // empty boxes, uneven cards, orphan words
|
|
111
|
+
});
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
The `review` option is accepted wherever a deck is written: `planDeck`, `writeDeck`, `generateDeck`,
|
|
115
|
+
`planEdit`, `editDeck`, and `presentationTools`.
|
|
116
|
+
|
|
117
|
+
How it works:
|
|
118
|
+
|
|
119
|
+
1. After each draft, validation runs as always. If the draft has no errors, the review is called with it.
|
|
120
|
+
2. What validation and the review found on the slides just written goes back to the model, each as one line:
|
|
121
|
+
`- s3.title: the last of its 2 lines holds one word, ...`.
|
|
122
|
+
3. This repeats up to `maxRepairs` times (2 by default). A review therefore runs up to three times for a deck.
|
|
123
|
+
4. Whatever is still found after the last round is returned in `warnings`, next to the validation warnings.
|
|
124
|
+
|
|
125
|
+
A review can make the planner use more model calls: a draft that was within its limits may now be sent back.
|
|
126
|
+
With `designReview` the review itself costs nothing; each repair it causes is one writing call.
|
|
127
|
+
|
|
128
|
+
### `designReview(template, options?)`
|
|
129
|
+
|
|
130
|
+
The code-only checks as a review. It reports `empty`, `uneven` and `orphan`; `overflow` is left to validation,
|
|
131
|
+
which reports it anyway. `options` are those of `checkDesign`.
|
|
132
|
+
|
|
133
|
+
### A review of your own
|
|
134
|
+
|
|
135
|
+
A review is a function from a draft deck to problems:
|
|
136
|
+
|
|
137
|
+
```ts
|
|
138
|
+
import type { DeckReview, Issue } from 'slotdeck';
|
|
139
|
+
|
|
140
|
+
const review: DeckReview = async (deck, { signal }) => {
|
|
141
|
+
const problems: Issue[] = [];
|
|
142
|
+
deck.slides.forEach((slide, index) => {
|
|
143
|
+
if (typeof slide.slots.title === 'string' && slide.slots.title.endsWith(':')) {
|
|
144
|
+
problems.push({ severity: 'warning', slide: index + 1, slot: 'title', message: 'a title must not end with a colon' });
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
return problems;
|
|
148
|
+
};
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
Each problem is an `Issue`: `severity`, a 1-based `slide`, a `slot` when it is about one, and a `message`
|
|
152
|
+
written for the model. A problem without a `slide`, or on a slide the model was not asked to write, is not
|
|
153
|
+
sent back; it is returned in `warnings` all the same.
|
|
154
|
+
|
|
155
|
+
### `visionReview(options)`: a model that looks at the slides
|
|
156
|
+
|
|
157
|
+
```ts
|
|
158
|
+
import { planDeck, visionReview } from 'slotdeck';
|
|
159
|
+
|
|
160
|
+
const review = visionReview({
|
|
161
|
+
template,
|
|
162
|
+
llm: visionModel, // an LlmProvider whose model can look at pictures
|
|
163
|
+
preview, // a PreviewProvider that gives PNG or JPEG
|
|
164
|
+
icons, // optional: the app's icons and supplied pictures, drawn as they are
|
|
165
|
+
assets,
|
|
166
|
+
});
|
|
167
|
+
const { deck, warnings } = await planDeck(template, brief, { llm, review });
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
For each draft it:
|
|
171
|
+
|
|
172
|
+
1. renders the deck, with a plain grey rectangle for every picture that does not exist yet (photos are
|
|
173
|
+
generated after planning);
|
|
174
|
+
2. asks the preview provider for a picture of each slide;
|
|
175
|
+
3. shows the model the pictures, six slides to a request, with the text of each slide's slots, and asks only
|
|
176
|
+
for what can be seen and fixed by changing text: text cut off or lying over something, text too small to
|
|
177
|
+
read, a box or slide left mostly empty, a heading that ends in a lone word;
|
|
178
|
+
4. returns what the model reports, each as `seen in the picture of the slide: ...`, with the slot when the
|
|
179
|
+
model named one that the slide has.
|
|
180
|
+
|
|
181
|
+
| Option | Default | Meaning |
|
|
182
|
+
| --- | --- | --- |
|
|
183
|
+
| `template` | required | The template the deck is made from. |
|
|
184
|
+
| `llm` | required | A provider whose model accepts pictures (`JsonRequest.images`). It can be another model than the one that writes. |
|
|
185
|
+
| `preview` | required | Draws the draft. It must give bitmap pictures: PNG, JPEG, WebP or GIF. |
|
|
186
|
+
| `icons`, `assets` | none | Pictures the deck may use, drawn as they are instead of as rectangles. |
|
|
187
|
+
| `layout` | `'adaptive'` | As for `renderDeck`. |
|
|
188
|
+
| `slidesPerRequest` | `6` | How many slides are shown to the model in one request. |
|
|
189
|
+
|
|
190
|
+
Each request is capped at 300 output tokens plus 200 for each slide in it. A draft that cannot be rendered is
|
|
191
|
+
not looked at: its errors are validation's to report.
|
|
192
|
+
|
|
193
|
+
**Read this before turning it on.**
|
|
194
|
+
|
|
195
|
+
- **It is only as good as the pictures.** A model that is shown a preview which differs from PowerPoint will
|
|
196
|
+
report problems that are not there. The Pagus adapter that comes with slotdeck gives SVG, which a model
|
|
197
|
+
cannot read, and `visionReview` refuses it with an error. Use a provider whose pictures can be trusted, such
|
|
198
|
+
as PowerPoint's own export on a machine that has it. See "How close the pictures are" in
|
|
199
|
+
[preview.md](preview.md).
|
|
200
|
+
- **It has not been run against a live model, or against faithful pictures.** It was built and tested with a
|
|
201
|
+
scripted model and made-up pictures: what is sent, how the answer is read, how it takes part in the repair
|
|
202
|
+
round. How well a real model judges real slides with this prompt is not known. Try it on your own decks
|
|
203
|
+
before relying on it.
|
|
204
|
+
- **It costs model calls with pictures:** one request for every six slides, for every draft, so up to three
|
|
205
|
+
times a deck with the default `maxRepairs`.
|
|
206
|
+
- The code-only checks already cover overflow, empty boxes, uneven cards and orphan words, exactly and at no
|
|
207
|
+
cost. A vision review is for what measurement cannot see.
|
|
208
|
+
|
|
209
|
+
### Reviews in the chat tools
|
|
210
|
+
|
|
211
|
+
```ts
|
|
212
|
+
const tools = presentationTools({ template, llm, store, review: designReview(template) });
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
The review then runs for every deck `create_presentation` writes and for the slides `edit_presentation`
|
|
216
|
+
rewrites. What it leaves unfixed is in the tool's `warnings`.
|
package/docs/generating.md
CHANGED
|
@@ -36,6 +36,7 @@ It runs `planDeck`, then `resolveAssets`, then `renderDeck`.
|
|
|
36
36
|
| `instructions` | string | none | Anything else to respect: audience, tone, points that must be covered. |
|
|
37
37
|
| `fields` | object of strings | none | Deck-level values the template needs (see "Deck fields" in [deck-format.md](deck-format.md)). A pattern that needs a field that is not given is not offered. |
|
|
38
38
|
| `textSize` | `"normal"`, `"large"`, `"x-large"` | `normal` | Size of body text. Larger text gets smaller budgets, so less is written. |
|
|
39
|
+
| `textOnly` | boolean | `false` | Plan every slide as plain text. Only the template's plain text patterns are offered. See "Asking for a kind of slide" below. |
|
|
39
40
|
|
|
40
41
|
### Options (`GenerateOptions`)
|
|
41
42
|
|
|
@@ -49,6 +50,7 @@ It runs `planDeck`, then `resolveAssets`, then `renderDeck`.
|
|
|
49
50
|
| `patterns` | string[] | all | Restrict the deck to these pattern ids. |
|
|
50
51
|
| `numberPatterns` | `"from-brief"`, `"always"`, `"never"` | `from-brief` | When patterns marked `figures` may be used. `from-brief` offers them only if the brief contains digits. |
|
|
51
52
|
| `maxRepairs` | number | 2 | How many times a draft that breaks the template's limits is sent back to the model. |
|
|
53
|
+
| `review` | `DeckReview` | none | A second look at every draft: design checks, a model that looks at pictures of the slides, or a function of your own. What it finds goes back to the model in the repair rounds. See [design-checks.md](design-checks.md). |
|
|
52
54
|
| `cache` | `Map<string, Uint8Array>` | none | Generated pictures by asset id. Pass the same map on later calls and pictures whose description did not change are reused. |
|
|
53
55
|
| `imageConcurrency` | number | 3 | How many pictures to generate at once. |
|
|
54
56
|
| `onProgress` | function | none | Called with `{ stage: 'outline' }`, `{ stage: 'write', slides }`, `{ stage: 'repair', attempt, issues }`, `{ stage: 'images', done, total }`, `{ stage: 'render' }`. |
|
|
@@ -87,7 +89,9 @@ const { pptx, deck, warnings } = await generateDeck(
|
|
|
87
89
|
2. **Write** (one model call). The model fills a JSON schema built for exactly that sequence of slides, so it
|
|
88
90
|
cannot invent patterns or slots.
|
|
89
91
|
3. **Repair** (up to `maxRepairs` more calls). The draft is validated against the manifest. Errors and
|
|
90
|
-
over-budget text go back to the model with the list of problems.
|
|
92
|
+
over-budget text go back to the model with the list of problems. For a template loaded with fonts the
|
|
93
|
+
text is measured, and the problems are stated in lines ([text-fit.md](text-fit.md)). With a `review`, what
|
|
94
|
+
the review finds on a draft goes back in the same list ([design-checks.md](design-checks.md)).
|
|
91
95
|
|
|
92
96
|
Which patterns are offered depends on what you supplied:
|
|
93
97
|
|
|
@@ -105,6 +109,37 @@ model.
|
|
|
105
109
|
|
|
106
110
|
If nothing can be offered, `PlanError` is thrown with the reasons.
|
|
107
111
|
|
|
112
|
+
### Asking for a kind of slide
|
|
113
|
+
|
|
114
|
+
By default the planner varies the patterns across a deck. A wish about the kind of slides overrides that, and
|
|
115
|
+
there are two ways to state one.
|
|
116
|
+
|
|
117
|
+
**In words.** A wish in `prompt` or `instructions`, such as "text only", "no tables" or "only cards", decides
|
|
118
|
+
which patterns may be used and comes before variety. The planner is told so, and the pattern list it reads marks
|
|
119
|
+
each plain text pattern with the words "Plain text.".
|
|
120
|
+
|
|
121
|
+
**As a flag.** `textOnly: true` is the reliable way to get a deck of text and nothing else. The planner is then
|
|
122
|
+
offered only the plain text patterns, so no other kind can be chosen, and it is told that using the same pattern
|
|
123
|
+
for several slides in a row is expected.
|
|
124
|
+
|
|
125
|
+
```ts
|
|
126
|
+
await generateDeck(template, { prompt: 'Our move to hybrid work: why, the rules, what changed', textOnly: true }, { llm });
|
|
127
|
+
// for example: cover, text-only, text-only, text-only, text-only, closing
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
A pattern counts as **plain text** when a slide made from it holds running text and nothing else: all its
|
|
131
|
+
slots are text (a picture that the pattern always drops does not count), it has no row or grid of items, and it
|
|
132
|
+
is not marked `figures`. A cover, a closing slide, a quotation and a title-with-paragraphs slide are plain text;
|
|
133
|
+
cards, tables, charts and anything with a picture or icon are not.
|
|
134
|
+
|
|
135
|
+
Two things to know:
|
|
136
|
+
|
|
137
|
+
- "No pictures" is a different wish. `imageDensity: 'none'` removes photos but still allows cards, tables and
|
|
138
|
+
charts.
|
|
139
|
+
- A text-only deck is only as varied as the template's plain text patterns. A template without one cannot make
|
|
140
|
+
such a deck: `PlanError: Template "x" has no plain text pattern, so a text-only deck cannot be planned from it`.
|
|
141
|
+
Add one as a derived pattern (see [layout-freedom.md](layout-freedom.md)).
|
|
142
|
+
|
|
108
143
|
### Why numbers are guarded
|
|
109
144
|
|
|
110
145
|
A model given a slide built around a statistic and no data tends to invent one. So patterns marked `figures` are
|
|
@@ -210,9 +245,13 @@ Warnings (text a little over a budget, for instance) do not throw. They are retu
|
|
|
210
245
|
|
|
211
246
|
## Cost and time
|
|
212
247
|
|
|
213
|
-
For one deck: two text calls, more if repairs are needed, and one image call per generated photo.
|
|
214
|
-
template with `gemini-3.8-flash
|
|
215
|
-
rewrites one slide
|
|
248
|
+
For one deck: two text calls, more if repairs are needed, and one image call per generated photo. Measured on
|
|
249
|
+
the demo template with `gemini-3.8-flash`: a plan takes about 5 seconds, an eight-slide deck about 30 seconds
|
|
250
|
+
from brief to file (with drawn stand-in pictures), and an edit that rewrites one slide about 8 seconds.
|
|
251
|
+
|
|
252
|
+
Planning calls (the outline, a change to a plan, the first step of an edit) ask the model for light reasoning,
|
|
253
|
+
because they choose and arrange rather than write. This made them several times faster and removed the runaway
|
|
254
|
+
answers described in [providers.md](providers.md). Writing the slides keeps the model's default.
|
|
216
255
|
|
|
217
256
|
To keep cost down: reuse `cache` across calls, set `imageDensity: 'low'` or `'none'`, and use `planOutline`
|
|
218
257
|
first so a person can correct the plan before content and pictures are produced.
|