@paroicms/site-generator-plugin 0.5.1 → 0.6.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.
@@ -33,6 +33,16 @@ function fillRoutingDocumentAndAddChildren(ctx, tasks, siteOptions, nodeOptions)
33
33
  const { routingIds, nodeType } = nodeOptions;
34
34
  const { siteSchema } = siteOptions;
35
35
  tasks.add(() => updateRoutingDocument(ctx, siteOptions, nodeOptions));
36
+ for (const listType of nodeType.lists ?? []) {
37
+ for (const typeName of listType.parts) {
38
+ const partType = getPartTypeByName(siteSchema, typeName);
39
+ tasks.add(() => addParts(ctx, siteOptions, {
40
+ parentNodeId: routingIds.nodeId,
41
+ nodeType: partType,
42
+ documentType: nodeType,
43
+ }));
44
+ }
45
+ }
36
46
  for (const typeName of nodeType.routingChildren ?? []) {
37
47
  const childType = getRoutingDocumentTypeByName(siteSchema, typeName);
38
48
  const childIds = routingIds.children?.[typeName];
@@ -48,17 +58,9 @@ function fillRoutingDocumentAndAddChildren(ctx, tasks, siteOptions, nodeOptions)
48
58
  tasks.add(() => addRegularDocuments(ctx, siteOptions, {
49
59
  parentNodeId: routingIds.nodeId,
50
60
  nodeType: childType,
61
+ documentType: childType,
51
62
  }));
52
63
  }
53
- for (const listType of nodeType.lists ?? []) {
54
- for (const typeName of listType.parts) {
55
- const childType = getPartTypeByName(siteSchema, typeName);
56
- tasks.add(() => addParts(ctx, siteOptions, {
57
- parentNodeId: routingIds.nodeId,
58
- nodeType: childType,
59
- }));
60
- }
61
- }
62
64
  }
63
65
  async function updateSiteFields(ctx, options) {
64
66
  const { service, logger } = ctx;
@@ -127,6 +129,7 @@ async function updateRoutingDocument(ctx, siteOptions, nodeOptions) {
127
129
  const { fqdn, siteSchema, schemaI18n } = siteOptions;
128
130
  const content = await generateFieldSetContent(ctx, {
129
131
  nodeType,
132
+ documentType: nodeType,
130
133
  siteSchema,
131
134
  schemaI18n,
132
135
  withTitle: false,
@@ -139,7 +142,7 @@ async function updateRoutingDocument(ctx, siteOptions, nodeOptions) {
139
142
  }
140
143
  async function addRegularDocuments(ctx, siteOptions, nodeOptions) {
141
144
  ctx.logger.debug(`[TASK] Adding regular documents "${nodeOptions.nodeType.typeName}"…`);
142
- const { parentNodeId, nodeType } = nodeOptions;
145
+ const { parentNodeId, nodeType, documentType } = nodeOptions;
143
146
  const { fqdn, siteSchema, schemaI18n } = siteOptions;
144
147
  const tolerateErrors = {
145
148
  errorMessages: [],
@@ -147,6 +150,7 @@ async function addRegularDocuments(ctx, siteOptions, nodeOptions) {
147
150
  const list = await generateMultipleFieldSetContents(ctx, {
148
151
  siteSchema,
149
152
  nodeType,
153
+ documentType,
150
154
  schemaI18n,
151
155
  count: getDefaultNodeContentCount(nodeType),
152
156
  withTitle: true,
@@ -163,7 +167,7 @@ async function addRegularDocuments(ctx, siteOptions, nodeOptions) {
163
167
  }
164
168
  async function addParts(ctx, siteOptions, nodeOptions) {
165
169
  ctx.logger.debug(`[TASK] Adding parts "${nodeOptions.nodeType.typeName}"…`);
166
- const { parentNodeId, nodeType } = nodeOptions;
170
+ const { parentNodeId, nodeType, documentType } = nodeOptions;
167
171
  const { fqdn, siteSchema, schemaI18n } = siteOptions;
168
172
  const tolerateErrors = {
169
173
  errorMessages: [],
@@ -171,6 +175,7 @@ async function addParts(ctx, siteOptions, nodeOptions) {
171
175
  const list = await generateMultipleFieldSetContents(ctx, {
172
176
  siteSchema,
173
177
  nodeType,
178
+ documentType,
174
179
  schemaI18n,
175
180
  count: getDefaultNodeContentCount(nodeType),
176
181
  withTitle: true,
@@ -11,10 +11,12 @@ export async function generateFieldSetContent(ctx, options) {
11
11
  return list[0];
12
12
  }
13
13
  export async function generateMultipleFieldSetContents(ctx, options) {
14
- const { siteSchema, nodeType, schemaI18n, count, withTitle, tolerateErrors, debugName } = options;
14
+ const { siteSchema, nodeType, documentType, schemaI18n, count, withTitle, tolerateErrors, debugName, } = options;
15
15
  if (nodeType.kind === "site")
16
16
  throw new Error("Cannot generate content for site node type");
17
- const outputTags = withTitle
17
+ // for a document, the LLM is best at generating the title, so we ask for it and remove it later
18
+ const skipTitle = nodeType.kind === "document" && !withTitle;
19
+ const outputTags = withTitle || skipTitle
18
20
  ? [{ tagName: "title", key: "title", format: "text", tagDescription: "Write the title here" }]
19
21
  : [];
20
22
  if (nodeType.fields) {
@@ -29,20 +31,32 @@ export async function generateMultipleFieldSetContents(ctx, options) {
29
31
  defaultValue: "",
30
32
  defaultLanguage,
31
33
  });
34
+ const documentDescription = translateText(schemaI18n, `nodeTypes.${documentType.typeName}.description`, {
35
+ defaultValue: "",
36
+ defaultLanguage,
37
+ });
32
38
  const siteTheme = translateText(schemaI18n, "siteTheme", {
33
39
  defaultValue: "",
34
40
  defaultLanguage,
35
41
  });
36
42
  const language = defaultLanguage ?? "en";
37
- const generatedContents = outputTags.length > 0
43
+ let generatedContents = outputTags.length > 0
38
44
  ? await invokeGenerateFakeContent(ctx, {
39
45
  count,
46
+ typeKind: nodeType.kind,
40
47
  typeLabel,
41
48
  typeDescription,
49
+ documentDescription,
42
50
  siteTheme,
43
51
  language,
44
52
  }, outputTags, { tolerateErrors, debugName })
45
53
  : undefined;
54
+ if (skipTitle && generatedContents) {
55
+ generatedContents = generatedContents.map((content) => {
56
+ const { title, ...rest } = content;
57
+ return rest;
58
+ });
59
+ }
46
60
  return createNodeContents({
47
61
  nodeType,
48
62
  count,
@@ -81,7 +95,7 @@ function toFakeContentOutputTag(fieldNameOrType) {
81
95
  tagName: `${camelToKebabCase(key)}-md`,
82
96
  key,
83
97
  format: "markdown",
84
- tagDescription: "Write document content here (150-200 words) in markdown format",
98
+ tagDescription: "Write document content here (150-200 words) in markdown format. It MUST NOT include the title.",
85
99
  };
86
100
  }
87
101
  if (key === "introduction") {
@@ -4,9 +4,10 @@ import { readPromptFile } from "../lib/create-prompt.js";
4
4
  import { debugBatchLlmOutputs } from "../lib/debug-utils.js";
5
5
  import { parseLlmResponseAsList } from "../lib/parse-llm-response.js";
6
6
  const singlePromptTpl = PromptTemplate.fromTemplate(await readPromptFile("generate-fake-content-single.md"));
7
- const multiplePromptTpl = PromptTemplate.fromTemplate(await readPromptFile("generate-fake-content-multiple.md"));
7
+ const multipleDocumentsPromptTpl = PromptTemplate.fromTemplate(await readPromptFile("generate-fake-content-multiple-documents.md"));
8
+ const multiplePartsPromptTpl = PromptTemplate.fromTemplate(await readPromptFile("generate-fake-content-multiple-parts.md"));
8
9
  export async function invokeGenerateFakeContent(ctx, input, outputTags, options) {
9
- const { language } = input;
10
+ const { language, typeKind } = input;
10
11
  const single = input.count === 1;
11
12
  const debugName = `fake-content-${options.debugName}${single ? "" : `-${input.count}`}`;
12
13
  const tagAndDescriptions = outputTags
@@ -26,6 +27,9 @@ export async function invokeGenerateFakeContent(ctx, input, outputTags, options)
26
27
  siteTheme: input.siteTheme,
27
28
  language: languageLabelIn(language, "en"),
28
29
  };
30
+ if (typeKind === "part") {
31
+ llmInput.documentDescription = input.documentDescription;
32
+ }
29
33
  if (!single) {
30
34
  llmInput.count = `${end - startIndex}`;
31
35
  }
@@ -35,7 +39,11 @@ export async function invokeGenerateFakeContent(ctx, input, outputTags, options)
35
39
  const debug = await debugBatchLlmOutputs(ctx, debugName, ctx.cheapModelName, batchInputs);
36
40
  let contents = debug.storedContents;
37
41
  if (!contents) {
38
- const llmMessages = await (single ? singlePromptTpl : multiplePromptTpl)
42
+ const llmMessages = await (single
43
+ ? singlePromptTpl
44
+ : typeKind === "document"
45
+ ? multipleDocumentsPromptTpl
46
+ : multiplePartsPromptTpl)
39
47
  .pipe(ctx.cheapModel)
40
48
  .batch(batchInputs);
41
49
  contents = await debug.getMessageContents(llmMessages);
@@ -97,10 +97,20 @@ async function invokeUpdateSiteSchemaStep2(ctx, input) {
97
97
  ...input.generatedSchema,
98
98
  };
99
99
  if (parsed.siteSchema) {
100
- result.siteSchema = parsed.siteSchema;
100
+ result.siteSchema = fixSiteSchema(parsed.siteSchema);
101
101
  }
102
102
  if (parsed.l10n) {
103
103
  result.l10n = parsed.l10n;
104
104
  }
105
105
  return result;
106
106
  }
107
+ function fixSiteSchema(siteSchema) {
108
+ for (const nodeType of siteSchema.nodeTypes ?? []) {
109
+ for (const field of nodeType.fields ?? []) {
110
+ if (typeof field !== "string" && field.dataType === "quillDelta") {
111
+ field.plugin = "@paroicms/quill-editor-plugin";
112
+ }
113
+ }
114
+ }
115
+ return siteSchema;
116
+ }
@@ -1,4 +1,4 @@
1
- Generate the text content of **{count}** different web pages.
1
+ Generate the text content of **{count}** different **web pages**.
2
2
 
3
3
  All the produced texts must be in **{language}**.
4
4
 
@@ -14,9 +14,9 @@ Make sure web pages are distinct from each other by:
14
14
 
15
15
  Guidelines:
16
16
 
17
+ - NEVER repeat the same title among several sub-contents.
17
18
  - Never invite the user to write a comment. There is no comment system.
18
- - Do not repeat the title in markdown content.
19
19
 
20
- For each web page, use the following exact format:
20
+ Each web page is composed by several sub-contents. Use the following exact format:
21
21
 
22
22
  {tagAndDescriptions}
@@ -0,0 +1,22 @@
1
+ Generate the text content of **{count}** different **sections** of a web page.
2
+
3
+ All the produced texts must be in **{language}**.
4
+
5
+ The sections in question are of type: **{typeLabel}** ({typeDescription}).
6
+
7
+ For the context, the website's theme is: "{siteTheme}", and the web page is about "{documentDescription}".
8
+
9
+ Make sure sections are distinct from each other by:
10
+
11
+ - Cover different aspects in line with the type of sections;
12
+ - Using varied writing styles;
13
+ - Having different lengths within the specified range.
14
+
15
+ Guidelines:
16
+
17
+ - NEVER repeat a title among several sub-contents.
18
+ - Never invite the user to write a comment. There is no comment system.
19
+
20
+ Each section is composed by several sub-contents. Use the following exact format:
21
+
22
+ {tagAndDescriptions}
@@ -1,4 +1,4 @@
1
- You will be given a description of a website's structure. Your task is to generate three things:
1
+ You will be given a description of a website's structure. Your task is to **analyze** the website description, then you will generate three things:
2
2
 
3
3
  1. A YAML for website properties.
4
4
  2. A Markdown bulleted list that represents the hierarchy of node types (routing documents, regular documents and parts) within the site.
@@ -55,10 +55,10 @@ Guidelines for creating the hierarchical bullet list:
55
55
  - Write `"list of"`, and then the **type name** within backquotes.
56
56
  - Append `(parts)`.
57
57
  - Add a coma, then write: `"list name:"` and append an identifier for the list name.
58
- - Each distinct node type must have a unique name through the whole tree structure.
59
- - Reusing the same node type several times (for recursivity etc.):
60
- - When the same node type is reused as a child in several places, then write its children only on the first occurence.
58
+ - Avoid recursivity. But if you can't avoid reusing a node type, then write its children only on the first occurence.
61
59
  - On this task, do not focus on fields. If the website description provide fields then you will report them in the unused information. In particular, a collection of medias (a carousel, a slider, an image gallery, a slideshow, etc.) is a type of field.
60
+ - Don't try to provide a comment mechanism when the user requests a blog. Blog comments do not belong to the hierarchy of node types.
61
+ - NEVER ever reuse the same type name for 2 distinct node type. Pay particular attention to words spelled identically in the singular and plural. Each distinct node type must have a unique name through the whole tree structure.
62
62
 
63
63
  Here's an example of a correct output:
64
64
 
@@ -82,27 +82,18 @@ Here is another incorrect example:
82
82
 
83
83
  <incorrect_example>
84
84
  * `home` (routing document)
85
- * `animals`
86
- * `pages` (regular document)
87
- * list of `page` (regular documents)
88
- * `vegetals`
89
- * `pages` (regular document)
90
- * list of `page` (regular documents)
85
+ * `species` (routing document)
86
+ * list of `species` (regular documents)
91
87
  </incorrect_example>
92
88
 
93
- This incorrect example fails because the children of `pages` node should not be written the second time we use this node type. Here is how to fix that:
89
+ This incorrect example fails because the type name `species` is used for 2 different types. You can distinguish them by suffixing both the collection and the item types:
94
90
 
95
91
  <correct_example>
96
92
  * `home` (routing document)
97
- * `animals`
98
- * `pages` (regular document)
99
- * list of `page` (regular documents)
100
- * `vegetals`
101
- * `pages` (regular document)
93
+ * `speciesColl` (routing document)
94
+ * list of `speciesItem` (regular documents)
102
95
  </correct_example>
103
96
 
104
- Notice: the `pages` node will have the same child types for both usage. But we describe them only the first time it appears on the tree.
105
-
106
97
  Here's an example of correct output using parts, and with the default contact and search pages:
107
98
 
108
99
  <correct_example>
@@ -125,6 +116,7 @@ Guidelines for creating the dictionnary YAML:
125
116
 
126
117
  - Use a YAML syntax: pay attention to the indentation.
127
118
  - Keys: each key is the name of a node type or the name of a list of parts.
119
+ - If the same type is reused several times, then write only one entry in this dictionnary.
128
120
  - Values contains the properties. For a node type, provide the following properties:
129
121
  - confidence: Your confidence level for the accuracy of this node type (0.0-1.0).
130
122
  - kind: Can be `routingDocument`, `regularDocument`, `part`.
@@ -1,4 +1,4 @@
1
- You are tasked with modifying a JSON object of a _site schema_, based on a given TypeScript type definition and an update message, and its localized labels. Follow these steps carefully:
1
+ You are tasked to plan how modifying a JSON object of a _site schema_, based on a given TypeScript type definition and an update message, and its localized labels. Follow these steps carefully:
2
2
 
3
3
  # 1. Review the TypeScript type definition of the JSON structure:
4
4