@purpleschool/gptbot-tools 0.1.10 → 0.1.11
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/build/presentation/commands/create-presentation.command.js +3 -0
- package/build/presentation/commands/get-presentation-slides-generation-price.command.js +1 -0
- package/build/presentation/enums/index.js +1 -0
- package/build/presentation/enums/presentation-target-audience.enum.js +10 -0
- package/build/presentation/models/index.js +1 -0
- package/build/presentation/models/presentation-template.schema.js +1 -0
- package/build/presentation/models/presentation-title-page.schema.js +9 -0
- package/build/presentation/models/presentation.schema.js +4 -0
- package/build/presentation/models/slide-content-edit.schema.js +12 -6
- package/build/presentation/models/slide-content.schema.js +197 -61
- package/package.json +1 -1
- package/presentation/commands/create-presentation.command.ts +4 -1
- package/presentation/commands/get-presentation-slides-generation-price.command.ts +1 -0
- package/presentation/enums/index.ts +1 -0
- package/presentation/enums/presentation-target-audience.enum.ts +6 -0
- package/presentation/models/index.ts +1 -0
- package/presentation/models/presentation-template.schema.ts +1 -0
- package/presentation/models/presentation-title-page.schema.ts +9 -0
- package/presentation/models/presentation.schema.ts +5 -1
- package/presentation/models/slide-content-edit.schema.ts +18 -12
- package/presentation/models/slide-content.schema.ts +269 -71
|
@@ -4,6 +4,7 @@ exports.CreatePresentationCommand = void 0;
|
|
|
4
4
|
const zod_1 = require("zod");
|
|
5
5
|
const common_1 = require("../../common");
|
|
6
6
|
const models_1 = require("../models");
|
|
7
|
+
const enums_1 = require("../enums");
|
|
7
8
|
var CreatePresentationCommand;
|
|
8
9
|
(function (CreatePresentationCommand) {
|
|
9
10
|
CreatePresentationCommand.RequestSchema = zod_1.z.object({
|
|
@@ -13,6 +14,8 @@ var CreatePresentationCommand;
|
|
|
13
14
|
languageId: zod_1.z.string(),
|
|
14
15
|
prompt: zod_1.z.string(),
|
|
15
16
|
slideCount: zod_1.z.number(),
|
|
17
|
+
titlePage: models_1.PresentationTitlePageSchema.optional().nullable(),
|
|
18
|
+
targetAudience: zod_1.z.nativeEnum(enums_1.PRESENTATION_TARGET_AUDIENCE).optional(),
|
|
16
19
|
});
|
|
17
20
|
CreatePresentationCommand.ResponseSchema = (0, common_1.ICommandResponseSchema)(models_1.PresentationSchema);
|
|
18
21
|
})(CreatePresentationCommand || (exports.CreatePresentationCommand = CreatePresentationCommand = {}));
|
|
@@ -7,6 +7,7 @@ var GetPresentationSlidesGenerationPriceCommand;
|
|
|
7
7
|
(function (GetPresentationSlidesGenerationPriceCommand) {
|
|
8
8
|
GetPresentationSlidesGenerationPriceCommand.RequestSchema = zod_1.z.object({
|
|
9
9
|
slideCount: zod_1.z.number().int().min(1),
|
|
10
|
+
templateId: zod_1.z.string().uuid(),
|
|
10
11
|
});
|
|
11
12
|
GetPresentationSlidesGenerationPriceCommand.ResponseDataSchema = zod_1.z.object({
|
|
12
13
|
price: zod_1.z.number(),
|
|
@@ -24,3 +24,4 @@ __exportStar(require("./slide-image-slot-action.enum"), exports);
|
|
|
24
24
|
__exportStar(require("./presentation-ai-action-call-status.enum"), exports);
|
|
25
25
|
__exportStar(require("./presentation-ai-action-type.enum"), exports);
|
|
26
26
|
__exportStar(require("./presentation-ai-action-pricing-type.enum"), exports);
|
|
27
|
+
__exportStar(require("./presentation-target-audience.enum"), exports);
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PRESENTATION_TARGET_AUDIENCE = void 0;
|
|
4
|
+
var PRESENTATION_TARGET_AUDIENCE;
|
|
5
|
+
(function (PRESENTATION_TARGET_AUDIENCE) {
|
|
6
|
+
PRESENTATION_TARGET_AUDIENCE["NONE"] = "NONE";
|
|
7
|
+
PRESENTATION_TARGET_AUDIENCE["SCHOOL"] = "SCHOOL";
|
|
8
|
+
PRESENTATION_TARGET_AUDIENCE["UNIVERSITY"] = "UNIVERSITY";
|
|
9
|
+
PRESENTATION_TARGET_AUDIENCE["BUSINESS"] = "BUSINESS";
|
|
10
|
+
})(PRESENTATION_TARGET_AUDIENCE || (exports.PRESENTATION_TARGET_AUDIENCE = PRESENTATION_TARGET_AUDIENCE = {}));
|
|
@@ -24,3 +24,4 @@ __exportStar(require("./slide.schema"), exports);
|
|
|
24
24
|
__exportStar(require("./slide-image-slot.schema"), exports);
|
|
25
25
|
__exportStar(require("./slide-content.schema"), exports);
|
|
26
26
|
__exportStar(require("./presentation-ai-action.schema"), exports);
|
|
27
|
+
__exportStar(require("./presentation-title-page.schema"), exports);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PresentationTitlePageSchema = void 0;
|
|
4
|
+
const zod_1 = require("zod");
|
|
5
|
+
exports.PresentationTitlePageSchema = zod_1.z.object({
|
|
6
|
+
author: zod_1.z.string().optional().nullable(),
|
|
7
|
+
createdAt: zod_1.z.date().optional().nullable(),
|
|
8
|
+
email: zod_1.z.string().email().optional().nullable(),
|
|
9
|
+
});
|
|
@@ -6,6 +6,7 @@ const enums_1 = require("../enums");
|
|
|
6
6
|
const slide_outline_schema_1 = require("./slide-outline.schema");
|
|
7
7
|
const slide_schema_1 = require("./slide.schema");
|
|
8
8
|
const common_1 = require("../../common");
|
|
9
|
+
const presentation_title_page_schema_1 = require("./presentation-title-page.schema");
|
|
9
10
|
exports.PresentationSchema = zod_1.z.object({
|
|
10
11
|
uuid: zod_1.z.string().uuid(),
|
|
11
12
|
prompt: zod_1.z.string(),
|
|
@@ -24,6 +25,8 @@ exports.PresentationSchema = zod_1.z.object({
|
|
|
24
25
|
tokenReservationId: zod_1.z.string().nullable().optional(),
|
|
25
26
|
lastContentUpdateAt: zod_1.z.date().nullable(),
|
|
26
27
|
lastPptxExportedAt: zod_1.z.date().nullable(),
|
|
28
|
+
titlePage: presentation_title_page_schema_1.PresentationTitlePageSchema.nullable(),
|
|
29
|
+
targetAudience: zod_1.z.nativeEnum(enums_1.PRESENTATION_TARGET_AUDIENCE),
|
|
27
30
|
createdAt: zod_1.z.date(),
|
|
28
31
|
updatedAt: zod_1.z.date(),
|
|
29
32
|
});
|
|
@@ -34,4 +37,5 @@ exports.PresentationWithSlidesSchema = exports.PresentationSchema.extend({
|
|
|
34
37
|
exports.PresentationUpdateSchema = exports.PresentationSchema.pick({
|
|
35
38
|
title: true,
|
|
36
39
|
templateId: true,
|
|
40
|
+
titlePage: true,
|
|
37
41
|
}).partial();
|
|
@@ -10,18 +10,24 @@ const slide_content_schema_1 = require("./slide-content.schema");
|
|
|
10
10
|
exports.CoverSlideDataUserEditSchema = zod_1.default.object({
|
|
11
11
|
contentType: zod_1.default.literal(enums_1.SLIDE_CONTENT_TYPE.COVER),
|
|
12
12
|
title: zod_1.default.string().min(1).max(500),
|
|
13
|
-
author: zod_1.default
|
|
13
|
+
author: zod_1.default
|
|
14
|
+
.object({
|
|
14
15
|
label: zod_1.default.string().min(1).max(100),
|
|
15
16
|
value: zod_1.default.string().min(1).max(200),
|
|
16
|
-
})
|
|
17
|
-
|
|
17
|
+
})
|
|
18
|
+
.optional(),
|
|
19
|
+
date: zod_1.default
|
|
20
|
+
.object({
|
|
18
21
|
label: zod_1.default.string().min(1).max(100),
|
|
19
22
|
value: zod_1.default.string().min(1).max(200),
|
|
20
|
-
})
|
|
21
|
-
|
|
23
|
+
})
|
|
24
|
+
.optional(),
|
|
25
|
+
email: zod_1.default
|
|
26
|
+
.object({
|
|
22
27
|
label: zod_1.default.string().min(1).max(100),
|
|
23
28
|
value: zod_1.default.string().min(1).max(200),
|
|
24
|
-
})
|
|
29
|
+
})
|
|
30
|
+
.optional(),
|
|
25
31
|
version: zod_1.default.literal(1),
|
|
26
32
|
});
|
|
27
33
|
exports.ThankYouSlideDataUserEditSchema = zod_1.default.object({
|
|
@@ -12,7 +12,17 @@ exports.ImageSlotSchema = zod_1.z.object({
|
|
|
12
12
|
.string()
|
|
13
13
|
.uuid()
|
|
14
14
|
.describe('Generate a valid uuid for image slot, that will be used for future lookups'),
|
|
15
|
-
prompt: zod_1.z
|
|
15
|
+
prompt: zod_1.z
|
|
16
|
+
.string()
|
|
17
|
+
.describe('Image generation prompt. MUST be written in ENGLISH regardless of the presentation language. ' +
|
|
18
|
+
'AI image generators excel at: atmospheric scenes, landscapes, cityscapes, architecture, nature, abstract light and texture, anonymous silhouettes, artistic photography. ' +
|
|
19
|
+
'AI fundamentally cannot render accurately: legible text on any surface, complex diagrams or flowcharts, data charts/graphs, specific product logos, clocks, precise mechanical parts. ' +
|
|
20
|
+
'Choose scene types from the first category. Avoid anything in the second. ' +
|
|
21
|
+
'Structure: [subject/scene] → [mood/atmosphere] → [lighting] → [visual style]. ' +
|
|
22
|
+
'Evoke the emotional register of the slide — do not illustrate the topic literally. ' +
|
|
23
|
+
'MODERATION: if the slide topic involves conflict, suffering, politics, or crime, redirect to abstract/atmospheric imagery (fog, ruins, empty landscapes) rather than depicting the subject directly — flagged prompts produce empty placeholders. ' +
|
|
24
|
+
'GOOD: "A lone figure on an observation deck at dusk gazing over an illuminated city. Cinematic wide-angle, golden-hour light, photorealistic." ' +
|
|
25
|
+
'BAD: "A bar chart showing quarterly growth. A robot at a laptop with code on the screen."'),
|
|
16
26
|
});
|
|
17
27
|
exports.IconSlotSchema = zod_1.z.object({
|
|
18
28
|
uuid: zod_1.z
|
|
@@ -24,22 +34,26 @@ exports.IconSlotSchema = zod_1.z.object({
|
|
|
24
34
|
exports.CoverSlideDataSchema = zod_1.z.object({
|
|
25
35
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.COVER),
|
|
26
36
|
title: zod_1.z.string().describe('Slide title in about 6 words').min(10).max(150),
|
|
27
|
-
author: zod_1.z
|
|
37
|
+
author: zod_1.z
|
|
38
|
+
.object({
|
|
28
39
|
label: zod_1.z.string().describe('Literal "Author" in presentation\'s language'),
|
|
29
|
-
value: zod_1.z
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
40
|
+
value: zod_1.z.string().describe('Author value from titlePage if provided'),
|
|
41
|
+
})
|
|
42
|
+
.optional(),
|
|
43
|
+
date: zod_1.z
|
|
44
|
+
.object({
|
|
34
45
|
label: zod_1.z.string().describe('Literal "Date" in presentation\'s language'),
|
|
35
46
|
value: zod_1.z
|
|
36
47
|
.string()
|
|
37
|
-
.describe('Date
|
|
38
|
-
})
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
48
|
+
.describe('Date from titlePage in the "dd month yyyy" format in presentation\'s locale'),
|
|
49
|
+
})
|
|
50
|
+
.optional(),
|
|
51
|
+
email: zod_1.z
|
|
52
|
+
.object({
|
|
53
|
+
label: zod_1.z.string().describe('Localized contact/email label'),
|
|
54
|
+
value: zod_1.z.string().describe('Email value from titlePage if provided'),
|
|
55
|
+
})
|
|
56
|
+
.optional(),
|
|
43
57
|
version: zod_1.z.literal(1),
|
|
44
58
|
});
|
|
45
59
|
exports.ThankYouSlideDataSchema = zod_1.z.object({
|
|
@@ -67,28 +81,49 @@ exports.ThankYouSlideDataSchema = zod_1.z.object({
|
|
|
67
81
|
});
|
|
68
82
|
exports.StructuredListSlideDataSchema = zod_1.z.object({
|
|
69
83
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.STRUCTURED_LIST),
|
|
70
|
-
title: zod_1.z
|
|
71
|
-
|
|
84
|
+
title: zod_1.z
|
|
85
|
+
.string()
|
|
86
|
+
.describe('Slide headline — 2–4 words naming the group. A noun phrase, NOT a full sentence. Displayed in very large font on the left panel.')
|
|
87
|
+
.min(5)
|
|
88
|
+
.max(40),
|
|
89
|
+
description: zod_1.z
|
|
90
|
+
.string()
|
|
91
|
+
.describe('One framing sentence answering "What are these 4 things about?". Displayed in small text below the title on the left panel.')
|
|
92
|
+
.min(30)
|
|
93
|
+
.max(80),
|
|
72
94
|
list: zod_1.z
|
|
73
95
|
.array(zod_1.z.object({
|
|
74
|
-
title: zod_1.z
|
|
96
|
+
title: zod_1.z
|
|
97
|
+
.string()
|
|
98
|
+
.describe('2–4 concrete words. A noun phrase or short verb phrase. All 4 titles MUST be grammatically parallel. Displayed in bold next to a large number (01–04).')
|
|
99
|
+
.min(3)
|
|
100
|
+
.max(30),
|
|
75
101
|
description: zod_1.z
|
|
76
102
|
.string()
|
|
77
|
-
.describe(
|
|
103
|
+
.describe('ONE complete sentence that expands on the title with a specific fact or benefit. NEVER just restate the title. NEVER cut short mid-word or mid-sentence. All 4 descriptions must be roughly equal in length.')
|
|
78
104
|
.min(50)
|
|
79
|
-
.max(
|
|
105
|
+
.max(100),
|
|
80
106
|
}))
|
|
81
107
|
.length(4),
|
|
82
108
|
version: zod_1.z.literal(1),
|
|
83
109
|
});
|
|
84
110
|
exports.TextSlideDataSchema = zod_1.z.object({
|
|
85
111
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.TEXT),
|
|
86
|
-
title: zod_1.z
|
|
112
|
+
title: zod_1.z
|
|
113
|
+
.string()
|
|
114
|
+
.describe('Slide headline rendered in very large bold font. Keep to 3–7 words (max 70 characters). It should name the topic or thesis — not summarise all content.')
|
|
115
|
+
.min(10)
|
|
116
|
+
.max(70),
|
|
87
117
|
description: zod_1.z
|
|
88
118
|
.string()
|
|
89
|
-
.describe(
|
|
119
|
+
.describe('Expository prose split into 2–3 paragraphs separated by \\n\\n (double newline). Total length 300–800 characters. ' +
|
|
120
|
+
'Use **bold** to highlight 1–3 key terms per paragraph (NOT entire sentences). ' +
|
|
121
|
+
'Use *italics* for definitions, counter-points, or light emphasis (1 per paragraph max). ' +
|
|
122
|
+
'NO bullet points, NO markdown headers, NO numbered lists. ' +
|
|
123
|
+
'Each paragraph covers ONE focused idea: e.g. context → main argument → implication. ' +
|
|
124
|
+
'Do NOT start consecutive paragraphs with the same word. Do NOT cut text short mid-sentence.')
|
|
90
125
|
.min(300)
|
|
91
|
-
.max(
|
|
126
|
+
.max(800),
|
|
92
127
|
version: zod_1.z.literal(1),
|
|
93
128
|
});
|
|
94
129
|
exports.ContentsSlideDataSchema = zod_1.z.object({
|
|
@@ -110,43 +145,92 @@ exports.ContentsSlideDataSchema = zod_1.z.object({
|
|
|
110
145
|
exports.ImageSlideDataSchema = zod_1.z
|
|
111
146
|
.object({
|
|
112
147
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.TEXT_WITH_IMAGE),
|
|
113
|
-
title: zod_1.z
|
|
114
|
-
description: zod_1.z
|
|
148
|
+
title: zod_1.z
|
|
115
149
|
.string()
|
|
116
|
-
.describe(
|
|
150
|
+
.describe('Slide headline rendered in very large bold font on the LEFT column. Keep to 3–7 words (max 70 characters). Aim for under 50 characters to avoid overflow. A noun phrase or short declarative phrase — NOT a full sentence.')
|
|
117
151
|
.min(10)
|
|
152
|
+
.max(70),
|
|
153
|
+
description: zod_1.z
|
|
154
|
+
.string()
|
|
155
|
+
.describe('Expository prose in 2 paragraphs separated by \\n\\n (double newline). Total length 150–500 characters. ' +
|
|
156
|
+
'Use **bold** for 1–2 key terms per paragraph (NOT entire sentences). ' +
|
|
157
|
+
'Use *italics* for definitions or emphasis at most once per paragraph. ' +
|
|
158
|
+
'NO bullet points, NO headers, NO numbered lists. ' +
|
|
159
|
+
'Each paragraph covers ONE focused idea. NEVER reference or describe the image in the text. ' +
|
|
160
|
+
'The image provides visual atmosphere — the text must stand alone as complete, readable prose.')
|
|
161
|
+
.min(150)
|
|
118
162
|
.max(500),
|
|
119
163
|
imageSlot: exports.ImageSlotSchema,
|
|
120
164
|
version: zod_1.z.literal(1),
|
|
121
165
|
})
|
|
122
|
-
.describe('Slide
|
|
166
|
+
.describe('Slide with a large title and prose description on the left, and a full-bleed supporting image on the right.');
|
|
123
167
|
exports.SectionBreakSlideDataSchema = zod_1.z.object({
|
|
124
168
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.SECTION_BREAK),
|
|
125
|
-
title: zod_1.z
|
|
126
|
-
|
|
169
|
+
title: zod_1.z
|
|
170
|
+
.string()
|
|
171
|
+
.describe('The section name — a clean noun phrase of 3–6 words that names the thematic block which follows. ' +
|
|
172
|
+
'NEVER prefix with "Раздел:", "Section:", "Part:", "Глава:", or any structural label. ' +
|
|
173
|
+
'NEVER include numbers. Just the name itself. ' +
|
|
174
|
+
'GOOD: "Технологические достижения". BAD: "Раздел 2: Технологические достижения".')
|
|
175
|
+
.min(5)
|
|
176
|
+
.max(60),
|
|
177
|
+
description: zod_1.z
|
|
178
|
+
.string()
|
|
179
|
+
.describe('One sentence (up to 100 characters) that briefly hints at the content of the upcoming section. ' +
|
|
180
|
+
'Should complement the title without repeating it. No markdown, no labels.')
|
|
181
|
+
.min(10)
|
|
182
|
+
.max(120),
|
|
127
183
|
version: zod_1.z.literal(1),
|
|
128
184
|
});
|
|
129
185
|
exports.TableSlideDataSchema = zod_1.z.object({
|
|
130
186
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.TABLE),
|
|
131
187
|
title: zod_1.z
|
|
132
188
|
.string()
|
|
133
|
-
.describe('
|
|
189
|
+
.describe('Table name — 2–4 words rendered as large bold heading above the table. ' +
|
|
190
|
+
'Doubles as both the slide title and the table heading. Keep concise.')
|
|
191
|
+
.min(5)
|
|
192
|
+
.max(55),
|
|
193
|
+
description: zod_1.z
|
|
194
|
+
.string()
|
|
195
|
+
.describe('One short sentence (max 80 characters) describing what the table shows. ' +
|
|
196
|
+
'Rendered in small gray text below the title. No markdown.')
|
|
134
197
|
.min(10)
|
|
135
|
-
.max(
|
|
136
|
-
description: zod_1.z.string().describe('Description of the table represents').min(10).max(200),
|
|
198
|
+
.max(100),
|
|
137
199
|
table: zod_1.z.object({
|
|
138
200
|
columnHeaders: zod_1.z
|
|
139
|
-
.array(zod_1.z
|
|
201
|
+
.array(zod_1.z
|
|
202
|
+
.string()
|
|
140
203
|
.min(1)
|
|
141
|
-
.max(
|
|
142
|
-
.describe('
|
|
204
|
+
.max(20)
|
|
205
|
+
.describe('Column label. Keep SHORT — 1–3 words. Include units here (e.g., "Сумма, ₽"), not in cells. ' +
|
|
206
|
+
'When hasRowHeaders is true, the first header should be a single space " " or a short category label.'))
|
|
207
|
+
.min(2)
|
|
208
|
+
.max(5)
|
|
209
|
+
.describe('Column header labels. MAXIMUM 5 columns total. Recommended 3–4 data columns. ' +
|
|
210
|
+
'More columns will overflow the slide — NEVER exceed 5.'),
|
|
143
211
|
rows: zod_1.z
|
|
144
|
-
.array(zod_1.z
|
|
145
|
-
.
|
|
212
|
+
.array(zod_1.z
|
|
213
|
+
.array(zod_1.z
|
|
214
|
+
.string()
|
|
215
|
+
.min(1)
|
|
216
|
+
.max(40)
|
|
217
|
+
.describe('Cell content. NUMERIC tables: numbers only (e.g., "1 200", "85%"). ' +
|
|
218
|
+
'TEXTUAL tables: 1–3 words maximum — keywords or short phrases ONLY, NEVER full sentences. ' +
|
|
219
|
+
'Row header cells (first cell when hasRowHeaders=true): category label, max 22 characters.'))
|
|
220
|
+
.describe('One row. Cell count MUST equal columnHeaders length exactly.'))
|
|
221
|
+
.min(2)
|
|
146
222
|
.max(4)
|
|
147
|
-
.describe('Table rows
|
|
148
|
-
|
|
149
|
-
|
|
223
|
+
.describe('Table rows. Max 4 rows total. ' +
|
|
224
|
+
'When hasSummaryRow is true, the LAST row is the summary row — so at most 3 regular rows + 1 summary = 4 total. ' +
|
|
225
|
+
'NEVER exceed 4 rows.'),
|
|
226
|
+
hasRowHeaders: zod_1.z
|
|
227
|
+
.boolean()
|
|
228
|
+
.describe('True when the first cell of each row is a descriptive label or category (pivot table). ' +
|
|
229
|
+
'False for plain data tables where all cells are equivalent data.'),
|
|
230
|
+
hasSummaryRow: zod_1.z
|
|
231
|
+
.boolean()
|
|
232
|
+
.describe('True when the last row contains totals, averages, or aggregated values. ' +
|
|
233
|
+
'That summary row must be the last element of the rows array.'),
|
|
150
234
|
}),
|
|
151
235
|
version: zod_1.z.literal(1),
|
|
152
236
|
});
|
|
@@ -154,61 +238,113 @@ exports.TableSlideDataSchema = zod_1.z.object({
|
|
|
154
238
|
exports.BarChartSlideDataSchema = zod_1.z.object({
|
|
155
239
|
type: zod_1.z.literal(SLIDE_CHART_TYPE.BAR),
|
|
156
240
|
categories: zod_1.z
|
|
157
|
-
.array(zod_1.z.string())
|
|
158
|
-
.min(
|
|
159
|
-
.max(
|
|
160
|
-
.describe('Category labels (e.g., months,
|
|
241
|
+
.array(zod_1.z.string().min(1).max(20))
|
|
242
|
+
.min(3)
|
|
243
|
+
.max(10)
|
|
244
|
+
.describe('Category labels (e.g., months, product names, departments). ' +
|
|
245
|
+
'Recommended: 4–8 items. Keep each label SHORT — 1–3 words, max 15 characters. ' +
|
|
246
|
+
'Categories work best when naturally ordered: time periods, rankings, or comparable groups.'),
|
|
161
247
|
series: zod_1.z
|
|
162
248
|
.array(zod_1.z.object({
|
|
163
249
|
name: zod_1.z
|
|
164
250
|
.string()
|
|
165
|
-
.
|
|
166
|
-
|
|
251
|
+
.max(40)
|
|
252
|
+
.describe('Series name shown in the chart legend. Do NOT include units here — units belong in the unit field. ' +
|
|
253
|
+
'GOOD: "Рост продаж". BAD: "Рост продаж (%)" or "Выручка (₽)".'),
|
|
254
|
+
data: zod_1.z
|
|
255
|
+
.array(zod_1.z.number())
|
|
256
|
+
.min(3)
|
|
257
|
+
.describe('Numeric values corresponding to categories. ' +
|
|
258
|
+
'MUST have EXACTLY the same number of values as categories — mismatch will break the chart. ' +
|
|
259
|
+
'Use round numbers or simple approximations. NEVER hallucinate precise figures. ' +
|
|
260
|
+
'Values should show meaningful variation — avoid all bars being the same height.'),
|
|
167
261
|
type: zod_1.z
|
|
168
262
|
.number()
|
|
169
263
|
.min(0)
|
|
170
264
|
.max(11)
|
|
171
|
-
.describe('
|
|
265
|
+
.describe('Color index from the theme palette. ALWAYS use 0 (primary blue). Never change this value.'),
|
|
172
266
|
}))
|
|
173
267
|
.min(1)
|
|
174
268
|
.max(1)
|
|
175
|
-
.describe('Data series
|
|
176
|
-
yAxisLabel: zod_1.z
|
|
177
|
-
|
|
269
|
+
.describe('Data series. Only ONE series is supported. Never add more than one.'),
|
|
270
|
+
yAxisLabel: zod_1.z
|
|
271
|
+
.string()
|
|
272
|
+
.max(30)
|
|
273
|
+
.optional()
|
|
274
|
+
.describe('Y-axis label. Include ONLY when the axis needs a descriptor that is not already covered by the unit field. ' +
|
|
275
|
+
'GOOD use: "Количество студентов" (when there is no unit symbol). ' +
|
|
276
|
+
'OMIT when unit is set (e.g., "%", "₽") — the unit already contextualises the values.'),
|
|
277
|
+
unit: zod_1.z
|
|
278
|
+
.string()
|
|
279
|
+
.max(10)
|
|
280
|
+
.optional()
|
|
281
|
+
.describe('Unit symbol displayed with each bar value (e.g., "%", "₽", "шт.", "млн"). ' +
|
|
282
|
+
'ALWAYS include when values represent percentages, currency, or any measurable quantity with a unit. ' +
|
|
283
|
+
'Omit only for dimensionless counts that are self-explanatory (e.g., raw ranking scores without a fixed scale).'),
|
|
178
284
|
version: zod_1.z.literal(1),
|
|
179
285
|
});
|
|
180
286
|
exports.ChartSlideDataSchema = zod_1.z.object({
|
|
181
287
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.CHART),
|
|
182
|
-
title: zod_1.z
|
|
183
|
-
|
|
288
|
+
title: zod_1.z
|
|
289
|
+
.string()
|
|
290
|
+
.describe('Chart name — 2–4 words rendered as large bold heading on the LEFT panel of the slide. ' +
|
|
291
|
+
'Keep short: the left panel is narrow and the title font is very large.')
|
|
292
|
+
.min(5)
|
|
293
|
+
.max(50),
|
|
294
|
+
description: zod_1.z
|
|
295
|
+
.string()
|
|
296
|
+
.describe('1–2 sentences (max 120 characters) explaining what the chart shows. ' +
|
|
297
|
+
'Rendered in small gray text below the title on the LEFT panel. No markdown.')
|
|
298
|
+
.min(10)
|
|
299
|
+
.max(150),
|
|
184
300
|
chart: zod_1.z.discriminatedUnion('type', [exports.BarChartSlideDataSchema]),
|
|
185
301
|
version: zod_1.z.literal(1),
|
|
186
302
|
});
|
|
187
303
|
exports.TimelineSlideDataSchema = zod_1.z.object({
|
|
188
304
|
contentType: zod_1.z.literal(enums_1.SLIDE_CONTENT_TYPE.TIMELINE),
|
|
189
|
-
title: zod_1.z
|
|
190
|
-
|
|
305
|
+
title: zod_1.z
|
|
306
|
+
.string()
|
|
307
|
+
.describe('Timeline name — 2–5 words, rendered as large bold heading above the timeline. ' +
|
|
308
|
+
'Names the subject or scope of the chronological sequence.')
|
|
309
|
+
.min(5)
|
|
310
|
+
.max(65),
|
|
311
|
+
description: zod_1.z
|
|
312
|
+
.string()
|
|
313
|
+
.describe('One sentence (max 100 characters) providing context for the timeline. ' +
|
|
314
|
+
'Rendered in small gray text below the title. No markdown.')
|
|
315
|
+
.min(10)
|
|
316
|
+
.max(120),
|
|
191
317
|
timeline: zod_1.z.object({
|
|
192
318
|
events: zod_1.z
|
|
193
319
|
.array(zod_1.z.object({
|
|
194
320
|
date: zod_1.z
|
|
195
321
|
.string()
|
|
196
|
-
.describe('
|
|
322
|
+
.describe('Temporal label displayed inside the arrow/chevron shape at the top of each column. ' +
|
|
323
|
+
'MUST be SHORT — max 20 characters — to fit inside the arrow. ' +
|
|
324
|
+
'Use a year ("2015"), a range ("2010–2015"), a quarter ("Q1 2023"), ' +
|
|
325
|
+
'an approximate period ("Early 2020s", "Середина 2010-х"), ' +
|
|
326
|
+
'or a phase label ("Этап 1", "Запуск") for process timelines. ' +
|
|
327
|
+
'NEVER fabricate specific dates you are not certain about.')
|
|
197
328
|
.min(2)
|
|
198
|
-
.max(
|
|
329
|
+
.max(25),
|
|
199
330
|
title: zod_1.z
|
|
200
331
|
.string()
|
|
201
|
-
.describe('Event
|
|
202
|
-
.
|
|
203
|
-
.
|
|
332
|
+
.describe('Event name in bold below the arrow. 2–3 words maximum. ' +
|
|
333
|
+
'Short and punchy — the column is narrow, long titles wrap to many lines. ' +
|
|
334
|
+
'GOOD: "Первый запуск", "Выход на рынок". BAD: "Успешный выход компании на международный рынок".')
|
|
335
|
+
.min(3)
|
|
336
|
+
.max(35),
|
|
204
337
|
description: zod_1.z
|
|
205
338
|
.string()
|
|
206
|
-
.describe('Brief description
|
|
339
|
+
.describe('Brief description below the event title. 1–2 sentences, max 100 characters. ' +
|
|
340
|
+
'The column is narrow — text wraps to ~5 lines at this limit. ' +
|
|
341
|
+
'Do NOT exceed 100 characters or the description will overflow off the slide.')
|
|
207
342
|
.min(20)
|
|
208
|
-
.max(
|
|
343
|
+
.max(110),
|
|
209
344
|
}))
|
|
210
|
-
.length(
|
|
211
|
-
.describe('
|
|
345
|
+
.length(5)
|
|
346
|
+
.describe('Exactly 5 chronological events in sequential order (oldest → newest). ' +
|
|
347
|
+
'The template renders exactly 5 equal columns — NEVER generate fewer or more.'),
|
|
212
348
|
}),
|
|
213
349
|
version: zod_1.z.literal(1),
|
|
214
350
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
import { ICommandResponseSchema } from '../../common';
|
|
3
|
-
import { PresentationSchema } from '../models';
|
|
3
|
+
import { PresentationSchema, PresentationTitlePageSchema } from '../models';
|
|
4
|
+
import { PRESENTATION_TARGET_AUDIENCE } from '../enums';
|
|
4
5
|
|
|
5
6
|
export namespace CreatePresentationCommand {
|
|
6
7
|
export const RequestSchema = z.object({
|
|
@@ -10,6 +11,8 @@ export namespace CreatePresentationCommand {
|
|
|
10
11
|
languageId: z.string(),
|
|
11
12
|
prompt: z.string(),
|
|
12
13
|
slideCount: z.number(),
|
|
14
|
+
titlePage: PresentationTitlePageSchema.optional().nullable(),
|
|
15
|
+
targetAudience: z.nativeEnum(PRESENTATION_TARGET_AUDIENCE).optional(),
|
|
13
16
|
});
|
|
14
17
|
export type Request = z.infer<typeof RequestSchema>;
|
|
15
18
|
|
|
@@ -4,6 +4,7 @@ import { ICommandResponseSchema } from '../../common';
|
|
|
4
4
|
export namespace GetPresentationSlidesGenerationPriceCommand {
|
|
5
5
|
export const RequestSchema = z.object({
|
|
6
6
|
slideCount: z.number().int().min(1),
|
|
7
|
+
templateId: z.string().uuid(),
|
|
7
8
|
});
|
|
8
9
|
export type Request = z.infer<typeof RequestSchema>;
|
|
9
10
|
|
|
@@ -8,3 +8,4 @@ export * from './slide-image-slot-action.enum';
|
|
|
8
8
|
export * from './presentation-ai-action-call-status.enum';
|
|
9
9
|
export * from './presentation-ai-action-type.enum';
|
|
10
10
|
export * from './presentation-ai-action-pricing-type.enum';
|
|
11
|
+
export * from './presentation-target-audience.enum';
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
|
|
3
|
+
export const PresentationTitlePageSchema = z.object({
|
|
4
|
+
author: z.string().optional().nullable(),
|
|
5
|
+
createdAt: z.date().optional().nullable(),
|
|
6
|
+
email: z.string().email().optional().nullable(),
|
|
7
|
+
});
|
|
8
|
+
|
|
9
|
+
export type PresentationTitlePage = z.infer<typeof PresentationTitlePageSchema>;
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
|
-
import { PRESENTATION_STAGE } from '../enums';
|
|
2
|
+
import { PRESENTATION_STAGE, PRESENTATION_TARGET_AUDIENCE } from '../enums';
|
|
3
3
|
import { SlideOutlineSchema } from './slide-outline.schema';
|
|
4
4
|
import { SlideSchema } from './slide.schema';
|
|
5
5
|
import { USER_REACTION } from '../../common';
|
|
6
|
+
import { PresentationTitlePageSchema } from './presentation-title-page.schema';
|
|
6
7
|
|
|
7
8
|
export const PresentationSchema = z.object({
|
|
8
9
|
uuid: z.string().uuid(),
|
|
@@ -22,6 +23,8 @@ export const PresentationSchema = z.object({
|
|
|
22
23
|
tokenReservationId: z.string().nullable().optional(),
|
|
23
24
|
lastContentUpdateAt: z.date().nullable(),
|
|
24
25
|
lastPptxExportedAt: z.date().nullable(),
|
|
26
|
+
titlePage: PresentationTitlePageSchema.nullable(),
|
|
27
|
+
targetAudience: z.nativeEnum(PRESENTATION_TARGET_AUDIENCE),
|
|
25
28
|
createdAt: z.date(),
|
|
26
29
|
updatedAt: z.date(),
|
|
27
30
|
});
|
|
@@ -36,5 +39,6 @@ export type PresentationWithSlides = z.infer<typeof PresentationWithSlidesSchema
|
|
|
36
39
|
export const PresentationUpdateSchema = PresentationSchema.pick({
|
|
37
40
|
title: true,
|
|
38
41
|
templateId: true,
|
|
42
|
+
titlePage: true,
|
|
39
43
|
}).partial();
|
|
40
44
|
export type PresentationUpdate = z.infer<typeof PresentationUpdateSchema>;
|
|
@@ -19,18 +19,24 @@ import {
|
|
|
19
19
|
export const CoverSlideDataUserEditSchema = z.object({
|
|
20
20
|
contentType: z.literal(SLIDE_CONTENT_TYPE.COVER),
|
|
21
21
|
title: z.string().min(1).max(500),
|
|
22
|
-
author: z
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
22
|
+
author: z
|
|
23
|
+
.object({
|
|
24
|
+
label: z.string().min(1).max(100),
|
|
25
|
+
value: z.string().min(1).max(200),
|
|
26
|
+
})
|
|
27
|
+
.optional(),
|
|
28
|
+
date: z
|
|
29
|
+
.object({
|
|
30
|
+
label: z.string().min(1).max(100),
|
|
31
|
+
value: z.string().min(1).max(200),
|
|
32
|
+
})
|
|
33
|
+
.optional(),
|
|
34
|
+
email: z
|
|
35
|
+
.object({
|
|
36
|
+
label: z.string().min(1).max(100),
|
|
37
|
+
value: z.string().min(1).max(200),
|
|
38
|
+
})
|
|
39
|
+
.optional(),
|
|
34
40
|
version: z.literal(1),
|
|
35
41
|
}) satisfies z.ZodType<ICoverSlideDataStructure>;
|
|
36
42
|
|
|
@@ -10,7 +10,19 @@ export const ImageSlotSchema = z.object({
|
|
|
10
10
|
.string()
|
|
11
11
|
.uuid()
|
|
12
12
|
.describe('Generate a valid uuid for image slot, that will be used for future lookups'),
|
|
13
|
-
prompt: z
|
|
13
|
+
prompt: z
|
|
14
|
+
.string()
|
|
15
|
+
.describe(
|
|
16
|
+
'Image generation prompt. MUST be written in ENGLISH regardless of the presentation language. ' +
|
|
17
|
+
'AI image generators excel at: atmospheric scenes, landscapes, cityscapes, architecture, nature, abstract light and texture, anonymous silhouettes, artistic photography. ' +
|
|
18
|
+
'AI fundamentally cannot render accurately: legible text on any surface, complex diagrams or flowcharts, data charts/graphs, specific product logos, clocks, precise mechanical parts. ' +
|
|
19
|
+
'Choose scene types from the first category. Avoid anything in the second. ' +
|
|
20
|
+
'Structure: [subject/scene] → [mood/atmosphere] → [lighting] → [visual style]. ' +
|
|
21
|
+
'Evoke the emotional register of the slide — do not illustrate the topic literally. ' +
|
|
22
|
+
'MODERATION: if the slide topic involves conflict, suffering, politics, or crime, redirect to abstract/atmospheric imagery (fog, ruins, empty landscapes) rather than depicting the subject directly — flagged prompts produce empty placeholders. ' +
|
|
23
|
+
'GOOD: "A lone figure on an observation deck at dusk gazing over an illuminated city. Cinematic wide-angle, golden-hour light, photorealistic." ' +
|
|
24
|
+
'BAD: "A bar chart showing quarterly growth. A robot at a laptop with code on the screen."',
|
|
25
|
+
),
|
|
14
26
|
});
|
|
15
27
|
export type ImageSlot = z.infer<typeof ImageSlotSchema>;
|
|
16
28
|
|
|
@@ -26,9 +38,9 @@ export type IconSlot = z.infer<typeof IconSlotSchema>;
|
|
|
26
38
|
export interface ICoverSlideDataStructure {
|
|
27
39
|
contentType: SLIDE_CONTENT_TYPE.COVER;
|
|
28
40
|
title: string;
|
|
29
|
-
author
|
|
30
|
-
date
|
|
31
|
-
email
|
|
41
|
+
author?: { label: string; value: string };
|
|
42
|
+
date?: { label: string; value: string };
|
|
43
|
+
email?: { label: string; value: string };
|
|
32
44
|
version: 1;
|
|
33
45
|
}
|
|
34
46
|
|
|
@@ -125,24 +137,28 @@ export interface ITimelineSlideDataStructure {
|
|
|
125
137
|
export const CoverSlideDataSchema = z.object({
|
|
126
138
|
contentType: z.literal(SLIDE_CONTENT_TYPE.COVER),
|
|
127
139
|
title: z.string().describe('Slide title in about 6 words').min(10).max(150),
|
|
128
|
-
author: z
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
.string()
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
date: z
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
140
|
+
author: z
|
|
141
|
+
.object({
|
|
142
|
+
label: z.string().describe('Literal "Author" in presentation\'s language'),
|
|
143
|
+
value: z.string().describe('Author value from titlePage if provided'),
|
|
144
|
+
})
|
|
145
|
+
.optional(),
|
|
146
|
+
date: z
|
|
147
|
+
.object({
|
|
148
|
+
label: z.string().describe('Literal "Date" in presentation\'s language'),
|
|
149
|
+
value: z
|
|
150
|
+
.string()
|
|
151
|
+
.describe(
|
|
152
|
+
'Date from titlePage in the "dd month yyyy" format in presentation\'s locale',
|
|
153
|
+
),
|
|
154
|
+
})
|
|
155
|
+
.optional(),
|
|
156
|
+
email: z
|
|
157
|
+
.object({
|
|
158
|
+
label: z.string().describe('Localized contact/email label'),
|
|
159
|
+
value: z.string().describe('Email value from titlePage if provided'),
|
|
160
|
+
})
|
|
161
|
+
.optional(),
|
|
146
162
|
version: z.literal(1),
|
|
147
163
|
}) satisfies z.ZodType<ICoverSlideDataStructure>;
|
|
148
164
|
export type CoverSlideData = z.infer<typeof CoverSlideDataSchema>;
|
|
@@ -176,19 +192,37 @@ export type ThankYouSlideData = z.infer<typeof ThankYouSlideDataSchema>;
|
|
|
176
192
|
|
|
177
193
|
export const StructuredListSlideDataSchema = z.object({
|
|
178
194
|
contentType: z.literal(SLIDE_CONTENT_TYPE.STRUCTURED_LIST),
|
|
179
|
-
title: z
|
|
180
|
-
|
|
195
|
+
title: z
|
|
196
|
+
.string()
|
|
197
|
+
.describe(
|
|
198
|
+
'Slide headline — 2–4 words naming the group. A noun phrase, NOT a full sentence. Displayed in very large font on the left panel.',
|
|
199
|
+
)
|
|
200
|
+
.min(5)
|
|
201
|
+
.max(40),
|
|
202
|
+
description: z
|
|
203
|
+
.string()
|
|
204
|
+
.describe(
|
|
205
|
+
'One framing sentence answering "What are these 4 things about?". Displayed in small text below the title on the left panel.',
|
|
206
|
+
)
|
|
207
|
+
.min(30)
|
|
208
|
+
.max(80),
|
|
181
209
|
list: z
|
|
182
210
|
.array(
|
|
183
211
|
z.object({
|
|
184
|
-
title: z
|
|
212
|
+
title: z
|
|
213
|
+
.string()
|
|
214
|
+
.describe(
|
|
215
|
+
'2–4 concrete words. A noun phrase or short verb phrase. All 4 titles MUST be grammatically parallel. Displayed in bold next to a large number (01–04).',
|
|
216
|
+
)
|
|
217
|
+
.min(3)
|
|
218
|
+
.max(30),
|
|
185
219
|
description: z
|
|
186
220
|
.string()
|
|
187
221
|
.describe(
|
|
188
|
-
|
|
222
|
+
'ONE complete sentence that expands on the title with a specific fact or benefit. NEVER just restate the title. NEVER cut short mid-word or mid-sentence. All 4 descriptions must be roughly equal in length.',
|
|
189
223
|
)
|
|
190
224
|
.min(50)
|
|
191
|
-
.max(
|
|
225
|
+
.max(100),
|
|
192
226
|
}),
|
|
193
227
|
)
|
|
194
228
|
.length(4),
|
|
@@ -198,14 +232,25 @@ export type StructuredListSlideData = z.infer<typeof StructuredListSlideDataSche
|
|
|
198
232
|
|
|
199
233
|
export const TextSlideDataSchema = z.object({
|
|
200
234
|
contentType: z.literal(SLIDE_CONTENT_TYPE.TEXT),
|
|
201
|
-
title: z
|
|
235
|
+
title: z
|
|
236
|
+
.string()
|
|
237
|
+
.describe(
|
|
238
|
+
'Slide headline rendered in very large bold font. Keep to 3–7 words (max 70 characters). It should name the topic or thesis — not summarise all content.',
|
|
239
|
+
)
|
|
240
|
+
.min(10)
|
|
241
|
+
.max(70),
|
|
202
242
|
description: z
|
|
203
243
|
.string()
|
|
204
244
|
.describe(
|
|
205
|
-
|
|
245
|
+
'Expository prose split into 2–3 paragraphs separated by \\n\\n (double newline). Total length 300–800 characters. ' +
|
|
246
|
+
'Use **bold** to highlight 1–3 key terms per paragraph (NOT entire sentences). ' +
|
|
247
|
+
'Use *italics* for definitions, counter-points, or light emphasis (1 per paragraph max). ' +
|
|
248
|
+
'NO bullet points, NO markdown headers, NO numbered lists. ' +
|
|
249
|
+
'Each paragraph covers ONE focused idea: e.g. context → main argument → implication. ' +
|
|
250
|
+
'Do NOT start consecutive paragraphs with the same word. Do NOT cut text short mid-sentence.',
|
|
206
251
|
)
|
|
207
252
|
.min(300)
|
|
208
|
-
.max(
|
|
253
|
+
.max(800),
|
|
209
254
|
version: z.literal(1),
|
|
210
255
|
}) satisfies z.ZodType<ITextSlideDataStructure>;
|
|
211
256
|
export type TextSlideData = z.infer<typeof TextSlideDataSchema>;
|
|
@@ -237,24 +282,53 @@ export type ContentsSlideData = z.infer<typeof ContentsSlideDataSchema>;
|
|
|
237
282
|
export const ImageSlideDataSchema = z
|
|
238
283
|
.object({
|
|
239
284
|
contentType: z.literal(SLIDE_CONTENT_TYPE.TEXT_WITH_IMAGE),
|
|
240
|
-
title: z
|
|
241
|
-
description: z
|
|
285
|
+
title: z
|
|
242
286
|
.string()
|
|
243
|
-
.describe(
|
|
287
|
+
.describe(
|
|
288
|
+
'Slide headline rendered in very large bold font on the LEFT column. Keep to 3–7 words (max 70 characters). Aim for under 50 characters to avoid overflow. A noun phrase or short declarative phrase — NOT a full sentence.',
|
|
289
|
+
)
|
|
244
290
|
.min(10)
|
|
291
|
+
.max(70),
|
|
292
|
+
description: z
|
|
293
|
+
.string()
|
|
294
|
+
.describe(
|
|
295
|
+
'Expository prose in 2 paragraphs separated by \\n\\n (double newline). Total length 150–500 characters. ' +
|
|
296
|
+
'Use **bold** for 1–2 key terms per paragraph (NOT entire sentences). ' +
|
|
297
|
+
'Use *italics* for definitions or emphasis at most once per paragraph. ' +
|
|
298
|
+
'NO bullet points, NO headers, NO numbered lists. ' +
|
|
299
|
+
'Each paragraph covers ONE focused idea. NEVER reference or describe the image in the text. ' +
|
|
300
|
+
'The image provides visual atmosphere — the text must stand alone as complete, readable prose.',
|
|
301
|
+
)
|
|
302
|
+
.min(150)
|
|
245
303
|
.max(500),
|
|
246
304
|
imageSlot: ImageSlotSchema,
|
|
247
305
|
version: z.literal(1),
|
|
248
306
|
})
|
|
249
307
|
.describe(
|
|
250
|
-
'Slide
|
|
308
|
+
'Slide with a large title and prose description on the left, and a full-bleed supporting image on the right.',
|
|
251
309
|
) satisfies z.ZodType<IImageSlideDataStructure>;
|
|
252
310
|
export type ImageSlideData = z.infer<typeof ImageSlideDataSchema>;
|
|
253
311
|
|
|
254
312
|
export const SectionBreakSlideDataSchema = z.object({
|
|
255
313
|
contentType: z.literal(SLIDE_CONTENT_TYPE.SECTION_BREAK),
|
|
256
|
-
title: z
|
|
257
|
-
|
|
314
|
+
title: z
|
|
315
|
+
.string()
|
|
316
|
+
.describe(
|
|
317
|
+
'The section name — a clean noun phrase of 3–6 words that names the thematic block which follows. ' +
|
|
318
|
+
'NEVER prefix with "Раздел:", "Section:", "Part:", "Глава:", or any structural label. ' +
|
|
319
|
+
'NEVER include numbers. Just the name itself. ' +
|
|
320
|
+
'GOOD: "Технологические достижения". BAD: "Раздел 2: Технологические достижения".',
|
|
321
|
+
)
|
|
322
|
+
.min(5)
|
|
323
|
+
.max(60),
|
|
324
|
+
description: z
|
|
325
|
+
.string()
|
|
326
|
+
.describe(
|
|
327
|
+
'One sentence (up to 100 characters) that briefly hints at the content of the upcoming section. ' +
|
|
328
|
+
'Should complement the title without repeating it. No markdown, no labels.',
|
|
329
|
+
)
|
|
330
|
+
.min(10)
|
|
331
|
+
.max(120),
|
|
258
332
|
version: z.literal(1),
|
|
259
333
|
}) satisfies z.ZodType<ISectionBreakSlideDataStructure>;
|
|
260
334
|
export type SectionBreakSlideData = z.infer<typeof SectionBreakSlideDataSchema>;
|
|
@@ -263,25 +337,73 @@ export const TableSlideDataSchema = z.object({
|
|
|
263
337
|
contentType: z.literal(SLIDE_CONTENT_TYPE.TABLE),
|
|
264
338
|
title: z
|
|
265
339
|
.string()
|
|
266
|
-
.describe(
|
|
340
|
+
.describe(
|
|
341
|
+
'Table name — 2–4 words rendered as large bold heading above the table. ' +
|
|
342
|
+
'Doubles as both the slide title and the table heading. Keep concise.',
|
|
343
|
+
)
|
|
344
|
+
.min(5)
|
|
345
|
+
.max(55),
|
|
346
|
+
description: z
|
|
347
|
+
.string()
|
|
348
|
+
.describe(
|
|
349
|
+
'One short sentence (max 80 characters) describing what the table shows. ' +
|
|
350
|
+
'Rendered in small gray text below the title. No markdown.',
|
|
351
|
+
)
|
|
267
352
|
.min(10)
|
|
268
|
-
.max(
|
|
269
|
-
description: z.string().describe('Description of the table represents').min(10).max(200),
|
|
353
|
+
.max(100),
|
|
270
354
|
table: z.object({
|
|
271
355
|
columnHeaders: z
|
|
272
|
-
.array(
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
356
|
+
.array(
|
|
357
|
+
z
|
|
358
|
+
.string()
|
|
359
|
+
.min(1)
|
|
360
|
+
.max(20)
|
|
361
|
+
.describe(
|
|
362
|
+
'Column label. Keep SHORT — 1–3 words. Include units here (e.g., "Сумма, ₽"), not in cells. ' +
|
|
363
|
+
'When hasRowHeaders is true, the first header should be a single space " " or a short category label.',
|
|
364
|
+
),
|
|
365
|
+
)
|
|
366
|
+
.min(2)
|
|
367
|
+
.max(5)
|
|
368
|
+
.describe(
|
|
369
|
+
'Column header labels. MAXIMUM 5 columns total. Recommended 3–4 data columns. ' +
|
|
370
|
+
'More columns will overflow the slide — NEVER exceed 5.',
|
|
371
|
+
),
|
|
276
372
|
rows: z
|
|
277
|
-
.array(
|
|
278
|
-
|
|
373
|
+
.array(
|
|
374
|
+
z
|
|
375
|
+
.array(
|
|
376
|
+
z
|
|
377
|
+
.string()
|
|
378
|
+
.min(1)
|
|
379
|
+
.max(40)
|
|
380
|
+
.describe(
|
|
381
|
+
'Cell content. NUMERIC tables: numbers only (e.g., "1 200", "85%"). ' +
|
|
382
|
+
'TEXTUAL tables: 1–3 words maximum — keywords or short phrases ONLY, NEVER full sentences. ' +
|
|
383
|
+
'Row header cells (first cell when hasRowHeaders=true): category label, max 22 characters.',
|
|
384
|
+
),
|
|
385
|
+
)
|
|
386
|
+
.describe('One row. Cell count MUST equal columnHeaders length exactly.'),
|
|
387
|
+
)
|
|
388
|
+
.min(2)
|
|
279
389
|
.max(4)
|
|
280
390
|
.describe(
|
|
281
|
-
'Table rows
|
|
391
|
+
'Table rows. Max 4 rows total. ' +
|
|
392
|
+
'When hasSummaryRow is true, the LAST row is the summary row — so at most 3 regular rows + 1 summary = 4 total. ' +
|
|
393
|
+
'NEVER exceed 4 rows.',
|
|
394
|
+
),
|
|
395
|
+
hasRowHeaders: z
|
|
396
|
+
.boolean()
|
|
397
|
+
.describe(
|
|
398
|
+
'True when the first cell of each row is a descriptive label or category (pivot table). ' +
|
|
399
|
+
'False for plain data tables where all cells are equivalent data.',
|
|
400
|
+
),
|
|
401
|
+
hasSummaryRow: z
|
|
402
|
+
.boolean()
|
|
403
|
+
.describe(
|
|
404
|
+
'True when the last row contains totals, averages, or aggregated values. ' +
|
|
405
|
+
'That summary row must be the last element of the rows array.',
|
|
282
406
|
),
|
|
283
|
-
hasRowHeaders: z.boolean().describe('If table needs special row headers, set this to true'),
|
|
284
|
-
hasSummaryRow: z.boolean().describe('If table needs a summary row, set this to true'),
|
|
285
407
|
}),
|
|
286
408
|
version: z.literal(1),
|
|
287
409
|
}) satisfies z.ZodType<ITableSlideDataStructure>;
|
|
@@ -291,37 +413,85 @@ export type TableSlideData = z.infer<typeof TableSlideDataSchema>;
|
|
|
291
413
|
export const BarChartSlideDataSchema = z.object({
|
|
292
414
|
type: z.literal(SLIDE_CHART_TYPE.BAR),
|
|
293
415
|
categories: z
|
|
294
|
-
.array(z.string())
|
|
295
|
-
.min(
|
|
296
|
-
.max(
|
|
297
|
-
.describe(
|
|
416
|
+
.array(z.string().min(1).max(20))
|
|
417
|
+
.min(3)
|
|
418
|
+
.max(10)
|
|
419
|
+
.describe(
|
|
420
|
+
'Category labels (e.g., months, product names, departments). ' +
|
|
421
|
+
'Recommended: 4–8 items. Keep each label SHORT — 1–3 words, max 15 characters. ' +
|
|
422
|
+
'Categories work best when naturally ordered: time periods, rankings, or comparable groups.',
|
|
423
|
+
),
|
|
298
424
|
series: z
|
|
299
425
|
.array(
|
|
300
426
|
z.object({
|
|
301
427
|
name: z
|
|
302
428
|
.string()
|
|
303
|
-
.
|
|
304
|
-
|
|
429
|
+
.max(40)
|
|
430
|
+
.describe(
|
|
431
|
+
'Series name shown in the chart legend. Do NOT include units here — units belong in the unit field. ' +
|
|
432
|
+
'GOOD: "Рост продаж". BAD: "Рост продаж (%)" or "Выручка (₽)".',
|
|
433
|
+
),
|
|
434
|
+
data: z
|
|
435
|
+
.array(z.number())
|
|
436
|
+
.min(3)
|
|
437
|
+
.describe(
|
|
438
|
+
'Numeric values corresponding to categories. ' +
|
|
439
|
+
'MUST have EXACTLY the same number of values as categories — mismatch will break the chart. ' +
|
|
440
|
+
'Use round numbers or simple approximations. NEVER hallucinate precise figures. ' +
|
|
441
|
+
'Values should show meaningful variation — avoid all bars being the same height.',
|
|
442
|
+
),
|
|
305
443
|
type: z
|
|
306
444
|
.number()
|
|
307
445
|
.min(0)
|
|
308
446
|
.max(11)
|
|
309
|
-
.describe(
|
|
447
|
+
.describe(
|
|
448
|
+
'Color index from the theme palette. ALWAYS use 0 (primary blue). Never change this value.',
|
|
449
|
+
),
|
|
310
450
|
}),
|
|
311
451
|
)
|
|
312
452
|
.min(1)
|
|
313
453
|
.max(1)
|
|
314
|
-
.describe('Data series
|
|
315
|
-
yAxisLabel: z
|
|
316
|
-
|
|
454
|
+
.describe('Data series. Only ONE series is supported. Never add more than one.'),
|
|
455
|
+
yAxisLabel: z
|
|
456
|
+
.string()
|
|
457
|
+
.max(30)
|
|
458
|
+
.optional()
|
|
459
|
+
.describe(
|
|
460
|
+
'Y-axis label. Include ONLY when the axis needs a descriptor that is not already covered by the unit field. ' +
|
|
461
|
+
'GOOD use: "Количество студентов" (when there is no unit symbol). ' +
|
|
462
|
+
'OMIT when unit is set (e.g., "%", "₽") — the unit already contextualises the values.',
|
|
463
|
+
),
|
|
464
|
+
unit: z
|
|
465
|
+
.string()
|
|
466
|
+
.max(10)
|
|
467
|
+
.optional()
|
|
468
|
+
.describe(
|
|
469
|
+
'Unit symbol displayed with each bar value (e.g., "%", "₽", "шт.", "млн"). ' +
|
|
470
|
+
'ALWAYS include when values represent percentages, currency, or any measurable quantity with a unit. ' +
|
|
471
|
+
'Omit only for dimensionless counts that are self-explanatory (e.g., raw ranking scores without a fixed scale).',
|
|
472
|
+
),
|
|
317
473
|
version: z.literal(1),
|
|
318
474
|
}) satisfies z.ZodType<IBarChartSlideDataStructure>;
|
|
319
475
|
export type BarChartSlideData = z.infer<typeof BarChartSlideDataSchema>;
|
|
320
476
|
|
|
321
477
|
export const ChartSlideDataSchema = z.object({
|
|
322
478
|
contentType: z.literal(SLIDE_CONTENT_TYPE.CHART),
|
|
323
|
-
title: z
|
|
324
|
-
|
|
479
|
+
title: z
|
|
480
|
+
.string()
|
|
481
|
+
.describe(
|
|
482
|
+
'Chart name — 2–4 words rendered as large bold heading on the LEFT panel of the slide. ' +
|
|
483
|
+
'Keep short: the left panel is narrow and the title font is very large.',
|
|
484
|
+
)
|
|
485
|
+
.min(5)
|
|
486
|
+
.max(50),
|
|
487
|
+
description: z
|
|
488
|
+
.string()
|
|
489
|
+
.describe(
|
|
490
|
+
'1–2 sentences (max 120 characters) explaining what the chart shows. ' +
|
|
491
|
+
'Rendered in small gray text below the title on the LEFT panel. No markdown.',
|
|
492
|
+
)
|
|
493
|
+
.min(10)
|
|
494
|
+
.max(150),
|
|
325
495
|
chart: z.discriminatedUnion('type', [BarChartSlideDataSchema]),
|
|
326
496
|
version: z.literal(1),
|
|
327
497
|
}) satisfies z.ZodType<IChartSlideDataStructure>;
|
|
@@ -329,8 +499,22 @@ export type ChartSlideData = z.infer<typeof ChartSlideDataSchema>;
|
|
|
329
499
|
|
|
330
500
|
export const TimelineSlideDataSchema = z.object({
|
|
331
501
|
contentType: z.literal(SLIDE_CONTENT_TYPE.TIMELINE),
|
|
332
|
-
title: z
|
|
333
|
-
|
|
502
|
+
title: z
|
|
503
|
+
.string()
|
|
504
|
+
.describe(
|
|
505
|
+
'Timeline name — 2–5 words, rendered as large bold heading above the timeline. ' +
|
|
506
|
+
'Names the subject or scope of the chronological sequence.',
|
|
507
|
+
)
|
|
508
|
+
.min(5)
|
|
509
|
+
.max(65),
|
|
510
|
+
description: z
|
|
511
|
+
.string()
|
|
512
|
+
.describe(
|
|
513
|
+
'One sentence (max 100 characters) providing context for the timeline. ' +
|
|
514
|
+
'Rendered in small gray text below the title. No markdown.',
|
|
515
|
+
)
|
|
516
|
+
.min(10)
|
|
517
|
+
.max(120),
|
|
334
518
|
timeline: z.object({
|
|
335
519
|
events: z
|
|
336
520
|
.array(
|
|
@@ -338,26 +522,40 @@ export const TimelineSlideDataSchema = z.object({
|
|
|
338
522
|
date: z
|
|
339
523
|
.string()
|
|
340
524
|
.describe(
|
|
341
|
-
'
|
|
525
|
+
'Temporal label displayed inside the arrow/chevron shape at the top of each column. ' +
|
|
526
|
+
'MUST be SHORT — max 20 characters — to fit inside the arrow. ' +
|
|
527
|
+
'Use a year ("2015"), a range ("2010–2015"), a quarter ("Q1 2023"), ' +
|
|
528
|
+
'an approximate period ("Early 2020s", "Середина 2010-х"), ' +
|
|
529
|
+
'or a phase label ("Этап 1", "Запуск") for process timelines. ' +
|
|
530
|
+
'NEVER fabricate specific dates you are not certain about.',
|
|
342
531
|
)
|
|
343
532
|
.min(2)
|
|
344
|
-
.max(
|
|
533
|
+
.max(25),
|
|
345
534
|
title: z
|
|
346
535
|
.string()
|
|
347
536
|
.describe(
|
|
348
|
-
'Event
|
|
537
|
+
'Event name in bold below the arrow. 2–3 words maximum. ' +
|
|
538
|
+
'Short and punchy — the column is narrow, long titles wrap to many lines. ' +
|
|
539
|
+
'GOOD: "Первый запуск", "Выход на рынок". BAD: "Успешный выход компании на международный рынок".',
|
|
349
540
|
)
|
|
350
|
-
.min(
|
|
351
|
-
.max(
|
|
541
|
+
.min(3)
|
|
542
|
+
.max(35),
|
|
352
543
|
description: z
|
|
353
544
|
.string()
|
|
354
|
-
.describe(
|
|
545
|
+
.describe(
|
|
546
|
+
'Brief description below the event title. 1–2 sentences, max 100 characters. ' +
|
|
547
|
+
'The column is narrow — text wraps to ~5 lines at this limit. ' +
|
|
548
|
+
'Do NOT exceed 100 characters or the description will overflow off the slide.',
|
|
549
|
+
)
|
|
355
550
|
.min(20)
|
|
356
|
-
.max(
|
|
551
|
+
.max(110),
|
|
357
552
|
}),
|
|
358
553
|
)
|
|
359
|
-
.length(
|
|
360
|
-
.describe(
|
|
554
|
+
.length(5)
|
|
555
|
+
.describe(
|
|
556
|
+
'Exactly 5 chronological events in sequential order (oldest → newest). ' +
|
|
557
|
+
'The template renders exactly 5 equal columns — NEVER generate fewer or more.',
|
|
558
|
+
),
|
|
361
559
|
}),
|
|
362
560
|
version: z.literal(1),
|
|
363
561
|
}) satisfies z.ZodType<ITimelineSlideDataStructure>;
|