From odoo-content-toolkit
Generate eye-catching course cover images using HTML/CSS + Puppeteer (primary) or Gemini Flash (fallback), and upload to Odoo 18 slide.channel via XML-RPC.
How this skill is triggered — by the user, by Claude, or both
Slash command
/odoo-content-toolkit:lesson-thumbnailThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
Generuje vizualne poutave cover image pro e-learning kurzy (slide.channel).
Generuje vizualne poutave cover image pro e-learning kurzy (slide.channel). Primarni metoda: HTML/CSS design renderovany pres Puppeteer do PNG. Fallback: Gemini Flash AI image generation.
Thumbnail se generuje na KURZ (slide.channel), NE na jednotlive lekce!
slide.channel.image_1920 = cover obrazek kurzu (videt na /slides)slide.slide.image_1920 = thumbnail lekce (volitelne, videt uvnitr kurzu)Kazdy kurz MUSI mit unikatni cover image aby se odlisil od ostatnich.
DULEZITE: Thumbnail NESMI byt vizualne chaby! Uzivatel ho nesmi mit depresi jen z pohledu.
+-------------------------------------------------------+
| [orby + gradient pozadi] |
| |
| [badge] E-LEARNING COURSE |
| [editor mockup]
| VELKY TITLE |requirements |
| GRADIENT TEXT | ## Stories |
| mensi podtitul | GIVEN/WHEN |
| | THEN... |
| Subtitle popis kurzu |
| [plovouci |
| [pill 1] > [pill 2] > [pill 3] karty] |
| |
+-------------------------------------------------------+
/* Glowing orb — POUZIVEJ 0.3-0.5 opacitu, ne 0.05! */
.orb {
position: absolute;
border-radius: 50%;
filter: blur(80px);
}
.orb1 { width: 500px; height: 500px; background: rgba(168, 85, 247, 0.5); }
/* Gradient text — pro zvyrazneni klicoveho slova */
.gradient-text {
background: linear-gradient(135deg, #c084fc 0%, #22d3ee 50%, #34d399 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
/* 3D editor mockup — perspective transform */
.editor {
transform: perspective(1200px) rotateY(-8deg) rotateX(3deg);
box-shadow: 0 0 60px rgba(124, 58, 237, 0.25), 0 25px 80px rgba(0,0,0,0.5);
border: 1px solid rgba(255,255,255,0.12);
background: rgba(15, 15, 30, 0.85);
}
/* Glass card */
.card {
background: rgba(255,255,255,0.07);
border: 1px solid rgba(255,255,255,0.15);
border-radius: 14px;
backdrop-filter: blur(20px);
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
}
/* Workflow pills — kazdy jina barva */
.pill { padding: 14px 24px; border-radius: 14px; font-weight: 700; }
.pill.p1 { background: rgba(168, 85, 247, 0.25); }
.pill.p2 { background: rgba(59, 130, 246, 0.25); }
.pill.p3 { background: rgba(6, 182, 212, 0.25); }
.pill.p4 { background: rgba(34, 197, 94, 0.25); }
| Tema kurzu | Primarni orby | Gradient text | Pills |
|---|---|---|---|
| AI/Coding | purple + cyan + pink | purple→cyan→green | purple, blue, cyan, green |
| Business/CRM | blue + amber + green | blue→amber | blue, amber, green, teal |
| DevOps/Infra | orange + red + blue | orange→red→purple | orange, red, blue, green |
| Security | red + purple + dark | red→purple | red, purple, slate, emerald |
| Design/UI | pink + violet + blue | pink→violet→blue | pink, violet, blue, cyan |
| Data/DB | emerald + cyan + blue | emerald→cyan | emerald, cyan, blue, indigo |
const puppeteer = require('puppeteer');
const path = require('path');
(async () => {
const browser = await puppeteer.launch({
headless: 'new',
executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome',
});
const page = await browser.newPage();
await page.setViewport({ width: 1920, height: 1080, deviceScaleFactor: 1 });
const htmlPath = path.resolve(__dirname, 'thumbnail.html');
await page.goto(`file://${htmlPath}`, { waitUntil: 'networkidle0' });
const outPath = path.resolve(__dirname, 'thumbnail.png');
await page.screenshot({ path: outPath, type: 'png' });
console.log(`Saved: ${outPath}`);
await browser.close();
})();
Pozadavky:
npm install puppeteer v projektu startbusiness)/Applications/Google Chrome.app/Contents/MacOS/Google Chrome)import base64
with open('thumbnail.png', 'rb') as f:
image_b64 = base64.b64encode(f.read()).decode('utf-8')
call('slide.channel', 'write', [[channel_id], {'image_1920': image_b64}])
Pro kazdy kurz vytvor adresar kurzy/{course_slug}/ s:
thumbnail.html — HTML/CSS designrender_thumbnail.js — Puppeteer rendererupload_thumbnail.py — upload do Odoothumbnail.png — renderovany vysledekThumbnail generovani a upload pridej PRIMO do hlavniho exec.py skriptu kurzu
(za vytvoreni channelu, pred finalni summary):
import subprocess
import base64
# ... po vytvoreni channel_id ...
# Generate thumbnail
print("Generating thumbnail...")
thumbnail_dir = os.path.dirname(os.path.abspath(__file__))
subprocess.run(['node', os.path.join(thumbnail_dir, 'render_thumbnail.js')], check=True)
# Upload thumbnail
with open(os.path.join(thumbnail_dir, 'thumbnail.png'), 'rb') as f:
image_b64 = base64.b64encode(f.read()).decode('utf-8')
call('slide.channel', 'write', [[channel_id], {'image_1920': image_b64}])
print(f" Thumbnail uploaded to channel {channel_id}")
Pouzij kdyz HTML/CSS neni mozne (napr. potrebujes realisticke ilustrace).
GEMINI_API_KEY — Google Gemini API keygoogle-genai (NE google-generativeai — deprecated!)Create a bold, eye-catching course cover image.
Theme: {course_topic_summary}
Visual: {specific_visual_metaphors_and_icons}
Colors: {unique_gradient_palette} background.
Style: Modern flat illustration, clean vector art, vibrant colors.
Do NOT include any text, words, letters, numbers, or watermarks.
from google import genai
from google.genai import types
client = genai.Client(api_key=os.environ.get('GEMINI_API_KEY'))
response = client.models.generate_content(
model="gemini-2.5-flash-image",
contents=prompt,
config=types.GenerateContentConfig(response_modalities=["IMAGE"]),
)
image_data = None
for part in response.candidates[0].content.parts:
if part.inline_data is not None:
image_data = part.inline_data.data
break
image_b64 = base64.b64encode(image_data).decode('utf-8')
Modely (v poradi stability):
gemini-2.5-flash-image — osvedceny, stabilnigemini-3.1-flash-image-preview — nejnovejsigemini-3-pro-image-preview — nejvyssi kvalitaNEFUNGUJE: gemini-2.0-flash-exp-image-generation — 404
image_1920 field pro base64 uploadexecutablePath pro lokalniho Chromenpx claudepluginhub michalvarys/claude-plugins --plugin odoo-content-toolkitCreates, edits, and optimizes skills for Claude Code, including drafting, evaluating with test prompts, iterating on performance, and improving skill descriptions for better triggering accuracy.