@aglyn/plugins-ai 1.0.0-beta.254 → 1.0.0-beta.255

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 (71) hide show
  1. package/package.json +17 -17
  2. package/src/lib/components/assist-signals-page.component.js +5 -6
  3. package/src/lib/components/assist-signals-page.component.js.map +1 -1
  4. package/src/lib/components/staff-org-ai-card.component.d.ts +0 -10
  5. package/src/lib/components/staff-org-ai-card.component.js +10 -79
  6. package/src/lib/components/staff-org-ai-card.component.js.map +1 -1
  7. package/src/lib/components/staff-org-ai-conversations.component.js +8 -41
  8. package/src/lib/components/staff-org-ai-conversations.component.js.map +1 -1
  9. package/src/lib/components/staff-user-ai-usage-card.component.js +2 -1
  10. package/src/lib/components/staff-user-ai-usage-card.component.js.map +1 -1
  11. package/src/lib/jobs/ai-job-page-language.d.ts +14 -1
  12. package/src/lib/jobs/ai-job-page-language.js +18 -3
  13. package/src/lib/jobs/ai-job-page-language.js.map +1 -1
  14. package/src/lib/jobs/ai-job-page-step.js +17 -3
  15. package/src/lib/jobs/ai-job-page-step.js.map +1 -1
  16. package/src/lib/jobs/ai-job-plan-step.js +4 -0
  17. package/src/lib/jobs/ai-job-plan-step.js.map +1 -1
  18. package/src/lib/jobs/ai-layout-stock-photos.d.ts +30 -0
  19. package/src/lib/jobs/ai-layout-stock-photos.js +76 -8
  20. package/src/lib/jobs/ai-layout-stock-photos.js.map +1 -1
  21. package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.d.ts +95 -0
  22. package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.js +137 -0
  23. package/src/lib/jobs/fixtures/ai-dental-site-plan-recording.js.map +1 -0
  24. package/src/lib/layout-language/ai-layout-labels.d.ts +2 -0
  25. package/src/lib/layout-language/ai-layout-labels.js +12 -6
  26. package/src/lib/layout-language/ai-layout-labels.js.map +1 -1
  27. package/src/lib/layout-language/ai-layout-pictures.d.ts +12 -3
  28. package/src/lib/layout-language/ai-layout-pictures.js +6 -3
  29. package/src/lib/layout-language/ai-layout-pictures.js.map +1 -1
  30. package/src/lib/model/ai-products-bulk.d.ts +48 -0
  31. package/src/lib/model/ai-products-bulk.js +56 -0
  32. package/src/lib/model/ai-products-bulk.js.map +1 -0
  33. package/src/lib/model/ai-products.d.ts +2 -4
  34. package/src/lib/model/ai-products.js +4 -9
  35. package/src/lib/model/ai-products.js.map +1 -1
  36. package/src/lib/providers/anthropic.js +26 -5
  37. package/src/lib/providers/anthropic.js.map +1 -1
  38. package/src/lib/providers/contract.d.ts +10 -0
  39. package/src/lib/providers/contract.js.map +1 -1
  40. package/src/lib/runtime/ai-doctrine-validators.d.ts +20 -0
  41. package/src/lib/runtime/ai-doctrine-validators.js +50 -0
  42. package/src/lib/runtime/ai-doctrine-validators.js.map +1 -1
  43. package/src/lib/runtime/ai-doctrine.d.ts +11 -0
  44. package/src/lib/runtime/ai-doctrine.js +9 -4
  45. package/src/lib/runtime/ai-doctrine.js.map +1 -1
  46. package/src/lib/runtime/ai-runtime.d.ts +6 -0
  47. package/src/lib/runtime/ai-runtime.js +10 -0
  48. package/src/lib/runtime/ai-runtime.js.map +1 -1
  49. package/src/lib/server/ai-admin-conversations.d.ts +2 -0
  50. package/src/lib/server/ai-admin-conversations.js +40 -7
  51. package/src/lib/server/ai-admin-conversations.js.map +1 -1
  52. package/src/lib/server/ai-admin-org.js +28 -2
  53. package/src/lib/server/ai-admin-org.js.map +1 -1
  54. package/src/lib/server/ai-admin-orgs-spend.js +19 -1
  55. package/src/lib/server/ai-admin-orgs-spend.js.map +1 -1
  56. package/src/lib/server/ai-admin-signals.js +11 -3
  57. package/src/lib/server/ai-admin-signals.js.map +1 -1
  58. package/src/lib/server/ai-admin-user.js +11 -1
  59. package/src/lib/server/ai-admin-user.js.map +1 -1
  60. package/src/lib/usage/ai-usage-wire.d.ts +5 -2
  61. package/src/lib/usage/ai-usage-wire.js +5 -2
  62. package/src/lib/usage/ai-usage-wire.js.map +1 -1
  63. package/src/lib/usage/assist-signals-view.d.ts +123 -0
  64. package/src/lib/usage/assist-signals-view.js +151 -0
  65. package/src/lib/usage/assist-signals-view.js.map +1 -0
  66. package/src/lib/usage/staff-org-ai-conversations-view.d.ts +51 -0
  67. package/src/lib/usage/staff-org-ai-conversations-view.js +127 -0
  68. package/src/lib/usage/staff-org-ai-conversations-view.js.map +1 -0
  69. package/src/lib/usage/staff-org-ai-view.d.ts +181 -0
  70. package/src/lib/usage/staff-org-ai-view.js +263 -0
  71. package/src/lib/usage/staff-org-ai-view.js.map +1 -0
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-layout-stock-photos.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\nimport {\n pluginMediaIngest,\n type PluginMediaIngest,\n type PluginMediaIngestResult,\n} from '@aglyn/aglyn/plugin-manager/plugin-media-ingest'\nimport {\n STOCK_PHOTO_QUERY_MAX_CHARS,\n stockPhotoProvider,\n stockPhotoSourceKey,\n type StockPhoto,\n type StockPhotoOrientation,\n type StockPhotoProvider,\n type StockPhotoSearchRequest,\n} from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport type { NodesMap } from '@aglyn/aglyn/types/nodes'\nimport {\n aiLayoutSeedNumber,\n type AiLayoutPicturePhoto,\n type AiLayoutPictureSlot,\n type AiLayoutPictureSource,\n} from '../layout-language/ai-layout-pictures'\nimport { aiStorefrontSays } from '../layout-language/ai-layout-storefront'\nimport { aiLayoutSpeaksOtherThanEnglish } from '../layout-language/ai-layout-labels'\nimport type { AiBuildPlan } from '../model/ai-build-plan'\nimport { aiSiteKindOfInputs } from '../model/ai-site-kinds'\nimport { aiStockBusinessNoun } from './ai-stock-business-nouns'\n\n/**\n * STOCK PHOTOS FOR A LANGUAGE PAGE'S PICTURE SLOTS (AGL-3660).\n *\n * The source `aiResolveLayoutPictures` asks before it falls back to the\n * starter photos. It names no library: it asks core for the deployment's\n * stock photo provider (`core.stock-photos`) and for the media library's\n * server door (`core.media-ingest`), and builds no source at all when either\n * is missing, so a deployment without a key behaves exactly as before.\n *\n * What the live starts of 2026-10-10 taught (Juniper Clay Works, a ceramic\n * artist's portfolio, and Willow Wick Candles, a candle store), each photo\n * traced through the library's cached answers:\n *\n * - The site's words were read as \"portfolio\" and \"online\" — the kind of\n * SITE, not the craft — so every search said \"serving bowl portfolio\" and\n * the hero asked for \"portfolio\": a wallet, fashion models, and a blank\n * paper mockup that read as an empty panel beside the brushes.\n * - A hit naming the object anywhere won: a robin tagged \"food bowl\" filled\n * \"Speckled serving bowl\", a lilac branch tagged \"bud, vase\" filled \"Tall\n * bud vase\", letterpress type tagged \"set\" filled \"Nesting bowl set\" (its\n * head noun was read as \"set\"), and an antique tea set tagged \"brown\n * candle\" filled \"Candle Gift Set\".\n * - The page's 20 seconds ran out after four photos (each copy took ~5s, one\n * after another), and the slots left took the starter photos: the laptop\n * desk with pink roses under \"Candle Wick Trimmer\" and a work card, and the\n * windowsill plants under another.\n *\n * So, for each slot:\n *\n * 1. **The site's terms** ({@link aiStockSiteTerms}): the business is the\n * first clause of its type that says more than what kind of site it is\n * (\"ceramic artist\" from \"a portfolio for a ceramic artist who makes\n * stoneware bowls\"), its craft one word (\"ceramic\"), and its DOMAIN the\n * words a photo of its world names: the craft, the business type's own\n * nouns (\"stoneware\", \"soy\") and, for common crafts, their kin (\"pottery\",\n * \"clay\", \"wax\"). Its broad searches ask for the world itself (\"handmade\n * ceramics\", \"pottery\").\n * 2. **Search.** A picture of a thing asks for its subject — the noun phrase\n * of the caption, filler dropped — qualified by the craft where it does\n * not already name the domain (\"ceramic serving bowl\"), then the craft and\n * the object alone (\"ceramic bowl\"), then the broad searches. A hero asks\n * for the business, then broad; an about picture for the business's\n * people, then broad. The orientation and a minimum size come from the\n * slot's frame.\n * 3. **Accept, or reject.** A hit tagged as a mockup, a blank or a template\n * never fills anything. A picture of a thing takes only a hit naming its\n * OBJECT (the head noun, past \"set\", \"gift\", \"kit\": \"bowl\" in \"nesting\n * bowl set\", \"candle\" in \"candle gift set\") AND either the site's domain\n * or the subject's own two-word phrase (\"bud vase\"). A broad, hero or\n * about search takes only a hit naming the domain. The accepted are\n * ranked: the object in the hit's first tags (what the photo is OF) over\n * a mention in its last, the subject's other words, the domain. Among\n * equals the job's seed picks, so two sites differ and one job repeats.\n * What the beta.239 Ember & Oak start added: \"hand-poured\", \"handmade\"\n * and \"by hand\" never make \"hands\" a subject, and a story of the craft\n * asks for the maker at work (\"candle making\"); a hit carrying a topic\n * the brief never named (a cross, a grave, a flag, a gun, wine, a child,\n * a mannequin) never fills anything; a product, and a collection tile,\n * take only a hit naming its head noun among the first tags, held to the\n * shop's category; and an object whose word is not enough (\"melt\") is\n * named and searched by its kin (\"wax melt\", \"melt warmer\"), never by the\n * category alone. And from the Kiln & Clover portfolio: nudity never fills\n * anything, for any business; a hit naming a rival craft (glass, for a\n * potter) counts only when it names the craft's own words too.\n * 4. **Never twice.** A photo is placed once per job: not twice on a page,\n * and not on a page when another page (or another pass, in this process)\n * of the same job already placed it. The caller hands in what the job's\n * other pages hold (`avoid`); a pass repeated over its own page keeps its\n * own.\n * 5. **Keep, all at once.** The choosing is done first, slot by slot; the\n * copies then run side by side, a few at a time, so a page of eight\n * pictures takes about as long as two. A photo the site's library already\n * holds (by its source key) is reused; otherwise its bytes are copied\n * into the site's own library as the member who started the job, credited\n * to its photographer. A copy that fails tries the slot's next accepted\n * hit.\n *\n * 6. **Fall back to the craft, never off it** (the beta.241 Saltmarsh Soap\n * Co start, a store \"for handmade cold-process soap\": its craft read as\n * nothing, its hero searched \"shop\" and took a florist's bouquet, and four\n * of five products took the starters' laptop desk and living room). A\n * business that is only a place takes its craft from what it is for\n * (\"soap shop\"); a hero names the craft itself ({@link AiStockSiteTerms.core});\n * a product, after its own searches, tries its head noun anywhere among\n * the tags, its gift wrapper with the craft and the craft's broad\n * searches, and then — a product or a hero only — reuses an on-topic photo\n * the job already shows rather than take a starter. Every slot of a\n * craft's site tries the craft's broad searches last.\n * 7. **A product takes the surest photo, even a borrowed one** (the beta.242\n * Tidewater Soap Works start: a sauna for \"Bath Gift Set\", colognes for\n * \"Natural Body Lotion\", a bathroom shelf for \"Soap Bar Trio\" and a soap\n * dispenser for its starter size, while the collection tiles beside them\n * were good). A product's searches are ranked by how sure they are: its\n * own photo (the head noun or its kin among the first tags), then a photo\n * OF its category, new or one the job already shows, then a weak hit of\n * its own. No product shows a room or a scene, a fragrance bottle, or what\n * its kin shuns (a pump for a bar) unless it names it; \"bath\" in a bath\n * gift set is what the set is for; a size is never the product.\n *\n * A slot nothing acceptable answered — the library down, refusing, or out\n * of time — is left `null` for the starter photos. A named object is never\n * given one while the library answers anything of the site's world: the\n * broad searches come first. Nothing here throws, and none of it is an AI\n * model call: photos cost no AI credits.\n */\n\n/** Wall clock the whole page's photos may take, inside the step's own signal. */\nexport const AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS = 30_000\n\n/** Searches one page may send to the provider; a repeated query is answered from the page's own memory. */\nexport const AI_LAYOUT_STOCK_SEARCHES_PER_PAGE = 18\n\n/** The hits a pick is made among. */\nexport const AI_LAYOUT_STOCK_PICK_WINDOW = 40\n\n/** The accepted hits a slot keeps in hand, in case a copy fails. */\nconst AI_LAYOUT_STOCK_TRIES_PER_SLOT = 3\n\n/** Copies made side by side. */\nconst AI_LAYOUT_STOCK_COPIES_AT_ONCE = 4\n\n/** The largest photo copied: inside one direct upload. */\nexport const AI_LAYOUT_STOCK_MAX_BYTES = 3 * 1024 * 1024\n\n/**\n * The unit job input naming the screen drafts the job's other pages were\n * written to, whose photos a page does not place again (AGL-3660).\n */\nexport const AI_STOCK_PHOTO_PAGES_INPUT = 'stockPhotoPages'\n\n/**\n * The unit job input naming library photos (`media:` references) another\n * part of the job already shows outside its pages — a dataset's records\n * (AGL-3616) — which a page does not place again.\n */\nexport const AI_STOCK_PHOTO_AVOID_INPUT = 'stockPhotoAvoid'\n\nconst words = (list: string) => new Set(list.trim().split(/\\s+/))\n\n/** Words that carry no subject. */\nconst STOPWORDS = words(\n 'a an the and or of in on at to for with from by into onto over under near our your their my his her its ' +\n 'this that these those is are be being was were who whom which where while as about than then very just ' +\n 'small local best new top quality premium family-owned family owned independent professional ' +\n 'business company services service page photo picture image showing shows show ' +\n 'someone people person one two three some many several',\n)\n\n/**\n * Words that describe a picture's look, not what it shows, dropped from a\n * subject. A word that is as often a noun (\"light\", \"set\") is not one.\n */\nconst FILLER = words(\n 'beautiful beautifully stunning gorgeous lovely pretty elegant modern contemporary rustic cozy cosy warm cool ' +\n 'soft bright natural simple minimal minimalist delicate unique special artisan artisanal handmade ' +\n 'hand-made hand-thrown handthrown hand-crafted handcrafted crafted hand-built handbuilt hand-poured ' +\n 'hand-painted hand-dyed hand-stitched poured finished styled perfect wheel-thrown wheelthrown thrown ' +\n 'fresh clean calm serene quiet peaceful vibrant colorful colourful sunlit sunny golden glossy matte textured ' +\n 'close-up closeup up view views detail details detailed shot shots overhead flat lay flatlay flat-lay ' +\n 'top-down wide angle featuring featured displayed arranged sitting resting placed standing lined ' +\n 'single pair collection assortment selection group few various array range large tiny big little ' +\n 'tall short wide narrow everyday classic signature original favorite favourite bestselling best-selling ' +\n 'small-batch batch limited edition custom bespoke ' +\n // How a soap is made, never what it shows: \"cold\" and \"process\" named a supermarket fridge (Saltmarsh, 2026-10-10).\n 'cold-process cold-processed hot-process hot-processed melt-and-pour ' +\n 'white black grey gray beige cream ivory brown tan blue green red pink yellow orange purple speckled ' +\n 'gentle airy inviting welcoming cheerful happy smiling friendly',\n)\n\n/** The nouns that name a place of business, not its craft: \"studio\" in \"ceramics studio\". */\nconst VENUES = words(\n 'studio studios shop shops store stores boutique company co workshop gallery atelier agency brand practice ' +\n 'salon house collective lab market services service firm clinic center centre parlor parlour bar ' +\n 'class classes lessons school academy',\n)\n\n/** The person who does the craft, not the craft: \"artist\" in \"ceramic artist\". */\nconst ROLES = words(\n 'artist artists maker makers artisan artisans owner owners founder founders creator creators',\n)\n\n/** Words naming what kind of SITE it is, never what it shows: \"portfolio\" in \"a portfolio for a ceramic artist\". */\nconst SITE_KINDS = words(\n 'portfolio portfolios website websites site sites blog blogs online web webshop ecommerce e-commerce ' +\n 'landing personal homepage storefront',\n)\n\n/** Verbs a business type uses to say what it does; what follows them is its domain, never its business. */\nconst DOING =\n /(?<![\\w-])(?:makes?|making|made|sells?|selling|sold|offers?|offering|creates?|creating|specializ(?:es|ing)|specialis(?:es|ing)|provides?|providing|featuring|showcasing)(?![\\w-])/g\n\n/** Where a business type's own clause ends. */\nconst BUSINESS_BREAK =\n /[,;:.()]|\\s[-–—]\\s|\\b(?:in|for|near|serving|based|located|that|which|who|with|from|since|and|&)\\b/\n\n/** A clause after one of these says where or for whom, never what: \"in Austin\", \"for busy parents\". */\nconst PLACE_OR_AUDIENCE =\n /^(?:in|near|serving|based|located|across|around|throughout|for)$/\n\n/**\n * Words naming a set or a wrapper of a thing, never the thing: the OBJECT\n * of \"nesting bowl set\" is the bowl, of \"candle gift set\" the candle.\n */\nconst WRAPPERS = words(\n 'set sets kit kits gift gifts bundle bundles pack packs box boxes trio duo pair collection sampler assortment ' +\n 'series range line group lot bunch',\n)\n\n/**\n * A hit tagged with any of these is never placed: a mockup's blank panel is\n * an empty frame on the page (the Juniper Clay hero), a template or a\n * graphic is not a photo of anything.\n */\nconst REJECTED_TAGS = words(\n 'mockup mock-up mock blank template templates clipart clip-art illustration vector logo icon ' +\n 'ai-generated generated render rendering 3d',\n)\n\n/**\n * Rooms and scenes, never a product (AGL-3660): the beta.242 Tidewater Soap\n * Works start put a wooden sauna under \"Bath Gift Set\" and a bathroom shelf of\n * baskets under \"Soap Bar Trio\". A product's hit whose first tags name one of\n * these is turned down unless the product or the brief names it too.\n */\nconst PRODUCT_SCENES = new Set(\n [\n 'sauna',\n 'bathroom',\n 'bathtub',\n 'shower',\n 'toilet',\n 'sink',\n 'washbasin',\n 'faucet',\n 'tap',\n 'shelf',\n 'shelves',\n 'interior',\n 'bedroom',\n 'kitchen',\n 'room',\n 'livingroom',\n 'hotel',\n 'lobby',\n ].map(aiStockStem),\n)\n\n/**\n * A fragrance's bottle, never a lotion, a cream or a soap (AGL-3660): the same\n * start's \"Natural Body Lotion\" showed blue cologne bottles tagged \"perfume,\n * bottle, lotion\". Turned down among a product's first tags unless the\n * product or the brief is a fragrance.\n */\nconst FRAGRANCE_BOTTLES = new Set(\n ['perfume', 'perfumes', 'perfumery', 'cologne', 'colognes', 'parfum', 'eau', 'atomizer', 'fragrance'].map(\n aiStockStem,\n ),\n)\n\n/**\n * Topics a business's photos never carry unless its own words name them\n * (AGL-3660, the beta.239 Ember & Oak start, whose \"Gifts for melt fans\" tile\n * showed devotional candles with crosses and names). A hit tagged with any\n * word of a topic is rejected unless the site's business type or brief says\n * one of the topic's words or its `allow` words. The last topic is not\n * sensitive but is never the thing: the same start's story band showed bronze\n * mannequin hands tagged \"wax\".\n */\nconst SENSITIVE_TOPICS: ReadonlyArray<{\n words: readonly string[]\n allow?: readonly string[]\n /** Rejected whatever the brief says. */\n always?: boolean\n}> = [\n {\n // Religion.\n words: [\n 'cross',\n 'crosses',\n 'crucifix',\n 'church',\n 'chapel',\n 'cathedral',\n 'jesus',\n 'christ',\n 'christian',\n 'christianity',\n 'god',\n 'bible',\n 'rosary',\n 'prayer',\n 'pray',\n 'praying',\n 'worship',\n 'worships',\n 'religion',\n 'religious',\n 'faith',\n 'islam',\n 'islamic',\n 'muslim',\n 'mosque',\n 'quran',\n 'temple',\n 'buddha',\n 'buddhism',\n 'buddhist',\n 'hindu',\n 'hinduism',\n 'synagogue',\n 'jewish',\n 'judaism',\n 'ecclesiastical',\n 'saint',\n 'altar',\n 'sacrificial',\n 'nativity',\n 'priest',\n 'nun',\n 'monk',\n ],\n allow: ['ministry', 'parish', 'congregation', 'wedding'],\n },\n {\n // Death and mourning.\n words: [\n 'funeral',\n 'memorial',\n 'grave',\n 'gravestone',\n 'cemetery',\n 'tomb',\n 'death',\n 'dead',\n 'grief',\n 'mourning',\n 'condolence',\n 'coffin',\n 'skull',\n ],\n allow: ['hospice', 'mortuary', 'cremation', 'obituary', 'halloween'],\n },\n {\n // Politics.\n words: [\n 'political',\n 'politics',\n 'protest',\n 'protester',\n 'demonstration',\n 'rally',\n 'flag',\n 'election',\n 'vote',\n 'voting',\n 'parliament',\n 'government',\n ],\n allow: ['advocacy', 'campaign', 'candidate', 'council', 'nonprofit'],\n },\n {\n // Weapons and war.\n words: [\n 'gun',\n 'rifle',\n 'pistol',\n 'weapon',\n 'firearm',\n 'ammunition',\n 'bullet',\n 'sword',\n 'war',\n 'military',\n 'army',\n 'soldier',\n ],\n allow: ['hunting', 'archery', 'martial', 'fencing', 'veteran'],\n },\n {\n // Alcohol, for a business that does not serve it.\n words: [\n 'alcohol',\n 'wine',\n 'beer',\n 'whiskey',\n 'whisky',\n 'vodka',\n 'cocktail',\n 'liquor',\n 'rum',\n 'gin',\n 'champagne',\n 'drunk',\n ],\n allow: [\n 'winery',\n 'vineyard',\n 'brewery',\n 'distillery',\n 'pub',\n 'tavern',\n 'taproom',\n 'bartender',\n 'sommelier',\n 'spirits',\n ],\n },\n {\n // Tobacco and drugs.\n // \"cbd\" and \"cannabinoid\": a hemp cream tube was the next \"body lotion\" answer (Tidewater, 2026-10-11).\n words: ['cigarette', 'smoking', 'tobacco', 'cannabis', 'marijuana', 'drug', 'drugs', 'cbd', 'cannabinoid', 'thc'],\n allow: ['dispensary', 'vape', 'cigar'],\n },\n {\n // Children, for a business that is not about them.\n words: ['child', 'children', 'kid', 'kids', 'baby', 'babies', 'toddler', 'infant'],\n allow: [\n 'nursery',\n 'daycare',\n 'preschool',\n 'kindergarten',\n 'school',\n 'tutor',\n 'tutoring',\n 'parent',\n 'parents',\n 'parenting',\n 'family',\n 'families',\n 'pediatric',\n 'paediatric',\n 'newborn',\n 'maternity',\n ],\n },\n {\n // Nudity, for every business: no word of a brief lets it in (Kiln &\n // Clover, 2026-10-10: a nude torso sculpture filled \"About the artist\").\n // Never bare \"body\": a skincare shop's body lotion is its product.\n words: [\n 'nude',\n 'nudes',\n 'nudity',\n 'naked',\n 'torso',\n 'breast',\n 'breasts',\n 'erotic',\n 'sensual',\n 'lingerie',\n 'bikini',\n ],\n allow: [],\n always: true,\n },\n {\n // Figures, never the maker: mannequin hands are not a candlemaker's.\n words: [\n 'mannequin',\n 'mannequins',\n 'dummy',\n 'statue',\n 'sculpture',\n 'figurine',\n 'doll',\n 'dolls',\n 'waxwork',\n ],\n allow: ['sculptor', 'museum', 'fashion', 'boutique', 'clothing', 'apparel', 'toy', 'toys'],\n },\n]\n\n/** Each topic's words and the words that allow it, as stems. */\nconst SENSITIVE_STEMS = SENSITIVE_TOPICS.map((topic) => ({\n words: new Set(topic.words.map(aiStockStem)),\n allow: new Set(\n topic.always\n ? []\n : [...topic.words, ...(topic.allow ?? [])].map(aiStockStem),\n ),\n}))\n\n/**\n * Hands are never a picture's subject (AGL-3660): \"hand-poured\", \"handmade\"\n * and \"by hand\" say how a thing was made, and a search for \"hands\" found\n * bronze mannequin hands for the beta.239 Ember & Oak story band. Each of\n * these is dropped from a picture's words; a hand only stays where it names\n * a thing sold for hands (\"hand cream\").\n */\nconst HAND_IDIOMS: readonly RegExp[] = [\n /\\b(?:made\\s+|poured\\s+|crafted\\s+|finished\\s+|done\\s+)?by\\s+(?:our\\s+|my\\s+|their\\s+)?(?:own\\s+)?hands?\\b/g,\n /\\bwith\\s+(?:our|my|their)\\s+(?:own\\s+)?(?:two\\s+)?hands\\b/g,\n /\\bhand[- ]?(?:poured|made|crafted|thrown|built|painted|dyed|stitched|sewn|knit|knitted|carved|tied|lettered|blown|bound|rolled|dipped|picked|forged|woven|cut|finished|mixed|cast|formed|shaped|pressed|printed|wrapped|selected|blended|turned|glazed)\\b/g,\n /\\bhands?\\b(?!\\s+(?:creams?|soaps?|lotions?|wash|towels?|saniti[sz]ers?|salves?|balms?|tools?|saws?|planes?|drills?|mixers?|puppets?|bags?|warmers?))/g,\n]\n\n/** A text without its hands. */\nfunction withoutHands(text: string): string {\n return HAND_IDIOMS.reduce(\n (out, idiom) => out.replace(idiom, ' '),\n text.toLowerCase(),\n )\n}\n\n/** Whether a text says how a thing was made by hand: a maker at work. */\nfunction saysMadeByHand(text: string): boolean {\n const lower = text.toLowerCase()\n return HAND_IDIOMS.some((idiom) => {\n idiom.lastIndex = 0\n const found = idiom.test(lower)\n idiom.lastIndex = 0\n return found\n })\n}\n\n/**\n * The kin of a few objects whose own word is not enough (AGL-3660): a \"melt\"\n * is any melting thing (the beta.239 \"Wax melts\" tile showed resin fluid\n * art), so a wax melt names one of these phrases. `within` is the world they\n * are of; `qualifier` the word a search adds; `queries` the searches for the\n * object itself, which stand in for the shop's category alone: a candle is\n * not a wax melt.\n */\nconst OBJECT_KIN: ReadonlyArray<{\n objects: readonly string[]\n within: readonly string[]\n /** The word a product's search adds where its subject lacks it; none where the subject is enough. */\n qualifier?: string\n /** Whether the qualifier follows the subject: \"bath gift set soap\". */\n after?: boolean\n kin: readonly string[]\n queries: readonly string[]\n /** Words a photo of the object never carries unless the product names them: a pump for a bar of soap. */\n shun?: readonly string[]\n}> = [\n {\n objects: ['melt', 'tart', 'cube'],\n within: ['wax', 'candle', 'soy'],\n qualifier: 'wax',\n kin: [\n 'wax melt',\n 'wax melts',\n 'wax cube',\n 'wax cubes',\n 'wax tart',\n 'wax tarts',\n 'melt warmer',\n 'wax warmer',\n 'tart warmer',\n 'oil burner',\n 'oil warmer',\n 'aroma burner',\n 'scent warmer',\n 'fragrance warmer',\n ],\n queries: ['wax melts', 'wax melt warmer', 'scented wax cubes'],\n },\n {\n // A \"bar\" is a pub's before it is a soap's (the Saltmarsh \"cold-process\n // soap bar\" search answered a pint of beer second): a soap bar is named\n // by soap, and searched by it.\n objects: ['bar'],\n within: ['soap', 'soapmaker', 'skincare'],\n qualifier: 'soap',\n kin: [\n 'soap bar',\n 'soap bars',\n 'bar of soap',\n 'bars of soap',\n 'soap',\n 'soaps',\n 'handmade soap',\n 'soap block',\n 'soap cubes',\n ],\n queries: ['soap bars', 'handmade soap bar'],\n // A bar is never a pump or a liquid soap (the beta.242 Tidewater start).\n shun: ['pump', 'pumps', 'liquid', 'dispenser', 'dispensers'],\n },\n {\n // \"Bath\" in \"bath gift set\", \"bath bomb\" or \"bath salts\" is what the\n // products are for, never the room: the beta.242 Tidewater Soap Works\n // start (2026-10-11) put a wooden sauna under \"Bath Gift Set\", its tags\n // \"sauna, steam, bath\". A bath set is named by soap and bath products,\n // and searched with soap.\n objects: ['bath'],\n within: ['soap', 'soapmaker', 'skincare', 'spa', 'cosmetic'],\n qualifier: 'soap',\n after: true,\n kin: [\n 'soap',\n 'soaps',\n 'soap bar',\n 'soap bars',\n 'handmade soap',\n 'bath bomb',\n 'bath bombs',\n 'bath salt',\n 'bath salts',\n 'bath product',\n 'bath products',\n 'bath set',\n 'toiletries',\n ],\n queries: ['soap gift set', 'bath products', 'bath bombs'],\n shun: ['pump', 'pumps', 'liquid', 'dispenser', 'dispensers'],\n },\n {\n // A lotion is any cream for the skin; a perfume bottle tagged \"lotion\"\n // is not one (the same start's \"Natural Body Lotion\" showed colognes).\n objects: ['lotion', 'moisturizer', 'moisturiser'],\n within: ['soap', 'soapmaker', 'skincare', 'lotion', 'cosmetic', 'beauty', 'spa'],\n kin: [\n 'lotion',\n 'lotions',\n 'body lotion',\n 'hand lotion',\n 'cream',\n 'creams',\n 'hand cream',\n 'body cream',\n 'skin cream',\n 'face cream',\n 'cream jar',\n 'body butter',\n 'moisturizer',\n 'moisturiser',\n ],\n queries: ['body lotion', 'hand cream', 'cream jar', 'moisturizer'],\n },\n]\n\n/** An object's kin where the site or the subject is of its world, else `null`. */\nfunction objectKin(\n object: string,\n world: readonly string[],\n): (typeof OBJECT_KIN)[number] | null {\n return (\n OBJECT_KIN.find(\n (entry) =>\n entry.objects.some((word) => aiStockStem(word) === object) &&\n entry.within.some((word) => world.includes(aiStockStem(word))),\n ) ?? null\n )\n}\n\n/**\n * The kin of a few common crafts: the words a photo of that world is\n * tagged with, and the broad searches that find it. A craft not listed\n * still has its own words; this only widens what counts as its world.\n */\nconst CRAFT_KIN: ReadonlyArray<{\n match: readonly string[]\n kin: readonly string[]\n broad: readonly string[]\n /** The maker at work: what a story of the craft shows, never \"hands\" (AGL-3660). */\n making: readonly string[]\n /**\n * Crafts a photo of this one is mistaken for, and the words only this\n * craft's photos say: a hit naming a rival counts as of this world only\n * when it names one of them too (Kiln & Clover, 2026-10-10: red and yellow\n * glass art filled a ceramic artist's Work hero, glass being fired and\n * \"vase\" too).\n */\n rivals?: { words: readonly string[]; core: readonly string[] }\n /**\n * Words no photo of this craft carries unless the slot or the brief names\n * them (AGL-3660): the beta.242 Tidewater start put a black soap dispenser\n * under \"Bath Gift Set Starter Size\", let in as a rival because its tags\n * also said \"cosmetics\".\n */\n shun?: readonly string[]\n}> = [\n {\n match: [\n 'ceramic',\n 'ceramics',\n 'pottery',\n 'potter',\n 'stoneware',\n 'porcelain',\n 'earthenware',\n 'clay',\n ],\n kin: [\n 'ceramic',\n 'ceramics',\n 'pottery',\n 'potter',\n 'stoneware',\n 'porcelain',\n 'earthenware',\n 'clay',\n 'glaze',\n 'kiln',\n ],\n broad: ['handmade ceramics', 'pottery'],\n rivals: {\n words: ['glass', 'glassware', 'glasswork', 'glassblowing', 'blown', 'stained', 'murano', 'crystal'],\n core: ['ceramic', 'ceramics', 'pottery', 'potter', 'stoneware', 'porcelain', 'earthenware', 'clay', 'terracotta'],\n },\n making: ['pottery wheel', 'potter at work'],\n },\n {\n match: ['candle', 'candlemaker', 'candlemaking'],\n kin: [\n 'candle',\n 'candlelight',\n 'wax',\n 'soy',\n 'wick',\n 'scented',\n 'votive',\n 'candlestick',\n ],\n broad: ['handmade candles', 'scented candles'],\n making: ['candle making', 'pouring wax'],\n },\n {\n match: [\n 'jewelry',\n 'jewellery',\n 'jeweler',\n 'jeweller',\n 'silversmith',\n 'goldsmith',\n ],\n kin: [\n 'jewelry',\n 'jewellery',\n 'ring',\n 'necklace',\n 'earring',\n 'bracelet',\n 'silver',\n 'gold',\n 'gemstone',\n ],\n broad: ['handmade jewelry', 'jewelry'],\n making: ['jewelry making', 'jeweler at work'],\n },\n {\n match: ['soap', 'soapmaker', 'skincare'],\n // Never \"natural\": a florist's bouquet tagged \"natural\" was the\n // Saltmarsh Soap Co hero (2026-10-10).\n kin: ['soap', 'skincare', 'lotion', 'cream', 'bath', 'spa', 'cosmetic'],\n broad: ['handmade soap', 'natural skincare'],\n // \"Soap making\" is answered with soap bubbles; a bar is what a soapmaker makes.\n making: ['soap making', 'handmade soap'],\n // Soap bubbles, a dispenser and detergent are soap, never a soapmaker's:\n // the same start's story band showed bubbles in flight.\n rivals: {\n words: ['bubble', 'bubbles', 'soapy', 'dispenser', 'detergent', 'dishwashing', 'laundry'],\n core: [\n 'bar',\n 'bars',\n 'handmade',\n 'homemade',\n 'loaf',\n 'lye',\n 'glycerin',\n 'skincare',\n 'lotion',\n 'cosmetic',\n 'spa',\n 'artisan',\n ],\n },\n shun: ['dispenser', 'dispensers'],\n },\n {\n match: [\n 'wood',\n 'woodwork',\n 'woodworking',\n 'woodworker',\n 'carpenter',\n 'carpentry',\n 'furniture',\n 'joinery',\n ],\n kin: [\n 'wood',\n 'wooden',\n 'woodwork',\n 'timber',\n 'furniture',\n 'carpentry',\n 'oak',\n 'walnut',\n ],\n broad: ['woodworking', 'wooden furniture'],\n making: ['woodworking workshop', 'carpenter at work'],\n },\n {\n match: ['bakery', 'baker', 'bread', 'pastry', 'cake', 'patisserie'],\n kin: [\n 'bakery',\n 'bread',\n 'pastry',\n 'cake',\n 'baking',\n 'baked',\n 'dough',\n 'croissant',\n ],\n broad: ['bakery', 'fresh bread'],\n making: ['baker kneading dough', 'baking bread'],\n },\n {\n match: ['coffee', 'cafe', 'café', 'roaster', 'espresso'],\n kin: [\n 'coffee',\n 'cafe',\n 'espresso',\n 'latte',\n 'cappuccino',\n 'barista',\n 'beans',\n ],\n broad: ['coffee shop', 'coffee'],\n making: ['barista making coffee'],\n },\n {\n match: ['florist', 'flower', 'floral'],\n kin: ['flower', 'floral', 'bouquet', 'florist', 'bloom', 'blossom'],\n broad: ['florist', 'flower bouquet'],\n making: ['florist arranging flowers'],\n },\n {\n match: [\n 'knit',\n 'knitting',\n 'yarn',\n 'weaving',\n 'weaver',\n 'textile',\n 'textiles',\n 'quilt',\n 'quilting',\n 'sewing',\n ],\n kin: [\n 'knit',\n 'knitting',\n 'yarn',\n 'wool',\n 'weaving',\n 'textile',\n 'fabric',\n 'quilt',\n 'sewing',\n ],\n broad: ['handmade textiles', 'yarn'],\n making: ['knitting', 'weaving loom'],\n },\n {\n match: ['leather', 'leatherwork', 'leathercraft'],\n kin: ['leather', 'wallet', 'bag', 'belt', 'stitching'],\n broad: ['leather craft', 'leather goods'],\n making: ['leather crafting'],\n },\n]\n\n/** Lowercase words, letters only, without stopwords. */\nfunction contentWords(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/https?:\\/\\/\\S+|\\S+@\\S+|\\+?\\d[\\d\\s().-]{5,}\\d/g, ' ')\n .replace(/[^a-zÀ-ɏ\\s-]/g, ' ')\n .split(/\\s+/)\n .map((word) => word.replace(/^-+|-+$/g, ''))\n .filter((word) => word.length > 1 && !STOPWORDS.has(word))\n}\n\n/**\n * A word's singular, for matching only: \"bowls\" and \"bowl\", \"vases\" and\n * \"vase\", \"berries\" and \"berry\", \"dishes\" and \"dish\" meet. Both sides of a\n * comparison are reduced the same way, so an odd stem still matches itself.\n */\nexport function aiStockStem(word: string): string {\n const lower = word.toLowerCase()\n if (lower.length > 4 && lower.endsWith('ies')) return `${lower.slice(0, -3)}y`\n if (lower.length > 4 && /(?:ches|shes|sses|xes|zes)$/.test(lower))\n return lower.slice(0, -2)\n if (lower.length > 3 && lower.endsWith('s') && !/(?:ss|us|is)$/.test(lower))\n return lower.slice(0, -1)\n return lower\n}\n\n/** A text's words as stems, in order; a hyphenated word counts as its parts. */\nfunction stemList(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-zÀ-ɏ]+/)\n .filter((word) => word.length > 1)\n .map(aiStockStem)\n}\n\n/** Where a noun phrase ends: punctuation, a preposition, a conjunction. */\nconst CLAUSE_BREAK =\n /[,;:.()]|\\s[-–—]\\s|\\b(?:with|on|in|at|against|beside|next|near|under|over|by|from|for|during|while|atop|inside|across|beneath|through|into|onto|amid|among|and|of|that|which|who)\\b|&/\n\n/** A business type's clauses, each with the word that opened it. */\nfunction businessClauses(\n businessType: string,\n): Array<{ opener: string; words: string[] }> {\n const text = businessType.toLowerCase().replace(DOING, ' | ')\n const clauses: Array<{ opener: string; words: string[] }> = []\n const breaker = new RegExp(`${BUSINESS_BREAK.source}|\\\\|`, 'g')\n let at = 0\n let opener = ''\n for (const match of text.matchAll(breaker)) {\n clauses.push({ opener, words: contentWords(text.slice(at, match.index)) })\n opener = match[0].trim()\n at = (match.index ?? 0) + match[0].length\n }\n clauses.push({ opener, words: contentWords(text.slice(at)) })\n return clauses\n}\n\n/** A clause's words that name the business: no site kind, no filler. */\nconst businessOf = (clause: readonly string[]) =>\n clause.filter((word) => !SITE_KINDS.has(word) && !FILLER.has(word))\n\n/**\n * The kind of business in a few words: the first clause of the business\n * type that says more than what kind of site it is, before a place, an\n * audience or what it makes, filler dropped, its last three words (the head\n * of an English noun phrase is at its end). \"ceramic artist\" from \"a\n * portfolio for a ceramic artist who makes stoneware bowls\"; \"candle shop\"\n * from \"a small-batch candle shop selling hand-poured soy candles online\".\n */\nexport function aiStockBusinessWords(businessType: string): string {\n for (const { words: clause } of businessClauses(businessType)) {\n const named = businessOf(clause)\n if (named.length) return named.slice(-3).join(' ')\n }\n return ''\n}\n\n/**\n * The business's craft in one word: the last of its words that is not the\n * place it is done in nor the person doing it, singular — \"ceramic\" from\n * \"ceramics studio\" or \"ceramic artist\", \"yoga\" from \"yoga studio\". Empty\n * when the business is only a place (\"a shop\").\n */\nexport function aiStockCraftWords(business: string): string {\n const named = business\n .split(/\\s+/)\n .filter(\n (word) =>\n word &&\n !VENUES.has(word) &&\n !ROLES.has(word) &&\n !FILLER.has(word) &&\n !SITE_KINDS.has(word),\n )\n const craft = named[named.length - 1]\n return craft ? aiStockStem(craft) : ''\n}\n\n/** What a site's photos are searched and judged by (AGL-3660). */\nexport interface AiStockSiteTerms {\n /** The kind of business, in a few words: \"ceramic artist\". */\n business: string\n /** Its craft, one singular word: \"ceramic\". */\n craft: string\n /**\n * The stems a photo of the site's world names: the business's own words,\n * what the things it makes are made of, and the craft's kin. Empty for a\n * site whose words name no world (a type left blank), and then no hit is\n * held to it.\n */\n domain: string[]\n /** The searches for the site's world itself, broadest last. */\n broad: string[]\n /** The searches for its maker at work, for a story of the craft (AGL-3660); empty for a craft not listed. */\n making: string[]\n /** Every stem of the business type or brief: what lets a sensitive topic in ({@link SENSITIVE_TOPICS}). */\n named: string[]\n /** Rival crafts' words, each with the words that must then be named too ({@link CRAFT_KIN}). */\n rivals: Array<{ words: string[]; core: string[] }>\n /**\n * The stems a photo of the craft ITSELF names, one of which a hero and a\n * product's fallbacks must name (AGL-3660): the craft and, for a listed\n * craft, its own names (\"soap\", \"soapmaker\", \"skincare\"). Empty where the\n * site names no craft.\n */\n core: string[]\n /** Words no photo of the site's craft carries unless the slot or the brief names them ({@link CRAFT_KIN}). */\n shun: string[]\n}\n\n/** The site's terms, read from its business type. */\nexport function aiStockSiteTerms(businessType: string): AiStockSiteTerms {\n let business = aiStockBusinessWords(businessType)\n let craft = aiStockCraftWords(business)\n const domain = new Set<string>()\n /** The things it makes, by their head nouns. */\n const made = new Set<string>()\n /** The last word of the first clause that names the world: \"soap\" of \"for handmade cold-process soap\". */\n let firstWorld = ''\n let named = false\n let making = false\n for (const { opener, words: clause } of businessClauses(businessType)) {\n if (opener === '|') making = true\n // Where it is, and who it is for, are not its world — once something has named it.\n if (named && PLACE_OR_AUDIENCE.test(opener)) {\n making = false\n continue\n }\n const kept = businessOf(clause).filter(\n (word) => !VENUES.has(word) && !ROLES.has(word),\n )\n if (kept.length) named = true\n // What it makes names its world by what the things are made of, never\n // the things: \"stoneware\" of \"stoneware bowls\", \"soy\" of \"soy candles\".\n // A bowl is not a ceramic world; a robin's food bowl is not pottery.\n // A set or a gift is never a world: \"gift\" of \"gift sets\" is not one.\n const world = (making ? kept.slice(0, -1) : kept).filter(\n (word) => !WRAPPERS.has(word),\n )\n for (const word of world)\n for (const stem of stemList(word)) domain.add(stem)\n const last = world[world.length - 1]\n if (!firstWorld && last) firstWorld = aiStockStem(last)\n if (making)\n for (const word of kept.slice(-1))\n for (const stem of stemList(word)) made.add(stem)\n }\n // A business named only by what it sells (\"a shop selling pottery\") is of that world.\n if (!domain.size) for (const stem of made) domain.add(stem)\n const groups = CRAFT_KIN.filter((group) =>\n group.match.some(\n (word) =>\n domain.has(aiStockStem(word)) ||\n made.has(aiStockStem(word)) ||\n aiStockStem(word) === craft,\n ),\n )\n // A business that is only a place (\"an online shop for handmade\n // cold-process soap\") takes its craft from what it is for: the Saltmarsh\n // Soap Co start (2026-10-10) read its craft as nothing, so its hero searched\n // \"shop\" (a florist's bouquet) and no product was held to soap.\n if (!craft) {\n const listed = groups[0]?.match\n .map(aiStockStem)\n .find((stem) => domain.has(stem) || made.has(stem))\n craft = listed || firstWorld || [...made][0] || ''\n if (craft && !stemList(business).includes(craft))\n business = `${craft} ${business}`.trim()\n }\n if (craft) domain.add(craft)\n const broad: string[] = []\n const makingSearches: string[] = []\n const rivals: Array<{ words: string[]; core: string[] }> = []\n const core = new Set<string>(craft ? [craft] : [])\n const shun = new Set<string>()\n for (const group of groups) {\n for (const word of group.shun ?? []) shun.add(aiStockStem(word))\n for (const word of group.match) core.add(aiStockStem(word))\n for (const word of group.kin) domain.add(aiStockStem(word))\n broad.push(...group.broad)\n makingSearches.push(...group.making)\n if (group.rivals)\n rivals.push({\n words: group.rivals.words.map(aiStockStem),\n core: group.rivals.core.map(aiStockStem),\n })\n }\n if (!broad.length) broad.push(business, craft)\n return {\n business,\n craft,\n domain: [...domain].filter((stem) => stem.length > 1),\n broad: [...new Set(broad.map((query) => query.trim()).filter(Boolean))],\n making: [...new Set(makingSearches)],\n named: [...new Set(stemList(businessType))],\n rivals,\n core: [...core],\n shun: [...shun],\n }\n}\n\n/** A phrase's content words without its filler; all filler, and nothing is left. */\nfunction subjectOf(list: readonly string[]): string[] {\n return list.filter((word) => !FILLER.has(word))\n}\n\n/**\n * A picture's subject in a few words (AGL-3660): the noun phrase its alt\n * text opens with — its first clause holding more than filler, cut where a\n * preposition starts the setting, filler dropped, its last three words (the\n * head noun is the last) — else its section's name.\n */\nexport function aiStockSubjectWords(alt: string, sectionName: string): string {\n // \"Hand-poured\", \"by hand\" and \"hands\" say how it was made, never what it shows.\n for (const clause of withoutHands(alt).split(CLAUSE_BREAK)) {\n const found = subjectOf(contentWords(clause ?? ''))\n if (found.length) return found.slice(-3).join(' ')\n }\n return subjectOf(contentWords(withoutHands(sectionName))).slice(0, 2).join(' ')\n}\n\n/**\n * The thing a subject shows, one singular word: its last word that is not\n * a set or a wrapper of it — \"bowl\" from \"nesting bowl set\", \"candle\" from\n * \"candle gift set\", \"vase\" from \"bud vase\". Its last word when every word\n * is one (\"gift set\").\n */\nexport function aiStockObjectWord(subject: string): string {\n const list = subject.split(/\\s+/).filter(Boolean)\n const object =\n [...list].reverse().find((word) => !WRAPPERS.has(word)) ??\n list[list.length - 1] ??\n ''\n return object ? aiStockStem(object) : ''\n}\n\nconst clip = (query: string) =>\n query.replace(/\\s+/g, ' ').trim().slice(0, STOCK_PHOTO_QUERY_MAX_CHARS).trim()\n\n/** The frame's orientation: a wide frame wants a landscape photo, a tall one a portrait. */\nexport function aiStockOrientation(aspect: number): StockPhotoOrientation {\n if (aspect > 1.15) return 'horizontal'\n if (aspect < 0.87) return 'vertical'\n return 'any'\n}\n\n/**\n * One search a slot tries. A `broad` one asks for the site's world and\n * takes any hit of it; any other picture of a thing takes only a hit naming\n * the thing.\n */\nexport interface AiStockSearch extends StockPhotoSearchRequest {\n broad?: boolean\n /** The words its hits are scored by, where they are not the slot's own subject (a product's searches, AGL-3676). */\n subject?: string\n /** A word every hit must name: a product's photo names the shop's category (AGL-3676). */\n requires?: string\n /**\n * Words of which a hit must name ONE, `requires` among them (AGL-3660): a\n * shop's category or the slot's own word of its world, so a soap shop's\n * body lotion is held to \"lotion\", never to \"soap\".\n */\n category?: readonly string[]\n /** The thing every hit must name, where it is not the subject's own: a product's head noun (AGL-3660). */\n object?: string\n /** Phrases that name the object where its own word is not enough: \"wax melt\" ({@link OBJECT_KIN}). */\n kin?: readonly string[]\n /** Whether the object must be among the hit's first tags, what the photo is OF (AGL-3660). */\n lead?: boolean\n /** Whether the hit's first tags must name the site's world, where the object need not lead (AGL-3660). */\n leadWorld?: boolean\n /**\n * Whether the hit's FIRST tag must name the site's world (AGL-3760): what\n * the photo is of, most of all. A hero is the site's opening picture; the\n * copper-fern-candle-co start (beta.246) took a latte with a candle behind\n * it, its tags \"coffee, mobile wallpaper 4k, latte art, …, candle\".\n */\n first?: boolean\n /** Phrases (as stems) of which one must be among the hit's first tags: a borrowed photo is OF the product's category (AGL-3660). */\n leadAny?: readonly string[]\n /** Whether it fills a product: no room, no scene, no fragrance bottle ({@link PRODUCT_SCENES}, AGL-3660). */\n product?: boolean\n /** Words its hits never carry unless the slot or the brief names them ({@link AiStockSiteTerms.shun}). */\n shun?: readonly string[]\n /**\n * How sure a product's search is (AGL-3660). Absent: its own photo, the\n * head noun among the first tags. `borrow`: a photo OF its category, which\n * may repeat one the job already shows. `weak`: the head noun anywhere, or\n * the category anywhere — taken only once nothing surer is left.\n */\n tier?: 'borrow' | 'weak'\n}\n\n/** A slot's part of a page, where it asks for more than its role: a collection tile or a story of the craft (AGL-3660). */\nexport type AiStockSlotPart = 'collection' | 'story'\n\n/**\n * A slot's part (AGL-3660): a tile of a collections band is product-like,\n * held to the shop's category and its own object; a picture of a story of\n * the craft, or of a thing made by hand, shows the maker at work.\n */\nexport function aiStockSlotPart(\n slot: Pick<AiLayoutPictureSlot, 'role' | 'alt'>,\n sectionName: string,\n): AiStockSlotPart | undefined {\n if (slot.role === 'hero') return undefined\n if (slot.role === 'gallery' && aiStorefrontSays('collections', sectionName))\n return 'collection'\n if (\n aiStorefrontSays('story', sectionName) ||\n saysMadeByHand(slot.alt) ||\n saysMadeByHand(sectionName)\n )\n return 'story'\n return undefined\n}\n\n/** An object's kin phrases as stems, or none. */\nconst kinStems = (entry: (typeof OBJECT_KIN)[number] | null): string[] =>\n entry ? [...new Set(entry.kin.map((phrase) => stemList(phrase).join(' ')))] : []\n\n/** What a product falls back to once its own searches find nothing ({@link aiStockProductSearches}). */\nexport interface AiStockProductFallback {\n /** The site's broad searches ({@link AiStockSiteTerms.broad}): \"handmade soap\". */\n broad?: readonly string[]\n /** The words a photo of the craft itself names ({@link AiStockSiteTerms.core}). */\n core?: readonly string[]\n}\n\n/**\n * A size never names a product (AGL-3660): the Tidewater start searched\n * \"soap set starter size\" for \"Bath Gift Set Starter Size\", its head noun\n * read as \"size\", and took a soap dispenser.\n */\nconst PRODUCT_SIZES =\n /\\b(?:(?:starter|travel|trial|sample|mini|full|half|family|value|jumbo|large|small|regular|standard|big)[- ])?sized?s?\\b/gi\n\n/** The wrapper words a gift is named by, searched with the craft: \"soap gift box\". */\nconst GIFT_WRAPPERS = words('gift gifts box boxes basket baskets hamper hampers')\n\n/**\n * A product's searches (AGL-3676), most specific first: each of its subjects\n * — its name's noun phrase, then its photo's — with the shop's category\n * where the phrase does not already name the shop's world (\"candle gift\n * box\"), then the category alone, a plain photo of what the shop sells. Every\n * one must find a hit naming the category — or the product's own word of the\n * shop's world, \"lotion\" in a soap shop — so no product is ever filled with a\n * lifestyle shot of something else: the beta.237 Willow Wick start put a\n * laptop and roses under \"Candle Wick Trimmer\" and an antique tea set under\n * \"Candle Gift Set\".\n *\n * And each must find a hit naming the product's own head noun among its\n * first tags (AGL-3660): the beta.239 Ember & Oak start put a bed with a book,\n * a mug and a camera (its candle a last tag) under \"Hand-Poured Soy Candle\".\n * An object whose own word is not enough ({@link OBJECT_KIN}) is searched by\n * its kin instead of the category alone, and named by them: a single taper\n * candle filled \"Wax Melt Gift Set\".\n *\n * Then, before a product is ever given a photo of something else, it falls\n * back to its own craft (AGL-3660). The Saltmarsh Soap Co start (2026-10-10)\n * found no hit naming \"bar\" or \"box\" among the first tags, and four of its\n * five products took the starter photos — a laptop and roses, a living room\n * of plants. And the beta.242 Tidewater Soap Works start (2026-10-11) showed\n * that the head noun anywhere is not enough: its own weak hits put a sauna\n * under \"Bath Gift Set\", colognes under \"Natural Body Lotion\", a bathroom\n * shelf under \"Soap Bar Trio\" and a soap dispenser under its starter size,\n * while the collection tiles beside them, searched for the category, were\n * good. So the searches are ranked by how sure they are ({@link AiStockSearch.tier}):\n *\n * 1. Its own: the head noun (or its kin) among the first tags, as above.\n * 2. `borrow`: a photo OF its category — the category alone, then the craft's\n * broad searches (\"handmade soap\", \"natural skincare\"), one of the\n * product's kin or the craft's own names among the first tags. A product\n * may repeat one the job already shows, a collection tile's photo or\n * another product's ({@link aiLayoutStockPhotoSource}): a borrowed\n * on-topic photo beats a weak specific one.\n * 3. `weak`: the same searches again, the head noun named anywhere among the\n * tags (no extra search: the page remembers its answers), a gift's own\n * wrapper with the craft (\"soap gift box\"), and the craft's broad searches,\n * any hit naming the craft itself ({@link AiStockSiteTerms.core}).\n *\n * Every one of them turns down a room or a scene, a fragrance bottle, and\n * what the product's kin shuns (a pump for a bar of soap), unless the\n * product names it. A size never names the product: \"Bath Gift Set Starter\n * Size\" is a bath gift set.\n */\nexport function aiStockProductSearches(\n slot: Pick<AiLayoutPictureSlot, 'aspect' | 'product'>,\n craft: string,\n domain: readonly string[] = [],\n fallback: AiStockProductFallback = {},\n): AiStockSearch[] {\n const orientation = aiStockOrientation(slot.aspect)\n const size = orientation === 'vertical' ? { minHeight: 900 } : { minWidth: 900 }\n const craftStems = stemList(craft)\n const world = new Set([...domain, ...craftStems])\n const subjects = (slot.product?.subjects ?? [])\n .map((raw) => aiStockSubjectWords(raw.replace(PRODUCT_SIZES, ' '), ''))\n .filter(Boolean)\n // The product's head noun is its name's: \"candle\" of \"Hand-Poured Soy Candle\".\n const own = subjects[0] ?? ''\n const object = aiStockObjectWord(own)\n const kin = object\n ? objectKin(object, [...craftStems, ...domain, ...stemList(subjects.join(' '))])\n : null\n const kinPhrases = kinStems(kin)\n // A product of the shop's world beside its category is held to either:\n // a soap shop's body lotion names \"lotion\", never \"soap\".\n const ownWorld = stemList(own).filter(\n (stem) => world.has(stem) && !WRAPPERS.has(stem) && !craftStems.includes(stem),\n )\n const category = craft && ownWorld.length ? [...craftStems, ...ownWorld] : []\n const core = [...new Set([...craftStems, ...(fallback.core ?? [])])]\n const shun = (kin?.shun ?? []).map(aiStockStem)\n type Query = {\n query: string\n subject: string\n object: string\n lead: boolean\n broad?: boolean\n tier?: 'borrow' | 'weak'\n }\n const queries: Query[] = []\n for (const subject of subjects) {\n const stems = stemList(subject)\n const qualifier = kin?.qualifier ?? ''\n const query = kin\n ? !qualifier || stems.includes(aiStockStem(qualifier))\n ? subject\n : kin.after\n ? `${subject} ${qualifier}`\n : `${qualifier} ${subject}`\n : craft && !stems.some((stem) => world.has(stem))\n ? `${craft} ${subject}`\n : subject\n queries.push({ query, subject, object, lead: true })\n }\n // The category alone stands in only for a thing that is no more than of\n // it; a thing that is its own word of the shop's world is searched by that\n // word (\"lotion\"). Its hits are still scored by the product's own words: a\n // soy candle over a taper.\n if (kin)\n for (const query of kin.queries)\n queries.push({ query, subject: own || query, object, lead: true })\n else if (object && ownWorld.includes(object))\n queries.push({ query: object, subject: own, object, lead: true })\n else if (craft)\n queries.push({ query: craft, subject: own || craft, object: craft, lead: true, tier: 'borrow' })\n const held = [...queries]\n // 2. A photo OF its category, which may be one the job already shows.\n for (const query of fallback.broad ?? [])\n queries.push({ query, subject: own, object: '', lead: true, broad: true, tier: 'borrow' })\n // 3. The head noun anywhere among the tags, by the same searches.\n for (const entry of held) queries.push({ ...entry, lead: false, tier: 'weak' })\n // A gift is its craft's: \"bath gift box\" asks for a \"soap gift box\".\n const wrapped = own\n .split(/\\s+/)\n .filter((word) => WRAPPERS.has(word) && aiStockStem(word) !== object)\n const gift = wrapped.find((word) => GIFT_WRAPPERS.has(word))\n if (craft && gift && !kin)\n queries.push({\n query: `${craft} ${wrapped.join(' ')}`,\n subject: own,\n object: aiStockStem(gift),\n lead: false,\n tier: 'weak',\n })\n // The craft's own broad searches, any hit naming the craft.\n for (const query of fallback.broad ?? [])\n queries.push({ query, subject: own, object: '', lead: false, broad: true, tier: 'weak' })\n // What a borrowed photo is OF: the product's kin, its own word of the shop's world, else the craft.\n const borrowed = kinPhrases.length ? kinPhrases : ownWorld.length ? ownWorld : core\n const seen = new Set<string>()\n const searches: AiStockSearch[] = []\n for (const entry of queries) {\n const query = clip(entry.query)\n const key = `${query}|${entry.lead}|${entry.object}|${entry.broad === true}|${entry.tier ?? ''}`\n if (!query || seen.has(key)) continue\n seen.add(key)\n const common = {\n query,\n orientation,\n ...size,\n subject: entry.subject,\n product: true,\n ...(entry.tier ? { tier: entry.tier } : {}),\n ...(shun.length ? { shun } : {}),\n }\n if (entry.broad) {\n const heldTo = [...new Set([...core, ...ownWorld])]\n searches.push({\n ...common,\n broad: true,\n ...(entry.lead\n ? {\n leadAny: borrowed,\n ...(kinPhrases.length ? { kin: kinPhrases } : {}),\n ...(heldTo.length ? { category: heldTo } : {}),\n }\n : core.length\n ? { category: core }\n : {}),\n })\n continue\n }\n searches.push({\n ...common,\n // Named anywhere, the hit's first tags are still of the shop's world:\n // a bed with a book, its candle a last tag, is not a candle's photo.\n ...(entry.lead ? { lead: true } : { leadWorld: true }),\n ...(entry.object ? { object: entry.object } : {}),\n ...(kinPhrases.length && entry.object === object ? { kin: kinPhrases } : {}),\n ...(craft ? { requires: craft } : {}),\n ...(category.length ? { category } : {}),\n })\n }\n return searches\n}\n\n/** The searches a slot tries, in order, most specific first, each distinct. */\nexport function aiStockSearchesFor(\n slot: Pick<AiLayoutPictureSlot, 'role' | 'alt' | 'aspect'>,\n terms: Pick<AiStockSiteTerms, 'business' | 'craft' | 'domain' | 'broad'> &\n Partial<Pick<AiStockSiteTerms, 'making' | 'core'>>,\n subject: string,\n part?: AiStockSlotPart,\n): AiStockSearch[] {\n const orientation = aiStockOrientation(slot.aspect)\n const size =\n slot.role === 'hero'\n ? { minWidth: 1600 }\n : orientation === 'vertical'\n ? { minHeight: 900 }\n : { minWidth: 900 }\n const domain = new Set(terms.domain)\n const object = aiStockObjectWord(subject)\n const subjectStems = stemList(subject)\n const kin = object ? objectKin(object, [...terms.domain, ...subjectStems]) : null\n const kinPhrases = kinStems(kin)\n // The craft qualifies a subject that does not already name the site's world.\n const namesWorld = subjectStems.some((stem) => domain.has(stem))\n // A tile of the shop's world beside its category is held to either: a soap\n // shop's \"Body care\" tile names \"body\", never \"soap\" (AGL-3660).\n const ownWorld = subjectStems.filter(\n (stem) => domain.has(stem) && !WRAPPERS.has(stem) && stem !== terms.craft,\n )\n // A hero of a craft names the craft itself: the Saltmarsh Soap Co hero\n // (2026-10-10) was a florist's bouquet tagged \"natural\" (AGL-3660).\n const core = terms.core ?? []\n const qualify = (phrase: string) =>\n terms.craft && !namesWorld && !stemList(phrase).includes(terms.craft)\n ? `${terms.craft} ${phrase}`\n : phrase\n type Query = {\n query: string\n broad?: boolean\n people?: boolean\n held?: boolean\n category?: boolean\n }\n // A collection tile is product-like: held to the shop's category and its\n // own object among the first tags, and searched by its object's kin, never\n // the category's world alone (AGL-3660).\n const collection = part === 'collection' && Boolean(terms.craft)\n const broad: Query[] = kin && collection\n ? []\n : terms.broad.map((query) => ({ query, broad: true, category: collection }))\n // The maker at work, held to the craft: never \"hands\" (AGL-3660).\n const making: Query[] = (terms.making ?? []).map((query) => ({\n query,\n broad: true,\n category: true,\n }))\n const thing: Query[] = subject\n ? [\n { query: qualify(subject), held: true },\n ...(kin\n ? kin.queries.map((query) => ({ query, held: true }))\n : [{ query: qualify(object), held: true }]),\n ]\n : []\n const queries: Query[] =\n slot.role === 'hero'\n ? [{ query: terms.business, broad: true }, ...broad]\n : slot.role === 'about'\n ? [\n ...(part === 'story' ? making : []),\n {\n query: `${terms.business} ${subject}`,\n broad: true,\n people: true,\n },\n { query: terms.business, broad: true, people: true },\n ...(part === 'story' ? [] : making),\n ...broad,\n ]\n : [...(part === 'story' ? making : []), ...thing, ...broad]\n const seen = new Set<string>()\n const searches: AiStockSearch[] = []\n for (const raw of queries) {\n const query = clip(raw.query)\n const key = `${query}|${raw.people === true}`\n if (!query || seen.has(key)) continue\n seen.add(key)\n const held = raw.held === true && (collection || kinPhrases.length > 0)\n searches.push({\n query,\n orientation,\n ...size,\n ...(raw.people ? { people: true } : {}),\n ...(raw.broad ? { broad: true } : {}),\n ...(held && kinPhrases.length ? { kin: kinPhrases } : {}),\n ...(held && collection ? { lead: true } : {}),\n ...(terms.craft && (raw.category || (raw.held && collection))\n ? {\n requires: terms.craft,\n ...(ownWorld.length ? { category: [terms.craft, ...ownWorld] } : {}),\n }\n : {}),\n ...(slot.role === 'hero' && core.length ? { category: core } : {}),\n // A hero is OF the site's world: its first tag names it (AGL-3760).\n ...(slot.role === 'hero' ? { first: true } : {}),\n })\n }\n return searches\n}\n\n/** What a hit is judged by. */\nexport interface AiStockJudgement {\n /** The words the picture is of; empty for a picture of the site's world. */\n subject?: string\n /** The site's domain stems ({@link AiStockSiteTerms.domain}). */\n domain?: readonly string[]\n /**\n * Whether a hit must name the subject's object. A broad search, a hero\n * and an about picture need only name the domain.\n */\n strict?: boolean\n /** A word every hit must name: a product's photo names the shop's category (AGL-3676). */\n requires?: string\n /** Words of which a hit must name one, `requires` among them ({@link AiStockSearch.category}). */\n category?: readonly string[]\n /** The thing a hit must name, where it is not the subject's own (AGL-3660). */\n object?: string\n /** Phrases naming the object where its word is not enough; one of them is then required, and stands for the category. */\n kin?: readonly string[]\n /** Whether the object must be among the hit's first tags (AGL-3660). */\n lead?: boolean\n /** Whether the hit's first tags must name the site's world ({@link AiStockSearch.leadWorld}). */\n leadWorld?: boolean\n /** Whether the hit's first tag must name the site's world ({@link AiStockSearch.first}). */\n first?: boolean\n /** The stems of the site's business type or brief, which let a sensitive topic in ({@link AiStockSiteTerms.named}). */\n named?: readonly string[]\n /** Rival crafts: a hit naming one is rejected unless it names the site's core words ({@link AiStockSiteTerms.rivals}). */\n rivals?: ReadonlyArray<{ words: readonly string[]; core: readonly string[] }>\n /** Phrases of which one must be among the hit's first tags ({@link AiStockSearch.leadAny}). */\n leadAny?: readonly string[]\n /** Whether it judges for a product: no room, no scene, no fragrance bottle (AGL-3660). */\n product?: boolean\n /** Words a hit never carries unless the subject or the brief names them ({@link AiStockSiteTerms.shun}). */\n shun?: readonly string[]\n}\n\n/** The words of a photo's page address at its library, its id dropped: \"robin-bird-songbird-garden-winter\". */\nfunction pageSlug(pageUrl: string): string {\n try {\n const last = decodeURIComponent(new URL(pageUrl).pathname)\n .split('/')\n .filter(Boolean)\n .pop()\n return last?.replace(/-?\\d+$/, '') ?? ''\n } catch {\n return ''\n }\n}\n\n/** A hit's words: the first few (what it is OF), every one, and each tag's phrase. */\nfunction hitWords(photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>) {\n const slug = pageSlug(photo.pageUrl)\n const tags = (photo.tags ?? [])\n .map((tag) => tag.toLowerCase().trim())\n .filter(Boolean)\n const lead = new Set(stemList([...tags.slice(0, 3), slug].join(' ')))\n const all = new Set(stemList([...tags, photo.alt ?? '', slug].join(' ')))\n const phrases = [\n ...tags.map((tag) => stemList(tag).join(' ')),\n stemList(photo.alt ?? '').join(' '),\n stemList(slug).join(' '),\n ]\n const leadPhrases = [\n ...tags.slice(0, 3).map((tag) => stemList(tag).join(' ')),\n stemList(slug).join(' '),\n ]\n /** The first tag: what the photo is most of all. */\n const firstPhrase = stemList(tags[0] ?? '').join(' ')\n const rejected = tags.some(\n (tag) =>\n REJECTED_TAGS.has(tag) ||\n tag.split(/\\s+/).some((word) => REJECTED_TAGS.has(word)),\n )\n // Whole words only, a hyphenated one kept whole: \"cross-stitch\" is not a cross.\n const words = new Set(\n [...tags, (photo.alt ?? '').toLowerCase()]\n .join(' ')\n .split(/[^a-zÀ-ɏ-]+/)\n .filter((word) => word.length > 1)\n .map(aiStockStem),\n )\n return { lead, all, phrases, leadPhrases, firstPhrase, rejected, words }\n}\n\n/** Whether a phrase is among a hit's phrases, word for word. */\nconst among = (phrases: readonly string[], phrase: string) =>\n phrases.some((found) => ` ${found} `.includes(` ${phrase} `))\n\n/**\n * Whether a hit carries a topic its site never named ({@link SENSITIVE_TOPICS}):\n * a cross, a grave, a flag, a gun, a glass of wine, a child, a mannequin.\n */\nexport function aiStockSensitive(\n photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>,\n named: readonly string[] = [],\n): boolean {\n const { words: found } = hitWords(photo)\n const site = new Set(named)\n return SENSITIVE_STEMS.some(\n (topic) =>\n [...topic.words].some((word) => found.has(word)) &&\n ![...topic.allow].some((word) => site.has(word)),\n )\n}\n\n/**\n * How well a hit shows what a slot needs (AGL-3660), or 0 when it must not\n * fill it: a mockup or a blank never; a topic the site never named never\n * ({@link aiStockSensitive}); a picture of a thing only when the hit\n * names its object AND either the site's world or the subject's own\n * two-word phrase (\"bud vase\", \"wick trimmer\"); anything else only when it\n * names the site's world (when the site names one). Among the accepted, the\n * object among the hit's first tags counts 4 (a mention among its last, 2),\n * the subject's two-word phrase 3, each of its other words 1, and the\n * site's world 1, plus a quarter when it is among the first tags.\n */\nexport function aiStockRelevance(\n photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>,\n judgement: AiStockJudgement,\n): number {\n const hit = hitWords(photo)\n if (hit.rejected) return 0\n if (aiStockSensitive(photo, judgement.named)) return 0\n // Glass art is not pottery: a rival craft's photo names this craft's own words.\n for (const rival of judgement.rivals ?? [])\n if (\n rival.words.some((word) => hit.all.has(word)) &&\n !rival.core.some((word) => hit.all.has(word))\n )\n return 0\n const subject = stemList(judgement.subject ?? '')\n // What the slot or the brief names lets a shunned word, a room or a fragrance in.\n const owned = new Set([...subject, ...(judgement.named ?? [])])\n // A dispenser is not a soapmaker's, nor a pump a bar's (AGL-3660).\n if ((judgement.shun ?? []).some((word) => hit.all.has(word) && !owned.has(word)))\n return 0\n if (judgement.product) {\n // A sauna, a bathroom shelf: a room is never the product.\n for (const word of hit.lead)\n if (PRODUCT_SCENES.has(word) && !owned.has(word)) return 0\n // Colognes are not a lotion: a fragrance's bottle only for a fragrance.\n if (\n ![...FRAGRANCE_BOTTLES].some((word) => owned.has(word)) &&\n [...hit.lead].some((word) => FRAGRANCE_BOTTLES.has(word))\n )\n return 0\n }\n // A borrowed photo is OF the product's category.\n const leadAny = judgement.leadAny ?? []\n if (leadAny.length && !leadAny.some((phrase) => among(hit.leadPhrases, phrase)))\n return 0\n const kin = judgement.kin ?? []\n const kinNamed = kin.some((phrase) => among(hit.phrases, phrase))\n const kinLead = kin.some((phrase) => among(hit.leadPhrases, phrase))\n const required = stemList(judgement.requires ?? '')\n const category = (judgement.category ?? []).flatMap(stemList)\n const anyOf = category.length ? [...new Set([...required, ...category])] : []\n const demanded = required.length > 0 || anyOf.length > 0\n const meets = anyOf.length\n ? anyOf.some((stem) => hit.all.has(stem))\n : required.every((stem) => hit.all.has(stem))\n // An object's kin stands for the category: a wax melt is the candle shop's.\n if (demanded && !kinNamed && !meets) return 0\n const object =\n judgement.object ??\n (judgement.subject ? aiStockObjectWord(judgement.subject) : '')\n const domain = (judgement.domain ?? []).filter((stem) => stem !== object)\n // A hit naming the word it must name is of the site's world: a product's\n // category is that world even where it is the product's own object.\n const world =\n demanded || kinNamed || domain.some((stem) => hit.all.has(stem))\n const worldLead =\n (anyOf.length\n ? anyOf.some((stem) => hit.lead.has(stem))\n : required.length > 0 && required.every((stem) => hit.lead.has(stem))) ||\n kinLead ||\n domain.some((stem) => hit.lead.has(stem))\n if (judgement.leadWorld && !worldLead) return 0\n // The first tag alone, never the page's address: Pixabay's slug repeats a\n // late tag (\"coffee-latte-art-candle-…\"). A site whose words name no world\n // holds its hero to none.\n const worldStems = new Set([...anyOf, ...required, ...domain])\n if (judgement.first && (worldStems.size || kin.length)) {\n const firstWorld =\n hit.firstPhrase.split(' ').some((stem) => worldStems.has(stem)) ||\n kin.some((phrase) => among([hit.firstPhrase], phrase))\n if (!firstWorld) return 0\n }\n // What the photo is most of all: its first tag names the object, its kin or what it must be OF.\n const firstNamed = (phrases: readonly string[]) =>\n phrases.some((phrase) => Boolean(phrase) && among([hit.firstPhrase], phrase))\n const pair = subject.length >= 2 ? subject.slice(-2).join(' ') : ''\n const phrased = Boolean(pair) && among(hit.phrases, pair)\n let score = 0\n if (judgement.strict && object) {\n // An object with kin is named only by them: \"melt\" alone is resin art.\n const named = kin.length ? kinNamed : hit.all.has(object)\n if (!named) return 0\n const leading = kin.length ? kinLead : hit.lead.has(object)\n // A lifestyle scene whose object is a last tag is not a photo OF it.\n if (judgement.lead && !leading) return 0\n if (domain.length && !world && !phrased) return 0\n score += leading ? 4 : 2\n if (kinNamed) score += 3\n if (firstNamed(kin.length ? kin : [object])) score += 1\n } else if (domain.length) {\n if (!world) return 0\n }\n if (leadAny.length && firstNamed(leadAny)) score += 1\n if (phrased) score += 3\n for (const word of new Set(subject))\n if (word !== object && hit.all.has(word)) score += 1\n if (world) score += worldLead ? 1.25 : 1\n return Math.max(score, 0.5)\n}\n\n/**\n * A search's acceptable hits in the order they are tried (AGL-3660): those\n * not placed yet, among the first few the library returned, those it must\n * not take dropped ({@link aiStockRelevance}), best first; the seed turns\n * the hits that score alike, so two jobs differ and one job repeats itself.\n */\nexport function aiStockRank(\n photos: readonly StockPhoto[],\n used: ReadonlySet<string>,\n seed: string,\n judgement: AiStockJudgement = {},\n): StockPhoto[] {\n const scored = photos\n .filter((photo) => !used.has(stockPhotoSourceKey(photo)))\n .slice(0, AI_LAYOUT_STOCK_PICK_WINDOW)\n .map((photo) => ({ photo, score: aiStockRelevance(photo, judgement) }))\n .filter((entry) => entry.score > 0)\n if (!scored.length) return []\n const turn = aiLayoutSeedNumber(seed)\n const ranked: StockPhoto[] = []\n for (const score of [...new Set(scored.map((entry) => entry.score))].sort(\n (a, b) => b - a,\n )) {\n const tier = scored.filter((entry) => entry.score === score)\n const start = turn % tier.length\n for (const entry of [...tier.slice(start), ...tier.slice(0, start)])\n ranked.push(entry.photo)\n }\n return ranked\n}\n\n/** The pick among a search's hits: the first {@link aiStockRank} would try, or `null`. */\nexport function aiStockPick(\n photos: readonly StockPhoto[],\n used: ReadonlySet<string>,\n seed: string,\n judgement: AiStockJudgement = {},\n): StockPhoto | null {\n return aiStockRank(photos, used, seed, judgement)[0] ?? null\n}\n\n/**\n * The library photos a stored page already shows: every `image` whose\n * source is the site's media reference. Starter photos are the platform's,\n * not the job's, and are not listed.\n */\nexport function aiStockPlacedSrcs(\n nodes: NodesMap | null | undefined,\n): string[] {\n const map = (nodes ?? {}) as unknown as Record<\n string,\n { componentId?: string; props?: Record<string, unknown> }\n >\n const out: string[] = []\n for (const node of Object.values(map)) {\n const src = node?.componentId === 'image' ? node.props?.['src'] : null\n if (typeof src === 'string' && src.startsWith('media:')) out.push(src)\n }\n return out\n}\n\n/**\n * What this process has placed for each job, by source key and asset src,\n * with the scope (the page's seed) that placed it (AGL-3660). It spans the\n * passes of one job that run here, so a page, the products or a post built\n * later does not place what an earlier one did, while a pass repeated over\n * its own page keeps its own photos. Bounded; the oldest job goes first.\n */\nconst JOB_PHOTOS = new Map<string, Map<string, string>>()\nconst JOB_PHOTOS_MAX = 200\n\nfunction jobPhotos(key: string | null): Map<string, string> | null {\n if (!key) return null\n let placed = JOB_PHOTOS.get(key)\n if (!placed) {\n placed = new Map()\n JOB_PHOTOS.set(key, placed)\n while (JOB_PHOTOS.size > JOB_PHOTOS_MAX) {\n const oldest = JOB_PHOTOS.keys().next().value\n if (oldest === undefined) break\n JOB_PHOTOS.delete(oldest)\n }\n }\n return placed\n}\n\n/** Forgets every job's placed photos; for specs. */\nexport function aiStockForgetJobPhotos(): void {\n JOB_PHOTOS.clear()\n}\n\nconst EXTENSIONS: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n}\n\nexport interface AiLayoutStockPhotoSourceInput {\n hostId: string\n /** The member the photos are stored as: the job's creator. */\n uid: string\n /** The job's seed, as the starter photos turn by; also the scope a photo is placed under. */\n seed: string\n /** The site's business type, else the job's brief. */\n business: string\n /** The site's language, from its plan (AGL-3750); absent, English. */\n language?: string\n /**\n * The plan's photo words, in English (AGL-3760): what a site in another\n * language is searched by, in place of its business type and its alt texts,\n * unless its business type names a business listed in English\n * (`aiStockBusinessNoun`, AGL-3779), which leads.\n */\n photoWords?: string\n /**\n * The English name of the kind of site the person picked (AGL-3771): what a\n * site in another language is searched by when its business type names no\n * business listed in English (`aiStockBusinessNoun`, AGL-3779) and its plan\n * gave no photo words, rather than its business type in its own language.\n */\n kindWords?: string\n /** The page's section names, by plan index. */\n sectionNames: readonly string[]\n /**\n * The job the member started (`aiOriginJobId`), so a photo is placed once\n * across its pages. Absent, only the page itself is kept free of repeats.\n */\n jobId?: string\n /** Asset srcs or source keys the job's other pages already show. */\n avoid?: readonly string[]\n /** The most searches this source sends; a page's own bound where absent. A store's products search more (AGL-3676). */\n searches?: number\n signal?: AbortSignal\n}\n\nexport interface AiLayoutStockPhotoDeps {\n provider?: () => StockPhotoProvider | null\n ingest?: () => PluginMediaIngest | null\n budgetMs?: number\n}\n\n/** A slot's choice: the accepted hits it may be filled from, best first, and the query that found them. */\ninterface AiStockChoice {\n candidates: StockPhoto[]\n query: string\n /** A photo another slot of the job already shows, reused rather than an off-topic one (AGL-3660). */\n repeat?: boolean\n}\n\n/**\n * A job's language and English photo words (AGL-3760), and the English name\n * of its kind of site (AGL-3771), as a stock photo source takes them.\n */\nexport function aiStockPhotoWordsOf(job: {\n plan?: Pick<AiBuildPlan, 'language' | 'photoWords'> | null\n inputs?: Readonly<Record<string, unknown>> | null\n}): Pick<AiLayoutStockPhotoSourceInput, 'language' | 'photoWords' | 'kindWords'> {\n const plan = job.plan\n const kind = job.inputs ? aiSiteKindOfInputs(job.inputs) : null\n // \"Restaurant & café\" searches as \"restaurant cafe\".\n const kindWords = kind ? kind.label.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').replace(/&/g, ' ').replace(/\\s+/g, ' ').trim().toLowerCase() : ''\n return {\n ...(plan?.language ? { language: plan.language } : {}),\n ...(plan?.photoWords ? { photoWords: plan.photoWords } : {}),\n ...(kindWords ? { kindWords } : {}),\n }\n}\n\n/**\n * The subject a plan's photo words lead with (AGL-3769): its first word that\n * is not filler, with the place or person words that follow it — \"bakery\" of\n * \"bakery pan dulce conchas\", \"candle shop\" of \"candle shop soy candles\",\n * \"ceramic artist\" of \"ceramic artist stoneware bowls\". The words are subject\n * first, never an English noun phrase with its head last, and what follows\n * the subject may be the brief's own names in English letters: Panaderia La\n * Espiga Dorada's \"pan dulce conchas\" read as the business, made \"concha\" its\n * craft, and placed purple ceanothus flowers, tagged \"ceanothus concha\", as\n * its hero. Empty when every word is filler.\n */\nexport function aiStockPhotoWordsSubject(photoWords: string): string {\n const list = contentWords(photoWords)\n const start = list.findIndex((word) => !FILLER.has(word) && !SITE_KINDS.has(word))\n if (start < 0) return ''\n let end = start + 1\n while (end < list.length && (VENUES.has(list[end]) || ROLES.has(list[end]))) end += 1\n return list.slice(start, end).join(' ')\n}\n\n/**\n * What a source's photos are searched and judged by (AGL-3760, AGL-3769): a\n * site in another language by an English subject ({@link aiStockSourceSubject}:\n * its business named in English, else its plan's photo words' subject, else\n * its kind of site), every other site by its business type. One reading for\n * every slot of every source — hero, background, gallery, card, product,\n * post — so no slot searches by words another slot is held against.\n */\nexport function aiStockSourceTerms(\n input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords'>,\n): AiStockSiteTerms {\n return aiStockSiteTerms(aiStockSourceSubject(input) || input.business)\n}\n\n/**\n * What a site in another language is searched by ({@link aiStockSourceTerms}),\n * in this order (AGL-3779):\n *\n * 1. The English name of the business its type names, where the curated table\n * knows it ({@link aiStockBusinessNoun}): \"florist\" for \"Una floristería en\n * Sevilla\". It leads whatever the plan's photo words say, because the words\n * are the model's and the table is not: a live plan for that florist gave\n * \"wedding bouquets event flowers\", whose subject, \"wedding\", would have\n * searched every slot, its hero included, by weddings.\n * 2. Its photo words' subject (AGL-3760, AGL-3769), for a business the table\n * does not list.\n * 3. The English name of its kind of site (AGL-3771), where the plan gave\n * none. Panaderia El Trigal's pages searched \"con pan dulce\" and placed the\n * Río Dulce; searched by its kind, a bakery's hero took a coffee mug\n * (\"restaurant cafe\"), which is why it comes last.\n *\n * The photo words' other words were never searched by (AGL-3769), so a site\n * the table names is searched by its name alone. Empty for every other site.\n */\nfunction aiStockSourceSubject(\n input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords'>,\n): string {\n if (!aiLayoutSpeaksOtherThanEnglish(input.language)) return ''\n return (\n aiStockBusinessNoun(input.business) ||\n aiStockPhotoWordsSubject(input.photoWords ?? '') ||\n (input.kindWords ?? '').trim()\n )\n}\n\n/**\n * The source for one page, or `null` when this deployment has no stock\n * photo library or no media door, which leaves every slot to the starters.\n */\nexport function aiLayoutStockPhotoSource(\n input: AiLayoutStockPhotoSourceInput,\n deps: AiLayoutStockPhotoDeps = {},\n): AiLayoutPictureSource | null {\n const provider = (deps.provider ?? stockPhotoProvider)()\n const ingest = (deps.ingest ?? pluginMediaIngest)()\n if (!provider || !ingest || !input.hostId || !input.uid) return null\n // The libraries are tagged in English (AGL-3760). A Spanish bakery's type,\n // \"Una panadería familiar de San Antonio con pan dulce…\", read as the\n // business \"con pan dulce\", and its hero searched that and placed the Río\n // Dulce at dusk; a site in another language is searched by its plan's\n // English photo words' subject ({@link aiStockSourceTerms}), and its slots'\n // alt texts, in its own language, name no subject a search could use.\n const english = aiStockSourceSubject(input)\n const terms = aiStockSourceTerms(input)\n return async (slots) => {\n const timeout = AbortSignal.timeout(\n deps.budgetMs ?? AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS,\n )\n const signal = input.signal\n ? AbortSignal.any([input.signal, timeout])\n : timeout\n const scope = input.seed\n const job = jobPhotos(input.jobId ? `${input.hostId}:${input.jobId}` : null)\n const avoid = new Set(input.avoid ?? [])\n /** Placed elsewhere in the job: by another page in this process, or one the caller read. */\n const elsewhere = (key: string) =>\n avoid.has(key) || (job?.has(key) === true && job.get(key) !== scope)\n /** Source keys this page has claimed for a slot, or turned down. */\n const claimed = new Set<string>()\n /** Asset srcs this page has placed. */\n const placedSrcs = new Set<string>()\n const answers = new Map<string, Promise<StockPhoto[] | null>>()\n let searches = 0\n let storing = true\n const remember = (sourceKey: string, src: string) => {\n placedSrcs.add(src)\n job?.set(sourceKey, scope)\n job?.set(src, scope)\n }\n /** A search's hits; the same words twice are answered from memory, and `null` once the page's searches are spent. */\n const search = (wanted: AiStockSearch): Promise<StockPhoto[] | null> => {\n const request: StockPhotoSearchRequest = { ...wanted }\n delete (request as AiStockSearch).broad\n delete (request as AiStockSearch).subject\n delete (request as AiStockSearch).requires\n delete (request as AiStockSearch).object\n delete (request as AiStockSearch).kin\n delete (request as AiStockSearch).lead\n delete (request as AiStockSearch).leadWorld\n delete (request as AiStockSearch).first\n delete (request as AiStockSearch).category\n const key = JSON.stringify([\n request.query,\n request.orientation,\n request.people === true,\n ])\n const known = answers.get(key)\n if (known) return known\n if (searches >= (input.searches ?? AI_LAYOUT_STOCK_SEARCHES_PER_PAGE))\n return Promise.resolve(null)\n searches += 1\n const asked = provider\n .search(request, { signal })\n .then((found) => found?.photos ?? [])\n .catch(() => [] as StockPhoto[])\n answers.set(key, asked)\n return asked\n }\n /** The photo placed in the site's library, a copy it holds or a new one; `null` when it cannot be placed. */\n const keep = async (\n photo: StockPhoto,\n slot: AiLayoutPictureSlot,\n query: string,\n repeat = false,\n ): Promise<AiLayoutPicturePhoto | null> => {\n const sourceKey = stockPhotoSourceKey(photo)\n try {\n const kept = await ingest.findStockPhoto({\n hostId: input.hostId,\n sourceKey,\n })\n if (kept) {\n // Held because a slot of this page or another page of the job shows it.\n if (!repeat && (placedSrcs.has(kept.src) || elsewhere(kept.src)))\n return null\n remember(sourceKey, kept.src)\n return {\n src: kept.src,\n width: kept.width ?? photo.width,\n height: kept.height ?? photo.height,\n }\n }\n // A refusal to store (the storage band, a lockdown) holds for the\n // whole page, so the rest of it reuses what it can and copies nothing.\n if (!storing || signal.aborted) return null\n const bytes = await provider.download(photo, {\n maxBytes: AI_LAYOUT_STOCK_MAX_BYTES,\n signal,\n })\n if (!bytes || signal.aborted || !storing) return null\n const credit = provider.credit(photo)\n const stored = await ingest.ingest({\n hostId: input.hostId,\n uid: input.uid,\n fileName: `${photo.provider}-${photo.id}.${EXTENSIONS[bytes.contentType] ?? 'jpg'}`,\n contentType: bytes.contentType,\n bytes: bytes.bytes,\n alt: slot.alt,\n description: credit.text,\n stockPhoto: {\n key: sourceKey,\n provider: photo.provider,\n providerLabel: credit.providerLabel,\n id: photo.id,\n pageUrl: photo.pageUrl,\n photographer: photo.photographer,\n ...(photo.photographerUrl\n ? { photographerUrl: photo.photographerUrl }\n : {}),\n license: credit.license,\n licenseUrl: credit.licenseUrl,\n attributionRequired: credit.attributionRequired,\n query,\n },\n })\n if (stored.ok) {\n remember(sourceKey, stored.src)\n return {\n src: stored.src,\n width: stored.width ?? photo.width,\n height: stored.height ?? photo.height,\n }\n }\n storing = false\n const refusal = stored as Extract<\n PluginMediaIngestResult,\n { ok: false }\n >\n console.warn(\n 'ai layout pictures: the media library refused a stock photo',\n {\n status: refusal.status,\n reason: refusal.reason,\n },\n )\n } catch (error) {\n console.warn('ai layout pictures: a stock photo could not be kept', {\n error: String(error),\n })\n }\n return null\n }\n\n /** How a search's hits are judged for a slot. */\n const judgementFor = (\n slot: AiLayoutPictureSlot,\n request: AiStockSearch,\n subject: string,\n ): AiStockJudgement => ({\n subject: request.subject ?? (request.broad ? '' : subject),\n domain: terms.domain,\n strict:\n (slot.role === 'gallery' && !request.broad) || !!request.requires,\n named: terms.named,\n rivals: terms.rivals,\n ...(terms.shun.length || request.shun?.length\n ? { shun: [...new Set([...terms.shun, ...(request.shun ?? [])])] }\n : {}),\n ...(request.product ? { product: true } : {}),\n ...(request.leadAny?.length ? { leadAny: request.leadAny } : {}),\n ...(request.requires ? { requires: request.requires } : {}),\n ...(request.category ? { category: request.category } : {}),\n ...(request.object ? { object: request.object } : {}),\n ...(request.kin ? { kin: request.kin } : {}),\n ...(request.lead ? { lead: true } : {}),\n ...(request.leadWorld ? { leadWorld: true } : {}),\n ...(request.first ? { first: true } : {}),\n })\n /**\n * The craft's own photos, the last thing a slot of a craft's site is\n * filled from (AGL-3660): its broad searches, any hit naming the craft\n * itself. Never a desk, a laptop or a living room for a soap shop.\n */\n const craftSearches = (slot: AiLayoutPictureSlot): AiStockSearch[] => {\n if (!terms.core.length) return []\n const orientation = aiStockOrientation(slot.aspect)\n const size =\n slot.role === 'hero'\n ? { minWidth: 1600 }\n : orientation === 'vertical'\n ? { minHeight: 900 }\n : { minWidth: 900 }\n return terms.broad.map((query) => ({\n query: clip(query),\n orientation,\n ...size,\n broad: true,\n category: terms.core,\n ...(slot.role === 'hero' ? { first: true } : {}),\n ...(slot.product ? { product: true, tier: 'weak' as const } : {}),\n }))\n }\n\n // 1. Choose, slot by slot, so the page's choices never collide: each\n // slot claims its best accepted hit before the next slot looks.\n const choices: Array<AiStockChoice | null> = []\n for (const [index, slot] of slots.entries()) {\n if (signal.aborted) {\n choices.push(null)\n continue\n }\n const sectionName = input.sectionNames[slot.sectionIndex] ?? ''\n const subject = english ? '' : aiStockSubjectWords(slot.alt, sectionName)\n let choice: AiStockChoice | null = null\n const requests = [\n ...(slot.product\n ? aiStockProductSearches(slot, terms.craft, terms.domain, {\n broad: terms.broad,\n core: terms.core,\n })\n : aiStockSearchesFor(\n slot,\n terms,\n subject,\n aiStockSlotPart(slot, sectionName),\n )),\n ...craftSearches(slot),\n ]\n /** The slot's accepted hits for a search; `null` once the page's searches are spent. */\n const accepted = async (\n request: AiStockSearch,\n repeat: boolean,\n ): Promise<StockPhoto[] | null> => {\n const found = await search(request)\n if (found === null) return null\n const blocked = new Set<string>()\n if (!repeat) {\n for (const key of claimed) blocked.add(key)\n for (const hit of found) {\n const key = stockPhotoSourceKey(hit)\n if (elsewhere(key)) blocked.add(key)\n }\n }\n return aiStockRank(\n found,\n blocked,\n `${input.seed}:${index}:${request.query}`,\n judgementFor(slot, request, subject),\n )\n }\n /** The first of these searches with a hit to take: a new one, or one the job already shows. */\n const choose = async (\n tried: readonly AiStockSearch[],\n repeat: boolean,\n ): Promise<AiStockChoice | null> => {\n for (const request of tried) {\n if (signal.aborted) return null\n // Spent searches answer nothing; those already asked still answer from memory.\n const ranked = await accepted(request, repeat)\n if (!ranked?.length) continue\n if (!repeat) claimed.add(stockPhotoSourceKey(ranked[0] as StockPhoto))\n return {\n candidates: ranked.slice(0, AI_LAYOUT_STOCK_TRIES_PER_SLOT),\n query: request.query,\n ...(repeat ? { repeat: true } : {}),\n }\n }\n return null\n }\n // 2. Nothing new of its own: a product or a hero reuses an on-topic\n // photo another slot of the job already shows (a product may repeat\n // a collection tile's photo, or another product's) before the\n // starters' desk or living room fills it (AGL-3660). Any other\n // picture keeps \"never twice\". A product goes by how sure each\n // search is: its own and its category's photos, new and then\n // repeated, before a weak hit of its own (the Tidewater sauna).\n const repeats = Boolean(slot.product) || slot.role === 'hero'\n const sure = slot.product\n ? requests.filter((request) => request.tier !== 'weak')\n : requests\n const unsure = slot.product\n ? requests.filter((request) => request.tier === 'weak')\n : []\n const phases: Array<[readonly AiStockSearch[], boolean]> = [\n [sure, false],\n ...(repeats ? [[sure, true] as [readonly AiStockSearch[], boolean]] : []),\n ...(unsure.length\n ? [\n [unsure, false] as [readonly AiStockSearch[], boolean],\n [unsure, true] as [readonly AiStockSearch[], boolean],\n ]\n : []),\n ]\n for (const [tried, repeat] of phases) {\n if (choice || signal.aborted) break\n choice = await choose(tried, repeat)\n }\n choices.push(choice)\n }\n\n // 3. Keep, a few at a time; a copy that fails tries the slot's next\n // accepted hit no other slot has claimed. A repeat waits for the\n // slot it repeats, so the library never holds a photo twice.\n const photos: Array<AiLayoutPicturePhoto | null> = slots.map(() => null)\n /** What this pass placed, by source key. */\n const placedByKey = new Map<string, AiLayoutPicturePhoto>()\n const fill = async (index: number) => {\n const choice = choices[index]\n const slot = slots[index]\n if (!choice || !slot) return\n for (const [rank, candidate] of choice.candidates.entries()) {\n if (signal.aborted) return\n const key = stockPhotoSourceKey(candidate)\n if (choice.repeat) {\n const placed =\n placedByKey.get(key) ?? (await keep(candidate, slot, choice.query, true))\n if (placed) {\n photos[index] = placed\n return\n }\n continue\n }\n if (rank > 0) {\n if (claimed.has(key)) continue\n claimed.add(key)\n }\n const placed = await keep(candidate, slot, choice.query)\n if (placed) {\n placedByKey.set(key, placed)\n photos[index] = placed\n return\n }\n }\n }\n const firsts = slots\n .map((_slot, index) => index)\n .filter((index) => !choices[index]?.repeat)\n let next = 0\n const worker = async () => {\n while (next < firsts.length) {\n const index = firsts[next] as number\n next += 1\n await fill(index)\n }\n }\n await Promise.all(\n Array.from(\n { length: Math.min(AI_LAYOUT_STOCK_COPIES_AT_ONCE, firsts.length) },\n worker,\n ),\n )\n for (const [index, choice] of choices.entries())\n if (choice?.repeat) await fill(index)\n return photos\n }\n}\n"],"names":["pluginMediaIngest","STOCK_PHOTO_QUERY_MAX_CHARS","stockPhotoProvider","stockPhotoSourceKey","aiLayoutSeedNumber","aiStorefrontSays","aiLayoutSpeaksOtherThanEnglish","aiSiteKindOfInputs","aiStockBusinessNoun","AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS","AI_LAYOUT_STOCK_SEARCHES_PER_PAGE","AI_LAYOUT_STOCK_PICK_WINDOW","AI_LAYOUT_STOCK_TRIES_PER_SLOT","AI_LAYOUT_STOCK_COPIES_AT_ONCE","AI_LAYOUT_STOCK_MAX_BYTES","AI_STOCK_PHOTO_PAGES_INPUT","AI_STOCK_PHOTO_AVOID_INPUT","words","list","Set","trim","split","STOPWORDS","FILLER","VENUES","ROLES","SITE_KINDS","DOING","BUSINESS_BREAK","PLACE_OR_AUDIENCE","WRAPPERS","REJECTED_TAGS","PRODUCT_SCENES","map","aiStockStem","FRAGRANCE_BOTTLES","SENSITIVE_TOPICS","allow","always","SENSITIVE_STEMS","topic","HAND_IDIOMS","withoutHands","text","reduce","out","idiom","replace","toLowerCase","saysMadeByHand","lower","some","lastIndex","found","test","OBJECT_KIN","objects","within","qualifier","kin","queries","shun","after","objectKin","object","world","find","entry","word","includes","CRAFT_KIN","match","broad","rivals","core","making","contentWords","filter","length","has","endsWith","slice","stemList","CLAUSE_BREAK","businessClauses","businessType","clauses","breaker","RegExp","source","at","opener","matchAll","push","index","businessOf","clause","aiStockBusinessWords","named","join","aiStockCraftWords","business","craft","aiStockSiteTerms","domain","made","firstWorld","kept","stem","add","last","size","groups","group","listed","makingSearches","query","Boolean","subjectOf","aiStockSubjectWords","alt","sectionName","aiStockObjectWord","subject","reverse","clip","aiStockOrientation","aspect","aiStockSlotPart","slot","role","undefined","kinStems","phrase","PRODUCT_SIZES","GIFT_WRAPPERS","aiStockProductSearches","fallback","subjects","orientation","minHeight","minWidth","craftStems","product","raw","own","kinPhrases","ownWorld","category","stems","lead","tier","held","wrapped","gift","borrowed","seen","searches","key","common","heldTo","leadAny","leadWorld","requires","aiStockSearchesFor","terms","part","subjectStems","namesWorld","qualify","collection","thing","people","first","pageSlug","pageUrl","decodeURIComponent","URL","pathname","pop","hitWords","photo","tags","slug","tag","all","phrases","leadPhrases","firstPhrase","rejected","among","aiStockSensitive","site","aiStockRelevance","judgement","hit","rival","owned","kinNamed","kinLead","required","flatMap","anyOf","demanded","meets","every","worldLead","worldStems","firstNamed","pair","phrased","score","strict","leading","Math","max","aiStockRank","photos","used","seed","scored","turn","ranked","sort","a","b","start","aiStockPick","aiStockPlacedSrcs","nodes","node","Object","values","src","componentId","props","startsWith","JOB_PHOTOS","Map","JOB_PHOTOS_MAX","jobPhotos","placed","get","set","oldest","keys","next","value","delete","aiStockForgetJobPhotos","clear","EXTENSIONS","aiStockPhotoWordsOf","job","plan","kind","inputs","kindWords","label","normalize","language","photoWords","aiStockPhotoWordsSubject","findIndex","end","aiStockSourceTerms","input","aiStockSourceSubject","aiLayoutStockPhotoSource","deps","provider","ingest","hostId","uid","english","slots","timeout","AbortSignal","budgetMs","signal","any","scope","jobId","avoid","elsewhere","claimed","placedSrcs","answers","storing","remember","sourceKey","search","wanted","request","JSON","stringify","known","Promise","resolve","asked","then","catch","keep","repeat","findStockPhoto","width","height","aborted","bytes","download","maxBytes","credit","stored","fileName","id","contentType","description","stockPhoto","providerLabel","photographer","photographerUrl","license","licenseUrl","attributionRequired","ok","refusal","console","warn","status","reason","error","String","judgementFor","craftSearches","choices","entries","sectionNames","sectionIndex","choice","requests","accepted","blocked","choose","tried","candidates","repeats","sure","unsure","phases","placedByKey","fill","rank","candidate","firsts","_slot","worker","Array","from","min"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,iBAAiB,QAGZ,kDAAiD;AACxD,SACEC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,QAKd,mDAAkD;AAEzD,SACEC,kBAAkB,QAIb,2CAAuC;AAC9C,SAASC,gBAAgB,QAAQ,6CAAyC;AAC1E,SAASC,8BAA8B,QAAQ,yCAAqC;AAEpF,SAASC,kBAAkB,QAAQ,4BAAwB;AAC3D,SAASC,mBAAmB,QAAQ,+BAA2B;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGC,GAED,+EAA+E,GAC/E,OAAO,MAAMC,mCAAmC,MAAM;AAEtD,yGAAyG,GACzG,OAAO,MAAMC,oCAAoC,GAAE;AAEnD,mCAAmC,GACnC,OAAO,MAAMC,8BAA8B,GAAE;AAE7C,kEAAkE,GAClE,MAAMC,iCAAiC;AAEvC,8BAA8B,GAC9B,MAAMC,iCAAiC;AAEvC,wDAAwD,GACxD,OAAO,MAAMC,4BAA4B,IAAI,OAAO,KAAI;AAExD;;;CAGC,GACD,OAAO,MAAMC,6BAA6B,kBAAiB;AAE3D;;;;CAIC,GACD,OAAO,MAAMC,6BAA6B,kBAAiB;AAE3D,MAAMC,QAAQ,CAACC,OAAiB,IAAIC,IAAID,KAAKE,IAAI,GAAGC,KAAK,CAAC;AAE1D,iCAAiC,GACjC,MAAMC,YAAYL,MAChB,6GACE,4GACA,iGACA,mFACA;AAGJ;;;CAGC,GACD,MAAMM,SAASN,MACb,kHACE,sGACA,wGACA,yGACA,iHACA,0GACA,qGACA,qGACA,4GACA,sDACA,oHAAoH;AACpH,yEACA,yGACA;AAGJ,2FAA2F,GAC3F,MAAMO,SAASP,MACb,+GACE,qGACA;AAGJ,gFAAgF,GAChF,MAAMQ,QAAQR,MACZ;AAGF,kHAAkH,GAClH,MAAMS,aAAaT,MACjB,yGACE;AAGJ,yGAAyG,GACzG,MAAMU,QACJ;AAEF,6CAA6C,GAC7C,MAAMC,iBACJ;AAEF,qGAAqG,GACrG,MAAMC,oBACJ;AAEF;;;CAGC,GACD,MAAMC,WAAWb,MACf,kHACE;AAGJ;;;;CAIC,GACD,MAAMc,gBAAgBd,MACpB,iGACE;AAGJ;;;;;CAKC,GACD,MAAMe,iBAAiB,IAAIb,IACzB;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAACc,GAAG,CAACC;AAGR;;;;;CAKC,GACD,MAAMC,oBAAoB,IAAIhB,IAC5B;IAAC;IAAW;IAAY;IAAa;IAAW;IAAY;IAAU;IAAO;IAAY;CAAY,CAACc,GAAG,CACvGC;AAIJ;;;;;;;;CAQC,GACD,MAAME,mBAKD;IACH;QACE,YAAY;QACZnB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAY;YAAU;YAAgB;SAAU;IAC1D;IACA;QACE,sBAAsB;QACtBpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAW;YAAY;YAAa;YAAY;SAAY;IACtE;IACA;QACE,YAAY;QACZpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAY;YAAY;YAAa;YAAW;SAAY;IACtE;IACA;QACE,mBAAmB;QACnBpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAW;YAAW;YAAW;YAAW;SAAU;IAChE;IACA;QACE,kDAAkD;QAClDpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YACL;YACA;Y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"}
1
+ {"version":3,"sources":["../../../../../../../libs/plugins/ai/src/lib/jobs/ai-layout-stock-photos.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\nimport {\n pluginMediaIngest,\n type PluginMediaIngest,\n type PluginMediaIngestResult,\n} from '@aglyn/aglyn/plugin-manager/plugin-media-ingest'\nimport {\n STOCK_PHOTO_QUERY_MAX_CHARS,\n stockPhotoProvider,\n stockPhotoSourceKey,\n type StockPhoto,\n type StockPhotoOrientation,\n type StockPhotoProvider,\n type StockPhotoSearchRequest,\n} from '@aglyn/aglyn/plugin-manager/stock-photo-provider'\nimport type { NodesMap } from '@aglyn/aglyn/types/nodes'\nimport {\n aiLayoutSeedNumber,\n type AiLayoutPicturePhoto,\n type AiLayoutPictureSlot,\n type AiLayoutPictureSource,\n} from '../layout-language/ai-layout-pictures'\nimport { aiStorefrontSays } from '../layout-language/ai-layout-storefront'\nimport { aiLayoutLabel, aiLayoutSpeaksOtherThanEnglish } from '../layout-language/ai-layout-labels'\nimport type { AiBuildPlan } from '../model/ai-build-plan'\nimport { aiSiteKindOfInputs } from '../model/ai-site-kinds'\nimport { aiStockBusinessNoun } from './ai-stock-business-nouns'\n\n/**\n * STOCK PHOTOS FOR A LANGUAGE PAGE'S PICTURE SLOTS (AGL-3660).\n *\n * The source `aiResolveLayoutPictures` asks before it falls back to the\n * starter photos. It names no library: it asks core for the deployment's\n * stock photo provider (`core.stock-photos`) and for the media library's\n * server door (`core.media-ingest`), and builds no source at all when either\n * is missing, so a deployment without a key behaves exactly as before.\n *\n * What the live starts of 2026-10-10 taught (Juniper Clay Works, a ceramic\n * artist's portfolio, and Willow Wick Candles, a candle store), each photo\n * traced through the library's cached answers:\n *\n * - The site's words were read as \"portfolio\" and \"online\" — the kind of\n * SITE, not the craft — so every search said \"serving bowl portfolio\" and\n * the hero asked for \"portfolio\": a wallet, fashion models, and a blank\n * paper mockup that read as an empty panel beside the brushes.\n * - A hit naming the object anywhere won: a robin tagged \"food bowl\" filled\n * \"Speckled serving bowl\", a lilac branch tagged \"bud, vase\" filled \"Tall\n * bud vase\", letterpress type tagged \"set\" filled \"Nesting bowl set\" (its\n * head noun was read as \"set\"), and an antique tea set tagged \"brown\n * candle\" filled \"Candle Gift Set\".\n * - The page's 20 seconds ran out after four photos (each copy took ~5s, one\n * after another), and the slots left took the starter photos: the laptop\n * desk with pink roses under \"Candle Wick Trimmer\" and a work card, and the\n * windowsill plants under another.\n *\n * So, for each slot:\n *\n * 1. **The site's terms** ({@link aiStockSiteTerms}): the business is the\n * first clause of its type that says more than what kind of site it is\n * (\"ceramic artist\" from \"a portfolio for a ceramic artist who makes\n * stoneware bowls\"), its craft one word (\"ceramic\"), and its DOMAIN the\n * words a photo of its world names: the craft, the business type's own\n * nouns (\"stoneware\", \"soy\") and, for common crafts, their kin (\"pottery\",\n * \"clay\", \"wax\"). Its broad searches ask for the world itself (\"handmade\n * ceramics\", \"pottery\").\n * 2. **Search.** A picture of a thing asks for its subject — the noun phrase\n * of the caption, filler dropped — qualified by the craft where it does\n * not already name the domain (\"ceramic serving bowl\"), then the craft and\n * the object alone (\"ceramic bowl\"), then the broad searches. A hero asks\n * for the business, then broad; an about picture for the business's\n * people, then broad. The orientation and a minimum size come from the\n * slot's frame.\n * 3. **Accept, or reject.** A hit tagged as a mockup, a blank or a template\n * never fills anything. A picture of a thing takes only a hit naming its\n * OBJECT (the head noun, past \"set\", \"gift\", \"kit\": \"bowl\" in \"nesting\n * bowl set\", \"candle\" in \"candle gift set\") AND either the site's domain\n * or the subject's own two-word phrase (\"bud vase\"). A broad, hero or\n * about search takes only a hit naming the domain. The accepted are\n * ranked: the object in the hit's first tags (what the photo is OF) over\n * a mention in its last, the subject's other words, the domain. Among\n * equals the job's seed picks, so two sites differ and one job repeats.\n * What the beta.239 Ember & Oak start added: \"hand-poured\", \"handmade\"\n * and \"by hand\" never make \"hands\" a subject, and a story of the craft\n * asks for the maker at work (\"candle making\"); a hit carrying a topic\n * the brief never named (a cross, a grave, a flag, a gun, wine, a child,\n * a mannequin) never fills anything; a product, and a collection tile,\n * take only a hit naming its head noun among the first tags, held to the\n * shop's category; and an object whose word is not enough (\"melt\") is\n * named and searched by its kin (\"wax melt\", \"melt warmer\"), never by the\n * category alone. And from the Kiln & Clover portfolio: nudity never fills\n * anything, for any business; a hit naming a rival craft (glass, for a\n * potter) counts only when it names the craft's own words too.\n * 4. **Never twice.** A photo is placed once per job: not twice on a page,\n * and not on a page when another page (or another pass, in this process)\n * of the same job already placed it. The caller hands in what the job's\n * other pages hold (`avoid`); a pass repeated over its own page keeps its\n * own.\n * 5. **Keep, all at once.** The choosing is done first, slot by slot; the\n * copies then run side by side, a few at a time, so a page of eight\n * pictures takes about as long as two. A photo the site's library already\n * holds (by its source key) is reused; otherwise its bytes are copied\n * into the site's own library as the member who started the job, credited\n * to its photographer. A copy that fails tries the slot's next accepted\n * hit.\n *\n * 6. **Fall back to the craft, never off it** (the beta.241 Saltmarsh Soap\n * Co start, a store \"for handmade cold-process soap\": its craft read as\n * nothing, its hero searched \"shop\" and took a florist's bouquet, and four\n * of five products took the starters' laptop desk and living room). A\n * business that is only a place takes its craft from what it is for\n * (\"soap shop\"); a hero names the craft itself ({@link AiStockSiteTerms.core});\n * a product, after its own searches, tries its head noun anywhere among\n * the tags, its gift wrapper with the craft and the craft's broad\n * searches, and then — a product or a hero only — reuses an on-topic photo\n * the job already shows rather than take a starter. Every slot of a\n * craft's site tries the craft's broad searches last.\n * 7. **A product takes the surest photo, even a borrowed one** (the beta.242\n * Tidewater Soap Works start: a sauna for \"Bath Gift Set\", colognes for\n * \"Natural Body Lotion\", a bathroom shelf for \"Soap Bar Trio\" and a soap\n * dispenser for its starter size, while the collection tiles beside them\n * were good). A product's searches are ranked by how sure they are: its\n * own photo (the head noun or its kin among the first tags), then a photo\n * OF its category, new or one the job already shows, then a weak hit of\n * its own. No product shows a room or a scene, a fragrance bottle, or what\n * its kin shuns (a pump for a bar) unless it names it; \"bath\" in a bath\n * gift set is what the set is for; a size is never the product.\n *\n * A slot nothing acceptable answered — the library down, refusing, or out\n * of time — is left `null` for the starter photos. A named object is never\n * given one while the library answers anything of the site's world: the\n * broad searches come first. Nothing here throws, and none of it is an AI\n * model call: photos cost no AI credits.\n */\n\n/** Wall clock the whole page's photos may take, inside the step's own signal. */\nexport const AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS = 30_000\n\n/** Searches one page may send to the provider; a repeated query is answered from the page's own memory. */\nexport const AI_LAYOUT_STOCK_SEARCHES_PER_PAGE = 18\n\n/** The hits a pick is made among. */\nexport const AI_LAYOUT_STOCK_PICK_WINDOW = 40\n\n/** The accepted hits a slot keeps in hand, in case a copy fails. */\nconst AI_LAYOUT_STOCK_TRIES_PER_SLOT = 3\n\n/** Copies made side by side. */\nconst AI_LAYOUT_STOCK_COPIES_AT_ONCE = 4\n\n/** The largest photo copied: inside one direct upload. */\nexport const AI_LAYOUT_STOCK_MAX_BYTES = 3 * 1024 * 1024\n\n/**\n * The unit job input naming the screen drafts the job's other pages were\n * written to, whose photos a page does not place again (AGL-3660).\n */\nexport const AI_STOCK_PHOTO_PAGES_INPUT = 'stockPhotoPages'\n\n/**\n * The unit job input naming library photos (`media:` references) another\n * part of the job already shows outside its pages — a dataset's records\n * (AGL-3616) — which a page does not place again.\n */\nexport const AI_STOCK_PHOTO_AVOID_INPUT = 'stockPhotoAvoid'\n\nconst words = (list: string) => new Set(list.trim().split(/\\s+/))\n\n/** Words that carry no subject. */\nconst STOPWORDS = words(\n 'a an the and or of in on at to for with from by into onto over under near our your their my his her its ' +\n 'this that these those is are be being was were who whom which where while as about than then very just ' +\n 'small local best new top quality premium family-owned family owned independent professional ' +\n 'business company services service page photo picture image showing shows show ' +\n 'someone people person one two three some many several',\n)\n\n/**\n * Words that describe a picture's look, not what it shows, dropped from a\n * subject. A word that is as often a noun (\"light\", \"set\") is not one.\n */\nconst FILLER = words(\n 'beautiful beautifully stunning gorgeous lovely pretty elegant modern contemporary rustic cozy cosy warm cool ' +\n 'soft bright natural simple minimal minimalist delicate unique special artisan artisanal handmade ' +\n 'hand-made hand-thrown handthrown hand-crafted handcrafted crafted hand-built handbuilt hand-poured ' +\n 'hand-painted hand-dyed hand-stitched poured finished styled perfect wheel-thrown wheelthrown thrown ' +\n 'fresh clean calm serene quiet peaceful vibrant colorful colourful sunlit sunny golden glossy matte textured ' +\n 'close-up closeup up view views detail details detailed shot shots overhead flat lay flatlay flat-lay ' +\n 'top-down wide angle featuring featured displayed arranged sitting resting placed standing lined ' +\n 'single pair collection assortment selection group few various array range large tiny big little ' +\n 'tall short wide narrow everyday classic signature original favorite favourite bestselling best-selling ' +\n 'small-batch batch limited edition custom bespoke ' +\n // How a soap is made, never what it shows: \"cold\" and \"process\" named a supermarket fridge (Saltmarsh, 2026-10-10).\n 'cold-process cold-processed hot-process hot-processed melt-and-pour ' +\n 'white black grey gray beige cream ivory brown tan blue green red pink yellow orange purple speckled ' +\n 'gentle airy inviting welcoming cheerful happy smiling friendly',\n)\n\n/** The nouns that name a place of business, not its craft: \"studio\" in \"ceramics studio\". */\nconst VENUES = words(\n 'studio studios shop shops store stores boutique company co workshop gallery atelier agency brand practice ' +\n 'salon house collective lab market services service firm clinic center centre parlor parlour bar ' +\n 'class classes lessons school academy',\n)\n\n/** The person who does the craft, not the craft: \"artist\" in \"ceramic artist\". */\nconst ROLES = words(\n 'artist artists maker makers artisan artisans owner owners founder founders creator creators',\n)\n\n/** Words naming what kind of SITE it is, never what it shows: \"portfolio\" in \"a portfolio for a ceramic artist\". */\nconst SITE_KINDS = words(\n 'portfolio portfolios website websites site sites blog blogs online web webshop ecommerce e-commerce ' +\n 'landing personal homepage storefront',\n)\n\n/** Verbs a business type uses to say what it does; what follows them is its domain, never its business. */\nconst DOING =\n /(?<![\\w-])(?:makes?|making|made|sells?|selling|sold|offers?|offering|creates?|creating|specializ(?:es|ing)|specialis(?:es|ing)|provides?|providing|featuring|showcasing)(?![\\w-])/g\n\n/** Where a business type's own clause ends. */\nconst BUSINESS_BREAK =\n /[,;:.()]|\\s[-–—]\\s|\\b(?:in|for|near|serving|based|located|that|which|who|with|from|since|and|&)\\b/\n\n/** A clause after one of these says where or for whom, never what: \"in Austin\", \"for busy parents\". */\nconst PLACE_OR_AUDIENCE =\n /^(?:in|near|serving|based|located|across|around|throughout|for)$/\n\n/**\n * Words naming a set or a wrapper of a thing, never the thing: the OBJECT\n * of \"nesting bowl set\" is the bowl, of \"candle gift set\" the candle.\n */\nconst WRAPPERS = words(\n 'set sets kit kits gift gifts bundle bundles pack packs box boxes trio duo pair collection sampler assortment ' +\n 'series range line group lot bunch',\n)\n\n/**\n * A hit tagged with any of these is never placed: a mockup's blank panel is\n * an empty frame on the page (the Juniper Clay hero), a template or a\n * graphic is not a photo of anything.\n */\nconst REJECTED_TAGS = words(\n 'mockup mock-up mock blank template templates clipart clip-art illustration vector logo icon ' +\n 'ai-generated generated render rendering 3d',\n)\n\n/**\n * Rooms and scenes, never a product (AGL-3660): the beta.242 Tidewater Soap\n * Works start put a wooden sauna under \"Bath Gift Set\" and a bathroom shelf of\n * baskets under \"Soap Bar Trio\". A product's hit whose first tags name one of\n * these is turned down unless the product or the brief names it too.\n */\nconst PRODUCT_SCENES = new Set(\n [\n 'sauna',\n 'bathroom',\n 'bathtub',\n 'shower',\n 'toilet',\n 'sink',\n 'washbasin',\n 'faucet',\n 'tap',\n 'shelf',\n 'shelves',\n 'interior',\n 'bedroom',\n 'kitchen',\n 'room',\n 'livingroom',\n 'hotel',\n 'lobby',\n ].map(aiStockStem),\n)\n\n/**\n * A fragrance's bottle, never a lotion, a cream or a soap (AGL-3660): the same\n * start's \"Natural Body Lotion\" showed blue cologne bottles tagged \"perfume,\n * bottle, lotion\". Turned down among a product's first tags unless the\n * product or the brief is a fragrance.\n */\nconst FRAGRANCE_BOTTLES = new Set(\n ['perfume', 'perfumes', 'perfumery', 'cologne', 'colognes', 'parfum', 'eau', 'atomizer', 'fragrance'].map(\n aiStockStem,\n ),\n)\n\n/**\n * Topics a business's photos never carry unless its own words name them\n * (AGL-3660, the beta.239 Ember & Oak start, whose \"Gifts for melt fans\" tile\n * showed devotional candles with crosses and names). A hit tagged with any\n * word of a topic is rejected unless the site's business type or brief says\n * one of the topic's words or its `allow` words. The last topic is not\n * sensitive but is never the thing: the same start's story band showed bronze\n * mannequin hands tagged \"wax\".\n */\nconst SENSITIVE_TOPICS: ReadonlyArray<{\n words: readonly string[]\n allow?: readonly string[]\n /** Rejected whatever the brief says. */\n always?: boolean\n}> = [\n {\n // Religion.\n words: [\n 'cross',\n 'crosses',\n 'crucifix',\n 'church',\n 'chapel',\n 'cathedral',\n 'jesus',\n 'christ',\n 'christian',\n 'christianity',\n 'god',\n 'bible',\n 'rosary',\n 'prayer',\n 'pray',\n 'praying',\n 'worship',\n 'worships',\n 'religion',\n 'religious',\n 'faith',\n 'islam',\n 'islamic',\n 'muslim',\n 'mosque',\n 'quran',\n 'temple',\n 'buddha',\n 'buddhism',\n 'buddhist',\n 'hindu',\n 'hinduism',\n 'synagogue',\n 'jewish',\n 'judaism',\n 'ecclesiastical',\n 'saint',\n 'altar',\n 'sacrificial',\n 'nativity',\n 'priest',\n 'nun',\n 'monk',\n ],\n allow: ['ministry', 'parish', 'congregation', 'wedding'],\n },\n {\n // Death and mourning.\n words: [\n 'funeral',\n 'memorial',\n 'grave',\n 'gravestone',\n 'cemetery',\n 'tomb',\n 'death',\n 'dead',\n 'grief',\n 'mourning',\n 'condolence',\n 'coffin',\n 'skull',\n ],\n allow: ['hospice', 'mortuary', 'cremation', 'obituary', 'halloween'],\n },\n {\n // Politics.\n words: [\n 'political',\n 'politics',\n 'protest',\n 'protester',\n 'demonstration',\n 'rally',\n 'flag',\n 'election',\n 'vote',\n 'voting',\n 'parliament',\n 'government',\n ],\n allow: ['advocacy', 'campaign', 'candidate', 'council', 'nonprofit'],\n },\n {\n // Weapons and war.\n words: [\n 'gun',\n 'rifle',\n 'pistol',\n 'weapon',\n 'firearm',\n 'ammunition',\n 'bullet',\n 'sword',\n 'war',\n 'military',\n 'army',\n 'soldier',\n ],\n allow: ['hunting', 'archery', 'martial', 'fencing', 'veteran'],\n },\n {\n // Alcohol, for a business that does not serve it.\n words: [\n 'alcohol',\n 'wine',\n 'beer',\n 'whiskey',\n 'whisky',\n 'vodka',\n 'cocktail',\n 'liquor',\n 'rum',\n 'gin',\n 'champagne',\n 'drunk',\n ],\n allow: [\n 'winery',\n 'vineyard',\n 'brewery',\n 'distillery',\n 'pub',\n 'tavern',\n 'taproom',\n 'bartender',\n 'sommelier',\n 'spirits',\n ],\n },\n {\n // Tobacco and drugs.\n // \"cbd\" and \"cannabinoid\": a hemp cream tube was the next \"body lotion\" answer (Tidewater, 2026-10-11).\n words: ['cigarette', 'smoking', 'tobacco', 'cannabis', 'marijuana', 'drug', 'drugs', 'cbd', 'cannabinoid', 'thc'],\n allow: ['dispensary', 'vape', 'cigar'],\n },\n {\n // Children, for a business that is not about them.\n words: ['child', 'children', 'kid', 'kids', 'baby', 'babies', 'toddler', 'infant'],\n allow: [\n 'nursery',\n 'daycare',\n 'preschool',\n 'kindergarten',\n 'school',\n 'tutor',\n 'tutoring',\n 'parent',\n 'parents',\n 'parenting',\n 'family',\n 'families',\n 'pediatric',\n 'paediatric',\n 'newborn',\n 'maternity',\n ],\n },\n {\n // Nudity, for every business: no word of a brief lets it in (Kiln &\n // Clover, 2026-10-10: a nude torso sculpture filled \"About the artist\").\n // Never bare \"body\": a skincare shop's body lotion is its product.\n words: [\n 'nude',\n 'nudes',\n 'nudity',\n 'naked',\n 'torso',\n 'breast',\n 'breasts',\n 'erotic',\n 'sensual',\n 'lingerie',\n 'bikini',\n ],\n allow: [],\n always: true,\n },\n {\n // Figures, never the maker: mannequin hands are not a candlemaker's.\n words: [\n 'mannequin',\n 'mannequins',\n 'dummy',\n 'statue',\n 'sculpture',\n 'figurine',\n 'doll',\n 'dolls',\n 'waxwork',\n ],\n allow: ['sculptor', 'museum', 'fashion', 'boutique', 'clothing', 'apparel', 'toy', 'toys'],\n },\n]\n\n/** Each topic's words and the words that allow it, as stems. */\nconst SENSITIVE_STEMS = SENSITIVE_TOPICS.map((topic) => ({\n words: new Set(topic.words.map(aiStockStem)),\n allow: new Set(\n topic.always\n ? []\n : [...topic.words, ...(topic.allow ?? [])].map(aiStockStem),\n ),\n}))\n\n/**\n * Hands are never a picture's subject (AGL-3660): \"hand-poured\", \"handmade\"\n * and \"by hand\" say how a thing was made, and a search for \"hands\" found\n * bronze mannequin hands for the beta.239 Ember & Oak story band. Each of\n * these is dropped from a picture's words; a hand only stays where it names\n * a thing sold for hands (\"hand cream\").\n */\nconst HAND_IDIOMS: readonly RegExp[] = [\n /\\b(?:made\\s+|poured\\s+|crafted\\s+|finished\\s+|done\\s+)?by\\s+(?:our\\s+|my\\s+|their\\s+)?(?:own\\s+)?hands?\\b/g,\n /\\bwith\\s+(?:our|my|their)\\s+(?:own\\s+)?(?:two\\s+)?hands\\b/g,\n /\\bhand[- ]?(?:poured|made|crafted|thrown|built|painted|dyed|stitched|sewn|knit|knitted|carved|tied|lettered|blown|bound|rolled|dipped|picked|forged|woven|cut|finished|mixed|cast|formed|shaped|pressed|printed|wrapped|selected|blended|turned|glazed)\\b/g,\n /\\bhands?\\b(?!\\s+(?:creams?|soaps?|lotions?|wash|towels?|saniti[sz]ers?|salves?|balms?|tools?|saws?|planes?|drills?|mixers?|puppets?|bags?|warmers?))/g,\n]\n\n/** A text without its hands. */\nfunction withoutHands(text: string): string {\n return HAND_IDIOMS.reduce(\n (out, idiom) => out.replace(idiom, ' '),\n text.toLowerCase(),\n )\n}\n\n/** Whether a text says how a thing was made by hand: a maker at work. */\nfunction saysMadeByHand(text: string): boolean {\n const lower = text.toLowerCase()\n return HAND_IDIOMS.some((idiom) => {\n idiom.lastIndex = 0\n const found = idiom.test(lower)\n idiom.lastIndex = 0\n return found\n })\n}\n\n/**\n * The kin of a few objects whose own word is not enough (AGL-3660): a \"melt\"\n * is any melting thing (the beta.239 \"Wax melts\" tile showed resin fluid\n * art), so a wax melt names one of these phrases. `within` is the world they\n * are of; `qualifier` the word a search adds; `queries` the searches for the\n * object itself, which stand in for the shop's category alone: a candle is\n * not a wax melt.\n */\nconst OBJECT_KIN: ReadonlyArray<{\n objects: readonly string[]\n within: readonly string[]\n /** The word a product's search adds where its subject lacks it; none where the subject is enough. */\n qualifier?: string\n /** Whether the qualifier follows the subject: \"bath gift set soap\". */\n after?: boolean\n kin: readonly string[]\n queries: readonly string[]\n /** Words a photo of the object never carries unless the product names them: a pump for a bar of soap. */\n shun?: readonly string[]\n}> = [\n {\n objects: ['melt', 'tart', 'cube'],\n within: ['wax', 'candle', 'soy'],\n qualifier: 'wax',\n kin: [\n 'wax melt',\n 'wax melts',\n 'wax cube',\n 'wax cubes',\n 'wax tart',\n 'wax tarts',\n 'melt warmer',\n 'wax warmer',\n 'tart warmer',\n 'oil burner',\n 'oil warmer',\n 'aroma burner',\n 'scent warmer',\n 'fragrance warmer',\n ],\n queries: ['wax melts', 'wax melt warmer', 'scented wax cubes'],\n },\n {\n // A \"bar\" is a pub's before it is a soap's (the Saltmarsh \"cold-process\n // soap bar\" search answered a pint of beer second): a soap bar is named\n // by soap, and searched by it.\n objects: ['bar'],\n within: ['soap', 'soapmaker', 'skincare'],\n qualifier: 'soap',\n kin: [\n 'soap bar',\n 'soap bars',\n 'bar of soap',\n 'bars of soap',\n 'soap',\n 'soaps',\n 'handmade soap',\n 'soap block',\n 'soap cubes',\n ],\n queries: ['soap bars', 'handmade soap bar'],\n // A bar is never a pump or a liquid soap (the beta.242 Tidewater start).\n shun: ['pump', 'pumps', 'liquid', 'dispenser', 'dispensers'],\n },\n {\n // \"Bath\" in \"bath gift set\", \"bath bomb\" or \"bath salts\" is what the\n // products are for, never the room: the beta.242 Tidewater Soap Works\n // start (2026-10-11) put a wooden sauna under \"Bath Gift Set\", its tags\n // \"sauna, steam, bath\". A bath set is named by soap and bath products,\n // and searched with soap.\n objects: ['bath'],\n within: ['soap', 'soapmaker', 'skincare', 'spa', 'cosmetic'],\n qualifier: 'soap',\n after: true,\n kin: [\n 'soap',\n 'soaps',\n 'soap bar',\n 'soap bars',\n 'handmade soap',\n 'bath bomb',\n 'bath bombs',\n 'bath salt',\n 'bath salts',\n 'bath product',\n 'bath products',\n 'bath set',\n 'toiletries',\n ],\n queries: ['soap gift set', 'bath products', 'bath bombs'],\n shun: ['pump', 'pumps', 'liquid', 'dispenser', 'dispensers'],\n },\n {\n // A lotion is any cream for the skin; a perfume bottle tagged \"lotion\"\n // is not one (the same start's \"Natural Body Lotion\" showed colognes).\n objects: ['lotion', 'moisturizer', 'moisturiser'],\n within: ['soap', 'soapmaker', 'skincare', 'lotion', 'cosmetic', 'beauty', 'spa'],\n kin: [\n 'lotion',\n 'lotions',\n 'body lotion',\n 'hand lotion',\n 'cream',\n 'creams',\n 'hand cream',\n 'body cream',\n 'skin cream',\n 'face cream',\n 'cream jar',\n 'body butter',\n 'moisturizer',\n 'moisturiser',\n ],\n queries: ['body lotion', 'hand cream', 'cream jar', 'moisturizer'],\n },\n]\n\n/** An object's kin where the site or the subject is of its world, else `null`. */\nfunction objectKin(\n object: string,\n world: readonly string[],\n): (typeof OBJECT_KIN)[number] | null {\n return (\n OBJECT_KIN.find(\n (entry) =>\n entry.objects.some((word) => aiStockStem(word) === object) &&\n entry.within.some((word) => world.includes(aiStockStem(word))),\n ) ?? null\n )\n}\n\n/**\n * The kin of a few common crafts: the words a photo of that world is\n * tagged with, and the broad searches that find it. A craft not listed\n * still has its own words; this only widens what counts as its world.\n */\nconst CRAFT_KIN: ReadonlyArray<{\n match: readonly string[]\n kin: readonly string[]\n broad: readonly string[]\n /** The maker at work: what a story of the craft shows, never \"hands\" (AGL-3660). */\n making: readonly string[]\n /**\n * Crafts a photo of this one is mistaken for, and the words only this\n * craft's photos say: a hit naming a rival counts as of this world only\n * when it names one of them too (Kiln & Clover, 2026-10-10: red and yellow\n * glass art filled a ceramic artist's Work hero, glass being fired and\n * \"vase\" too).\n */\n rivals?: { words: readonly string[]; core: readonly string[] }\n /**\n * Words no photo of this craft carries unless the slot or the brief names\n * them (AGL-3660): the beta.242 Tidewater start put a black soap dispenser\n * under \"Bath Gift Set Starter Size\", let in as a rival because its tags\n * also said \"cosmetics\".\n */\n shun?: readonly string[]\n}> = [\n {\n match: [\n 'ceramic',\n 'ceramics',\n 'pottery',\n 'potter',\n 'stoneware',\n 'porcelain',\n 'earthenware',\n 'clay',\n ],\n kin: [\n 'ceramic',\n 'ceramics',\n 'pottery',\n 'potter',\n 'stoneware',\n 'porcelain',\n 'earthenware',\n 'clay',\n 'glaze',\n 'kiln',\n ],\n broad: ['handmade ceramics', 'pottery'],\n rivals: {\n words: ['glass', 'glassware', 'glasswork', 'glassblowing', 'blown', 'stained', 'murano', 'crystal'],\n core: ['ceramic', 'ceramics', 'pottery', 'potter', 'stoneware', 'porcelain', 'earthenware', 'clay', 'terracotta'],\n },\n making: ['pottery wheel', 'potter at work'],\n },\n {\n match: ['candle', 'candlemaker', 'candlemaking'],\n kin: [\n 'candle',\n 'candlelight',\n 'wax',\n 'soy',\n 'wick',\n 'scented',\n 'votive',\n 'candlestick',\n ],\n broad: ['handmade candles', 'scented candles'],\n making: ['candle making', 'pouring wax'],\n },\n {\n match: [\n 'jewelry',\n 'jewellery',\n 'jeweler',\n 'jeweller',\n 'silversmith',\n 'goldsmith',\n ],\n kin: [\n 'jewelry',\n 'jewellery',\n 'ring',\n 'necklace',\n 'earring',\n 'bracelet',\n 'silver',\n 'gold',\n 'gemstone',\n ],\n broad: ['handmade jewelry', 'jewelry'],\n making: ['jewelry making', 'jeweler at work'],\n },\n {\n match: ['soap', 'soapmaker', 'skincare'],\n // Never \"natural\": a florist's bouquet tagged \"natural\" was the\n // Saltmarsh Soap Co hero (2026-10-10).\n kin: ['soap', 'skincare', 'lotion', 'cream', 'bath', 'spa', 'cosmetic'],\n broad: ['handmade soap', 'natural skincare'],\n // \"Soap making\" is answered with soap bubbles; a bar is what a soapmaker makes.\n making: ['soap making', 'handmade soap'],\n // Soap bubbles, a dispenser and detergent are soap, never a soapmaker's:\n // the same start's story band showed bubbles in flight.\n rivals: {\n words: ['bubble', 'bubbles', 'soapy', 'dispenser', 'detergent', 'dishwashing', 'laundry'],\n core: [\n 'bar',\n 'bars',\n 'handmade',\n 'homemade',\n 'loaf',\n 'lye',\n 'glycerin',\n 'skincare',\n 'lotion',\n 'cosmetic',\n 'spa',\n 'artisan',\n ],\n },\n shun: ['dispenser', 'dispensers'],\n },\n {\n match: [\n 'wood',\n 'woodwork',\n 'woodworking',\n 'woodworker',\n 'carpenter',\n 'carpentry',\n 'furniture',\n 'joinery',\n ],\n kin: [\n 'wood',\n 'wooden',\n 'woodwork',\n 'timber',\n 'furniture',\n 'carpentry',\n 'oak',\n 'walnut',\n ],\n broad: ['woodworking', 'wooden furniture'],\n making: ['woodworking workshop', 'carpenter at work'],\n },\n {\n match: ['bakery', 'baker', 'bread', 'pastry', 'cake', 'patisserie'],\n kin: [\n 'bakery',\n 'bread',\n 'pastry',\n 'cake',\n 'baking',\n 'baked',\n 'dough',\n 'croissant',\n ],\n broad: ['bakery', 'fresh bread'],\n making: ['baker kneading dough', 'baking bread'],\n },\n {\n match: ['coffee', 'cafe', 'café', 'roaster', 'espresso'],\n kin: [\n 'coffee',\n 'cafe',\n 'espresso',\n 'latte',\n 'cappuccino',\n 'barista',\n 'beans',\n ],\n broad: ['coffee shop', 'coffee'],\n making: ['barista making coffee'],\n },\n {\n match: ['florist', 'flower', 'floral'],\n kin: ['flower', 'floral', 'bouquet', 'florist', 'bloom', 'blossom'],\n broad: ['florist', 'flower bouquet'],\n making: ['florist arranging flowers'],\n },\n {\n match: [\n 'knit',\n 'knitting',\n 'yarn',\n 'weaving',\n 'weaver',\n 'textile',\n 'textiles',\n 'quilt',\n 'quilting',\n 'sewing',\n ],\n kin: [\n 'knit',\n 'knitting',\n 'yarn',\n 'wool',\n 'weaving',\n 'textile',\n 'fabric',\n 'quilt',\n 'sewing',\n ],\n broad: ['handmade textiles', 'yarn'],\n making: ['knitting', 'weaving loom'],\n },\n {\n match: ['leather', 'leatherwork', 'leathercraft'],\n kin: ['leather', 'wallet', 'bag', 'belt', 'stitching'],\n broad: ['leather craft', 'leather goods'],\n making: ['leather crafting'],\n },\n]\n\n/** Lowercase words, letters only, without stopwords. */\nfunction contentWords(text: string): string[] {\n return text\n .toLowerCase()\n .replace(/https?:\\/\\/\\S+|\\S+@\\S+|\\+?\\d[\\d\\s().-]{5,}\\d/g, ' ')\n .replace(/[^a-zÀ-ɏ\\s-]/g, ' ')\n .split(/\\s+/)\n .map((word) => word.replace(/^-+|-+$/g, ''))\n .filter((word) => word.length > 1 && !STOPWORDS.has(word))\n}\n\n/**\n * A word's singular, for matching only: \"bowls\" and \"bowl\", \"vases\" and\n * \"vase\", \"berries\" and \"berry\", \"dishes\" and \"dish\" meet. Both sides of a\n * comparison are reduced the same way, so an odd stem still matches itself.\n */\nexport function aiStockStem(word: string): string {\n const lower = word.toLowerCase()\n if (lower.length > 4 && lower.endsWith('ies')) return `${lower.slice(0, -3)}y`\n if (lower.length > 4 && /(?:ches|shes|sses|xes|zes)$/.test(lower))\n return lower.slice(0, -2)\n if (lower.length > 3 && lower.endsWith('s') && !/(?:ss|us|is)$/.test(lower))\n return lower.slice(0, -1)\n return lower\n}\n\n/** A text's words as stems, in order; a hyphenated word counts as its parts. */\nfunction stemList(text: string): string[] {\n return text\n .toLowerCase()\n .split(/[^a-zÀ-ɏ]+/)\n .filter((word) => word.length > 1)\n .map(aiStockStem)\n}\n\n/** Where a noun phrase ends: punctuation, a preposition, a conjunction. */\nconst CLAUSE_BREAK =\n /[,;:.()]|\\s[-–—]\\s|\\b(?:with|on|in|at|against|beside|next|near|under|over|by|from|for|during|while|atop|inside|across|beneath|through|into|onto|amid|among|and|of|that|which|who)\\b|&/\n\n/** A business type's clauses, each with the word that opened it. */\nfunction businessClauses(\n businessType: string,\n): Array<{ opener: string; words: string[] }> {\n const text = businessType.toLowerCase().replace(DOING, ' | ')\n const clauses: Array<{ opener: string; words: string[] }> = []\n const breaker = new RegExp(`${BUSINESS_BREAK.source}|\\\\|`, 'g')\n let at = 0\n let opener = ''\n for (const match of text.matchAll(breaker)) {\n clauses.push({ opener, words: contentWords(text.slice(at, match.index)) })\n opener = match[0].trim()\n at = (match.index ?? 0) + match[0].length\n }\n clauses.push({ opener, words: contentWords(text.slice(at)) })\n return clauses\n}\n\n/** A clause's words that name the business: no site kind, no filler. */\nconst businessOf = (clause: readonly string[]) =>\n clause.filter((word) => !SITE_KINDS.has(word) && !FILLER.has(word))\n\n/**\n * The kind of business in a few words: the first clause of the business\n * type that says more than what kind of site it is, before a place, an\n * audience or what it makes, filler dropped, its last three words (the head\n * of an English noun phrase is at its end). \"ceramic artist\" from \"a\n * portfolio for a ceramic artist who makes stoneware bowls\"; \"candle shop\"\n * from \"a small-batch candle shop selling hand-poured soy candles online\".\n */\nexport function aiStockBusinessWords(businessType: string): string {\n for (const { words: clause } of businessClauses(businessType)) {\n const named = businessOf(clause)\n if (named.length) return named.slice(-3).join(' ')\n }\n return ''\n}\n\n/**\n * The business's craft in one word: the last of its words that is not the\n * place it is done in nor the person doing it, singular — \"ceramic\" from\n * \"ceramics studio\" or \"ceramic artist\", \"yoga\" from \"yoga studio\". Empty\n * when the business is only a place (\"a shop\").\n */\nexport function aiStockCraftWords(business: string): string {\n const named = business\n .split(/\\s+/)\n .filter(\n (word) =>\n word &&\n !VENUES.has(word) &&\n !ROLES.has(word) &&\n !FILLER.has(word) &&\n !SITE_KINDS.has(word),\n )\n const craft = named[named.length - 1]\n return craft ? aiStockStem(craft) : ''\n}\n\n/** What a site's photos are searched and judged by (AGL-3660). */\nexport interface AiStockSiteTerms {\n /** The kind of business, in a few words: \"ceramic artist\". */\n business: string\n /** Its craft, one singular word: \"ceramic\". */\n craft: string\n /**\n * The stems a photo of the site's world names: the business's own words,\n * what the things it makes are made of, and the craft's kin. Empty for a\n * site whose words name no world (a type left blank), and then no hit is\n * held to it.\n */\n domain: string[]\n /** The searches for the site's world itself, broadest last. */\n broad: string[]\n /** The searches for its maker at work, for a story of the craft (AGL-3660); empty for a craft not listed. */\n making: string[]\n /** Every stem of the business type or brief: what lets a sensitive topic in ({@link SENSITIVE_TOPICS}). */\n named: string[]\n /** Rival crafts' words, each with the words that must then be named too ({@link CRAFT_KIN}). */\n rivals: Array<{ words: string[]; core: string[] }>\n /**\n * The stems a photo of the craft ITSELF names, one of which a hero and a\n * product's fallbacks must name (AGL-3660): the craft and, for a listed\n * craft, its own names (\"soap\", \"soapmaker\", \"skincare\"). Empty where the\n * site names no craft.\n */\n core: string[]\n /** Words no photo of the site's craft carries unless the slot or the brief names them ({@link CRAFT_KIN}). */\n shun: string[]\n}\n\n/** The site's terms, read from its business type. */\nexport function aiStockSiteTerms(businessType: string): AiStockSiteTerms {\n let business = aiStockBusinessWords(businessType)\n let craft = aiStockCraftWords(business)\n const domain = new Set<string>()\n /** The things it makes, by their head nouns. */\n const made = new Set<string>()\n /** The last word of the first clause that names the world: \"soap\" of \"for handmade cold-process soap\". */\n let firstWorld = ''\n let named = false\n let making = false\n for (const { opener, words: clause } of businessClauses(businessType)) {\n if (opener === '|') making = true\n // Where it is, and who it is for, are not its world — once something has named it.\n if (named && PLACE_OR_AUDIENCE.test(opener)) {\n making = false\n continue\n }\n const kept = businessOf(clause).filter(\n (word) => !VENUES.has(word) && !ROLES.has(word),\n )\n if (kept.length) named = true\n // What it makes names its world by what the things are made of, never\n // the things: \"stoneware\" of \"stoneware bowls\", \"soy\" of \"soy candles\".\n // A bowl is not a ceramic world; a robin's food bowl is not pottery.\n // A set or a gift is never a world: \"gift\" of \"gift sets\" is not one.\n const world = (making ? kept.slice(0, -1) : kept).filter(\n (word) => !WRAPPERS.has(word),\n )\n for (const word of world)\n for (const stem of stemList(word)) domain.add(stem)\n const last = world[world.length - 1]\n if (!firstWorld && last) firstWorld = aiStockStem(last)\n if (making)\n for (const word of kept.slice(-1))\n for (const stem of stemList(word)) made.add(stem)\n }\n // A business named only by what it sells (\"a shop selling pottery\") is of that world.\n if (!domain.size) for (const stem of made) domain.add(stem)\n const groups = CRAFT_KIN.filter((group) =>\n group.match.some(\n (word) =>\n domain.has(aiStockStem(word)) ||\n made.has(aiStockStem(word)) ||\n aiStockStem(word) === craft,\n ),\n )\n // A business that is only a place (\"an online shop for handmade\n // cold-process soap\") takes its craft from what it is for: the Saltmarsh\n // Soap Co start (2026-10-10) read its craft as nothing, so its hero searched\n // \"shop\" (a florist's bouquet) and no product was held to soap.\n if (!craft) {\n const listed = groups[0]?.match\n .map(aiStockStem)\n .find((stem) => domain.has(stem) || made.has(stem))\n craft = listed || firstWorld || [...made][0] || ''\n if (craft && !stemList(business).includes(craft))\n business = `${craft} ${business}`.trim()\n }\n if (craft) domain.add(craft)\n const broad: string[] = []\n const makingSearches: string[] = []\n const rivals: Array<{ words: string[]; core: string[] }> = []\n const core = new Set<string>(craft ? [craft] : [])\n const shun = new Set<string>()\n for (const group of groups) {\n for (const word of group.shun ?? []) shun.add(aiStockStem(word))\n for (const word of group.match) core.add(aiStockStem(word))\n for (const word of group.kin) domain.add(aiStockStem(word))\n broad.push(...group.broad)\n makingSearches.push(...group.making)\n if (group.rivals)\n rivals.push({\n words: group.rivals.words.map(aiStockStem),\n core: group.rivals.core.map(aiStockStem),\n })\n }\n if (!broad.length) broad.push(business, craft)\n return {\n business,\n craft,\n domain: [...domain].filter((stem) => stem.length > 1),\n broad: [...new Set(broad.map((query) => query.trim()).filter(Boolean))],\n making: [...new Set(makingSearches)],\n named: [...new Set(stemList(businessType))],\n rivals,\n core: [...core],\n shun: [...shun],\n }\n}\n\n/** A phrase's content words without its filler; all filler, and nothing is left. */\nfunction subjectOf(list: readonly string[]): string[] {\n return list.filter((word) => !FILLER.has(word))\n}\n\n/**\n * A picture's subject in a few words (AGL-3660): the noun phrase its alt\n * text opens with — its first clause holding more than filler, cut where a\n * preposition starts the setting, filler dropped, its last three words (the\n * head noun is the last) — else its section's name.\n */\nexport function aiStockSubjectWords(alt: string, sectionName: string): string {\n // \"Hand-poured\", \"by hand\" and \"hands\" say how it was made, never what it shows.\n for (const clause of withoutHands(alt).split(CLAUSE_BREAK)) {\n const found = subjectOf(contentWords(clause ?? ''))\n if (found.length) return found.slice(-3).join(' ')\n }\n return subjectOf(contentWords(withoutHands(sectionName))).slice(0, 2).join(' ')\n}\n\n/**\n * The thing a subject shows, one singular word: its last word that is not\n * a set or a wrapper of it — \"bowl\" from \"nesting bowl set\", \"candle\" from\n * \"candle gift set\", \"vase\" from \"bud vase\". Its last word when every word\n * is one (\"gift set\").\n */\nexport function aiStockObjectWord(subject: string): string {\n const list = subject.split(/\\s+/).filter(Boolean)\n const object =\n [...list].reverse().find((word) => !WRAPPERS.has(word)) ??\n list[list.length - 1] ??\n ''\n return object ? aiStockStem(object) : ''\n}\n\nconst clip = (query: string) =>\n query.replace(/\\s+/g, ' ').trim().slice(0, STOCK_PHOTO_QUERY_MAX_CHARS).trim()\n\n/** The frame's orientation: a wide frame wants a landscape photo, a tall one a portrait. */\nexport function aiStockOrientation(aspect: number): StockPhotoOrientation {\n if (aspect > 1.15) return 'horizontal'\n if (aspect < 0.87) return 'vertical'\n return 'any'\n}\n\n/**\n * One search a slot tries. A `broad` one asks for the site's world and\n * takes any hit of it; any other picture of a thing takes only a hit naming\n * the thing.\n */\nexport interface AiStockSearch extends StockPhotoSearchRequest {\n broad?: boolean\n /** The words its hits are scored by, where they are not the slot's own subject (a product's searches, AGL-3676). */\n subject?: string\n /** A word every hit must name: a product's photo names the shop's category (AGL-3676). */\n requires?: string\n /**\n * Words of which a hit must name ONE, `requires` among them (AGL-3660): a\n * shop's category or the slot's own word of its world, so a soap shop's\n * body lotion is held to \"lotion\", never to \"soap\".\n */\n category?: readonly string[]\n /** The thing every hit must name, where it is not the subject's own: a product's head noun (AGL-3660). */\n object?: string\n /** Phrases that name the object where its own word is not enough: \"wax melt\" ({@link OBJECT_KIN}). */\n kin?: readonly string[]\n /** Whether the object must be among the hit's first tags, what the photo is OF (AGL-3660). */\n lead?: boolean\n /** Whether the hit's first tags must name the site's world, where the object need not lead (AGL-3660). */\n leadWorld?: boolean\n /**\n * Whether the hit's FIRST tag must name the site's world (AGL-3760): what\n * the photo is of, most of all. A hero is the site's opening picture; the\n * copper-fern-candle-co start (beta.246) took a latte with a candle behind\n * it, its tags \"coffee, mobile wallpaper 4k, latte art, …, candle\".\n */\n first?: boolean\n /** Phrases (as stems) of which one must be among the hit's first tags: a borrowed photo is OF the product's category (AGL-3660). */\n leadAny?: readonly string[]\n /** Whether it fills a product: no room, no scene, no fragrance bottle ({@link PRODUCT_SCENES}, AGL-3660). */\n product?: boolean\n /** Words its hits never carry unless the slot or the brief names them ({@link AiStockSiteTerms.shun}). */\n shun?: readonly string[]\n /**\n * How sure a product's search is (AGL-3660). Absent: its own photo, the\n * head noun among the first tags. `borrow`: a photo OF its category, which\n * may repeat one the job already shows. `weak`: the head noun anywhere, or\n * the category anywhere — taken only once nothing surer is left.\n */\n tier?: 'borrow' | 'weak'\n}\n\n/** A slot's part of a page, where it asks for more than its role: a collection tile or a story of the craft (AGL-3660). */\nexport type AiStockSlotPart = 'collection' | 'story'\n\n/**\n * A slot's part (AGL-3660): a tile of a collections band is product-like,\n * held to the shop's category and its own object; a picture of a story of\n * the craft, or of a thing made by hand, shows the maker at work.\n */\nexport function aiStockSlotPart(\n slot: Pick<AiLayoutPictureSlot, 'role' | 'alt'>,\n sectionName: string,\n): AiStockSlotPart | undefined {\n if (slot.role === 'hero') return undefined\n if (slot.role === 'gallery' && aiStorefrontSays('collections', sectionName))\n return 'collection'\n if (\n aiStorefrontSays('story', sectionName) ||\n saysMadeByHand(slot.alt) ||\n saysMadeByHand(sectionName)\n )\n return 'story'\n return undefined\n}\n\n/** An object's kin phrases as stems, or none. */\nconst kinStems = (entry: (typeof OBJECT_KIN)[number] | null): string[] =>\n entry ? [...new Set(entry.kin.map((phrase) => stemList(phrase).join(' ')))] : []\n\n/** What a product falls back to once its own searches find nothing ({@link aiStockProductSearches}). */\nexport interface AiStockProductFallback {\n /** The site's broad searches ({@link AiStockSiteTerms.broad}): \"handmade soap\". */\n broad?: readonly string[]\n /** The words a photo of the craft itself names ({@link AiStockSiteTerms.core}). */\n core?: readonly string[]\n}\n\n/**\n * A size never names a product (AGL-3660): the Tidewater start searched\n * \"soap set starter size\" for \"Bath Gift Set Starter Size\", its head noun\n * read as \"size\", and took a soap dispenser.\n */\nconst PRODUCT_SIZES =\n /\\b(?:(?:starter|travel|trial|sample|mini|full|half|family|value|jumbo|large|small|regular|standard|big)[- ])?sized?s?\\b/gi\n\n/** The wrapper words a gift is named by, searched with the craft: \"soap gift box\". */\nconst GIFT_WRAPPERS = words('gift gifts box boxes basket baskets hamper hampers')\n\n/**\n * A product's searches (AGL-3676), most specific first: each of its subjects\n * — its name's noun phrase, then its photo's — with the shop's category\n * where the phrase does not already name the shop's world (\"candle gift\n * box\"), then the category alone, a plain photo of what the shop sells. Every\n * one must find a hit naming the category — or the product's own word of the\n * shop's world, \"lotion\" in a soap shop — so no product is ever filled with a\n * lifestyle shot of something else: the beta.237 Willow Wick start put a\n * laptop and roses under \"Candle Wick Trimmer\" and an antique tea set under\n * \"Candle Gift Set\".\n *\n * And each must find a hit naming the product's own head noun among its\n * first tags (AGL-3660): the beta.239 Ember & Oak start put a bed with a book,\n * a mug and a camera (its candle a last tag) under \"Hand-Poured Soy Candle\".\n * An object whose own word is not enough ({@link OBJECT_KIN}) is searched by\n * its kin instead of the category alone, and named by them: a single taper\n * candle filled \"Wax Melt Gift Set\".\n *\n * Then, before a product is ever given a photo of something else, it falls\n * back to its own craft (AGL-3660). The Saltmarsh Soap Co start (2026-10-10)\n * found no hit naming \"bar\" or \"box\" among the first tags, and four of its\n * five products took the starter photos — a laptop and roses, a living room\n * of plants. And the beta.242 Tidewater Soap Works start (2026-10-11) showed\n * that the head noun anywhere is not enough: its own weak hits put a sauna\n * under \"Bath Gift Set\", colognes under \"Natural Body Lotion\", a bathroom\n * shelf under \"Soap Bar Trio\" and a soap dispenser under its starter size,\n * while the collection tiles beside them, searched for the category, were\n * good. So the searches are ranked by how sure they are ({@link AiStockSearch.tier}):\n *\n * 1. Its own: the head noun (or its kin) among the first tags, as above.\n * 2. `borrow`: a photo OF its category — the category alone, then the craft's\n * broad searches (\"handmade soap\", \"natural skincare\"), one of the\n * product's kin or the craft's own names among the first tags. A product\n * may repeat one the job already shows, a collection tile's photo or\n * another product's ({@link aiLayoutStockPhotoSource}): a borrowed\n * on-topic photo beats a weak specific one.\n * 3. `weak`: the same searches again, the head noun named anywhere among the\n * tags (no extra search: the page remembers its answers), a gift's own\n * wrapper with the craft (\"soap gift box\"), and the craft's broad searches,\n * any hit naming the craft itself ({@link AiStockSiteTerms.core}).\n *\n * Every one of them turns down a room or a scene, a fragrance bottle, and\n * what the product's kin shuns (a pump for a bar of soap), unless the\n * product names it. A size never names the product: \"Bath Gift Set Starter\n * Size\" is a bath gift set.\n */\nexport function aiStockProductSearches(\n slot: Pick<AiLayoutPictureSlot, 'aspect' | 'product'>,\n craft: string,\n domain: readonly string[] = [],\n fallback: AiStockProductFallback = {},\n): AiStockSearch[] {\n const orientation = aiStockOrientation(slot.aspect)\n const size = orientation === 'vertical' ? { minHeight: 900 } : { minWidth: 900 }\n const craftStems = stemList(craft)\n const world = new Set([...domain, ...craftStems])\n const subjects = (slot.product?.subjects ?? [])\n .map((raw) => aiStockSubjectWords(raw.replace(PRODUCT_SIZES, ' '), ''))\n .filter(Boolean)\n // The product's head noun is its name's: \"candle\" of \"Hand-Poured Soy Candle\".\n const own = subjects[0] ?? ''\n const object = aiStockObjectWord(own)\n const kin = object\n ? objectKin(object, [...craftStems, ...domain, ...stemList(subjects.join(' '))])\n : null\n const kinPhrases = kinStems(kin)\n // A product of the shop's world beside its category is held to either:\n // a soap shop's body lotion names \"lotion\", never \"soap\".\n const ownWorld = stemList(own).filter(\n (stem) => world.has(stem) && !WRAPPERS.has(stem) && !craftStems.includes(stem),\n )\n const category = craft && ownWorld.length ? [...craftStems, ...ownWorld] : []\n const core = [...new Set([...craftStems, ...(fallback.core ?? [])])]\n const shun = (kin?.shun ?? []).map(aiStockStem)\n type Query = {\n query: string\n subject: string\n object: string\n lead: boolean\n broad?: boolean\n tier?: 'borrow' | 'weak'\n }\n const queries: Query[] = []\n for (const subject of subjects) {\n const stems = stemList(subject)\n const qualifier = kin?.qualifier ?? ''\n const query = kin\n ? !qualifier || stems.includes(aiStockStem(qualifier))\n ? subject\n : kin.after\n ? `${subject} ${qualifier}`\n : `${qualifier} ${subject}`\n : craft && !stems.some((stem) => world.has(stem))\n ? `${craft} ${subject}`\n : subject\n queries.push({ query, subject, object, lead: true })\n }\n // The category alone stands in only for a thing that is no more than of\n // it; a thing that is its own word of the shop's world is searched by that\n // word (\"lotion\"). Its hits are still scored by the product's own words: a\n // soy candle over a taper.\n if (kin)\n for (const query of kin.queries)\n queries.push({ query, subject: own || query, object, lead: true })\n else if (object && ownWorld.includes(object))\n queries.push({ query: object, subject: own, object, lead: true })\n else if (craft)\n queries.push({ query: craft, subject: own || craft, object: craft, lead: true, tier: 'borrow' })\n const held = [...queries]\n // 2. A photo OF its category, which may be one the job already shows.\n for (const query of fallback.broad ?? [])\n queries.push({ query, subject: own, object: '', lead: true, broad: true, tier: 'borrow' })\n // 3. The head noun anywhere among the tags, by the same searches.\n for (const entry of held) queries.push({ ...entry, lead: false, tier: 'weak' })\n // A gift is its craft's: \"bath gift box\" asks for a \"soap gift box\".\n const wrapped = own\n .split(/\\s+/)\n .filter((word) => WRAPPERS.has(word) && aiStockStem(word) !== object)\n const gift = wrapped.find((word) => GIFT_WRAPPERS.has(word))\n if (craft && gift && !kin)\n queries.push({\n query: `${craft} ${wrapped.join(' ')}`,\n subject: own,\n object: aiStockStem(gift),\n lead: false,\n tier: 'weak',\n })\n // The craft's own broad searches, any hit naming the craft.\n for (const query of fallback.broad ?? [])\n queries.push({ query, subject: own, object: '', lead: false, broad: true, tier: 'weak' })\n // What a borrowed photo is OF: the product's kin, its own word of the shop's world, else the craft.\n const borrowed = kinPhrases.length ? kinPhrases : ownWorld.length ? ownWorld : core\n const seen = new Set<string>()\n const searches: AiStockSearch[] = []\n for (const entry of queries) {\n const query = clip(entry.query)\n const key = `${query}|${entry.lead}|${entry.object}|${entry.broad === true}|${entry.tier ?? ''}`\n if (!query || seen.has(key)) continue\n seen.add(key)\n const common = {\n query,\n orientation,\n ...size,\n subject: entry.subject,\n product: true,\n ...(entry.tier ? { tier: entry.tier } : {}),\n ...(shun.length ? { shun } : {}),\n }\n if (entry.broad) {\n const heldTo = [...new Set([...core, ...ownWorld])]\n searches.push({\n ...common,\n broad: true,\n ...(entry.lead\n ? {\n leadAny: borrowed,\n ...(kinPhrases.length ? { kin: kinPhrases } : {}),\n ...(heldTo.length ? { category: heldTo } : {}),\n }\n : core.length\n ? { category: core }\n : {}),\n })\n continue\n }\n searches.push({\n ...common,\n // Named anywhere, the hit's first tags are still of the shop's world:\n // a bed with a book, its candle a last tag, is not a candle's photo.\n ...(entry.lead ? { lead: true } : { leadWorld: true }),\n ...(entry.object ? { object: entry.object } : {}),\n ...(kinPhrases.length && entry.object === object ? { kin: kinPhrases } : {}),\n ...(craft ? { requires: craft } : {}),\n ...(category.length ? { category } : {}),\n })\n }\n return searches\n}\n\n/** The searches a slot tries, in order, most specific first, each distinct. */\nexport function aiStockSearchesFor(\n slot: Pick<AiLayoutPictureSlot, 'role' | 'alt' | 'aspect'>,\n terms: Pick<AiStockSiteTerms, 'business' | 'craft' | 'domain' | 'broad'> &\n Partial<Pick<AiStockSiteTerms, 'making' | 'core'>>,\n subject: string,\n part?: AiStockSlotPart,\n): AiStockSearch[] {\n const orientation = aiStockOrientation(slot.aspect)\n const size =\n slot.role === 'hero'\n ? { minWidth: 1600 }\n : orientation === 'vertical'\n ? { minHeight: 900 }\n : { minWidth: 900 }\n const domain = new Set(terms.domain)\n const object = aiStockObjectWord(subject)\n const subjectStems = stemList(subject)\n const kin = object ? objectKin(object, [...terms.domain, ...subjectStems]) : null\n const kinPhrases = kinStems(kin)\n // The craft qualifies a subject that does not already name the site's world.\n const namesWorld = subjectStems.some((stem) => domain.has(stem))\n // A tile of the shop's world beside its category is held to either: a soap\n // shop's \"Body care\" tile names \"body\", never \"soap\" (AGL-3660).\n const ownWorld = subjectStems.filter(\n (stem) => domain.has(stem) && !WRAPPERS.has(stem) && stem !== terms.craft,\n )\n // A hero of a craft names the craft itself: the Saltmarsh Soap Co hero\n // (2026-10-10) was a florist's bouquet tagged \"natural\" (AGL-3660).\n const core = terms.core ?? []\n const qualify = (phrase: string) =>\n terms.craft && !namesWorld && !stemList(phrase).includes(terms.craft)\n ? `${terms.craft} ${phrase}`\n : phrase\n type Query = {\n query: string\n broad?: boolean\n people?: boolean\n held?: boolean\n category?: boolean\n }\n // A collection tile is product-like: held to the shop's category and its\n // own object among the first tags, and searched by its object's kin, never\n // the category's world alone (AGL-3660).\n const collection = part === 'collection' && Boolean(terms.craft)\n const broad: Query[] = kin && collection\n ? []\n : terms.broad.map((query) => ({ query, broad: true, category: collection }))\n // The maker at work, held to the craft: never \"hands\" (AGL-3660).\n const making: Query[] = (terms.making ?? []).map((query) => ({\n query,\n broad: true,\n category: true,\n }))\n const thing: Query[] = subject\n ? [\n { query: qualify(subject), held: true },\n ...(kin\n ? kin.queries.map((query) => ({ query, held: true }))\n : [{ query: qualify(object), held: true }]),\n ]\n : []\n const queries: Query[] =\n slot.role === 'hero'\n ? [{ query: terms.business, broad: true }, ...broad]\n : slot.role === 'about'\n ? [\n ...(part === 'story' ? making : []),\n {\n query: `${terms.business} ${subject}`,\n broad: true,\n people: true,\n },\n { query: terms.business, broad: true, people: true },\n ...(part === 'story' ? [] : making),\n ...broad,\n ]\n : [...(part === 'story' ? making : []), ...thing, ...broad]\n const seen = new Set<string>()\n const searches: AiStockSearch[] = []\n for (const raw of queries) {\n const query = clip(raw.query)\n const key = `${query}|${raw.people === true}`\n if (!query || seen.has(key)) continue\n seen.add(key)\n const held = raw.held === true && (collection || kinPhrases.length > 0)\n searches.push({\n query,\n orientation,\n ...size,\n ...(raw.people ? { people: true } : {}),\n ...(raw.broad ? { broad: true } : {}),\n ...(held && kinPhrases.length ? { kin: kinPhrases } : {}),\n ...(held && collection ? { lead: true } : {}),\n ...(terms.craft && (raw.category || (raw.held && collection))\n ? {\n requires: terms.craft,\n ...(ownWorld.length ? { category: [terms.craft, ...ownWorld] } : {}),\n }\n : {}),\n ...(slot.role === 'hero' && core.length ? { category: core } : {}),\n // A hero is OF the site's world: its first tag names it (AGL-3760).\n ...(slot.role === 'hero' ? { first: true } : {}),\n })\n }\n return searches\n}\n\n/** What a hit is judged by. */\nexport interface AiStockJudgement {\n /** The words the picture is of; empty for a picture of the site's world. */\n subject?: string\n /** The site's domain stems ({@link AiStockSiteTerms.domain}). */\n domain?: readonly string[]\n /**\n * Whether a hit must name the subject's object. A broad search, a hero\n * and an about picture need only name the domain.\n */\n strict?: boolean\n /** A word every hit must name: a product's photo names the shop's category (AGL-3676). */\n requires?: string\n /** Words of which a hit must name one, `requires` among them ({@link AiStockSearch.category}). */\n category?: readonly string[]\n /** The thing a hit must name, where it is not the subject's own (AGL-3660). */\n object?: string\n /** Phrases naming the object where its word is not enough; one of them is then required, and stands for the category. */\n kin?: readonly string[]\n /** Whether the object must be among the hit's first tags (AGL-3660). */\n lead?: boolean\n /** Whether the hit's first tags must name the site's world ({@link AiStockSearch.leadWorld}). */\n leadWorld?: boolean\n /** Whether the hit's first tag must name the site's world ({@link AiStockSearch.first}). */\n first?: boolean\n /** The stems of the site's business type or brief, which let a sensitive topic in ({@link AiStockSiteTerms.named}). */\n named?: readonly string[]\n /** Rival crafts: a hit naming one is rejected unless it names the site's core words ({@link AiStockSiteTerms.rivals}). */\n rivals?: ReadonlyArray<{ words: readonly string[]; core: readonly string[] }>\n /** Phrases of which one must be among the hit's first tags ({@link AiStockSearch.leadAny}). */\n leadAny?: readonly string[]\n /** Whether it judges for a product: no room, no scene, no fragrance bottle (AGL-3660). */\n product?: boolean\n /** Words a hit never carries unless the subject or the brief names them ({@link AiStockSiteTerms.shun}). */\n shun?: readonly string[]\n}\n\n/** The words of a photo's page address at its library, its id dropped: \"robin-bird-songbird-garden-winter\". */\nfunction pageSlug(pageUrl: string): string {\n try {\n const last = decodeURIComponent(new URL(pageUrl).pathname)\n .split('/')\n .filter(Boolean)\n .pop()\n return last?.replace(/-?\\d+$/, '') ?? ''\n } catch {\n return ''\n }\n}\n\n/** A hit's words: the first few (what it is OF), every one, and each tag's phrase. */\nfunction hitWords(photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>) {\n const slug = pageSlug(photo.pageUrl)\n const tags = (photo.tags ?? [])\n .map((tag) => tag.toLowerCase().trim())\n .filter(Boolean)\n const lead = new Set(stemList([...tags.slice(0, 3), slug].join(' ')))\n const all = new Set(stemList([...tags, photo.alt ?? '', slug].join(' ')))\n const phrases = [\n ...tags.map((tag) => stemList(tag).join(' ')),\n stemList(photo.alt ?? '').join(' '),\n stemList(slug).join(' '),\n ]\n const leadPhrases = [\n ...tags.slice(0, 3).map((tag) => stemList(tag).join(' ')),\n stemList(slug).join(' '),\n ]\n /** The first tag: what the photo is most of all. */\n const firstPhrase = stemList(tags[0] ?? '').join(' ')\n const rejected = tags.some(\n (tag) =>\n REJECTED_TAGS.has(tag) ||\n tag.split(/\\s+/).some((word) => REJECTED_TAGS.has(word)),\n )\n // Whole words only, a hyphenated one kept whole: \"cross-stitch\" is not a cross.\n const words = new Set(\n [...tags, (photo.alt ?? '').toLowerCase()]\n .join(' ')\n .split(/[^a-zÀ-ɏ-]+/)\n .filter((word) => word.length > 1)\n .map(aiStockStem),\n )\n return { lead, all, phrases, leadPhrases, firstPhrase, rejected, words }\n}\n\n/** Whether a phrase is among a hit's phrases, word for word. */\nconst among = (phrases: readonly string[], phrase: string) =>\n phrases.some((found) => ` ${found} `.includes(` ${phrase} `))\n\n/**\n * Whether a hit carries a topic its site never named ({@link SENSITIVE_TOPICS}):\n * a cross, a grave, a flag, a gun, a glass of wine, a child, a mannequin.\n */\nexport function aiStockSensitive(\n photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>,\n named: readonly string[] = [],\n): boolean {\n const { words: found } = hitWords(photo)\n const site = new Set(named)\n return SENSITIVE_STEMS.some(\n (topic) =>\n [...topic.words].some((word) => found.has(word)) &&\n ![...topic.allow].some((word) => site.has(word)),\n )\n}\n\n/**\n * How well a hit shows what a slot needs (AGL-3660), or 0 when it must not\n * fill it: a mockup or a blank never; a topic the site never named never\n * ({@link aiStockSensitive}); a picture of a thing only when the hit\n * names its object AND either the site's world or the subject's own\n * two-word phrase (\"bud vase\", \"wick trimmer\"); anything else only when it\n * names the site's world (when the site names one). Among the accepted, the\n * object among the hit's first tags counts 4 (a mention among its last, 2),\n * the subject's two-word phrase 3, each of its other words 1, and the\n * site's world 1, plus a quarter when it is among the first tags.\n */\nexport function aiStockRelevance(\n photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>,\n judgement: AiStockJudgement,\n): number {\n const hit = hitWords(photo)\n if (hit.rejected) return 0\n if (aiStockSensitive(photo, judgement.named)) return 0\n // Glass art is not pottery: a rival craft's photo names this craft's own words.\n for (const rival of judgement.rivals ?? [])\n if (\n rival.words.some((word) => hit.all.has(word)) &&\n !rival.core.some((word) => hit.all.has(word))\n )\n return 0\n const subject = stemList(judgement.subject ?? '')\n // What the slot or the brief names lets a shunned word, a room or a fragrance in.\n const owned = new Set([...subject, ...(judgement.named ?? [])])\n // A dispenser is not a soapmaker's, nor a pump a bar's (AGL-3660).\n if ((judgement.shun ?? []).some((word) => hit.all.has(word) && !owned.has(word)))\n return 0\n if (judgement.product) {\n // A sauna, a bathroom shelf: a room is never the product.\n for (const word of hit.lead)\n if (PRODUCT_SCENES.has(word) && !owned.has(word)) return 0\n // Colognes are not a lotion: a fragrance's bottle only for a fragrance.\n if (\n ![...FRAGRANCE_BOTTLES].some((word) => owned.has(word)) &&\n [...hit.lead].some((word) => FRAGRANCE_BOTTLES.has(word))\n )\n return 0\n }\n // A borrowed photo is OF the product's category.\n const leadAny = judgement.leadAny ?? []\n if (leadAny.length && !leadAny.some((phrase) => among(hit.leadPhrases, phrase)))\n return 0\n const kin = judgement.kin ?? []\n const kinNamed = kin.some((phrase) => among(hit.phrases, phrase))\n const kinLead = kin.some((phrase) => among(hit.leadPhrases, phrase))\n const required = stemList(judgement.requires ?? '')\n const category = (judgement.category ?? []).flatMap(stemList)\n const anyOf = category.length ? [...new Set([...required, ...category])] : []\n const demanded = required.length > 0 || anyOf.length > 0\n const meets = anyOf.length\n ? anyOf.some((stem) => hit.all.has(stem))\n : required.every((stem) => hit.all.has(stem))\n // An object's kin stands for the category: a wax melt is the candle shop's.\n if (demanded && !kinNamed && !meets) return 0\n const object =\n judgement.object ??\n (judgement.subject ? aiStockObjectWord(judgement.subject) : '')\n const domain = (judgement.domain ?? []).filter((stem) => stem !== object)\n // A hit naming the word it must name is of the site's world: a product's\n // category is that world even where it is the product's own object.\n const world =\n demanded || kinNamed || domain.some((stem) => hit.all.has(stem))\n const worldLead =\n (anyOf.length\n ? anyOf.some((stem) => hit.lead.has(stem))\n : required.length > 0 && required.every((stem) => hit.lead.has(stem))) ||\n kinLead ||\n domain.some((stem) => hit.lead.has(stem))\n if (judgement.leadWorld && !worldLead) return 0\n // The first tag alone, never the page's address: Pixabay's slug repeats a\n // late tag (\"coffee-latte-art-candle-…\"). A site whose words name no world\n // holds its hero to none.\n const worldStems = new Set([...anyOf, ...required, ...domain])\n if (judgement.first && (worldStems.size || kin.length)) {\n const firstWorld =\n hit.firstPhrase.split(' ').some((stem) => worldStems.has(stem)) ||\n kin.some((phrase) => among([hit.firstPhrase], phrase))\n if (!firstWorld) return 0\n }\n // What the photo is most of all: its first tag names the object, its kin or what it must be OF.\n const firstNamed = (phrases: readonly string[]) =>\n phrases.some((phrase) => Boolean(phrase) && among([hit.firstPhrase], phrase))\n const pair = subject.length >= 2 ? subject.slice(-2).join(' ') : ''\n const phrased = Boolean(pair) && among(hit.phrases, pair)\n let score = 0\n if (judgement.strict && object) {\n // An object with kin is named only by them: \"melt\" alone is resin art.\n const named = kin.length ? kinNamed : hit.all.has(object)\n if (!named) return 0\n const leading = kin.length ? kinLead : hit.lead.has(object)\n // A lifestyle scene whose object is a last tag is not a photo OF it.\n if (judgement.lead && !leading) return 0\n if (domain.length && !world && !phrased) return 0\n score += leading ? 4 : 2\n if (kinNamed) score += 3\n if (firstNamed(kin.length ? kin : [object])) score += 1\n } else if (domain.length) {\n if (!world) return 0\n }\n if (leadAny.length && firstNamed(leadAny)) score += 1\n if (phrased) score += 3\n for (const word of new Set(subject))\n if (word !== object && hit.all.has(word)) score += 1\n if (world) score += worldLead ? 1.25 : 1\n return Math.max(score, 0.5)\n}\n\n/**\n * A search's acceptable hits in the order they are tried (AGL-3660): those\n * not placed yet, among the first few the library returned, those it must\n * not take dropped ({@link aiStockRelevance}), best first; the seed turns\n * the hits that score alike, so two jobs differ and one job repeats itself.\n */\nexport function aiStockRank(\n photos: readonly StockPhoto[],\n used: ReadonlySet<string>,\n seed: string,\n judgement: AiStockJudgement = {},\n): StockPhoto[] {\n const scored = photos\n .filter((photo) => !used.has(stockPhotoSourceKey(photo)))\n .slice(0, AI_LAYOUT_STOCK_PICK_WINDOW)\n .map((photo) => ({ photo, score: aiStockRelevance(photo, judgement) }))\n .filter((entry) => entry.score > 0)\n if (!scored.length) return []\n const turn = aiLayoutSeedNumber(seed)\n const ranked: StockPhoto[] = []\n for (const score of [...new Set(scored.map((entry) => entry.score))].sort(\n (a, b) => b - a,\n )) {\n const tier = scored.filter((entry) => entry.score === score)\n const start = turn % tier.length\n for (const entry of [...tier.slice(start), ...tier.slice(0, start)])\n ranked.push(entry.photo)\n }\n return ranked\n}\n\n/** The pick among a search's hits: the first {@link aiStockRank} would try, or `null`. */\nexport function aiStockPick(\n photos: readonly StockPhoto[],\n used: ReadonlySet<string>,\n seed: string,\n judgement: AiStockJudgement = {},\n): StockPhoto | null {\n return aiStockRank(photos, used, seed, judgement)[0] ?? null\n}\n\n/**\n * The library photos a stored page already shows: every `image` whose\n * source is the site's media reference. Starter photos are the platform's,\n * not the job's, and are not listed.\n */\nexport function aiStockPlacedSrcs(\n nodes: NodesMap | null | undefined,\n): string[] {\n const map = (nodes ?? {}) as unknown as Record<\n string,\n { componentId?: string; props?: Record<string, unknown> }\n >\n const out: string[] = []\n for (const node of Object.values(map)) {\n const src = node?.componentId === 'image' ? node.props?.['src'] : null\n if (typeof src === 'string' && src.startsWith('media:')) out.push(src)\n }\n return out\n}\n\n/**\n * What this process has placed for each job, by source key and asset src,\n * with the scope (the page's seed) that placed it (AGL-3660). It spans the\n * passes of one job that run here, so a page, the products or a post built\n * later does not place what an earlier one did, while a pass repeated over\n * its own page keeps its own photos. Bounded; the oldest job goes first.\n */\nconst JOB_PHOTOS = new Map<string, Map<string, string>>()\nconst JOB_PHOTOS_MAX = 200\n\nfunction jobPhotos(key: string | null): Map<string, string> | null {\n if (!key) return null\n let placed = JOB_PHOTOS.get(key)\n if (!placed) {\n placed = new Map()\n JOB_PHOTOS.set(key, placed)\n while (JOB_PHOTOS.size > JOB_PHOTOS_MAX) {\n const oldest = JOB_PHOTOS.keys().next().value\n if (oldest === undefined) break\n JOB_PHOTOS.delete(oldest)\n }\n }\n return placed\n}\n\n/** Forgets every job's placed photos; for specs. */\nexport function aiStockForgetJobPhotos(): void {\n JOB_PHOTOS.clear()\n}\n\n/** The longest description of a photo written from the library's own words. */\nconst AI_STOCK_ALT_MAX = 160\n\n/**\n * THE WORDS A PLACED STOCK PHOTO IS DESCRIBED BY (AGL-3805).\n *\n * A slot's alt text is the model's, written for the picture the page asked\n * for before any photo was found, and a slot is filled by whatever the\n * library answers for its search: a hero searched by the business, a gallery\n * picture by its subject, a site in another language by English words alone.\n * Kept as written, it described a photo the page does not show: the beta.253\n * Panadería La Concha Dorada start (job eg4maZMGtN) captioned a round cake\n * dusted \"HOME MADE\" on a cloth \"Conchas recién horneadas sobre una charola en\n * el mostrador de la panadería\", and none of its nine photos showed what its\n * words said: a birthday cake with candles was \"the family kneading pan\n * dulce\", a plate of macarons the shop's display case.\n *\n * So the photo placed answers for its own words. `null` keeps the slot's: on\n * an English site whose words name what the photo is OF — a word of their\n * subject (`aiStockSubjectWords`: the noun phrase they open with, before any\n * setting) among the hit's first tags or its page's address, so \"conchas on\n * a tray at the bakery counter\" is never kept for a loaf tagged \"bakery\".\n * Otherwise the photo is described by the\n * library's own words: its description where it writes one (a Pexels hit's\n * `alt`), else its first tags, the things it shows. The libraries write in\n * English, and no model translates them, so a site in another language takes\n * the platform's own words for an illustrative photo in its language\n * (`aiLayoutLabel`), true of any photo, as does a hit with no words at all.\n */\nexport function aiStockPhotoAlt(\n photo: Pick<StockPhoto, 'tags' | 'alt' | 'pageUrl'>,\n slot: Pick<AiLayoutPictureSlot, 'alt' | 'product'>,\n input: { language?: string; sectionName?: string } = {},\n): string | null {\n if (aiLayoutSpeaksOtherThanEnglish(input.language)) return aiLayoutLabel('illustrativePhoto', input.language)\n const { lead } = hitWords(photo)\n const named = [slot.alt, ...(slot.product?.subjects ?? [])].flatMap((words) =>\n stemList(aiStockSubjectWords(words, input.sectionName ?? '')),\n )\n if (named.some((word) => lead.has(word))) return null\n const own = (photo.alt ?? '').replace(/\\s+/g, ' ').trim()\n if (own) return own.length > AI_STOCK_ALT_MAX ? `${own.slice(0, AI_STOCK_ALT_MAX).replace(/\\s+\\S*$/, '')}…` : own\n const tags = [...new Set((photo.tags ?? []).map((tag) => tag.replace(/\\s+/g, ' ').trim().toLowerCase()).filter(Boolean))].slice(0, 3)\n if (!tags.length) return aiLayoutLabel('illustrativePhoto', input.language)\n const said = tags.join(', ')\n return `${said.charAt(0).toUpperCase()}${said.slice(1)}`\n}\n\nconst EXTENSIONS: Record<string, string> = {\n 'image/jpeg': 'jpg',\n 'image/png': 'png',\n 'image/webp': 'webp',\n}\n\nexport interface AiLayoutStockPhotoSourceInput {\n hostId: string\n /** The member the photos are stored as: the job's creator. */\n uid: string\n /** The job's seed, as the starter photos turn by; also the scope a photo is placed under. */\n seed: string\n /** The site's business type, else the job's brief. */\n business: string\n /** The site's language, from its plan (AGL-3750); absent, English. */\n language?: string\n /**\n * The plan's photo words, in English (AGL-3760): what a site in another\n * language is searched by, in place of its business type and its alt texts,\n * unless its business type names a business listed in English\n * (`aiStockBusinessNoun`, AGL-3779), which leads.\n */\n photoWords?: string\n /**\n * The English name of the kind of site the person picked (AGL-3771): what a\n * site in another language is searched by when its business type names no\n * business listed in English (`aiStockBusinessNoun`, AGL-3779) and its plan\n * gave no photo words, rather than its business type in its own language.\n */\n kindWords?: string\n /** The page's section names, by plan index. */\n sectionNames: readonly string[]\n /**\n * The job the member started (`aiOriginJobId`), so a photo is placed once\n * across its pages. Absent, only the page itself is kept free of repeats.\n */\n jobId?: string\n /** Asset srcs or source keys the job's other pages already show. */\n avoid?: readonly string[]\n /** The most searches this source sends; a page's own bound where absent. A store's products search more (AGL-3676). */\n searches?: number\n signal?: AbortSignal\n}\n\nexport interface AiLayoutStockPhotoDeps {\n provider?: () => StockPhotoProvider | null\n ingest?: () => PluginMediaIngest | null\n budgetMs?: number\n}\n\n/** A slot's choice: the accepted hits it may be filled from, best first, and the query that found them. */\ninterface AiStockChoice {\n candidates: StockPhoto[]\n query: string\n /** A photo another slot of the job already shows, reused rather than an off-topic one (AGL-3660). */\n repeat?: boolean\n}\n\n/**\n * A job's language and English photo words (AGL-3760), and the English name\n * of its kind of site (AGL-3771), as a stock photo source takes them.\n */\nexport function aiStockPhotoWordsOf(job: {\n plan?: Pick<AiBuildPlan, 'language' | 'photoWords'> | null\n inputs?: Readonly<Record<string, unknown>> | null\n}): Pick<AiLayoutStockPhotoSourceInput, 'language' | 'photoWords' | 'kindWords'> {\n const plan = job.plan\n const kind = job.inputs ? aiSiteKindOfInputs(job.inputs) : null\n // \"Restaurant & café\" searches as \"restaurant cafe\".\n const kindWords = kind ? kind.label.normalize('NFD').replace(/[\\u0300-\\u036f]/g, '').replace(/&/g, ' ').replace(/\\s+/g, ' ').trim().toLowerCase() : ''\n return {\n ...(plan?.language ? { language: plan.language } : {}),\n ...(plan?.photoWords ? { photoWords: plan.photoWords } : {}),\n ...(kindWords ? { kindWords } : {}),\n }\n}\n\n/**\n * The subject a plan's photo words lead with (AGL-3769): its first word that\n * is not filler, with the place or person words that follow it — \"bakery\" of\n * \"bakery pan dulce conchas\", \"candle shop\" of \"candle shop soy candles\",\n * \"ceramic artist\" of \"ceramic artist stoneware bowls\". The words are subject\n * first, never an English noun phrase with its head last, and what follows\n * the subject may be the brief's own names in English letters: Panaderia La\n * Espiga Dorada's \"pan dulce conchas\" read as the business, made \"concha\" its\n * craft, and placed purple ceanothus flowers, tagged \"ceanothus concha\", as\n * its hero. Empty when every word is filler.\n */\nexport function aiStockPhotoWordsSubject(photoWords: string): string {\n const list = contentWords(photoWords)\n const start = list.findIndex((word) => !FILLER.has(word) && !SITE_KINDS.has(word))\n if (start < 0) return ''\n let end = start + 1\n while (end < list.length && (VENUES.has(list[end]) || ROLES.has(list[end]))) end += 1\n return list.slice(start, end).join(' ')\n}\n\n/**\n * What a source's photos are searched and judged by (AGL-3760, AGL-3769): a\n * site in another language by an English subject ({@link aiStockSourceSubject}:\n * its business named in English, else its plan's photo words' subject, else\n * its kind of site), every other site by its business type. One reading for\n * every slot of every source — hero, background, gallery, card, product,\n * post — so no slot searches by words another slot is held against.\n */\nexport function aiStockSourceTerms(\n input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords'>,\n): AiStockSiteTerms {\n return aiStockSiteTerms(aiStockSourceSubject(input) || input.business)\n}\n\n/**\n * What a site in another language is searched by ({@link aiStockSourceTerms}),\n * in this order (AGL-3779):\n *\n * 1. The English name of the business its type names, where the curated table\n * knows it ({@link aiStockBusinessNoun}): \"florist\" for \"Una floristería en\n * Sevilla\". It leads whatever the plan's photo words say, because the words\n * are the model's and the table is not: a live plan for that florist gave\n * \"wedding bouquets event flowers\", whose subject, \"wedding\", would have\n * searched every slot, its hero included, by weddings.\n * 2. Its photo words' subject (AGL-3760, AGL-3769), for a business the table\n * does not list.\n * 3. The English name of its kind of site (AGL-3771), where the plan gave\n * none. Panaderia El Trigal's pages searched \"con pan dulce\" and placed the\n * Río Dulce; searched by its kind, a bakery's hero took a coffee mug\n * (\"restaurant cafe\"), which is why it comes last.\n *\n * The photo words' other words were never searched by (AGL-3769), so a site\n * the table names is searched by its name alone. Empty for every other site.\n */\nfunction aiStockSourceSubject(\n input: Pick<AiLayoutStockPhotoSourceInput, 'business' | 'language' | 'photoWords' | 'kindWords'>,\n): string {\n if (!aiLayoutSpeaksOtherThanEnglish(input.language)) return ''\n return (\n aiStockBusinessNoun(input.business) ||\n aiStockPhotoWordsSubject(input.photoWords ?? '') ||\n (input.kindWords ?? '').trim()\n )\n}\n\n/**\n * The source for one page, or `null` when this deployment has no stock\n * photo library or no media door, which leaves every slot to the starters.\n */\nexport function aiLayoutStockPhotoSource(\n input: AiLayoutStockPhotoSourceInput,\n deps: AiLayoutStockPhotoDeps = {},\n): AiLayoutPictureSource | null {\n const provider = (deps.provider ?? stockPhotoProvider)()\n const ingest = (deps.ingest ?? pluginMediaIngest)()\n if (!provider || !ingest || !input.hostId || !input.uid) return null\n // The libraries are tagged in English (AGL-3760). A Spanish bakery's type,\n // \"Una panadería familiar de San Antonio con pan dulce…\", read as the\n // business \"con pan dulce\", and its hero searched that and placed the Río\n // Dulce at dusk; a site in another language is searched by its plan's\n // English photo words' subject ({@link aiStockSourceTerms}), and its slots'\n // alt texts, in its own language, name no subject a search could use.\n const english = aiStockSourceSubject(input)\n const terms = aiStockSourceTerms(input)\n return async (slots) => {\n const timeout = AbortSignal.timeout(\n deps.budgetMs ?? AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS,\n )\n const signal = input.signal\n ? AbortSignal.any([input.signal, timeout])\n : timeout\n const scope = input.seed\n const job = jobPhotos(input.jobId ? `${input.hostId}:${input.jobId}` : null)\n const avoid = new Set(input.avoid ?? [])\n /** Placed elsewhere in the job: by another page in this process, or one the caller read. */\n const elsewhere = (key: string) =>\n avoid.has(key) || (job?.has(key) === true && job.get(key) !== scope)\n /** Source keys this page has claimed for a slot, or turned down. */\n const claimed = new Set<string>()\n /** Asset srcs this page has placed. */\n const placedSrcs = new Set<string>()\n const answers = new Map<string, Promise<StockPhoto[] | null>>()\n let searches = 0\n let storing = true\n const remember = (sourceKey: string, src: string) => {\n placedSrcs.add(src)\n job?.set(sourceKey, scope)\n job?.set(src, scope)\n }\n /** A search's hits; the same words twice are answered from memory, and `null` once the page's searches are spent. */\n const search = (wanted: AiStockSearch): Promise<StockPhoto[] | null> => {\n const request: StockPhotoSearchRequest = { ...wanted }\n delete (request as AiStockSearch).broad\n delete (request as AiStockSearch).subject\n delete (request as AiStockSearch).requires\n delete (request as AiStockSearch).object\n delete (request as AiStockSearch).kin\n delete (request as AiStockSearch).lead\n delete (request as AiStockSearch).leadWorld\n delete (request as AiStockSearch).first\n delete (request as AiStockSearch).category\n const key = JSON.stringify([\n request.query,\n request.orientation,\n request.people === true,\n ])\n const known = answers.get(key)\n if (known) return known\n if (searches >= (input.searches ?? AI_LAYOUT_STOCK_SEARCHES_PER_PAGE))\n return Promise.resolve(null)\n searches += 1\n const asked = provider\n .search(request, { signal })\n .then((found) => found?.photos ?? [])\n .catch(() => [] as StockPhoto[])\n answers.set(key, asked)\n return asked\n }\n /** The photo's own words where the slot's do not describe it ({@link aiStockPhotoAlt}). */\n const altFor = (photo: StockPhoto, slot: AiLayoutPictureSlot) =>\n aiStockPhotoAlt(photo, slot, {\n ...(input.language ? { language: input.language } : {}),\n sectionName: input.sectionNames[slot.sectionIndex] ?? '',\n })\n /** The photo placed in the site's library, a copy it holds or a new one; `null` when it cannot be placed. */\n const keep = async (\n photo: StockPhoto,\n slot: AiLayoutPictureSlot,\n query: string,\n repeat = false,\n ): Promise<AiLayoutPicturePhoto | null> => {\n const sourceKey = stockPhotoSourceKey(photo)\n const alt = altFor(photo, slot)\n const described = alt === null ? {} : { alt }\n try {\n const kept = await ingest.findStockPhoto({\n hostId: input.hostId,\n sourceKey,\n })\n if (kept) {\n // Held because a slot of this page or another page of the job shows it.\n if (!repeat && (placedSrcs.has(kept.src) || elsewhere(kept.src)))\n return null\n remember(sourceKey, kept.src)\n return {\n src: kept.src,\n width: kept.width ?? photo.width,\n height: kept.height ?? photo.height,\n ...described,\n }\n }\n // A refusal to store (the storage band, a lockdown) holds for the\n // whole page, so the rest of it reuses what it can and copies nothing.\n if (!storing || signal.aborted) return null\n const bytes = await provider.download(photo, {\n maxBytes: AI_LAYOUT_STOCK_MAX_BYTES,\n signal,\n })\n if (!bytes || signal.aborted || !storing) return null\n const credit = provider.credit(photo)\n const stored = await ingest.ingest({\n hostId: input.hostId,\n uid: input.uid,\n fileName: `${photo.provider}-${photo.id}.${EXTENSIONS[bytes.contentType] ?? 'jpg'}`,\n contentType: bytes.contentType,\n bytes: bytes.bytes,\n alt: alt ?? slot.alt,\n description: credit.text,\n stockPhoto: {\n key: sourceKey,\n provider: photo.provider,\n providerLabel: credit.providerLabel,\n id: photo.id,\n pageUrl: photo.pageUrl,\n photographer: photo.photographer,\n ...(photo.photographerUrl\n ? { photographerUrl: photo.photographerUrl }\n : {}),\n license: credit.license,\n licenseUrl: credit.licenseUrl,\n attributionRequired: credit.attributionRequired,\n query,\n },\n })\n if (stored.ok) {\n remember(sourceKey, stored.src)\n return {\n src: stored.src,\n width: stored.width ?? photo.width,\n height: stored.height ?? photo.height,\n ...described,\n }\n }\n storing = false\n const refusal = stored as Extract<\n PluginMediaIngestResult,\n { ok: false }\n >\n console.warn(\n 'ai layout pictures: the media library refused a stock photo',\n {\n status: refusal.status,\n reason: refusal.reason,\n },\n )\n } catch (error) {\n console.warn('ai layout pictures: a stock photo could not be kept', {\n error: String(error),\n })\n }\n return null\n }\n\n /** How a search's hits are judged for a slot. */\n const judgementFor = (\n slot: AiLayoutPictureSlot,\n request: AiStockSearch,\n subject: string,\n ): AiStockJudgement => ({\n subject: request.subject ?? (request.broad ? '' : subject),\n domain: terms.domain,\n strict:\n (slot.role === 'gallery' && !request.broad) || !!request.requires,\n named: terms.named,\n rivals: terms.rivals,\n ...(terms.shun.length || request.shun?.length\n ? { shun: [...new Set([...terms.shun, ...(request.shun ?? [])])] }\n : {}),\n ...(request.product ? { product: true } : {}),\n ...(request.leadAny?.length ? { leadAny: request.leadAny } : {}),\n ...(request.requires ? { requires: request.requires } : {}),\n ...(request.category ? { category: request.category } : {}),\n ...(request.object ? { object: request.object } : {}),\n ...(request.kin ? { kin: request.kin } : {}),\n ...(request.lead ? { lead: true } : {}),\n ...(request.leadWorld ? { leadWorld: true } : {}),\n ...(request.first ? { first: true } : {}),\n })\n /**\n * The craft's own photos, the last thing a slot of a craft's site is\n * filled from (AGL-3660): its broad searches, any hit naming the craft\n * itself. Never a desk, a laptop or a living room for a soap shop.\n */\n const craftSearches = (slot: AiLayoutPictureSlot): AiStockSearch[] => {\n if (!terms.core.length) return []\n const orientation = aiStockOrientation(slot.aspect)\n const size =\n slot.role === 'hero'\n ? { minWidth: 1600 }\n : orientation === 'vertical'\n ? { minHeight: 900 }\n : { minWidth: 900 }\n return terms.broad.map((query) => ({\n query: clip(query),\n orientation,\n ...size,\n broad: true,\n category: terms.core,\n ...(slot.role === 'hero' ? { first: true } : {}),\n ...(slot.product ? { product: true, tier: 'weak' as const } : {}),\n }))\n }\n\n // 1. Choose, slot by slot, so the page's choices never collide: each\n // slot claims its best accepted hit before the next slot looks.\n const choices: Array<AiStockChoice | null> = []\n for (const [index, slot] of slots.entries()) {\n if (signal.aborted) {\n choices.push(null)\n continue\n }\n const sectionName = input.sectionNames[slot.sectionIndex] ?? ''\n const subject = english ? '' : aiStockSubjectWords(slot.alt, sectionName)\n let choice: AiStockChoice | null = null\n const requests = [\n ...(slot.product\n ? aiStockProductSearches(slot, terms.craft, terms.domain, {\n broad: terms.broad,\n core: terms.core,\n })\n : aiStockSearchesFor(\n slot,\n terms,\n subject,\n aiStockSlotPart(slot, sectionName),\n )),\n ...craftSearches(slot),\n ]\n /** The slot's accepted hits for a search; `null` once the page's searches are spent. */\n const accepted = async (\n request: AiStockSearch,\n repeat: boolean,\n ): Promise<StockPhoto[] | null> => {\n const found = await search(request)\n if (found === null) return null\n const blocked = new Set<string>()\n if (!repeat) {\n for (const key of claimed) blocked.add(key)\n for (const hit of found) {\n const key = stockPhotoSourceKey(hit)\n if (elsewhere(key)) blocked.add(key)\n }\n }\n return aiStockRank(\n found,\n blocked,\n `${input.seed}:${index}:${request.query}`,\n judgementFor(slot, request, subject),\n )\n }\n /** The first of these searches with a hit to take: a new one, or one the job already shows. */\n const choose = async (\n tried: readonly AiStockSearch[],\n repeat: boolean,\n ): Promise<AiStockChoice | null> => {\n for (const request of tried) {\n if (signal.aborted) return null\n // Spent searches answer nothing; those already asked still answer from memory.\n const ranked = await accepted(request, repeat)\n if (!ranked?.length) continue\n if (!repeat) claimed.add(stockPhotoSourceKey(ranked[0] as StockPhoto))\n return {\n candidates: ranked.slice(0, AI_LAYOUT_STOCK_TRIES_PER_SLOT),\n query: request.query,\n ...(repeat ? { repeat: true } : {}),\n }\n }\n return null\n }\n // 2. Nothing new of its own: a product or a hero reuses an on-topic\n // photo another slot of the job already shows (a product may repeat\n // a collection tile's photo, or another product's) before the\n // starters' desk or living room fills it (AGL-3660). Any other\n // picture keeps \"never twice\". A product goes by how sure each\n // search is: its own and its category's photos, new and then\n // repeated, before a weak hit of its own (the Tidewater sauna).\n const repeats = Boolean(slot.product) || slot.role === 'hero'\n const sure = slot.product\n ? requests.filter((request) => request.tier !== 'weak')\n : requests\n const unsure = slot.product\n ? requests.filter((request) => request.tier === 'weak')\n : []\n const phases: Array<[readonly AiStockSearch[], boolean]> = [\n [sure, false],\n ...(repeats ? [[sure, true] as [readonly AiStockSearch[], boolean]] : []),\n ...(unsure.length\n ? [\n [unsure, false] as [readonly AiStockSearch[], boolean],\n [unsure, true] as [readonly AiStockSearch[], boolean],\n ]\n : []),\n ]\n for (const [tried, repeat] of phases) {\n if (choice || signal.aborted) break\n choice = await choose(tried, repeat)\n }\n choices.push(choice)\n }\n\n // 3. Keep, a few at a time; a copy that fails tries the slot's next\n // accepted hit no other slot has claimed. A repeat waits for the\n // slot it repeats, so the library never holds a photo twice.\n const photos: Array<AiLayoutPicturePhoto | null> = slots.map(() => null)\n /** What this pass placed, by source key. */\n const placedByKey = new Map<string, AiLayoutPicturePhoto>()\n const fill = async (index: number) => {\n const choice = choices[index]\n const slot = slots[index]\n if (!choice || !slot) return\n for (const [rank, candidate] of choice.candidates.entries()) {\n if (signal.aborted) return\n const key = stockPhotoSourceKey(candidate)\n if (choice.repeat) {\n // Placed for another slot, it is described for this one.\n const shown = placedByKey.get(key)\n const alt = shown ? altFor(candidate, slot) : null\n const placed = shown\n ? { src: shown.src, width: shown.width, height: shown.height, ...(alt === null ? {} : { alt }) }\n : await keep(candidate, slot, choice.query, true)\n if (placed) {\n photos[index] = placed\n return\n }\n continue\n }\n if (rank > 0) {\n if (claimed.has(key)) continue\n claimed.add(key)\n }\n const placed = await keep(candidate, slot, choice.query)\n if (placed) {\n placedByKey.set(key, placed)\n photos[index] = placed\n return\n }\n }\n }\n const firsts = slots\n .map((_slot, index) => index)\n .filter((index) => !choices[index]?.repeat)\n let next = 0\n const worker = async () => {\n while (next < firsts.length) {\n const index = firsts[next] as number\n next += 1\n await fill(index)\n }\n }\n await Promise.all(\n Array.from(\n { length: Math.min(AI_LAYOUT_STOCK_COPIES_AT_ONCE, firsts.length) },\n worker,\n ),\n )\n for (const [index, choice] of choices.entries())\n if (choice?.repeat) await fill(index)\n return photos\n }\n}\n"],"names":["pluginMediaIngest","STOCK_PHOTO_QUERY_MAX_CHARS","stockPhotoProvider","stockPhotoSourceKey","aiLayoutSeedNumber","aiStorefrontSays","aiLayoutLabel","aiLayoutSpeaksOtherThanEnglish","aiSiteKindOfInputs","aiStockBusinessNoun","AI_LAYOUT_STOCK_PHOTOS_BUDGET_MS","AI_LAYOUT_STOCK_SEARCHES_PER_PAGE","AI_LAYOUT_STOCK_PICK_WINDOW","AI_LAYOUT_STOCK_TRIES_PER_SLOT","AI_LAYOUT_STOCK_COPIES_AT_ONCE","AI_LAYOUT_STOCK_MAX_BYTES","AI_STOCK_PHOTO_PAGES_INPUT","AI_STOCK_PHOTO_AVOID_INPUT","words","list","Set","trim","split","STOPWORDS","FILLER","VENUES","ROLES","SITE_KINDS","DOING","BUSINESS_BREAK","PLACE_OR_AUDIENCE","WRAPPERS","REJECTED_TAGS","PRODUCT_SCENES","map","aiStockStem","FRAGRANCE_BOTTLES","SENSITIVE_TOPICS","allow","always","SENSITIVE_STEMS","topic","HAND_IDIOMS","withoutHands","text","reduce","out","idiom","replace","toLowerCase","saysMadeByHand","lower","some","lastIndex","found","test","OBJECT_KIN","objects","within","qualifier","kin","queries","shun","after","objectKin","object","world","find","entry","word","includes","CRAFT_KIN","match","broad","rivals","core","making","contentWords","filter","length","has","endsWith","slice","stemList","CLAUSE_BREAK","businessClauses","businessType","clauses","breaker","RegExp","source","at","opener","matchAll","push","index","businessOf","clause","aiStockBusinessWords","named","join","aiStockCraftWords","business","craft","aiStockSiteTerms","domain","made","firstWorld","kept","stem","add","last","size","groups","group","listed","makingSearches","query","Boolean","subjectOf","aiStockSubjectWords","alt","sectionName","aiStockObjectWord","subject","reverse","clip","aiStockOrientation","aspect","aiStockSlotPart","slot","role","undefined","kinStems","phrase","PRODUCT_SIZES","GIFT_WRAPPERS","aiStockProductSearches","fallback","subjects","orientation","minHeight","minWidth","craftStems","product","raw","own","kinPhrases","ownWorld","category","stems","lead","tier","held","wrapped","gift","borrowed","seen","searches","key","common","heldTo","leadAny","leadWorld","requires","aiStockSearchesFor","terms","part","subjectStems","namesWorld","qualify","collection","thing","people","first","pageSlug","pageUrl","decodeURIComponent","URL","pathname","pop","hitWords","photo","tags","slug","tag","all","phrases","leadPhrases","firstPhrase","rejected","among","aiStockSensitive","site","aiStockRelevance","judgement","hit","rival","owned","kinNamed","kinLead","required","flatMap","anyOf","demanded","meets","every","worldLead","worldStems","firstNamed","pair","phrased","score","strict","leading","Math","max","aiStockRank","photos","used","seed","scored","turn","ranked","sort","a","b","start","aiStockPick","aiStockPlacedSrcs","nodes","node","Object","values","src","componentId","props","startsWith","JOB_PHOTOS","Map","JOB_PHOTOS_MAX","jobPhotos","placed","get","set","oldest","keys","next","value","delete","aiStockForgetJobPhotos","clear","AI_STOCK_ALT_MAX","aiStockPhotoAlt","input","language","said","charAt","toUpperCase","EXTENSIONS","aiStockPhotoWordsOf","job","plan","kind","inputs","kindWords","label","normalize","photoWords","aiStockPhotoWordsSubject","findIndex","end","aiStockSourceTerms","aiStockSourceSubject","aiLayoutStockPhotoSource","deps","provider","ingest","hostId","uid","english","slots","timeout","AbortSignal","budgetMs","signal","any","scope","jobId","avoid","elsewhere","claimed","placedSrcs","answers","storing","remember","sourceKey","search","wanted","request","JSON","stringify","known","Promise","resolve","asked","then","catch","altFor","sectionNames","sectionIndex","keep","repeat","described","findStockPhoto","width","height","aborted","bytes","download","maxBytes","credit","stored","fileName","id","contentType","description","stockPhoto","providerLabel","photographer","photographerUrl","license","licenseUrl","attributionRequired","ok","refusal","console","warn","status","reason","error","String","judgementFor","craftSearches","choices","entries","choice","requests","accepted","blocked","choose","tried","candidates","repeats","sure","unsure","phases","placedByKey","fill","rank","candidate","shown","firsts","_slot","worker","Array","from","min"],"mappings":";AAAA;;;;;;;;;;;;;;;CAeC,GAED,SACEA,iBAAiB,QAGZ,kDAAiD;AACxD,SACEC,2BAA2B,EAC3BC,kBAAkB,EAClBC,mBAAmB,QAKd,mDAAkD;AAEzD,SACEC,kBAAkB,QAIb,2CAAuC;AAC9C,SAASC,gBAAgB,QAAQ,6CAAyC;AAC1E,SAASC,aAAa,EAAEC,8BAA8B,QAAQ,yCAAqC;AAEnG,SAASC,kBAAkB,QAAQ,4BAAwB;AAC3D,SAASC,mBAAmB,QAAQ,+BAA2B;AAE/D;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwGC,GAED,+EAA+E,GAC/E,OAAO,MAAMC,mCAAmC,MAAM;AAEtD,yGAAyG,GACzG,OAAO,MAAMC,oCAAoC,GAAE;AAEnD,mCAAmC,GACnC,OAAO,MAAMC,8BAA8B,GAAE;AAE7C,kEAAkE,GAClE,MAAMC,iCAAiC;AAEvC,8BAA8B,GAC9B,MAAMC,iCAAiC;AAEvC,wDAAwD,GACxD,OAAO,MAAMC,4BAA4B,IAAI,OAAO,KAAI;AAExD;;;CAGC,GACD,OAAO,MAAMC,6BAA6B,kBAAiB;AAE3D;;;;CAIC,GACD,OAAO,MAAMC,6BAA6B,kBAAiB;AAE3D,MAAMC,QAAQ,CAACC,OAAiB,IAAIC,IAAID,KAAKE,IAAI,GAAGC,KAAK,CAAC;AAE1D,iCAAiC,GACjC,MAAMC,YAAYL,MAChB,6GACE,4GACA,iGACA,mFACA;AAGJ;;;CAGC,GACD,MAAMM,SAASN,MACb,kHACE,sGACA,wGACA,yGACA,iHACA,0GACA,qGACA,qGACA,4GACA,sDACA,oHAAoH;AACpH,yEACA,yGACA;AAGJ,2FAA2F,GAC3F,MAAMO,SAASP,MACb,+GACE,qGACA;AAGJ,gFAAgF,GAChF,MAAMQ,QAAQR,MACZ;AAGF,kHAAkH,GAClH,MAAMS,aAAaT,MACjB,yGACE;AAGJ,yGAAyG,GACzG,MAAMU,QACJ;AAEF,6CAA6C,GAC7C,MAAMC,iBACJ;AAEF,qGAAqG,GACrG,MAAMC,oBACJ;AAEF;;;CAGC,GACD,MAAMC,WAAWb,MACf,kHACE;AAGJ;;;;CAIC,GACD,MAAMc,gBAAgBd,MACpB,iGACE;AAGJ;;;;;CAKC,GACD,MAAMe,iBAAiB,IAAIb,IACzB;IACE;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;IACA;CACD,CAACc,GAAG,CAACC;AAGR;;;;;CAKC,GACD,MAAMC,oBAAoB,IAAIhB,IAC5B;IAAC;IAAW;IAAY;IAAa;IAAW;IAAY;IAAU;IAAO;IAAY;CAAY,CAACc,GAAG,CACvGC;AAIJ;;;;;;;;CAQC,GACD,MAAME,mBAKD;IACH;QACE,YAAY;QACZnB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAY;YAAU;YAAgB;SAAU;IAC1D;IACA;QACE,sBAAsB;QACtBpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAW;YAAY;YAAa;YAAY;SAAY;IACtE;IACA;QACE,YAAY;QACZpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAY;YAAY;YAAa;YAAW;SAAY;IACtE;IACA;QACE,mBAAmB;QACnBpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;YAAC;YAAW;YAAW;YAAW;YAAW;SAAU;IAChE;IACA;QACE,kDAAkD;QAClDpB,OAAO;YACL;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;YACA;SACD;QACDoB,OAAO;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"}