Skip to content

[Feature] Add 'generate_caption' ability for AI-powered caption generation #8

@chubes4

Description

@chubes4

Overview

Add a generic, extensible caption generation ability that leverages AI/system agents to create platform-optimized captions from post content. This should be a reusable service that any social platform handler can call.

Goals

  1. Generic Architecture: Avoid hardcoding platform-specific logic; use configuration-driven approach
  2. Context-Aware: Generate captions based on post content, title, excerpt, and metadata
  3. Platform Constraints: Respect character limits, formatting rules, and best practices per platform
  4. Extensible: Easy to add new platforms or adjust generation parameters
  5. Agent-Ready: Works with Data Machine's AI conversation loop and abilities system

Proposed Implementation

New Ability: datamachine-socials/generate-caption

wp_register_ability('datamachine-socials/generate-caption', [
    'label' => 'Generate Social Media Caption',
    'description' => 'Generate platform-optimized caption from post content using AI',
    'category' => 'datamachine',
    'input_schema' => [
        'type' => 'object',
        'required' => ['content', 'platform'],
        'properties' => [
            'content' => [
                'type' => 'string',
                'description' => 'Source content to base caption on (post content, excerpt, etc.)',
            ],
            'platform' => [
                'type' => 'string', 
                'description' => 'Target platform: instagram, twitter, facebook, bluesky, threads, pinterest',
                'enum' => ['instagram', 'twitter', 'facebook', 'bluesky', 'threads', 'pinterest'],
            ],
            'title' => [
                'type' => 'string',
                'description' => 'Optional post title for context',
            ],
            'excerpt' => [
                'type' => 'string',
                'description' => 'Optional post excerpt',
            ],
            'source_url' => [
                'type' => 'string',
                'format' => 'uri',
                'description' => 'Optional source URL to include',
            ],
            'tone' => [
                'type' => 'string',
                'description' => 'Desired tone: professional, casual, enthusiastic, informative',
                'enum' => ['professional', 'casual', 'enthusiastic', 'informative'],
                'default' => 'casual',
            ],
            'include_hashtags' => [
                'type' => 'boolean',
                'description' => 'Whether to generate relevant hashtags',
                'default' => true,
            ],
            'max_hashtags' => [
                'type' => 'integer',
                'description' => 'Maximum number of hashtags to include',
                'default' => 5,
            ],
        ],
    ],
    'output_schema' => [
        'type' => 'object',
        'properties' => [
            'success' => ['type' => 'boolean'],
            'caption' => ['type' => 'string'],
            'original_length' => ['type' => 'integer'],
            'final_length' => ['type' => 'integer'],
            'truncated' => ['type' => 'boolean'],
            'platform' => ['type' => 'string'],
            'hashtags' => [
                'type' => 'array',
                'items' => ['type' => 'string'],
            ],
            'error' => ['type' => 'string'],
        ],
    ],
    'execute_callback' => [...],
    'permission_callback' => fn() => PermissionHelper::can_manage(),
]);

Platform Configuration Registry

Create inc/Services/PlatformConstraints.php with configurable constraints:

class PlatformConstraints {
    private static array $constraints = [
        'instagram' => [
            'char_limit' => 2200,
            'hashtag_limit' => 30,
            'supports_emojis' => true,
            'supports_mentions' => true,
            'supports_links' => false, // "link in bio" culture
            'best_practices' => [
                'optimal_length' => 138, // characters for feed view
                'line_breaks_ok' => true,
                'hashtag_placement' => 'end', // or 'inline'
            ],
        ],
        'twitter' => [
            'char_limit' => 280,
            'hashtag_limit' => null,
            'supports_emojis' => true,
            'supports_mentions' => true,
            'supports_links' => true,
            'best_practices' => [
                'optimal_length' => 71, // for engagement
                'line_breaks_ok' => false, // discouraged
                'hashtag_placement' => 'inline',
            ],
        ],
        'facebook' => [
            'char_limit' => 63206,
            'hashtag_limit' => null,
            'supports_emojis' => true,
            'supports_mentions' => true,
            'supports_links' => true,
            'best_practices' => [
                'optimal_length' => 40-80,
                'line_breaks_ok' => true,
                'hashtag_placement' => 'end',
            ],
        ],
        'bluesky' => [
            'char_limit' => 300,
            'hashtag_limit' => null,
            'supports_emojis' => true,
            'supports_mentions' => true,
            'supports_links' => true,
            'best_practices' => [
                'optimal_length' => 300,
                'line_breaks_ok' => true,
                'hashtag_placement' => 'inline',
            ],
        ],
        'threads' => [
            'char_limit' => 500,
            'hashtag_limit' => null,
            'supports_emojis' => true,
            'supports_mentions' => true,
            'supports_links' => true,
            'best_practices' => [
                'optimal_length' => 500,
                'line_breaks_ok' => true,
                'hashtag_placement' => 'inline',
            ],
        ],
        'pinterest' => [
            'char_limit' => 500,
            'hashtag_limit' => 20,
            'supports_emojis' => false, // generally discouraged
            'supports_mentions' => false,
            'supports_links' => true,
            'best_practices' => [
                'optimal_length' => 100-200,
                'line_breaks_ok' => false,
                'hashtag_placement' => 'end',
            ],
        ],
    ];
    
    public static function get(string $platform): array;
    public static function getCharLimit(string $platform): int;
    public static function getBestPractices(string $platform): array;
}

AI Integration Strategy

The ability should integrate with Data Machine's AI system. Options:

  1. Direct AI Call: Use existing AI conversation loop
  2. Tool-based: Register as a tool the AI can call
  3. Prompt Template: Use predefined prompts with variable substitution

Proposed approach: Use the AI system with a structured prompt:

$prompt = <<<PROMPT
Generate a {$tone} social media caption for {$platform} based on the following content:

Title: {$title}
Excerpt: {$excerpt}
Content: {$content}

Constraints:
- Maximum {$char_limit} characters
- Platform: {$platform}
- Include hashtags: {$include_hashtags} (max {$max_hashtags})
- Source URL to include: {$source_url}
- Best practices: {$best_practices}

Generate a caption that:
1. Captures the essence of the content
2. Engages the audience
3. Respects platform constraints
4. Includes relevant hashtags (if enabled)
5. Includes the source URL appropriately (if provided and platform supports it)

Return ONLY the caption text, no explanations.
PROMPT;

Usage Examples

Via REST API:

POST /wp-json/wp-abilities/v1/datamachine-socials/generate-caption/run
{
  "content": "This is my blog post about photography tips...",
  "platform": "instagram",
  "title": "10 Photography Tips for Beginners",
  "include_hashtags": true,
  "tone": "enthusiastic"
}

Via Handler:

$caption_data = GenerateCaptionAbility::execute([
  'content' => $post_content,
  'platform' => 'twitter',
  'source_url' => $permalink,
]);

if ($caption_data['success']) {
  $caption = $caption_data['caption'];
  // truncated = true if AI couldn't fit everything
}

Via Gutenberg (Phase 2):

  • "Generate Caption" button in sidebar
  • Auto-generate per-platform variants
  • Show character count preview
  • One-click regenerate

Benefits

  1. Fluid/Extensible: New platforms just need config entry, no code changes
  2. Reusable: Any handler can call this ability
  3. AI-Powered: Leverages Data Machine's AI capabilities
  4. Consistent: Same generation logic across all platforms
  5. Smart: Respects platform nuances automatically

Open Questions

  1. Should we cache generated captions to avoid repeated AI calls?
  2. Should we store multiple variants (one per platform) or generate on-demand?
  3. How do we handle rate limiting on AI calls?
  4. Should we allow custom prompt templates per site?

Dependencies

  • AI integration in Data Machine core
  • Phase 1 complete (Instagram handler migrated)

Related

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions