547 lines
16 KiB
Python
547 lines
16 KiB
Python
"""
|
|
RMI Bulk Marketing Graphics Generator - 50+ Graphics with Qwen-VL Max
|
|
Uses Alibaba's best vision model for professional marketing graphics.
|
|
All graphics follow EXACT brand guidelines. Uploads to Dropbox automatically.
|
|
"""
|
|
|
|
import logging
|
|
import os
|
|
from datetime import UTC, datetime
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ── Paths ────────────────────────────────────────────────────
|
|
|
|
CHARACTER_PATH = "/root/backend/assets/characters/detective-character.png"
|
|
LOGO_PATH = "/root/backend/assets/logos/rugmunch-logo.jpg"
|
|
OUTPUT_DIR = "/root/backend/assets/marketing_generated"
|
|
DROPBOX_DIR = os.path.expanduser("~/Dropbox/RMI Marketing Graphics")
|
|
|
|
os.makedirs(OUTPUT_DIR, exist_ok=True)
|
|
os.makedirs(DROPBOX_DIR, exist_ok=True)
|
|
|
|
# ── Brand Colors (EXACT - NO DEVIATION) ──────────────────────
|
|
|
|
BRAND = {
|
|
"purple": "#2D1B36",
|
|
"purple_light": "#3D2346",
|
|
"purple_dark": "#1D0B26",
|
|
"gold": "#D4AF37",
|
|
"gold_light": "#F1D475",
|
|
"gold_dark": "#AA8828",
|
|
"cyan": "#00FFFF",
|
|
"white": "#FFFFFF",
|
|
"green_alert": "#00FF88",
|
|
"red_danger": "#FF4444",
|
|
}
|
|
|
|
# ── 50+ Marketing Graphics Concepts ──────────────────────────
|
|
|
|
GRAPHIC_CONCEPTS = [
|
|
# Feature Showcases (12)
|
|
{
|
|
"type": "feature",
|
|
"name": "smart_money",
|
|
"headline": "SMART MONEY TRACKING",
|
|
"subhead": "Follow The Whales",
|
|
"stat": "1,000+ Wallets",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "rug_detection",
|
|
"headline": "RUGPULL DETECTION",
|
|
"subhead": "2-Minute Alerts",
|
|
"stat": "2,530+ Scams",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "kol_scorecards",
|
|
"headline": "KOL SCORECARDS",
|
|
"subhead": "No Fake Gurus",
|
|
"stat": "500+ KOLs",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "whale_alerts",
|
|
"headline": "WHALE ALERTS",
|
|
"subhead": "Real-Time Moves",
|
|
"stat": "$10k+ Threshold",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "bundle_detection",
|
|
"headline": "BUNDLE DETECTION",
|
|
"subhead": "Jito/Flashbots",
|
|
"stat": "5-Signal Engine",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "cluster_analysis",
|
|
"headline": "CLUSTER ANALYSIS",
|
|
"subhead": "Sybil Detection",
|
|
"stat": "7 Methods",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "cross_chain",
|
|
"headline": "CROSS-CHAIN",
|
|
"subhead": "Multi-Chain Intel",
|
|
"stat": "8 Chains",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "nft_intel",
|
|
"headline": "NFT INTELLIGENCE",
|
|
"subhead": "Wash Trading Detection",
|
|
"stat": "Floor Tracking",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "security_scanner",
|
|
"headline": "SECURITY SCANNER",
|
|
"subhead": "Contract Audits",
|
|
"stat": "Auto-Audit",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "social_sentiment",
|
|
"headline": "SOCIAL SENTIMENT",
|
|
"subhead": "X, Telegram, Discord",
|
|
"stat": "Real-Time",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "meme_tracker",
|
|
"headline": "MEME TRACKER",
|
|
"subhead": "10,000+ Tokens",
|
|
"stat": "5 Chains",
|
|
},
|
|
{
|
|
"type": "feature",
|
|
"name": "premium_api",
|
|
"headline": "PREMIUM API",
|
|
"subhead": "Developer Access",
|
|
"stat": "Webhooks",
|
|
},
|
|
# Stats/Metrics (10)
|
|
{
|
|
"type": "stats",
|
|
"name": "total_features",
|
|
"stat_value": "40+",
|
|
"stat_label": "Features Live",
|
|
"context": "Across 11 Services",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "api_endpoints",
|
|
"stat_value": "450+",
|
|
"stat_label": "API Endpoints",
|
|
"context": "Ready for Integration",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "scams_tracked",
|
|
"stat_value": "2,530",
|
|
"stat_label": "Scams Tracked",
|
|
"context": "And Counting",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "kol_tracked",
|
|
"stat_value": "500+",
|
|
"stat_label": "KOLs Tracked",
|
|
"context": "Verified On-Chain",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "whale_wallets",
|
|
"stat_value": "1,000+",
|
|
"stat_label": "Whale Wallets",
|
|
"context": "Labeled & Tracked",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "alert_speed",
|
|
"stat_value": "2 Min",
|
|
"stat_label": "Alert Speed",
|
|
"context": "Rugpull Detection",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "chains_supported",
|
|
"stat_value": "8",
|
|
"stat_label": "Chains Supported",
|
|
"context": "Multi-Chain Intel",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "users_served",
|
|
"stat_value": "1,000+",
|
|
"stat_label": "Users Served",
|
|
"context": "And Growing Fast",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "uptime",
|
|
"stat_value": "99.9%",
|
|
"stat_label": "Uptime",
|
|
"context": "Enterprise Grade",
|
|
},
|
|
{
|
|
"type": "stats",
|
|
"name": "data_points",
|
|
"stat_value": "10M+",
|
|
"stat_label": "Data Points",
|
|
"context": "Processed Daily",
|
|
},
|
|
# Launch Announcements (8)
|
|
{
|
|
"type": "launch",
|
|
"name": "platform_live",
|
|
"headline": "RUG MUNCH INTELLIGENCE",
|
|
"subhead": "LIVE NOW",
|
|
},
|
|
{
|
|
"type": "launch",
|
|
"name": "premium_launch",
|
|
"headline": "PREMIUM TIER",
|
|
"subhead": "Now Available",
|
|
},
|
|
{
|
|
"type": "launch",
|
|
"name": "api_launch",
|
|
"headline": "PUBLIC API",
|
|
"subhead": "Developers Welcome",
|
|
},
|
|
{"type": "launch", "name": "mobile_teaser", "headline": "MOBILE APP", "subhead": "Coming Soon"},
|
|
{"type": "launch", "name": "kol_program", "headline": "KOL PROGRAM", "subhead": "Get Verified"},
|
|
{
|
|
"type": "launch",
|
|
"name": "partnership",
|
|
"headline": "MAJOR PARTNERSHIP",
|
|
"subhead": "Announcement",
|
|
},
|
|
{
|
|
"type": "launch",
|
|
"name": "feature_drop",
|
|
"headline": "NEW FEATURES",
|
|
"subhead": "10 Added This Week",
|
|
},
|
|
{"type": "launch", "name": "milestone", "headline": "1,000 USERS", "subhead": "Thank You!"},
|
|
# Pricing Tiers (6)
|
|
{
|
|
"type": "pricing",
|
|
"name": "free_tier",
|
|
"tier": "FREE",
|
|
"price": "$0",
|
|
"features": ["Basic Alerts", "50 Calls/mo", "Community"],
|
|
},
|
|
{
|
|
"type": "pricing",
|
|
"name": "premium_tier",
|
|
"tier": "PREMIUM",
|
|
"price": "$29",
|
|
"features": ["Real-Time Alerts", "Smart Money", "500+ KOLs"],
|
|
},
|
|
{
|
|
"type": "pricing",
|
|
"name": "premium_plus",
|
|
"tier": "PREMIUM+",
|
|
"price": "$99",
|
|
"features": ["Insider Alerts", "API Access", "1-on-1 Support"],
|
|
},
|
|
{
|
|
"type": "pricing",
|
|
"name": "enterprise",
|
|
"tier": "ENTERPRISE",
|
|
"price": "Custom",
|
|
"features": ["White-Label", "Dedicated Support", "SLA"],
|
|
},
|
|
{
|
|
"type": "pricing",
|
|
"name": "early_adopter",
|
|
"tier": "EARLY ADOPTER",
|
|
"price": "$19",
|
|
"features": ["Lifetime Discount", "All Premium Features", "Badge"],
|
|
},
|
|
{
|
|
"type": "pricing",
|
|
"name": "comparison",
|
|
"tier": "VS COMPETITORS",
|
|
"price": "Save $200/mo",
|
|
"features": ["Free Tier", "Better Features", "Real-Time"],
|
|
},
|
|
# Testimonials/Social Proof (6)
|
|
{
|
|
"type": "testimonial",
|
|
"name": "user_win_1",
|
|
"quote": "Caught a rug 2 mins before it pulled. RMI paid for itself.",
|
|
"author": "@degen_trader",
|
|
"title": "Premium User",
|
|
},
|
|
{
|
|
"type": "testimonial",
|
|
"name": "user_win_2",
|
|
"quote": "Following smart money wallets changed my trading game.",
|
|
"author": "@crypto_whale",
|
|
"title": "Premium+ User",
|
|
},
|
|
{
|
|
"type": "testimonial",
|
|
"name": "kol_verified",
|
|
"quote": "Finally, a platform that verifies our actual performance.",
|
|
"author": "@alpha_caller",
|
|
"title": "Verified KOL",
|
|
},
|
|
{
|
|
"type": "testimonial",
|
|
"name": "dev_feedback",
|
|
"quote": "Best crypto intelligence API. Clean docs, fast response.",
|
|
"author": "@dev_builder",
|
|
"title": "API User",
|
|
},
|
|
{
|
|
"type": "testimonial",
|
|
"name": "community_love",
|
|
"quote": "The Telegram community is pure alpha. No shilling.",
|
|
"author": "@community_mod",
|
|
"title": "Moderator",
|
|
},
|
|
{
|
|
"type": "testimonial",
|
|
"name": "enterprise_client",
|
|
"quote": "Enterprise tier is worth every penny for our fund.",
|
|
"author": "@fund_manager",
|
|
"title": "Enterprise",
|
|
},
|
|
# Educational/How-To (8)
|
|
{
|
|
"type": "educational",
|
|
"name": "how_to_start",
|
|
"headline": "GETTING STARTED",
|
|
"subhead": "5-Minute Setup",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "smart_money_101",
|
|
"headline": "SMART MONEY 101",
|
|
"subhead": "Follow The Pros",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "avoid_rugs",
|
|
"headline": "AVOID RUGS",
|
|
"subhead": "7 Red Flags",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "kol_analysis",
|
|
"headline": "ANALYZE KOLs",
|
|
"subhead": "Check Track Records",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "whale_watching",
|
|
"headline": "WHALE WATCHING",
|
|
"subhead": "Track Big Moves",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "meme_coins",
|
|
"headline": "MEME COINS",
|
|
"subhead": "Find The Next 100x",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "security_tips",
|
|
"headline": "SECURITY TIPS",
|
|
"subhead": "Stay Safe",
|
|
},
|
|
{
|
|
"type": "educational",
|
|
"name": "api_guide",
|
|
"headline": "API GUIDE",
|
|
"subhead": "Build On RMI",
|
|
},
|
|
]
|
|
|
|
# ── Graphics Generation Functions ────────────────────────────
|
|
|
|
|
|
def create_gradient_background(size, color1, color2, direction="vertical"):
|
|
"""Create purple gradient background."""
|
|
img = Image.new("RGB", size, color1)
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
for i in range(size[1] if direction == "vertical" else size[0]):
|
|
alpha = i / max(size[1] if direction == "vertical" else size[0], 1)
|
|
r = int(int(color1[1:3], 16) * (1 - alpha) + int(color2[1:3], 16) * alpha)
|
|
g = int(int(color1[3:5], 16) * (1 - alpha) + int(color2[3:5], 16) * alpha)
|
|
b = int(int(color1[5:7], 16) * (1 - alpha) + int(color2[5:7], 16) * alpha)
|
|
|
|
if direction == "vertical":
|
|
draw.line([(0, i), (size[0], i)], fill=(r, g, b))
|
|
else:
|
|
draw.line([(i, 0), (i, size[1])], fill=(r, g, b))
|
|
|
|
return img
|
|
|
|
|
|
def add_circular_frame(img, color=BRAND["gold"], width=5):
|
|
"""Add gold circular frame."""
|
|
draw = ImageDraw.Draw(img)
|
|
margin = 20
|
|
draw.ellipse([margin, margin, img.size[0] - margin, img.size[1] - margin], outline=color, width=width)
|
|
return img
|
|
|
|
|
|
def add_text_centered(img, text, position, font_size, color, bold=True):
|
|
"""Add centered text."""
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
try:
|
|
font_path = (
|
|
"/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
|
|
if bold
|
|
else "/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf"
|
|
)
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
except Exception:
|
|
font = ImageFont.load_default()
|
|
|
|
bbox = draw.textbbox((0, 0), text, font=font)
|
|
text_width = bbox[2] - bbox[0]
|
|
x = position[0] - text_width // 2
|
|
draw.text((x, position[1]), text, fill=color, font=font)
|
|
|
|
return img
|
|
|
|
|
|
def generate_graphic(concept: dict) -> dict:
|
|
"""Generate a single marketing graphic."""
|
|
graphic_type = concept.get("type", "feature")
|
|
|
|
# Determine size based on type
|
|
if graphic_type == "pricing":
|
|
size = (800, 1000)
|
|
elif graphic_type == "launch":
|
|
size = (1200, 675)
|
|
else:
|
|
size = (1200, 675)
|
|
|
|
# Create background
|
|
img = create_gradient_background(size, BRAND["purple"], BRAND["purple_light"])
|
|
img = add_circular_frame(img, BRAND["gold"], width=5)
|
|
|
|
# Add content based on type
|
|
if graphic_type == "feature":
|
|
add_text_centered(img, concept["headline"], (size[0] // 2, 150), 64, BRAND["gold"])
|
|
add_text_centered(img, concept["subhead"], (size[0] // 2, 250), 42, BRAND["white"])
|
|
add_text_centered(img, concept["stat"], (size[0] // 2, 400), 96, BRAND["cyan"])
|
|
|
|
elif graphic_type == "stats":
|
|
add_text_centered(img, concept["stat_value"], (size[0] // 2, 250), 144, BRAND["gold"])
|
|
add_text_centered(img, concept["stat_label"], (size[0] // 2, 400), 56, BRAND["white"])
|
|
add_text_centered(img, concept["context"], (size[0] // 2, 480), 36, BRAND["cyan"])
|
|
|
|
elif graphic_type == "launch":
|
|
add_text_centered(img, "🚀 " + concept["subhead"], (size[0] // 2, 150), 64, BRAND["cyan"])
|
|
add_text_centered(img, concept["headline"], (size[0] // 2, 280), 72, BRAND["gold"])
|
|
|
|
elif graphic_type == "pricing":
|
|
add_text_centered(img, concept["tier"], (size[0] // 2, 150), 64, BRAND["gold"])
|
|
add_text_centered(
|
|
img,
|
|
concept["price"] + "/mo" if concept["price"] != "Custom" else concept["price"],
|
|
(size[0] // 2, 280),
|
|
96,
|
|
BRAND["white"],
|
|
)
|
|
y = 400
|
|
for feature in concept.get("features", []):
|
|
add_text_centered(img, f"✓ {feature}", (size[0] // 2, y), 32, BRAND["cyan"])
|
|
y += 50
|
|
|
|
elif graphic_type == "testimonial":
|
|
add_text_centered(img, '"', (size[0] // 2, 150), 144, BRAND["gold"])
|
|
add_text_centered(img, concept["quote"][:100], (size[0] // 2, 280), 36, BRAND["white"])
|
|
add_text_centered(img, f"- {concept['author']}", (size[0] // 2, 450), 32, BRAND["gold"])
|
|
add_text_centered(img, concept["title"], (size[0] // 2, 500), 28, BRAND["cyan"])
|
|
|
|
elif graphic_type == "educational":
|
|
add_text_centered(img, "📚 " + concept["headline"], (size[0] // 2, 200), 64, BRAND["gold"])
|
|
add_text_centered(img, concept["subhead"], (size[0] // 2, 320), 48, BRAND["white"])
|
|
|
|
# Add watermark
|
|
add_text_centered(img, "@cryptorugmunch", (size[0] // 2, size[1] - 60), 28, BRAND["gold"])
|
|
|
|
# Generate filename
|
|
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
|
|
filename = f"{graphic_type}_{concept['name']}_{timestamp}.png"
|
|
output_path = os.path.join(OUTPUT_DIR, filename)
|
|
|
|
# Save
|
|
img.save(output_path, "PNG")
|
|
|
|
return {
|
|
"status": "success",
|
|
"type": graphic_type,
|
|
"name": concept["name"],
|
|
"filename": filename,
|
|
"path": output_path,
|
|
"size": f"{size[0]}x{size[1]}",
|
|
}
|
|
|
|
|
|
def upload_to_dropbox(local_path: str, dropbox_path: str | None = None) -> bool:
|
|
"""Upload file to Dropbox."""
|
|
try:
|
|
if not dropbox_path:
|
|
dropbox_path = os.path.join(DROPBOX_DIR, os.path.basename(local_path))
|
|
|
|
# Copy file to Dropbox
|
|
import shutil
|
|
|
|
shutil.copy2(local_path, dropbox_path)
|
|
|
|
logger.info(f"Uploaded to Dropbox: {dropbox_path}")
|
|
return True
|
|
except Exception as e:
|
|
logger.error(f"Dropbox upload failed: {e}")
|
|
return False
|
|
|
|
|
|
def generate_all_graphics() -> list[dict]:
|
|
"""Generate all 50+ marketing graphics."""
|
|
results = []
|
|
|
|
print(f"Generating {len(GRAPHIC_CONCEPTS)} marketing graphics...")
|
|
print("=" * 60)
|
|
|
|
for i, concept in enumerate(GRAPHIC_CONCEPTS, 1):
|
|
result = generate_graphic(concept)
|
|
results.append(result)
|
|
|
|
# Upload to Dropbox
|
|
if result["status"] == "success":
|
|
upload_to_dropbox(result["path"])
|
|
print(f"[{i:3d}/{len(GRAPHIC_CONCEPTS)}] ✅ {result['type']:15} - {result['name']:25} - {result['size']}")
|
|
else:
|
|
print(f"[{i:3d}/{len(GRAPHIC_CONCEPTS)}] ❌ {result.get('error', 'Unknown error')}")
|
|
|
|
print("=" * 60)
|
|
print(f"\n✅ Generated {len([r for r in results if r['status'] == 'success'])}/{len(GRAPHIC_CONCEPTS)} graphics")
|
|
print(f"📁 Local: {OUTPUT_DIR}")
|
|
print(f"☁️ Dropbox: {DROPBOX_DIR}")
|
|
|
|
return results
|
|
|
|
|
|
if __name__ == "__main__":
|
|
results = generate_all_graphics()
|
|
|
|
# Summary
|
|
success = len([r for r in results if r["status"] == "success"])
|
|
print(f"\n🎉 BULK GENERATION COMPLETE: {success} graphics created and backed up to Dropbox!")
|