--- name: seo-multi-channel description: Generate multi-channel marketing content (Facebook, Ads, Blog, X) with Thai language support, image generation, and website-creator integration. Use when user wants to create content for multiple channels from a single topic. --- # 🎯 SEO Multi-Channel Content Generator **Skill Name:** `seo-multi-channel` **Category:** `deep` **Load Skills:** `['image-generation', 'image-edit', 'website-creator']` --- ## 🚀 Purpose Generate marketing content for multiple channels from a single topic with: - ✅ **Priority Channels:** Facebook > Facebook Ads > Google Ads > Blog > X (Twitter) - ✅ **Thai Language Support:** Full Thai text processing with PyThaiNLP - ✅ **Image Generation:** Auto-generate images for social/ads, save to website repo for blog - ✅ **Product Image Handling:** Browse website repo first, then ask user or enhance with image-edit - ✅ **Website-Creator Integration:** Auto-publish blog posts to Astro content collections - ✅ **API-Ready Output:** Structured JSON for future ad platform API integration - ✅ **Per-Project Context:** Context files in each website repo **Use Cases:** 1. **Multi-Channel Campaign:** One topic → Facebook post + Facebook Ads + Google Ads + Blog + X thread 2. **Social-Only:** Facebook post + Facebook Ads for product promotion 3. **Blog-First:** SEO blog post with auto-publish to website 4. **Ads-Only:** Google Ads + Facebook Ads copy for existing product --- ## 📋 Pre-Flight Questions **MUST ask before generating:** 1. **Topic/Subject:** What topic do you want content about? 2. **Channels Needed:** (Default: All channels) - Facebook (organic posts) - Facebook Ads (paid campaigns) - Google Ads (search campaigns) - Blog (SEO articles) - X/Twitter (threads) 3. **Content Type:** (Auto-detect or ask) - Product/Service (requires product images) - Knowledge/Educational (generates fresh images) - Statistics/Data (generates infographic-style images) - Announcement/News (may not need images) 4. **Target Language:** (Auto-detect from topic or ask) - Thai (default for Thai topics) - English - Bilingual (both Thai + English) 5. **For Product Content:** - Product name - Website repo path (to browse for existing images) - Product URL (if available) 6. **For Blog Posts:** - Target keyword for SEO - Should I auto-publish to website? (yes/no) - Website repo path (if auto-publish) 7. **Tone/Formality:** (Auto-detect from context or default) - กันเอง (Casual) - for social media - ปกติ (Normal) - for blog - เป็นทางการ (Formal) - for corporate --- ## 🔄 Workflow ### Phase 1: Context Loading 1. **Load Project Context:** - Read `context/brand-voice.md` from website repo - Read `context/target-keywords.md` - Read `context/seo-guidelines.md` - Auto-detect formality level from brand voice 2. **Check Data Services:** - Check if GA4 configured (skip if not) - Check if GSC configured (skip if not) - Check if DataForSEO configured (skip if not) - Check if Umami configured (skip if not) - Fetch available performance data 3. **Load Channel Templates:** - Load YAML templates for selected channels - Apply brand voice customizations --- ### Phase 2: Content Generation #### **For Each Channel:** **Facebook (Organic):** ```yaml Output: - primary_text: 125-250 chars (Thai can be longer) - headline: 100 chars max - hashtags: 3-5 recommended - cta: เลือกจาก ["เรียนรู้เพิ่มเติม", "สมัครเลย", "ซื้อเลย", "ดูรายละเอียด"] - image: Generated or edited - variations: 5 options ``` **Facebook Ads:** ```yaml Output: - primary_text: 125 chars recommended (5000 max) - headline: 40 chars - description: 90 chars - cta: Button choice - image: Product-focused or benefit-focused - variations: 5 options - api_ready: true (matches Meta Ads API structure) ``` **Google Ads:** ```yaml Output: - headlines: 15 variations (30 chars each) - descriptions: 4 variations (90 chars each) - keywords: Suggested keyword list - negative_keywords: Suggested negatives - ad_extensions: Sitelink, callout, structured snippets - api_ready: true (matches Google Ads API structure) ``` **Blog (SEO Article):** ```yaml Output: - markdown: Full article with frontmatter - word_count: 1500-3000 (Thai), 2000-3000 (English) - keyword_density: 1.0-1.5% (Thai), 1.5-2% (English) - meta_title: 50-60 chars - meta_description: 150-160 chars - slug: Auto-generated (Thai-friendly) - images: Saved to website repo - astro_ready: true (content collections format) ``` **X/Twitter Thread:** ```yaml Output: - tweets: 5-10 tweet thread - hook_tweet: First tweet (280 chars) - body_tweets: 2-8 tweets (280 chars each) - cta_tweet: Final tweet with CTA - hashtags: 2-3 per tweet - thread_title: Optional title card ``` --- ### Phase 3: Image Handling #### **Product Content:** ```python 1. Browse website repo for existing product images: - Search: public/images/, src/assets/, **/*{product_name}*.{jpg,png,webp} 2. If images found: - Select best image (highest quality, product-focused) - Call image-edit skill: prompt: "Enhance product image for {channel}, professional lighting, clean background, {channel}-specific dimensions" 3. If no images found: - Ask user: "No product images found in repo. Please provide image path or URL." - Wait for user to provide - Then call image-edit ``` #### **Non-Product Content:** ```python 1. Determine content type: - Service → Professional illustration - Knowledge → Educational visual metaphor - Stats → Infographic with charts - News → Clean, modern announcement style 2. Call image-generation skill: prompt: "{content_type} illustration for {topic}, {style}, Thai-friendly aesthetic, {channel}-optimized dimensions" 3. Save images: - Social/Ads → seo-multi-channel/generated-images/{topic}/{channel}/ - Blog → {website-repo}/public/images/blog/{slug}/ ``` --- ### Phase 4: Output & Publishing #### **Output Structure:** ``` output/{topic-slug}/ ├── facebook/ │ ├── posts.json │ └── images/ ├── facebook_ads/ │ ├── ads.json │ └── images/ ├── google_ads/ │ └── ads.json ├── blog/ │ ├── article.md │ └── images/ ├── x/ │ └── thread.json └── summary.json ``` #### **Auto-Publish Blog (if enabled):** ```python 1. Parse frontmatter from blog markdown 2. Detect language (Thai → 'th', English → 'en') 3. Generate slug (Thai-friendly: use transliteration or keep Thai) 4. Save to: {website-repo}/src/content/blog/({lang})/{slug}.md 5. Copy images to: {website-repo}/public/images/blog/{slug}/ 6. Git commit: git add . && git commit -m "Add blog post: {slug}" 7. Git push: git push origin main (triggers Easypanel auto-deploy) 8. Return deployment URL ``` --- ## 📁 Output Examples ### **Facebook Post Output:** ```json { "channel": "facebook", "topic": "บริการ podcast", "language": "th", "generated_at": "2026-03-08T14:30:00+07:00", "variations": [ { "id": "fb_post_1", "primary_text": "คุณกำลังมองหาวิธีเริ่มต้น podcast ใช่ไหม? 🎙️\n\nตอนนี้ใครๆ ก็ทำ podcast ได้ง่ายๆ แค่มีเครื่องมือที่เหมาะสม เราช่วยคุณได้ตั้งแต่เริ่มจนถึงเผยแพร่\n\n#podcast #podcastไทย #สร้างpodcast", "headline": "เริ่มต้น podcast ของคุณวันนี้", "cta": "เรียนรู้เพิ่มเติม", "hashtags": ["#podcast", "#podcastไทย", "#สร้างpodcast"], "image": { "type": "generated", "path": "output/บริการ-podcast/facebook/images/variation_1.png", "prompt": "Professional podcast studio setup with microphone and headphones, modern aesthetic, Thai-friendly design" }, "api_ready": { "message": "Matches Meta Graph API /act_id/adcreatives structure", "endpoint": "POST /v18.0/act_{ad_account_id}/adcreatives" } } ] } ``` ### **Google Ads Output:** ```json { "channel": "google_ads", "topic": "podcast hosting", "language": "th", "generated_at": "2026-03-08T14:30:00+07:00", "responsive_search_ads": [ { "id": "ga_rsa_1", "headlines": [ {"text": "บริการ Podcast Hosting", "pin": false}, {"text": "เริ่มต้นฟรี 14 วัน", "pin": false}, {"text": "เผยแพร่ทุกแพลตฟอร์ม", "pin": false}, {"text": "ง่าย รวดเร็ว มืออาชีพ", "pin": false}, {"text": "รองรับภาษาไทย", "pin": false} ], "descriptions": [ {"text": "แพลตฟอร์ม podcast ที่ครบวงจรที่สุด เริ่มต้นสร้าง podcast ของคุณวันนี้"}, {"text": "เผยแพร่ Apple Podcasts, Spotify, YouTube Music ได้ในคลิกเดียว"} ], "keywords": ["podcast hosting", "host podcast", "บริการ podcast", "แพลตฟอร์ม podcast"], "negative_keywords": ["ฟรี", "download", "mp3"], "ad_extensions": { "sitelinks": [ {"text": "เริ่มฟรี 14 วัน", "url": "/free-trial"}, {"text": "ดูคุณสมบัติ", "url": "/features"} ], "callouts": ["รองรับภาษาไทย", "ทีมซัพพอร์ท 24/7", "ยกเลิกเมื่อไหร่ก็ได้"] }, "api_ready": { "matches": "Google Ads API v15.0", "endpoint": "POST /google.ads.googleads.v15.services/GoogleAdsService:Mutate", "resource": "AdGroupAd" } } ] } ``` ### **Blog Post Output:** ```markdown --- title: "บริการ Podcast Hosting ที่ดีที่สุดปี 2026: คู่มือครบวงจร" description: "เปรียบเทียบ 10+ บริการ podcast hosting พร้อมข้อมูลจริง ช่วยคุณเลือกแพลตฟอร์มที่เหมาะกับ podcast ของคุณ" keywords: ["podcast hosting", "บริการ podcast", "แพลตฟอร์ม podcast", "host podcast"] slug: podcast-hosting-best-2026 lang: th category: guides tags: [podcast, hosting, review] created: 2026-03-08 images: - src: /images/blog/podcast-hosting-best-2026/hero.png alt: "เปรียบเทียบบริการ podcast hosting" --- # บริการ Podcast Hosting ที่ดีที่สุดในปี 2026 คุณกำลังมองหาบริการ podcast hosting ที่ใช่อยู่ใช่ไหม? 🎙️ บทความนี้จะเปรียบเทียบแพลตฟอร์มยอดนิยม 10+ เจ้า พร้อมข้อมูลจริงจากการทดสอบ... [Content continues for 2000+ words] ## สรุป เลือกบริการ podcast hosting ที่เหมาะกับคุณที่สุด... **พร้อมเริ่ม podcast ของคุณหรือยัง?** [สมัครฟรี 14 วัน →](/signup) ``` --- ## 🔧 Technical Implementation ### **Thai Language Processing:** ```python from pythainlp import word_tokenize, sent_tokenize from pythainlp.util import normalize def count_thai_words(text: str) -> int: """Count Thai words (no spaces between words)""" tokens = word_tokenize(text, engine="newmm") return len([t for t in tokens if t.strip() and not t.isspace()]) def calculate_thai_keyword_density(text: str, keyword: str) -> float: """Calculate keyword density for Thai text""" text_normalized = normalize(text) keyword_normalized = normalize(keyword) count = text_normalized.count(keyword_normalized) word_count = count_thai_words(text) return (count / word_count * 100) if word_count > 0 else 0 def detect_content_language(text: str) -> str: """Detect if content is Thai or English""" thai_chars = sum(1 for c in text if '\u0E00' <= c <= '\u0E7F') total_chars = len(text) thai_ratio = thai_chars / total_chars if total_chars > 0 else 0 if thai_ratio > 0.3: return 'th' return 'en' ``` ### **Image Handling:** ```python import os import glob from pathlib import Path def find_product_images(product_name: str, website_repo: str) -> List[str]: """Find existing product images in website repo""" extensions = ['.jpg', '.jpeg', '.png', '.webp'] found_images = [] search_patterns = [ f"**/*{product_name}*{{ext}}" for ext in extensions ] + [ f"public/images/**/*{{ext}}", f"src/assets/**/*{{ext}}" ] for pattern in search_patterns: matches = glob.glob(os.path.join(website_repo, pattern), recursive=True) found_images.extend(matches) return found_images[:10] # Return top 10 matches def save_image_for_channel(image_data: bytes, topic: str, channel: str) -> str: """Save generated/edited image to correct location""" if channel == 'blog': # Blog images go to website repo output_dir = os.path.join(website_repo, 'public/images/blog', topic_slug) else: # Social/Ads images go to separate folder output_dir = os.path.join('output', topic_slug, channel, 'images') os.makedirs(output_dir, exist_ok=True) image_path = os.path.join(output_dir, f"variation_{variation_num}.png") with open(image_path, 'wb') as f: f.write(image_data) return image_path ``` ### **Website-Creator Integration:** ```python def publish_blog_to_astro(article_md: str, website_repo: str) -> Dict: """ Publish blog post to Astro content collections Returns deployment status """ # Parse frontmatter frontmatter = parse_frontmatter(article_md) # Detect language lang = detect_content_language(article_md) # Generate slug slug = generate_slug(frontmatter['title'], lang) # Determine output path output_path = os.path.join( website_repo, 'src/content/blog', f'({lang})', f'{slug}.md' ) # Ensure directory exists os.makedirs(os.path.dirname(output_path), exist_ok=True) # Write article with open(output_path, 'w', encoding='utf-8') as f: f.write(article_md) # Copy images if any if 'images' in frontmatter: for img in frontmatter['images']: # Copy from temp location to website repo dest_path = os.path.join(website_repo, 'public', img['src'].lstrip('/')) os.makedirs(os.path.dirname(dest_path), exist_ok=True) shutil.copy(img['local_path'], dest_path) # Git commit and push subprocess.run(['git', 'add', '.'], cwd=website_repo, check=True) subprocess.run(['git', 'commit', '-m', f'Add blog post: {slug}'], cwd=website_repo, check=True) subprocess.run(['git', 'push', 'origin', 'main'], cwd=website_repo, check=True) # Return deployment info return { 'published': True, 'slug': slug, 'language': lang, 'path': output_path, 'deployment_url': f"https://your-domain.com/blog/{slug}" if lang == 'en' else f"https://your-domain.com/th/{slug}" } ``` --- ## 📐 Channel Specifications ### **Facebook:** - Primary text: 125-250 chars (Thai can be longer) - Headline: 100 chars max - Hashtags: 3-5 recommended - Image: 1200x630 (1.91:1) - Variations: 5 ### **Facebook Ads:** - Primary text: 125 chars recommended (5000 max) - Headline: 40 chars - Description: 90 chars - CTA: Button selection - Image: 1200x628 (1.91:1) or 1080x1080 (1:1) - API ready: Yes (Meta Graph API) ### **Google Ads:** - Headlines: 15 variations, 30 chars each - Descriptions: 4 variations, 90 chars each - Keywords: 15-20 suggested - Negative keywords: 10-15 suggested - Ad extensions: Sitelinks, callouts, structured snippets - API ready: Yes (Google Ads API) ### **Blog:** - Word count: 1500-3000 (Thai), 2000-3000 (English) - Keyword density: 1.0-1.5% (Thai), 1.5-2% (English) - Meta title: 50-60 chars - Meta description: 150-160 chars - Images: Saved to website repo - Format: Markdown with frontmatter - Astro ready: Yes (content collections) ### **X/Twitter:** - Hook tweet: 280 chars - Body tweets: 2-8 tweets, 280 chars each - CTA tweet: 280 chars - Hashtags: 2-3 per tweet - Thread title: Optional --- ## ⚙️ Environment Variables **Required (in unified .env or project .env):** ```bash # Chutes AI (for image generation/editing) CHUTES_API_TOKEN=your_token_here # Google Analytics 4 (optional) GA4_PROPERTY_ID=G-XXXXXXXXXX GA4_CREDENTIALS_PATH=path/to/ga4-credentials.json # Google Search Console (optional) GSC_SITE_URL=https://yourdomain.com GSC_CREDENTIALS_PATH=path/to/gsc-credentials.json # DataForSEO (optional) DATAFORSEO_LOGIN=your_login DATAFORSEO_PASSWORD=your_password # Umami Analytics (optional, if self-hosted) UMAMI_API_URL=https://analytics.yourdomain.com UMAMI_API_KEY=your_api_key ``` --- ## 🚀 Commands ### **Generate Multi-Channel Content:** ```bash python3 skills/seo-multi-channel/scripts/generate_content.py \ --topic "บริการ podcast hosting" \ --channels facebook facebook_ads google_ads blog x \ --website-repo ./my-website \ --auto-publish true ``` ### **Generate for Specific Channel:** ```bash # Facebook Ads only python3 skills/seo-multi-channel/scripts/generate_content.py \ --topic "podcast microphone" \ --channels facebook_ads \ --product-name "PodMic Pro" \ --website-repo ./my-website ``` ### **Publish Existing Blog:** ```bash python3 skills/seo-multi-channel/scripts/publish_blog.py \ --article drafts/podcast-guide-2026.md \ --website-repo ./my-website ``` --- ## 📊 Quality Scoring Each piece of content is scored before output: 1. **Keyword Optimization** (0-25 points) - Density, placement, variations 2. **Brand Voice Alignment** (0-25 points) - Tone, terminology, style 3. **Channel Fit** (0-25 points) - Length, format, CTA appropriateness 4. **Thai Language Quality** (0-25 points) - Natural phrasing, formality level, no awkward translations **Minimum score: 70/100** to publish. Below 70 → auto-revise or flag for review. --- ## ⚠️ Important Notes 1. **Thai Word Counting:** Thai has no spaces between words. Uses PyThaiNLP for accurate counting. 2. **Formality Detection:** Auto-detects from brand voice context. Defaults to casual for social, normal for blog. 3. **Image Handling:** - Product content → Browse repo first → Edit with image-edit - Non-product → Generate fresh with image-generation - Blog images → Website repo - Social/Ads images → Separate folder 4. **API Ready:** Output structures match Google Ads and Meta Ads API schemas for future integration. 5. **Data Services Optional:** Skips unconfigured services (GA4, GSC, DataForSEO, Umami). 6. **Per-Project Context:** Each website has its own context/ folder with brand voice, keywords, guidelines. --- ## 🔄 Integration with Other Skills - **image-generation:** Called for fresh images (non-product content) - **image-edit:** Called for product images (browse repo first) - **website-creator:** Blog posts published to Astro content collections - **seo-analyzers:** Quality scoring and Thai language analysis - **seo-data:** Performance data for content optimization - **seo-context:** Context file management --- ## ✅ Success Criteria - ✅ Content generated for all selected channels - ✅ Thai language processing accurate (word count, keyword density) - ✅ Product images found/enhanced or user asked to provide - ✅ Fresh images generated for non-product content - ✅ Blog posts published to Astro (if enabled) - ✅ Git commit + push successful (triggers auto-deploy) - ✅ Output structures API-ready for future integration - ✅ Quality scores ≥ 70/100 for all content --- **Use this skill when you need to create multi-channel marketing content from a single topic with full Thai language support and automatic image handling.**