@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.
- package/gen-backend/dist/generator/fake-content-generator.ts/create-database-with-fake-content.js +16 -11
- package/gen-backend/dist/generator/fake-content-generator.ts/generate-fake-content.js +18 -4
- package/gen-backend/dist/generator/fake-content-generator.ts/invoke-generate-fake-content.js +11 -3
- package/gen-backend/dist/generator/llm-queries/invoke-update-site-schema.js +11 -1
- package/gen-backend/prompts/{generate-fake-content-multiple.md → generate-fake-content-multiple-documents.md} +3 -3
- package/gen-backend/prompts/generate-fake-content-multiple-parts.md +22 -0
- package/gen-backend/prompts/new-site-1-analysis.md +10 -18
- package/gen-backend/prompts/update-site-schema-1-write-details.md +1 -1
- package/gen-front/dist/gen-front.css +1 -1
- package/package.json +2 -2
package/gen-backend/dist/generator/fake-content-generator.ts/create-database-with-fake-content.js
CHANGED
|
@@ -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
|
-
|
|
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
|
-
|
|
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") {
|
package/gen-backend/dist/generator/fake-content-generator.ts/invoke-generate-fake-content.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
-
|
|
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
|
-
-
|
|
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
|
-
* `
|
|
86
|
-
* `
|
|
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
|
|
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
|
-
* `
|
|
98
|
-
* `
|
|
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
|
|
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
|
|