@paroicms/site-generator-plugin 0.5.0 → 0.5.2
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 +2 -1
- package/gen-backend/prompts/update-site-schema-1-write-details.md +1 -1
- package/gen-backend/prompts/update-site-schema-2-execute.md +23 -4
- package/gen-front/dist/gen-front.css +1 -1
- package/gen-front/dist/gen-front.mjs +96 -94
- package/package.json +1 -1
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 a 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.
|
|
@@ -59,6 +59,7 @@ Guidelines for creating the hierarchical bullet list:
|
|
|
59
59
|
- Reusing the same node type several times (for recursivity etc.):
|
|
60
60
|
- When the same node type is reused as a child in several places, then write its children only on the first occurence.
|
|
61
61
|
- 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.
|
|
62
|
+
- 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.
|
|
62
63
|
|
|
63
64
|
Here's an example of a correct output:
|
|
64
65
|
|
|
@@ -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
|
|
|
@@ -20,7 +20,7 @@ Here is an example of an object for describing a custom **HTML** field type:
|
|
|
20
20
|
|
|
21
21
|
<field_type_example>
|
|
22
22
|
{{
|
|
23
|
-
"name": "
|
|
23
|
+
"name": "myCustomField",
|
|
24
24
|
"localized": true,
|
|
25
25
|
"storedAs": "text",
|
|
26
26
|
"dataType": "quillDelta",
|
|
@@ -35,11 +35,11 @@ Then, in the locales, the translations of custom field types must be in a sub-ke
|
|
|
35
35
|
{{
|
|
36
36
|
"nodeTypes": {{
|
|
37
37
|
...
|
|
38
|
-
"
|
|
38
|
+
"myNodeTypeName": {{
|
|
39
39
|
...
|
|
40
40
|
"fields": {{
|
|
41
|
-
"
|
|
42
|
-
"label": "My
|
|
41
|
+
"myCustomField": {{
|
|
42
|
+
"label": "My custom field",
|
|
43
43
|
"description": "This is a description that will be displayed in a tooltip of the back-office"
|
|
44
44
|
}}
|
|
45
45
|
}}
|
|
@@ -48,10 +48,29 @@ Then, in the locales, the translations of custom field types must be in a sub-ke
|
|
|
48
48
|
}}
|
|
49
49
|
</l10n_example>
|
|
50
50
|
|
|
51
|
+
Here is how to write field locales for a custom site field:
|
|
52
|
+
|
|
53
|
+
<l10n_example>
|
|
54
|
+
{{
|
|
55
|
+
"nodeTypes": {{
|
|
56
|
+
...
|
|
57
|
+
"_site": {{
|
|
58
|
+
"fields": {{
|
|
59
|
+
"myCustomSiteField": {{
|
|
60
|
+
"label": "My custom site field",
|
|
61
|
+
"description": "…"
|
|
62
|
+
}}
|
|
63
|
+
}}
|
|
64
|
+
}}
|
|
65
|
+
}}
|
|
66
|
+
}}
|
|
67
|
+
</l10n_example>
|
|
68
|
+
|
|
51
69
|
Important:
|
|
52
70
|
|
|
53
71
|
- Never add locales for a predefined field.
|
|
54
72
|
- Never add an unknown predefined field.
|
|
73
|
+
- The type name of the "site" node type is omitted from the JSON but its value is always `_site`.
|
|
55
74
|
|
|
56
75
|
# 3. Examine the current JSON data, which conforms to the `JtSiteSchema` type:
|
|
57
76
|
|