prompt-artist
Optimize and generate text-to-image prompts for AI art platforms. Use when a user wants to: (1) Optimize prompts for Midjourney, Nano Banana, Dreamina, Qwen image generation, (2) Translate simple descriptions into professional prompts, (3) Generate platform-specific prompt variations, (4) Add style/lighting/composition modifiers, (5) Create negative prompts. Supports Chinese/English input. Integrates SkillPay.me at 0.005 USDT/call.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install openclaw-skills-prompt-artist
Repository
Skill path: skills/elevo11/prompt-artist
Optimize and generate text-to-image prompts for AI art platforms. Use when a user wants to: (1) Optimize prompts for Midjourney, Nano Banana, Dreamina, Qwen image generation, (2) Translate simple descriptions into professional prompts, (3) Generate platform-specific prompt variations, (4) Add style/lighting/composition modifiers, (5) Create negative prompts. Supports Chinese/English input. Integrates SkillPay.me at 0.005 USDT/call.
Open repositoryBest for
Primary workflow: Analyze Data & AI.
Technical facets: Full Stack, Data / AI.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: openclaw.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install prompt-artist into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/openclaw/skills before adding prompt-artist to shared team environments
- Use prompt-artist for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: prompt-artist
description: >
Optimize and generate text-to-image prompts for AI art platforms. Use when a user wants to:
(1) Optimize prompts for Midjourney, Nano Banana, Dreamina, Qwen image generation,
(2) Translate simple descriptions into professional prompts, (3) Generate platform-specific
prompt variations, (4) Add style/lighting/composition modifiers, (5) Create negative prompts.
Supports Chinese/English input. Integrates SkillPay.me at 0.005 USDT/call.
---
# Prompt Artist
AI art prompt optimizer for Midjourney, Nano Banana, Dreamina, Qwen. 0.005 USDT/call.
## Commands
| Command | Script | Description |
|:---|:---|:---|
| **optimize** | `scripts/optimize.py` | Optimize a prompt for target platform |
| **multi** | `scripts/multi_platform.py` | Generate prompts for all platforms at once |
| **style** | `scripts/style_library.py` | Browse/apply art styles |
| **history** | `scripts/history.py` | Prompt history + favorites (NEW) |
| **billing** | `scripts/billing.py` | SkillPay charge/balance/payment |
## Workflow
```
1. Billing: python3 scripts/billing.py --charge --user-id <id>
2. Optimize: python3 scripts/optimize.py --prompt "一只猫在月光下" --platform midjourney
3. Multi: python3 scripts/multi_platform.py --prompt "sunset over mountains"
4. Styles: python3 scripts/style_library.py --list
```
## Examples
```bash
# Optimize for Midjourney
python3 scripts/optimize.py --prompt "一只猫在月光下" --platform midjourney --style cinematic
# Optimize for Dreamina
python3 scripts/optimize.py --prompt "cyberpunk city" --platform dreamina --ratio 16:9
# All platforms at once
python3 scripts/multi_platform.py --prompt "beautiful girl in garden" --style anime
# List styles
python3 scripts/style_library.py --list
python3 scripts/style_library.py --category photography
```
## Config
| Env Var | Required | Description |
|:---|:---:|:---|
| `SKILLPAY_API_KEY` | Yes | SkillPay.me API key |
## References
See `references/platform-specs.md` for platform-specific prompt syntax and limits.
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### scripts/billing.py
```python
#!/usr/bin/env python3
"""SkillPay.me billing for prompt-artist."""
import json, sys, argparse, os
import urllib.request, urllib.error
API = "https://skillpay.me/api/v1"
SKILL_ID = "66a1cf1e-9177-4fd9-a417-8917978118e3"
def _key(o=None):
return o or os.environ.get("SKILLPAY_API_KEY")
def _post(path, body, key):
req = urllib.request.Request(f"{API}{path}", data=json.dumps(body).encode(),
headers={"Content-Type": "application/json", "X-API-Key": key}, method="POST")
try:
with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read())
except urllib.error.HTTPError as e: return json.loads(e.read())
def _get(path, key):
req = urllib.request.Request(f"{API}{path}", headers={"X-API-Key": key})
try:
with urllib.request.urlopen(req, timeout=15) as r: return json.loads(r.read())
except urllib.error.HTTPError as e: return json.loads(e.read())
def charge(uid, amount=0.005, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
d = _post("/billing/charge", {"user_id": uid, "skill_id": SKILL_ID, "amount": amount,
"currency": "USDT", "description": "Prompt Artist"}, k)
if d.get("success"): return {"success": True, "charged": amount, "data": d}
return {"success": False, "needs_payment": bool(d.get("payment_url")),
"payment_url": d.get("payment_url", ""), "balance": d.get("balance", 0),
"message": d.get("message", "charge failed")}
def balance(uid, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
return {"success": True, "data": _get(f"/billing/balance?user_id={uid}", k)}
def payment_link(uid, amount=5.0, key=None):
k = _key(key)
if not k: return {"success": False, "error": "SKILLPAY_API_KEY not set"}
return {"success": True, "data": _post("/billing/payment-link",
{"user_id": uid, "skill_id": SKILL_ID, "Amount": amount}, k)}
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--user-id", required=True)
p.add_argument("--amount", type=float, default=0.005)
p.add_argument("--api-key", default=None)
g = p.add_mutually_exclusive_group()
g.add_argument("--charge", action="store_true", default=True)
g.add_argument("--balance", action="store_true")
g.add_argument("--payment-link", action="store_true")
a = p.parse_args()
if a.balance: r = balance(a.user_id, a.api_key)
elif a.payment_link: r = payment_link(a.user_id, a.amount or 5.0, a.api_key)
else: r = charge(a.user_id, a.amount, a.api_key)
print(json.dumps(r, indent=2, ensure_ascii=False))
sys.exit(0 if r.get("success") else 1)
```
### scripts/optimize.py
```python
#!/usr/bin/env python3
"""Optimize text-to-image prompts for various AI art platforms."""
import argparse, json, sys, re
# Style modifiers library
STYLES = {
"cinematic": "cinematic lighting, dramatic atmosphere, film grain, anamorphic lens, movie still",
"anime": "anime style, cel shading, vibrant colors, detailed eyes, studio ghibli inspired",
"photorealistic": "photorealistic, 8k uhd, DSLR, high detail, sharp focus, professional photography",
"oil_painting": "oil painting, brush strokes, canvas texture, classical art, rich colors, masterpiece",
"watercolor": "watercolor painting, soft edges, color bleeding, paper texture, delicate",
"cyberpunk": "cyberpunk, neon lights, futuristic, rain, holographic, dark atmosphere, blade runner",
"fantasy": "fantasy art, magical, ethereal glow, mystical atmosphere, detailed, epic composition",
"minimalist": "minimalist, clean design, simple composition, negative space, modern aesthetic",
"vintage": "vintage, retro, faded colors, film photography, nostalgic, 1970s aesthetic",
"3d_render": "3D render, octane render, C4D, volumetric lighting, smooth, high quality",
"pixel_art": "pixel art, 16-bit, retro gaming, sprite art, low resolution charm",
"sketch": "pencil sketch, hand drawn, detailed linework, graphite, artistic",
"pop_art": "pop art, Andy Warhol style, bold colors, halftone dots, graphic design",
"surreal": "surrealism, Salvador Dali inspired, dreamlike, impossible geometry, melting",
"ukiyo_e": "ukiyo-e, Japanese woodblock print, traditional art, Hokusai style",
"ink_wash": "Chinese ink wash painting, 水墨画, traditional, elegant, flowing brush strokes",
}
# Quality boosters per platform
QUALITY = {
"midjourney": "masterpiece, best quality, highly detailed, sharp focus, 8k resolution",
"dreamina": "高清, 精细, 大师级, 高质量, 细节丰富",
"nano_banana": "best quality, masterpiece, ultra detailed, high resolution",
"qwen": "高质量, 精美, 细节丰富, 专业级",
}
# Negative prompts per platform
NEGATIVES = {
"midjourney": "--no blurry, low quality, distorted, deformed, ugly, bad anatomy",
"dreamina": "低质量, 模糊, 变形, 丑陋, 解剖错误",
"nano_banana": "blurry, low quality, distorted, deformed, bad anatomy, watermark, text",
"qwen": "低质量, 模糊, 变形, 水印, 文字",
}
# Platform-specific formatting
PLATFORM_CONFIG = {
"midjourney": {
"name": "Midjourney",
"icon": "🎨",
"lang": "en",
"max_len": 6000,
"suffix_template": " --ar {ratio} --v 6.1 --q 2",
"tips": ["Use :: for multi-prompts", "Use --ar for aspect ratio", "Use --s for stylize value"],
},
"dreamina": {
"name": "极梦 Dreamina",
"icon": "🌈",
"lang": "zh",
"max_len": 2000,
"suffix_template": "",
"tips": ["支持中英文混合", "可指定画面比例", "使用逗号分隔关键词"],
},
"nano_banana": {
"name": "Nano Banana",
"icon": "🍌",
"lang": "en",
"max_len": 4000,
"suffix_template": "",
"tips": ["Use detailed descriptions", "Separate concepts with commas", "Add quality tags"],
},
"qwen": {
"name": "Qwen",
"icon": "🤖",
"lang": "zh",
"max_len": 2000,
"suffix_template": "",
"tips": ["支持中文自然语言描述", "可添加风格关键词", "描述越详细效果越好"],
},
}
def detect_language(text):
"""Detect if text is primarily Chinese or English."""
chinese_chars = len(re.findall(r'[\u4e00-\u9fff]', text))
return "zh" if chinese_chars > len(text) * 0.3 else "en"
def enhance_prompt(prompt, platform="midjourney", style=None, ratio="1:1", quality=True):
"""Enhance a basic prompt into an optimized one for the target platform."""
config = PLATFORM_CONFIG.get(platform, PLATFORM_CONFIG["midjourney"])
parts = []
# Main prompt
parts.append(prompt.strip())
# Add style
if style and style in STYLES:
parts.append(STYLES[style])
# Add quality boosters
if quality and platform in QUALITY:
parts.append(QUALITY[platform])
# Combine
enhanced = ", ".join(parts)
# Platform-specific suffix
suffix = config["suffix_template"].format(ratio=ratio)
enhanced += suffix
# Truncate if needed
if len(enhanced) > config["max_len"]:
enhanced = enhanced[:config["max_len"] - 3] + "..."
# Negative prompt
negative = NEGATIVES.get(platform, "")
return {
"platform": config["name"],
"icon": config["icon"],
"original": prompt,
"optimized": enhanced,
"negative": negative,
"style": style,
"ratio": ratio,
"length": len(enhanced),
"max_length": config["max_len"],
"tips": config["tips"],
}
def format_output(data):
lines = [f"{data['icon']} {data['platform']} 优化提示词", ""]
lines.append(f"📝 原始: {data['original']}")
lines.append("")
lines.append(f"✨ 优化后:")
lines.append(f"```")
lines.append(data["optimized"])
lines.append(f"```")
if data["negative"]:
lines.append(f"\n🚫 反向提示:")
lines.append(f"```")
lines.append(data["negative"])
lines.append(f"```")
lines.append(f"\n📐 比例: {data['ratio']} | 字数: {data['length']}/{data['max_length']}")
if data["style"]:
lines.append(f"🎨 风格: {data['style']}")
lines.append(f"\n💡 技巧:")
for t in data["tips"]:
lines.append(f" • {t}")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--prompt", required=True, help="Original prompt text")
p.add_argument("--platform", choices=list(PLATFORM_CONFIG.keys()), default="midjourney")
p.add_argument("--style", default=None, help="Art style name")
p.add_argument("--ratio", default="1:1", help="Aspect ratio (e.g. 16:9)")
p.add_argument("--no-quality", action="store_true", help="Skip quality boosters")
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = enhance_prompt(a.prompt, a.platform, a.style, a.ratio, not a.no_quality)
print(json.dumps(data, indent=2, ensure_ascii=False) if a.json else format_output(data))
```
### scripts/multi_platform.py
```python
#!/usr/bin/env python3
"""Generate optimized prompts for all platforms at once."""
import argparse, json, sys
from optimize import enhance_prompt, PLATFORM_CONFIG, STYLES
def multi_optimize(prompt, style=None, ratio="1:1"):
results = []
for platform in PLATFORM_CONFIG:
data = enhance_prompt(prompt, platform, style, ratio)
results.append(data)
return {"original": prompt, "style": style, "ratio": ratio, "platforms": results}
def format_output(data):
lines = [f"🎨 多平台提示词优化", f"📝 原始: {data['original']}", ""]
if data["style"]:
lines.append(f"🖌️ 风格: {data['style']}")
lines.append(f"📐 比例: {data['ratio']}")
lines.append("")
for p in data["platforms"]:
lines.append(f"{'='*50}")
lines.append(f"{p['icon']} **{p['platform']}**")
lines.append(f"```")
lines.append(p["optimized"])
lines.append(f"```")
if p["negative"]:
lines.append(f"🚫 反向: {p['negative']}")
lines.append("")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--prompt", required=True)
p.add_argument("--style", default=None)
p.add_argument("--ratio", default="1:1")
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = multi_optimize(a.prompt, a.style, a.ratio)
print(json.dumps(data, indent=2, ensure_ascii=False) if a.json else format_output(data))
```
### scripts/style_library.py
```python
#!/usr/bin/env python3
"""Art style library browser."""
import argparse, json, sys
CATEGORIES = {
"photography": {
"name": "📷 摄影风格",
"styles": {
"cinematic": "电影感 — 戏剧性灯光, 浅景深, 电影质感",
"photorealistic": "超写实 — 8K, DSLR, 专业摄影",
"vintage": "复古 — 胶片感, 褪色, 怀旧",
"portrait": "人像 — 柔光, 散景, 特写",
"landscape": "风景 — 广角, 黄金时刻, 壮丽",
}
},
"illustration": {
"name": "🖌️ 插画风格",
"styles": {
"anime": "动漫 — 赛璐璐, 鲜艳色彩, 日系",
"watercolor": "水彩 — 柔和边缘, 纸质感",
"oil_painting": "油画 — 笔触, 画布质感, 古典",
"sketch": "素描 — 铅笔, 线条, 石墨",
"ink_wash": "水墨 — 中国传统, 写意",
}
},
"digital_art": {
"name": "💻 数字艺术",
"styles": {
"3d_render": "3D渲染 — Octane, C4D, 体积光",
"pixel_art": "像素画 — 16-bit, 复古游戏",
"cyberpunk": "赛博朋克 — 霓虹, 未来, 暗黑",
"fantasy": "奇幻 — 魔法, 史诗, 神秘",
"surreal": "超现实 — 达利风格, 梦幻",
}
},
"traditional": {
"name": "🏛️ 传统艺术",
"styles": {
"ukiyo_e": "浮世绘 — 日本木版画",
"ink_wash": "水墨画 — 中国传统",
"pop_art": "波普艺术 — 安迪沃霍尔",
"minimalist": "极简 — 简洁, 留白",
}
},
}
def list_styles(category=None):
if category and category in CATEGORIES:
cats = {category: CATEGORIES[category]}
else:
cats = CATEGORIES
return cats
def format_output(cats):
lines = ["🎨 风格库", ""]
for key, cat in cats.items():
lines.append(f"{cat['name']}")
for style, desc in cat["styles"].items():
lines.append(f" • {style}: {desc}")
lines.append("")
lines.append(f"共 {sum(len(c['styles']) for c in cats.values())} 种风格")
lines.append("使用: --style <style_name> 应用风格")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--list", action="store_true", help="List all styles")
p.add_argument("--category", default=None, choices=list(CATEGORIES.keys()))
p.add_argument("--json", action="store_true")
a = p.parse_args()
data = list_styles(a.category)
if a.json:
print(json.dumps(data, indent=2, ensure_ascii=False, default=str))
else:
print(format_output(data))
```
### scripts/history.py
```python
#!/usr/bin/env python3
"""Prompt history and favorites management."""
import argparse, json, os, sys
from datetime import datetime
HISTORY_FILE = os.path.expanduser("~/.openclaw/workspace/prompt-artist/data/history.json")
def load():
os.makedirs(os.path.dirname(HISTORY_FILE), exist_ok=True)
if os.path.exists(HISTORY_FILE):
return json.load(open(HISTORY_FILE))
return {"history": [], "favorites": []}
def save(data):
os.makedirs(os.path.dirname(HISTORY_FILE), exist_ok=True)
json.dump(data, open(HISTORY_FILE, "w"), indent=2, ensure_ascii=False)
def add_to_history(original, optimized, platform, style=None, ratio="1:1"):
data = load()
entry = {
"id": len(data["history"]) + 1,
"original": original,
"optimized": optimized,
"platform": platform,
"style": style,
"ratio": ratio,
"created": datetime.now().isoformat(),
"favorite": False,
}
data["history"].append(entry)
# Keep last 100
data["history"] = data["history"][-100:]
save(data)
return entry
def add_favorite(item_id):
data = load()
for item in data["history"]:
if item["id"] == item_id:
item["favorite"] = True
data["favorites"].append(item)
save(data)
return item
return None
def remove_favorite(item_id):
data = load()
for item in data["history"]:
if item["id"] == item_id:
item["favorite"] = False
data["favorites"] = [f for f in data["favorites"] if f["id"] != item_id]
save(data)
def show(limit=20, favorites_only=False):
data = load()
if favorites_only:
return {"favorites": data["favorites"]}
return {"history": data["history"][-limit:]}
def format_output(data, favorites_only=False):
items = data.get("favorites", []) if favorites_only else data.get("history", [])
title = "⭐ 收藏提示词" if favorites_only else "📜 提示词历史"
lines = [title, ""]
for item in items:
fav_icon = "⭐" if item.get("favorite") else " "
lines.append(f"{fav_icon} [{item['id']}] {item['platform']} - {item['original'][:40]}")
lines.append(f" ✨ {item['optimized'][:80]}...")
if item.get("style"):
lines.append(f" 🎨 风格:{item['style']}")
lines.append(f" 📅 {item['created'][:10]}")
lines.append("")
if not items:
lines.append(" (空列表)")
return "\n".join(lines)
if __name__ == "__main__":
p = argparse.ArgumentParser()
p.add_argument("--action", choices=["show", "add", "favorite", "unfavorite", "favorites"], default="show")
p.add_argument("--id", type=int, default=None)
p.add_argument("--original", default=None)
p.add_argument("--optimized", default=None)
p.add_argument("--platform", default=None)
p.add_argument("--style", default=None)
p.add_argument("--ratio", default="1:1")
p.add_argument("--limit", type=int, default=20)
p.add_argument("--json", action="store_true")
a = p.parse_args()
if a.action == "add":
r = add_to_history(a.original, a.optimized, a.platform, a.style, a.ratio)
print(f"✅ 已保存:[{r['id']}] {r['original'][:30]}")
elif a.action == "favorite":
r = add_favorite(a.id)
if r:
print(f"⭐ 已收藏:[{a.id}]")
else:
print(f"❌ 未找到 #{a.id}")
elif a.action == "unfavorite":
remove_favorite(a.id)
print(f"✅ 已取消收藏:#{a.id}")
elif a.action == "favorites":
data = show(favorites_only=True)
print(json.dumps(data, indent=2) if a.json else format_output(data, favorites_only=True))
else:
data = show(a.limit)
print(json.dumps(data, indent=2) if a.json else format_output(data))
```
### references/platform-specs.md
```markdown
# Platform Specifications
## Midjourney 🎨
- **Language**: English preferred
- **Max length**: ~6000 chars
- **Params**: `--ar` (ratio), `--v` (version), `--q` (quality), `--s` (stylize), `--no` (negative)
- **Multi-prompt**: Use `::` to separate concepts with weights
- **Best practices**: Descriptive nouns > verbs, specify camera/lens, add lighting
## Dreamina 极梦 🌈
- **Language**: Chinese/English
- **Max length**: ~2000 chars
- **Features**: Style presets, ratio selection, batch generation
- **Best practices**: 中文关键词效果好, 逗号分隔, 可指定艺术家风格
## Nano Banana 🍌
- **Language**: English preferred
- **Max length**: ~4000 chars
- **Features**: Quality tags, negative prompts, seed control
- **Best practices**: Use quality tags (masterpiece, best quality), comma-separated
## Qwen 🤖
- **Language**: Chinese/English
- **Max length**: ~2000 chars
- **Features**: Natural language input, style keywords
- **Best practices**: 自然语言描述, 越详细越好, 可加风格关键词
```
---
## Skill Companion Files
> Additional files collected from the skill directory layout.
### _meta.json
```json
{
"owner": "elevo11",
"slug": "prompt-artist",
"displayName": "Prompt Artist",
"latest": {
"version": "1.1.0",
"publishedAt": 1772787436252,
"commit": "https://github.com/openclaw/skills/commit/2736205bf5422c6b107dcb908a4384434db54698"
},
"history": [
{
"version": "1.0.0",
"publishedAt": 1772782738200,
"commit": "https://github.com/openclaw/skills/commit/b49108ed0f65127b894d5abc9d7bd26b27ee8dc6"
}
]
}
```