@aglyn/plugins-ai 1.0.0-beta.250 → 1.0.0-beta.252
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/package.json +17 -17
- package/src/lib/components/ai-brief-dialog.component.js +15 -1
- package/src/lib/components/ai-brief-dialog.component.js.map +1 -1
- package/src/lib/components/ai-job-links.js +1 -1
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-job-plan.component.js +20 -2
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-jobs-store.d.ts +11 -0
- package/src/lib/components/ai-jobs-store.js +22 -0
- package/src/lib/components/ai-jobs-store.js.map +1 -1
- package/src/lib/jobs/ai-job-crm-step.js +7 -4
- package/src/lib/jobs/ai-job-crm-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.d.ts +24 -0
- package/src/lib/jobs/ai-job-drafts.js +46 -0
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-experiment-step.js +6 -1
- package/src/lib/jobs/ai-job-experiment-step.js.map +1 -1
- package/src/lib/jobs/ai-job-form-reuse.d.ts +78 -0
- package/src/lib/jobs/ai-job-form-reuse.js +136 -0
- package/src/lib/jobs/ai-job-form-reuse.js.map +1 -0
- package/src/lib/jobs/ai-job-form-step.d.ts +17 -0
- package/src/lib/jobs/ai-job-form-step.js +63 -11
- package/src/lib/jobs/ai-job-form-step.js.map +1 -1
- package/src/lib/jobs/ai-job-insight-step.js +6 -1
- package/src/lib/jobs/ai-job-insight-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +19 -0
- package/src/lib/jobs/ai-job-plan-step.js +39 -1
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-seo-step.js +5 -3
- package/src/lib/jobs/ai-job-seo-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-content.d.ts +7 -5
- package/src/lib/jobs/ai-job-site-content.js +7 -5
- package/src/lib/jobs/ai-job-site-content.js.map +1 -1
- package/src/lib/jobs/ai-job-text-step.js +6 -3
- package/src/lib/jobs/ai-job-text-step.js.map +1 -1
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +11 -7
- package/src/lib/jobs/ai-layout-stock-photos.js +25 -10
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-stock-business-nouns.d.ts +62 -0
- package/src/lib/jobs/ai-stock-business-nouns.js +264 -0
- package/src/lib/jobs/ai-stock-business-nouns.js.map +1 -0
- package/src/lib/model/ai-build-plan.d.ts +7 -3
- package/src/lib/model/ai-build-plan.js +11 -1
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-credit-estimate.d.ts +32 -18
- package/src/lib/model/ai-credit-estimate.js +36 -18
- package/src/lib/model/ai-credit-estimate.js.map +1 -1
- package/src/lib/model/ai-job-activity.d.ts +30 -0
- package/src/lib/model/ai-job-activity.js +35 -0
- package/src/lib/model/ai-job-activity.js.map +1 -1
- package/src/lib/model/ai-media-credits.d.ts +5 -3
- package/src/lib/model/ai-media-credits.js +7 -5
- package/src/lib/model/ai-media-credits.js.map +1 -1
- package/src/lib/model/ai-site-job.js +6 -3
- package/src/lib/model/ai-site-job.js.map +1 -1
- package/src/lib/model/ai-site-store-pages.d.ts +5 -0
- package/src/lib/model/ai-site-store-pages.js +2 -0
- package/src/lib/model/ai-site-store-pages.js.map +1 -1
- package/src/lib/plugin-config.js +2 -2
- package/src/lib/plugin-config.js.map +1 -1
- package/src/lib/providers/anthropic-crm-wording-superseded.d.ts +29 -0
- package/src/lib/providers/anthropic-crm-wording-superseded.js +31 -0
- package/src/lib/providers/anthropic-crm-wording-superseded.js.map +1 -0
- package/src/lib/providers/catalog.d.ts +24 -17
- package/src/lib/providers/catalog.js +63 -30
- package/src/lib/providers/catalog.js.map +1 -1
- package/src/lib/providers/model-choice.d.ts +1 -1
- package/src/lib/providers/model-choice.js +39 -30
- package/src/lib/providers/model-choice.js.map +1 -1
- package/src/lib/providers/routing.d.ts +20 -1
- package/src/lib/providers/routing.js +47 -8
- package/src/lib/providers/routing.js.map +1 -1
- package/src/lib/runtime/ai-dev-env.d.ts +37 -1
- package/src/lib/runtime/ai-dev-env.js +59 -6
- package/src/lib/runtime/ai-dev-env.js.map +1 -1
- package/src/lib/runtime/ai-doctrine-validators.js +3 -1
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +8 -4
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/ai-eval-live.d.ts +8 -0
- package/src/lib/runtime/ai-eval-live.js +34 -8
- package/src/lib/runtime/ai-eval-live.js.map +1 -1
- package/src/lib/runtime/ai-palette.generated.js +4 -0
- package/src/lib/runtime/ai-palette.generated.js.map +1 -1
- package/src/lib/runtime/ai-runtime.js +17 -2
- package/src/lib/runtime/ai-runtime.js.map +1 -1
- package/src/lib/runtime/seo-fields.js +4 -3
- package/src/lib/runtime/seo-fields.js.map +1 -1
- package/src/lib/server/ai-assist.js +3 -2
- package/src/lib/server/ai-assist.js.map +1 -1
- package/src/lib/server/ai-media-svg.js +4 -0
- package/src/lib/server/ai-media-svg.js.map +1 -1
- package/src/lib/usage/ai-allotment-alerts.js +2 -5
- package/src/lib/usage/ai-allotment-alerts.js.map +1 -1
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* THE ENGLISH NAME OF A BUSINESS TYPE WRITTEN IN ANOTHER LANGUAGE (AGL-3779).
|
|
19
|
+
*
|
|
20
|
+
* The stock photo libraries are tagged in English, so a site in another
|
|
21
|
+
* language is searched by an English subject (`aiStockSourceTerms`). The
|
|
22
|
+
* business type the person typed is the surest word for what the site is
|
|
23
|
+
* about, once it is English: "Una panadería familiar … con pan dulce" read
|
|
24
|
+
* as an English noun phrase searched "con pan dulce" and placed the Río
|
|
25
|
+
* Dulce, the kind of site picked ("restaurant cafe") placed a coffee mug as a
|
|
26
|
+
* bakery's hero (jobs ih6kVvCGP1 and iGmqrEgyW4, beta.250), and a live plan's
|
|
27
|
+
* photo words for a florist, "wedding bouquets event flowers", led with
|
|
28
|
+
* "wedding". So a business this table names leads the search, ahead of the
|
|
29
|
+
* plan's photo words, which decide only for a business it does not name.
|
|
30
|
+
*
|
|
31
|
+
* This table names the common kinds of local business in Spanish, French,
|
|
32
|
+
* Portuguese, German and Italian, each with the English words a library is
|
|
33
|
+
* searched by. It is deliberately small: a kind belongs here when people
|
|
34
|
+
* start sites for it and its name is not already English. Words English
|
|
35
|
+
* shares ("café", "restaurant", "boutique", "pizzeria") are left out, because
|
|
36
|
+
* the guided start's own brief is English around the person's words ("Make
|
|
37
|
+
* it a restaurant & café site") and must never decide the subject; such a
|
|
38
|
+
* site falls through to the kind it picked, as before.
|
|
39
|
+
*
|
|
40
|
+
* A word matches whole, accents and case aside: "panaderia" and "Panadería"
|
|
41
|
+
* meet, so a name two languages spell alike ("farmacia", "fotógrafo") is
|
|
42
|
+
* listed once; "pan" never matches inside "panadería", and a German compound
|
|
43
|
+
* ("Familienbäckerei") matches only if it is listed itself. The first listed
|
|
44
|
+
* name the text says wins, the longer of two that start at the same word —
|
|
45
|
+
* "peluquería canina" is a dog groomer, "peluquería" a hair salon — so the
|
|
46
|
+
* head noun a Romance-language business type opens with decides.
|
|
47
|
+
*/
|
|
48
|
+
/** A kind of business: the English words its photos are searched by, and its names in other languages. */
|
|
49
|
+
interface AiStockBusinessNoun {
|
|
50
|
+
/** What a stock photo library is searched by: "bakery". */
|
|
51
|
+
english: string;
|
|
52
|
+
/** Its names in es, fr, pt, de and it, as people write them. */
|
|
53
|
+
names: readonly string[];
|
|
54
|
+
}
|
|
55
|
+
export declare const AI_STOCK_BUSINESS_NOUNS: readonly AiStockBusinessNoun[];
|
|
56
|
+
/**
|
|
57
|
+
* The English words for the kind of business a text in another language
|
|
58
|
+
* names ({@link AI_STOCK_BUSINESS_NOUNS}): "bakery" for "Una panadería
|
|
59
|
+
* familiar de San Antonio con pan dulce". Empty when it names none listed.
|
|
60
|
+
*/
|
|
61
|
+
export declare function aiStockBusinessNoun(text: string): string;
|
|
62
|
+
export {};
|
|
@@ -0,0 +1,264 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @license
|
|
3
|
+
* Copyright 2026 Aglyn LLC
|
|
4
|
+
*
|
|
5
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
6
|
+
* you may not use this file except in compliance with the License.
|
|
7
|
+
* You may obtain a copy of the License at
|
|
8
|
+
*
|
|
9
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
10
|
+
*
|
|
11
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
12
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
13
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
14
|
+
* See the License for the specific language governing permissions and
|
|
15
|
+
* limitations under the License.
|
|
16
|
+
*/ /**
|
|
17
|
+
* THE ENGLISH NAME OF A BUSINESS TYPE WRITTEN IN ANOTHER LANGUAGE (AGL-3779).
|
|
18
|
+
*
|
|
19
|
+
* The stock photo libraries are tagged in English, so a site in another
|
|
20
|
+
* language is searched by an English subject (`aiStockSourceTerms`). The
|
|
21
|
+
* business type the person typed is the surest word for what the site is
|
|
22
|
+
* about, once it is English: "Una panadería familiar … con pan dulce" read
|
|
23
|
+
* as an English noun phrase searched "con pan dulce" and placed the Río
|
|
24
|
+
* Dulce, the kind of site picked ("restaurant cafe") placed a coffee mug as a
|
|
25
|
+
* bakery's hero (jobs ih6kVvCGP1 and iGmqrEgyW4, beta.250), and a live plan's
|
|
26
|
+
* photo words for a florist, "wedding bouquets event flowers", led with
|
|
27
|
+
* "wedding". So a business this table names leads the search, ahead of the
|
|
28
|
+
* plan's photo words, which decide only for a business it does not name.
|
|
29
|
+
*
|
|
30
|
+
* This table names the common kinds of local business in Spanish, French,
|
|
31
|
+
* Portuguese, German and Italian, each with the English words a library is
|
|
32
|
+
* searched by. It is deliberately small: a kind belongs here when people
|
|
33
|
+
* start sites for it and its name is not already English. Words English
|
|
34
|
+
* shares ("café", "restaurant", "boutique", "pizzeria") are left out, because
|
|
35
|
+
* the guided start's own brief is English around the person's words ("Make
|
|
36
|
+
* it a restaurant & café site") and must never decide the subject; such a
|
|
37
|
+
* site falls through to the kind it picked, as before.
|
|
38
|
+
*
|
|
39
|
+
* A word matches whole, accents and case aside: "panaderia" and "Panadería"
|
|
40
|
+
* meet, so a name two languages spell alike ("farmacia", "fotógrafo") is
|
|
41
|
+
* listed once; "pan" never matches inside "panadería", and a German compound
|
|
42
|
+
* ("Familienbäckerei") matches only if it is listed itself. The first listed
|
|
43
|
+
* name the text says wins, the longer of two that start at the same word —
|
|
44
|
+
* "peluquería canina" is a dog groomer, "peluquería" a hair salon — so the
|
|
45
|
+
* head noun a Romance-language business type opens with decides.
|
|
46
|
+
*/ /** A kind of business: the English words its photos are searched by, and its names in other languages. */ export const AI_STOCK_BUSINESS_NOUNS = [
|
|
47
|
+
{
|
|
48
|
+
english: 'bakery',
|
|
49
|
+
names: [
|
|
50
|
+
'panadería',
|
|
51
|
+
'boulangerie',
|
|
52
|
+
'padaria',
|
|
53
|
+
'Bäckerei',
|
|
54
|
+
'panetteria',
|
|
55
|
+
'panificio'
|
|
56
|
+
]
|
|
57
|
+
},
|
|
58
|
+
{
|
|
59
|
+
english: 'pastry shop',
|
|
60
|
+
names: [
|
|
61
|
+
'pastelería',
|
|
62
|
+
'repostería',
|
|
63
|
+
'pâtisserie',
|
|
64
|
+
'confeitaria',
|
|
65
|
+
'Konditorei',
|
|
66
|
+
'pasticceria'
|
|
67
|
+
]
|
|
68
|
+
},
|
|
69
|
+
{
|
|
70
|
+
english: 'tacos',
|
|
71
|
+
names: [
|
|
72
|
+
'taquería'
|
|
73
|
+
]
|
|
74
|
+
},
|
|
75
|
+
{
|
|
76
|
+
english: 'cafe',
|
|
77
|
+
names: [
|
|
78
|
+
'cafetería',
|
|
79
|
+
'caffetteria'
|
|
80
|
+
]
|
|
81
|
+
},
|
|
82
|
+
{
|
|
83
|
+
english: 'restaurant',
|
|
84
|
+
names: [
|
|
85
|
+
'restaurante',
|
|
86
|
+
'ristorante',
|
|
87
|
+
'Gaststätte'
|
|
88
|
+
]
|
|
89
|
+
},
|
|
90
|
+
// A library knows the trattoria by its own name, a narrower search than "restaurant".
|
|
91
|
+
{
|
|
92
|
+
english: 'trattoria',
|
|
93
|
+
names: [
|
|
94
|
+
'trattoria',
|
|
95
|
+
'osteria'
|
|
96
|
+
]
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
english: 'butcher shop',
|
|
100
|
+
names: [
|
|
101
|
+
'carnicería',
|
|
102
|
+
'boucherie',
|
|
103
|
+
'açougue',
|
|
104
|
+
'Metzgerei',
|
|
105
|
+
'macelleria'
|
|
106
|
+
]
|
|
107
|
+
},
|
|
108
|
+
{
|
|
109
|
+
english: 'florist',
|
|
110
|
+
names: [
|
|
111
|
+
'floristería',
|
|
112
|
+
'florería',
|
|
113
|
+
'fleuriste',
|
|
114
|
+
'floricultura',
|
|
115
|
+
'Blumenladen',
|
|
116
|
+
'fioraio',
|
|
117
|
+
'fioreria'
|
|
118
|
+
]
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
english: 'hair salon',
|
|
122
|
+
names: [
|
|
123
|
+
'peluquería',
|
|
124
|
+
'salon de coiffure',
|
|
125
|
+
'coiffeur',
|
|
126
|
+
'coiffeuse',
|
|
127
|
+
'cabeleireiro',
|
|
128
|
+
'Friseur',
|
|
129
|
+
'Friseursalon',
|
|
130
|
+
'parrucchiere'
|
|
131
|
+
]
|
|
132
|
+
},
|
|
133
|
+
{
|
|
134
|
+
english: 'dog grooming',
|
|
135
|
+
names: [
|
|
136
|
+
'peluquería canina',
|
|
137
|
+
'toilettage',
|
|
138
|
+
'banho e tosa',
|
|
139
|
+
'Hundesalon',
|
|
140
|
+
'toelettatura'
|
|
141
|
+
]
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
english: 'beauty salon',
|
|
145
|
+
names: [
|
|
146
|
+
'salón de belleza',
|
|
147
|
+
'institut de beauté',
|
|
148
|
+
'salão de beleza',
|
|
149
|
+
'Kosmetikstudio',
|
|
150
|
+
'centro estetico'
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
english: 'barber shop',
|
|
155
|
+
names: [
|
|
156
|
+
'barbería',
|
|
157
|
+
'barbearia',
|
|
158
|
+
'Barbier',
|
|
159
|
+
'barbiere'
|
|
160
|
+
]
|
|
161
|
+
},
|
|
162
|
+
{
|
|
163
|
+
english: 'auto repair',
|
|
164
|
+
names: [
|
|
165
|
+
'taller mecánico',
|
|
166
|
+
'oficina mecânica',
|
|
167
|
+
'Autowerkstatt',
|
|
168
|
+
'Kfz-Werkstatt',
|
|
169
|
+
'officina meccanica',
|
|
170
|
+
'autofficina'
|
|
171
|
+
]
|
|
172
|
+
},
|
|
173
|
+
{
|
|
174
|
+
english: 'dentist',
|
|
175
|
+
names: [
|
|
176
|
+
'dentista',
|
|
177
|
+
'clínica dental',
|
|
178
|
+
'dentiste',
|
|
179
|
+
'cabinet dentaire',
|
|
180
|
+
'Zahnarzt',
|
|
181
|
+
'Zahnarztpraxis',
|
|
182
|
+
'studio dentistico'
|
|
183
|
+
]
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
english: 'veterinary clinic',
|
|
187
|
+
names: [
|
|
188
|
+
'veterinaria',
|
|
189
|
+
'veterinario',
|
|
190
|
+
'vétérinaire',
|
|
191
|
+
'Tierarzt',
|
|
192
|
+
'Tierarztpraxis'
|
|
193
|
+
]
|
|
194
|
+
},
|
|
195
|
+
{
|
|
196
|
+
english: 'pharmacy',
|
|
197
|
+
names: [
|
|
198
|
+
'farmacia',
|
|
199
|
+
'pharmacie',
|
|
200
|
+
'Apotheke'
|
|
201
|
+
]
|
|
202
|
+
},
|
|
203
|
+
{
|
|
204
|
+
english: 'bookstore',
|
|
205
|
+
names: [
|
|
206
|
+
'librería',
|
|
207
|
+
'librairie',
|
|
208
|
+
'livraria',
|
|
209
|
+
'Buchhandlung'
|
|
210
|
+
]
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
english: 'photographer',
|
|
214
|
+
names: [
|
|
215
|
+
'fotógrafo',
|
|
216
|
+
'fotógrafa',
|
|
217
|
+
'photographe',
|
|
218
|
+
'Fotograf',
|
|
219
|
+
'Fotografin'
|
|
220
|
+
]
|
|
221
|
+
},
|
|
222
|
+
{
|
|
223
|
+
english: 'plumber',
|
|
224
|
+
names: [
|
|
225
|
+
'fontanero',
|
|
226
|
+
'plomero',
|
|
227
|
+
'plombier',
|
|
228
|
+
'encanador',
|
|
229
|
+
'Klempner',
|
|
230
|
+
'idraulico'
|
|
231
|
+
]
|
|
232
|
+
},
|
|
233
|
+
{
|
|
234
|
+
english: 'cleaning service',
|
|
235
|
+
names: [
|
|
236
|
+
'servicio de limpieza',
|
|
237
|
+
'nettoyage',
|
|
238
|
+
'limpeza',
|
|
239
|
+
'Reinigung',
|
|
240
|
+
'impresa di pulizie'
|
|
241
|
+
]
|
|
242
|
+
}
|
|
243
|
+
];
|
|
244
|
+
/** A text's words, lowercase, without accents: "Panadería" and "panaderia" are one word. */ function foldedWords(text) {
|
|
245
|
+
return text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase().replace(/ß/g, 'ss').split(/[^a-z]+/).filter(Boolean);
|
|
246
|
+
}
|
|
247
|
+
/** Every listed name as its words, the longest first, so the longer of two at one word wins. */ const NAMES = AI_STOCK_BUSINESS_NOUNS.flatMap(({ english, names })=>names.map((name)=>({
|
|
248
|
+
words: foldedWords(name),
|
|
249
|
+
english
|
|
250
|
+
}))).sort((a, b)=>b.words.length - a.words.length);
|
|
251
|
+
/**
|
|
252
|
+
* The English words for the kind of business a text in another language
|
|
253
|
+
* names ({@link AI_STOCK_BUSINESS_NOUNS}): "bakery" for "Una panadería
|
|
254
|
+
* familiar de San Antonio con pan dulce". Empty when it names none listed.
|
|
255
|
+
*/ export function aiStockBusinessNoun(text) {
|
|
256
|
+
const words = foldedWords(text);
|
|
257
|
+
for(let at = 0; at < words.length; at += 1){
|
|
258
|
+
const found = NAMES.find((name)=>name.words.every((word, index)=>words[at + index] === word));
|
|
259
|
+
if (found) return found.english;
|
|
260
|
+
}
|
|
261
|
+
return '';
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
//# sourceMappingURL=ai-stock-business-nouns.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-stock-business-nouns.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\n/**\n * THE ENGLISH NAME OF A BUSINESS TYPE WRITTEN IN ANOTHER LANGUAGE (AGL-3779).\n *\n * The stock photo libraries are tagged in English, so a site in another\n * language is searched by an English subject (`aiStockSourceTerms`). The\n * business type the person typed is the surest word for what the site is\n * about, once it is English: \"Una panadería familiar … con pan dulce\" read\n * as an English noun phrase searched \"con pan dulce\" and placed the Río\n * Dulce, the kind of site picked (\"restaurant cafe\") placed a coffee mug as a\n * bakery's hero (jobs ih6kVvCGP1 and iGmqrEgyW4, beta.250), and a live plan's\n * photo words for a florist, \"wedding bouquets event flowers\", led with\n * \"wedding\". So a business this table names leads the search, ahead of the\n * plan's photo words, which decide only for a business it does not name.\n *\n * This table names the common kinds of local business in Spanish, French,\n * Portuguese, German and Italian, each with the English words a library is\n * searched by. It is deliberately small: a kind belongs here when people\n * start sites for it and its name is not already English. Words English\n * shares (\"café\", \"restaurant\", \"boutique\", \"pizzeria\") are left out, because\n * the guided start's own brief is English around the person's words (\"Make\n * it a restaurant & café site\") and must never decide the subject; such a\n * site falls through to the kind it picked, as before.\n *\n * A word matches whole, accents and case aside: \"panaderia\" and \"Panadería\"\n * meet, so a name two languages spell alike (\"farmacia\", \"fotógrafo\") is\n * listed once; \"pan\" never matches inside \"panadería\", and a German compound\n * (\"Familienbäckerei\") matches only if it is listed itself. The first listed\n * name the text says wins, the longer of two that start at the same word —\n * \"peluquería canina\" is a dog groomer, \"peluquería\" a hair salon — so the\n * head noun a Romance-language business type opens with decides.\n */\n\n/** A kind of business: the English words its photos are searched by, and its names in other languages. */\ninterface AiStockBusinessNoun {\n /** What a stock photo library is searched by: \"bakery\". */\n english: string\n /** Its names in es, fr, pt, de and it, as people write them. */\n names: readonly string[]\n}\n\nexport const AI_STOCK_BUSINESS_NOUNS: readonly AiStockBusinessNoun[] = [\n { english: 'bakery', names: ['panadería', 'boulangerie', 'padaria', 'Bäckerei', 'panetteria', 'panificio'] },\n { english: 'pastry shop', names: ['pastelería', 'repostería', 'pâtisserie', 'confeitaria', 'Konditorei', 'pasticceria'] },\n { english: 'tacos', names: ['taquería'] },\n { english: 'cafe', names: ['cafetería', 'caffetteria'] },\n { english: 'restaurant', names: ['restaurante', 'ristorante', 'Gaststätte'] },\n // A library knows the trattoria by its own name, a narrower search than \"restaurant\".\n { english: 'trattoria', names: ['trattoria', 'osteria'] },\n { english: 'butcher shop', names: ['carnicería', 'boucherie', 'açougue', 'Metzgerei', 'macelleria'] },\n { english: 'florist', names: ['floristería', 'florería', 'fleuriste', 'floricultura', 'Blumenladen', 'fioraio', 'fioreria'] },\n {\n english: 'hair salon',\n names: ['peluquería', 'salon de coiffure', 'coiffeur', 'coiffeuse', 'cabeleireiro', 'Friseur', 'Friseursalon', 'parrucchiere'],\n },\n { english: 'dog grooming', names: ['peluquería canina', 'toilettage', 'banho e tosa', 'Hundesalon', 'toelettatura'] },\n { english: 'beauty salon', names: ['salón de belleza', 'institut de beauté', 'salão de beleza', 'Kosmetikstudio', 'centro estetico'] },\n { english: 'barber shop', names: ['barbería', 'barbearia', 'Barbier', 'barbiere'] },\n { english: 'auto repair', names: ['taller mecánico', 'oficina mecânica', 'Autowerkstatt', 'Kfz-Werkstatt', 'officina meccanica', 'autofficina'] },\n { english: 'dentist', names: ['dentista', 'clínica dental', 'dentiste', 'cabinet dentaire', 'Zahnarzt', 'Zahnarztpraxis', 'studio dentistico'] },\n { english: 'veterinary clinic', names: ['veterinaria', 'veterinario', 'vétérinaire', 'Tierarzt', 'Tierarztpraxis'] },\n { english: 'pharmacy', names: ['farmacia', 'pharmacie', 'Apotheke'] },\n { english: 'bookstore', names: ['librería', 'librairie', 'livraria', 'Buchhandlung'] },\n { english: 'photographer', names: ['fotógrafo', 'fotógrafa', 'photographe', 'Fotograf', 'Fotografin'] },\n { english: 'plumber', names: ['fontanero', 'plomero', 'plombier', 'encanador', 'Klempner', 'idraulico'] },\n { english: 'cleaning service', names: ['servicio de limpieza', 'nettoyage', 'limpeza', 'Reinigung', 'impresa di pulizie'] },\n]\n\n/** A text's words, lowercase, without accents: \"Panadería\" and \"panaderia\" are one word. */\nfunction foldedWords(text: string): string[] {\n return text\n .normalize('NFD')\n .replace(/[̀-ͯ]/g, '')\n .toLowerCase()\n .replace(/ß/g, 'ss')\n .split(/[^a-z]+/)\n .filter(Boolean)\n}\n\n/** Every listed name as its words, the longest first, so the longer of two at one word wins. */\nconst NAMES: ReadonlyArray<{ words: string[]; english: string }> = AI_STOCK_BUSINESS_NOUNS.flatMap(({ english, names }) =>\n names.map((name) => ({ words: foldedWords(name), english })),\n).sort((a, b) => b.words.length - a.words.length)\n\n/**\n * The English words for the kind of business a text in another language\n * names ({@link AI_STOCK_BUSINESS_NOUNS}): \"bakery\" for \"Una panadería\n * familiar de San Antonio con pan dulce\". Empty when it names none listed.\n */\nexport function aiStockBusinessNoun(text: string): string {\n const words = foldedWords(text)\n for (let at = 0; at < words.length; at += 1) {\n const found = NAMES.find((name) => name.words.every((word, index) => words[at + index] === word))\n if (found) return found.english\n }\n return ''\n}\n"],"names":["AI_STOCK_BUSINESS_NOUNS","english","names","foldedWords","text","normalize","replace","toLowerCase","split","filter","Boolean","NAMES","flatMap","map","name","words","sort","a","b","length","aiStockBusinessNoun","at","found","find","every","word","index"],"mappings":"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"}
|
|
@@ -228,9 +228,13 @@ export interface AiBuildPlan {
|
|
|
228
228
|
* is in (AGL-3760): two to four words a stock photo library is searched by,
|
|
229
229
|
* the business's subject first — "bakery bread pastries" for "una panadería
|
|
230
230
|
* … con pan dulce, conchas". The libraries are tagged in English, so a site
|
|
231
|
-
* in another language searches by these rather than its own words
|
|
232
|
-
*
|
|
233
|
-
*
|
|
231
|
+
* in another language searches by these rather than its own words — unless
|
|
232
|
+
* its business type names a business the curated table knows in English
|
|
233
|
+
* (`aiStockBusinessNoun`), which leads — and its plan is asked for them
|
|
234
|
+
* again once when it gave none (AGL-3779). Absent on every other kind's
|
|
235
|
+
* plan, on one that said null, on one whose words were not plain English
|
|
236
|
+
* letters, and on a plan in another language whose re-ask still gave none,
|
|
237
|
+
* whose photos then fall back to its kind of site.
|
|
234
238
|
*/
|
|
235
239
|
photoWords?: string;
|
|
236
240
|
}
|
|
@@ -451,7 +451,17 @@ const LANGUAGE_SCHEMA = nullableString("The language the brief is written in, wh
|
|
|
451
451
|
const words = text.split(/[\s,&]+/).map((word)=>word.replace(/^[-']+|[-']+$/g, '')).filter((word)=>word.length > 1);
|
|
452
452
|
return words.length ? words.slice(0, AI_PLAN_PHOTO_WORDS_MAX).join(' ') : null;
|
|
453
453
|
}
|
|
454
|
-
|
|
454
|
+
/**
|
|
455
|
+
* Required whenever the plan's language is not English (AGL-3779), the field
|
|
456
|
+
* beside it. Asked "for a brief not in English", two Spanish bakeries' plans
|
|
457
|
+
* said `es` and gave none (jobs ih6kVvCGP1, iGmqrEgyW4): a guided start's
|
|
458
|
+
* brief is English sentences around the person's own words. A strict schema
|
|
459
|
+
* has no conditional keyword, so the condition is said here and held by the
|
|
460
|
+
* plan step (`aiSitePhotoWordsCheck`), which re-asks once. The kind of
|
|
461
|
+
* business comes first because the first word is the subject every photo is
|
|
462
|
+
* searched by (`aiStockPhotoWordsSubject`): asked for the most specific word
|
|
463
|
+
* first, a florist's live plan wrote "wedding bouquets event flowers".
|
|
464
|
+
*/ const PHOTO_WORDS_SCHEMA = nullableString('Required when language is not en: 2-4 English words, the kind of business first, then what it sells, e.g. florist wedding bouquets; never a place or the business name. Null when language is en.');
|
|
455
465
|
/**
|
|
456
466
|
* Any plan tool with the site's language (AGL-3750) and its photo words in
|
|
457
467
|
* English (AGL-3760), offered only to a `site` job, whose guided start sets
|