[object Object]

← back to Wallco Ai

tick 11: process 8 new wikimedia PD images (palette+tileability+classification — 4 new AI-input candidates) · 'Surprise me' button on /designs fires random-palette/random-motif chat → 1 fresh SDXL design, ~30s//bin/zsh.014

45049061c17a017d7d1ed3199a3457c75a7933f9 · 2026-05-11 20:31:08 -0700 · Steve

Files touched

Diff

commit 45049061c17a017d7d1ed3199a3457c75a7933f9
Author: Steve <steve@designerwallcoverings.com>
Date:   Mon May 11 20:31:08 2026 -0700

    tick 11: process 8 new wikimedia PD images (palette+tileability+classification — 4 new AI-input candidates) · 'Surprise me' button on /designs fires random-palette/random-motif chat → 1 fresh SDXL design, ~30s//bin/zsh.014
---
 server.js    | 49 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/admin.js |  6 +++++-
 2 files changed, 54 insertions(+), 1 deletion(-)

diff --git a/server.js b/server.js
index f97a345..5209302 100644
--- a/server.js
+++ b/server.js
@@ -729,6 +729,9 @@ ${htmlHeader('/designs')}
         <label class="density-label">Density
           <input type="range" id="density-slider" min="2" max="8" step="1" value="4" class="density-range">
         </label>
+        <button type="button" id="surprise-btn" class="filter-select"
+          style="background:var(--gold,#c9a14b);color:var(--accent,#0d0d0d);border:0;font-weight:500;padding:8px 14px;cursor:pointer;border-radius:6px;letter-spacing:.04em"
+          title="Generate one fresh design in a random palette · ~30s">✦ Surprise me</button>
       </div>
       <input type="hidden" name="motif" id="motif-hidden" value="${motifQ}">
     </form>
@@ -741,6 +744,52 @@ ${htmlHeader('/designs')}
     </div>
 
     <p class="result-count">${total} design${total===1?'':'s'}${cat?' in '+cat:''}${motifQ?' with '+motifQ:''}${q?' matching "'+q+'"':''}</p>
+
+    <div id="surprise-result" style="display:none;margin-bottom:18px;padding:16px;border:1px solid var(--gold);border-radius:8px;background:var(--card-bg)"></div>
+    <script>
+    (function(){
+      var btn = document.getElementById('surprise-btn');
+      if (!btn) return;
+      var palettes = [
+        ['amber and emerald','damask'],
+        ['blush and indigo','floral'],
+        ['oyster and bone','damask'],
+        ['terracotta and sage','mixed'],
+        ['plum and gold','geometric'],
+        ['marine and coral','floral'],
+        ['charcoal and brass','geometric'],
+        ['ivory and persimmon','floral'],
+        ['sapphire and pearl','damask'],
+        ['olive and rose','floral']
+      ];
+      var motifsCue = ['scrollwork','peony','lattice','vine','arabesque','asanoha','fan','blossom','toile','trellis'];
+      btn.addEventListener('click', async function(){
+        var pick = palettes[Math.floor(Math.random()*palettes.length)];
+        var motif = motifsCue[Math.floor(Math.random()*motifsCue.length)];
+        var msg = 'make me a new wallpaper in ' + pick[0] + ' with a ' + motif + ' motif — surprising me';
+        var box = document.getElementById('surprise-result');
+        box.style.display = 'block';
+        box.innerHTML = '<div style="font:13px/1.5 -apple-system,sans-serif;color:var(--ink-soft)">Generating <em>' + pick[0] + ' · ' + motif + '</em>… (~30s)</div>';
+        btn.disabled = true; var orig = btn.textContent; btn.textContent = '… generating';
+        try {
+          var r = await fetch('/api/chat/catalog', {
+            method: 'POST', headers: {'Content-Type': 'application/json'},
+            body: JSON.stringify({ message: msg })
+          });
+          var j = await r.json();
+          var d = (j.actions || []).find(function(a){ return a.type === 'new_design'; });
+          if (d && d.design) {
+            box.innerHTML = '<div style="display:flex;gap:14px;align-items:flex-start"><a href="/design/' + d.design.id + '" style="text-decoration:none"><img src="' + d.design.image_url + '" style="width:140px;height:140px;object-fit:cover;border-radius:6px;border:1px solid var(--line)"></a><div style="font:14px/1.6 var(--sans);color:var(--ink)"><div style="font-family:var(--serif);font-size:18px;margin-bottom:2px">Just generated — #' + d.design.id + '</div><div style="color:var(--ink-soft);font-size:12px"><span style="display:inline-block;width:10px;height:10px;border-radius:50%;background:' + d.design.dominant_hex + ';vertical-align:middle;margin-right:4px"></span>' + d.design.dominant_hex + ' · ' + pick[0] + ' · ' + motif + '</div><a href="/design/' + d.design.id + '" style="display:inline-block;margin-top:10px;color:var(--ink);text-decoration:none;border-bottom:1px solid var(--gold)">View design →</a></div></div>';
+          } else {
+            box.innerHTML = '<div style="color:#b03a2e">Generation failed: ' + (j.error || JSON.stringify(j).slice(0,200)) + '</div>';
+          }
+        } catch (e) {
+          box.innerHTML = '<div style="color:#b03a2e">Error: ' + e.message + '</div>';
+        }
+        btn.disabled = false; btn.textContent = orig;
+      });
+    })();
+    </script>
     ${isAdmin ? `<div class="export-links">
       <a href="/moodboard">Moodboard →</a>
       <span style="color:#444">·</span>
diff --git a/src/admin.js b/src/admin.js
index d6ca583..58bc01e 100644
--- a/src/admin.js
+++ b/src/admin.js
@@ -19,8 +19,12 @@
 'use strict';
 const { execSync } = require('child_process');
 
+const PSQL_CMD = (process.platform === 'linux')
+  ? `sudo -n -u postgres psql dw_unified -At -q`
+  : `psql dw_unified -At -q`;
+
 function psql(sql) {
-  return execSync(`psql dw_unified -At -q`, { input: sql, encoding: 'utf8' }).trim();
+  return execSync(PSQL_CMD, { input: sql, encoding: 'utf8' }).trim();
 }
 function esc(s) { if (s == null) return 'NULL'; return "'" + String(s).replace(/'/g, "''") + "'"; }
 

← 525d067 width slider: offer 24/36/52 on every design + samples form,  ·  back to Wallco Ai  ·  fix(kamatera): wrap psql with sudo -u postgres on Linux 4bb293e →