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,227 @@
# Facebook Writer API
A comprehensive FastAPI-based backend for generating Facebook content using AI. This is a complete migration of the original Streamlit-based Facebook writer to a modern REST API architecture.
## Overview
The Facebook Writer API provides 10 different tools for creating, optimizing, and analyzing Facebook content:
### Content Creation Tools
- **FB Post Generator** - Create engaging Facebook posts with optimization features
- **FB Story Generator** - Generate creative Facebook Stories with visual suggestions
- **FB Reel Generator** - Create Reels scripts with music and hashtag suggestions
- **Carousel Generator** - Generate multi-slide carousel posts
### Business Tools
- **Event Description Generator** - Create compelling event descriptions
- **Group Post Generator** - Generate community-focused group posts
- **Page About Generator** - Create professional page About sections
### Marketing Tools
- **Ad Copy Generator** - Generate high-converting ad copy with targeting suggestions
- **Hashtag Generator** - Create relevant and trending hashtags
- **Engagement Analyzer** - Analyze content performance and get optimization tips
## API Architecture
### Directory Structure
```
backend/api/facebook_writer/
├── models/ # Pydantic models for request/response
├── services/ # Business logic and AI integration
├── routers/ # FastAPI route definitions
└── README.md # This file
```
### Key Components
#### Models (`models/`)
- **Request Models**: Strongly typed input validation using Pydantic
- **Response Models**: Structured output with success/error handling
- **Enum Classes**: Predefined options for dropdowns and selections
#### Services (`services/`)
- **Base Service**: Common functionality and Gemini AI integration
- **Specialized Services**: Individual services for each content type
- **Error Handling**: Consistent error responses across all services
#### Routers (`routers/`)
- **FastAPI Routes**: RESTful endpoints with automatic documentation
- **Request Validation**: Automatic validation using Pydantic models
- **Response Formatting**: Consistent JSON responses
## API Endpoints
### Health & Discovery
- `GET /api/facebook-writer/health` - Health check
- `GET /api/facebook-writer/tools` - List available tools
- `GET /api/facebook-writer/post/templates` - Get post templates
- `GET /api/facebook-writer/analytics/benchmarks` - Get industry benchmarks
- `GET /api/facebook-writer/compliance/guidelines` - Get compliance guidelines
### Content Generation
- `POST /api/facebook-writer/post/generate` - Generate Facebook post
- `POST /api/facebook-writer/story/generate` - Generate Facebook story
- `POST /api/facebook-writer/reel/generate` - Generate Facebook reel
- `POST /api/facebook-writer/carousel/generate` - Generate carousel post
- `POST /api/facebook-writer/event/generate` - Generate event description
- `POST /api/facebook-writer/group-post/generate` - Generate group post
- `POST /api/facebook-writer/page-about/generate` - Generate page about
- `POST /api/facebook-writer/ad-copy/generate` - Generate ad copy
- `POST /api/facebook-writer/hashtags/generate` - Generate hashtags
- `POST /api/facebook-writer/engagement/analyze` - Analyze engagement
## Usage Examples
### Generate a Facebook Post
```python
import requests
payload = {
"business_type": "Fitness coach",
"target_audience": "Fitness enthusiasts aged 25-35",
"post_goal": "Increase engagement",
"post_tone": "Inspirational",
"include": "Success story, workout tips",
"avoid": "Generic advice",
"media_type": "Image",
"advanced_options": {
"use_hook": True,
"use_story": True,
"use_cta": True,
"use_question": True,
"use_emoji": True,
"use_hashtags": True
}
}
response = requests.post(
"http://localhost:8000/api/facebook-writer/post/generate",
json=payload
)
if response.status_code == 200:
data = response.json()
print(f"Generated post: {data['content']}")
print(f"Expected reach: {data['analytics']['expected_reach']}")
```
### Generate Ad Copy
```python
payload = {
"business_type": "E-commerce store",
"product_service": "Wireless headphones",
"ad_objective": "Conversions",
"ad_format": "Single image",
"target_audience": "Tech enthusiasts and music lovers",
"targeting_options": {
"age_group": "25-34",
"interests": "Technology, Music",
"location": "United States"
},
"unique_selling_proposition": "Premium sound at affordable prices",
"budget_range": "Medium"
}
response = requests.post(
"http://localhost:8000/api/facebook-writer/ad-copy/generate",
json=payload
)
```
## Setup & Configuration
### Environment Variables
Create a `.env` file in the backend directory:
```bash
GEMINI_API_KEY=your_gemini_api_key_here
```
### Installation
```bash
cd backend
pip install -r requirements.txt
```
### Running the Server
```bash
python -m uvicorn app:app --host 0.0.0.0 --port 8000 --reload
```
### Testing
```bash
python test_facebook_writer.py
```
## AI Integration
The API uses Google's Gemini AI through the existing `gemini_provider` service:
- **Text Generation**: For creating content
- **Structured Output**: For complex responses with multiple fields
- **Error Handling**: Robust retry logic and fallbacks
- **Temperature Control**: Optimized for different content types
## Migration Notes
This FastAPI backend replaces the original Streamlit interface while maintaining all functionality:
### ✅ Migrated Features
- All 10 Facebook writer tools
- AI content generation using Gemini
- Advanced options and customization
- Analytics predictions
- Optimization suggestions
- Error handling and validation
### 🔄 Architecture Changes
- **UI Framework**: Streamlit → FastAPI REST API
- **Input Handling**: Streamlit widgets → Pydantic models
- **Output Format**: Streamlit display → JSON responses
- **State Management**: Session state → Stateless API
- **Integration**: Direct function calls → HTTP endpoints
### 🎯 Benefits
- **Scalability**: Can handle multiple concurrent requests
- **Integration**: Easy to integrate with React frontend
- **Documentation**: Automatic OpenAPI/Swagger docs
- **Testing**: Comprehensive test coverage
- **Deployment**: Standard FastAPI deployment options
## API Documentation
When the server is running, visit:
- **Interactive Docs**: http://localhost:8000/docs
- **ReDoc**: http://localhost:8000/redoc
- **OpenAPI JSON**: http://localhost:8000/openapi.json
## Error Handling
All endpoints return consistent error responses:
```json
{
"success": false,
"error": "Detailed error message",
"content": null,
"metadata": {
"operation": "operation_name",
"error_type": "ValueError"
}
}
```
## Performance
- **Response Time**: ~2-5 seconds for content generation
- **Concurrency**: Supports multiple simultaneous requests
- **Rate Limiting**: Handled by Gemini API quotas
- **Caching**: Consider implementing for repeated requests
## Next Steps
1. **Frontend Integration**: Connect React UI to these endpoints
2. **Authentication**: Add user authentication and authorization
3. **Rate Limiting**: Implement API rate limiting
4. **Caching**: Add Redis for caching generated content
5. **Monitoring**: Add logging and metrics collection
6. **Testing**: Expand test coverage for edge cases

View File

@@ -0,0 +1,79 @@
"""Facebook Writer API Models."""
from .post_models import (
FacebookPostRequest,
FacebookPostResponse,
FacebookPostAnalytics,
FacebookPostOptimization
)
from .story_models import (
FacebookStoryRequest,
FacebookStoryResponse
)
from .reel_models import (
FacebookReelRequest,
FacebookReelResponse
)
from .carousel_models import (
FacebookCarouselRequest,
FacebookCarouselResponse
)
from .event_models import (
FacebookEventRequest,
FacebookEventResponse
)
from .hashtag_models import (
FacebookHashtagRequest,
FacebookHashtagResponse
)
from .engagement_models import (
FacebookEngagementRequest,
FacebookEngagementResponse
)
from .group_post_models import (
FacebookGroupPostRequest,
FacebookGroupPostResponse
)
from .page_about_models import (
FacebookPageAboutRequest,
FacebookPageAboutResponse
)
from .ad_copy_models import (
FacebookAdCopyRequest,
FacebookAdCopyResponse
)
__all__ = [
# Post models
"FacebookPostRequest",
"FacebookPostResponse",
"FacebookPostAnalytics",
"FacebookPostOptimization",
# Story models
"FacebookStoryRequest",
"FacebookStoryResponse",
# Reel models
"FacebookReelRequest",
"FacebookReelResponse",
# Carousel models
"FacebookCarouselRequest",
"FacebookCarouselResponse",
# Event models
"FacebookEventRequest",
"FacebookEventResponse",
# Hashtag models
"FacebookHashtagRequest",
"FacebookHashtagResponse",
# Engagement models
"FacebookEngagementRequest",
"FacebookEngagementResponse",
# Group post models
"FacebookGroupPostRequest",
"FacebookGroupPostResponse",
# Page about models
"FacebookPageAboutRequest",
"FacebookPageAboutResponse",
# Ad copy models
"FacebookAdCopyRequest",
"FacebookAdCopyResponse"
]

View File

@@ -0,0 +1,114 @@
"""Pydantic models for Facebook Ad Copy functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class AdObjective(str, Enum):
"""Ad objective options."""
BRAND_AWARENESS = "Brand awareness"
REACH = "Reach"
TRAFFIC = "Traffic"
ENGAGEMENT = "Engagement"
APP_INSTALLS = "App installs"
VIDEO_VIEWS = "Video views"
LEAD_GENERATION = "Lead generation"
MESSAGES = "Messages"
CONVERSIONS = "Conversions"
CATALOG_SALES = "Catalog sales"
STORE_TRAFFIC = "Store traffic"
CUSTOM = "Custom"
class AdFormat(str, Enum):
"""Ad format options."""
SINGLE_IMAGE = "Single image"
SINGLE_VIDEO = "Single video"
CAROUSEL = "Carousel"
SLIDESHOW = "Slideshow"
COLLECTION = "Collection"
INSTANT_EXPERIENCE = "Instant experience"
class TargetAge(str, Enum):
"""Target age groups."""
TEENS = "13-17"
YOUNG_ADULTS = "18-24"
MILLENNIALS = "25-34"
GEN_X = "35-44"
MIDDLE_AGED = "45-54"
SENIORS = "55-64"
ELDERLY = "65+"
CUSTOM = "Custom"
class AdBudget(str, Enum):
"""Ad budget ranges."""
SMALL = "$10-50/day"
MEDIUM = "$50-200/day"
LARGE = "$200-1000/day"
ENTERPRISE = "$1000+/day"
CUSTOM = "Custom"
class TargetingOptions(BaseModel):
"""Targeting options for the ad."""
age_group: TargetAge = Field(..., description="Target age group")
custom_age: Optional[str] = Field(None, description="Custom age range if 'Custom' is selected")
gender: Optional[str] = Field(None, description="Gender targeting")
location: Optional[str] = Field(None, description="Geographic targeting")
interests: Optional[str] = Field(None, description="Interest-based targeting")
behaviors: Optional[str] = Field(None, description="Behavior-based targeting")
lookalike_audience: Optional[str] = Field(None, description="Lookalike audience description")
class FacebookAdCopyRequest(BaseModel):
"""Request model for Facebook ad copy generation."""
business_type: str = Field(..., description="Type of business")
product_service: str = Field(..., description="Product or service being advertised")
ad_objective: AdObjective = Field(..., description="Main objective of the ad campaign")
custom_objective: Optional[str] = Field(None, description="Custom objective if 'Custom' is selected")
ad_format: AdFormat = Field(..., description="Format of the ad")
target_audience: str = Field(..., description="Target audience description")
targeting_options: TargetingOptions = Field(..., description="Detailed targeting options")
unique_selling_proposition: str = Field(..., description="What makes your offer unique")
offer_details: Optional[str] = Field(None, description="Special offers, discounts, or promotions")
budget_range: AdBudget = Field(..., description="Ad budget range")
custom_budget: Optional[str] = Field(None, description="Custom budget if 'Custom' is selected")
campaign_duration: Optional[str] = Field(None, description="How long the campaign will run")
competitor_analysis: Optional[str] = Field(None, description="Information about competitor ads")
brand_voice: Optional[str] = Field(None, description="Brand voice and tone guidelines")
compliance_requirements: Optional[str] = Field(None, description="Any compliance or regulatory requirements")
class AdCopyVariations(BaseModel):
"""Different variations of ad copy."""
headline_variations: List[str] = Field(..., description="Multiple headline options")
primary_text_variations: List[str] = Field(..., description="Multiple primary text options")
description_variations: List[str] = Field(..., description="Multiple description options")
cta_variations: List[str] = Field(..., description="Multiple call-to-action options")
class AdPerformancePredictions(BaseModel):
"""Predicted ad performance metrics."""
estimated_reach: str = Field(..., description="Estimated reach")
estimated_ctr: str = Field(..., description="Estimated click-through rate")
estimated_cpc: str = Field(..., description="Estimated cost per click")
estimated_conversions: str = Field(..., description="Estimated conversions")
optimization_score: str = Field(..., description="Overall optimization score")
class FacebookAdCopyResponse(BaseModel):
"""Response model for Facebook ad copy generation."""
success: bool = Field(..., description="Whether the generation was successful")
primary_ad_copy: Optional[Dict[str, str]] = Field(None, description="Primary ad copy with headline, text, description")
ad_variations: Optional[AdCopyVariations] = Field(None, description="Multiple variations for A/B testing")
targeting_suggestions: Optional[List[str]] = Field(None, description="Additional targeting suggestions")
creative_suggestions: Optional[List[str]] = Field(None, description="Creative and visual suggestions")
performance_predictions: Optional[AdPerformancePredictions] = Field(None, description="Performance predictions")
optimization_tips: Optional[List[str]] = Field(None, description="Optimization tips for better performance")
compliance_notes: Optional[List[str]] = Field(None, description="Compliance and policy considerations")
budget_recommendations: Optional[List[str]] = Field(None, description="Budget allocation recommendations")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,51 @@
"""Pydantic models for Facebook Carousel functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class CarouselType(str, Enum):
"""Carousel type options."""
PRODUCT_SHOWCASE = "Product showcase"
STEP_BY_STEP = "Step-by-step guide"
BEFORE_AFTER = "Before/After"
TESTIMONIALS = "Customer testimonials"
FEATURES_BENEFITS = "Features & Benefits"
PORTFOLIO = "Portfolio showcase"
EDUCATIONAL = "Educational content"
CUSTOM = "Custom"
class CarouselSlide(BaseModel):
"""Individual carousel slide content."""
title: str = Field(..., description="Slide title")
content: str = Field(..., description="Slide content/description")
image_description: Optional[str] = Field(None, description="Description of the image for this slide")
class FacebookCarouselRequest(BaseModel):
"""Request model for Facebook carousel generation."""
business_type: str = Field(..., description="Type of business")
target_audience: str = Field(..., description="Target audience description")
carousel_type: CarouselType = Field(..., description="Type of carousel to create")
custom_carousel_type: Optional[str] = Field(None, description="Custom carousel type if 'Custom' is selected")
topic: str = Field(..., description="Main topic or theme of the carousel")
num_slides: int = Field(default=5, ge=3, le=10, description="Number of slides (3-10)")
include_cta: bool = Field(default=True, description="Include call-to-action in final slide")
cta_text: Optional[str] = Field(None, description="Custom call-to-action text")
brand_colors: Optional[str] = Field(None, description="Brand colors to mention for design")
include: Optional[str] = Field(None, description="Elements to include")
avoid: Optional[str] = Field(None, description="Elements to avoid")
class FacebookCarouselResponse(BaseModel):
"""Response model for Facebook carousel generation."""
success: bool = Field(..., description="Whether the generation was successful")
main_caption: Optional[str] = Field(None, description="Main caption for the carousel post")
slides: Optional[List[CarouselSlide]] = Field(None, description="Generated carousel slides")
design_suggestions: Optional[List[str]] = Field(None, description="Design and layout suggestions")
hashtag_suggestions: Optional[List[str]] = Field(None, description="Hashtag suggestions")
engagement_tips: Optional[List[str]] = Field(None, description="Engagement optimization tips")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,70 @@
"""Pydantic models for Facebook Engagement Analysis functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class ContentType(str, Enum):
"""Content type options for analysis."""
POST = "Post"
STORY = "Story"
REEL = "Reel"
CAROUSEL = "Carousel"
VIDEO = "Video"
IMAGE = "Image"
LINK = "Link"
class AnalysisType(str, Enum):
"""Analysis type options."""
CONTENT_ANALYSIS = "Content analysis"
PERFORMANCE_PREDICTION = "Performance prediction"
OPTIMIZATION_SUGGESTIONS = "Optimization suggestions"
COMPETITOR_COMPARISON = "Competitor comparison"
TREND_ANALYSIS = "Trend analysis"
class FacebookEngagementRequest(BaseModel):
"""Request model for Facebook engagement analysis."""
content: str = Field(..., description="Content to analyze")
content_type: ContentType = Field(..., description="Type of content being analyzed")
analysis_type: AnalysisType = Field(..., description="Type of analysis to perform")
business_type: str = Field(..., description="Type of business")
target_audience: str = Field(..., description="Target audience description")
post_timing: Optional[str] = Field(None, description="When the content was/will be posted")
hashtags: Optional[List[str]] = Field(None, description="Hashtags used with the content")
competitor_content: Optional[str] = Field(None, description="Competitor content for comparison")
historical_performance: Optional[Dict[str, Any]] = Field(None, description="Historical performance data")
class EngagementMetrics(BaseModel):
"""Engagement metrics and predictions."""
predicted_reach: str = Field(..., description="Predicted reach")
predicted_engagement_rate: str = Field(..., description="Predicted engagement rate")
predicted_likes: str = Field(..., description="Predicted likes")
predicted_comments: str = Field(..., description="Predicted comments")
predicted_shares: str = Field(..., description="Predicted shares")
virality_score: str = Field(..., description="Virality potential score")
class OptimizationSuggestions(BaseModel):
"""Content optimization suggestions."""
content_improvements: List[str] = Field(..., description="Content improvement suggestions")
timing_suggestions: List[str] = Field(..., description="Posting time optimization")
hashtag_improvements: List[str] = Field(..., description="Hashtag optimization suggestions")
visual_suggestions: List[str] = Field(..., description="Visual element suggestions")
engagement_tactics: List[str] = Field(..., description="Engagement boosting tactics")
class FacebookEngagementResponse(BaseModel):
"""Response model for Facebook engagement analysis."""
success: bool = Field(..., description="Whether the analysis was successful")
content_score: Optional[float] = Field(None, description="Overall content quality score (0-100)")
engagement_metrics: Optional[EngagementMetrics] = Field(None, description="Predicted engagement metrics")
optimization_suggestions: Optional[OptimizationSuggestions] = Field(None, description="Optimization recommendations")
sentiment_analysis: Optional[Dict[str, Any]] = Field(None, description="Content sentiment analysis")
trend_alignment: Optional[Dict[str, Any]] = Field(None, description="Alignment with current trends")
competitor_insights: Optional[Dict[str, Any]] = Field(None, description="Competitor comparison insights")
error: Optional[str] = Field(None, description="Error message if analysis failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the analysis")

View File

@@ -0,0 +1,61 @@
"""Pydantic models for Facebook Event functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
from datetime import datetime
class EventType(str, Enum):
"""Event type options."""
WORKSHOP = "Workshop"
WEBINAR = "Webinar"
CONFERENCE = "Conference"
NETWORKING = "Networking event"
PRODUCT_LAUNCH = "Product launch"
SALE_PROMOTION = "Sale/Promotion"
COMMUNITY = "Community event"
EDUCATION = "Educational event"
CUSTOM = "Custom"
class EventFormat(str, Enum):
"""Event format options."""
IN_PERSON = "In-person"
VIRTUAL = "Virtual"
HYBRID = "Hybrid"
class FacebookEventRequest(BaseModel):
"""Request model for Facebook event generation."""
event_name: str = Field(..., description="Name of the event")
event_type: EventType = Field(..., description="Type of event")
custom_event_type: Optional[str] = Field(None, description="Custom event type if 'Custom' is selected")
event_format: EventFormat = Field(..., description="Format of the event")
business_type: str = Field(..., description="Type of business hosting the event")
target_audience: str = Field(..., description="Target audience for the event")
event_date: Optional[str] = Field(None, description="Event date (YYYY-MM-DD format)")
event_time: Optional[str] = Field(None, description="Event time")
location: Optional[str] = Field(None, description="Event location (physical address or virtual platform)")
duration: Optional[str] = Field(None, description="Event duration")
key_benefits: Optional[str] = Field(None, description="Key benefits or highlights of attending")
speakers: Optional[str] = Field(None, description="Key speakers or presenters")
agenda: Optional[str] = Field(None, description="Brief agenda or schedule")
ticket_info: Optional[str] = Field(None, description="Ticket pricing and availability")
special_offers: Optional[str] = Field(None, description="Special offers or early bird discounts")
include: Optional[str] = Field(None, description="Additional elements to include")
avoid: Optional[str] = Field(None, description="Elements to avoid")
class FacebookEventResponse(BaseModel):
"""Response model for Facebook event generation."""
success: bool = Field(..., description="Whether the generation was successful")
event_title: Optional[str] = Field(None, description="Generated event title")
event_description: Optional[str] = Field(None, description="Generated event description")
short_description: Optional[str] = Field(None, description="Short version for social media")
key_highlights: Optional[List[str]] = Field(None, description="Key event highlights")
call_to_action: Optional[str] = Field(None, description="Call-to-action text")
hashtag_suggestions: Optional[List[str]] = Field(None, description="Hashtag suggestions")
promotion_tips: Optional[List[str]] = Field(None, description="Event promotion tips")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,68 @@
"""Pydantic models for Facebook Group Post functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class GroupType(str, Enum):
"""Group type options."""
INDUSTRY = "Industry/Professional"
HOBBY = "Hobby/Interest"
LOCAL = "Local community"
SUPPORT = "Support group"
EDUCATIONAL = "Educational"
BUSINESS = "Business networking"
LIFESTYLE = "Lifestyle"
CUSTOM = "Custom"
class PostPurpose(str, Enum):
"""Post purpose in group."""
SHARE_KNOWLEDGE = "Share knowledge"
ASK_QUESTION = "Ask question"
PROMOTE_BUSINESS = "Promote business"
BUILD_RELATIONSHIPS = "Build relationships"
PROVIDE_VALUE = "Provide value"
SEEK_ADVICE = "Seek advice"
ANNOUNCE_NEWS = "Announce news"
CUSTOM = "Custom"
class GroupRules(BaseModel):
"""Group rules and guidelines."""
no_promotion: bool = Field(default=False, description="No promotion allowed")
value_first: bool = Field(default=True, description="Must provide value first")
no_links: bool = Field(default=False, description="No external links allowed")
community_focused: bool = Field(default=True, description="Must be community-focused")
relevant_only: bool = Field(default=True, description="Only relevant content allowed")
class FacebookGroupPostRequest(BaseModel):
"""Request model for Facebook group post generation."""
group_name: str = Field(..., description="Name of the Facebook group")
group_type: GroupType = Field(..., description="Type of group")
custom_group_type: Optional[str] = Field(None, description="Custom group type if 'Custom' is selected")
post_purpose: PostPurpose = Field(..., description="Purpose of the post")
custom_purpose: Optional[str] = Field(None, description="Custom purpose if 'Custom' is selected")
business_type: str = Field(..., description="Your business type")
topic: str = Field(..., description="Main topic or subject of the post")
target_audience: str = Field(..., description="Target audience within the group")
value_proposition: str = Field(..., description="What value are you providing to the group")
group_rules: GroupRules = Field(default_factory=GroupRules, description="Group rules to follow")
include: Optional[str] = Field(None, description="Elements to include")
avoid: Optional[str] = Field(None, description="Elements to avoid")
call_to_action: Optional[str] = Field(None, description="Desired call-to-action")
class FacebookGroupPostResponse(BaseModel):
"""Response model for Facebook group post generation."""
success: bool = Field(..., description="Whether the generation was successful")
content: Optional[str] = Field(None, description="Generated group post content")
engagement_starters: Optional[List[str]] = Field(None, description="Questions or prompts to encourage engagement")
value_highlights: Optional[List[str]] = Field(None, description="Key value points highlighted in the post")
community_guidelines: Optional[List[str]] = Field(None, description="How the post follows community guidelines")
follow_up_suggestions: Optional[List[str]] = Field(None, description="Suggestions for follow-up engagement")
relationship_building_tips: Optional[List[str]] = Field(None, description="Tips for building relationships in the group")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,54 @@
"""Pydantic models for Facebook Hashtag functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class HashtagPurpose(str, Enum):
"""Hashtag purpose options."""
BRAND_AWARENESS = "Brand awareness"
ENGAGEMENT = "Engagement"
REACH = "Reach expansion"
COMMUNITY = "Community building"
TREND = "Trend participation"
PRODUCT_PROMOTION = "Product promotion"
EVENT_PROMOTION = "Event promotion"
CUSTOM = "Custom"
class HashtagCategory(str, Enum):
"""Hashtag category options."""
BRANDED = "Branded hashtags"
TRENDING = "Trending hashtags"
INDUSTRY = "Industry-specific"
LOCATION = "Location-based"
LIFESTYLE = "Lifestyle"
COMMUNITY = "Community hashtags"
class FacebookHashtagRequest(BaseModel):
"""Request model for Facebook hashtag generation."""
business_type: str = Field(..., description="Type of business")
industry: str = Field(..., description="Industry or niche")
target_audience: str = Field(..., description="Target audience description")
purpose: HashtagPurpose = Field(..., description="Purpose of the hashtags")
custom_purpose: Optional[str] = Field(None, description="Custom purpose if 'Custom' is selected")
content_topic: str = Field(..., description="Topic or theme of the content")
location: Optional[str] = Field(None, description="Location if relevant for local hashtags")
brand_name: Optional[str] = Field(None, description="Brand name for branded hashtags")
campaign_name: Optional[str] = Field(None, description="Campaign name if applicable")
hashtag_count: int = Field(default=10, ge=5, le=30, description="Number of hashtags to generate")
include_categories: List[HashtagCategory] = Field(default_factory=list, description="Categories to include")
class FacebookHashtagResponse(BaseModel):
"""Response model for Facebook hashtag generation."""
success: bool = Field(..., description="Whether the generation was successful")
hashtags: Optional[List[str]] = Field(None, description="Generated hashtags")
categorized_hashtags: Optional[Dict[str, List[str]]] = Field(None, description="Hashtags organized by category")
trending_hashtags: Optional[List[str]] = Field(None, description="Currently trending relevant hashtags")
usage_tips: Optional[List[str]] = Field(None, description="Tips for using hashtags effectively")
performance_predictions: Optional[Dict[str, str]] = Field(None, description="Predicted performance for different hashtag sets")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,80 @@
"""Pydantic models for Facebook Page About functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class BusinessCategory(str, Enum):
"""Business category options."""
RETAIL = "Retail"
RESTAURANT = "Restaurant/Food"
HEALTH_FITNESS = "Health & Fitness"
EDUCATION = "Education"
TECHNOLOGY = "Technology"
CONSULTING = "Consulting"
CREATIVE = "Creative Services"
NONPROFIT = "Non-profit"
ENTERTAINMENT = "Entertainment"
REAL_ESTATE = "Real Estate"
AUTOMOTIVE = "Automotive"
BEAUTY = "Beauty & Personal Care"
FINANCE = "Finance"
TRAVEL = "Travel & Tourism"
CUSTOM = "Custom"
class PageTone(str, Enum):
"""Page tone options."""
PROFESSIONAL = "Professional"
FRIENDLY = "Friendly"
INNOVATIVE = "Innovative"
TRUSTWORTHY = "Trustworthy"
CREATIVE = "Creative"
APPROACHABLE = "Approachable"
AUTHORITATIVE = "Authoritative"
CUSTOM = "Custom"
class ContactInfo(BaseModel):
"""Contact information for the page."""
website: Optional[str] = Field(None, description="Website URL")
phone: Optional[str] = Field(None, description="Phone number")
email: Optional[str] = Field(None, description="Email address")
address: Optional[str] = Field(None, description="Physical address")
hours: Optional[str] = Field(None, description="Business hours")
class FacebookPageAboutRequest(BaseModel):
"""Request model for Facebook page about generation."""
business_name: str = Field(..., description="Name of the business")
business_category: BusinessCategory = Field(..., description="Category of business")
custom_category: Optional[str] = Field(None, description="Custom category if 'Custom' is selected")
business_description: str = Field(..., description="Brief description of what the business does")
target_audience: str = Field(..., description="Target audience description")
unique_value_proposition: str = Field(..., description="What makes the business unique")
services_products: str = Field(..., description="Main services or products offered")
company_history: Optional[str] = Field(None, description="Brief company history or founding story")
mission_vision: Optional[str] = Field(None, description="Mission statement or vision")
achievements: Optional[str] = Field(None, description="Key achievements or awards")
page_tone: PageTone = Field(..., description="Desired tone for the page")
custom_tone: Optional[str] = Field(None, description="Custom tone if 'Custom' is selected")
contact_info: ContactInfo = Field(default_factory=ContactInfo, description="Contact information")
keywords: Optional[str] = Field(None, description="Important keywords to include")
call_to_action: Optional[str] = Field(None, description="Primary call-to-action")
class FacebookPageAboutResponse(BaseModel):
"""Response model for Facebook page about generation."""
success: bool = Field(..., description="Whether the generation was successful")
short_description: Optional[str] = Field(None, description="Short description (under 155 characters)")
long_description: Optional[str] = Field(None, description="Detailed about section")
company_overview: Optional[str] = Field(None, description="Company overview section")
mission_statement: Optional[str] = Field(None, description="Mission statement")
story_section: Optional[str] = Field(None, description="Company story/history section")
services_section: Optional[str] = Field(None, description="Services/products section")
cta_suggestions: Optional[List[str]] = Field(None, description="Call-to-action suggestions")
keyword_optimization: Optional[List[str]] = Field(None, description="SEO keyword suggestions")
completion_tips: Optional[List[str]] = Field(None, description="Tips for completing the page")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,84 @@
"""Pydantic models for Facebook Post functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class PostGoal(str, Enum):
"""Post goal options."""
PROMOTE_PRODUCT = "Promote a product/service"
SHARE_CONTENT = "Share valuable content"
INCREASE_ENGAGEMENT = "Increase engagement"
BUILD_AWARENESS = "Build brand awareness"
DRIVE_TRAFFIC = "Drive website traffic"
GENERATE_LEADS = "Generate leads"
ANNOUNCE_NEWS = "Announce news/updates"
CUSTOM = "Custom"
class PostTone(str, Enum):
"""Post tone options."""
INFORMATIVE = "Informative"
HUMOROUS = "Humorous"
INSPIRATIONAL = "Inspirational"
UPBEAT = "Upbeat"
CASUAL = "Casual"
PROFESSIONAL = "Professional"
CONVERSATIONAL = "Conversational"
CUSTOM = "Custom"
class MediaType(str, Enum):
"""Media type options."""
NONE = "None"
IMAGE = "Image"
VIDEO = "Video"
CAROUSEL = "Carousel"
LINK_PREVIEW = "Link Preview"
class AdvancedOptions(BaseModel):
"""Advanced post generation options."""
use_hook: bool = Field(default=True, description="Use attention-grabbing hook")
use_story: bool = Field(default=True, description="Include storytelling elements")
use_cta: bool = Field(default=True, description="Add clear call-to-action")
use_question: bool = Field(default=True, description="Include engagement question")
use_emoji: bool = Field(default=True, description="Use relevant emojis")
use_hashtags: bool = Field(default=True, description="Add relevant hashtags")
class FacebookPostRequest(BaseModel):
"""Request model for Facebook post generation."""
business_type: str = Field(..., description="Type of business (e.g., 'Fitness coach')")
target_audience: str = Field(..., description="Target audience description (e.g., 'Fitness enthusiasts aged 25-35')")
post_goal: PostGoal = Field(..., description="Main goal of the post")
custom_goal: Optional[str] = Field(None, description="Custom goal if 'Custom' is selected")
post_tone: PostTone = Field(..., description="Tone of the post")
custom_tone: Optional[str] = Field(None, description="Custom tone if 'Custom' is selected")
include: Optional[str] = Field(None, description="Elements to include in the post")
avoid: Optional[str] = Field(None, description="Elements to avoid in the post")
media_type: MediaType = Field(default=MediaType.NONE, description="Type of media to include")
advanced_options: AdvancedOptions = Field(default_factory=AdvancedOptions, description="Advanced generation options")
class FacebookPostAnalytics(BaseModel):
"""Analytics predictions for the generated post."""
expected_reach: str = Field(..., description="Expected reach range")
expected_engagement: str = Field(..., description="Expected engagement percentage")
best_time_to_post: str = Field(..., description="Optimal posting time")
class FacebookPostOptimization(BaseModel):
"""Optimization suggestions for the post."""
suggestions: List[str] = Field(..., description="List of optimization suggestions")
class FacebookPostResponse(BaseModel):
"""Response model for Facebook post generation."""
success: bool = Field(..., description="Whether the generation was successful")
content: Optional[str] = Field(None, description="Generated post content")
analytics: Optional[FacebookPostAnalytics] = Field(None, description="Analytics predictions")
optimization: Optional[FacebookPostOptimization] = Field(None, description="Optimization suggestions")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,61 @@
"""Pydantic models for Facebook Reel functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class ReelType(str, Enum):
"""Reel type options."""
PRODUCT_DEMO = "Product demonstration"
TUTORIAL = "Tutorial/How-to"
ENTERTAINMENT = "Entertainment"
EDUCATIONAL = "Educational"
TREND_BASED = "Trend-based"
BEHIND_SCENES = "Behind the scenes"
USER_GENERATED = "User-generated content"
CUSTOM = "Custom"
class ReelLength(str, Enum):
"""Reel length options."""
SHORT = "15-30 seconds"
MEDIUM = "30-60 seconds"
LONG = "60-90 seconds"
class ReelStyle(str, Enum):
"""Reel style options."""
FAST_PACED = "Fast-paced"
RELAXED = "Relaxed"
DRAMATIC = "Dramatic"
MINIMALIST = "Minimalist"
VIBRANT = "Vibrant"
CUSTOM = "Custom"
class FacebookReelRequest(BaseModel):
"""Request model for Facebook reel generation."""
business_type: str = Field(..., description="Type of business")
target_audience: str = Field(..., description="Target audience description")
reel_type: ReelType = Field(..., description="Type of reel to create")
custom_reel_type: Optional[str] = Field(None, description="Custom reel type if 'Custom' is selected")
reel_length: ReelLength = Field(..., description="Desired length of the reel")
reel_style: ReelStyle = Field(..., description="Style of the reel")
custom_style: Optional[str] = Field(None, description="Custom style if 'Custom' is selected")
topic: str = Field(..., description="Main topic or focus of the reel")
include: Optional[str] = Field(None, description="Elements to include in the reel")
avoid: Optional[str] = Field(None, description="Elements to avoid in the reel")
music_preference: Optional[str] = Field(None, description="Music style preference")
class FacebookReelResponse(BaseModel):
"""Response model for Facebook reel generation."""
success: bool = Field(..., description="Whether the generation was successful")
script: Optional[str] = Field(None, description="Generated reel script")
scene_breakdown: Optional[List[str]] = Field(None, description="Scene-by-scene breakdown")
music_suggestions: Optional[List[str]] = Field(None, description="Music suggestions")
hashtag_suggestions: Optional[List[str]] = Field(None, description="Hashtag suggestions")
engagement_tips: Optional[List[str]] = Field(None, description="Engagement optimization tips")
error: Optional[str] = Field(None, description="Error message if generation failed")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,84 @@
"""Pydantic models for Facebook Story functionality."""
from typing import Optional, List, Dict, Any
from pydantic import BaseModel, Field
from enum import Enum
class StoryType(str, Enum):
"""Story type options."""
PRODUCT_SHOWCASE = "Product showcase"
BEHIND_SCENES = "Behind the scenes"
USER_TESTIMONIAL = "User testimonial"
EVENT_PROMOTION = "Event promotion"
TUTORIAL = "Tutorial/How-to"
QUESTION_POLL = "Question/Poll"
ANNOUNCEMENT = "Announcement"
CUSTOM = "Custom"
class StoryTone(str, Enum):
"""Story tone options."""
CASUAL = "Casual"
FUN = "Fun"
PROFESSIONAL = "Professional"
INSPIRATIONAL = "Inspirational"
EDUCATIONAL = "Educational"
ENTERTAINING = "Entertaining"
CUSTOM = "Custom"
class StoryVisualOptions(BaseModel):
"""Visual options for story."""
# 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):
"""Request model for Facebook story generation."""
business_type: str = Field(..., description="Type of business")
target_audience: str = Field(..., description="Target audience description")
story_type: StoryType = Field(..., description="Type of story to create")
custom_story_type: Optional[str] = Field(None, description="Custom story type if 'Custom' is selected")
story_tone: StoryTone = Field(..., description="Tone of the story")
custom_tone: Optional[str] = Field(None, description="Custom tone if 'Custom' is selected")
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")
metadata: Optional[Dict[str, Any]] = Field(None, description="Additional metadata about the generation")

View File

@@ -0,0 +1,5 @@
"""Facebook Writer API Routers."""
from .facebook_router import router as facebook_router
__all__ = ["facebook_router"]

View File

@@ -0,0 +1,654 @@
"""FastAPI router for Facebook Writer endpoints."""
from fastapi import APIRouter, HTTPException, Depends
from typing import Dict, Any, Optional
import logging
from sqlalchemy.orm import Session
from ..models import *
from ..services import *
from middleware.auth_middleware import get_current_user
from services.database import get_db as get_db_dependency
from utils.text_asset_tracker import save_and_track_text_content
# Configure logging
logger = logging.getLogger(__name__)
# Create router
router = APIRouter(
prefix="/api/facebook-writer",
tags=["Facebook Writer"],
responses={404: {"description": "Not found"}},
)
# Initialize services
post_service = FacebookPostService()
story_service = FacebookStoryService()
reel_service = FacebookReelService()
carousel_service = FacebookCarouselService()
event_service = FacebookEventService()
hashtag_service = FacebookHashtagService()
engagement_service = FacebookEngagementService()
group_post_service = FacebookGroupPostService()
page_about_service = FacebookPageAboutService()
ad_copy_service = FacebookAdCopyService()
@router.get("/health")
async def health_check():
"""Health check endpoint for Facebook Writer API."""
return {"status": "healthy", "service": "Facebook Writer API"}
@router.get("/tools")
async def get_available_tools():
"""Get list of available Facebook Writer tools."""
tools = [
{
"name": "FB Post Generator",
"endpoint": "/post/generate",
"description": "Create engaging Facebook posts that drive engagement and reach",
"icon": "📝",
"category": "Content Creation"
},
{
"name": "FB Story Generator",
"endpoint": "/story/generate",
"description": "Generate creative Facebook Stories with text overlays and engagement elements",
"icon": "📱",
"category": "Content Creation"
},
{
"name": "FB Reel Generator",
"endpoint": "/reel/generate",
"description": "Create engaging Facebook Reels scripts with trending music suggestions",
"icon": "🎥",
"category": "Content Creation"
},
{
"name": "Carousel Generator",
"endpoint": "/carousel/generate",
"description": "Generate multi-image carousel posts with engaging captions for each slide",
"icon": "🔄",
"category": "Content Creation"
},
{
"name": "Event Description Generator",
"endpoint": "/event/generate",
"description": "Create compelling event descriptions that drive attendance and engagement",
"icon": "📅",
"category": "Business Tools"
},
{
"name": "Group Post Generator",
"endpoint": "/group-post/generate",
"description": "Generate engaging posts for Facebook Groups with community-focused content",
"icon": "👥",
"category": "Business Tools"
},
{
"name": "Page About Generator",
"endpoint": "/page-about/generate",
"description": "Create professional and engaging About sections for your Facebook Page",
"icon": "",
"category": "Business Tools"
},
{
"name": "Ad Copy Generator",
"endpoint": "/ad-copy/generate",
"description": "Generate high-converting ad copy for Facebook Ads with targeting suggestions",
"icon": "💰",
"category": "Marketing Tools"
},
{
"name": "Hashtag Generator",
"endpoint": "/hashtags/generate",
"description": "Generate trending and relevant hashtags for your Facebook content",
"icon": "#️⃣",
"category": "Marketing Tools"
},
{
"name": "Engagement Analyzer",
"endpoint": "/engagement/analyze",
"description": "Analyze your content performance and get AI-powered improvement suggestions",
"icon": "📊",
"category": "Marketing Tools"
}
]
return {"tools": tools, "total_count": len(tools)}
# Use the proper database dependency from services.database
get_db = get_db_dependency
# Content Creation Endpoints
@router.post("/post/generate", response_model=FacebookPostResponse)
async def generate_facebook_post(
request: FacebookPostRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook post with engagement optimization."""
try:
logger.info(f"Generating Facebook post for business: {request.business_type}")
response = post_service.generate_post(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.content:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
text_content = response.content
if response.analytics:
text_content += f"\n\n## Analytics\nExpected Reach: {response.analytics.expected_reach}\nExpected Engagement: {response.analytics.expected_engagement}\nBest Time to Post: {response.analytics.best_time_to_post}"
save_and_track_text_content(
db=db,
user_id=user_id,
content=text_content,
source_module="facebook_writer",
title=f"Facebook Post: {request.business_type[:60]}",
description=f"Facebook post for {request.business_type}",
prompt=f"Business Type: {request.business_type}\nTarget Audience: {request.target_audience}\nGoal: {request.post_goal.value if hasattr(request.post_goal, 'value') else request.post_goal}\nTone: {request.post_tone.value if hasattr(request.post_tone, 'value') else request.post_tone}",
tags=["facebook", "post", request.business_type.lower().replace(' ', '_')],
asset_metadata={
"post_goal": request.post_goal.value if hasattr(request.post_goal, 'value') else str(request.post_goal),
"post_tone": request.post_tone.value if hasattr(request.post_tone, 'value') else str(request.post_tone),
"media_type": request.media_type.value if hasattr(request.media_type, 'value') else str(request.media_type)
},
subdirectory="posts"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook post asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook post: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/story/generate", response_model=FacebookStoryResponse)
async def generate_facebook_story(
request: FacebookStoryRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook story with visual suggestions."""
try:
logger.info(f"Generating Facebook story for business: {request.business_type}")
response = story_service.generate_story(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.content:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
save_and_track_text_content(
db=db,
user_id=user_id,
content=response.content,
source_module="facebook_writer",
title=f"Facebook Story: {request.business_type[:60]}",
description=f"Facebook story for {request.business_type}",
prompt=f"Business Type: {request.business_type}\nStory Type: {request.story_type.value if hasattr(request.story_type, 'value') else request.story_type}",
tags=["facebook", "story", request.business_type.lower().replace(' ', '_')],
asset_metadata={
"story_type": request.story_type.value if hasattr(request.story_type, 'value') else str(request.story_type)
},
subdirectory="stories"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook story asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook story: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/reel/generate", response_model=FacebookReelResponse)
async def generate_facebook_reel(
request: FacebookReelRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook reel script with music suggestions."""
try:
logger.info(f"Generating Facebook reel for business: {request.business_type}")
response = reel_service.generate_reel(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.script:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
text_content = f"# Facebook Reel Script\n\n## Script\n{response.script}\n"
if response.scene_breakdown:
text_content += f"\n## Scene Breakdown\n" + "\n".join([f"{i+1}. {scene}" for i, scene in enumerate(response.scene_breakdown)]) + "\n"
if response.music_suggestions:
text_content += f"\n## Music Suggestions\n" + "\n".join(response.music_suggestions) + "\n"
if response.hashtag_suggestions:
text_content += f"\n## Hashtag Suggestions\n" + " ".join([f"#{tag}" for tag in response.hashtag_suggestions]) + "\n"
save_and_track_text_content(
db=db,
user_id=user_id,
content=text_content,
source_module="facebook_writer",
title=f"Facebook Reel: {request.topic[:60]}",
description=f"Facebook reel script for {request.business_type}",
prompt=f"Business Type: {request.business_type}\nTopic: {request.topic}\nReel Type: {request.reel_type.value if hasattr(request.reel_type, 'value') else request.reel_type}\nLength: {request.reel_length.value if hasattr(request.reel_length, 'value') else request.reel_length}",
tags=["facebook", "reel", request.business_type.lower().replace(' ', '_')],
asset_metadata={
"reel_type": request.reel_type.value if hasattr(request.reel_type, 'value') else str(request.reel_type),
"reel_length": request.reel_length.value if hasattr(request.reel_length, 'value') else str(request.reel_length),
"reel_style": request.reel_style.value if hasattr(request.reel_style, 'value') else str(request.reel_style)
},
subdirectory="reels",
file_extension=".md"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook reel asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook reel: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/carousel/generate", response_model=FacebookCarouselResponse)
async def generate_facebook_carousel(
request: FacebookCarouselRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook carousel post with multiple slides."""
try:
logger.info(f"Generating Facebook carousel for business: {request.business_type}")
response = carousel_service.generate_carousel(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.main_caption and response.slides:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
text_content = f"# Facebook Carousel\n\n## Main Caption\n{response.main_caption}\n\n"
text_content += "## Slides\n"
for i, slide in enumerate(response.slides, 1):
text_content += f"\n### Slide {i}: {slide.title}\n{slide.content}\n"
if slide.image_description:
text_content += f"Image Description: {slide.image_description}\n"
if response.hashtag_suggestions:
text_content += f"\n## Hashtag Suggestions\n" + " ".join([f"#{tag}" for tag in response.hashtag_suggestions]) + "\n"
save_and_track_text_content(
db=db,
user_id=user_id,
content=text_content,
source_module="facebook_writer",
title=f"Facebook Carousel: {request.topic[:60]}",
description=f"Facebook carousel for {request.business_type}",
prompt=f"Business Type: {request.business_type}\nTopic: {request.topic}\nCarousel Type: {request.carousel_type.value if hasattr(request.carousel_type, 'value') else request.carousel_type}\nSlides: {request.num_slides}",
tags=["facebook", "carousel", request.business_type.lower().replace(' ', '_')],
asset_metadata={
"carousel_type": request.carousel_type.value if hasattr(request.carousel_type, 'value') else str(request.carousel_type),
"num_slides": request.num_slides,
"has_cta": request.include_cta
},
subdirectory="carousels",
file_extension=".md"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook carousel asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook carousel: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
# Business Tools Endpoints
@router.post("/event/generate", response_model=FacebookEventResponse)
async def generate_facebook_event(
request: FacebookEventRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook event description."""
try:
logger.info(f"Generating Facebook event: {request.event_name}")
response = event_service.generate_event(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.description:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
text_content = f"# Facebook Event: {request.event_name}\n\n## Description\n{response.description}\n"
if hasattr(response, 'details') and response.details:
text_content += f"\n## Details\n{response.details}\n"
save_and_track_text_content(
db=db,
user_id=user_id,
content=text_content,
source_module="facebook_writer",
title=f"Facebook Event: {request.event_name[:60]}",
description=f"Facebook event description for {request.event_name}",
prompt=f"Event Name: {request.event_name}\nEvent Type: {getattr(request, 'event_type', 'N/A')}\nDate: {getattr(request, 'event_date', 'N/A')}",
tags=["facebook", "event", request.event_name.lower().replace(' ', '_')[:20]],
asset_metadata={
"event_name": request.event_name,
"event_type": getattr(request, 'event_type', None)
},
subdirectory="events"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook event asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook event: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/group-post/generate", response_model=FacebookGroupPostResponse)
async def generate_facebook_group_post(
request: FacebookGroupPostRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook group post following community guidelines."""
try:
logger.info(f"Generating Facebook group post for: {request.group_name}")
response = group_post_service.generate_group_post(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.content:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
save_and_track_text_content(
db=db,
user_id=user_id,
content=response.content,
source_module="facebook_writer",
title=f"Facebook Group Post: {request.group_name[:60]}",
description=f"Facebook group post for {request.group_name}",
prompt=f"Group Name: {request.group_name}\nTopic: {getattr(request, 'topic', 'N/A')}",
tags=["facebook", "group_post", request.group_name.lower().replace(' ', '_')[:20]],
asset_metadata={
"group_name": request.group_name,
"group_type": getattr(request, 'group_type', None)
},
subdirectory="group_posts"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook group post asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook group post: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/page-about/generate", response_model=FacebookPageAboutResponse)
async def generate_facebook_page_about(
request: FacebookPageAboutRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate a Facebook page about section."""
try:
logger.info(f"Generating Facebook page about for: {request.business_name}")
response = page_about_service.generate_page_about(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.about_section:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
save_and_track_text_content(
db=db,
user_id=user_id,
content=response.about_section,
source_module="facebook_writer",
title=f"Facebook Page About: {request.business_name[:60]}",
description=f"Facebook page about section for {request.business_name}",
prompt=f"Business Name: {request.business_name}\nBusiness Type: {getattr(request, 'business_type', 'N/A')}",
tags=["facebook", "page_about", request.business_name.lower().replace(' ', '_')[:20]],
asset_metadata={
"business_name": request.business_name,
"business_type": getattr(request, 'business_type', None)
},
subdirectory="page_about"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook page about asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook page about: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
# Marketing Tools Endpoints
@router.post("/ad-copy/generate", response_model=FacebookAdCopyResponse)
async def generate_facebook_ad_copy(
request: FacebookAdCopyRequest,
current_user: Optional[Dict[str, Any]] = Depends(get_current_user),
db: Session = Depends(get_db)
):
"""Generate Facebook ad copy with targeting suggestions."""
try:
logger.info(f"Generating Facebook ad copy for: {request.business_type}")
response = ad_copy_service.generate_ad_copy(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
# Save and track text content (non-blocking)
if response.ad_copy:
try:
user_id = None
if current_user:
user_id = str(current_user.get('id', '') or current_user.get('sub', ''))
if user_id:
text_content = f"# Facebook Ad Copy\n\n## Ad Copy\n{response.ad_copy}\n"
if hasattr(response, 'headline') and response.headline:
text_content += f"\n## Headline\n{response.headline}\n"
if hasattr(response, 'description') and response.description:
text_content += f"\n## Description\n{response.description}\n"
if hasattr(response, 'targeting_suggestions') and response.targeting_suggestions:
text_content += f"\n## Targeting Suggestions\n" + "\n".join(response.targeting_suggestions) + "\n"
save_and_track_text_content(
db=db,
user_id=user_id,
content=text_content,
source_module="facebook_writer",
title=f"Facebook Ad Copy: {request.business_type[:60]}",
description=f"Facebook ad copy for {request.business_type}",
prompt=f"Business Type: {request.business_type}\nAd Objective: {getattr(request, 'ad_objective', 'N/A')}\nTarget Audience: {getattr(request, 'target_audience', 'N/A')}",
tags=["facebook", "ad_copy", request.business_type.lower().replace(' ', '_')],
asset_metadata={
"ad_objective": getattr(request, 'ad_objective', None),
"budget": getattr(request, 'budget', None)
},
subdirectory="ad_copy",
file_extension=".md"
)
except Exception as track_error:
logger.warning(f"Failed to track Facebook ad copy asset: {track_error}")
return response
except Exception as e:
logger.error(f"Error generating Facebook ad copy: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/hashtags/generate", response_model=FacebookHashtagResponse)
async def generate_facebook_hashtags(request: FacebookHashtagRequest):
"""Generate relevant hashtags for Facebook content."""
try:
logger.info(f"Generating Facebook hashtags for: {request.content_topic}")
response = hashtag_service.generate_hashtags(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
return response
except Exception as e:
logger.error(f"Error generating Facebook hashtags: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
@router.post("/engagement/analyze", response_model=FacebookEngagementResponse)
async def analyze_facebook_engagement(request: FacebookEngagementRequest):
"""Analyze Facebook content for engagement optimization."""
try:
logger.info(f"Analyzing Facebook engagement for {request.content_type.value}")
response = engagement_service.analyze_engagement(request)
if not response.success:
raise HTTPException(status_code=400, detail=response.error)
return response
except Exception as e:
logger.error(f"Error analyzing Facebook engagement: {e}")
raise HTTPException(status_code=500, detail=f"Internal server error: {str(e)}")
# Utility Endpoints
@router.get("/post/templates")
async def get_post_templates():
"""Get predefined post templates."""
templates = [
{
"name": "Product Launch",
"description": "Template for announcing new products",
"goal": "Promote a product/service",
"tone": "Upbeat",
"structure": "Hook + Features + Benefits + CTA"
},
{
"name": "Educational Content",
"description": "Template for sharing knowledge",
"goal": "Share valuable content",
"tone": "Informative",
"structure": "Problem + Solution + Tips + Engagement Question"
},
{
"name": "Community Engagement",
"description": "Template for building community",
"goal": "Increase engagement",
"tone": "Conversational",
"structure": "Question + Context + Personal Experience + Call for Comments"
}
]
return {"templates": templates}
@router.get("/analytics/benchmarks")
async def get_analytics_benchmarks():
"""Get Facebook analytics benchmarks by industry."""
benchmarks = {
"general": {
"average_engagement_rate": "3.91%",
"average_reach": "5.5%",
"best_posting_times": ["1 PM - 3 PM", "3 PM - 4 PM"]
},
"retail": {
"average_engagement_rate": "4.2%",
"average_reach": "6.1%",
"best_posting_times": ["12 PM - 2 PM", "5 PM - 7 PM"]
},
"health_fitness": {
"average_engagement_rate": "5.1%",
"average_reach": "7.2%",
"best_posting_times": ["6 AM - 8 AM", "6 PM - 8 PM"]
}
}
return {"benchmarks": benchmarks}
@router.get("/compliance/guidelines")
async def get_compliance_guidelines():
"""Get Facebook content compliance guidelines."""
guidelines = {
"general": [
"Avoid misleading or false information",
"Don't use excessive capitalization",
"Ensure claims are substantiated",
"Respect intellectual property rights"
],
"advertising": [
"Include required disclaimers",
"Avoid prohibited content categories",
"Use appropriate targeting",
"Follow industry-specific regulations"
],
"community": [
"Respect community standards",
"Avoid spam or repetitive content",
"Don't engage in artificial engagement",
"Report violations appropriately"
]
}
return {"guidelines": guidelines}

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"
]