Base code

This commit is contained in:
Kunthawat Greethong
2026-01-08 22:39:53 +07:00
parent 697115c61a
commit c35fa52117
2169 changed files with 626670 additions and 0 deletions

View File

@@ -0,0 +1,29 @@
"""Facebook Writer Services."""
from .base_service import FacebookWriterBaseService
from .post_service import FacebookPostService
from .story_service import FacebookStoryService
from .ad_copy_service import FacebookAdCopyService
from .remaining_services import (
FacebookReelService,
FacebookCarouselService,
FacebookEventService,
FacebookHashtagService,
FacebookEngagementService,
FacebookGroupPostService,
FacebookPageAboutService
)
__all__ = [
"FacebookWriterBaseService",
"FacebookPostService",
"FacebookStoryService",
"FacebookReelService",
"FacebookCarouselService",
"FacebookEventService",
"FacebookHashtagService",
"FacebookEngagementService",
"FacebookGroupPostService",
"FacebookPageAboutService",
"FacebookAdCopyService"
]

View File

@@ -0,0 +1,350 @@
"""Facebook Ad Copy generation service."""
from typing import Dict, Any, List
from ..models.ad_copy_models import (
FacebookAdCopyRequest,
FacebookAdCopyResponse,
AdCopyVariations,
AdPerformancePredictions
)
from .base_service import FacebookWriterBaseService
class FacebookAdCopyService(FacebookWriterBaseService):
"""Service for generating Facebook ad copy."""
def generate_ad_copy(self, request: FacebookAdCopyRequest) -> FacebookAdCopyResponse:
"""
Generate Facebook ad copy based on the request parameters.
Args:
request: FacebookAdCopyRequest containing all the parameters
Returns:
FacebookAdCopyResponse with the generated content
"""
try:
# Determine actual values
actual_objective = request.custom_objective if request.ad_objective.value == "Custom" else request.ad_objective.value
actual_budget = request.custom_budget if request.budget_range.value == "Custom" else request.budget_range.value
actual_age = request.targeting_options.custom_age if request.targeting_options.age_group.value == "Custom" else request.targeting_options.age_group.value
# Generate primary ad copy
primary_copy = self._generate_primary_ad_copy(request, actual_objective, actual_age)
# Generate variations for A/B testing
variations = self._generate_ad_variations(request, actual_objective, actual_age)
# Generate performance predictions
performance = self._generate_performance_predictions(request, actual_budget)
# Generate suggestions and tips
targeting_suggestions = self._generate_targeting_suggestions(request)
creative_suggestions = self._generate_creative_suggestions(request)
optimization_tips = self._generate_optimization_tips(request)
compliance_notes = self._generate_compliance_notes(request)
budget_recommendations = self._generate_budget_recommendations(request, actual_budget)
return FacebookAdCopyResponse(
success=True,
primary_ad_copy=primary_copy,
ad_variations=variations,
targeting_suggestions=targeting_suggestions,
creative_suggestions=creative_suggestions,
performance_predictions=performance,
optimization_tips=optimization_tips,
compliance_notes=compliance_notes,
budget_recommendations=budget_recommendations,
metadata={
"business_type": request.business_type,
"objective": actual_objective,
"format": request.ad_format.value,
"budget": actual_budget
}
)
except Exception as e:
return FacebookAdCopyResponse(
**self._handle_error(e, "Facebook ad copy generation")
)
def _generate_primary_ad_copy(self, request: FacebookAdCopyRequest, objective: str, age_group: str) -> Dict[str, str]:
"""Generate the primary ad copy."""
prompt = f"""
Create a high-converting Facebook ad copy for:
Business: {request.business_type}
Product/Service: {request.product_service}
Objective: {objective}
Format: {request.ad_format.value}
Target Audience: {request.target_audience}
Age Group: {age_group}
Unique Selling Proposition: {request.unique_selling_proposition}
Offer Details: {request.offer_details or 'No specific offer'}
Brand Voice: {request.brand_voice or 'Professional and engaging'}
Targeting Details:
- Location: {request.targeting_options.location or 'Not specified'}
- Interests: {request.targeting_options.interests or 'Not specified'}
- Behaviors: {request.targeting_options.behaviors or 'Not specified'}
Create ad copy with:
1. Compelling headline (25 characters max)
2. Primary text (125 characters max for optimal performance)
3. Description (27 characters max)
4. Strong call-to-action
Make it conversion-focused and compliant with Facebook ad policies.
"""
try:
schema = {
"type": "object",
"properties": {
"headline": {"type": "string"},
"primary_text": {"type": "string"},
"description": {"type": "string"},
"call_to_action": {"type": "string"}
}
}
response = self._generate_structured_response(prompt, schema, temperature=0.6)
if isinstance(response, dict) and not response.get('error'):
return response
else:
# Fallback to text generation
content = self._generate_text(prompt, temperature=0.6)
return self._parse_ad_copy_from_text(content)
except Exception:
# Fallback to text generation
content = self._generate_text(prompt, temperature=0.6)
return self._parse_ad_copy_from_text(content)
def _generate_ad_variations(self, request: FacebookAdCopyRequest, objective: str, age_group: str) -> AdCopyVariations:
"""Generate multiple variations for A/B testing."""
prompt = f"""
Create 3 variations each of headlines, primary text, descriptions, and CTAs for Facebook ads targeting:
Business: {request.business_type}
Product/Service: {request.product_service}
Objective: {objective}
Target: {request.target_audience} ({age_group})
USP: {request.unique_selling_proposition}
Create variations that test different approaches:
- Emotional vs. Logical appeals
- Benefit-focused vs. Feature-focused
- Urgency vs. Value-driven
Format as lists of 3 items each.
"""
try:
schema = {
"type": "object",
"properties": {
"headline_variations": {
"type": "array",
"items": {"type": "string"}
},
"primary_text_variations": {
"type": "array",
"items": {"type": "string"}
},
"description_variations": {
"type": "array",
"items": {"type": "string"}
},
"cta_variations": {
"type": "array",
"items": {"type": "string"}
}
}
}
response = self._generate_structured_response(prompt, schema, temperature=0.7)
if isinstance(response, dict) and not response.get('error'):
return AdCopyVariations(**response)
else:
return self._create_default_variations()
except Exception:
return self._create_default_variations()
def _generate_performance_predictions(self, request: FacebookAdCopyRequest, budget: str) -> AdPerformancePredictions:
"""Generate performance predictions based on budget and targeting."""
# Simple logic based on budget and audience size
if "Small" in budget or "$10-50" in budget:
reach = "1K-5K"
ctr = "1.2-2.5%"
cpc = "$0.75-1.50"
conversions = "15-40"
score = "Good"
elif "Medium" in budget or "$50-200" in budget:
reach = "5K-20K"
ctr = "1.5-3.0%"
cpc = "$0.50-1.00"
conversions = "50-150"
score = "Very Good"
else:
reach = "20K-100K"
ctr = "2.0-4.0%"
cpc = "$0.30-0.80"
conversions = "200-800"
score = "Excellent"
return AdPerformancePredictions(
estimated_reach=reach,
estimated_ctr=ctr,
estimated_cpc=cpc,
estimated_conversions=conversions,
optimization_score=score
)
def _generate_targeting_suggestions(self, request: FacebookAdCopyRequest) -> List[str]:
"""Generate additional targeting suggestions."""
suggestions = []
if request.targeting_options.interests:
suggestions.append("Consider expanding interests to related categories")
if request.targeting_options.lookalike_audience:
suggestions.append("Test lookalike audiences at 1%, 2%, and 5% similarity")
suggestions.extend([
"Add behavioral targeting based on purchase intent",
"Consider excluding recent customers to focus on new prospects",
"Test custom audiences from website visitors",
"Use demographic targeting refinements"
])
return suggestions
def _generate_creative_suggestions(self, request: FacebookAdCopyRequest) -> List[str]:
"""Generate creative and visual suggestions."""
suggestions = []
if request.ad_format.value == "Single image":
suggestions.extend([
"Use high-quality, eye-catching visuals",
"Include product in lifestyle context",
"Test different color schemes"
])
elif request.ad_format.value == "Carousel":
suggestions.extend([
"Show different product angles or features",
"Tell a story across carousel cards",
"Include customer testimonials"
])
elif request.ad_format.value == "Single video":
suggestions.extend([
"Keep video under 15 seconds for best performance",
"Include captions for sound-off viewing",
"Start with attention-grabbing first 3 seconds"
])
suggestions.extend([
"Ensure mobile-first design approach",
"Include social proof elements",
"Test user-generated content"
])
return suggestions
def _generate_optimization_tips(self, request: FacebookAdCopyRequest) -> List[str]:
"""Generate optimization tips."""
return [
"Test different ad placements (feed, stories, reels)",
"Use automatic placements initially, then optimize",
"Monitor frequency and refresh creative if >3",
"A/B test audiences with 70% overlap maximum",
"Set up conversion tracking for accurate measurement",
"Use broad targeting to leverage Facebook's AI",
"Schedule ads for peak audience activity times"
]
def _generate_compliance_notes(self, request: FacebookAdCopyRequest) -> List[str]:
"""Generate compliance and policy notes."""
notes = [
"Ensure all claims are substantiated and truthful",
"Avoid excessive capitalization or punctuation",
"Don't use misleading or exaggerated language"
]
if "health" in request.business_type.lower() or "fitness" in request.business_type.lower():
notes.extend([
"Health claims require proper disclaimers",
"Avoid before/after images without context"
])
if "finance" in request.business_type.lower():
notes.extend([
"Financial services ads require additional compliance",
"Include proper risk disclosures"
])
return notes
def _generate_budget_recommendations(self, request: FacebookAdCopyRequest, budget: str) -> List[str]:
"""Generate budget allocation recommendations."""
recommendations = [
"Start with automatic bidding for optimal results",
"Set daily budget 5-10x your target CPA",
"Allow 3-7 days for Facebook's learning phase"
]
if "Small" in budget:
recommendations.extend([
"Focus on one audience segment initially",
"Use conversion optimization once you have 50+ conversions/week"
])
else:
recommendations.extend([
"Split budget across 2-3 audience segments",
"Allocate 70% to best-performing ads",
"Reserve 30% for testing new creative"
])
return recommendations
def _parse_ad_copy_from_text(self, content: str) -> Dict[str, str]:
"""Parse ad copy components from generated text."""
# Basic parsing - in production, you'd want more sophisticated parsing
lines = content.split('\n')
return {
"headline": "Discover Amazing Results Today!",
"primary_text": "Transform your life with our proven solution. Join thousands of satisfied customers who've seen incredible results.",
"description": "Limited time offer - Act now!",
"call_to_action": "Learn More"
}
def _create_default_variations(self) -> AdCopyVariations:
"""Create default variations as fallback."""
return AdCopyVariations(
headline_variations=[
"Get Results Fast",
"Transform Your Life",
"Limited Time Offer"
],
primary_text_variations=[
"Join thousands who've achieved success",
"Discover the solution you've been looking for",
"Don't miss out on this opportunity"
],
description_variations=[
"Act now - limited time",
"Free trial available",
"Money-back guarantee"
],
cta_variations=[
"Learn More",
"Get Started",
"Claim Offer"
]
)

View File

@@ -0,0 +1,281 @@
"""Base service for Facebook Writer functionality."""
import os
import sys
from pathlib import Path
from typing import Dict, Any, Optional
from loguru import logger
# Add the backend path to sys.path to import services
backend_path = Path(__file__).parent.parent.parent.parent
sys.path.append(str(backend_path))
from services.llm_providers.gemini_provider import gemini_text_response, gemini_structured_json_response
from services.persona_analysis_service import PersonaAnalysisService
from typing import Dict, Any, Optional
import time
class FacebookWriterBaseService:
"""Base service class for Facebook Writer functionality."""
def __init__(self):
"""Initialize the base service."""
self.logger = logger
self.persona_service = PersonaAnalysisService()
# Persona caching
self._persona_cache: Dict[str, Dict[str, Any]] = {}
self._cache_timestamps: Dict[str, float] = {}
self._cache_duration = 300 # 5 minutes cache duration
def _generate_text(self, prompt: str, temperature: float = 0.7, max_tokens: int = 2048) -> str:
"""
Generate text using Gemini provider.
Args:
prompt: The prompt to send to the AI
temperature: Control randomness of output
max_tokens: Maximum tokens in response
Returns:
Generated text response
"""
try:
response = gemini_text_response(
prompt=prompt,
temperature=temperature,
top_p=0.9,
n=40,
max_tokens=max_tokens,
system_prompt=None
)
return response
except Exception as e:
self.logger.error(f"Error generating text: {e}")
raise
def _generate_structured_response(
self,
prompt: str,
schema: Dict[str, Any],
temperature: float = 0.3,
max_tokens: int = 8192
) -> Dict[str, Any]:
"""
Generate structured JSON response using Gemini provider.
Args:
prompt: The prompt to send to the AI
schema: JSON schema for structured output
temperature: Control randomness (lower for structured output)
max_tokens: Maximum tokens in response
Returns:
Structured JSON response
"""
try:
response = gemini_structured_json_response(
prompt=prompt,
schema=schema,
temperature=temperature,
top_p=0.9,
top_k=40,
max_tokens=max_tokens,
system_prompt=None
)
return response
except Exception as e:
self.logger.error(f"Error generating structured response: {e}")
raise
def _build_base_prompt(self, business_type: str, target_audience: str, purpose: str) -> str:
"""
Build a base prompt for Facebook content generation.
Args:
business_type: Type of business
target_audience: Target audience description
purpose: Purpose or goal of the content
Returns:
Base prompt string
"""
return f"""
You are an expert Facebook content creator specializing in creating engaging, high-performing social media content.
Business Context:
- Business Type: {business_type}
- Target Audience: {target_audience}
- Content Purpose: {purpose}
Create content that:
1. Resonates with the target audience
2. Aligns with Facebook's best practices
3. Encourages engagement and interaction
4. Maintains a professional yet approachable tone
5. Includes relevant calls-to-action when appropriate
"""
def _create_analytics_prediction(self) -> Dict[str, str]:
"""
Create default analytics predictions.
Returns:
Dictionary with analytics predictions
"""
return {
"expected_reach": "2.5K - 5K",
"expected_engagement": "5-8%",
"best_time_to_post": "2 PM - 4 PM"
}
def _create_optimization_suggestions(self, content_type: str = "post") -> list:
"""
Create default optimization suggestions.
Args:
content_type: Type of content being optimized
Returns:
List of optimization suggestions
"""
base_suggestions = [
"Consider adding a question to increase comments",
"Use more emojis to increase visibility",
"Keep paragraphs shorter for better readability"
]
if content_type == "post":
base_suggestions.append("Add a poll to increase engagement")
elif content_type == "story":
base_suggestions.append("Include interactive stickers")
elif content_type == "reel":
base_suggestions.append("Use trending music for better reach")
return base_suggestions
def _get_persona_data(self, user_id: int = 1) -> Optional[Dict[str, Any]]:
"""
Get persona data for Facebook platform with caching.
Args:
user_id: User ID to get persona for
Returns:
Persona data or None if not available
"""
cache_key = f"facebook_persona_{user_id}"
current_time = time.time()
# Check cache first
if cache_key in self._persona_cache and cache_key in self._cache_timestamps:
cache_age = current_time - self._cache_timestamps[cache_key]
if cache_age < self._cache_duration:
self.logger.debug(f"Using cached persona data for user {user_id} (age: {cache_age:.1f}s)")
return self._persona_cache[cache_key]
else:
# Cache expired, remove it
self.logger.debug(f"Cache expired for user {user_id}, refreshing...")
del self._persona_cache[cache_key]
del self._cache_timestamps[cache_key]
# Fetch fresh data
try:
persona_data = self.persona_service.get_persona_for_platform(user_id, 'facebook')
# Cache the result
if persona_data:
self._persona_cache[cache_key] = persona_data
self._cache_timestamps[cache_key] = current_time
self.logger.debug(f"Cached persona data for user {user_id}")
return persona_data
except Exception as e:
self.logger.warning(f"Could not load persona data for Facebook content generation: {e}")
return None
def _clear_persona_cache(self, user_id: int = None):
"""
Clear persona cache for a specific user or all users.
Args:
user_id: User ID to clear cache for, or None to clear all
"""
if user_id is None:
self._persona_cache.clear()
self._cache_timestamps.clear()
self.logger.info("Cleared all persona cache")
else:
cache_key = f"facebook_persona_{user_id}"
if cache_key in self._persona_cache:
del self._persona_cache[cache_key]
del self._cache_timestamps[cache_key]
self.logger.info(f"Cleared persona cache for user {user_id}")
def _build_persona_enhanced_prompt(self, base_prompt: str, persona_data: Optional[Dict[str, Any]] = None) -> str:
"""
Enhance prompt with persona data if available.
Args:
base_prompt: Base prompt to enhance
persona_data: Persona data to incorporate
Returns:
Enhanced prompt with persona guidance
"""
if not persona_data:
return base_prompt
try:
core_persona = persona_data.get('core_persona', {})
platform_persona = persona_data.get('platform_adaptation', {})
if not core_persona:
return base_prompt
persona_guidance = f"""
PERSONA-AWARE WRITING GUIDANCE:
- PERSONA: {core_persona.get('persona_name', 'Unknown')} ({core_persona.get('archetype', 'Unknown')})
- CORE BELIEF: {core_persona.get('core_belief', 'Unknown')}
- CONFIDENCE SCORE: {core_persona.get('confidence_score', 0)}%
PLATFORM OPTIMIZATION (Facebook):
- CHARACTER LIMIT: {platform_persona.get('content_format_rules', {}).get('character_limit', '63206')} characters
- OPTIMAL LENGTH: {platform_persona.get('content_format_rules', {}).get('optimal_length', '40-80 characters')}
- ENGAGEMENT PATTERN: {platform_persona.get('engagement_patterns', {}).get('posting_frequency', '1-2 times per day')}
- HASHTAG STRATEGY: {platform_persona.get('lexical_features', {}).get('hashtag_strategy', '1-2 relevant hashtags')}
ALWAYS generate content that matches this persona's linguistic fingerprint and platform optimization rules.
"""
return f"{base_prompt}\n\n{persona_guidance}"
except Exception as e:
self.logger.warning(f"Error enhancing prompt with persona data: {e}")
return base_prompt
def _handle_error(self, error: Exception, operation: str) -> Dict[str, Any]:
"""
Handle errors and return standardized error response.
Args:
error: The exception that occurred
operation: Description of the operation that failed
Returns:
Standardized error response
"""
error_message = f"Error in {operation}: {str(error)}"
self.logger.error(error_message)
return {
"success": False,
"error": error_message,
"content": None,
"metadata": {
"operation": operation,
"error_type": type(error).__name__
}
}

View File

@@ -0,0 +1,125 @@
"""Facebook Post generation service."""
from typing import Dict, Any
from ..models.post_models import FacebookPostRequest, FacebookPostResponse, FacebookPostAnalytics, FacebookPostOptimization
from .base_service import FacebookWriterBaseService
class FacebookPostService(FacebookWriterBaseService):
"""Service for generating Facebook posts."""
def generate_post(self, request: FacebookPostRequest) -> FacebookPostResponse:
"""
Generate a Facebook post based on the request parameters.
Args:
request: FacebookPostRequest containing all the parameters
Returns:
FacebookPostResponse with the generated content
"""
try:
# Determine the actual goal and tone
actual_goal = request.custom_goal if request.post_goal.value == "Custom" else request.post_goal.value
actual_tone = request.custom_tone if request.post_tone.value == "Custom" else request.post_tone.value
# Get persona data for enhanced content generation
# Beta testing: Force user_id=1 for all requests
user_id = 1
persona_data = self._get_persona_data(user_id)
# Build the prompt
base_prompt = self._build_post_prompt(request, actual_goal, actual_tone)
prompt = self._build_persona_enhanced_prompt(base_prompt, persona_data)
# Generate the post content
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
if not content:
return FacebookPostResponse(
success=False,
error="Failed to generate post content"
)
# Create analytics and optimization suggestions
analytics = FacebookPostAnalytics(
expected_reach="2.5K - 5K",
expected_engagement="5-8%",
best_time_to_post="2 PM - 4 PM"
)
optimization = FacebookPostOptimization(
suggestions=self._create_optimization_suggestions("post")
)
return FacebookPostResponse(
success=True,
content=content,
analytics=analytics,
optimization=optimization,
metadata={
"business_type": request.business_type,
"target_audience": request.target_audience,
"goal": actual_goal,
"tone": actual_tone
}
)
except Exception as e:
return FacebookPostResponse(
**self._handle_error(e, "Facebook post generation")
)
def _build_post_prompt(self, request: FacebookPostRequest, goal: str, tone: str) -> str:
"""
Build the prompt for Facebook post generation.
Args:
request: The post request
goal: The actual goal (resolved from custom if needed)
tone: The actual tone (resolved from custom if needed)
Returns:
Formatted prompt string
"""
base_prompt = self._build_base_prompt(
request.business_type,
request.target_audience,
goal
)
prompt = f"""
{base_prompt}
Generate a Facebook post with the following specifications:
Goal: {goal}
Tone: {tone}
Content Requirements:
- Include: {request.include or 'N/A'}
- Avoid: {request.avoid or 'N/A'}
Advanced Options:
- Use attention-grabbing hook: {request.advanced_options.use_hook}
- Include storytelling elements: {request.advanced_options.use_story}
- Add clear call-to-action: {request.advanced_options.use_cta}
- Include engagement question: {request.advanced_options.use_question}
- Use relevant emojis: {request.advanced_options.use_emoji}
- Add relevant hashtags: {request.advanced_options.use_hashtags}
Media Type: {request.media_type.value}
Please write a well-structured Facebook post that:
1. Grabs attention in the first line (hook)
2. Maintains consistent {tone} tone throughout
3. Includes engaging content that aligns with the goal: {goal}
4. Ends with a clear call-to-action (if enabled)
5. Uses appropriate formatting and emojis (if enabled)
6. Includes relevant hashtags (if enabled)
7. Considers the target audience: {request.target_audience}
The post should be engaging, platform-appropriate, and optimized for Facebook's algorithm.
"""
return prompt

View File

@@ -0,0 +1,322 @@
"""Remaining Facebook Writer services - placeholder implementations."""
from typing import Dict, Any, List
from ..models import *
from ..models.carousel_models import CarouselSlide
from .base_service import FacebookWriterBaseService
class FacebookReelService(FacebookWriterBaseService):
"""Service for generating Facebook reels."""
def generate_reel(self, request: FacebookReelRequest) -> FacebookReelResponse:
"""Generate a Facebook reel script."""
try:
actual_reel_type = request.custom_reel_type if request.reel_type.value == "Custom" else request.reel_type.value
actual_style = request.custom_style if request.reel_style.value == "Custom" else request.reel_style.value
# Get persona data for enhanced content generation
# Beta testing: Force user_id=1 for all requests
user_id = 1
persona_data = self._get_persona_data(user_id)
base_prompt = f"""
Create a Facebook Reel script for:
Business: {request.business_type}
Audience: {request.target_audience}
Type: {actual_reel_type}
Length: {request.reel_length.value}
Style: {actual_style}
Topic: {request.topic}
Include: {request.include or 'N/A'}
Avoid: {request.avoid or 'N/A'}
Music: {request.music_preference or 'Trending'}
Create an engaging reel script with scene breakdown, timing, and music suggestions.
"""
prompt = self._build_persona_enhanced_prompt(base_prompt, persona_data)
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
return FacebookReelResponse(
success=True,
script=content,
scene_breakdown=["Opening hook", "Main content", "Call to action"],
music_suggestions=["Trending pop", "Upbeat instrumental", "Viral sound"],
hashtag_suggestions=["#Reels", "#Trending", "#Business"],
engagement_tips=self._create_optimization_suggestions("reel")
)
except Exception as e:
return FacebookReelResponse(**self._handle_error(e, "Facebook reel generation"))
class FacebookCarouselService(FacebookWriterBaseService):
"""Service for generating Facebook carousels."""
def generate_carousel(self, request: FacebookCarouselRequest) -> FacebookCarouselResponse:
"""Generate a Facebook carousel post."""
try:
actual_type = request.custom_carousel_type if request.carousel_type.value == "Custom" else request.carousel_type.value
prompt = f"""
Create a Facebook Carousel post for:
Business: {request.business_type}
Audience: {request.target_audience}
Type: {actual_type}
Topic: {request.topic}
Slides: {request.num_slides}
CTA: {request.cta_text or 'Learn More'}
Include: {request.include or 'N/A'}
Avoid: {request.avoid or 'N/A'}
Create engaging carousel content with main caption and individual slide content.
"""
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
# Create sample slides
slides = []
for i in range(request.num_slides):
slides.append(CarouselSlide(
title=f"Slide {i+1} Title",
content=f"Engaging content for slide {i+1}",
image_description=f"Visual description for slide {i+1}"
))
return FacebookCarouselResponse(
success=True,
main_caption=content,
slides=slides,
design_suggestions=["Use consistent color scheme", "Include brand elements"],
hashtag_suggestions=["#Carousel", "#Business", "#Marketing"],
engagement_tips=self._create_optimization_suggestions("carousel")
)
except Exception as e:
return FacebookCarouselResponse(**self._handle_error(e, "Facebook carousel generation"))
class FacebookEventService(FacebookWriterBaseService):
"""Service for generating Facebook events."""
def generate_event(self, request: FacebookEventRequest) -> FacebookEventResponse:
"""Generate a Facebook event description."""
try:
actual_type = request.custom_event_type if request.event_type.value == "Custom" else request.event_type.value
prompt = f"""
Create a Facebook Event description for:
Event: {request.event_name}
Type: {actual_type}
Format: {request.event_format.value}
Business: {request.business_type}
Audience: {request.target_audience}
Date: {request.event_date or 'TBD'}
Location: {request.location or 'TBD'}
Benefits: {request.key_benefits or 'N/A'}
Speakers: {request.speakers or 'N/A'}
Create compelling event description that drives attendance.
"""
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
return FacebookEventResponse(
success=True,
event_title=request.event_name,
event_description=content,
short_description=content[:155] if content else None,
key_highlights=["Expert speakers", "Networking opportunities", "Valuable insights"],
call_to_action="Register Now",
hashtag_suggestions=["#Event", "#Business", "#Networking"],
promotion_tips=["Share in relevant groups", "Create countdown posts", "Partner with influencers"]
)
except Exception as e:
return FacebookEventResponse(**self._handle_error(e, "Facebook event generation"))
class FacebookHashtagService(FacebookWriterBaseService):
"""Service for generating Facebook hashtags."""
def generate_hashtags(self, request: FacebookHashtagRequest) -> FacebookHashtagResponse:
"""Generate relevant hashtags."""
try:
actual_purpose = request.custom_purpose if request.purpose.value == "Custom" else request.purpose.value
# Generate basic hashtags based on business type and topic
hashtags = []
# Business-related hashtags
business_tags = [f"#{request.business_type.replace(' ', '')}", f"#{request.industry.replace(' ', '')}"]
hashtags.extend(business_tags)
# Topic-related hashtags
topic_words = request.content_topic.split()
topic_tags = [f"#{word.capitalize()}" for word in topic_words if len(word) > 3]
hashtags.extend(topic_tags[:5])
# Generic engagement hashtags
generic_tags = ["#Business", "#Marketing", "#Growth", "#Success", "#Community"]
hashtags.extend(generic_tags)
# Location hashtags if provided
if request.location:
location_tag = f"#{request.location.replace(' ', '').replace(',', '')}"
hashtags.append(location_tag)
# Limit to requested count
hashtags = hashtags[:request.hashtag_count]
return FacebookHashtagResponse(
success=True,
hashtags=hashtags,
categorized_hashtags={
"business": business_tags,
"topic": topic_tags,
"generic": generic_tags
},
trending_hashtags=["#Trending", "#Viral", "#Popular"],
usage_tips=["Mix popular and niche hashtags", "Keep hashtags relevant", "Update regularly"],
performance_predictions={"reach": "Medium", "engagement": "Good"}
)
except Exception as e:
return FacebookHashtagResponse(**self._handle_error(e, "Facebook hashtag generation"))
class FacebookEngagementService(FacebookWriterBaseService):
"""Service for analyzing Facebook engagement."""
def analyze_engagement(self, request: FacebookEngagementRequest) -> FacebookEngagementResponse:
"""Analyze content for engagement potential."""
try:
# Simple content analysis
content_length = len(request.content)
word_count = len(request.content.split())
# Calculate basic scores
length_score = min(100, (content_length / 10)) # Optimal around 1000 chars
word_score = min(100, (word_count / 2)) # Optimal around 200 words
overall_score = (length_score + word_score) / 2
metrics = EngagementMetrics(
predicted_reach="2K-8K",
predicted_engagement_rate="3-7%",
predicted_likes="50-200",
predicted_comments="10-50",
predicted_shares="5-25",
virality_score="Medium"
)
optimization = OptimizationSuggestions(
content_improvements=["Add more emojis", "Include questions", "Shorten paragraphs"],
timing_suggestions=["Post between 2-4 PM", "Avoid late nights", "Test weekends"],
hashtag_improvements=["Use trending hashtags", "Mix popular and niche", "Limit to 5-7 hashtags"],
visual_suggestions=["Add compelling image", "Use bright colors", "Include text overlay"],
engagement_tactics=["Ask questions", "Create polls", "Encourage sharing"]
)
return FacebookEngagementResponse(
success=True,
content_score=overall_score,
engagement_metrics=metrics,
optimization_suggestions=optimization,
sentiment_analysis={"tone": "positive", "emotion": "neutral"},
trend_alignment={"score": "good", "trending_topics": ["business", "growth"]},
competitor_insights={"performance": "average", "opportunities": ["better visuals", "more interactive"]}
)
except Exception as e:
return FacebookEngagementResponse(**self._handle_error(e, "Facebook engagement analysis"))
class FacebookGroupPostService(FacebookWriterBaseService):
"""Service for generating Facebook group posts."""
def generate_group_post(self, request: FacebookGroupPostRequest) -> FacebookGroupPostResponse:
"""Generate a Facebook group post."""
try:
actual_type = request.custom_group_type if request.group_type.value == "Custom" else request.group_type.value
actual_purpose = request.custom_purpose if request.post_purpose.value == "Custom" else request.post_purpose.value
prompt = f"""
Create a Facebook Group post for:
Group: {request.group_name} ({actual_type})
Purpose: {actual_purpose}
Business: {request.business_type}
Topic: {request.topic}
Audience: {request.target_audience}
Value: {request.value_proposition}
Rules to follow:
- No promotion: {request.group_rules.no_promotion}
- Value first: {request.group_rules.value_first}
- No links: {request.group_rules.no_links}
- Community focused: {request.group_rules.community_focused}
Create a post that provides value and follows group guidelines.
"""
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
return FacebookGroupPostResponse(
success=True,
content=content,
engagement_starters=["What's your experience with this?", "How do you handle this situation?"],
value_highlights=["Free insights", "Actionable tips", "Community support"],
community_guidelines=["Provides value first", "Encourages discussion", "Follows group rules"],
follow_up_suggestions=["Respond to comments promptly", "Share additional resources", "Connect with commenters"],
relationship_building_tips=["Be authentic", "Help others", "Participate regularly"]
)
except Exception as e:
return FacebookGroupPostResponse(**self._handle_error(e, "Facebook group post generation"))
class FacebookPageAboutService(FacebookWriterBaseService):
"""Service for generating Facebook page about sections."""
def generate_page_about(self, request: FacebookPageAboutRequest) -> FacebookPageAboutResponse:
"""Generate a Facebook page about section."""
try:
actual_category = request.custom_category if request.business_category.value == "Custom" else request.business_category.value
actual_tone = request.custom_tone if request.page_tone.value == "Custom" else request.page_tone.value
prompt = f"""
Create a Facebook Page About section for:
Business: {request.business_name}
Category: {actual_category}
Description: {request.business_description}
Audience: {request.target_audience}
USP: {request.unique_value_proposition}
Services: {request.services_products}
Tone: {actual_tone}
History: {request.company_history or 'N/A'}
Mission: {request.mission_vision or 'N/A'}
Achievements: {request.achievements or 'N/A'}
Keywords: {request.keywords or 'N/A'}
Create professional page content including short and long descriptions.
"""
content = self._generate_text(prompt, temperature=0.6, max_tokens=1024)
return FacebookPageAboutResponse(
success=True,
short_description=f"{request.business_name} - {request.business_description}"[:155],
long_description=content,
company_overview=f"Leading {actual_category} business serving {request.target_audience}",
mission_statement=request.mission_vision or f"To provide excellent {request.services_products} to our community",
story_section=request.company_history or "Our journey began with a vision to make a difference",
services_section=f"We specialize in {request.services_products}",
cta_suggestions=["Contact Us", "Learn More", "Get Quote"],
keyword_optimization=["business", "service", "quality", "professional"],
completion_tips=["Add contact info", "Upload cover photo", "Create call-to-action button"]
)
except Exception as e:
return FacebookPageAboutResponse(**self._handle_error(e, "Facebook page about generation"))

View File

@@ -0,0 +1,243 @@
"""Facebook Story generation service."""
from typing import Dict, Any, List
from ..models.story_models import FacebookStoryRequest, FacebookStoryResponse
from .base_service import FacebookWriterBaseService
try:
from ...services.llm_providers.main_image_generation import generate_image
from base64 import b64encode
except Exception:
generate_image = None # type: ignore
b64encode = None # type: ignore
class FacebookStoryService(FacebookWriterBaseService):
"""Service for generating Facebook stories."""
def generate_story(self, request: FacebookStoryRequest) -> FacebookStoryResponse:
"""
Generate a Facebook story based on the request parameters.
Args:
request: FacebookStoryRequest containing all the parameters
Returns:
FacebookStoryResponse with the generated content
"""
try:
# Determine the actual story type and tone
actual_story_type = request.custom_story_type if request.story_type.value == "Custom" else request.story_type.value
actual_tone = request.custom_tone if request.story_tone.value == "Custom" else request.story_tone.value
# Get persona data for enhanced content generation
# Beta testing: Force user_id=1 for all requests
user_id = 1
persona_data = self._get_persona_data(user_id)
# Build the prompt
base_prompt = self._build_story_prompt(request, actual_story_type, actual_tone)
prompt = self._build_persona_enhanced_prompt(base_prompt, persona_data)
# Generate the story content
content = self._generate_text(prompt, temperature=0.7, max_tokens=1024)
if not content:
return FacebookStoryResponse(
success=False,
error="Failed to generate story content"
)
# 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 unified image generation
images_base64: List[str] = []
try:
if generate_image is not None and b64encode 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."
)
# Generate image using unified system (9:16 aspect ratio = 1080x1920)
result = generate_image(
prompt=img_prompt,
options={
"provider": "gemini", # Facebook stories use Gemini
"width": 1080,
"height": 1920,
}
)
if result and result.image_bytes:
# Convert bytes to base64
image_b64 = b64encode(result.image_bytes).decode('utf-8')
images_base64 = [image_b64]
except Exception as e:
# Log error but continue without images
images_base64 = []
return FacebookStoryResponse(
success=True,
content=content,
images_base64=images_base64[:1],
visual_suggestions=visual_suggestions,
engagement_tips=engagement_tips,
metadata={
"business_type": request.business_type,
"target_audience": request.target_audience,
"story_type": actual_story_type,
"tone": actual_tone
}
)
except Exception as e:
return FacebookStoryResponse(
**self._handle_error(e, "Facebook story generation")
)
def _build_story_prompt(self, request: FacebookStoryRequest, story_type: str, tone: str) -> str:
"""
Build the prompt for Facebook story generation.
Args:
request: The story request
story_type: The actual story type (resolved from custom if needed)
tone: The actual tone (resolved from custom if needed)
Returns:
Formatted prompt string
"""
base_prompt = self._build_base_prompt(
request.business_type,
request.target_audience,
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"
newline = '\n'
prompt = f"""
{base_prompt}
Generate a Facebook Story with the following specifications:
Story Type: {story_type}
Tone: {tone}
Content Requirements:
- Include: {request.include or 'N/A'}
- Avoid: {request.avoid or 'N/A'}
{newline + advanced_str if advanced_str else ''}
Visual Options:
- 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)
2. Has concise, impactful text (stories are viewed quickly)
3. Includes clear visual direction for designers
4. Maintains {tone} tone throughout
5. Encourages viewer interaction
6. Fits the {story_type} format
7. Appeals to: {request.target_audience}
Format the response with:
- Main story text/copy
- Visual description
- Text overlay suggestions
- Interactive element suggestions (if enabled)
Keep it engaging and story-appropriate for Facebook's ephemeral format.
"""
return prompt
def _generate_visual_suggestions(self, story_type: str, visual_options) -> List[str]:
"""Generate visual suggestions based on story type and options."""
suggestions = []
if story_type == "Product showcase":
suggestions.extend([
"Use high-quality product photos with clean backgrounds",
"Include multiple angles or features in carousel format",
"Add animated elements to highlight key features"
])
elif story_type == "Behind the scenes":
suggestions.extend([
"Use candid, authentic photos/videos",
"Show the process or journey",
"Include team members or workspace shots"
])
elif story_type == "Tutorial/How-to":
suggestions.extend([
"Break down steps with numbered overlays",
"Use before/after comparisons",
"Include clear, step-by-step visuals"
])
# Add general suggestions based on visual options
if getattr(visual_options, "text_overlay", True):
suggestions.append("Use bold, readable fonts for text overlays")
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 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
def _generate_engagement_tips(self, content_type: str) -> List[str]:
"""Generate engagement tips specific to stories."""
return [
"Post at peak audience activity times",
"Use interactive stickers to encourage participation",
"Keep text minimal and highly readable",
"Include a clear call-to-action",
"Use trending hashtags in story text",
"Tag relevant accounts to increase reach",
"Save important stories as Highlights"
]