Que fait daily-card · Générateur de cartes sociales ?
En une phrase
Entrez titre + sous-titre → obtenez un PNG : la date du jour, des stickers vectoriels en rapport avec le sujet et une palette de couleurs harmonieuse sont automatiquement ajoutés. Rendu local, texte chinois 100 % maîtrisé, résultats reproductibles avec les mêmes paramètres.
Ce dépôt est lui-même un répertoire de skill : le répertoire contenant ce SKILL.md est la racine du projet. Le code, les modèles de configuration et la documentation sont au même niveau. Il peut être placé dans les chemins de skills de WorkBuddy / Claude Code / Codex CLI, ou importé depuis GitHub par une plateforme de type skillhub.
Installation et emplacement
Racine du projet = répertoire contenant ce SKILL.md. Peut être placé n'importe où : le code utilise __file__ pour se localiser, pas de chemin absolu.
cd /path/to/daily-card # Remplacez par l'emplacement réel
python3 -m pip install -r requirements.txt
./install.sh # Installation idempotente : dépendances, initialisation config privée, auto-vérification
./scripts/selfcheck.sh # Auto-vérification ultérieure (également point d'entrée CI)
Pas besoin de réseau, pas d'interface IA, pas de clé API. Police chinoise détectée automatiquement : macOS utilise Hiragino Sans GB / PingFang, Linux utilise Noto Sans CJK, Windows utilise Microsoft YaHei ; si aucune n'est trouvée, le programme s'arrête en invitant à spécifier un fichier de police avec --font / --font-bold.
L'agent utilise en priorité la CLI locale, pas besoin de lancer de service. Le serveur web et l'API distante sont des backends optionnels, voir « Deux backends optionnels ».
Utilisation principale : génération en ligne de commande (priorité agent)
python3 cardgen.py "Profite bien de la vie" "Rends les jours ordinaires un peu plus brillants"
La commande affiche le chemin complet Fichier : ... ; présentez ce chemin PNG à l'utilisateur via present_files et expliquez le thème et les dimensions dans la réponse. Répertoire de sortie par défaut output/, nom du fichier <titre>-<date>-<plateforme>.png.
Paramètres courants
| Paramètre | Rôle | Exemple |
|---|---|---|
-t / -s | Titre / Sous-titre | -t "Bonjour" -s "Se lever d'abord" |
--platform | Préréglage de dimensions | xhs(1080×1440) / moments(1080×1080) / wechat(900×500) / story(1080×1920) / wechat2(1080×460) |
--theme | Forcer un thème, par défaut détection automatique par mots-clés | --theme study |
--date | Spécifier une date | --date 2026-01-01 |
--brand | Marque en bas de carte | --brand "Claw · Citation du jour" |
--out | Spécifier le chemin de sortie | --out /tmp/carte.png |
--seed | Graine aléatoire de composition, même graine = même composition | --seed 42 |
--bg-image | Image de fond personnalisée (extraction automatique des couleurs) | --bg-image ./bg.jpg |
--bg-scheme | Choisir la N-ième palette de couleurs de l'image, ou une couleur personnalisée | --bg-scheme 2 / --bg-scheme "#C2185B" |
--list-schemes | Afficher les palettes candidates de l'image de fond au format JSON | python3 cardgen.py --bg-image bg.jpg --list-schemes |
--list-themes | Lister tous les thèmes et stickers | |
--config-dir | Utiliser un autre répertoire de configuration | |
--init-config | Reconstruire config/themes.json à partir du modèle d'usine (écrase les thèmes privés, sauvegardez d'abord) |
Processus complet d'extraction des couleurs d'une image de fond
# 1. Voir les palettes extractibles de l'image (retourne JSON : name / base / colors / ratio)
python3 cardgen.py --bg-image ./bg.jpg --list-schemes
# 2. Choisir une palette pour générer (0 est la couleur principale, 1/2/3 sont secondaires ; on peut aussi donner directement #RRGGBB)
python3 cardgen.py "Le crépuscule est la réponse du jour à la nuit" "Merci pour aujourd'hui" \
--bg-image ./bg.jpg --bg-scheme 2 --platform xhs
Les couleurs (fond, texte, accent, carte, stickers) sont toutes dérivées de la palette choisie, donc les couleurs des stickers sont forcément dans la même gamme que l'image ; le type de sticker reste automatiquement attribué en fonction du thème du titre.
Fichiers de configuration (modifiez la configuration, pas le code)
| Fichier | Contenu | Versionné ? |
|---|---|---|
config/themes.default.json | Modèle d'usine, 11 thèmes, lecture seule, pour « rétablir les valeurs par défaut » | Oui |
config/stickers.json | 28 stickers (nom chinois / groupe) + registre de 6 motifs de fond (avec description sémantique desc) | Oui |
config/themes.json | Configuration réellement utilisée des thèmes : label, keywords, 10 couleurs, motif, stickers, dark | Non, données privées |
config/settings.json | Plateforme par défaut, marque, facteur de suréchantillonnage, intensité du grain, répertoire de sortie, numéro de palette par défaut | Non, données privées |
themes.json et settings.json sont des données privées de l'utilisateur, pas versionnées, pas publiées avec le dépôt public. Au premier lancement, cardconfig.ensure_config() les crée automatiquement à partir du modèle d'usine, pas besoin de création manuelle. Pour utiliser un autre répertoire de configuration, utilisez la variable d'environnement DAILY_CARD_CONFIG ou --config-dir. Voir config/README.md.
11 thèmes intégrés : study morning night coffee sport nature mood work tech festival quote.
Pour modifier les couleurs/stickers : éditez directement config/themes.json (couleurs / stickers / keywords du thème concerné), ou via l'API du backend. Le script relit la configuration à chaque exécution, les modifications sont prises en compte immédiatement. Pour ajouter un nouveau thème, incluez les 10 clés de couleur (#RRGGBB) et au moins un ID de sticker valide. Comme ce fichier est privé, les modifications n'apparaîtront pas dans git status. Sauvegardez-le manuellement si besoin.
Deux backends optionnels
| Backend | Quand ? | Activation |
|---|---|---|
| Aucun (par défaut) | Utilisez simplement la CLI pour générer des cartes | Ne rien faire, exécutez python3 cardgen.py ... |
| Serveur web local (mode autonome) | Interface graphique, aperçu en temps réel, modification visuelle des thèmes | python3 server.py (héberge page et API, interface sur http://127.0.0.1:8777) |
| Serveur distant (mode API uniquement) | Partage en équipe, agent nécessite un endpoint stable | python3 server.py --api-only + proxy nginx (sous-chemin), définir DAILY_CARD_URL |
En mode --api-only, le backend ne répond qu'aux /api/* (le statique est servi par nginx), /api/reveal retourne 403 ; GET /api/health affiche version / mode / serves_static / config_dir, utile pour vérifier la version en ligne.
La CLI s'exécute toujours sur la machine appelante, indépendamment du backend. Ne pas appeler /api/* si aucun service n'est démarré, cela échouera.
Serveur web local (configuration visuelle + aperçu en temps réel)
python3 server.py # http://127.0.0.1:8777 (mode autonome)
python3 server.py --port 9000 --open
python3 server.py --api-only # Déploiement cloud : API uniquement, statique géré par nginx
# macOS : double-cliquez aussi sur start-server.command
Trois panneaux : Conception de carte (formulaire + aperçu en temps réel + téléchargement/sauvegarde), Configuration des thèmes (modification visuelle des couleurs/stickers/mots-clés et écriture dans le JSON), Paramètres globaux (valeurs par défaut et paramètres de rendu). Les onglets sont accessibles via #design / #config / #settings (liens profonds).
Le panneau de configuration des thèmes est en trois colonnes : liste des thèmes / éditeur / aperçu en temps réel. Lorsque vous modifiez une couleur, un motif de fond, l'option sombre ou les stickers, la colonne de droite affiche immédiatement un aperçu non sauvegardé de l'effet, incluant la vraie carte, le diagramme sémantique des couleurs (indiquant où chacune des 10 couleurs est utilisée, l'apparence réelle du motif actuel), l'apparence des stickers avec cette palette, et un diagnostic de contraste/conformité WCAG. L'aperçu est en mémoire en lecture seule, n'écrit pas dans config/themes.json. Cliquez sur « Sauvegarder la configuration » pour écrire sur le disque.
Déploiement sur un sous-chemin de domaine (serveur cloud)
Toutes les URL du frontend sont dérivées du BASE défini par web/app.js en runtime (document.baseURI), le code source n'a pas de racine de domaine en dur ; index.html utilise des chemins relatifs pour style.css / app.js. Pour pointer l'API vers un domaine différent, définissez window.DAILY_CARD_BASE avant de charger app.js. nginx se charge de retirer le préfixe /daily-card/api/* pour le transformer en /api/*, aucune modification du routage backend n'est nécessaire.
| Commande | Rôle |
|---|---|
./scripts/publish-web.sh | Publier web/ dans un répertoire de version et basculer atomiquement le lien symbolique current |
./scripts/publish-web.sh --list | Voir les versions publiées et la version courante |
./scripts/publish-web.sh --rollback [ver] | Retour instantané, sans redémarrer Python |
./scripts/test_subpath.py | Simulation in-process du retrait de préfixe par nginx, 10 assertions de chaîne |
Les versions statiques du frontend peuvent être publiées et annulées indépendamment du backend. Utilisez DAILY_CARD_WEB_ROOT (par défaut /opt/daily-card-web) et DAILY_CARD_WEB_KEEP (par défaut 5) pour les surcharger. La barre oblique finale est obligatoire : /daily-card doit rediriger (301) vers /daily-card/, sinon les chemins relatifs pointeront vers la racine du domaine. Voir docs/DEPLOY.md pour la configuration nginx complète, systemd, cache et authentification.
Lorsque l'agent appelle une interface distante, DAILY_CARD_URL doit être défini jusqu'au préfixe inclus, par exemple https://host/daily-card, le code construira https://host/daily-card/api/save ; ne pas mettre de nom de domaine nu.
Interface JSON (appelable directement par l'agent, sans navigateur)
| Interface | Description |
|---|---|
GET /api/health | Vérification de santé : version, mode d'exécution, répertoire de configuration (pas besoin de lancer le frontend) |
GET /api/bootstrap | Obtenir en une fois themes_doc / settings / registry / platforms / chemin |
POST /api/render | Générer un aperçu, retourne {png: dataURL, path, theme, size, bytes} |
POST /api/save | Générer et écrire dans output/, retourne le chemin |
POST /api/theme-preview | Brouillon de thème non sauvegardé → carte + diagramme sémantique + stickers + diagnostic de lisibilité, n'écrit pas le fichier de configuration |
POST /api/schemes | Image de fond → plusieurs palettes. Envoyer {"path":"/abs/bg.jpg"} ou {"image":"data:image/png;base64,..."} |
GET /api/schemes?image_id=xxx | Récupérer les palettes d'une image déjà téléchargée |
POST /api/config/themes | {"themes_doc": {...}} Sauvegarder la configuration des thèmes (avec validation) |
POST /api/config/settings | {"settings": {...}} Sauvegarder les paramètres globaux |
POST /api/config/reset | Restaurer les thèmes d'usine (écrase les thèmes privés, sauvegardez d'abord) |
POST /api/reveal | Ouvrir le dossier de sortie |
GET /api/sticker?id=book&theme=study | Icône de sticker PNG |
Corps de requête pour /api/render et /api/save :
{
"title": "Profite bien de la vie",
"subtitle": "Rends les jours ordinaires un peu plus brillants",
"platform": "xhs",
"theme": "auto",
"date": null,
"brand": "Claw · Citation du jour",
"seed": null,
"bg_image_id": null,
"bg_path": "./bg.jpg",
"bg_scheme": 0,
"dark_override": null
}
bg_schemepeut être un index entier ou#RRGGBB;dark_override=true/falseforce la carte claire/sombre,nullsuit l'image.bg_image_idest retourné par/api/schemes; on peut aussi donner directementbg_pathaccessible par le serveur.- Le
pngretourné estdata:image/png;base64,..., à décoder pour écrire le fichier.
Exemple (quand DAILY_CARD_URL n'est pas défini, utilise localhost) :
DC_URL="${DAILY_CARD_URL:-http://127.0.0.1:8777}"
curl -s "$DC_URL/api/save" \
-H 'Content-Type: application/json' \
-d '{"title":"Profite bien de la vie","subtitle":"Rends les jours ordinaires un peu plus brillants","platform":"xhs"}' \
| python3 -c 'import json,sys; print(json.load(sys.stdin)["path"])'
Aperçu du brouillon de thème / diagnostic de palette (inspectez avant de sauvegarder)
Pour juger si une palette est belle et le texte lisible avant de l'écrire dans la configuration, appelez /api/theme-preview. theme est un brouillon complet de thème, le serveur le garde uniquement en mémoire :
{
"theme": {
"label": "MON THÈME · Nouveau thème",
"keywords": ["check-in"],
"motif": "dots",
"dark": false,
"colors": {
"bg1": "#F7E9C8", "bg2": "#EED6A4", "card": "#FFFCF6",
"ink": "#2E3A2C", "sub": "#6D7570", "accent": "#E0703C",
"accent2": "#5D8B6A", "soft": "#F1D9A8", "pill": "#2E3A2C",
"pill_text": "#FFFDF5"
},
"stickers": ["book", "pencil", "sun"]
},
"title": "Titre exemple",
"subtitle": "Sous-titre exemple",
"platform": "moments",
"date": "2026-11-11",
"seed": 7
}
Champs retournés (card / legend / stickers / sticker_sheet sont tous des data:image/png;base64,...) :
| Champ | Signification |
|---|---|
card | Carte rendue avec ce brouillon |
legend | Diagramme sémantique des couleurs : motif réel + hiérarchie de la carte + rôle de chaque couleur |
stickers | Apparence des stickers sélectionnés avec la palette courante |
sticker_sheet | Sprite complet des stickers, avec sheet (cols/rows/cell/order) pour le découpage |
diagnostics | [{level: ok/warn/tip, text: explication en chinois}] |
contrast | Valeurs de contraste (ink_card / sub_card / pill_pair / card_bg / accent_bg / bg_light) |
motif / dark / draft_only | Nom du motif, indicateur clair/sombre, toujours true pour non sauvegardé |
diagnostics vérifie le contraste selon WCAG : lisibilité du texte principal/secondaire/étiquette, distinction carte/fond, visibilité de la couleur d'accent, et contradictions comme « fond très sombre défini comme thème clair ». Méthode recommandée : envoyez d'abord le brouillon pour le diagnostic → s'il y a des warn, modifiez les couleurs selon les conseils et réessayez → une fois sans warn, appelez /api/config/themes pour sauvegarder.
Sans démarrer le backend, vous pouvez appeler directement le module :
import base64, cardconfig as cfg, cardpreview as cp
draft = cfg.load_doc()["themes"]["study"] # Structure imbriquée, contient colors
draft["colors"]["accent"] = "#C2185B" # Modifions pour voir
r = cp.build_preview({"theme": draft, "title": "Exemple", "subtitle": "Sous-titre"})
for it in r["diagnostics"]:
print(it["level"], it["text"])
open("/tmp/draft-card.png", "wb").write(base64.b64decode(r["card"].split(",", 1)[1]))
Mise à jour et synchronisation multi-postes
La seule source de vérité pour les versions est le dépôt git, tous les autres postes sont des dérivés, flux unidirectionnel :
| Poste | Méthode de mise à jour | Configuration privée |
|---|---|---|
| Machine locale / serveur cloud | git pull && ./install.sh | Non affectée, non écrasée |
| Version statique frontend sur serveur cloud | ./scripts/publish-web.sh, --rollback pour retour instantané | Découplé du service Python, pas de redémarrage |
| Enregistrement du skill sur la machine locale | ./install.sh --link-skill crée un lien symbolique (évite la dérive de copies) | Non affectée |
| Snapshot sur plateforme skillhub, etc. | Le mainteneur crée un tag puis réimporte, décalage de version naturel | La plateforme n'obtient que le modèle d'usine |
Le modèle d'usine themes.default.json est mis à jour avec les versions. Le themes.json privé de l'utilisateur n'est jamais écrasé. Pour fusionner les nouveaux thèmes d'usine dans votre configuration, copiez manuellement les entrées depuis themes.default.json, ou utilisez dans le backend « Exporter JSON → Fusionner → Importer ». N'exécutez pas --init-config / /api/config/reset.
Voir docs/DEPLOY.md pour le déploiement serveur et l'intégration CI/CD. scripts/selfcheck.sh comporte 8 étapes, incluant la vérification de la portabilité des chemins frontend et la simulation de déploiement sur sous-chemin (proxy in-process, pas besoin d'installer nginx).
Workflow recommandé pour l'agent
- À partir des paroles de l'utilisateur, extraire le titre et le sous-titre (si pas de sous-titre, en ajouter un court et pertinent, ou laisser vide).
- Déterminer la plateforme : si non précisée, utiliser
xhs; si mentionné « article WeChat » utiliserwechat, « Moments » utilisermoments. - Si l'utilisateur fournit une image de fond : d'abord
--list-schemesou/api/schemespour voir les candidates, puis utiliser la sélectionnée ; si non précisé, utiliser le schéma 0. - Exécuter la CLI (pas besoin de service) ; n'appeler
/api/saveque si l'utilisateur demande explicitement un backend/accès distant. - Présenter l'image finale avec
present_files, en indiquant dans la réponse le thème, les dimensions, la date et la palette de couleurs. - Si l'utilisateur veut changer le style → modifier
config/themes.jsonou le panneau de configuration du backend, ne pas modifiercardgen.py.
Remarques importantes
- Répartition du code :
cardgen.pyne s'occupe que du rendu,cardconfig.pydu chargement/sauvegarde de la configuration et de l'extraction des couleurs,cardpreview.pyde l'aperçu du brouillon et du diagnostic de palette,server.pyest le backend. Tous lisent les mêmesconfig/*.json. output/,uploads/,config/themes.json,config/settings.json,.envsont ignorés par.gitignore;examples/contient des démos (environ 6.7 Mo, non nécessaires au fonctionnement, peuvent être supprimés à tout moment).- Les ID de thème acceptent uniquement les lettres, chiffres,
-,_; les couleurs doivent être en#RRGGBB; les ID de stickers doivent exister dansconfig/stickers.json. - Plus l'image est grande et le suréchantillonnage élevé, plus c'est lent ; le suréchantillonnage 2x par défaut est suffisamment net.
server.pyn'a aucune authentification et écoute par défaut seulement127.0.0.1. Avant un déploiement public, ajoutez une authentification par proxy inverse ou une liste blanche IP ; pour le cloud, utilisez--api-onlypour exposer uniquement l'API, voirdocs/DEPLOY.md.- Le code source ne doit pas contenir de chemins absolus comme
src="/..."/href="/..."/"/api/...";selfcheck.shbloque ces régressions ; toutes les requêtes passent parurl().
Limitations connues / Plan pour la prochaine version
- Pas de téléchargement personnalisé de stickers (version actuelle) : les stickers sont limités aux 28 stickers vectoriels enregistrés dans
config/stickers.json. Il n'y a pas de module de gestion de bibliothèque de stickers indépendant, et le téléchargement de PNG/SVG comme sticker n'est pas supporté. Pour ajouter une forme, le développeur doit actuellement ajouter une fonction de dessins_xxxdanscardgen.pyet l'enregistrer dansstickers.json. - Plan pour la prochaine version : téléchargement personnalisé de stickers (PNG/SVG, avec adaptation automatique des couleurs au thème), panneau de gestion de bibliothèque de stickers (ajout/suppression/modification / regroupement / aperçu / réutilisation), découplage stickers/thèmes. L'utilisateur a clairement indiqué que cette fonctionnalité est repoussée à la prochaine version, non implémentée ici.
- L'aperçu du brouillon de thème utilise un suréchantillonnage 1x pour accélérer la réponse, légèrement différent du rendu final 2x pour les détails les plus fins, mais la mise en page et les couleurs sont les mêmes.