588 lines
20 KiB
Python
588 lines
20 KiB
Python
"""
|
|
RMI Marketing Graphics Generator - Advertising & Feature Showcase Graphics.
|
|
Professional visuals for platform marketing, feature showcases, comparisons.
|
|
Uses template-based generation with Alibaba AI enhancement options.
|
|
|
|
Graphics Types:
|
|
- Platform banners (website, social)
|
|
- Feature showcase cards
|
|
- Comparison charts (vs competitors)
|
|
- Stats/metrics graphics
|
|
- Testimonial cards
|
|
- Launch announcements
|
|
- Pricing tier graphics
|
|
"""
|
|
|
|
import hashlib
|
|
import logging
|
|
import os
|
|
from datetime import UTC, datetime
|
|
|
|
from PIL import Image, ImageDraw, ImageFont
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
# ── Paths ────────────────────────────────────────────────────
|
|
|
|
MARKETING_TEMPLATE_DIR = "/root/backend/assets/marketing_templates"
|
|
MARKETING_GENERATED_DIR = "/root/backend/assets/marketing_generated"
|
|
|
|
os.makedirs(MARKETING_TEMPLATE_DIR, exist_ok=True)
|
|
os.makedirs(MARKETING_GENERATED_DIR, exist_ok=True)
|
|
|
|
# ── Brand Colors (EXACT - NO DEVIATION) ─────────────────────────
|
|
|
|
BRAND_COLORS = {
|
|
"deep_purple": "#2D1B36", # Primary background
|
|
"metallic_gold": "#D4AF37", # Primary text, borders
|
|
"cyan_glow": "#00FFFF", # Character glasses, tech accents
|
|
"gold_highlight": "#F1D475", # Light gradients
|
|
"gold_shadow": "#AA8828", # Dark gradients
|
|
"neon_green": "#00FF88", # ONLY for alerts (rugpulls, scams)
|
|
"danger_red": "#FF4444", # ONLY for losses, danger
|
|
"white": "#FFFFFF", # Body text
|
|
"background": "#2D1B36", # Same as deep_purple
|
|
"surface": "#3D2346", # Slightly lighter purple for cards
|
|
"text_primary": "#D4AF37", # Gold for headlines
|
|
"text_secondary": "#FFFFFF", # White for body
|
|
}
|
|
|
|
# ── Marketing Graphics Templates ─────────────────────────────
|
|
|
|
MARKETING_TEMPLATES = {
|
|
# Platform Banners
|
|
"platform_banner_wide": {
|
|
"name": "Platform Banner (Wide)",
|
|
"size": (1920, 1080), # Full HD
|
|
"use_cases": ["Website hero", "YouTube banner", "Presentations"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_purple"},
|
|
{"type": "logo", "position": (100, 100)},
|
|
{
|
|
"type": "headline",
|
|
"text": "Rug Munch Intelligence",
|
|
"position": (100, 300),
|
|
"font_size": 96,
|
|
"color": "#D4AF37",
|
|
},
|
|
{
|
|
"type": "subheadline",
|
|
"text": "Track Smart Money. Avoid Rugs. Find Alpha.",
|
|
"position": (100, 420),
|
|
"font_size": 48,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "features_list", "position": (100, 550), "font_size": 36, "color": "#FFFFFF"},
|
|
{
|
|
"type": "cta_button",
|
|
"text": "Join Now - Free",
|
|
"position": (100, 850),
|
|
"font_size": 48,
|
|
"color": "#2D1B36",
|
|
"bg_color": "#D4AF37",
|
|
},
|
|
{"type": "character", "position": (1400, 200), "size": 500},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (1700, 1000),
|
|
"font_size": 32,
|
|
"color": "#D4AF37",
|
|
},
|
|
],
|
|
},
|
|
"platform_banner_square": {
|
|
"name": "Platform Banner (Square)",
|
|
"size": (1080, 1080), # Instagram/Twitter
|
|
"use_cases": ["Social media", "Profile banner"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_purple"},
|
|
{"type": "logo", "position": (440, 150)},
|
|
{
|
|
"type": "headline",
|
|
"text": "Rug Munch Intelligence",
|
|
"position": (100, 400),
|
|
"font_size": 72,
|
|
"color": "#D4AF37",
|
|
},
|
|
{
|
|
"type": "subheadline",
|
|
"text": "Track Smart Money. Avoid Rugs.",
|
|
"position": (100, 500),
|
|
"font_size": 36,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "character", "position": (340, 650), "size": 400},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (400, 950),
|
|
"font_size": 28,
|
|
"color": "#D4AF37",
|
|
},
|
|
],
|
|
},
|
|
# Feature Showcase Cards
|
|
"feature_card": {
|
|
"name": "Feature Showcase Card",
|
|
"size": (1200, 675),
|
|
"use_cases": ["Twitter posts", "Telegram", "Blog headers"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_dark"},
|
|
{"type": "icon", "position": (100, 150), "size": 200},
|
|
{
|
|
"type": "feature_name",
|
|
"text": "{feature_name}",
|
|
"position": (350, 200),
|
|
"font_size": 64,
|
|
"color": "#00FF88",
|
|
},
|
|
{
|
|
"type": "feature_desc",
|
|
"text": "{feature_description}",
|
|
"position": (350, 300),
|
|
"font_size": 36,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "stats", "position": (350, 450), "font_size": 32, "color": "#FFD700"},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (950, 600),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
],
|
|
},
|
|
"feature_grid": {
|
|
"name": "Feature Grid (All Features)",
|
|
"size": (1920, 1920),
|
|
"use_cases": ["Comprehensive overview", "Website section"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_dark"},
|
|
{
|
|
"type": "title",
|
|
"text": "40+ Features Live Now",
|
|
"position": (100, 100),
|
|
"font_size": 80,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "grid", "columns": 4, "rows": 3, "position": (100, 250)},
|
|
{
|
|
"type": "watermark",
|
|
"text": "rugmunch.io",
|
|
"position": (1500, 1800),
|
|
"font_size": 40,
|
|
"color": "#00FF88",
|
|
},
|
|
],
|
|
},
|
|
# Comparison Graphics
|
|
"competitor_comparison": {
|
|
"name": "Competitor Comparison Chart",
|
|
"size": (1600, 900),
|
|
"use_cases": ["Twitter threads", "Blog posts", "Sales pages"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_dark"},
|
|
{
|
|
"type": "title",
|
|
"text": "RMI vs. The Competition",
|
|
"position": (100, 80),
|
|
"font_size": 64,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "comparison_table", "position": (100, 180), "font_size": 28},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (1300, 820),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
],
|
|
},
|
|
# Stats/Metrics Graphics
|
|
"stats_card": {
|
|
"name": "Stats/Metrics Card",
|
|
"size": (1200, 675),
|
|
"use_cases": ["Milestone announcements", "Growth metrics"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_dark"},
|
|
{
|
|
"type": "stat_number",
|
|
"text": "{stat_value}",
|
|
"position": (600, 250),
|
|
"font_size": 144,
|
|
"color": "#00FF88",
|
|
},
|
|
{
|
|
"type": "stat_label",
|
|
"text": "{stat_label}",
|
|
"position": (600, 420),
|
|
"font_size": 48,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{
|
|
"type": "context",
|
|
"text": "{context}",
|
|
"position": (600, 520),
|
|
"font_size": 32,
|
|
"color": "#A0A0A0",
|
|
},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (950, 600),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
],
|
|
},
|
|
# Pricing Tier Graphics
|
|
"pricing_card": {
|
|
"name": "Pricing Tier Card",
|
|
"size": (800, 1000),
|
|
"use_cases": ["Pricing page", "Social posts"],
|
|
"elements": [
|
|
{"type": "background", "style": "card_surface"},
|
|
{
|
|
"type": "tier_name",
|
|
"text": "{tier_name}",
|
|
"position": (400, 150),
|
|
"font_size": 64,
|
|
"color": "#00FF88",
|
|
},
|
|
{
|
|
"type": "tier_price",
|
|
"text": "${price}/mo",
|
|
"position": (400, 250),
|
|
"font_size": 72,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{"type": "features_list", "position": (100, 350), "font_size": 28, "color": "#FFFFFF"},
|
|
{
|
|
"type": "cta_button",
|
|
"text": "Get Started",
|
|
"position": (200, 850),
|
|
"font_size": 40,
|
|
"color": "#000000",
|
|
"bg_color": "#00FF88",
|
|
},
|
|
],
|
|
},
|
|
# Launch Announcement
|
|
"launch_announcement": {
|
|
"name": "Launch Announcement",
|
|
"size": (1200, 675),
|
|
"use_cases": ["Product launches", "Major announcements"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_celebration"},
|
|
{
|
|
"type": "badge",
|
|
"text": "🚀 LIVE NOW",
|
|
"position": (450, 100),
|
|
"font_size": 64,
|
|
"color": "#FFD700",
|
|
},
|
|
{
|
|
"type": "headline",
|
|
"text": "{headline}",
|
|
"position": (100, 250),
|
|
"font_size": 72,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{
|
|
"type": "subheadline",
|
|
"text": "{subheadline}",
|
|
"position": (100, 350),
|
|
"font_size": 40,
|
|
"color": "#00FF88",
|
|
},
|
|
{
|
|
"type": "cta",
|
|
"text": "rugmunch.io",
|
|
"position": (450, 550),
|
|
"font_size": 48,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (950, 600),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
],
|
|
},
|
|
# Testimonial Card
|
|
"testimonial_card": {
|
|
"name": "Testimonial/User Quote",
|
|
"size": (1200, 675),
|
|
"use_cases": ["Social proof", "User reviews"],
|
|
"elements": [
|
|
{"type": "background", "style": "gradient_dark"},
|
|
{"type": "quote_icon", "position": (100, 100), "size": 80},
|
|
{
|
|
"type": "quote_text",
|
|
"text": "{quote}",
|
|
"position": (200, 150),
|
|
"font_size": 40,
|
|
"color": "#FFFFFF",
|
|
},
|
|
{
|
|
"type": "author",
|
|
"text": "- {author}",
|
|
"position": (200, 450),
|
|
"font_size": 32,
|
|
"color": "#00FF88",
|
|
},
|
|
{
|
|
"type": "author_title",
|
|
"text": "{title}",
|
|
"position": (200, 500),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
{
|
|
"type": "watermark",
|
|
"text": "@cryptorugmunch",
|
|
"position": (950, 600),
|
|
"font_size": 28,
|
|
"color": "#A0A0A0",
|
|
},
|
|
],
|
|
},
|
|
}
|
|
|
|
# ── Feature List for Graphics ────────────────────────────────
|
|
|
|
FEATURE_LIST = [
|
|
{
|
|
"name": "Rugpull Detection",
|
|
"desc": "7-method engine, 2-min alerts",
|
|
"stat": "2,530+ scams tracked",
|
|
},
|
|
{
|
|
"name": "Smart Money Tracking",
|
|
"desc": "1,000+ labeled whale wallets",
|
|
"stat": "Real-time alerts",
|
|
},
|
|
{"name": "KOL Scorecards", "desc": "500+ influencers tracked", "stat": "Verified on-chain"},
|
|
{"name": "Meme Intelligence", "desc": "10,000+ meme tokens", "stat": "Across 5 chains"},
|
|
{"name": "Cluster Analysis", "desc": "Sybil & team detection", "stat": "7 detection methods"},
|
|
{"name": "Bundle Detection", "desc": "Jito/Flashbots tracking", "stat": "5-signal engine"},
|
|
{"name": "Cross-Chain", "desc": "Multi-chain correlation", "stat": "8 chains supported"},
|
|
{"name": "Social Sentiment", "desc": "X, Telegram, Discord", "stat": "Real-time monitoring"},
|
|
{"name": "Security Scanner", "desc": "Contract vulnerability detection", "stat": "Auto-audit"},
|
|
{"name": "Whale Alerts", "desc": "Large transfer tracking", "stat": "$10k+ threshold"},
|
|
{"name": "NFT Intelligence", "desc": "Wash trading detection", "stat": "Floor price tracking"},
|
|
{"name": "Premium API", "desc": "Developer access", "stat": "Webhook support"},
|
|
]
|
|
|
|
# ── Graphics Generation Functions ────────────────────────────
|
|
|
|
|
|
def create_placeholder_marketing_template(template_name: str, config: dict) -> Image.Image:
|
|
"""Create a placeholder marketing template."""
|
|
img = Image.new("RGB", config["size"], color=BRAND_COLORS["background"])
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# Add gradient effect (simplified)
|
|
for y in range(config["size"][1]):
|
|
alpha = y / config["size"][1]
|
|
r = int(10 + alpha * 20)
|
|
g = int(10 + alpha * 30)
|
|
b = int(15 + alpha * 40)
|
|
draw.line([(0, y), (config["size"][0], y)], fill=(r, g, b))
|
|
|
|
# Add title
|
|
title = config["name"]
|
|
try:
|
|
font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf", 72)
|
|
except Exception:
|
|
font = ImageFont.load_default()
|
|
|
|
bbox = draw.textbbox((0, 0), title, font=font)
|
|
title_width = bbox[2] - bbox[0]
|
|
draw.text(((config["size"][0] - title_width) / 2, 50), title, fill=BRAND_COLORS["primary"], font=font)
|
|
|
|
# Add watermark
|
|
try:
|
|
watermark_font = ImageFont.truetype("/usr/share/fonts/truetype/dejavu/DejaVuSans.ttf", 32)
|
|
except Exception:
|
|
watermark_font = font
|
|
|
|
draw.text(
|
|
(config["size"][0] - 250, config["size"][1] - 50),
|
|
"@cryptorugmunch",
|
|
fill=BRAND_COLORS["text_secondary"],
|
|
font=watermark_font,
|
|
)
|
|
|
|
# Save template
|
|
template_path = os.path.join(MARKETING_TEMPLATE_DIR, f"{template_name}_template.png")
|
|
img.save(template_path)
|
|
logger.info(f"Created marketing template: {template_path}")
|
|
|
|
return img
|
|
|
|
|
|
def generate_marketing_graphic(graphic_type: str, data: dict | None = None) -> dict:
|
|
"""
|
|
Generate marketing graphic by overlaying text on template.
|
|
Returns image path and metadata.
|
|
"""
|
|
try:
|
|
config = MARKETING_TEMPLATES.get(graphic_type)
|
|
if not config:
|
|
return {"error": f"Unknown graphic type: {graphic_type}"}
|
|
|
|
# Get or create template
|
|
template_path = os.path.join(MARKETING_TEMPLATE_DIR, f"{graphic_type}_template.png")
|
|
|
|
if os.path.exists(template_path):
|
|
img = Image.open(template_path)
|
|
else:
|
|
img = create_placeholder_marketing_template(graphic_type, config)
|
|
|
|
draw = ImageDraw.Draw(img)
|
|
|
|
# Try to load font
|
|
try:
|
|
font_path = "/usr/share/fonts/truetype/dejavu/DejaVuSans-Bold.ttf"
|
|
base_font = ImageFont.truetype(font_path, 32)
|
|
except Exception:
|
|
base_font = ImageFont.load_default()
|
|
|
|
# Overlay dynamic data if provided
|
|
if data:
|
|
for key, value in data.items():
|
|
# Find matching element in config
|
|
for element in config.get("elements", []):
|
|
if element.get("type") == key or f"{{{key}}}" in str(element.get("text", "")):
|
|
position = element.get("position", (100, 100))
|
|
font_size = element.get("font_size", 32)
|
|
color = element.get("color", "#FFFFFF")
|
|
|
|
try:
|
|
font = ImageFont.truetype(font_path, font_size)
|
|
except Exception:
|
|
font = base_font
|
|
|
|
draw.text(position, str(value), fill=color, font=font)
|
|
|
|
# Generate filename
|
|
data_hash = hashlib.md5(str(sorted((data or {}).items())).encode()).hexdigest()[:12]
|
|
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
|
|
filename = f"{graphic_type}_{timestamp}_{data_hash}.png"
|
|
output_path = os.path.join(MARKETING_GENERATED_DIR, filename)
|
|
|
|
# Save image
|
|
img.save(output_path, "PNG")
|
|
|
|
return {
|
|
"status": "success",
|
|
"graphic_type": graphic_type,
|
|
"image_path": output_path,
|
|
"image_url": f"/assets/marketing_generated/{filename}",
|
|
"filename": filename,
|
|
"size": config["size"],
|
|
"data": data or {},
|
|
"generated_at": datetime.now(UTC).isoformat(),
|
|
}
|
|
|
|
except Exception as e:
|
|
logger.error(f"Marketing graphic generation failed: {e}")
|
|
return {"status": "error", "error": str(e)}
|
|
|
|
|
|
# ── Convenience Functions ────────────────────────────────────
|
|
|
|
|
|
async def generate_platform_banner(data: dict | None = None) -> dict:
|
|
"""Generate platform banner (wide format)."""
|
|
return generate_marketing_graphic("platform_banner_wide", data)
|
|
|
|
|
|
async def generate_feature_card(feature_name: str, description: str, stat: str) -> dict:
|
|
"""Generate feature showcase card."""
|
|
data = {
|
|
"feature_name": feature_name,
|
|
"feature_description": description[:100],
|
|
"stats": stat,
|
|
}
|
|
return generate_marketing_graphic("feature_card", data)
|
|
|
|
|
|
async def generate_all_feature_cards() -> list[dict]:
|
|
"""Generate cards for all features."""
|
|
results = []
|
|
for feature in FEATURE_LIST:
|
|
result = await generate_feature_card(feature["name"], feature["desc"], feature["stat"])
|
|
results.append(result)
|
|
return results
|
|
|
|
|
|
async def generate_stats_card(stat_value: str, stat_label: str, context: str = "") -> dict:
|
|
"""Generate stats/metrics card."""
|
|
data = {
|
|
"stat_value": stat_value,
|
|
"stat_label": stat_label,
|
|
"context": context,
|
|
}
|
|
return generate_marketing_graphic("stats_card", data)
|
|
|
|
|
|
async def generate_pricing_card(tier_name: str, price: float, features: list[str]) -> dict:
|
|
"""Generate pricing tier card."""
|
|
data = {
|
|
"tier_name": tier_name,
|
|
"price": price,
|
|
"features_list": "\n".join(f"✓ {f}" for f in features),
|
|
}
|
|
return generate_marketing_graphic("pricing_card", data)
|
|
|
|
|
|
async def generate_launch_announcement(headline: str, subheadline: str) -> dict:
|
|
"""Generate launch announcement graphic."""
|
|
data = {
|
|
"headline": headline,
|
|
"subheadline": subheadline,
|
|
}
|
|
return generate_marketing_graphic("launch_announcement", data)
|
|
|
|
|
|
async def generate_testimonial_card(quote: str, author: str, title: str) -> dict:
|
|
"""Generate testimonial card."""
|
|
data = {
|
|
"quote": quote[:200],
|
|
"author": author,
|
|
"title": title,
|
|
}
|
|
return generate_marketing_graphic("testimonial_card", data)
|
|
|
|
|
|
# ── Template Management ──────────────────────────────────────
|
|
|
|
|
|
def list_marketing_templates() -> list[dict]:
|
|
"""List available marketing graphic templates."""
|
|
return [
|
|
{
|
|
"id": key,
|
|
"name": config["name"],
|
|
"size": f"{config['size'][0]}x{config['size'][1]}",
|
|
"use_cases": config.get("use_cases", []),
|
|
"exists": os.path.exists(os.path.join(MARKETING_TEMPLATE_DIR, f"{key}_template.png")),
|
|
}
|
|
for key, config in MARKETING_TEMPLATES.items()
|
|
]
|
|
|
|
|
|
def create_all_marketing_templates():
|
|
"""Create all placeholder marketing templates."""
|
|
for graphic_type, config in MARKETING_TEMPLATES.items():
|
|
try:
|
|
create_placeholder_marketing_template(graphic_type, config)
|
|
except Exception as e:
|
|
logger.error(f"Failed to create template for {graphic_type}: {e}")
|