@paroicms/site-generator-plugin 0.9.0 → 0.10.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.
Files changed (59) hide show
  1. package/gen-backend/ddl/site-generator.ddl.sql +57 -9
  2. package/gen-backend/dist/commands/execute-command.js +35 -9
  3. package/gen-backend/dist/commands/generator-session.js +49 -10
  4. package/gen-backend/dist/data-format.js +32 -4
  5. package/gen-backend/dist/db/db-init.js +3 -1
  6. package/gen-backend/dist/db/db-read.queries.js +142 -0
  7. package/gen-backend/dist/db/db-write.queries.js +144 -0
  8. package/gen-backend/dist/db/ddl-migration.js +8 -6
  9. package/gen-backend/dist/db/formatters.js +46 -0
  10. package/gen-backend/dist/generator/fake-content-generator.ts/content-report.js +9 -5
  11. package/gen-backend/dist/generator/fake-content-generator.ts/create-database-with-fake-content.js +18 -13
  12. package/gen-backend/dist/generator/fake-content-generator.ts/generate-fake-content.js +16 -12
  13. package/gen-backend/dist/generator/fake-content-generator.ts/invoke-generate-fake-content.js +26 -17
  14. package/gen-backend/dist/generator/lib/calling-llm-anthropic.js +33 -0
  15. package/gen-backend/dist/generator/lib/calling-llm-mistral.js +156 -0
  16. package/gen-backend/dist/generator/lib/create-prompt.js +2 -2
  17. package/gen-backend/dist/generator/lib/debug-utils.js +74 -48
  18. package/gen-backend/dist/generator/lib/llm-tokens.js +7 -9
  19. package/gen-backend/dist/generator/lib/llm-utils.js +8 -0
  20. package/gen-backend/dist/generator/lib/prompt-template.js +10 -0
  21. package/gen-backend/dist/generator/lib/session-utils.js +31 -0
  22. package/gen-backend/dist/generator/llm-queries/invoke-message-guard.js +20 -9
  23. package/gen-backend/dist/generator/llm-queries/invoke-new-site-analysis.js +73 -47
  24. package/gen-backend/dist/generator/llm-queries/invoke-update-site-schema.js +106 -43
  25. package/gen-backend/dist/generator/site-generator/site-generator.js +26 -18
  26. package/gen-backend/dist/lib/create-raw-context.js +31 -0
  27. package/gen-backend/dist/lib/site-remover.js +1 -1
  28. package/gen-backend/dist/plugin.js +8 -54
  29. package/gen-backend/prompts/generate-fake-content-multiple-documents.md +5 -5
  30. package/gen-backend/prompts/generate-fake-content-multiple-parts.md +5 -5
  31. package/gen-backend/prompts/generate-fake-content-single.md +4 -4
  32. package/gen-backend/prompts/{new-site-1-analysis.md → initial-1-analysis.md} +38 -29
  33. package/gen-backend/prompts/{new-site-2-fields.md → initial-2-fields.md} +3 -3
  34. package/gen-backend/prompts/message-guard.md +1 -1
  35. package/gen-backend/prompts/update-site-schema-1-write-details.md +5 -5
  36. package/gen-backend/prompts/update-site-schema-2-execute.md +29 -29
  37. package/gen-front/dist/gen-front.css +1 -1
  38. package/gen-front/dist/gen-front.mjs +137 -1175
  39. package/package.json +30 -32
  40. package/gen-backend/dist/commands/actions.js +0 -49
  41. package/gen-backend/dist/db/db.queries.js +0 -60
  42. package/gen-backend/dist/errors.js +0 -20
  43. package/gen-backend/dist/generator/actions.js +0 -45
  44. package/gen-backend/dist/generator/fake-content-generator.ts/augment-fields.js +0 -51
  45. package/gen-backend/dist/generator/generator-session.js +0 -33
  46. package/gen-backend/dist/generator/generator-types.js +0 -1
  47. package/gen-backend/dist/generator/lib/token-tracking.js +0 -118
  48. package/gen-backend/dist/generator/session/generator-session.js +0 -33
  49. package/gen-backend/dist/generator/session/session-command.js +0 -17
  50. package/gen-backend/dist/generator/site-generator/theme-scss.js +0 -262
  51. package/gen-backend/dist/lib/generator-context.js +0 -14
  52. package/gen-backend/prompts/test-message1.txt +0 -1
  53. package/gen-front/dist/gen-front.eot +0 -0
  54. package/gen-front/dist/gen-front.svg +0 -345
  55. package/gen-front/dist/gen-front.ttf +0 -0
  56. package/gen-front/dist/gen-front.woff +0 -0
  57. package/gen-front/dist/gen-front.woff2 +0 -0
  58. package/gen-front/dist/gen-front2.woff2 +0 -0
  59. package/gen-front/dist/gen-front3.woff2 +0 -0
@@ -1,6 +1,5 @@
1
- import { ChatAnthropic } from "@langchain/anthropic";
2
- import { ChatMistralAI } from "@langchain/mistralai";
3
- import { getJwtSecretSync, pathExists } from "@paroicms/internal-server-lib";
1
+ import { messageOf } from "@paroi/data-formatters-lib";
2
+ import { pathExists } from "@paroicms/internal-server-lib";
4
3
  import { ApiError, escapeHtml } from "@paroicms/public-server-lib";
5
4
  import { join } from "node:path";
6
5
  import { executeCommand } from "./commands/execute-command.js";
@@ -8,7 +7,8 @@ import { SLUG, packageDir, pluginVersion } from "./context.js";
8
7
  import { formatGeneratorCommand, formatGeneratorPluginConfiguration } from "./data-format.js";
9
8
  import { createOrOpenSiteGeneratorConnection } from "./db/db-init.js";
10
9
  import { initializeImageNames } from "./generator/lib/images-lib.js";
11
- import { removeExpiredSites } from "./lib/site-remover.js";
10
+ import { createRawContext } from "./lib/create-raw-context.js";
11
+ import { startSiteRemover } from "./lib/site-remover.js";
12
12
  await initializeImageNames();
13
13
  const plugin = {
14
14
  version: pluginVersion,
@@ -27,61 +27,15 @@ const plugin = {
27
27
  debugDir = undefined;
28
28
  }
29
29
  }
30
- const bestModel = new ChatAnthropic({
31
- modelName: "claude-3-7-sonnet-20250219",
32
- anthropicApiKey: pluginConf.anthropicApiKey,
33
- temperature: 0.1,
34
- maxTokens: 6500,
35
- clientOptions: {
36
- timeout: 60_000,
37
- },
38
- });
39
- const goodModel = new ChatAnthropic({
40
- modelName: "claude-3-7-sonnet-20250219",
41
- anthropicApiKey: pluginConf.anthropicApiKey,
42
- temperature: 0.1,
43
- maxTokens: 3000,
44
- clientOptions: {
45
- timeout: 20_000,
46
- },
47
- });
48
- // const cheapModel = new ChatAnthropic({
49
- // modelName: "claude-3-5-haiku-20241022",
50
- // anthropicApiKey: pluginConf.anthropicApiKey,
51
- // temperature: 0.6,
52
- // maxTokens: 50_000,
53
- // });
54
- const cheapModel = new ChatMistralAI({
55
- modelName: "ministral-8b-2410", // ministral-8b-2410
56
- apiKey: pluginConf.mistralApiKey,
57
- temperature: 0.2,
58
- maxTokens: 50_000,
59
- });
60
30
  let rawContext;
61
31
  service.registerHook("initialized", (service) => {
62
- const packConf = service.connector.getSitePackConf(pluginConf.packName);
63
- const { sitesDir, packName } = packConf;
64
- if (!sitesDir || packConf.serveOn !== "subDomain") {
65
- throw new Error(`Site-generator plugin can generate sites only for sub-domain pack with "sitesDir", but pack "${packName}" doesn't have it`);
66
- }
67
- rawContext = {
32
+ rawContext = createRawContext(service, {
68
33
  cn,
69
34
  logNextQuery,
70
- jwtSecret: getJwtSecretSync(join(service.registeredSite.dataDir, "site-generator-secret.txt")),
71
35
  pluginConf,
72
- bestModel,
73
- bestModelName: bestModel.model,
74
- goodModel,
75
- goodModelName: goodModel.model,
76
- cheapModel,
77
- cheapModelName: cheapModel.model,
78
36
  debugDir,
79
- sitesDir,
80
- packConf,
81
- service,
82
- logger: service.logger,
83
- };
84
- removeExpiredSites(rawContext).catch(console.error);
37
+ });
38
+ startSiteRemover(rawContext);
85
39
  });
86
40
  service.setPublicAssetsDirectory(join(packageDir, "gen-front", "dist"));
87
41
  const scriptAttr = [
@@ -105,7 +59,7 @@ const plugin = {
105
59
  command = formatGeneratorCommand(req.body);
106
60
  }
107
61
  catch (error) {
108
- res.status(400).send({ status: 400, message: error.message });
62
+ res.status(400).send({ status: 400, message: messageOf(error) });
109
63
  return;
110
64
  }
111
65
  try {
@@ -1,10 +1,10 @@
1
- Generate the text content of **{count}** different **web pages**.
1
+ Generate the text content of **{{count}}** different **web pages**.
2
2
 
3
- All the produced texts must be in **{language}**.
3
+ All the produced texts must be in **{{language}}**.
4
4
 
5
- The web pages in question are of type: **{typeLabel}** ({typeDescription}).
5
+ The web pages in question are of type: **{{typeLabel}}** ({{typeDescription}}).
6
6
 
7
- For the context, the website's theme is: "{siteTheme}".
7
+ For the context, the website's theme is: "{{siteTheme}}".
8
8
 
9
9
  Make sure web pages are distinct from each other by:
10
10
 
@@ -19,4 +19,4 @@ Guidelines:
19
19
 
20
20
  Each web page is composed by several sub-contents. Use the following exact format:
21
21
 
22
- {tagAndDescriptions}
22
+ {{tagAndDescriptions}}
@@ -1,10 +1,10 @@
1
- Generate the text content of **{count}** different **sections** of a web page.
1
+ Generate the text content of **{{count}}** different **sections** of a web page.
2
2
 
3
- All the produced texts must be in **{language}**.
3
+ All the produced texts must be in **{{language}}**.
4
4
 
5
- The sections in question are of type: **{typeLabel}** ({typeDescription}).
5
+ The sections in question are of type: **{{typeLabel}}** ({{typeDescription}}).
6
6
 
7
- For the context, the website's theme is: "{siteTheme}", and the web page is about "{documentDescription}".
7
+ For the context, the website's theme is: "{{siteTheme}}", and the web page is about "{{documentDescription}}".
8
8
 
9
9
  Make sure sections are distinct from each other by:
10
10
 
@@ -19,4 +19,4 @@ Guidelines:
19
19
 
20
20
  Each section is composed by several sub-contents. Use the following exact format:
21
21
 
22
- {tagAndDescriptions}
22
+ {{tagAndDescriptions}}
@@ -1,10 +1,10 @@
1
1
  Generate the text content of a web page.
2
2
 
3
- All the produced texts for the web page must be in **{language}**.
3
+ All the produced texts for the web page must be in **{{language}}**.
4
4
 
5
- The web page in question is: **{typeLabel}** ({typeDescription}).
5
+ The web page in question is: **{{typeLabel}}** ({{typeDescription}}).
6
6
 
7
- For the context, the website's theme is: "{siteTheme}".
7
+ For the context, the website's theme is: "{{siteTheme}}".
8
8
 
9
9
  Guidelines:
10
10
 
@@ -13,4 +13,4 @@ Guidelines:
13
13
 
14
14
  Follow the exact format:
15
15
 
16
- {tagAndDescriptions}
16
+ {{tagAndDescriptions}}
@@ -6,9 +6,9 @@ You will be given a description of a website's structure. Your task is to **anal
6
6
 
7
7
  Here is the website description:
8
8
 
9
- <website_description>
10
- {message}
11
- </website_description>
9
+ <user_message>
10
+ {{message}}
11
+ </user_message>
12
12
 
13
13
  Notice: If the website description doesn't mention a _contact page_ and a _search page_, then append them by default as routing documents, children of the home page.
14
14
 
@@ -18,7 +18,7 @@ In the first step, you are tasked to write global properties of the website as a
18
18
 
19
19
  Provide the following website properties:
20
20
 
21
- - language: The language used in <website_description>, as a two-letters code. This is the website language.
21
+ - language: The language used in <user_message>, as a two-letters code. This is the website language.
22
22
  - title: The website title, in the _website language_.
23
23
  - theme: A description (5-40 words) that can be used as a tooltip to explain the main theme and/or purpose of the website. Write it in the _website language_.
24
24
 
@@ -33,8 +33,6 @@ For this second step, follow these instructions for creating the bullet list:
33
33
  3. Determine the hierarchical relationships between documents and parts.
34
34
  4. Create a tree structure using a limited Markdown format to represent the website's tree structure.
35
35
 
36
- Whenever you have a choice, keep it simple. If the user is not directive, if he gives a general and vague instruction, for example with a short prompt like “create a blog”, then limit the site sections to two main entries (in the example of a blog, a list of posts and a list of pages). Plus the usual contact and search pages.
37
-
38
36
  Guidelines for creating the hierarchical bullet list:
39
37
 
40
38
  - Write in English.
@@ -111,6 +109,10 @@ Here's an example of correct output using parts, and with the default contact an
111
109
  * `searchPage` (routing document)
112
110
  </correct_example>
113
111
 
112
+ ### Keep it simple!
113
+
114
+ When you have a choice, keep it simple. If the user lets you invent the site's structure, limit the site's sections to **2 main entries**. For example, a “news” routing document with a list of articles and categories, and a list of pages on the site's theme. Plus the usual contact and search pages.
115
+
114
116
  ## Step 3 - Instructions for the dictionnary YAML.
115
117
 
116
118
  In the third step, you are tasked to produce a YAML that describes every node type and list of parts identified in the hierarchical YAML.
@@ -128,7 +130,7 @@ Guidelines for creating the dictionnary YAML:
128
130
  - ogType: (optional, and document only) If you think of a particular Open-Graph type for this document, give it here.
129
131
  - label: A label of the node type, in the _website language_.
130
132
  - description: A description (5-40 words) for describing the purpose and theme of the node type. Write it in the _website language_.
131
- - prompt: This is an optional property. If there is an information to process later about this node type (a description of fields), then write it here. Keep is short.
133
+ - prompt: This is an optional property. If there is an information to process later about this node type (a description of fields), then write it here. Keep is short, and in English.
132
134
  - For a list type (only for part list, never for document list), provide the following properties:
133
135
  - confidence: Your confidence level for the accuracy of this node type (0.0-1.0).
134
136
  - kind: Must be `partList`.
@@ -154,6 +156,32 @@ homeSection:
154
156
  kind: part
155
157
  label: Section
156
158
  description: A home section is a sub-part of the home page.
159
+ pages:
160
+ confidence: 0.9
161
+ kind: routingDocument
162
+ label: Pages
163
+ description: This is the document for grouping all pages.
164
+ page:
165
+ confidence: 0.9
166
+ kind: regularDocument
167
+ temporal: false
168
+ label: Page
169
+ description: ...
170
+ pageSections:
171
+ confidence: 0.9
172
+ kind: partList
173
+ label: Sections
174
+ description: ...
175
+ pageSection:
176
+ confidence: 0.8
177
+ kind: part
178
+ label: Section
179
+ description: ...
180
+ </correct_example>
181
+
182
+ Here is how to specify posts with a "tags" taxonomy:
183
+
184
+ <correct_example>
157
185
  news:
158
186
  confidence: 1
159
187
  kind: routingDocument
@@ -167,7 +195,7 @@ post:
167
195
  ogType: article
168
196
  label: Post
169
197
  description: A topical post about the subject of the website whatever it is.
170
- prompt: Add a labeling field using the tags taxonomy
198
+ prompt: Add a labeling field using the tags taxonomy (allow multiple tags)
171
199
  tags:
172
200
  confidence: 0.9
173
201
  kind: routingDocument
@@ -179,29 +207,10 @@ tag:
179
207
  temporal: true
180
208
  label: Tag
181
209
  description: A tag is a term in the tags taxonomy.
182
- pages:
183
- confidence: 0.9
184
- kind: routingDocument
185
- label: Pages
186
- description: This is the document for grouping all pages.
187
- page:
188
- confidence: 0.9
189
- kind: regularDocument
190
- temporal: false
191
- label: Page
192
- description: ...
193
- pageSections:
194
- confidence: 0.9
195
- kind: partList
196
- label: Sections
197
- description: ...
198
- pageSection:
199
- confidence: 0.8
200
- kind: part
201
- label: Section
202
- description: ...
203
210
  </correct_example>
204
211
 
212
+ Note the `prompt` property in the `post` type: in this way, tags can be assigned to a post.
213
+
205
214
  # Producing outputs
206
215
 
207
216
  Before providing your final answer, use the scratchpad to organize your thoughts and plan the structure:
@@ -3,19 +3,19 @@ You are tasked of assigning predefined fields for each node type (routing docume
3
3
  1. Look at the list of available predefined fields (in JSON format):
4
4
 
5
5
  <predefined_fields_json>
6
- {predefinedFields}
6
+ {{predefinedFields}}
7
7
  </predefined_fields_json>
8
8
 
9
9
  2. Examine the current site schema, which conforms to the `JtSiteSchema` type:
10
10
 
11
11
  <site_schema_json>
12
- {siteSchemaJson}
12
+ {{siteSchemaJson}}
13
13
  </site_schema_json>
14
14
 
15
15
  3. Check if there are instructions about fields in these user instructions:
16
16
 
17
17
  <user_request>
18
- {message}
18
+ {{message}}
19
19
  </user_request>
20
20
 
21
21
  4. Now, here is what to do:
@@ -36,7 +36,7 @@ Be real quick! Do not think a lot. Your first impression will be the right one.
36
36
  Now, here is the user request:
37
37
 
38
38
  <user_message>
39
- {message}
39
+ {{message}}
40
40
  </user_message>
41
41
 
42
42
  # The output format in YAML
@@ -3,7 +3,7 @@ You are tasked to plan how modifying a JSON object of a _site schema_, based on
3
3
  # 1. Review the TypeScript type definition of the JSON structure:
4
4
 
5
5
  <site_schema_ts_defs>
6
- {siteSchemaTsDefs}
6
+ {{siteSchemaTsDefs}}
7
7
  </site_schema_ts_defs>
8
8
 
9
9
  # 2. About fields
@@ -11,7 +11,7 @@ You are tasked to plan how modifying a JSON object of a _site schema_, based on
11
11
  Fields can be either predefined fields or custom fields. Take a look at the predefined fields provided by the CMS:
12
12
 
13
13
  <predefined_fields_json>
14
- {predefinedFields}
14
+ {{predefinedFields}}
15
15
  </predefined_fields_json>
16
16
 
17
17
  # 3. The current site schema
@@ -19,19 +19,19 @@ Fields can be either predefined fields or custom fields. Take a look at the pred
19
19
  Examine the current JSON data, which conforms to the `JtSiteSchema` type:
20
20
 
21
21
  <site_schema_json>
22
- {siteSchemaJson}
22
+ {{siteSchemaJson}}
23
23
  </site_schema_json>
24
24
 
25
25
  Also, the attached localized labels:
26
26
 
27
27
  <localized_labels_json>
28
- {l10nJson}
28
+ {{l10nJson}}
29
29
  </localized_labels_json>
30
30
 
31
31
  # 4. Read the user message that describes the required changes:
32
32
 
33
33
  <user_message>
34
- {updateMessage}
34
+ {{updateMessage}}
35
35
  </user_message>
36
36
 
37
37
  # 5. When there is nothing to change
@@ -3,7 +3,7 @@ You are tasked with modifying a JSON object based on a given TypeScript type def
3
3
  # 1. Review the TypeScript type definition of the JSON structure:
4
4
 
5
5
  <site_schema_ts_defs>
6
- {siteSchemaTsDefs}
6
+ {{siteSchemaTsDefs}}
7
7
  </site_schema_ts_defs>
8
8
 
9
9
  # 2. Fields
@@ -13,13 +13,13 @@ In a list of fields, an item can be either a predefined field name (a string) or
13
13
  Here are the predefined fields provided by ParoiCMS:
14
14
 
15
15
  <predefined_fields_json>
16
- {predefinedFields}
16
+ {{predefinedFields}}
17
17
  </predefined_fields_json>
18
18
 
19
19
  Here is an example of an object for describing a custom **HTML** field type:
20
20
 
21
21
  <field_type_example>
22
- {{
22
+ {
23
23
  "name": "myCustomField",
24
24
  "localized": true,
25
25
  "storedAs": "text",
@@ -27,44 +27,44 @@ Here is an example of an object for describing a custom **HTML** field type:
27
27
  "renderAs": "html",
28
28
  "useAsExcerpt": 1,
29
29
  "plugin": "@paroicms/quill-editor-plugin"
30
- }}
30
+ }
31
31
  </field_type_example>
32
32
 
33
33
  Then, in the locales, the translations of custom field types must be in a sub-key `fields` of the node type:
34
34
 
35
35
  <l10n_example>
36
- {{
37
- "nodeTypes": {{
36
+ {
37
+ "nodeTypes": {
38
38
  ...
39
- "myNodeTypeName": {{
39
+ "myNodeTypeName": {
40
40
  ...
41
- "fields": {{
42
- "myCustomField": {{
41
+ "fields": {
42
+ "myCustomField": {
43
43
  "label": "My custom field",
44
44
  "description": "This is a description that will be displayed in a tooltip of the back-office"
45
- }}
46
- }}
47
- }}
48
- }}
49
- }}
45
+ }
46
+ }
47
+ }
48
+ }
49
+ }
50
50
  </l10n_example>
51
51
 
52
52
  Here is how to write field locales for a custom site field:
53
53
 
54
54
  <l10n_example>
55
- {{
56
- "nodeTypes": {{
55
+ {
56
+ "nodeTypes": {
57
57
  ...
58
- "_site": {{
59
- "fields": {{
60
- "myCustomSiteField": {{
58
+ "_site": {
59
+ "fields": {
60
+ "myCustomSiteField": {
61
61
  "label": "My custom site field",
62
62
  "description": "…"
63
- }}
64
- }}
65
- }}
66
- }}
67
- }}
63
+ }
64
+ }
65
+ }
66
+ }
67
+ }
68
68
  </l10n_example>
69
69
 
70
70
  Important:
@@ -78,13 +78,13 @@ Important:
78
78
  A labeling field lets the user assign taxonomy terms to a document (or part).
79
79
 
80
80
  <field_type_example>
81
- {{
81
+ {
82
82
  "name": "tags",
83
83
  "localized": false,
84
84
  "storedAs": "labeling",
85
85
  "taxonomy": "tags",
86
86
  "multiple": true
87
- }},
87
+ },
88
88
  </field_type_example>
89
89
 
90
90
  Most of the time, the field name will be the same as the taxonomy type name.
@@ -92,19 +92,19 @@ Most of the time, the field name will be the same as the taxonomy type name.
92
92
  # 4. Examine the current JSON data, which conforms to the `JtSiteSchema` type:
93
93
 
94
94
  <site_schema_json>
95
- {siteSchemaJson}
95
+ {{siteSchemaJson}}
96
96
  </site_schema_json>
97
97
 
98
98
  Also, the attached locales:
99
99
 
100
100
  <l10n_json>
101
- {l10nJson}
101
+ {{l10nJson}}
102
102
  </l10n_json>
103
103
 
104
104
  # 5. Now, here is what to do:
105
105
 
106
106
  <user_request>
107
- {taskDetailsMd}
107
+ {{taskDetailsMd}}
108
108
  </user_request>
109
109
 
110
110
  # 6. Guidelines