[object Object]

← back to Wallco Ai

drunk-animals: dedicated motif tagger w/ animal+pose+plant+style vocab

d5ea5adc572147ea03dbd0e79667f5556f771316 · 2026-05-12 19:35:39 -0700 · SteveStudio2

Generic tag_motifs.py prompt covers floral/damask/geometric vocab.
Drunk-animal designs would only get 'tropical / palm / dense' tags
from that pool. New script feeds llava a category-specific prompt
listing animal species (frog/elephant/giraffe/orangutan/...),
poses (drunk/dancing/sleeping/...), props (cocktail/martini/...),
plants (monstera/fern/...), and styles (warhol/silkscreen/...)
so /designs?motif=frog etc. actually returns frogs.

Background tag run kicked at start of this tick — 43 designs.

Files touched

Diff

commit d5ea5adc572147ea03dbd0e79667f5556f771316
Author: SteveStudio2 <stevestudio2@SteveStacStudio.lan>
Date:   Tue May 12 19:35:39 2026 -0700

    drunk-animals: dedicated motif tagger w/ animal+pose+plant+style vocab
    
    Generic tag_motifs.py prompt covers floral/damask/geometric vocab.
    Drunk-animal designs would only get 'tropical / palm / dense' tags
    from that pool. New script feeds llava a category-specific prompt
    listing animal species (frog/elephant/giraffe/orangutan/...),
    poses (drunk/dancing/sleeping/...), props (cocktail/martini/...),
    plants (monstera/fern/...), and styles (warhol/silkscreen/...)
    so /designs?motif=frog etc. actually returns frogs.
    
    Background tag run kicked at start of this tick — 43 designs.
---
 scripts/tag_drunk_animal_motifs.py | 107 +++++++++++++++++++++++++++++++++++++
 1 file changed, 107 insertions(+)

diff --git a/scripts/tag_drunk_animal_motifs.py b/scripts/tag_drunk_animal_motifs.py
new file mode 100644
index 0000000..7d967b4
--- /dev/null
+++ b/scripts/tag_drunk_animal_motifs.py
@@ -0,0 +1,107 @@
+#!/usr/bin/env python3
+"""
+Drunk-animal motif tagger — runs llava on local Ollama against every
+spoon_all_designs row where category='drunk-animals' and motifs IS NULL.
+
+Uses a drunk-animal-aware prompt vocabulary (frog/elephant/giraffe/orangutan/
+jungle/cocktail/etc.) so the tags actually match the prompt aesthetic, rather
+than the generic floral/damask vocabulary in tag_motifs.py.
+
+Free (local Ollama). ~10-15s per image. Idempotent — skips already-tagged rows.
+
+Usage:  python3 scripts/tag_drunk_animal_motifs.py [limit]
+"""
+import base64, json, subprocess, time, sys
+from pathlib import Path
+import urllib.request
+
+OLLAMA = 'http://127.0.0.1:11434'
+MODEL  = 'llava:latest'
+
+PROMPT = """Look at this wallpaper pattern image. It probably shows a drunk
+animal in a forest, in a Warhol-style botanical-pop aesthetic. Extract 3 to 6
+concrete tags describing what you see.
+
+Pick from this vocabulary (or invent similar single-word tags):
+  ANIMALS: frog, elephant, giraffe, orangutan, capybara, lemur, sloth,
+           macaw, panda, peacock, parrot, monkey, snake
+  POSE:    drunk, tipsy, dancing, sleeping, hiccup, swaying, dancing,
+           passed-out, smiling, drinking, holding-glass
+  PROPS:   cocktail, martini, wine, champagne, umbrella, glass, bottle, bubbles
+  PLANTS:  monstera, fern, banana-leaf, palm, philodendron, vine, bromeliad,
+           orchid, lily, flower, jungle, forest, leaves
+  STYLE:   warhol, pop-art, silkscreen, halftone, neon, bright, primary-colors,
+           4-panel, color-swap, screen-print, bold, flat, outlined
+
+Return ONLY a JSON array of 3-6 lowercase tag strings. No commentary. No code fences.
+"""
+
+def psql(sql):
+    r = subprocess.run(['psql','dw_unified','-At','-q'], input=sql, capture_output=True, text=True)
+    if r.returncode != 0: raise RuntimeError(r.stderr)
+    return r.stdout.strip()
+
+def esc(s):
+    if s is None: return 'NULL'
+    return "'" + str(s).replace("'", "''") + "'"
+
+def tag_one(image_path):
+    img_b64 = base64.b64encode(Path(image_path).read_bytes()).decode()
+    body = json.dumps({
+        'model': MODEL,
+        'prompt': PROMPT,
+        'images': [img_b64],
+        'stream': False,
+        'options': { 'temperature': 0.2 }
+    }).encode()
+    req = urllib.request.Request(f'{OLLAMA}/api/generate',
+        data=body, headers={'Content-Type': 'application/json'})
+    with urllib.request.urlopen(req, timeout=120) as r:
+        out = json.loads(r.read())
+    text = (out.get('response') or '').strip()
+    import re
+    m = re.search(r'\[[^\]]+\]', text)
+    if not m: return []
+    try:
+        tags = json.loads(m.group(0))
+        if not isinstance(tags, list): return []
+        return [str(t).lower().strip()[:30] for t in tags if t][:6]
+    except Exception:
+        return []
+
+def main():
+    limit = int(sys.argv[1]) if len(sys.argv) > 1 else 50
+    rows = json.loads(psql(
+        f"SELECT COALESCE(json_agg(t),'[]'::json) FROM (SELECT id, local_path "
+        f"FROM spoon_all_designs "
+        f"WHERE category='drunk-animals' AND local_path IS NOT NULL "
+        f"AND (motifs IS NULL OR array_length(motifs,1) IS NULL) "
+        f"ORDER BY id LIMIT {limit}) t;") or '[]')
+    print(f'{len(rows)} drunk-animal designs pending motif tags')
+    sql_lines = ['BEGIN;']
+    ok = 0
+    for i, r in enumerate(rows, 1):
+        p = Path(r['local_path'])
+        if not p.exists():
+            print(f'  [{i}/{len(rows)}] missing file: {r["local_path"]}')
+            continue
+        try:
+            t0 = time.time()
+            tags = tag_one(p)
+            took = time.time() - t0
+            if tags:
+                arr = "ARRAY[" + ",".join(esc(x) for x in tags) + "]::text[]"
+                sql_lines.append(f"UPDATE spoon_all_designs SET motifs={arr} WHERE id={r['id']};")
+                print(f'  [{i:>3}/{len(rows)}] #{r["id"]:<4} ({took:.1f}s) → {tags}')
+                ok += 1
+            else:
+                print(f'  [{i:>3}/{len(rows)}] #{r["id"]:<4} no tags returned')
+        except Exception as e:
+            print(f'  [{i:>3}/{len(rows)}] #{r["id"]:<4} err: {e}')
+    sql_lines.append('COMMIT;')
+    Path('/tmp/dad_motifs.sql').write_text('\n'.join(sql_lines))
+    subprocess.run(['psql','dw_unified','-q','-f','/tmp/dad_motifs.sql'], check=True)
+    print(f'\nTagged {ok}/{len(rows)}')
+
+if __name__ == '__main__':
+    main()

← a5f9d55 drunk-animals: category-aware titler (Hiccup/Tipple/Tableau/  ·  back to Wallco Ai  ·  drunk-animals: /drunk-animals friendly URL → 302 to /designs 1370963 →