ALwrity Facebook Writer CopilotKit Implementation Plan

This commit is contained in:
ajaysi
2025-08-31 18:41:07 +05:30
parent 66c14e158c
commit eb0789321d
11 changed files with 2116 additions and 206 deletions

View File

@@ -30,10 +30,27 @@ class StoryTone(str, Enum):
class StoryVisualOptions(BaseModel):
"""Visual options for story."""
background_type: str = Field(default="Solid color", description="Background type")
# Background layer
background_type: str = Field(default="Solid color", description="Background type (Solid color, Gradient, Image, Video)")
background_image_prompt: Optional[str] = Field(None, description="If background_type is Image/Video, describe desired visual")
gradient_style: Optional[str] = Field(None, description="Gradient style if gradient background is chosen")
# Text overlay styling
text_overlay: bool = Field(default=True, description="Include text overlay")
text_style: Optional[str] = Field(None, description="Headline/Subtext style, e.g., Bold, Minimal, Handwritten")
text_color: Optional[str] = Field(None, description="Preferred text color or palette")
text_position: Optional[str] = Field(None, description="Top/Center/Bottom; Left/Center/Right")
# Embellishments and interactivity
stickers: bool = Field(default=True, description="Use stickers/emojis")
interactive_elements: bool = Field(default=True, description="Include polls/questions")
interactive_types: Optional[List[str]] = Field(
default=None,
description="List of interactive types like ['poll','quiz','slider','countdown']"
)
# CTA overlay
call_to_action: Optional[str] = Field(None, description="Optional CTA copy to place on story")
class FacebookStoryRequest(BaseModel):
@@ -47,12 +64,20 @@ class FacebookStoryRequest(BaseModel):
include: Optional[str] = Field(None, description="Elements to include in the story")
avoid: Optional[str] = Field(None, description="Elements to avoid in the story")
visual_options: StoryVisualOptions = Field(default_factory=StoryVisualOptions, description="Visual customization options")
# Advanced text generation options (parity with original Streamlit module)
use_hook: bool = Field(default=True, description="Start with a hook to grab attention")
use_story: bool = Field(default=True, description="Use a short narrative arc")
use_cta: bool = Field(default=True, description="Include a call to action")
use_question: bool = Field(default=True, description="Ask a question to spur interaction")
use_emoji: bool = Field(default=True, description="Use emojis where appropriate")
use_hashtags: bool = Field(default=True, description="Include relevant hashtags in copy")
class FacebookStoryResponse(BaseModel):
"""Response model for Facebook story generation."""
success: bool = Field(..., description="Whether the generation was successful")
content: Optional[str] = Field(None, description="Generated story content")
images_base64: Optional[List[str]] = Field(None, description="List of base64-encoded story images (PNG)")
visual_suggestions: Optional[List[str]] = Field(None, description="Visual element suggestions")
engagement_tips: Optional[List[str]] = Field(None, description="Engagement optimization tips")
error: Optional[str] = Field(None, description="Error message if generation failed")

View File

@@ -2,6 +2,7 @@
from typing import Dict, Any, List
from ..models import *
from ..models.carousel_models import CarouselSlide
from .base_service import FacebookWriterBaseService

View File

@@ -3,6 +3,12 @@
from typing import Dict, Any, List
from ..models.story_models import FacebookStoryRequest, FacebookStoryResponse
from .base_service import FacebookWriterBaseService
try:
from ...services.llm_providers.text_to_image_generation.gen_gemini_images import (
generate_gemini_images_base64,
)
except Exception:
generate_gemini_images_base64 = None # type: ignore
class FacebookStoryService(FacebookWriterBaseService):
@@ -38,10 +44,28 @@ class FacebookStoryService(FacebookWriterBaseService):
# Generate visual suggestions and engagement tips
visual_suggestions = self._generate_visual_suggestions(actual_story_type, request.visual_options)
engagement_tips = self._generate_engagement_tips("story")
# Optional: generate one story image (9:16) using Gemini
images_base64: List[str] = []
try:
if generate_gemini_images_base64 is not None:
img_prompt = request.visual_options.background_image_prompt or (
f"Facebook story background for {request.business_type}. "
f"Style: {actual_tone}. Type: {actual_story_type}. Vertical mobile 9:16, high contrast, legible overlay space."
)
images_base64 = generate_gemini_images_base64(
img_prompt,
enhance_prompt=False,
aspect_ratio="9:16",
max_retries=2,
initial_retry_delay=1.0,
) or []
except Exception:
images_base64 = []
return FacebookStoryResponse(
success=True,
content=content,
images_base64=images_base64[:1],
visual_suggestions=visual_suggestions,
engagement_tips=engagement_tips,
metadata={
@@ -75,6 +99,28 @@ class FacebookStoryService(FacebookWriterBaseService):
f"Create a {story_type} story"
)
# Advanced writing flags
advanced_lines = []
if getattr(request, "use_hook", True):
advanced_lines.append("- Start with a compelling hook in the first line")
if getattr(request, "use_story", True):
advanced_lines.append("- Use a mini narrative with a clear flow")
if getattr(request, "use_cta", True):
cta_text = request.visual_options.call_to_action or "Add a clear call-to-action"
advanced_lines.append(f"- Include a CTA: {cta_text}")
if getattr(request, "use_question", True):
advanced_lines.append("- Ask a question to prompt replies or taps")
if getattr(request, "use_emoji", True):
advanced_lines.append("- Use a few relevant emojis for tone and scannability")
if getattr(request, "use_hashtags", True):
advanced_lines.append("- Include 1-3 relevant hashtags if appropriate")
advanced_str = "\n".join(advanced_lines)
# Visual details
v = request.visual_options
interactive_types_str = ", ".join(v.interactive_types) if v.interactive_types else "None specified"
prompt = f"""
{base_prompt}
@@ -86,12 +132,20 @@ class FacebookStoryService(FacebookWriterBaseService):
Content Requirements:
- Include: {request.include or 'N/A'}
- Avoid: {request.avoid or 'N/A'}
{('\n' + advanced_str) if advanced_str else ''}
Visual Options:
- Background Type: {request.visual_options.background_type}
- Text Overlay: {request.visual_options.text_overlay}
- Stickers/Emojis: {request.visual_options.stickers}
- Interactive Elements: {request.visual_options.interactive_elements}
- Background Type: {v.background_type}
- Background Visual Prompt: {v.background_image_prompt or 'N/A'}
- Gradient Style: {v.gradient_style or 'N/A'}
- Text Overlay: {v.text_overlay}
- Text Style: {v.text_style or 'N/A'}
- Text Color: {v.text_color or 'N/A'}
- Text Position: {v.text_position or 'N/A'}
- Stickers/Emojis: {v.stickers}
- Interactive Elements: {v.interactive_elements}
- Interactive Types: {interactive_types_str}
- Call To Action: {v.call_to_action or 'N/A'}
Please create a Facebook Story that:
1. Is optimized for mobile viewing (vertical format)
@@ -137,14 +191,28 @@ class FacebookStoryService(FacebookWriterBaseService):
])
# Add general suggestions based on visual options
if visual_options.text_overlay:
if getattr(visual_options, "text_overlay", True):
suggestions.append("Use bold, readable fonts for text overlays")
if visual_options.stickers:
if getattr(visual_options, "text_style", None):
suggestions.append(f"Match text style to tone: {visual_options.text_style}")
if getattr(visual_options, "text_color", None):
suggestions.append(f"Ensure sufficient contrast with text color: {visual_options.text_color}")
if getattr(visual_options, "text_position", None):
suggestions.append(f"Place text at {visual_options.text_position} to avoid occluding subject")
if getattr(visual_options, "stickers", True):
suggestions.append("Add relevant emojis and stickers to increase engagement")
if visual_options.interactive_elements:
if getattr(visual_options, "interactive_elements", True):
suggestions.append("Include polls, questions, or swipe-up actions")
if getattr(visual_options, "interactive_types", None):
suggestions.append(f"Try interactive types: {', '.join(visual_options.interactive_types)}")
if getattr(visual_options, "background_type", None) in {"Image", "Video"} and getattr(visual_options, "background_image_prompt", None):
suggestions.append("Source visuals based on background prompt for consistency")
if getattr(visual_options, "call_to_action", None):
suggestions.append(f"Overlay CTA copy near focal point: {visual_options.call_to_action}")
return suggestions