@aglyn/plugins-ai 1.0.0-beta.239 → 1.0.0-beta.241
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-job-links.d.ts +17 -0
- package/src/lib/components/ai-job-links.js +63 -0
- package/src/lib/components/ai-job-links.js.map +1 -1
- package/src/lib/components/ai-job-plan.component.js +8 -1
- package/src/lib/components/ai-job-plan.component.js.map +1 -1
- package/src/lib/components/ai-job-requests.d.ts +5 -0
- package/src/lib/components/ai-job-requests.js +4 -2
- package/src/lib/components/ai-job-requests.js.map +1 -1
- package/src/lib/components/ai-site-build-page.component.js +7 -1
- package/src/lib/components/ai-site-build-page.component.js.map +1 -1
- package/src/lib/components/ai-store-finish-card.component.d.ts +28 -0
- package/src/lib/components/ai-store-finish-card.component.js +116 -0
- package/src/lib/components/ai-store-finish-card.component.js.map +1 -0
- package/src/lib/components/assist-build-card.component.js +12 -1
- package/src/lib/components/assist-build-card.component.js.map +1 -1
- package/src/lib/components/assist-panel.component.js +14 -2
- package/src/lib/components/assist-panel.component.js.map +1 -1
- package/src/lib/jobs/ai-job-build-step.d.ts +45 -1
- package/src/lib/jobs/ai-job-build-step.js +283 -7
- package/src/lib/jobs/ai-job-build-step.js.map +1 -1
- package/src/lib/jobs/ai-job-drafts.d.ts +9 -1
- package/src/lib/jobs/ai-job-drafts.js +4 -1
- package/src/lib/jobs/ai-job-drafts.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-language.d.ts +3 -0
- package/src/lib/jobs/ai-job-layout-language.js +11 -4
- package/src/lib/jobs/ai-job-layout-language.js.map +1 -1
- package/src/lib/jobs/ai-job-layout-step.js +3 -1
- package/src/lib/jobs/ai-job-layout-step.js.map +1 -1
- package/src/lib/jobs/ai-job-page-language.d.ts +2 -1
- package/src/lib/jobs/ai-job-page-language.js +26 -9
- package/src/lib/jobs/ai-job-page-language.js.map +1 -1
- package/src/lib/jobs/ai-job-page-sections.d.ts +11 -0
- package/src/lib/jobs/ai-job-page-sections.js +53 -5
- package/src/lib/jobs/ai-job-page-sections.js.map +1 -1
- package/src/lib/jobs/ai-job-page-step.d.ts +2 -1
- package/src/lib/jobs/ai-job-page-step.js +51 -10
- package/src/lib/jobs/ai-job-page-step.js.map +1 -1
- package/src/lib/jobs/ai-job-plan-step.d.ts +12 -0
- package/src/lib/jobs/ai-job-plan-step.js +41 -7
- package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-datasets.d.ts +89 -2
- package/src/lib/jobs/ai-job-site-datasets.js +239 -15
- package/src/lib/jobs/ai-job-site-datasets.js.map +1 -1
- package/src/lib/jobs/ai-job-site-step.d.ts +18 -2
- package/src/lib/jobs/ai-job-site-step.js +109 -22
- package/src/lib/jobs/ai-job-site-step.js.map +1 -1
- package/src/lib/jobs/ai-job-site-store-pages.d.ts +75 -0
- package/src/lib/jobs/ai-job-site-store-pages.js +195 -0
- package/src/lib/jobs/ai-job-site-store-pages.js.map +1 -0
- package/src/lib/jobs/ai-job-store-links-layout.d.ts +71 -0
- package/src/lib/jobs/ai-job-store-links-layout.js +95 -0
- package/src/lib/jobs/ai-job-store-links-layout.js.map +1 -0
- package/src/lib/jobs/ai-layout-stock-photos.d.ts +69 -3
- package/src/lib/jobs/ai-layout-stock-photos.js +603 -42
- package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
- package/src/lib/jobs/ai-site-publish.d.ts +18 -0
- package/src/lib/jobs/ai-site-publish.js +76 -15
- package/src/lib/jobs/ai-site-publish.js.map +1 -1
- package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.d.ts +43 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.js +61 -0
- package/src/lib/jobs/fixtures/ai-stock-photo-ember-oak-hits.js.map +1 -0
- package/src/lib/layout-language/ai-layout-compiler.js +25 -2
- package/src/lib/layout-language/ai-layout-compiler.js.map +1 -1
- package/src/lib/layout-language/ai-layout-frame.d.ts +10 -0
- package/src/lib/layout-language/ai-layout-frame.js +58 -4
- package/src/lib/layout-language/ai-layout-frame.js.map +1 -1
- package/src/lib/layout-language/ai-layout-listings.d.ts +6 -0
- package/src/lib/layout-language/ai-layout-listings.js +3 -0
- package/src/lib/layout-language/ai-layout-listings.js.map +1 -1
- package/src/lib/layout-language/ai-layout-pictures.js +12 -4
- package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
- package/src/lib/model/ai-build-job.d.ts +2 -0
- package/src/lib/model/ai-build-job.js +23 -3
- package/src/lib/model/ai-build-job.js.map +1 -1
- package/src/lib/model/ai-build-plan.d.ts +7 -0
- package/src/lib/model/ai-build-plan.js.map +1 -1
- package/src/lib/model/ai-build-progress.js +3 -1
- package/src/lib/model/ai-build-progress.js.map +1 -1
- package/src/lib/model/ai-build-store-pages.d.ts +133 -0
- package/src/lib/model/ai-build-store-pages.js +209 -0
- package/src/lib/model/ai-build-store-pages.js.map +1 -0
- package/src/lib/model/ai-layout-store-links.d.ts +64 -0
- package/src/lib/model/ai-layout-store-links.js +165 -0
- package/src/lib/model/ai-layout-store-links.js.map +1 -0
- package/src/lib/model/ai-site-inventory.d.ts +5 -0
- package/src/lib/model/ai-site-inventory.js.map +1 -1
- package/src/lib/model/ai-site-store-pages.d.ts +192 -0
- package/src/lib/model/ai-site-store-pages.js +383 -0
- package/src/lib/model/ai-site-store-pages.js.map +1 -0
- package/src/lib/runtime/ai-doctrine-validators.d.ts +44 -0
- package/src/lib/runtime/ai-doctrine-validators.js +177 -0
- package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
- package/src/lib/runtime/ai-doctrine.js +3 -2
- package/src/lib/runtime/ai-doctrine.js.map +1 -1
- package/src/lib/runtime/site-inventory.js +8 -3
- package/src/lib/runtime/site-inventory.js.map +1 -1
- package/src/lib/testing/stand-in-dataset-index.js +8 -4
- package/src/lib/testing/stand-in-dataset-index.js.map +1 -1
|
@@ -22,6 +22,11 @@ import { AI_STEP_TIERS } from "../providers/catalog.js";
|
|
|
22
22
|
import { aiModelForStep } from "../providers/routing.js";
|
|
23
23
|
import { AI_DATASET_MAX_TOKENS, AI_DATASET_STEP, aiDatasetDraftContent, generateAiDataset } from "../runtime/ai-dataset-generation.js";
|
|
24
24
|
import { aiLayoutListingId, aiLayoutRecordsPlacements } from "../layout-language/ai-layout-listings.js";
|
|
25
|
+
import { aiLayoutStarterPhotos } from "../layout-language/ai-layout-pictures.js";
|
|
26
|
+
import { aiSiteWords } from "../model/ai-site-job.js";
|
|
27
|
+
import { aiOriginJobId } from "./ai-job-draft-ids.js";
|
|
28
|
+
import { aiSiteProductPhotoSrc } from "./ai-job-site-content.js";
|
|
29
|
+
import { aiLayoutStockPhotoSource } from "./ai-layout-stock-photos.js";
|
|
25
30
|
import { AI_DATASET_DRAFT_RESOURCE } from "./ai-build-unit-outcome.js";
|
|
26
31
|
import { aiJobStepBudget } from "./ai-job-budget.js";
|
|
27
32
|
import { aiGenerationSpent, aiUnspentOutcome } from "./ai-job-generation.js";
|
|
@@ -49,10 +54,20 @@ import { aiPluginDraftAdmissionRefusal } from "./ai-job-plugin-drafts.js";
|
|
|
49
54
|
* has: the member's role and `data.manage`, `release_data_store`,
|
|
50
55
|
* `dataStore` (Starter and up), `datasetsPerOrg` counted inside the create,
|
|
51
56
|
* `recordsPerDataset` and the storage band.
|
|
57
|
+
* - PICTURED where the plan lists it the way a gallery is listed (Zach,
|
|
58
|
+
* 2026-10-10: a ceramic artist's "Selected work" came back as text-only
|
|
59
|
+
* cards, where it had been an image-led gallery): a portfolio's pieces, a
|
|
60
|
+
* team, a menu, classes and events, and services or offerings whose
|
|
61
|
+
* section says it shows them in pictures (`aiSiteDatasetPicturesOf`). Such
|
|
62
|
+
* a dataset gets an Image field, and each record a stock photo of its own
|
|
63
|
+
* name in the site's craft, copied into the site's library — never one the
|
|
64
|
+
* job already placed, else a starter photo — searched in code, so it
|
|
65
|
+
* costs no credits (`aiSiteDatasetRecordPhotos`).
|
|
52
66
|
* - LISTED by the pages built after it: each section naming it repeats over
|
|
53
67
|
* the dataset (`aiSiteDatasetListings`, a `records` listing the layout
|
|
54
|
-
* compiler draws
|
|
55
|
-
*
|
|
68
|
+
* compiler draws, its card led by the record's photo where it has one),
|
|
69
|
+
* and a page the plan made its record template binds its fields by id,
|
|
70
|
+
* its photo the record's, and keeps the address field the writer added.
|
|
56
71
|
*
|
|
57
72
|
* Where datasets cannot be created — the Free taste, Starter's two used up,
|
|
58
73
|
* the data store not released — the plan is told so and creates none, so its
|
|
@@ -63,6 +78,29 @@ import { aiPluginDraftAdmissionRefusal } from "./ai-job-plugin-drafts.js";
|
|
|
63
78
|
/** The resource the data plugin's writer is registered under. */ export const AI_SITE_DATASET_RESOURCE = AI_DATASET_DRAFT_RESOURCE;
|
|
64
79
|
/** What the site's plugin list calls the plugin, for "Turn on Data for this site". */ const DATA_PLUGIN_LABEL = 'Data';
|
|
65
80
|
/** The input a dataset unit's own job carries what it needs in. */ export const AI_SITE_DATASET_INPUT = 'siteDataset';
|
|
81
|
+
/** A list of questions, voices or plain facts: read, never pictured. */ const READ_ONLY_LIST = /\b(faqs?|questions?|q ?& ?a|answers?|testimonials?|reviews?|quotes?|voices|hours|opening|steps?|process|policies|policy|terms|stats?|numbers|figures|milestones|timeline|values|benefits|reasons|features|requirements|checklist|ingredients|donations?|needs|partners|sponsors|supporters|roles|positions|jobs|openings)\b/i;
|
|
82
|
+
/** A list of people: its photos are of the business's people. */ const PEOPLE_LIST = /\b(team|staff|people|crew|instructors?|teachers?|tutors?|stylists?|barbers?|therapists?|coaches?|trainers?|chefs?|doctors?|dentists?|hygienists?|practitioners?|artists?|musicians?|performers?|speakers?|founders?|members?)\b/i;
|
|
83
|
+
/** A list a visitor looks at before reading: pictured wherever it is listed. */ const PICTURED_LIST = /\b(portfolio|pieces?|works?|projects?|gallery|galleries|collections?|series|menus?|dishes|plates|drinks|cocktails|wines?|beers?|coffees?|pastries|cakes|products?|items|events?|classes|class|workshops?|courses?|retreats?|tours?|trips?|adventures?|experiences?|rooms?|suites?|cabins?|properties|listings|homes|venues?|spaces?|recipes?|artworks?|paintings?|prints?|photos?|photographs?|designs?|commissions?|builds?|vehicles?|animals?|pets?|plants?|flowers?|bouquets?|arrangements?|case studies)\b/i;
|
|
84
|
+
/** A section that says it shows its items in pictures: a gallery, a grid of photos, tiles. */ const PICTURED_SECTION = /\b(gallery|galleries|grid|images?|photos?|photographs?|pictures?|lightbox|portfolio|showcase|tiles?|visuals?|lookbook|carousel|slideshow|mosaic|thumbnails?)\b/i;
|
|
85
|
+
/**
|
|
86
|
+
* Whether a dataset's records carry a photo, read off the plan (AGL-3616):
|
|
87
|
+
* its name and the names of the sections that list it. Questions, voices and
|
|
88
|
+
* plain facts never; people as people; a list a visitor looks at — pieces,
|
|
89
|
+
* dishes, classes, events, rooms — always; any other list (services,
|
|
90
|
+
* offerings, programs) only where a section that lists it says it shows them
|
|
91
|
+
* in pictures, or names one of those. A dataset no page lists is not
|
|
92
|
+
* pictured. Pure.
|
|
93
|
+
*/ export function aiSiteDatasetPicturesOf(dataset, sections) {
|
|
94
|
+
if (!sections.length) return null;
|
|
95
|
+
const own = dataset.name;
|
|
96
|
+
if (READ_ONLY_LIST.test(own)) return null;
|
|
97
|
+
if (PEOPLE_LIST.test(own)) return 'people';
|
|
98
|
+
if (PICTURED_LIST.test(own)) return 'things';
|
|
99
|
+
if (sections.some((section)=>READ_ONLY_LIST.test(section) && !PICTURED_SECTION.test(section))) return null;
|
|
100
|
+
if (sections.some((section)=>PEOPLE_LIST.test(section))) return 'people';
|
|
101
|
+
if (sections.some((section)=>PICTURED_LIST.test(section) || PICTURED_SECTION.test(section))) return 'things';
|
|
102
|
+
return null;
|
|
103
|
+
}
|
|
66
104
|
/** What a dataset row says when its design could not be written: our failure, refunded. */ export const AI_SITE_DATASET_NOT_WRITTEN_COPY = 'This dataset could not be added this time.';
|
|
67
105
|
/** The note a written dataset carries on the job's page. */ export function aiSiteDatasetNote(records) {
|
|
68
106
|
return `${records} ${records === 1 ? 'record' : 'records'} to start, in Data. Edit them there and every page that lists them follows.`;
|
|
@@ -84,14 +122,18 @@ const str = (value)=>typeof value === 'string' ? value.trim() : '';
|
|
|
84
122
|
}
|
|
85
123
|
/** Where the plan lists a dataset, in words its design reads, whether a page is its record template, and the form that writes to it. */ export function aiSiteDatasetInputOf(dataset, screens, create = []) {
|
|
86
124
|
const shownIn = [];
|
|
125
|
+
const sectionNames = [];
|
|
87
126
|
for (const screen of screens){
|
|
88
127
|
for (const section of screen.sections){
|
|
89
128
|
if (!section.uses.some((ref)=>namesDataset(ref, dataset.name))) continue;
|
|
90
129
|
shownIn.push(`${screen.title} › ${section.name}${section.items ? ` (${section.items} items)` : ''}`);
|
|
130
|
+
sectionNames.push(section.name);
|
|
91
131
|
}
|
|
92
132
|
}
|
|
93
133
|
const recordPages = screens.some((screen)=>!!screen.record && namesDataset(screen.record.dataset, dataset.name));
|
|
94
134
|
const form = create.find((entry)=>entry.kind === 'form' && !!entry.writesTo && namesDataset(entry.writesTo, dataset.name));
|
|
135
|
+
// A form's dataset holds its submissions: nobody's photo.
|
|
136
|
+
const pictures = form ? null : aiSiteDatasetPicturesOf(dataset, sectionNames);
|
|
95
137
|
return _extends({
|
|
96
138
|
shownIn: shownIn.slice(0, 8),
|
|
97
139
|
recordPages
|
|
@@ -100,6 +142,8 @@ const str = (value)=>typeof value === 'string' ? value.trim() : '';
|
|
|
100
142
|
name: form.name,
|
|
101
143
|
fields: form.fields.slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX)
|
|
102
144
|
}
|
|
145
|
+
} : {}, pictures ? {
|
|
146
|
+
pictures
|
|
103
147
|
} : {});
|
|
104
148
|
}
|
|
105
149
|
/** Whether a plan screen is the record template of a dataset the plan creates, and which. */ export function aiSiteRecordTemplateOf(screen) {
|
|
@@ -120,6 +164,8 @@ function datasetInputOf(job) {
|
|
|
120
164
|
name: str(form.name),
|
|
121
165
|
fields: Array.isArray(form.fields) ? form.fields.map(str).filter(Boolean).slice(0, AI_SITE_FORM_DATASET_FIELDS_MAX) : []
|
|
122
166
|
}
|
|
167
|
+
} : {}, raw.pictures === 'things' || raw.pictures === 'people' ? {
|
|
168
|
+
pictures: raw.pictures
|
|
123
169
|
} : {});
|
|
124
170
|
}
|
|
125
171
|
/** The most fields a form's dataset is designed with: the data plugin writer's own ceiling is higher. */ export const AI_SITE_FORM_DATASET_FIELDS_MAX = 12;
|
|
@@ -171,6 +217,135 @@ const limitReview = (message)=>({
|
|
|
171
217
|
message,
|
|
172
218
|
findings: []
|
|
173
219
|
});
|
|
220
|
+
/** The wall clock a dataset's photos may take inside its pass: the 20 seconds a page's pictures had (AGL-3660). */ export const AI_SITE_DATASET_PHOTOS_BUDGET_MS = 20000;
|
|
221
|
+
/** The field a pictured dataset's photo is kept in, where the plan gave it none. */ export const AI_SITE_DATASET_IMAGE_FIELD = 'Image';
|
|
222
|
+
/** A planned field that already names a record's photo. */ const IMAGE_FIELD_NAME = /^(?:main |cover |hero |featured? )?(?:image|photo|picture|photograph|thumbnail|headshot|portrait|cover)s?$/i;
|
|
223
|
+
/**
|
|
224
|
+
* A photo for each record of a pictured dataset (AGL-3616), in order: a stock
|
|
225
|
+
* photo of the record's own name, in the site's craft ("ceramic speckled
|
|
226
|
+
* serving bowl"), copied into the site's library, where the deployment has a
|
|
227
|
+
* stock library — never twice in the dataset nor one another part of the job
|
|
228
|
+
* placed, inside {@link AI_SITE_DATASET_PHOTOS_BUDGET_MS} — else a starter
|
|
229
|
+
* photo, as a page's empty picture takes one. A team is searched as the
|
|
230
|
+
* business's people. The photo is kept as the asset's CDN path, the form a
|
|
231
|
+
* product keeps (`aiSiteProductPhotoSrc`), so a replace in the library still
|
|
232
|
+
* reaches it. No AI model is asked, so no credits; never throws.
|
|
233
|
+
*/ export async function aiSiteDatasetRecordPhotos(input) {
|
|
234
|
+
const { job } = input;
|
|
235
|
+
if (!input.names.length || !job.hostId) return input.names.map(()=>({
|
|
236
|
+
src: null,
|
|
237
|
+
placed: null
|
|
238
|
+
}));
|
|
239
|
+
const people = input.pictures === 'people';
|
|
240
|
+
const slots = input.names.map((name, index)=>({
|
|
241
|
+
imageId: `record${index}`,
|
|
242
|
+
frameId: null,
|
|
243
|
+
iconId: null,
|
|
244
|
+
alt: name.trim() || input.name,
|
|
245
|
+
// The record card's own shape: a team's portraits stand, pieces sit wide.
|
|
246
|
+
aspect: people ? 4 / 5 : 4 / 3,
|
|
247
|
+
sectionIndex: 0,
|
|
248
|
+
role: people ? 'about' : 'gallery'
|
|
249
|
+
}));
|
|
250
|
+
const seed = `${job.$id}:records`;
|
|
251
|
+
let found = [];
|
|
252
|
+
try {
|
|
253
|
+
var _input_stockPhotos;
|
|
254
|
+
const source = ((_input_stockPhotos = input.stockPhotos) != null ? _input_stockPhotos : aiLayoutStockPhotoSource)(_extends({
|
|
255
|
+
hostId: job.hostId,
|
|
256
|
+
uid: job.createdBy,
|
|
257
|
+
seed,
|
|
258
|
+
business: aiSiteWords(job.inputs).about || job.brief,
|
|
259
|
+
sectionNames: [
|
|
260
|
+
input.name
|
|
261
|
+
],
|
|
262
|
+
jobId: aiOriginJobId(job),
|
|
263
|
+
// Each record may try its name, its object and the site's world.
|
|
264
|
+
searches: slots.length * 3
|
|
265
|
+
}, input.signal ? {
|
|
266
|
+
signal: input.signal
|
|
267
|
+
} : {}), {
|
|
268
|
+
budgetMs: AI_SITE_DATASET_PHOTOS_BUDGET_MS
|
|
269
|
+
});
|
|
270
|
+
if (source) found = await source(slots);
|
|
271
|
+
} catch (error) {
|
|
272
|
+
console.warn('ai site dataset: the stock photos failed; starter photos fill them', {
|
|
273
|
+
error: String(error)
|
|
274
|
+
});
|
|
275
|
+
}
|
|
276
|
+
const starters = aiLayoutStarterPhotos(slots, seed);
|
|
277
|
+
const hostId = job.hostId;
|
|
278
|
+
return slots.map((_slot, index)=>{
|
|
279
|
+
var _ref;
|
|
280
|
+
var _found_index, _found_index1, _starters_index;
|
|
281
|
+
const stock = aiSiteProductPhotoSrc((_found_index = found[index]) == null ? void 0 : _found_index.src, hostId);
|
|
282
|
+
if (stock) return {
|
|
283
|
+
src: stock,
|
|
284
|
+
placed: (_ref = (_found_index1 = found[index]) == null ? void 0 : _found_index1.src) != null ? _ref : null
|
|
285
|
+
};
|
|
286
|
+
return {
|
|
287
|
+
src: aiSiteProductPhotoSrc((_starters_index = starters[index]) == null ? void 0 : _starters_index.src, hostId),
|
|
288
|
+
placed: null
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* A designed dataset's content with its records' photos (AGL-3616): the
|
|
294
|
+
* planned field that names a photo ("Image", "Photo") becomes the data
|
|
295
|
+
* plugin's `image` field, else one called "Image" is added after the others,
|
|
296
|
+
* and each record holds its photo there; a record with none holds nothing.
|
|
297
|
+
* Pure.
|
|
298
|
+
*/ export function aiSiteDatasetContentWithPhotos(content, photos) {
|
|
299
|
+
const fields = Array.isArray(content['fields']) ? content['fields'] : [];
|
|
300
|
+
const named = fields.find((field)=>IMAGE_FIELD_NAME.test(str(field.name)));
|
|
301
|
+
const fieldName = named ? named.name : AI_SITE_DATASET_IMAGE_FIELD;
|
|
302
|
+
const nextFields = named ? fields.map((field)=>field === named ? _extends({}, field, {
|
|
303
|
+
type: 'image'
|
|
304
|
+
}) : field) : [
|
|
305
|
+
...fields,
|
|
306
|
+
{
|
|
307
|
+
name: AI_SITE_DATASET_IMAGE_FIELD,
|
|
308
|
+
type: 'image'
|
|
309
|
+
}
|
|
310
|
+
];
|
|
311
|
+
const records = Array.isArray(content['records']) ? content['records'] : [];
|
|
312
|
+
return _extends({}, content, {
|
|
313
|
+
fields: nextFields,
|
|
314
|
+
records: records.map((record, index)=>{
|
|
315
|
+
const next = _extends({}, record);
|
|
316
|
+
delete next[fieldName];
|
|
317
|
+
const photo = photos[index];
|
|
318
|
+
return photo ? _extends({}, next, {
|
|
319
|
+
[fieldName]: photo
|
|
320
|
+
}) : next;
|
|
321
|
+
})
|
|
322
|
+
});
|
|
323
|
+
}
|
|
324
|
+
/**
|
|
325
|
+
* The fields of a designed dataset that its records leave empty on most of
|
|
326
|
+
* them — every record, or more than half — by the id the data plugin gave
|
|
327
|
+
* each (AGL-3616). Its first field is the record's name and is never one. The
|
|
328
|
+
* live low-tide-hollow start (beta.239) seeded its tour dates with no venue,
|
|
329
|
+
* rightly inventing none, and its cards bound the venue as their eyebrow.
|
|
330
|
+
*/ export function aiDatasetSparseFields(dataset, written) {
|
|
331
|
+
if (!dataset.records.length) return [];
|
|
332
|
+
const idOf = (name, column)=>{
|
|
333
|
+
var _ref, _ref1;
|
|
334
|
+
var _written_find, _written_column;
|
|
335
|
+
return (_ref = (_ref1 = (_written_find = written.find((field)=>field.name.trim().toLowerCase() === name.trim().toLowerCase())) == null ? void 0 : _written_find.id) != null ? _ref1 : (_written_column = written[column]) == null ? void 0 : _written_column.id) != null ? _ref : null;
|
|
336
|
+
};
|
|
337
|
+
return dataset.fields.flatMap((field, column)=>{
|
|
338
|
+
if (column === 0) return [];
|
|
339
|
+
const filled = dataset.records.filter((values)=>{
|
|
340
|
+
var _values_column;
|
|
341
|
+
return ((_values_column = values[column]) != null ? _values_column : '').trim();
|
|
342
|
+
}).length;
|
|
343
|
+
const id = idOf(field.name, column);
|
|
344
|
+
return id && filled * 2 <= dataset.records.length ? [
|
|
345
|
+
id
|
|
346
|
+
] : [];
|
|
347
|
+
});
|
|
348
|
+
}
|
|
174
349
|
function proposalOf(output) {
|
|
175
350
|
var _output_proposal;
|
|
176
351
|
const raw = (_output_proposal = output.proposal) != null ? _output_proposal : {};
|
|
@@ -181,7 +356,10 @@ function proposalOf(output) {
|
|
|
181
356
|
type: str(field.type) || 'text'
|
|
182
357
|
})) : [],
|
|
183
358
|
recordNames: Array.isArray(raw.recordNames) ? raw.recordNames.map(str).filter(Boolean).slice(0, 12) : [],
|
|
184
|
-
addressField: str(raw.addressField) || null
|
|
359
|
+
addressField: str(raw.addressField) || null,
|
|
360
|
+
imageField: str(raw.imageField) || null,
|
|
361
|
+
photos: Array.isArray(raw.photos) ? raw.photos.map(str).filter((src)=>src.startsWith('media:')).slice(0, 24) : [],
|
|
362
|
+
sparseFields: Array.isArray(raw.sparseFields) ? raw.sparseFields.map(str).filter(Boolean) : []
|
|
185
363
|
};
|
|
186
364
|
}
|
|
187
365
|
/**
|
|
@@ -190,11 +368,12 @@ function proposalOf(output) {
|
|
|
190
368
|
* plugin, under the creation's own id. A pass repeated after its write finds
|
|
191
369
|
* the dataset the writer wrote and reports it again, spending nothing.
|
|
192
370
|
*/ export function createAiSiteDatasetRunner(deps = {}) {
|
|
193
|
-
var _deps_generate, _deps_writerFor;
|
|
371
|
+
var _deps_generate, _deps_writerFor, _deps_photos;
|
|
194
372
|
const generate = (_deps_generate = deps.generate) != null ? _deps_generate : generateAiDataset;
|
|
195
373
|
const writerFor = (_deps_writerFor = deps.writerFor) != null ? _deps_writerFor : pluginResourceDraftWriter;
|
|
374
|
+
const photosFor = (_deps_photos = deps.photos) != null ? _deps_photos : aiSiteDatasetRecordPhotos;
|
|
196
375
|
return async (context)=>{
|
|
197
|
-
var _ref, _context_org, _facts_fields, _facts_addressField, _facts_records;
|
|
376
|
+
var _ref, _context_org, _facts_fields, _facts_addressField, _facts_fields1, _facts_records;
|
|
198
377
|
var _job_plan_create, _job_plan;
|
|
199
378
|
const { job, firestore, signal } = context;
|
|
200
379
|
const model = (_ref = context.modelFor == null ? void 0 : context.modelFor.call(context, AI_DATASET_STEP)) != null ? _ref : aiModelForStep(AI_DATASET_STEP);
|
|
@@ -228,12 +407,13 @@ function proposalOf(output) {
|
|
|
228
407
|
id: job.$id
|
|
229
408
|
});
|
|
230
409
|
if (written) {
|
|
231
|
-
var
|
|
410
|
+
var _facts_fields2, _facts_addressField1, _facts_imageField;
|
|
232
411
|
const facts = written.facts;
|
|
233
412
|
const again = output(written.id, written.name || creation.name, {
|
|
234
|
-
fields: (
|
|
413
|
+
fields: (_facts_fields2 = facts.fields) != null ? _facts_fields2 : [],
|
|
235
414
|
recordNames: [],
|
|
236
|
-
addressField: (_facts_addressField1 = facts.addressField) != null ? _facts_addressField1 : null
|
|
415
|
+
addressField: (_facts_addressField1 = facts.addressField) != null ? _facts_addressField1 : null,
|
|
416
|
+
imageField: (_facts_imageField = facts.imageField) != null ? _facts_imageField : null
|
|
237
417
|
}, 0);
|
|
238
418
|
return aiUnspentOutcome(model, {
|
|
239
419
|
outputs: [
|
|
@@ -246,7 +426,7 @@ function proposalOf(output) {
|
|
|
246
426
|
// A form's dataset (AGL-3616): its records are the submissions, so it is
|
|
247
427
|
// designed from the plan with no model, and starts empty.
|
|
248
428
|
if (input.forForm) {
|
|
249
|
-
var _context_org1,
|
|
429
|
+
var _context_org1, _facts_fields3;
|
|
250
430
|
const content = aiSiteFormDatasetContent(creation.name, creation.fields, input.forForm);
|
|
251
431
|
const checked = keeper.writer.check(content, {
|
|
252
432
|
hostId: job.hostId
|
|
@@ -283,7 +463,7 @@ function proposalOf(output) {
|
|
|
283
463
|
return aiUnspentOutcome(model, {
|
|
284
464
|
outputs: [
|
|
285
465
|
_extends({}, output(result.id, result.name, {
|
|
286
|
-
fields: (
|
|
466
|
+
fields: (_facts_fields3 = facts.fields) != null ? _facts_fields3 : [],
|
|
287
467
|
recordNames: [],
|
|
288
468
|
addressField: null
|
|
289
469
|
}, 0), {
|
|
@@ -312,9 +492,27 @@ function proposalOf(output) {
|
|
|
312
492
|
if (generation.status === 'needs_input') return _extends({}, spent, {
|
|
313
493
|
failure: generation.message
|
|
314
494
|
});
|
|
315
|
-
const
|
|
495
|
+
const designed = aiDatasetDraftContent(creation.name, generation.value, {
|
|
316
496
|
recordPages: input.recordPages
|
|
317
497
|
});
|
|
498
|
+
// A list a visitor looks at keeps its records' photos (AGL-3616): searched
|
|
499
|
+
// in code, never asked of the model, so they cost no credits.
|
|
500
|
+
const photos = input.pictures ? await photosFor(_extends({
|
|
501
|
+
job,
|
|
502
|
+
name: creation.name,
|
|
503
|
+
names: generation.value.records.map((values)=>{
|
|
504
|
+
var _values_;
|
|
505
|
+
return (_values_ = values[0]) != null ? _values_ : '';
|
|
506
|
+
}),
|
|
507
|
+
pictures: input.pictures
|
|
508
|
+
}, signal ? {
|
|
509
|
+
signal
|
|
510
|
+
} : {})).catch(()=>[]) : [];
|
|
511
|
+
const content = input.pictures ? aiSiteDatasetContentWithPhotos(designed, generation.value.records.map((_values, index)=>{
|
|
512
|
+
var _ref;
|
|
513
|
+
var _photos_index;
|
|
514
|
+
return (_ref = (_photos_index = photos[index]) == null ? void 0 : _photos_index.src) != null ? _ref : null;
|
|
515
|
+
})) : designed;
|
|
318
516
|
// The data plugin's own rules, before anything is written: content we
|
|
319
517
|
// made that its model refuses is our failure, refunded.
|
|
320
518
|
const checked = keeper.writer.check(content, {
|
|
@@ -350,14 +548,23 @@ function proposalOf(output) {
|
|
|
350
548
|
});
|
|
351
549
|
}
|
|
352
550
|
const facts = result.facts;
|
|
353
|
-
const
|
|
551
|
+
const placed = photos.flatMap((photo)=>photo.placed ? [
|
|
552
|
+
photo.placed
|
|
553
|
+
] : []);
|
|
554
|
+
const proposal = _extends({
|
|
354
555
|
fields: (_facts_fields = facts.fields) != null ? _facts_fields : [],
|
|
355
556
|
recordNames: generation.value.records.map((values)=>{
|
|
356
557
|
var _values_;
|
|
357
558
|
return (_values_ = values[0]) != null ? _values_ : '';
|
|
358
559
|
}).filter(Boolean).slice(0, 12),
|
|
359
560
|
addressField: (_facts_addressField = facts.addressField) != null ? _facts_addressField : null
|
|
360
|
-
}
|
|
561
|
+
}, facts.imageField ? {
|
|
562
|
+
imageField: facts.imageField
|
|
563
|
+
} : {}, placed.length ? {
|
|
564
|
+
photos: placed
|
|
565
|
+
} : {}, {
|
|
566
|
+
sparseFields: aiDatasetSparseFields(generation.value, (_facts_fields1 = facts.fields) != null ? _facts_fields1 : [])
|
|
567
|
+
});
|
|
361
568
|
return _extends({}, spent, {
|
|
362
569
|
outputs: [
|
|
363
570
|
output(result.id, result.name, proposal, (_facts_records = facts.records) != null ? _facts_records : generation.value.records.length)
|
|
@@ -456,6 +663,8 @@ export const runAiSiteDatasetUnit = createAiSiteDatasetRunner();
|
|
|
456
663
|
datasetId: dataset.id
|
|
457
664
|
}, ((_dataset_fields = dataset.fields) == null ? void 0 : _dataset_fields.length) ? {
|
|
458
665
|
fields: dataset.fields
|
|
666
|
+
} : {}, dataset.imageField ? {
|
|
667
|
+
imageField: dataset.imageField
|
|
459
668
|
} : {}, {
|
|
460
669
|
placements
|
|
461
670
|
})
|
|
@@ -469,6 +678,7 @@ export const runAiSiteDatasetUnit = createAiSiteDatasetRunner();
|
|
|
469
678
|
* nowhere: the pages built without it write the items out.
|
|
470
679
|
*/ export function aiSiteDatasetListings(input) {
|
|
471
680
|
const made = input.datasets.flatMap((dataset)=>{
|
|
681
|
+
var _proposal_imageField;
|
|
472
682
|
const id = input.delivered.get(dataset.name.trim().toLowerCase());
|
|
473
683
|
const output = id ? input.outputs.find((entry)=>entry.resource === 'draft' && entry.draftResource === AI_SITE_DATASET_RESOURCE && entry.id === id) : undefined;
|
|
474
684
|
if (!id || !output) return [];
|
|
@@ -479,13 +689,27 @@ export const runAiSiteDatasetUnit = createAiSiteDatasetRunner();
|
|
|
479
689
|
// Placed by the name the plan's sections gave it.
|
|
480
690
|
name: dataset.name,
|
|
481
691
|
records: proposal.recordNames,
|
|
482
|
-
// The address field is the record page's, never a card's words
|
|
483
|
-
|
|
692
|
+
// The address field is the record page's, never a card's words; the
|
|
693
|
+
// photo is the card's picture, never its words; a field most records
|
|
694
|
+
// leave empty is no card's either (AGL-3616).
|
|
695
|
+
fields: proposal.fields.filter((field, index)=>{
|
|
696
|
+
var _proposal_sparseFields;
|
|
697
|
+
return field.id !== proposal.addressField && field.id !== proposal.imageField && (index === 0 || !((_proposal_sparseFields = proposal.sparseFields) == null ? void 0 : _proposal_sparseFields.includes(field.id)));
|
|
698
|
+
}),
|
|
699
|
+
imageField: (_proposal_imageField = proposal.imageField) != null ? _proposal_imageField : null
|
|
484
700
|
}
|
|
485
701
|
];
|
|
486
702
|
});
|
|
487
703
|
return aiDatasetListingsOf(made, input.screens);
|
|
488
704
|
}
|
|
705
|
+
/** The library photos the site's datasets' records show (AGL-3616), which a page does not place again. */ export function aiSiteDatasetPlacedPhotos(outputs) {
|
|
706
|
+
return [
|
|
707
|
+
...new Set(outputs.filter((output)=>output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE).flatMap((output)=>{
|
|
708
|
+
var _proposalOf_photos;
|
|
709
|
+
return (_proposalOf_photos = proposalOf(output).photos) != null ? _proposalOf_photos : [];
|
|
710
|
+
}))
|
|
711
|
+
];
|
|
712
|
+
}
|
|
489
713
|
/** What a page is told about the datasets built before it. */ export function aiSiteDatasetBriefLines(outputs) {
|
|
490
714
|
const datasets = outputs.filter((output)=>output.resource === 'draft' && output.draftResource === AI_SITE_DATASET_RESOURCE);
|
|
491
715
|
return datasets.flatMap((output)=>{
|