ALwrity persona system
This commit is contained in:
@@ -45,6 +45,24 @@ class PersonaGenerationResponse(BaseModel):
|
||||
data_sufficiency: Optional[float] = None
|
||||
platforms_generated: List[str] = []
|
||||
|
||||
class LinkedInPersonaValidationRequest(BaseModel):
|
||||
"""Request model for LinkedIn persona validation."""
|
||||
persona_data: Dict[str, Any]
|
||||
|
||||
class LinkedInPersonaValidationResponse(BaseModel):
|
||||
"""Response model for LinkedIn persona validation."""
|
||||
is_valid: bool
|
||||
quality_score: float
|
||||
completeness_score: float
|
||||
professional_context_score: float
|
||||
linkedin_optimization_score: float
|
||||
missing_fields: List[str]
|
||||
incomplete_fields: List[str]
|
||||
recommendations: List[str]
|
||||
quality_issues: List[str]
|
||||
strengths: List[str]
|
||||
validation_details: Dict[str, Any]
|
||||
|
||||
# Dependency to get persona service
|
||||
def get_persona_service() -> PersonaAnalysisService:
|
||||
"""Get the persona analysis service instance."""
|
||||
@@ -380,6 +398,211 @@ async def get_supported_platforms():
|
||||
"description": "Newsletter platform for building subscriber relationships",
|
||||
"format": "email newsletter",
|
||||
"subscription_focus": True
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
class LinkedInOptimizationRequest(BaseModel):
|
||||
"""Request model for LinkedIn algorithm optimization."""
|
||||
persona_data: Dict[str, Any]
|
||||
|
||||
|
||||
class LinkedInOptimizationResponse(BaseModel):
|
||||
"""Response model for LinkedIn algorithm optimization."""
|
||||
optimized_persona: Dict[str, Any]
|
||||
optimization_applied: bool
|
||||
optimization_details: Dict[str, Any]
|
||||
|
||||
|
||||
async def validate_linkedin_persona(
|
||||
request: LinkedInPersonaValidationRequest,
|
||||
persona_service: PersonaAnalysisService = Depends(get_persona_service)
|
||||
):
|
||||
"""
|
||||
Validate LinkedIn persona data for completeness and quality.
|
||||
|
||||
This endpoint provides comprehensive validation of LinkedIn persona data,
|
||||
including core fields, LinkedIn-specific optimizations, professional context,
|
||||
and content quality assessments.
|
||||
"""
|
||||
try:
|
||||
logger.info("Validating LinkedIn persona data")
|
||||
|
||||
# Get LinkedIn persona service
|
||||
from services.persona.linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
linkedin_service = LinkedInPersonaService()
|
||||
|
||||
# Validate the persona data
|
||||
validation_results = linkedin_service.validate_linkedin_persona(request.persona_data)
|
||||
|
||||
logger.info(f"LinkedIn persona validation completed: Quality Score: {validation_results['quality_score']:.1f}%")
|
||||
|
||||
return LinkedInPersonaValidationResponse(**validation_results)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error validating LinkedIn persona: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to validate LinkedIn persona: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
async def optimize_linkedin_persona(
|
||||
request: LinkedInOptimizationRequest,
|
||||
persona_service: PersonaAnalysisService = Depends(get_persona_service)
|
||||
):
|
||||
"""
|
||||
Optimize LinkedIn persona data for maximum algorithm performance.
|
||||
|
||||
This endpoint applies comprehensive LinkedIn algorithm optimization to persona data,
|
||||
including content quality optimization, multimedia strategy, engagement optimization,
|
||||
timing optimization, and professional context optimization.
|
||||
"""
|
||||
try:
|
||||
logger.info("Optimizing LinkedIn persona for algorithm performance")
|
||||
|
||||
# Get LinkedIn persona service
|
||||
from services.persona.linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
linkedin_service = LinkedInPersonaService()
|
||||
|
||||
# Apply algorithm optimization
|
||||
optimized_persona = linkedin_service.optimize_for_linkedin_algorithm(request.persona_data)
|
||||
|
||||
# Extract optimization details
|
||||
optimization_details = optimized_persona.get("algorithm_optimization", {})
|
||||
|
||||
logger.info("✅ LinkedIn persona algorithm optimization completed successfully")
|
||||
|
||||
return LinkedInOptimizationResponse(
|
||||
optimized_persona=optimized_persona,
|
||||
optimization_applied=True,
|
||||
optimization_details={
|
||||
"optimization_categories": list(optimization_details.keys()),
|
||||
"total_optimization_strategies": sum(len(strategies) if isinstance(strategies, list) else 1
|
||||
for category in optimization_details.values()
|
||||
for strategies in category.values() if isinstance(category, dict)),
|
||||
"optimization_timestamp": datetime.utcnow().isoformat()
|
||||
}
|
||||
]
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error optimizing LinkedIn persona: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to optimize LinkedIn persona: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
class FacebookPersonaValidationRequest(BaseModel):
|
||||
"""Request model for Facebook persona validation."""
|
||||
persona_data: Dict[str, Any]
|
||||
|
||||
|
||||
class FacebookPersonaValidationResponse(BaseModel):
|
||||
"""Response model for Facebook persona validation."""
|
||||
is_valid: bool
|
||||
quality_score: float
|
||||
completeness_score: float
|
||||
facebook_optimization_score: float
|
||||
engagement_strategy_score: float
|
||||
content_format_score: float
|
||||
audience_targeting_score: float
|
||||
community_building_score: float
|
||||
missing_fields: List[str]
|
||||
incomplete_fields: List[str]
|
||||
recommendations: List[str]
|
||||
quality_issues: List[str]
|
||||
strengths: List[str]
|
||||
validation_details: Dict[str, Any]
|
||||
|
||||
|
||||
class FacebookOptimizationRequest(BaseModel):
|
||||
"""Request model for Facebook algorithm optimization."""
|
||||
persona_data: Dict[str, Any]
|
||||
|
||||
|
||||
class FacebookOptimizationResponse(BaseModel):
|
||||
"""Response model for Facebook algorithm optimization."""
|
||||
optimized_persona: Dict[str, Any]
|
||||
optimization_applied: bool
|
||||
optimization_details: Dict[str, Any]
|
||||
|
||||
|
||||
async def validate_facebook_persona(
|
||||
request: FacebookPersonaValidationRequest,
|
||||
persona_service: PersonaAnalysisService = Depends(get_persona_service)
|
||||
):
|
||||
"""
|
||||
Validate Facebook persona data for completeness and quality.
|
||||
|
||||
This endpoint provides comprehensive validation of Facebook persona data,
|
||||
including core fields, Facebook-specific optimizations, engagement strategies,
|
||||
content formats, audience targeting, and community building assessments.
|
||||
"""
|
||||
try:
|
||||
logger.info("Validating Facebook persona data")
|
||||
|
||||
# Get Facebook persona service
|
||||
from services.persona.facebook.facebook_persona_service import FacebookPersonaService
|
||||
facebook_service = FacebookPersonaService()
|
||||
|
||||
# Validate the persona data
|
||||
validation_results = facebook_service.validate_facebook_persona(request.persona_data)
|
||||
|
||||
logger.info(f"Facebook persona validation completed: Quality Score: {validation_results['quality_score']:.1f}%")
|
||||
|
||||
return FacebookPersonaValidationResponse(**validation_results)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error validating Facebook persona: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to validate Facebook persona: {str(e)}"
|
||||
)
|
||||
|
||||
|
||||
async def optimize_facebook_persona(
|
||||
request: FacebookOptimizationRequest,
|
||||
persona_service: PersonaAnalysisService = Depends(get_persona_service)
|
||||
):
|
||||
"""
|
||||
Optimize Facebook persona data for maximum algorithm performance.
|
||||
|
||||
This endpoint applies comprehensive Facebook algorithm optimization to persona data,
|
||||
including engagement optimization, content quality optimization, timing optimization,
|
||||
audience targeting optimization, and community building strategies.
|
||||
"""
|
||||
try:
|
||||
logger.info("Optimizing Facebook persona for algorithm performance")
|
||||
|
||||
# Get Facebook persona service
|
||||
from services.persona.facebook.facebook_persona_service import FacebookPersonaService
|
||||
facebook_service = FacebookPersonaService()
|
||||
|
||||
# Apply algorithm optimization
|
||||
optimized_persona = facebook_service.optimize_for_facebook_algorithm(request.persona_data)
|
||||
|
||||
# Extract optimization details
|
||||
optimization_details = optimized_persona.get("algorithm_optimization", {})
|
||||
|
||||
logger.info("✅ Facebook persona algorithm optimization completed successfully")
|
||||
|
||||
# Use the optimization metadata from the service
|
||||
optimization_metadata = optimized_persona.get("optimization_metadata", {})
|
||||
|
||||
return FacebookOptimizationResponse(
|
||||
optimized_persona=optimized_persona,
|
||||
optimization_applied=True,
|
||||
optimization_details={
|
||||
"optimization_categories": optimization_metadata.get("optimization_categories", []),
|
||||
"total_optimization_strategies": optimization_metadata.get("total_optimization_strategies", 0),
|
||||
"optimization_timestamp": optimization_metadata.get("optimization_timestamp", datetime.utcnow().isoformat())
|
||||
}
|
||||
)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error optimizing Facebook persona: {str(e)}")
|
||||
raise HTTPException(
|
||||
status_code=500,
|
||||
detail=f"Failed to optimize Facebook persona: {str(e)}"
|
||||
)
|
||||
@@ -16,7 +16,19 @@ from api.persona import (
|
||||
validate_persona_generation_readiness,
|
||||
generate_persona_preview,
|
||||
get_supported_platforms,
|
||||
PersonaGenerationRequest
|
||||
validate_linkedin_persona,
|
||||
optimize_linkedin_persona,
|
||||
validate_facebook_persona,
|
||||
optimize_facebook_persona,
|
||||
PersonaGenerationRequest,
|
||||
LinkedInPersonaValidationRequest,
|
||||
LinkedInPersonaValidationResponse,
|
||||
LinkedInOptimizationRequest,
|
||||
LinkedInOptimizationResponse,
|
||||
FacebookPersonaValidationRequest,
|
||||
FacebookPersonaValidationResponse,
|
||||
FacebookOptimizationRequest,
|
||||
FacebookOptimizationResponse
|
||||
)
|
||||
|
||||
from services.persona_replication_engine import PersonaReplicationEngine
|
||||
@@ -89,6 +101,34 @@ async def get_supported_platforms_endpoint():
|
||||
"""Get list of supported platforms for persona generation."""
|
||||
return await get_supported_platforms()
|
||||
|
||||
@router.post("/linkedin/validate", response_model=LinkedInPersonaValidationResponse)
|
||||
async def validate_linkedin_persona_endpoint(
|
||||
request: LinkedInPersonaValidationRequest
|
||||
):
|
||||
"""Validate LinkedIn persona data for completeness and quality."""
|
||||
return await validate_linkedin_persona(request)
|
||||
|
||||
@router.post("/linkedin/optimize", response_model=LinkedInOptimizationResponse)
|
||||
async def optimize_linkedin_persona_endpoint(
|
||||
request: LinkedInOptimizationRequest
|
||||
):
|
||||
"""Optimize LinkedIn persona data for maximum algorithm performance."""
|
||||
return await optimize_linkedin_persona(request)
|
||||
|
||||
@router.post("/facebook/validate", response_model=FacebookPersonaValidationResponse)
|
||||
async def validate_facebook_persona_endpoint(
|
||||
request: FacebookPersonaValidationRequest
|
||||
):
|
||||
"""Validate Facebook persona data for completeness and quality."""
|
||||
return await validate_facebook_persona(request)
|
||||
|
||||
@router.post("/facebook/optimize", response_model=FacebookOptimizationResponse)
|
||||
async def optimize_facebook_persona_endpoint(
|
||||
request: FacebookOptimizationRequest
|
||||
):
|
||||
"""Optimize Facebook persona data for maximum algorithm performance."""
|
||||
return await optimize_facebook_persona(request)
|
||||
|
||||
@router.post("/generate-content")
|
||||
async def generate_content_with_persona_endpoint(
|
||||
request: Dict[str, Any]
|
||||
|
||||
@@ -1,473 +0,0 @@
|
||||
# LinkedIn Content Generation Service
|
||||
|
||||
A comprehensive FastAPI-based service for generating professional LinkedIn content using AI. This service has been migrated from the legacy Streamlit implementation to provide robust API endpoints for LinkedIn content creation.
|
||||
|
||||
## Overview
|
||||
|
||||
The LinkedIn Content Generation Service provides AI-powered tools for creating various types of LinkedIn content:
|
||||
|
||||
- **Posts**: Short-form professional posts with research-backed content
|
||||
- **Articles**: Long-form articles with SEO optimization
|
||||
- **Carousels**: Multi-slide visual content
|
||||
- **Video Scripts**: Structured scripts for LinkedIn videos
|
||||
- **Comment Responses**: Professional responses to LinkedIn comments
|
||||
|
||||
## Features
|
||||
|
||||
### 🚀 Core Capabilities
|
||||
|
||||
- **Multi-format Content Generation**: Posts, articles, carousels, video scripts, and comment responses
|
||||
- **Research Integration**: Automated research using multiple search engines (Metaphor, Google, Tavily)
|
||||
- **AI-Powered Optimization**: Industry-specific content optimization using Gemini AI
|
||||
- **SEO Enhancement**: Built-in SEO optimization for LinkedIn articles
|
||||
- **Engagement Prediction**: AI-based engagement metrics prediction
|
||||
- **Professional Tone Control**: Multiple tone options (professional, conversational, authoritative, etc.)
|
||||
|
||||
### 🛠 Technical Features
|
||||
|
||||
- **FastAPI Integration**: RESTful API with automatic documentation
|
||||
- **Comprehensive Error Handling**: Robust exception handling and logging
|
||||
- **Database Monitoring**: Request logging and performance monitoring
|
||||
- **Async/Await Support**: Non-blocking operations for better performance
|
||||
- **Pydantic Validation**: Strong request/response validation
|
||||
- **Structured JSON Responses**: Consistent API response format
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Base URL
|
||||
```
|
||||
/api/linkedin
|
||||
```
|
||||
|
||||
### Available Endpoints
|
||||
|
||||
| Endpoint | Method | Description |
|
||||
|----------|--------|-------------|
|
||||
| `/health` | GET | Health check for service status |
|
||||
| `/generate-post` | POST | Generate LinkedIn posts |
|
||||
| `/generate-article` | POST | Generate LinkedIn articles |
|
||||
| `/generate-carousel` | POST | Generate LinkedIn carousels |
|
||||
| `/generate-video-script` | POST | Generate video scripts |
|
||||
| `/generate-comment-response` | POST | Generate comment responses |
|
||||
| `/content-types` | GET | Get available content types |
|
||||
| `/usage-stats` | GET | Get usage statistics |
|
||||
|
||||
## Quick Start
|
||||
|
||||
### 1. Prerequisites
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Set environment variables
|
||||
export GEMINI_API_KEY="your_gemini_api_key"
|
||||
export DATABASE_URL="sqlite:///./alwrity.db"
|
||||
```
|
||||
|
||||
### 2. Start the Service
|
||||
|
||||
```bash
|
||||
# Start FastAPI server
|
||||
uvicorn app:app --host 0.0.0.0 --port 8000 --reload
|
||||
```
|
||||
|
||||
### 3. Access Documentation
|
||||
|
||||
- **Interactive API Docs**: http://localhost:8000/docs
|
||||
- **Alternative Docs**: http://localhost:8000/redoc
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Generate a LinkedIn Post
|
||||
|
||||
```python
|
||||
import requests
|
||||
|
||||
# Request payload
|
||||
payload = {
|
||||
"topic": "Artificial Intelligence in Healthcare",
|
||||
"industry": "Healthcare",
|
||||
"post_type": "thought_leadership",
|
||||
"tone": "professional",
|
||||
"target_audience": "Healthcare executives",
|
||||
"key_points": ["AI diagnostics", "Patient outcomes", "Cost reduction"],
|
||||
"include_hashtags": True,
|
||||
"include_call_to_action": True,
|
||||
"research_enabled": True,
|
||||
"max_length": 2000
|
||||
}
|
||||
|
||||
# Make request
|
||||
response = requests.post(
|
||||
"http://localhost:8000/api/linkedin/generate-post",
|
||||
json=payload
|
||||
)
|
||||
|
||||
# Process response
|
||||
if response.status_code == 200:
|
||||
data = response.json()
|
||||
print(f"Generated post: {data['data']['content']}")
|
||||
print(f"Hashtags: {[h['hashtag'] for h in data['data']['hashtags']]}")
|
||||
else:
|
||||
print(f"Error: {response.status_code}")
|
||||
```
|
||||
|
||||
### Generate a LinkedIn Article
|
||||
|
||||
```python
|
||||
payload = {
|
||||
"topic": "Digital Transformation in Manufacturing",
|
||||
"industry": "Manufacturing",
|
||||
"tone": "professional",
|
||||
"target_audience": "Manufacturing leaders",
|
||||
"key_sections": ["Current challenges", "Technology solutions", "Implementation strategies"],
|
||||
"include_images": True,
|
||||
"seo_optimization": True,
|
||||
"research_enabled": True,
|
||||
"word_count": 1500
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
"http://localhost:8000/api/linkedin/generate-article",
|
||||
json=payload
|
||||
)
|
||||
```
|
||||
|
||||
### Generate a LinkedIn Carousel
|
||||
|
||||
```python
|
||||
payload = {
|
||||
"topic": "5 Ways to Improve Team Productivity",
|
||||
"industry": "Business Management",
|
||||
"slide_count": 8,
|
||||
"tone": "professional",
|
||||
"target_audience": "Team leaders and managers",
|
||||
"key_takeaways": ["Clear communication", "Goal setting", "Tool optimization"],
|
||||
"include_cover_slide": True,
|
||||
"include_cta_slide": True,
|
||||
"visual_style": "modern"
|
||||
}
|
||||
|
||||
response = requests.post(
|
||||
"http://localhost:8000/api/linkedin/generate-carousel",
|
||||
json=payload
|
||||
)
|
||||
```
|
||||
|
||||
## Request/Response Models
|
||||
|
||||
### LinkedIn Post Request
|
||||
|
||||
```json
|
||||
{
|
||||
"topic": "string",
|
||||
"industry": "string",
|
||||
"post_type": "professional|thought_leadership|industry_news|personal_story|company_update|poll",
|
||||
"tone": "professional|conversational|authoritative|inspirational|educational|friendly",
|
||||
"target_audience": "string (optional)",
|
||||
"key_points": ["string"] (optional),
|
||||
"include_hashtags": true,
|
||||
"include_call_to_action": true,
|
||||
"research_enabled": true,
|
||||
"search_engine": "metaphor|google|tavily",
|
||||
"max_length": 3000
|
||||
}
|
||||
```
|
||||
|
||||
### LinkedIn Post Response
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"data": {
|
||||
"content": "Generated post content...",
|
||||
"character_count": 1250,
|
||||
"hashtags": [
|
||||
{
|
||||
"hashtag": "#AIinHealthcare",
|
||||
"category": "industry",
|
||||
"popularity_score": 0.9
|
||||
}
|
||||
],
|
||||
"call_to_action": "What's your experience with AI in healthcare?",
|
||||
"engagement_prediction": {
|
||||
"estimated_likes": 120,
|
||||
"estimated_comments": 15,
|
||||
"estimated_shares": 8
|
||||
}
|
||||
},
|
||||
"research_sources": [
|
||||
{
|
||||
"title": "AI in Healthcare: Current Trends",
|
||||
"url": "https://example.com/ai-healthcare",
|
||||
"content": "Summary of AI healthcare trends...",
|
||||
"relevance_score": 0.95
|
||||
}
|
||||
],
|
||||
"generation_metadata": {
|
||||
"generation_time": 3.2,
|
||||
"timestamp": "2025-01-27T10:00:00Z",
|
||||
"model_used": "gemini-2.0-flash-001"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
|
||||
| Variable | Description | Required | Default |
|
||||
|----------|-------------|----------|---------|
|
||||
| `GEMINI_API_KEY` | Google Gemini API key | Yes | - |
|
||||
| `DATABASE_URL` | Database connection string | No | `sqlite:///./alwrity.db` |
|
||||
| `LOG_LEVEL` | Logging level | No | `INFO` |
|
||||
|
||||
### Content Generation Settings
|
||||
|
||||
The service supports various customization options:
|
||||
|
||||
#### Post Types
|
||||
- `professional`: Standard professional posts
|
||||
- `thought_leadership`: Industry insights and expertise
|
||||
- `industry_news`: News and updates
|
||||
- `personal_story`: Personal experiences and stories
|
||||
- `company_update`: Company news and announcements
|
||||
- `poll`: Interactive polls
|
||||
|
||||
#### Tone Options
|
||||
- `professional`: Formal business tone
|
||||
- `conversational`: Casual but professional
|
||||
- `authoritative`: Expert and confident
|
||||
- `inspirational`: Motivational and uplifting
|
||||
- `educational`: Informative and teaching
|
||||
- `friendly`: Warm and approachable
|
||||
|
||||
#### Search Engines
|
||||
- `metaphor`: Metaphor AI search (recommended)
|
||||
- `google`: Google Search API
|
||||
- `tavily`: Tavily AI search
|
||||
|
||||
## Architecture
|
||||
|
||||
### Service Structure
|
||||
|
||||
```
|
||||
backend/
|
||||
├── models/
|
||||
│ └── linkedin_models.py # Pydantic models for requests/responses
|
||||
├── services/
|
||||
│ └── linkedin_service.py # Core business logic
|
||||
├── routers/
|
||||
│ └── linkedin.py # FastAPI route handlers
|
||||
├── middleware/
|
||||
│ └── monitoring_middleware.py # Request monitoring
|
||||
└── docs/
|
||||
└── LINKEDIN_CONTENT_GENERATION.md
|
||||
```
|
||||
|
||||
### Key Components
|
||||
|
||||
#### LinkedInContentService
|
||||
The core service class that handles all content generation logic:
|
||||
|
||||
- **Content Generation**: AI-powered content creation
|
||||
- **Research Integration**: Multi-source research capabilities
|
||||
- **Error Handling**: Comprehensive exception management
|
||||
- **Logging**: Detailed operation logging
|
||||
|
||||
#### Request Models
|
||||
Pydantic models for strong typing and validation:
|
||||
|
||||
- `LinkedInPostRequest`
|
||||
- `LinkedInArticleRequest`
|
||||
- `LinkedInCarouselRequest`
|
||||
- `LinkedInVideoScriptRequest`
|
||||
- `LinkedInCommentResponseRequest`
|
||||
|
||||
#### Response Models
|
||||
Structured response models with metadata:
|
||||
|
||||
- `LinkedInPostResponse`
|
||||
- `LinkedInArticleResponse`
|
||||
- `LinkedInCarouselResponse`
|
||||
- `LinkedInVideoScriptResponse`
|
||||
- `LinkedInCommentResponseResult`
|
||||
|
||||
## Performance Considerations
|
||||
|
||||
### Response Times
|
||||
- **Posts**: 3-8 seconds (with research)
|
||||
- **Articles**: 15-45 seconds (depending on length)
|
||||
- **Carousels**: 5-15 seconds
|
||||
- **Video Scripts**: 3-10 seconds
|
||||
- **Comment Responses**: 1-3 seconds
|
||||
|
||||
### Rate Limiting
|
||||
The service respects API rate limits:
|
||||
- Gemini API: Built-in retry logic with exponential backoff
|
||||
- Research APIs: Configurable rate limiting
|
||||
|
||||
### Caching
|
||||
- Research results caching (planned)
|
||||
- Response caching for similar requests (planned)
|
||||
|
||||
## Error Handling
|
||||
|
||||
### Common Error Scenarios
|
||||
|
||||
#### 422 Validation Error
|
||||
```json
|
||||
{
|
||||
"detail": [
|
||||
{
|
||||
"loc": ["body", "topic"],
|
||||
"msg": "ensure this value has at least 3 characters",
|
||||
"type": "value_error.any_str.min_length"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
#### 500 Internal Server Error
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"error": "Content generation failed: API key not configured",
|
||||
"generation_metadata": {
|
||||
"service_version": "1.0.0",
|
||||
"timestamp": "2025-01-27T10:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### Error Recovery
|
||||
- Automatic retry logic for transient failures
|
||||
- Graceful fallback for content generation
|
||||
- Detailed error logging for debugging
|
||||
|
||||
## Monitoring and Logging
|
||||
|
||||
### Request Monitoring
|
||||
All API requests are logged with:
|
||||
- Request path and method
|
||||
- Response time and status code
|
||||
- User information (if available)
|
||||
- Request/response sizes
|
||||
|
||||
### Performance Metrics
|
||||
- Generation time tracking
|
||||
- Success/failure rates
|
||||
- Popular content types
|
||||
- Error frequency analysis
|
||||
|
||||
### Health Checks
|
||||
```bash
|
||||
curl http://localhost:8000/api/linkedin/health
|
||||
```
|
||||
|
||||
## Migration from Streamlit
|
||||
|
||||
### Key Changes
|
||||
|
||||
1. **Architecture**: Streamlit UI → FastAPI REST API
|
||||
2. **Dependencies**: Integrated with existing backend services
|
||||
3. **Error Handling**: Enhanced exception handling and logging
|
||||
4. **Monitoring**: Database-backed request monitoring
|
||||
5. **Validation**: Strong request/response validation
|
||||
6. **Documentation**: Automatic API documentation
|
||||
|
||||
### Compatibility
|
||||
- All original functionality preserved
|
||||
- Enhanced features and capabilities
|
||||
- Better integration with existing systems
|
||||
- Improved performance and scalability
|
||||
|
||||
## Testing
|
||||
|
||||
### Running Tests
|
||||
|
||||
```bash
|
||||
# Structure validation
|
||||
python3 validate_linkedin_structure.py
|
||||
|
||||
# Full functionality tests (requires dependencies)
|
||||
python3 test_linkedin_endpoints.py
|
||||
```
|
||||
|
||||
### Test Coverage
|
||||
- ✅ Post generation
|
||||
- ✅ Article generation
|
||||
- ✅ Carousel generation
|
||||
- ✅ Video script generation
|
||||
- ✅ Comment response generation
|
||||
- ✅ Error handling
|
||||
- ✅ Structure validation
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
#### 1. Import Errors
|
||||
```bash
|
||||
ModuleNotFoundError: No module named 'pydantic'
|
||||
```
|
||||
**Solution**: Install dependencies
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
#### 2. API Key Issues
|
||||
```bash
|
||||
Error: GEMINI_API_KEY environment variable is not set
|
||||
```
|
||||
**Solution**: Set the environment variable
|
||||
```bash
|
||||
export GEMINI_API_KEY="your_api_key_here"
|
||||
```
|
||||
|
||||
#### 3. Database Connection Issues
|
||||
```bash
|
||||
Error creating database session
|
||||
```
|
||||
**Solution**: Check database configuration and permissions
|
||||
|
||||
#### 4. Generation Timeouts
|
||||
**Solution**: Increase timeout settings or reduce content complexity
|
||||
|
||||
### Debug Mode
|
||||
Enable debug logging:
|
||||
```bash
|
||||
export LOG_LEVEL=DEBUG
|
||||
```
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
- [ ] Real search engine integration (Metaphor, Google, Tavily)
|
||||
- [ ] Content scheduling and calendar integration
|
||||
- [ ] A/B testing capabilities
|
||||
- [ ] Advanced analytics and reporting
|
||||
- [ ] Multi-language support
|
||||
- [ ] Custom templates and brand voice
|
||||
- [ ] LinkedIn API integration for direct posting
|
||||
- [ ] Content performance tracking
|
||||
|
||||
### Performance Improvements
|
||||
- [ ] Response caching
|
||||
- [ ] Parallel processing for multiple requests
|
||||
- [ ] Background job processing
|
||||
- [ ] CDN integration for static assets
|
||||
|
||||
## Support
|
||||
|
||||
For issues and questions:
|
||||
|
||||
1. Check the [troubleshooting section](#troubleshooting)
|
||||
2. Review the API documentation at `/docs`
|
||||
3. Check the logs for detailed error information
|
||||
4. Validate your request format against the examples
|
||||
|
||||
## License
|
||||
|
||||
This LinkedIn Content Generation Service is part of the ALwrity platform and follows the same licensing terms.
|
||||
@@ -1,401 +0,0 @@
|
||||
# AI SEO Tools Migration Documentation
|
||||
|
||||
## Overview
|
||||
|
||||
This document describes the successful migration of AI SEO tools from the `ToBeMigrated/ai_seo_tools` directory to FastAPI endpoints in the backend services. The migration maintains all existing functionality while adding intelligent logging, exception handling, and structured API responses.
|
||||
|
||||
## Migration Summary
|
||||
|
||||
### What Was Migrated
|
||||
|
||||
The following SEO tools have been converted to FastAPI endpoints:
|
||||
|
||||
1. **Meta Description Generator** - AI-powered meta description generation
|
||||
2. **Google PageSpeed Insights Analyzer** - Performance analysis with AI insights
|
||||
3. **Sitemap Analyzer** - Website structure and content trend analysis
|
||||
4. **Image Alt Text Generator** - AI-powered alt text generation
|
||||
5. **OpenGraph Tags Generator** - Social media optimization tags
|
||||
6. **On-Page SEO Analyzer** - Comprehensive on-page SEO analysis
|
||||
7. **Technical SEO Analyzer** - Website crawling and technical analysis
|
||||
8. **Enterprise SEO Suite** - Complete SEO audit workflows
|
||||
9. **Content Strategy Analyzer** - AI-powered content gap analysis
|
||||
|
||||
### New Architecture
|
||||
|
||||
```
|
||||
backend/
|
||||
├── services/seo_tools/ # SEO tool services
|
||||
│ ├── meta_description_service.py
|
||||
│ ├── pagespeed_service.py
|
||||
│ ├── sitemap_service.py
|
||||
│ ├── image_alt_service.py
|
||||
│ ├── opengraph_service.py
|
||||
│ ├── on_page_seo_service.py
|
||||
│ ├── technical_seo_service.py
|
||||
│ ├── enterprise_seo_service.py
|
||||
│ └── content_strategy_service.py
|
||||
├── routers/seo_tools.py # FastAPI router
|
||||
├── middleware/logging_middleware.py # Intelligent logging
|
||||
└── logs/seo_tools/ # Structured log files
|
||||
```
|
||||
|
||||
## API Endpoints
|
||||
|
||||
### Base URL
|
||||
All SEO tools are available under: `/api/seo`
|
||||
|
||||
### Individual Tool Endpoints
|
||||
|
||||
#### 1. Meta Description Generation
|
||||
- **Endpoint**: `POST /api/seo/meta-description`
|
||||
- **Purpose**: Generate AI-powered SEO meta descriptions
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"keywords": ["SEO", "content marketing"],
|
||||
"tone": "Professional",
|
||||
"search_intent": "Informational Intent",
|
||||
"language": "English",
|
||||
"custom_prompt": "Optional custom prompt"
|
||||
}
|
||||
```
|
||||
- **Response**: Structured response with 5 meta descriptions, analysis, and recommendations
|
||||
|
||||
#### 2. PageSpeed Analysis
|
||||
- **Endpoint**: `POST /api/seo/pagespeed-analysis`
|
||||
- **Purpose**: Analyze website performance using Google PageSpeed Insights
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"strategy": "DESKTOP",
|
||||
"locale": "en",
|
||||
"categories": ["performance", "accessibility", "best-practices", "seo"]
|
||||
}
|
||||
```
|
||||
- **Response**: Performance metrics, Core Web Vitals, AI insights, and optimization plan
|
||||
|
||||
#### 3. Sitemap Analysis
|
||||
- **Endpoint**: `POST /api/seo/sitemap-analysis`
|
||||
- **Purpose**: Analyze website sitemap structure and content patterns
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"sitemap_url": "https://example.com/sitemap.xml",
|
||||
"analyze_content_trends": true,
|
||||
"analyze_publishing_patterns": true
|
||||
}
|
||||
```
|
||||
- **Response**: Structure analysis, content trends, publishing patterns, and AI insights
|
||||
|
||||
#### 4. Image Alt Text Generation
|
||||
- **Endpoint**: `POST /api/seo/image-alt-text`
|
||||
- **Purpose**: Generate SEO-optimized alt text for images
|
||||
- **Request**: Form data with image file or JSON with image URL
|
||||
- **Response**: Generated alt text with confidence score and suggestions
|
||||
|
||||
#### 5. OpenGraph Tags Generation
|
||||
- **Endpoint**: `POST /api/seo/opengraph-tags`
|
||||
- **Purpose**: Generate OpenGraph tags for social media optimization
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"title_hint": "Optional title hint",
|
||||
"description_hint": "Optional description hint",
|
||||
"platform": "General"
|
||||
}
|
||||
```
|
||||
- **Response**: Complete OpenGraph tags with platform-specific optimizations
|
||||
|
||||
#### 6. On-Page SEO Analysis
|
||||
- **Endpoint**: `POST /api/seo/on-page-analysis`
|
||||
- **Purpose**: Comprehensive on-page SEO analysis
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"target_keywords": ["keyword1", "keyword2"],
|
||||
"analyze_images": true,
|
||||
"analyze_content_quality": true
|
||||
}
|
||||
```
|
||||
- **Response**: SEO score, content analysis, keyword optimization, and recommendations
|
||||
|
||||
#### 7. Technical SEO Analysis
|
||||
- **Endpoint**: `POST /api/seo/technical-seo`
|
||||
- **Purpose**: Technical SEO crawling and analysis
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"url": "https://example.com",
|
||||
"crawl_depth": 3,
|
||||
"include_external_links": true,
|
||||
"analyze_performance": true
|
||||
}
|
||||
```
|
||||
- **Response**: Technical issues, site structure, performance metrics, and recommendations
|
||||
|
||||
### Workflow Endpoints
|
||||
|
||||
#### 1. Complete Website Audit
|
||||
- **Endpoint**: `POST /api/seo/workflow/website-audit`
|
||||
- **Purpose**: Execute comprehensive SEO audit workflow
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"website_url": "https://example.com",
|
||||
"workflow_type": "complete_audit",
|
||||
"competitors": ["https://competitor1.com"],
|
||||
"target_keywords": ["keyword1", "keyword2"]
|
||||
}
|
||||
```
|
||||
|
||||
#### 2. Content Analysis Workflow
|
||||
- **Endpoint**: `POST /api/seo/workflow/content-analysis`
|
||||
- **Purpose**: AI-powered content strategy analysis
|
||||
- **Request**:
|
||||
```json
|
||||
{
|
||||
"website_url": "https://example.com",
|
||||
"workflow_type": "content_analysis",
|
||||
"competitors": ["https://competitor1.com"],
|
||||
"target_keywords": ["content", "strategy"]
|
||||
}
|
||||
```
|
||||
|
||||
### Health and Status Endpoints
|
||||
|
||||
- **GET** `/api/seo/health` - Health check for SEO tools
|
||||
- **GET** `/api/seo/tools/status` - Status of all SEO tools and dependencies
|
||||
|
||||
## Key Features
|
||||
|
||||
### 1. Intelligent Logging
|
||||
- **Structured Logging**: All operations logged to JSONL files
|
||||
- **Performance Tracking**: Execution time monitoring
|
||||
- **Error Logging**: Comprehensive error tracking with stack traces
|
||||
- **AI Analysis Logging**: Prompt/response tracking for AI operations
|
||||
|
||||
**Log Files**:
|
||||
- `/backend/logs/seo_tools/operations.jsonl` - Successful operations
|
||||
- `/backend/logs/seo_tools/errors.jsonl` - Error logs
|
||||
- `/backend/logs/seo_tools/ai_analysis.jsonl` - AI prompt/response logs
|
||||
- `/backend/logs/seo_tools/external_apis.jsonl` - External API calls
|
||||
- `/backend/logs/seo_tools/crawling.jsonl` - Web crawling operations
|
||||
|
||||
### 2. Exception Handling
|
||||
- **Never Mock Data**: Real API failures return proper error responses
|
||||
- **Graceful Degradation**: AI analysis failures don't break core functionality
|
||||
- **Detailed Error Messages**: Clear error descriptions for debugging
|
||||
- **Error IDs**: Unique error identifiers for tracking
|
||||
|
||||
### 3. AI Enhancement
|
||||
- **Gemini Integration**: Uses `gemini_provide` functionality for AI analysis
|
||||
- **Structured Responses**: AI responses parsed into structured data
|
||||
- **Context-Aware Analysis**: AI considers user type (content creators, marketers)
|
||||
- **Business Impact Focus**: AI recommendations focus on practical business outcomes
|
||||
|
||||
### 4. Background Processing
|
||||
- **Async Operations**: All heavy operations run asynchronously
|
||||
- **Background Tasks**: Logging and cleanup run in background
|
||||
- **Non-blocking**: API responses don't wait for logging operations
|
||||
|
||||
## Response Format
|
||||
|
||||
All endpoints follow a consistent response format:
|
||||
|
||||
```json
|
||||
{
|
||||
"success": true,
|
||||
"message": "Operation completed successfully",
|
||||
"timestamp": "2024-01-15T10:30:00Z",
|
||||
"execution_time": 2.45,
|
||||
"data": {
|
||||
// Tool-specific data
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**Error Response**:
|
||||
```json
|
||||
{
|
||||
"success": false,
|
||||
"message": "Error description",
|
||||
"timestamp": "2024-01-15T10:30:00Z",
|
||||
"execution_time": 1.23,
|
||||
"error_type": "ValueError",
|
||||
"error_details": "Detailed error message",
|
||||
"traceback": "Full traceback (only in debug mode)"
|
||||
}
|
||||
```
|
||||
|
||||
## Dependencies
|
||||
|
||||
### New Dependencies Added
|
||||
```
|
||||
aiofiles>=23.2.0 # Async file operations
|
||||
crawl4ai>=0.2.0 # Web crawling (placeholder)
|
||||
```
|
||||
|
||||
### Existing Dependencies Used
|
||||
- `fastapi` - Web framework
|
||||
- `pydantic` - Data validation
|
||||
- `aiohttp` - Async HTTP client
|
||||
- `beautifulsoup4` - HTML parsing
|
||||
- `advertools` - SEO analysis
|
||||
- `loguru` - Logging
|
||||
- `google-genai` - AI analysis
|
||||
|
||||
## Testing
|
||||
|
||||
### Test Script
|
||||
Run the comprehensive test suite:
|
||||
```bash
|
||||
cd /workspace/backend
|
||||
python test_seo_tools.py
|
||||
```
|
||||
|
||||
### Manual Testing
|
||||
1. Start the FastAPI server:
|
||||
```bash
|
||||
uvicorn app:app --reload --host 0.0.0.0 --port 8000
|
||||
```
|
||||
|
||||
2. Access API documentation:
|
||||
- Swagger UI: `http://localhost:8000/docs`
|
||||
- ReDoc: `http://localhost:8000/redoc`
|
||||
|
||||
3. Test individual endpoints using the documentation interface
|
||||
|
||||
## Configuration
|
||||
|
||||
### Environment Variables
|
||||
Set these environment variables for full functionality:
|
||||
|
||||
```bash
|
||||
# Google PageSpeed Insights API Key (optional)
|
||||
GOOGLE_PAGESPEED_API_KEY=your_api_key_here
|
||||
|
||||
# AI Provider API Keys (at least one required)
|
||||
GEMINI_API_KEY=your_gemini_key
|
||||
OPENAI_API_KEY=your_openai_key
|
||||
ANTHROPIC_API_KEY=your_anthropic_key
|
||||
|
||||
# Debug mode (optional)
|
||||
DEBUG=false
|
||||
```
|
||||
|
||||
### Logging Configuration
|
||||
Logs are automatically rotated daily and retained for 30 days. Configure in:
|
||||
`/workspace/backend/middleware/logging_middleware.py`
|
||||
|
||||
## Migration Benefits
|
||||
|
||||
### For Content Creators
|
||||
- **User-Friendly**: API responses tailored for non-technical users
|
||||
- **Actionable Insights**: Clear recommendations with business impact
|
||||
- **Comprehensive Analysis**: All-in-one SEO analysis platform
|
||||
- **AI-Enhanced**: Advanced AI provides strategic insights
|
||||
|
||||
### For Digital Marketers
|
||||
- **Performance Tracking**: Detailed metrics and optimization plans
|
||||
- **Competitive Analysis**: Built-in competitor intelligence
|
||||
- **Workflow Automation**: Complete audit workflows
|
||||
- **ROI Focus**: Recommendations tied to business outcomes
|
||||
|
||||
### For Solopreneurs
|
||||
- **Cost-Effective**: Single API for multiple SEO tools
|
||||
- **Time-Saving**: Automated analysis and recommendations
|
||||
- **Easy Integration**: RESTful API with clear documentation
|
||||
- **Scalable**: Handles small to enterprise-level analysis
|
||||
|
||||
### For Developers
|
||||
- **Modern Architecture**: FastAPI with async support
|
||||
- **Comprehensive Logging**: Full observability
|
||||
- **Error Handling**: Robust error management
|
||||
- **Documentation**: Auto-generated API docs
|
||||
|
||||
## Monitoring and Maintenance
|
||||
|
||||
### Log Analysis
|
||||
Use the built-in log analyzer for insights:
|
||||
```python
|
||||
from middleware.logging_middleware import log_analyzer
|
||||
|
||||
# Get performance summary
|
||||
performance = await log_analyzer.get_performance_summary(hours=24)
|
||||
|
||||
# Get error summary
|
||||
errors = await log_analyzer.get_error_summary(hours=24)
|
||||
```
|
||||
|
||||
### Health Monitoring
|
||||
Monitor service health via:
|
||||
- `/api/seo/health` - Overall health
|
||||
- `/api/seo/tools/status` - Individual tool status
|
||||
|
||||
### Performance Optimization
|
||||
- Monitor execution times in logs
|
||||
- Optimize slow-performing tools
|
||||
- Scale based on usage patterns
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
### Planned Features
|
||||
1. **Real-time Monitoring Dashboard** - Visual monitoring interface
|
||||
2. **Batch Processing** - Process multiple URLs simultaneously
|
||||
3. **Webhook Support** - Async notifications for long-running operations
|
||||
4. **Rate Limiting** - Prevent API abuse
|
||||
5. **Caching** - Cache frequently requested analyses
|
||||
6. **Authentication** - API key-based authentication
|
||||
7. **Usage Analytics** - Track API usage and popular tools
|
||||
|
||||
### Extension Points
|
||||
1. **New SEO Tools** - Easy to add new tools following existing patterns
|
||||
2. **Custom AI Models** - Support for additional AI providers
|
||||
3. **Export Formats** - PDF, Excel, CSV export options
|
||||
4. **Integration APIs** - Connect with popular marketing tools
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
1. **Import Errors**
|
||||
- Ensure all dependencies are installed: `pip install -r requirements.txt`
|
||||
- Check Python path configuration
|
||||
|
||||
2. **AI Analysis Failures**
|
||||
- Verify API keys are set correctly
|
||||
- Check internet connectivity
|
||||
- Review error logs for specific issues
|
||||
|
||||
3. **PageSpeed API Errors**
|
||||
- Get Google PageSpeed API key for higher rate limits
|
||||
- Verify URL format and accessibility
|
||||
|
||||
4. **Logging Issues**
|
||||
- Ensure write permissions to `/workspace/backend/logs/`
|
||||
- Check disk space availability
|
||||
|
||||
### Debug Mode
|
||||
Enable debug mode for detailed error information:
|
||||
```bash
|
||||
export DEBUG=true
|
||||
```
|
||||
|
||||
This will include full tracebacks in API responses.
|
||||
|
||||
## Conclusion
|
||||
|
||||
The AI SEO Tools migration successfully transforms individual Python scripts into a cohesive, scalable FastAPI service. The new architecture provides:
|
||||
|
||||
- ✅ **Complete Functionality Preservation**
|
||||
- ✅ **Enhanced Error Handling**
|
||||
- ✅ **Intelligent Logging**
|
||||
- ✅ **AI-Powered Insights**
|
||||
- ✅ **Workflow Automation**
|
||||
- ✅ **Developer-Friendly API**
|
||||
- ✅ **Business-Focused Outputs**
|
||||
|
||||
The system is now ready for production use and can easily scale to serve content creators, digital marketers, and solopreneurs with professional-grade SEO analysis capabilities.
|
||||
@@ -115,7 +115,7 @@ class PlatformPersona(Base):
|
||||
|
||||
def to_dict(self):
|
||||
"""Convert model to dictionary."""
|
||||
return {
|
||||
result = {
|
||||
'id': self.id,
|
||||
'writing_persona_id': self.writing_persona_id,
|
||||
'platform_type': self.platform_type,
|
||||
@@ -134,6 +134,19 @@ class PlatformPersona(Base):
|
||||
'updated_at': self.updated_at.isoformat() if self.updated_at else None,
|
||||
'is_active': self.is_active
|
||||
}
|
||||
|
||||
# Add LinkedIn-specific fields if this is a LinkedIn persona
|
||||
if self.platform_type.lower() == "linkedin" and self.algorithm_considerations:
|
||||
linkedin_data = self.algorithm_considerations
|
||||
if isinstance(linkedin_data, dict):
|
||||
result.update({
|
||||
'professional_networking': linkedin_data.get('professional_networking', {}),
|
||||
'linkedin_features': linkedin_data.get('linkedin_features', {}),
|
||||
'algorithm_optimization': linkedin_data.get('algorithm_optimization', {}),
|
||||
'professional_context_optimization': linkedin_data.get('professional_context_optimization', {})
|
||||
})
|
||||
|
||||
return result
|
||||
|
||||
class PersonaAnalysisResult(Base):
|
||||
"""Stores AI analysis results used to generate personas."""
|
||||
|
||||
106
backend/services/persona/README.md
Normal file
106
backend/services/persona/README.md
Normal file
@@ -0,0 +1,106 @@
|
||||
# Persona Services Package
|
||||
|
||||
This package contains platform-specific persona generation and analysis services, providing a modular and extensible architecture for creating platform-optimized writing personas.
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
services/persona/
|
||||
├── __init__.py # Package initialization
|
||||
├── linkedin/ # LinkedIn-specific persona services
|
||||
│ ├── __init__.py # LinkedIn package initialization
|
||||
│ ├── linkedin_persona_service.py # Main LinkedIn persona service
|
||||
│ ├── linkedin_persona_prompts.py # LinkedIn-specific prompts
|
||||
│ └── linkedin_persona_schemas.py # LinkedIn-specific schemas
|
||||
└── README.md # This documentation
|
||||
```
|
||||
|
||||
## LinkedIn Persona Services
|
||||
|
||||
### LinkedInPersonaService
|
||||
The main service class for generating LinkedIn-specific persona adaptations.
|
||||
|
||||
**Key Features:**
|
||||
- Enhanced LinkedIn-specific prompt generation
|
||||
- Professional networking optimization
|
||||
- Industry-specific adaptations
|
||||
- Algorithm optimization for LinkedIn
|
||||
- Persona validation and quality scoring
|
||||
|
||||
**Methods:**
|
||||
- `generate_linkedin_persona()` - Generate LinkedIn-optimized persona
|
||||
- `validate_linkedin_persona()` - Validate persona data quality
|
||||
- `optimize_for_linkedin_algorithm()` - Algorithm-specific optimizations
|
||||
- `get_linkedin_constraints()` - Get LinkedIn platform constraints
|
||||
|
||||
### LinkedInPersonaPrompts
|
||||
Handles LinkedIn-specific prompt generation with professional optimization.
|
||||
|
||||
**Key Features:**
|
||||
- Industry-specific targeting (technology, business, etc.)
|
||||
- Professional networking focus
|
||||
- Thought leadership positioning
|
||||
- B2B optimization
|
||||
- LinkedIn algorithm awareness
|
||||
|
||||
### LinkedInPersonaSchemas
|
||||
Defines LinkedIn-specific JSON schemas for persona generation.
|
||||
|
||||
**Key Features:**
|
||||
- Enhanced LinkedIn schema with professional fields
|
||||
- Algorithm optimization fields
|
||||
- Professional networking elements
|
||||
- LinkedIn feature-specific adaptations
|
||||
|
||||
## Usage
|
||||
|
||||
```python
|
||||
from services.persona.linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
|
||||
# Initialize the service
|
||||
linkedin_service = LinkedInPersonaService()
|
||||
|
||||
# Generate LinkedIn persona
|
||||
linkedin_persona = linkedin_service.generate_linkedin_persona(
|
||||
core_persona=core_persona_data,
|
||||
onboarding_data=onboarding_data
|
||||
)
|
||||
|
||||
# Validate persona quality
|
||||
validation_results = linkedin_service.validate_linkedin_persona(linkedin_persona)
|
||||
|
||||
# Optimize for LinkedIn algorithm
|
||||
optimized_persona = linkedin_service.optimize_for_linkedin_algorithm(linkedin_persona)
|
||||
```
|
||||
|
||||
## Integration with Main Persona Service
|
||||
|
||||
The main `PersonaAnalysisService` automatically uses the LinkedIn service when generating LinkedIn personas:
|
||||
|
||||
```python
|
||||
# In PersonaAnalysisService._generate_single_platform_persona()
|
||||
if platform.lower() == "linkedin":
|
||||
return self.linkedin_service.generate_linkedin_persona(core_persona, onboarding_data)
|
||||
```
|
||||
|
||||
## Benefits of This Architecture
|
||||
|
||||
1. **Modularity**: Each platform has its own dedicated service
|
||||
2. **Extensibility**: Easy to add new platforms (Facebook, Instagram, etc.)
|
||||
3. **Maintainability**: Platform-specific logic is isolated
|
||||
4. **Testability**: Each service can be tested independently
|
||||
5. **Reusability**: Services can be used across different parts of the application
|
||||
|
||||
## Future Extensions
|
||||
|
||||
This architecture makes it easy to add new platform-specific services:
|
||||
|
||||
- `services/persona/facebook/` - Facebook-specific persona services
|
||||
- `services/persona/instagram/` - Instagram-specific persona services
|
||||
- `services/persona/twitter/` - Twitter-specific persona services
|
||||
- `services/persona/blog/` - Blog-specific persona services
|
||||
|
||||
Each platform service would follow the same pattern:
|
||||
- `{platform}_persona_service.py` - Main service class
|
||||
- `{platform}_persona_prompts.py` - Platform-specific prompts
|
||||
- `{platform}_persona_schemas.py` - Platform-specific schemas
|
||||
8
backend/services/persona/__init__.py
Normal file
8
backend/services/persona/__init__.py
Normal file
@@ -0,0 +1,8 @@
|
||||
"""
|
||||
Persona Services Package
|
||||
Contains platform-specific persona generation and analysis services.
|
||||
"""
|
||||
|
||||
from .linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
|
||||
__all__ = ['LinkedInPersonaService']
|
||||
16
backend/services/persona/core_persona/__init__.py
Normal file
16
backend/services/persona/core_persona/__init__.py
Normal file
@@ -0,0 +1,16 @@
|
||||
"""
|
||||
Core Persona Generation Module
|
||||
|
||||
This module contains the core persona generation logic extracted from persona_analysis_service.py
|
||||
to improve maintainability and modularity.
|
||||
"""
|
||||
|
||||
from .core_persona_service import CorePersonaService
|
||||
from .data_collector import OnboardingDataCollector
|
||||
from .prompt_builder import PersonaPromptBuilder
|
||||
|
||||
__all__ = [
|
||||
'CorePersonaService',
|
||||
'OnboardingDataCollector',
|
||||
'PersonaPromptBuilder'
|
||||
]
|
||||
159
backend/services/persona/core_persona/core_persona_service.py
Normal file
159
backend/services/persona/core_persona/core_persona_service.py
Normal file
@@ -0,0 +1,159 @@
|
||||
"""
|
||||
Core Persona Service
|
||||
|
||||
Handles the core persona generation logic using Gemini AI.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List
|
||||
from loguru import logger
|
||||
from datetime import datetime
|
||||
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
from .data_collector import OnboardingDataCollector
|
||||
from .prompt_builder import PersonaPromptBuilder
|
||||
from services.persona.linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
|
||||
|
||||
class CorePersonaService:
|
||||
"""Core service for generating writing personas using Gemini AI."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the core persona service."""
|
||||
self.data_collector = OnboardingDataCollector()
|
||||
self.prompt_builder = PersonaPromptBuilder()
|
||||
self.linkedin_service = LinkedInPersonaService()
|
||||
logger.info("CorePersonaService initialized")
|
||||
|
||||
def generate_core_persona(self, onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate core writing persona using Gemini structured response."""
|
||||
|
||||
# Build analysis prompt
|
||||
prompt = self.prompt_builder.build_persona_analysis_prompt(onboarding_data)
|
||||
|
||||
# Get schema for structured response
|
||||
persona_schema = self.prompt_builder.get_persona_schema()
|
||||
|
||||
try:
|
||||
# Generate structured response using Gemini
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=persona_schema,
|
||||
temperature=0.2, # Low temperature for consistent analysis
|
||||
max_tokens=8192,
|
||||
system_prompt="You are an expert writing style analyst and persona developer. Analyze the provided data to create a precise, actionable writing persona."
|
||||
)
|
||||
|
||||
if "error" in response:
|
||||
logger.error(f"Gemini API error: {response['error']}")
|
||||
return {"error": f"AI analysis failed: {response['error']}"}
|
||||
|
||||
logger.info("✅ Core persona generated successfully")
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating core persona: {str(e)}")
|
||||
return {"error": f"Failed to generate core persona: {str(e)}"}
|
||||
|
||||
def generate_platform_adaptations(self, core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate platform-specific persona adaptations."""
|
||||
|
||||
platforms = ["twitter", "linkedin", "instagram", "facebook", "blog", "medium", "substack"]
|
||||
platform_personas = {}
|
||||
|
||||
for platform in platforms:
|
||||
try:
|
||||
platform_persona = self._generate_single_platform_persona(core_persona, platform, onboarding_data)
|
||||
if "error" not in platform_persona:
|
||||
platform_personas[platform] = platform_persona
|
||||
else:
|
||||
logger.warning(f"Failed to generate {platform} persona: {platform_persona['error']}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating {platform} persona: {str(e)}")
|
||||
|
||||
return platform_personas
|
||||
|
||||
def _generate_single_platform_persona(self, core_persona: Dict[str, Any], platform: str, onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate persona adaptation for a specific platform."""
|
||||
|
||||
# Use LinkedIn service for LinkedIn platform
|
||||
if platform.lower() == "linkedin":
|
||||
return self.linkedin_service.generate_linkedin_persona(core_persona, onboarding_data)
|
||||
|
||||
# Use generic platform adaptation for other platforms
|
||||
platform_constraints = self._get_platform_constraints(platform)
|
||||
prompt = self.prompt_builder.build_platform_adaptation_prompt(core_persona, platform, onboarding_data, platform_constraints)
|
||||
|
||||
# Get platform-specific schema
|
||||
platform_schema = self.prompt_builder.get_platform_schema()
|
||||
|
||||
try:
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=platform_schema,
|
||||
temperature=0.2,
|
||||
max_tokens=4096,
|
||||
system_prompt=f"You are an expert in {platform} content strategy and platform-specific writing optimization."
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating {platform} persona: {str(e)}")
|
||||
return {"error": f"Failed to generate {platform} persona: {str(e)}"}
|
||||
|
||||
def _get_platform_constraints(self, platform: str) -> Dict[str, Any]:
|
||||
"""Get platform-specific constraints and best practices."""
|
||||
|
||||
constraints = {
|
||||
"twitter": {
|
||||
"character_limit": 280,
|
||||
"optimal_length": "120-150 characters",
|
||||
"hashtag_limit": 3,
|
||||
"image_support": True,
|
||||
"thread_support": True,
|
||||
"link_shortening": True
|
||||
},
|
||||
"linkedin": self.linkedin_service.get_linkedin_constraints(),
|
||||
"instagram": {
|
||||
"caption_limit": 2200,
|
||||
"optimal_length": "125-150 words",
|
||||
"hashtag_limit": 30,
|
||||
"visual_first": True,
|
||||
"story_support": True,
|
||||
"emoji_friendly": True
|
||||
},
|
||||
"facebook": {
|
||||
"character_limit": 63206,
|
||||
"optimal_length": "40-80 words",
|
||||
"algorithm_favors": "engagement",
|
||||
"link_preview": True,
|
||||
"event_support": True,
|
||||
"group_sharing": True
|
||||
},
|
||||
"blog": {
|
||||
"word_count": "800-2000 words",
|
||||
"seo_important": True,
|
||||
"header_structure": True,
|
||||
"internal_linking": True,
|
||||
"meta_descriptions": True,
|
||||
"readability_score": True
|
||||
},
|
||||
"medium": {
|
||||
"word_count": "1000-3000 words",
|
||||
"storytelling_focus": True,
|
||||
"subtitle_support": True,
|
||||
"publication_support": True,
|
||||
"clap_optimization": True,
|
||||
"follower_building": True
|
||||
},
|
||||
"substack": {
|
||||
"newsletter_format": True,
|
||||
"email_optimization": True,
|
||||
"subscription_focus": True,
|
||||
"long_form": True,
|
||||
"personal_connection": True,
|
||||
"monetization_support": True
|
||||
}
|
||||
}
|
||||
|
||||
return constraints.get(platform, {})
|
||||
306
backend/services/persona/core_persona/data_collector.py
Normal file
306
backend/services/persona/core_persona/data_collector.py
Normal file
@@ -0,0 +1,306 @@
|
||||
"""
|
||||
Onboarding Data Collector
|
||||
|
||||
Handles comprehensive collection of onboarding data for persona generation.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from sqlalchemy.orm import Session
|
||||
from loguru import logger
|
||||
|
||||
from services.database import get_db_session
|
||||
from models.onboarding import OnboardingSession, WebsiteAnalysis, ResearchPreferences, APIKey
|
||||
|
||||
|
||||
class OnboardingDataCollector:
|
||||
"""Collects comprehensive onboarding data for persona analysis."""
|
||||
|
||||
def collect_onboarding_data(self, user_id: int, session_id: int = None) -> Optional[Dict[str, Any]]:
|
||||
"""Collect comprehensive onboarding data for persona analysis."""
|
||||
try:
|
||||
session = get_db_session()
|
||||
|
||||
# Find onboarding session
|
||||
if session_id:
|
||||
onboarding_session = session.query(OnboardingSession).filter(
|
||||
OnboardingSession.id == session_id,
|
||||
OnboardingSession.user_id == user_id
|
||||
).first()
|
||||
else:
|
||||
onboarding_session = session.query(OnboardingSession).filter(
|
||||
OnboardingSession.user_id == user_id
|
||||
).order_by(OnboardingSession.updated_at.desc()).first()
|
||||
|
||||
if not onboarding_session:
|
||||
return None
|
||||
|
||||
# Get ALL website analyses (there might be multiple)
|
||||
website_analyses = session.query(WebsiteAnalysis).filter(
|
||||
WebsiteAnalysis.session_id == onboarding_session.id
|
||||
).order_by(WebsiteAnalysis.updated_at.desc()).all()
|
||||
|
||||
# Get research preferences
|
||||
research_prefs = session.query(ResearchPreferences).filter(
|
||||
ResearchPreferences.session_id == onboarding_session.id
|
||||
).first()
|
||||
|
||||
# Get API keys
|
||||
api_keys = session.query(APIKey).filter(
|
||||
APIKey.session_id == onboarding_session.id
|
||||
).all()
|
||||
|
||||
# Compile comprehensive data with ALL available information
|
||||
onboarding_data = {
|
||||
"session_info": {
|
||||
"session_id": onboarding_session.id,
|
||||
"user_id": onboarding_session.user_id,
|
||||
"current_step": onboarding_session.current_step,
|
||||
"progress": onboarding_session.progress,
|
||||
"started_at": onboarding_session.started_at.isoformat() if onboarding_session.started_at else None,
|
||||
"updated_at": onboarding_session.updated_at.isoformat() if onboarding_session.updated_at else None
|
||||
},
|
||||
"api_keys": [key.to_dict() for key in api_keys] if api_keys else [],
|
||||
"website_analyses": [analysis.to_dict() for analysis in website_analyses] if website_analyses else [],
|
||||
"research_preferences": research_prefs.to_dict() if research_prefs else None,
|
||||
|
||||
# Legacy compatibility - use the latest website analysis
|
||||
"website_analysis": website_analyses[0].to_dict() if website_analyses else None,
|
||||
|
||||
# Enhanced data extraction for persona generation
|
||||
"enhanced_analysis": self._extract_enhanced_analysis_data(website_analyses, research_prefs)
|
||||
}
|
||||
|
||||
session.close()
|
||||
return onboarding_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error collecting onboarding data: {str(e)}")
|
||||
return None
|
||||
|
||||
def _extract_enhanced_analysis_data(self, website_analyses: List, research_prefs) -> Dict[str, Any]:
|
||||
"""Extract and structure all the rich AI analysis data for persona generation."""
|
||||
enhanced_data = {
|
||||
"comprehensive_style_analysis": {},
|
||||
"content_insights": {},
|
||||
"audience_intelligence": {},
|
||||
"brand_voice_analysis": {},
|
||||
"technical_writing_metrics": {},
|
||||
"competitive_analysis": {},
|
||||
"content_strategy_insights": {}
|
||||
}
|
||||
|
||||
if not website_analyses:
|
||||
return enhanced_data
|
||||
|
||||
# Use the latest (most comprehensive) website analysis
|
||||
latest_analysis = website_analyses[0]
|
||||
|
||||
# Extract comprehensive style analysis
|
||||
if latest_analysis.writing_style:
|
||||
enhanced_data["comprehensive_style_analysis"] = {
|
||||
"tone_analysis": latest_analysis.writing_style.get("tone", ""),
|
||||
"voice_characteristics": latest_analysis.writing_style.get("voice", ""),
|
||||
"complexity_assessment": latest_analysis.writing_style.get("complexity", ""),
|
||||
"engagement_level": latest_analysis.writing_style.get("engagement_level", ""),
|
||||
"brand_personality": latest_analysis.writing_style.get("brand_personality", ""),
|
||||
"formality_level": latest_analysis.writing_style.get("formality_level", ""),
|
||||
"emotional_appeal": latest_analysis.writing_style.get("emotional_appeal", "")
|
||||
}
|
||||
|
||||
# Extract content insights
|
||||
if latest_analysis.content_characteristics:
|
||||
enhanced_data["content_insights"] = {
|
||||
"sentence_structure_analysis": latest_analysis.content_characteristics.get("sentence_structure", ""),
|
||||
"vocabulary_level": latest_analysis.content_characteristics.get("vocabulary_level", ""),
|
||||
"paragraph_organization": latest_analysis.content_characteristics.get("paragraph_organization", ""),
|
||||
"content_flow": latest_analysis.content_characteristics.get("content_flow", ""),
|
||||
"readability_score": latest_analysis.content_characteristics.get("readability_score", ""),
|
||||
"content_density": latest_analysis.content_characteristics.get("content_density", ""),
|
||||
"visual_elements_usage": latest_analysis.content_characteristics.get("visual_elements_usage", "")
|
||||
}
|
||||
|
||||
# Extract audience intelligence
|
||||
if latest_analysis.target_audience:
|
||||
enhanced_data["audience_intelligence"] = {
|
||||
"demographics": latest_analysis.target_audience.get("demographics", []),
|
||||
"expertise_level": latest_analysis.target_audience.get("expertise_level", ""),
|
||||
"industry_focus": latest_analysis.target_audience.get("industry_focus", ""),
|
||||
"geographic_focus": latest_analysis.target_audience.get("geographic_focus", ""),
|
||||
"psychographic_profile": latest_analysis.target_audience.get("psychographic_profile", ""),
|
||||
"pain_points": latest_analysis.target_audience.get("pain_points", []),
|
||||
"motivations": latest_analysis.target_audience.get("motivations", [])
|
||||
}
|
||||
|
||||
# Extract brand voice analysis
|
||||
if latest_analysis.content_type:
|
||||
enhanced_data["brand_voice_analysis"] = {
|
||||
"primary_content_type": latest_analysis.content_type.get("primary_type", ""),
|
||||
"secondary_content_types": latest_analysis.content_type.get("secondary_types", []),
|
||||
"content_purpose": latest_analysis.content_type.get("purpose", ""),
|
||||
"call_to_action_style": latest_analysis.content_type.get("call_to_action", ""),
|
||||
"conversion_focus": latest_analysis.content_type.get("conversion_focus", ""),
|
||||
"educational_value": latest_analysis.content_type.get("educational_value", "")
|
||||
}
|
||||
|
||||
# Extract technical writing metrics
|
||||
if latest_analysis.style_patterns:
|
||||
enhanced_data["technical_writing_metrics"] = {
|
||||
"sentence_length_preference": latest_analysis.style_patterns.get("patterns", {}).get("sentence_length", ""),
|
||||
"vocabulary_patterns": latest_analysis.style_patterns.get("patterns", {}).get("vocabulary_patterns", []),
|
||||
"rhetorical_devices": latest_analysis.style_patterns.get("patterns", {}).get("rhetorical_devices", []),
|
||||
"paragraph_structure": latest_analysis.style_patterns.get("patterns", {}).get("paragraph_structure", ""),
|
||||
"transition_phrases": latest_analysis.style_patterns.get("patterns", {}).get("transition_phrases", []),
|
||||
"style_consistency": latest_analysis.style_patterns.get("style_consistency", ""),
|
||||
"unique_elements": latest_analysis.style_patterns.get("unique_elements", [])
|
||||
}
|
||||
|
||||
# Extract competitive analysis from crawl results
|
||||
if latest_analysis.crawl_result:
|
||||
crawl_data = latest_analysis.crawl_result
|
||||
enhanced_data["competitive_analysis"] = {
|
||||
"domain_info": crawl_data.get("domain_info", {}),
|
||||
"social_media_presence": crawl_data.get("social_media", {}),
|
||||
"brand_info": crawl_data.get("brand_info", {}),
|
||||
"content_structure": crawl_data.get("content_structure", {}),
|
||||
"meta_optimization": crawl_data.get("meta_tags", {})
|
||||
}
|
||||
|
||||
# Extract content strategy insights from style guidelines
|
||||
if latest_analysis.style_guidelines:
|
||||
guidelines = latest_analysis.style_guidelines
|
||||
enhanced_data["content_strategy_insights"] = {
|
||||
"tone_recommendations": guidelines.get("guidelines", {}).get("tone_recommendations", []),
|
||||
"structure_guidelines": guidelines.get("guidelines", {}).get("structure_guidelines", []),
|
||||
"vocabulary_suggestions": guidelines.get("guidelines", {}).get("vocabulary_suggestions", []),
|
||||
"engagement_tips": guidelines.get("guidelines", {}).get("engagement_tips", []),
|
||||
"audience_considerations": guidelines.get("guidelines", {}).get("audience_considerations", []),
|
||||
"brand_alignment": guidelines.get("guidelines", {}).get("brand_alignment", []),
|
||||
"seo_optimization": guidelines.get("guidelines", {}).get("seo_optimization", []),
|
||||
"conversion_optimization": guidelines.get("guidelines", {}).get("conversion_optimization", []),
|
||||
"best_practices": guidelines.get("best_practices", []),
|
||||
"avoid_elements": guidelines.get("avoid_elements", []),
|
||||
"content_strategy": guidelines.get("content_strategy", ""),
|
||||
"ai_generation_tips": guidelines.get("ai_generation_tips", []),
|
||||
"competitive_advantages": guidelines.get("competitive_advantages", []),
|
||||
"content_calendar_suggestions": guidelines.get("content_calendar_suggestions", [])
|
||||
}
|
||||
|
||||
# Add research preferences insights
|
||||
if research_prefs:
|
||||
enhanced_data["research_preferences"] = {
|
||||
"research_depth": research_prefs.research_depth,
|
||||
"content_types": research_prefs.content_types,
|
||||
"auto_research": research_prefs.auto_research,
|
||||
"factual_content": research_prefs.factual_content
|
||||
}
|
||||
|
||||
return enhanced_data
|
||||
|
||||
def calculate_data_sufficiency(self, onboarding_data: Dict[str, Any]) -> float:
|
||||
"""Calculate how sufficient the onboarding data is for persona generation."""
|
||||
score = 0.0
|
||||
|
||||
# Get enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
research_prefs = onboarding_data.get("research_preferences", {}) or {}
|
||||
|
||||
# Enhanced scoring based on comprehensive data availability
|
||||
|
||||
# Comprehensive Style Analysis (25% of score)
|
||||
style_analysis = enhanced_analysis.get("comprehensive_style_analysis", {})
|
||||
if style_analysis.get("tone_analysis"):
|
||||
score += 5
|
||||
if style_analysis.get("voice_characteristics"):
|
||||
score += 5
|
||||
if style_analysis.get("brand_personality"):
|
||||
score += 5
|
||||
if style_analysis.get("formality_level"):
|
||||
score += 5
|
||||
if style_analysis.get("emotional_appeal"):
|
||||
score += 5
|
||||
|
||||
# Content Insights (20% of score)
|
||||
content_insights = enhanced_analysis.get("content_insights", {})
|
||||
if content_insights.get("sentence_structure_analysis"):
|
||||
score += 4
|
||||
if content_insights.get("vocabulary_level"):
|
||||
score += 4
|
||||
if content_insights.get("readability_score"):
|
||||
score += 4
|
||||
if content_insights.get("content_flow"):
|
||||
score += 4
|
||||
if content_insights.get("visual_elements_usage"):
|
||||
score += 4
|
||||
|
||||
# Audience Intelligence (15% of score)
|
||||
audience_intel = enhanced_analysis.get("audience_intelligence", {})
|
||||
if audience_intel.get("demographics"):
|
||||
score += 3
|
||||
if audience_intel.get("expertise_level"):
|
||||
score += 3
|
||||
if audience_intel.get("industry_focus"):
|
||||
score += 3
|
||||
if audience_intel.get("psychographic_profile"):
|
||||
score += 3
|
||||
if audience_intel.get("pain_points"):
|
||||
score += 3
|
||||
|
||||
# Technical Writing Metrics (15% of score)
|
||||
tech_metrics = enhanced_analysis.get("technical_writing_metrics", {})
|
||||
if tech_metrics.get("vocabulary_patterns"):
|
||||
score += 3
|
||||
if tech_metrics.get("rhetorical_devices"):
|
||||
score += 3
|
||||
if tech_metrics.get("paragraph_structure"):
|
||||
score += 3
|
||||
if tech_metrics.get("style_consistency"):
|
||||
score += 3
|
||||
if tech_metrics.get("unique_elements"):
|
||||
score += 3
|
||||
|
||||
# Content Strategy Insights (15% of score)
|
||||
strategy_insights = enhanced_analysis.get("content_strategy_insights", {})
|
||||
if strategy_insights.get("tone_recommendations"):
|
||||
score += 3
|
||||
if strategy_insights.get("best_practices"):
|
||||
score += 3
|
||||
if strategy_insights.get("competitive_advantages"):
|
||||
score += 3
|
||||
if strategy_insights.get("content_strategy"):
|
||||
score += 3
|
||||
if strategy_insights.get("ai_generation_tips"):
|
||||
score += 3
|
||||
|
||||
# Research Preferences (10% of score)
|
||||
if research_prefs.get("research_depth"):
|
||||
score += 5
|
||||
if research_prefs.get("content_types"):
|
||||
score += 5
|
||||
|
||||
# Legacy compatibility - add points for basic data if enhanced data is missing
|
||||
if score < 50: # If enhanced data is insufficient, fall back to legacy scoring
|
||||
legacy_score = 0.0
|
||||
|
||||
# Website analysis components (70% of legacy score)
|
||||
if website_analysis.get("writing_style"):
|
||||
legacy_score += 25
|
||||
if website_analysis.get("content_characteristics"):
|
||||
legacy_score += 20
|
||||
if website_analysis.get("target_audience"):
|
||||
legacy_score += 15
|
||||
if website_analysis.get("style_patterns"):
|
||||
legacy_score += 10
|
||||
|
||||
# Research preferences components (30% of legacy score)
|
||||
if research_prefs.get("research_depth"):
|
||||
legacy_score += 10
|
||||
if research_prefs.get("content_types"):
|
||||
legacy_score += 10
|
||||
if research_prefs.get("writing_style"):
|
||||
legacy_score += 10
|
||||
|
||||
# Use the higher of enhanced or legacy score
|
||||
score = max(score, legacy_score)
|
||||
|
||||
return min(score, 100.0)
|
||||
313
backend/services/persona/core_persona/prompt_builder.py
Normal file
313
backend/services/persona/core_persona/prompt_builder.py
Normal file
@@ -0,0 +1,313 @@
|
||||
"""
|
||||
Persona Prompt Builder
|
||||
|
||||
Handles building comprehensive prompts for persona generation.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
import json
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class PersonaPromptBuilder:
|
||||
"""Builds comprehensive prompts for persona generation."""
|
||||
|
||||
def build_persona_analysis_prompt(self, onboarding_data: Dict[str, Any]) -> str:
|
||||
"""Build the main persona analysis prompt with comprehensive data."""
|
||||
|
||||
# Get enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
research_prefs = onboarding_data.get("research_preferences", {}) or {}
|
||||
|
||||
prompt = f"""
|
||||
COMPREHENSIVE PERSONA GENERATION TASK: Create a highly detailed, data-driven writing persona based on extensive AI analysis of user's website and content strategy.
|
||||
|
||||
=== COMPREHENSIVE ONBOARDING DATA ANALYSIS ===
|
||||
|
||||
WEBSITE ANALYSIS OVERVIEW:
|
||||
- URL: {website_analysis.get('website_url', 'Not provided')}
|
||||
- Analysis Date: {website_analysis.get('analysis_date', 'Not provided')}
|
||||
- Status: {website_analysis.get('status', 'Not provided')}
|
||||
|
||||
=== DETAILED STYLE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('comprehensive_style_analysis', {}), indent=2)}
|
||||
|
||||
=== CONTENT INSIGHTS ===
|
||||
{json.dumps(enhanced_analysis.get('content_insights', {}), indent=2)}
|
||||
|
||||
=== AUDIENCE INTELLIGENCE ===
|
||||
{json.dumps(enhanced_analysis.get('audience_intelligence', {}), indent=2)}
|
||||
|
||||
=== BRAND VOICE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('brand_voice_analysis', {}), indent=2)}
|
||||
|
||||
=== TECHNICAL WRITING METRICS ===
|
||||
{json.dumps(enhanced_analysis.get('technical_writing_metrics', {}), indent=2)}
|
||||
|
||||
=== COMPETITIVE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('competitive_analysis', {}), indent=2)}
|
||||
|
||||
=== CONTENT STRATEGY INSIGHTS ===
|
||||
{json.dumps(enhanced_analysis.get('content_strategy_insights', {}), indent=2)}
|
||||
|
||||
=== RESEARCH PREFERENCES ===
|
||||
{json.dumps(enhanced_analysis.get('research_preferences', {}), indent=2)}
|
||||
|
||||
=== LEGACY DATA (for compatibility) ===
|
||||
Website Analysis: {json.dumps(website_analysis.get('writing_style', {}), indent=2)}
|
||||
Content Characteristics: {json.dumps(website_analysis.get('content_characteristics', {}) or {}, indent=2)}
|
||||
Target Audience: {json.dumps(website_analysis.get('target_audience', {}), indent=2)}
|
||||
Style Patterns: {json.dumps(website_analysis.get('style_patterns', {}), indent=2)}
|
||||
|
||||
=== COMPREHENSIVE PERSONA GENERATION REQUIREMENTS ===
|
||||
|
||||
1. IDENTITY CREATION (Based on Brand Analysis):
|
||||
- Create a memorable persona name that captures the essence of the brand personality and writing style
|
||||
- Define a clear archetype that reflects the brand's positioning and audience appeal
|
||||
- Articulate a core belief that drives the writing philosophy and brand values
|
||||
- Write a comprehensive brand voice description incorporating all style elements
|
||||
|
||||
2. LINGUISTIC FINGERPRINT (Quantitative Analysis from Technical Metrics):
|
||||
- Calculate precise average sentence length from sentence structure analysis
|
||||
- Determine preferred sentence types based on paragraph organization patterns
|
||||
- Analyze active vs passive voice ratio from voice characteristics
|
||||
- Extract go-to words and phrases from vocabulary patterns and style analysis
|
||||
- List words and phrases to avoid based on brand alignment guidelines
|
||||
- Determine contraction usage patterns from formality level
|
||||
- Assess vocabulary complexity level from readability scores
|
||||
|
||||
3. RHETORICAL ANALYSIS (From Style Patterns):
|
||||
- Identify metaphor patterns and themes from rhetorical devices
|
||||
- Analyze analogy usage from content strategy insights
|
||||
- Assess rhetorical question frequency from engagement tips
|
||||
- Determine storytelling approach from content flow analysis
|
||||
|
||||
4. TONAL RANGE (From Comprehensive Style Analysis):
|
||||
- Define the default tone from tone analysis and brand personality
|
||||
- List permissible tones based on emotional appeal and audience considerations
|
||||
- Identify forbidden tones from avoid elements and brand alignment
|
||||
- Describe emotional range from psychographic profile and engagement level
|
||||
|
||||
5. STYLISTIC CONSTRAINTS (From Technical Writing Metrics):
|
||||
- Define punctuation preferences from paragraph structure analysis
|
||||
- Set formatting guidelines from content structure insights
|
||||
- Establish paragraph structure preferences from organization patterns
|
||||
- Include transition phrase preferences from style patterns
|
||||
|
||||
6. PLATFORM-SPECIFIC ADAPTATIONS (From Content Strategy):
|
||||
- Incorporate SEO optimization strategies
|
||||
- Include conversion optimization techniques
|
||||
- Apply engagement tips for different platforms
|
||||
- Use competitive advantages for differentiation
|
||||
|
||||
7. CONTENT STRATEGY INTEGRATION:
|
||||
- Incorporate best practices from content strategy insights
|
||||
- Include AI generation tips for consistent output
|
||||
- Apply content calendar suggestions for timing
|
||||
- Use competitive advantages for positioning
|
||||
|
||||
=== ENHANCED ANALYSIS INSTRUCTIONS ===
|
||||
- Base your analysis on ALL the comprehensive data provided above
|
||||
- Use the detailed technical metrics for precise linguistic analysis
|
||||
- Incorporate brand voice analysis for authentic personality
|
||||
- Apply audience intelligence for targeted communication
|
||||
- Include competitive analysis for market positioning
|
||||
- Use content strategy insights for practical application
|
||||
- Ensure the persona reflects the brand's unique elements and competitive advantages
|
||||
- Provide a confidence score (0-100) based on data richness and quality
|
||||
- Include detailed analysis notes explaining your reasoning and data sources
|
||||
|
||||
Generate a comprehensive, data-driven persona profile that can be used to replicate this writing style across different platforms while maintaining brand authenticity and competitive positioning.
|
||||
"""
|
||||
|
||||
return prompt
|
||||
|
||||
def build_platform_adaptation_prompt(self, core_persona: Dict[str, Any], platform: str, onboarding_data: Dict[str, Any], platform_constraints: Dict[str, Any]) -> str:
|
||||
"""Build prompt for platform-specific persona adaptation."""
|
||||
|
||||
prompt = f"""
|
||||
PLATFORM ADAPTATION TASK: Adapt the core writing persona for {platform.upper()}.
|
||||
|
||||
CORE PERSONA:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
PLATFORM: {platform.upper()}
|
||||
|
||||
PLATFORM CONSTRAINTS:
|
||||
{json.dumps(platform_constraints, indent=2)}
|
||||
|
||||
ADAPTATION REQUIREMENTS:
|
||||
|
||||
1. SENTENCE METRICS:
|
||||
- Adjust sentence length for platform optimal performance
|
||||
- Adapt sentence variety for platform engagement
|
||||
- Consider platform reading patterns
|
||||
|
||||
2. LEXICAL ADAPTATIONS:
|
||||
- Identify platform-specific vocabulary and slang
|
||||
- Define hashtag strategy (if applicable)
|
||||
- Set emoji usage guidelines
|
||||
- Establish mention and tagging strategy
|
||||
|
||||
3. CONTENT FORMAT RULES:
|
||||
- Respect character/word limits
|
||||
- Optimize paragraph structure for platform
|
||||
- Define call-to-action style
|
||||
- Set link placement strategy
|
||||
|
||||
4. ENGAGEMENT PATTERNS:
|
||||
- Determine optimal posting frequency
|
||||
- Identify best posting times for audience
|
||||
- Define engagement tactics
|
||||
- Set community interaction guidelines
|
||||
|
||||
5. PLATFORM BEST PRACTICES:
|
||||
- List platform-specific optimization techniques
|
||||
- Consider algorithm preferences
|
||||
- Include trending format adaptations
|
||||
|
||||
INSTRUCTIONS:
|
||||
- Maintain the core persona identity while optimizing for platform performance
|
||||
- Ensure all adaptations align with the original brand voice
|
||||
- Consider platform-specific audience behavior
|
||||
- Provide actionable, specific guidelines
|
||||
|
||||
Generate a platform-optimized persona adaptation that maintains brand consistency while maximizing platform performance.
|
||||
"""
|
||||
|
||||
return prompt
|
||||
|
||||
def get_persona_schema(self) -> Dict[str, Any]:
|
||||
"""Get the schema for core persona generation."""
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"identity": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"persona_name": {"type": "string"},
|
||||
"archetype": {"type": "string"},
|
||||
"core_belief": {"type": "string"},
|
||||
"brand_voice_description": {"type": "string"}
|
||||
},
|
||||
"required": ["persona_name", "archetype", "core_belief"]
|
||||
},
|
||||
"linguistic_fingerprint": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"average_sentence_length_words": {"type": "number"},
|
||||
"preferred_sentence_type": {"type": "string"},
|
||||
"active_to_passive_ratio": {"type": "string"},
|
||||
"complexity_level": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_features": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"go_to_words": {"type": "array", "items": {"type": "string"}},
|
||||
"go_to_phrases": {"type": "array", "items": {"type": "string"}},
|
||||
"avoid_words": {"type": "array", "items": {"type": "string"}},
|
||||
"contractions": {"type": "string"},
|
||||
"filler_words": {"type": "string"},
|
||||
"vocabulary_level": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"rhetorical_devices": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metaphors": {"type": "string"},
|
||||
"analogies": {"type": "string"},
|
||||
"rhetorical_questions": {"type": "string"},
|
||||
"storytelling_style": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tonal_range": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default_tone": {"type": "string"},
|
||||
"permissible_tones": {"type": "array", "items": {"type": "string"}},
|
||||
"forbidden_tones": {"type": "array", "items": {"type": "string"}},
|
||||
"emotional_range": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"stylistic_constraints": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"punctuation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ellipses": {"type": "string"},
|
||||
"em_dash": {"type": "string"},
|
||||
"exclamation_points": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"formatting": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"paragraphs": {"type": "string"},
|
||||
"lists": {"type": "string"},
|
||||
"markdown": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"confidence_score": {"type": "number"},
|
||||
"analysis_notes": {"type": "string"}
|
||||
},
|
||||
"required": ["identity", "linguistic_fingerprint", "tonal_range", "confidence_score"]
|
||||
}
|
||||
|
||||
def get_platform_schema(self) -> Dict[str, Any]:
|
||||
"""Get the schema for platform-specific persona adaptation."""
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_type": {"type": "string"},
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_sentence_length": {"type": "number"},
|
||||
"optimal_sentence_length": {"type": "number"},
|
||||
"sentence_variety": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_adaptations": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_specific_words": {"type": "array", "items": {"type": "string"}},
|
||||
"hashtag_strategy": {"type": "string"},
|
||||
"emoji_usage": {"type": "string"},
|
||||
"mention_strategy": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"content_format_rules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"character_limit": {"type": "number"},
|
||||
"paragraph_structure": {"type": "string"},
|
||||
"call_to_action_style": {"type": "string"},
|
||||
"link_placement": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"engagement_patterns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"posting_frequency": {"type": "string"},
|
||||
"optimal_posting_times": {"type": "array", "items": {"type": "string"}},
|
||||
"engagement_tactics": {"type": "array", "items": {"type": "string"}},
|
||||
"community_interaction": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"platform_best_practices": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"required": ["platform_type", "sentence_metrics", "content_format_rules", "engagement_patterns"]
|
||||
}
|
||||
213
backend/services/persona/facebook/facebook_persona_prompts.py
Normal file
213
backend/services/persona/facebook/facebook_persona_prompts.py
Normal file
@@ -0,0 +1,213 @@
|
||||
"""
|
||||
Facebook Persona Prompts
|
||||
Contains Facebook-specific persona prompt generation logic.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class FacebookPersonaPrompts:
|
||||
"""Facebook-specific persona prompt generation."""
|
||||
|
||||
@staticmethod
|
||||
def build_facebook_system_prompt(core_persona: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build optimized system prompt with core persona for Facebook generation.
|
||||
This moves the core persona to system prompt to free up context window.
|
||||
"""
|
||||
import json
|
||||
|
||||
return f"""You are an expert Facebook content strategist specializing in community engagement and social sharing optimization.
|
||||
|
||||
CORE PERSONA FOUNDATION:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
TASK: Create Facebook-optimized persona adaptations that maintain core identity while maximizing community engagement and Facebook algorithm performance.
|
||||
|
||||
FOCUS AREAS:
|
||||
- Community-focused tone and engagement strategies
|
||||
- Facebook algorithm optimization (engagement, reach, timing)
|
||||
- Social sharing and viral content potential
|
||||
- Facebook-specific features (Stories, Reels, Live, Groups, Events)
|
||||
- Audience interaction and community building"""
|
||||
|
||||
@staticmethod
|
||||
def build_focused_facebook_prompt(onboarding_data: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build focused Facebook prompt without core persona JSON to optimize context usage.
|
||||
"""
|
||||
# Extract audience context
|
||||
audience_context = FacebookPersonaPrompts._extract_audience_context(onboarding_data)
|
||||
|
||||
target_audience = audience_context.get("target_audience", "general")
|
||||
content_goals = audience_context.get("content_goals", "engagement")
|
||||
business_type = audience_context.get("business_type", "general")
|
||||
|
||||
return f"""FACEBOOK OPTIMIZATION TASK: Create Facebook-specific adaptations for the core persona.
|
||||
|
||||
AUDIENCE CONTEXT:
|
||||
- Target: {target_audience} | Goals: {content_goals} | Business: {business_type}
|
||||
- Demographics: {audience_context.get('demographics', [])}
|
||||
- Interests: {audience_context.get('interests', [])}
|
||||
- Behaviors: {audience_context.get('behaviors', [])}
|
||||
|
||||
FACEBOOK SPECS:
|
||||
- Character Limit: 63,206 | Optimal Length: 40-80 words
|
||||
- Algorithm Priority: Engagement, meaningful interactions, community building
|
||||
- Content Types: Posts, Stories, Reels, Live, Events, Groups, Carousels, Polls
|
||||
- Hashtag Strategy: 1-2 recommended (max 30)
|
||||
- Link Strategy: Native content performs better
|
||||
|
||||
OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. COMMUNITY-FOCUSED TONE:
|
||||
- Authentic, conversational, approachable language
|
||||
- Balance professionalism with relatability
|
||||
- Incorporate storytelling and personal anecdotes
|
||||
- Community-building elements
|
||||
|
||||
2. CONTENT STRATEGY FOR {business_type.upper()}:
|
||||
- Community engagement content for {target_audience}
|
||||
- Social sharing optimization for {content_goals}
|
||||
- Facebook-specific content formats
|
||||
- Audience interaction strategies
|
||||
- Viral content potential
|
||||
|
||||
3. FACEBOOK-SPECIFIC ADAPTATIONS:
|
||||
- Algorithm optimization (engagement, reach, timing)
|
||||
- Platform-specific vocabulary and terminology
|
||||
- Engagement patterns for Facebook audience
|
||||
- Community interaction strategies
|
||||
- Facebook feature optimization (Stories, Reels, Live, Events, Groups)
|
||||
|
||||
4. AUDIENCE TARGETING:
|
||||
- Demographic-specific positioning
|
||||
- Interest-based content adaptation
|
||||
- Behavioral targeting considerations
|
||||
- Community building strategies
|
||||
- Engagement optimization tactics
|
||||
|
||||
Generate comprehensive Facebook-optimized persona maintaining core identity while maximizing community engagement and social sharing potential."""
|
||||
|
||||
@staticmethod
|
||||
def _extract_audience_context(onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Extract audience context from onboarding data."""
|
||||
try:
|
||||
# Get enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
research_prefs = onboarding_data.get("research_preferences", {}) or {}
|
||||
|
||||
# Extract audience intelligence
|
||||
audience_intel = enhanced_analysis.get("audience_intelligence", {})
|
||||
|
||||
# Extract target audience from website analysis
|
||||
target_audience_data = website_analysis.get("target_audience", {}) or {}
|
||||
|
||||
# Build audience context
|
||||
audience_context = {
|
||||
"target_audience": target_audience_data.get("primary_audience", "general"),
|
||||
"content_goals": research_prefs.get("content_goals", "engagement"),
|
||||
"business_type": website_analysis.get("business_type", "general"),
|
||||
"demographics": audience_intel.get("demographics", []),
|
||||
"interests": audience_intel.get("interests", []),
|
||||
"behaviors": audience_intel.get("behaviors", []),
|
||||
"psychographic_profile": audience_intel.get("psychographic_profile", "general"),
|
||||
"pain_points": audience_intel.get("pain_points", []),
|
||||
"engagement_level": audience_intel.get("engagement_level", "moderate")
|
||||
}
|
||||
|
||||
return audience_context
|
||||
|
||||
except Exception as e:
|
||||
logger.warning(f"Error extracting audience context: {str(e)}")
|
||||
return {
|
||||
"target_audience": "general",
|
||||
"content_goals": "engagement",
|
||||
"business_type": "general",
|
||||
"demographics": [],
|
||||
"interests": [],
|
||||
"behaviors": [],
|
||||
"psychographic_profile": "general",
|
||||
"pain_points": [],
|
||||
"engagement_level": "moderate"
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def build_facebook_validation_prompt(persona_data: Dict[str, Any]) -> str:
|
||||
"""Build optimized prompt for validating Facebook persona data."""
|
||||
return f"""FACEBOOK PERSONA VALIDATION TASK: Validate Facebook persona data for completeness and quality.
|
||||
|
||||
PERSONA DATA:
|
||||
{persona_data}
|
||||
|
||||
VALIDATION REQUIREMENTS:
|
||||
|
||||
1. COMPLETENESS CHECK:
|
||||
- Verify all required Facebook-specific fields are present
|
||||
- Check for missing algorithm optimization strategies
|
||||
- Validate engagement strategy completeness
|
||||
- Ensure content format rules are defined
|
||||
|
||||
2. QUALITY ASSESSMENT:
|
||||
- Evaluate Facebook algorithm optimization quality
|
||||
- Assess engagement strategy effectiveness
|
||||
- Check content format optimization
|
||||
- Validate audience targeting strategies
|
||||
|
||||
3. FACEBOOK-SPECIFIC VALIDATION:
|
||||
- Verify Facebook platform constraints are respected
|
||||
- Check for Facebook-specific best practices
|
||||
- Validate community building strategies
|
||||
- Ensure Facebook feature optimization
|
||||
|
||||
4. RECOMMENDATIONS:
|
||||
- Provide specific improvement suggestions
|
||||
- Identify missing optimization opportunities
|
||||
- Suggest Facebook-specific enhancements
|
||||
- Recommend engagement strategy improvements
|
||||
|
||||
Generate comprehensive validation report with scores, recommendations, and specific improvement suggestions for Facebook optimization."""
|
||||
|
||||
@staticmethod
|
||||
def build_facebook_optimization_prompt(persona_data: Dict[str, Any]) -> str:
|
||||
"""Build optimized prompt for optimizing Facebook persona data."""
|
||||
return f"""FACEBOOK PERSONA OPTIMIZATION TASK: Optimize Facebook persona data for maximum algorithm performance and community engagement.
|
||||
|
||||
CURRENT PERSONA DATA:
|
||||
{persona_data}
|
||||
|
||||
OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. ALGORITHM OPTIMIZATION:
|
||||
- Enhance Facebook algorithm performance strategies
|
||||
- Optimize for Facebook's engagement metrics
|
||||
- Improve content timing and frequency
|
||||
- Enhance audience targeting precision
|
||||
|
||||
2. ENGAGEMENT OPTIMIZATION:
|
||||
- Strengthen community building strategies
|
||||
- Enhance social sharing potential
|
||||
- Improve audience interaction tactics
|
||||
- Optimize content for viral potential
|
||||
|
||||
3. CONTENT FORMAT OPTIMIZATION:
|
||||
- Optimize for Facebook's content formats
|
||||
- Enhance visual content strategies
|
||||
- Improve video content optimization
|
||||
- Optimize for Facebook Stories and Reels
|
||||
|
||||
4. AUDIENCE TARGETING OPTIMIZATION:
|
||||
- Refine demographic targeting
|
||||
- Enhance interest-based targeting
|
||||
- Improve behavioral targeting
|
||||
- Optimize for Facebook's audience insights
|
||||
|
||||
5. COMMUNITY BUILDING OPTIMIZATION:
|
||||
- Enhance group management strategies
|
||||
- Improve event management tactics
|
||||
- Optimize live streaming strategies
|
||||
- Enhance community interaction methods
|
||||
|
||||
Generate optimized Facebook persona data with enhanced algorithm performance, engagement strategies, and community building tactics."""
|
||||
364
backend/services/persona/facebook/facebook_persona_schemas.py
Normal file
364
backend/services/persona/facebook/facebook_persona_schemas.py
Normal file
@@ -0,0 +1,364 @@
|
||||
"""
|
||||
Facebook Persona Schemas
|
||||
Defines Facebook-specific persona data structures and validation schemas.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, List, Optional
|
||||
from pydantic import BaseModel, Field
|
||||
|
||||
|
||||
class FacebookPersonaSchema(BaseModel):
|
||||
"""Facebook-specific persona schema with platform optimizations."""
|
||||
|
||||
# Core persona fields (inherited from base persona)
|
||||
persona_name: str = Field(..., description="Name of the persona")
|
||||
archetype: str = Field(..., description="Persona archetype")
|
||||
core_belief: str = Field(..., description="Core belief driving the persona")
|
||||
|
||||
# Facebook-specific optimizations
|
||||
facebook_algorithm_optimization: Dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Facebook algorithm optimization strategies"
|
||||
)
|
||||
|
||||
facebook_engagement_strategies: Dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Facebook-specific engagement strategies"
|
||||
)
|
||||
|
||||
facebook_content_formats: Dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Facebook content format optimizations"
|
||||
)
|
||||
|
||||
facebook_audience_targeting: Dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Facebook audience targeting strategies"
|
||||
)
|
||||
|
||||
facebook_community_building: Dict[str, Any] = Field(
|
||||
default_factory=dict,
|
||||
description="Facebook community building strategies"
|
||||
)
|
||||
|
||||
|
||||
class FacebookPersonaConstraints:
|
||||
"""Facebook platform constraints and best practices."""
|
||||
|
||||
@staticmethod
|
||||
def get_facebook_constraints() -> Dict[str, Any]:
|
||||
"""Get Facebook-specific platform constraints."""
|
||||
return {
|
||||
"character_limit": 63206,
|
||||
"optimal_length": "40-80 words",
|
||||
"hashtag_limit": 30,
|
||||
"image_support": True,
|
||||
"video_support": True,
|
||||
"link_preview": True,
|
||||
"event_support": True,
|
||||
"group_sharing": True,
|
||||
"story_support": True,
|
||||
"reel_support": True,
|
||||
"carousel_support": True,
|
||||
"poll_support": True,
|
||||
"live_support": True,
|
||||
"algorithm_favors": [
|
||||
"engagement",
|
||||
"meaningful_interactions",
|
||||
"video_content",
|
||||
"community_posts",
|
||||
"authentic_content"
|
||||
],
|
||||
"content_types": [
|
||||
"text_posts",
|
||||
"image_posts",
|
||||
"video_posts",
|
||||
"carousel_posts",
|
||||
"story_posts",
|
||||
"reel_posts",
|
||||
"event_posts",
|
||||
"poll_posts",
|
||||
"live_posts"
|
||||
],
|
||||
"engagement_metrics": [
|
||||
"likes",
|
||||
"comments",
|
||||
"shares",
|
||||
"saves",
|
||||
"clicks",
|
||||
"reactions",
|
||||
"video_views",
|
||||
"story_views"
|
||||
],
|
||||
"posting_frequency": {
|
||||
"optimal": "1-2 times per day",
|
||||
"maximum": "3-4 times per day",
|
||||
"minimum": "3-4 times per week"
|
||||
},
|
||||
"best_posting_times": [
|
||||
"9:00 AM - 11:00 AM",
|
||||
"1:00 PM - 3:00 PM",
|
||||
"5:00 PM - 7:00 PM"
|
||||
],
|
||||
"content_guidelines": {
|
||||
"authenticity": "High priority - Facebook favors authentic content",
|
||||
"community_focus": "Build community and meaningful connections",
|
||||
"visual_content": "Images and videos perform better than text-only",
|
||||
"engagement_bait": "Avoid engagement bait - Facebook penalizes it",
|
||||
"clickbait": "Avoid clickbait headlines and misleading content"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class FacebookPersonaValidation:
|
||||
"""Facebook persona validation rules and scoring."""
|
||||
|
||||
@staticmethod
|
||||
def validate_facebook_persona(persona_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Validate Facebook persona data for completeness and quality."""
|
||||
|
||||
validation_results = {
|
||||
"is_valid": True,
|
||||
"quality_score": 0.0,
|
||||
"completeness_score": 0.0,
|
||||
"facebook_optimization_score": 0.0,
|
||||
"engagement_strategy_score": 0.0,
|
||||
"missing_fields": [],
|
||||
"incomplete_fields": [],
|
||||
"recommendations": [],
|
||||
"quality_issues": [],
|
||||
"strengths": [],
|
||||
"validation_details": {}
|
||||
}
|
||||
|
||||
# Check required fields
|
||||
required_fields = [
|
||||
"persona_name", "archetype", "core_belief",
|
||||
"facebook_algorithm_optimization", "facebook_engagement_strategies"
|
||||
]
|
||||
|
||||
for field in required_fields:
|
||||
if not persona_data.get(field):
|
||||
validation_results["missing_fields"].append(field)
|
||||
validation_results["is_valid"] = False
|
||||
|
||||
# Calculate completeness score
|
||||
total_fields = len(required_fields)
|
||||
present_fields = total_fields - len(validation_results["missing_fields"])
|
||||
validation_results["completeness_score"] = (present_fields / total_fields) * 100
|
||||
|
||||
# Validate Facebook-specific optimizations
|
||||
facebook_opt = persona_data.get("facebook_algorithm_optimization", {})
|
||||
if facebook_opt:
|
||||
validation_results["facebook_optimization_score"] = 85.0
|
||||
validation_results["strengths"].append("Facebook algorithm optimization present")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook algorithm optimization")
|
||||
validation_results["recommendations"].append("Add Facebook-specific algorithm strategies")
|
||||
|
||||
# Validate engagement strategies
|
||||
engagement_strategies = persona_data.get("facebook_engagement_strategies", {})
|
||||
if engagement_strategies:
|
||||
validation_results["engagement_strategy_score"] = 80.0
|
||||
validation_results["strengths"].append("Facebook engagement strategies defined")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook engagement strategies")
|
||||
validation_results["recommendations"].append("Define Facebook-specific engagement tactics")
|
||||
|
||||
# Calculate overall quality score
|
||||
validation_results["quality_score"] = (
|
||||
validation_results["completeness_score"] * 0.4 +
|
||||
validation_results["facebook_optimization_score"] * 0.3 +
|
||||
validation_results["engagement_strategy_score"] * 0.3
|
||||
)
|
||||
|
||||
# Add validation details
|
||||
validation_results["validation_details"] = {
|
||||
"total_fields_checked": total_fields,
|
||||
"present_fields": present_fields,
|
||||
"facebook_optimization_present": bool(facebook_opt),
|
||||
"engagement_strategies_present": bool(engagement_strategies),
|
||||
"validation_timestamp": "2024-01-01T00:00:00Z" # Will be updated with actual timestamp
|
||||
}
|
||||
|
||||
return validation_results
|
||||
|
||||
|
||||
class FacebookPersonaOptimization:
|
||||
"""Facebook persona optimization strategies and techniques."""
|
||||
|
||||
@staticmethod
|
||||
def get_facebook_optimization_strategies() -> Dict[str, Any]:
|
||||
"""Get comprehensive Facebook optimization strategies."""
|
||||
return {
|
||||
"algorithm_optimization": {
|
||||
"engagement_optimization": [
|
||||
"Post when your audience is most active",
|
||||
"Use Facebook's native video uploads instead of external links",
|
||||
"Encourage meaningful comments and discussions",
|
||||
"Respond to comments within 2 hours",
|
||||
"Use Facebook Live for real-time engagement",
|
||||
"Create shareable, valuable content",
|
||||
"Use Facebook Stories for behind-the-scenes content",
|
||||
"Leverage Facebook Groups for community building"
|
||||
],
|
||||
"content_quality_optimization": [
|
||||
"Create authentic, original content",
|
||||
"Use high-quality images and videos",
|
||||
"Write compelling captions that encourage engagement",
|
||||
"Use Facebook's built-in editing tools",
|
||||
"Create content that sparks conversations",
|
||||
"Share user-generated content",
|
||||
"Use Facebook's trending topics and hashtags",
|
||||
"Create content that provides value to your audience"
|
||||
],
|
||||
"timing_optimization": [
|
||||
"Post during peak engagement hours (9-11 AM, 1-3 PM, 5-7 PM)",
|
||||
"Use Facebook Insights to find your best posting times",
|
||||
"Post consistently but not too frequently",
|
||||
"Schedule posts for different time zones if global audience",
|
||||
"Use Facebook's scheduling feature for optimal timing",
|
||||
"Post when your competitors are less active",
|
||||
"Consider your audience's daily routines and habits"
|
||||
],
|
||||
"audience_targeting_optimization": [
|
||||
"Use Facebook's audience insights for targeting",
|
||||
"Create content for specific audience segments",
|
||||
"Use Facebook's lookalike audiences",
|
||||
"Target based on interests and behaviors",
|
||||
"Use Facebook's custom audiences",
|
||||
"Create content that resonates with your core audience",
|
||||
"Use Facebook's demographic targeting",
|
||||
"Leverage Facebook's psychographic targeting"
|
||||
]
|
||||
},
|
||||
"engagement_strategies": {
|
||||
"community_building": [
|
||||
"Create and moderate Facebook Groups",
|
||||
"Host Facebook Live sessions regularly",
|
||||
"Respond to all comments and messages",
|
||||
"Share user-generated content",
|
||||
"Create Facebook Events for community gatherings",
|
||||
"Use Facebook's community features",
|
||||
"Encourage user participation and feedback",
|
||||
"Build relationships with your audience"
|
||||
],
|
||||
"content_engagement": [
|
||||
"Ask questions in your posts",
|
||||
"Use polls and surveys to engage audience",
|
||||
"Create interactive content like quizzes",
|
||||
"Use Facebook's reaction buttons strategically",
|
||||
"Create content that encourages sharing",
|
||||
"Use Facebook's tagging feature appropriately",
|
||||
"Create content that sparks discussions",
|
||||
"Use Facebook's story features for engagement"
|
||||
],
|
||||
"conversion_optimization": [
|
||||
"Use clear call-to-actions in posts",
|
||||
"Create Facebook-specific landing pages",
|
||||
"Use Facebook's conversion tracking",
|
||||
"Create content that drives traffic to your website",
|
||||
"Use Facebook's lead generation features",
|
||||
"Create content that builds trust and credibility",
|
||||
"Use Facebook's retargeting capabilities",
|
||||
"Create content that showcases your products/services"
|
||||
]
|
||||
},
|
||||
"content_formats": {
|
||||
"text_posts": {
|
||||
"optimal_length": "40-80 words",
|
||||
"best_practices": [
|
||||
"Use compelling headlines",
|
||||
"Include relevant hashtags (1-2)",
|
||||
"Ask questions to encourage engagement",
|
||||
"Use emojis sparingly but effectively",
|
||||
"Include clear call-to-actions"
|
||||
]
|
||||
},
|
||||
"image_posts": {
|
||||
"optimal_specs": "1200x630 pixels",
|
||||
"best_practices": [
|
||||
"Use high-quality, original images",
|
||||
"Include text overlay for key messages",
|
||||
"Use consistent branding and colors",
|
||||
"Create visually appealing graphics",
|
||||
"Use Facebook's image editing tools"
|
||||
]
|
||||
},
|
||||
"video_posts": {
|
||||
"optimal_length": "15-60 seconds for feed, 2-3 minutes for longer content",
|
||||
"best_practices": [
|
||||
"Upload videos directly to Facebook",
|
||||
"Create engaging thumbnails",
|
||||
"Add captions for accessibility",
|
||||
"Use Facebook's video editing tools",
|
||||
"Create videos that work without sound"
|
||||
]
|
||||
},
|
||||
"carousel_posts": {
|
||||
"optimal_slides": "3-5 slides",
|
||||
"best_practices": [
|
||||
"Tell a story across slides",
|
||||
"Use consistent design elements",
|
||||
"Include clear navigation",
|
||||
"Create slides that work individually",
|
||||
"Use carousels for product showcases"
|
||||
]
|
||||
}
|
||||
},
|
||||
"audience_targeting": {
|
||||
"demographic_targeting": [
|
||||
"Age and gender targeting",
|
||||
"Location-based targeting",
|
||||
"Education and work targeting",
|
||||
"Relationship status targeting",
|
||||
"Language targeting"
|
||||
],
|
||||
"interest_targeting": [
|
||||
"Hobbies and interests",
|
||||
"Brand and product interests",
|
||||
"Entertainment preferences",
|
||||
"Lifestyle and behavior targeting",
|
||||
"Purchase behavior targeting"
|
||||
],
|
||||
"behavioral_targeting": [
|
||||
"Device usage patterns",
|
||||
"Travel behavior",
|
||||
"Purchase behavior",
|
||||
"Digital activity patterns",
|
||||
"Life events targeting"
|
||||
]
|
||||
},
|
||||
"community_building": {
|
||||
"group_management": [
|
||||
"Create and moderate relevant Facebook Groups",
|
||||
"Set clear group rules and guidelines",
|
||||
"Encourage member participation",
|
||||
"Share valuable content in groups",
|
||||
"Use groups for customer support",
|
||||
"Create group events and activities",
|
||||
"Recognize and reward active members",
|
||||
"Use groups for market research"
|
||||
],
|
||||
"event_management": [
|
||||
"Create Facebook Events for promotions",
|
||||
"Use events for product launches",
|
||||
"Host virtual events and webinars",
|
||||
"Create recurring events for consistency",
|
||||
"Use events for community building",
|
||||
"Promote events across all channels",
|
||||
"Follow up with event attendees",
|
||||
"Use events for lead generation"
|
||||
],
|
||||
"live_streaming": [
|
||||
"Host regular Facebook Live sessions",
|
||||
"Use live streaming for Q&A sessions",
|
||||
"Create behind-the-scenes content",
|
||||
"Use live streaming for product demos",
|
||||
"Engage with viewers in real-time",
|
||||
"Use live streaming for announcements",
|
||||
"Create interactive live content",
|
||||
"Use live streaming for customer support"
|
||||
]
|
||||
}
|
||||
}
|
||||
421
backend/services/persona/facebook/facebook_persona_service.py
Normal file
421
backend/services/persona/facebook/facebook_persona_service.py
Normal file
@@ -0,0 +1,421 @@
|
||||
"""
|
||||
Facebook Persona Service
|
||||
Encapsulates Facebook-specific persona generation logic.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from loguru import logger
|
||||
from datetime import datetime
|
||||
|
||||
from .facebook_persona_schemas import (
|
||||
FacebookPersonaSchema,
|
||||
FacebookPersonaConstraints,
|
||||
FacebookPersonaValidation,
|
||||
FacebookPersonaOptimization
|
||||
)
|
||||
from .facebook_persona_prompts import FacebookPersonaPrompts
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
|
||||
|
||||
class FacebookPersonaService:
|
||||
"""Facebook-specific persona generation and optimization service."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the Facebook persona service."""
|
||||
self.schemas = FacebookPersonaSchema
|
||||
self.constraints = FacebookPersonaConstraints()
|
||||
self.validation = FacebookPersonaValidation()
|
||||
self.optimization = FacebookPersonaOptimization()
|
||||
self.prompts = FacebookPersonaPrompts()
|
||||
logger.info("FacebookPersonaService initialized")
|
||||
|
||||
def generate_facebook_persona(self, core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate Facebook-specific persona adaptation using optimized chained prompts.
|
||||
|
||||
Args:
|
||||
core_persona: The core persona data
|
||||
onboarding_data: User onboarding data
|
||||
|
||||
Returns:
|
||||
Facebook-optimized persona data
|
||||
"""
|
||||
try:
|
||||
logger.info("Generating Facebook-specific persona with optimized prompts")
|
||||
|
||||
# Build focused Facebook prompt (without core persona JSON)
|
||||
prompt = self.prompts.build_focused_facebook_prompt(onboarding_data)
|
||||
|
||||
# Create system prompt with core persona
|
||||
system_prompt = self.prompts.build_facebook_system_prompt(core_persona)
|
||||
|
||||
# Get Facebook-specific schema
|
||||
schema = self._get_enhanced_facebook_schema()
|
||||
|
||||
# Generate structured response using Gemini with optimized prompts
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=schema,
|
||||
temperature=0.2,
|
||||
max_tokens=4096,
|
||||
system_prompt=system_prompt
|
||||
)
|
||||
|
||||
if not response or "error" in response:
|
||||
logger.error(f"Failed to generate Facebook persona: {response}")
|
||||
return {"error": f"Failed to generate Facebook persona: {response}"}
|
||||
|
||||
# Validate the generated persona
|
||||
validation_results = self.validate_facebook_persona(response)
|
||||
|
||||
# Apply algorithm optimization
|
||||
optimized_persona = self.optimize_for_facebook_algorithm(response)
|
||||
|
||||
# Add validation results to the persona
|
||||
optimized_persona["validation_results"] = validation_results
|
||||
|
||||
logger.info(f"✅ Facebook persona generated successfully with {validation_results['quality_score']:.1f}% quality score")
|
||||
|
||||
return optimized_persona
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating Facebook persona: {str(e)}")
|
||||
return {"error": f"Failed to generate Facebook persona: {str(e)}"}
|
||||
|
||||
def get_facebook_constraints(self) -> Dict[str, Any]:
|
||||
"""Get Facebook-specific platform constraints."""
|
||||
return self.constraints.get_facebook_constraints()
|
||||
|
||||
def validate_facebook_persona(self, persona_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Validate Facebook persona data for completeness and quality.
|
||||
|
||||
Args:
|
||||
persona_data: Facebook persona data to validate
|
||||
|
||||
Returns:
|
||||
Validation results with scores and recommendations
|
||||
"""
|
||||
try:
|
||||
logger.info("Validating Facebook persona data")
|
||||
|
||||
# Use the validation class
|
||||
validation_results = self.validation.validate_facebook_persona(persona_data)
|
||||
|
||||
# Initialize missing fields if they don't exist
|
||||
if "content_format_score" not in validation_results:
|
||||
validation_results["content_format_score"] = 0.0
|
||||
if "audience_targeting_score" not in validation_results:
|
||||
validation_results["audience_targeting_score"] = 0.0
|
||||
if "community_building_score" not in validation_results:
|
||||
validation_results["community_building_score"] = 0.0
|
||||
|
||||
# Add Facebook-specific validation
|
||||
facebook_opt = persona_data.get("facebook_algorithm_optimization", {})
|
||||
if facebook_opt:
|
||||
validation_results["facebook_optimization_score"] = 90.0
|
||||
validation_results["strengths"].append("Facebook algorithm optimization present")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook algorithm optimization")
|
||||
validation_results["recommendations"].append("Add Facebook-specific algorithm strategies")
|
||||
|
||||
# Validate engagement strategies
|
||||
engagement_strategies = persona_data.get("facebook_engagement_strategies", {})
|
||||
if engagement_strategies:
|
||||
validation_results["engagement_strategy_score"] = 85.0
|
||||
validation_results["strengths"].append("Facebook engagement strategies defined")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook engagement strategies")
|
||||
validation_results["recommendations"].append("Define Facebook-specific engagement tactics")
|
||||
|
||||
# Validate content formats
|
||||
content_formats = persona_data.get("facebook_content_formats", {})
|
||||
if content_formats:
|
||||
validation_results["content_format_score"] = 80.0
|
||||
validation_results["strengths"].append("Facebook content formats optimized")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook content format optimization")
|
||||
validation_results["recommendations"].append("Add Facebook-specific content format strategies")
|
||||
|
||||
# Validate audience targeting
|
||||
audience_targeting = persona_data.get("facebook_audience_targeting", {})
|
||||
if audience_targeting:
|
||||
validation_results["audience_targeting_score"] = 75.0
|
||||
validation_results["strengths"].append("Facebook audience targeting strategies present")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook audience targeting")
|
||||
validation_results["recommendations"].append("Add Facebook-specific audience targeting strategies")
|
||||
|
||||
# Validate community building
|
||||
community_building = persona_data.get("facebook_community_building", {})
|
||||
if community_building:
|
||||
validation_results["community_building_score"] = 85.0
|
||||
validation_results["strengths"].append("Facebook community building strategies defined")
|
||||
else:
|
||||
validation_results["quality_issues"].append("Missing Facebook community building strategies")
|
||||
validation_results["recommendations"].append("Add Facebook-specific community building tactics")
|
||||
|
||||
# Recalculate overall quality score
|
||||
validation_results["quality_score"] = (
|
||||
validation_results["completeness_score"] * 0.2 +
|
||||
validation_results["facebook_optimization_score"] * 0.25 +
|
||||
validation_results["engagement_strategy_score"] * 0.2 +
|
||||
validation_results["content_format_score"] * 0.15 +
|
||||
validation_results["audience_targeting_score"] * 0.1 +
|
||||
validation_results["community_building_score"] * 0.1
|
||||
)
|
||||
|
||||
# Add validation timestamp
|
||||
validation_results["validation_timestamp"] = datetime.utcnow().isoformat()
|
||||
|
||||
logger.info(f"Facebook persona validation completed: Quality Score: {validation_results['quality_score']:.1f}%")
|
||||
|
||||
return validation_results
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error validating Facebook persona: {str(e)}")
|
||||
return {
|
||||
"is_valid": False,
|
||||
"quality_score": 0.0,
|
||||
"error": f"Validation failed: {str(e)}"
|
||||
}
|
||||
|
||||
def optimize_for_facebook_algorithm(self, persona_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Optimize Facebook persona data for maximum algorithm performance.
|
||||
|
||||
Args:
|
||||
persona_data: Facebook persona data to optimize
|
||||
|
||||
Returns:
|
||||
Optimized Facebook persona data
|
||||
"""
|
||||
try:
|
||||
logger.info("Optimizing Facebook persona for algorithm performance")
|
||||
|
||||
# Get optimization strategies
|
||||
optimization_strategies = self.optimization.get_facebook_optimization_strategies()
|
||||
|
||||
# Apply algorithm optimization
|
||||
optimized_persona = persona_data.copy()
|
||||
|
||||
# Add comprehensive algorithm optimization
|
||||
optimized_persona["algorithm_optimization"] = {
|
||||
"engagement_optimization": optimization_strategies["algorithm_optimization"]["engagement_optimization"],
|
||||
"content_quality_optimization": optimization_strategies["algorithm_optimization"]["content_quality_optimization"],
|
||||
"timing_optimization": optimization_strategies["algorithm_optimization"]["timing_optimization"],
|
||||
"audience_targeting_optimization": optimization_strategies["algorithm_optimization"]["audience_targeting_optimization"]
|
||||
}
|
||||
|
||||
# Add engagement strategies
|
||||
optimized_persona["engagement_strategies"] = {
|
||||
"community_building": optimization_strategies["engagement_strategies"]["community_building"],
|
||||
"content_engagement": optimization_strategies["engagement_strategies"]["content_engagement"],
|
||||
"conversion_optimization": optimization_strategies["engagement_strategies"]["conversion_optimization"]
|
||||
}
|
||||
|
||||
# Add content format optimization
|
||||
optimized_persona["content_formats"] = optimization_strategies["content_formats"]
|
||||
|
||||
# Add audience targeting optimization
|
||||
optimized_persona["audience_targeting"] = optimization_strategies["audience_targeting"]
|
||||
|
||||
# Add community building optimization
|
||||
optimized_persona["community_building"] = optimization_strategies["community_building"]
|
||||
|
||||
# Add optimization metadata
|
||||
total_strategies = 0
|
||||
for category_name, category_data in optimization_strategies.items():
|
||||
if isinstance(category_data, dict):
|
||||
for strategy_name, strategies in category_data.items():
|
||||
if isinstance(strategies, list):
|
||||
total_strategies += len(strategies)
|
||||
elif isinstance(strategies, dict):
|
||||
# Handle nested dictionaries
|
||||
for sub_strategy_name, sub_strategies in strategies.items():
|
||||
if isinstance(sub_strategies, list):
|
||||
total_strategies += len(sub_strategies)
|
||||
else:
|
||||
total_strategies += 1
|
||||
else:
|
||||
total_strategies += 1
|
||||
elif isinstance(category_data, list):
|
||||
total_strategies += len(category_data)
|
||||
else:
|
||||
total_strategies += 1
|
||||
|
||||
optimized_persona["optimization_metadata"] = {
|
||||
"optimization_applied": True,
|
||||
"optimization_timestamp": datetime.utcnow().isoformat(),
|
||||
"optimization_categories": list(optimization_strategies.keys()),
|
||||
"total_optimization_strategies": total_strategies
|
||||
}
|
||||
|
||||
logger.info("✅ Facebook persona algorithm optimization completed successfully")
|
||||
|
||||
return optimized_persona
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error optimizing Facebook persona: {str(e)}")
|
||||
return persona_data # Return original data if optimization fails
|
||||
|
||||
def _get_enhanced_facebook_schema(self) -> Dict[str, Any]:
|
||||
"""Get enhanced Facebook persona schema for Gemini structured response with improved JSON parsing reliability."""
|
||||
return {
|
||||
"type": "object",
|
||||
"description": "Facebook-optimized persona data structure for community engagement and algorithm optimization",
|
||||
"properties": {
|
||||
"persona_name": {
|
||||
"type": "string",
|
||||
"description": "Name of the Facebook-optimized persona (e.g., 'Community Builder', 'Social Connector')",
|
||||
"minLength": 3,
|
||||
"maxLength": 50
|
||||
},
|
||||
"archetype": {
|
||||
"type": "string",
|
||||
"description": "Persona archetype for Facebook (e.g., 'The Community Catalyst', 'The Social Storyteller')",
|
||||
"minLength": 5,
|
||||
"maxLength": 50
|
||||
},
|
||||
"core_belief": {
|
||||
"type": "string",
|
||||
"description": "Core belief driving the Facebook persona (e.g., 'Building authentic connections through shared experiences')",
|
||||
"minLength": 10,
|
||||
"maxLength": 200
|
||||
},
|
||||
"facebook_algorithm_optimization": {
|
||||
"type": "object",
|
||||
"description": "Facebook algorithm optimization strategies",
|
||||
"properties": {
|
||||
"engagement_optimization": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Strategies for optimizing Facebook engagement (3-8 strategies)",
|
||||
"minItems": 3,
|
||||
"maxItems": 8
|
||||
},
|
||||
"content_quality_optimization": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Strategies for optimizing content quality on Facebook (3-8 strategies)",
|
||||
"minItems": 3,
|
||||
"maxItems": 8
|
||||
},
|
||||
"timing_optimization": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Strategies for optimizing posting timing on Facebook (3-8 strategies)",
|
||||
"minItems": 3,
|
||||
"maxItems": 8
|
||||
},
|
||||
"audience_targeting_optimization": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Strategies for optimizing audience targeting on Facebook (3-8 strategies)",
|
||||
"minItems": 3,
|
||||
"maxItems": 8
|
||||
}
|
||||
}
|
||||
},
|
||||
"facebook_engagement_strategies": {
|
||||
"type": "object",
|
||||
"description": "Facebook-specific engagement strategies",
|
||||
"properties": {
|
||||
"community_building": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Community building strategies for Facebook"
|
||||
},
|
||||
"content_engagement": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Content engagement strategies for Facebook"
|
||||
},
|
||||
"conversion_optimization": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Conversion optimization strategies for Facebook"
|
||||
}
|
||||
}
|
||||
},
|
||||
"facebook_content_formats": {
|
||||
"type": "object",
|
||||
"description": "Facebook content format optimizations",
|
||||
"properties": {
|
||||
"text_posts": {
|
||||
"type": "object",
|
||||
"description": "Text post optimization for Facebook"
|
||||
},
|
||||
"image_posts": {
|
||||
"type": "object",
|
||||
"description": "Image post optimization for Facebook"
|
||||
},
|
||||
"video_posts": {
|
||||
"type": "object",
|
||||
"description": "Video post optimization for Facebook"
|
||||
},
|
||||
"carousel_posts": {
|
||||
"type": "object",
|
||||
"description": "Carousel post optimization for Facebook"
|
||||
}
|
||||
}
|
||||
},
|
||||
"facebook_audience_targeting": {
|
||||
"type": "object",
|
||||
"description": "Facebook audience targeting strategies",
|
||||
"properties": {
|
||||
"demographic_targeting": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Demographic targeting strategies for Facebook"
|
||||
},
|
||||
"interest_targeting": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Interest targeting strategies for Facebook"
|
||||
},
|
||||
"behavioral_targeting": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Behavioral targeting strategies for Facebook"
|
||||
}
|
||||
}
|
||||
},
|
||||
"facebook_community_building": {
|
||||
"type": "object",
|
||||
"description": "Facebook community building strategies",
|
||||
"properties": {
|
||||
"group_management": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Facebook Group management strategies"
|
||||
},
|
||||
"event_management": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Facebook Event management strategies"
|
||||
},
|
||||
"live_streaming": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"},
|
||||
"description": "Facebook Live streaming strategies"
|
||||
}
|
||||
}
|
||||
},
|
||||
"confidence_score": {
|
||||
"type": "number",
|
||||
"description": "Confidence score for the Facebook persona (0-100)",
|
||||
"minimum": 0,
|
||||
"maximum": 100
|
||||
}
|
||||
},
|
||||
"required": [
|
||||
"persona_name",
|
||||
"archetype",
|
||||
"core_belief",
|
||||
"facebook_algorithm_optimization",
|
||||
"facebook_engagement_strategies",
|
||||
"confidence_score"
|
||||
],
|
||||
"additionalProperties": False
|
||||
}
|
||||
10
backend/services/persona/linkedin/__init__.py
Normal file
10
backend/services/persona/linkedin/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
LinkedIn Persona Services
|
||||
Contains LinkedIn-specific persona generation and optimization services.
|
||||
"""
|
||||
|
||||
from .linkedin_persona_service import LinkedInPersonaService
|
||||
from .linkedin_persona_prompts import LinkedInPersonaPrompts
|
||||
from .linkedin_persona_schemas import LinkedInPersonaSchemas
|
||||
|
||||
__all__ = ['LinkedInPersonaService', 'LinkedInPersonaPrompts', 'LinkedInPersonaSchemas']
|
||||
319
backend/services/persona/linkedin/linkedin_persona_prompts.py
Normal file
319
backend/services/persona/linkedin/linkedin_persona_prompts.py
Normal file
@@ -0,0 +1,319 @@
|
||||
"""
|
||||
LinkedIn Persona Prompts
|
||||
Contains LinkedIn-specific prompt generation for persona analysis.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
import json
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class LinkedInPersonaPrompts:
|
||||
"""Handles LinkedIn-specific persona prompt generation."""
|
||||
|
||||
@staticmethod
|
||||
def build_enhanced_linkedin_prompt(core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> str:
|
||||
"""Build enhanced LinkedIn-specific persona prompt with professional optimization."""
|
||||
|
||||
# Extract comprehensive professional context
|
||||
professional_context = LinkedInPersonaPrompts._extract_professional_context(onboarding_data)
|
||||
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
target_audience = website_analysis.get("target_audience", {})
|
||||
industry_focus = professional_context.get("industry_focus", "general")
|
||||
expertise_level = professional_context.get("expertise_level", "intermediate")
|
||||
|
||||
prompt = f"""
|
||||
LINKEDIN PROFESSIONAL PERSONA OPTIMIZATION TASK: Create a comprehensive LinkedIn-optimized writing persona for professional networking and thought leadership.
|
||||
|
||||
CORE PERSONA FOUNDATION:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
PROFESSIONAL CONTEXT:
|
||||
- Industry: {industry_focus}
|
||||
- Expertise Level: {expertise_level}
|
||||
- Company Size: {professional_context.get('company_size', 'Not specified')}
|
||||
- Business Model: {professional_context.get('business_model', 'Not specified')}
|
||||
- Professional Role: {professional_context.get('professional_role', 'Not specified')}
|
||||
- Demographics: {professional_context.get('target_demographics', [])}
|
||||
- Psychographic: {professional_context.get('psychographic_profile', 'Not specified')}
|
||||
|
||||
LINKEDIN PLATFORM SPECIFICATIONS:
|
||||
- Character Limit: 3,000 characters
|
||||
- Optimal Post Length: 150-300 words for maximum engagement
|
||||
- Professional Network: B2B focused, career-oriented audience
|
||||
- Algorithm Priority: Engagement, relevance, professional value
|
||||
- Content Types: Posts, Articles, Polls, Videos, Carousels, Events
|
||||
- Hashtag Limit: 3-5 hashtags for optimal reach
|
||||
- Link Strategy: Place external links in first comment for algorithm optimization
|
||||
|
||||
LINKEDIN PROFESSIONAL OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. PROFESSIONAL TONE & VOICE:
|
||||
- Maintain authoritative yet approachable professional tone
|
||||
- Use industry-specific terminology appropriately
|
||||
- Balance expertise with accessibility for {expertise_level} audience
|
||||
- Incorporate thought leadership elements
|
||||
- Include professional storytelling and case studies
|
||||
|
||||
2. CONTENT STRATEGY FOR {industry_focus.upper()}:
|
||||
- Industry insights for {expertise_level} professionals
|
||||
- Professional development content for {professional_context.get('target_demographics', [])}
|
||||
- Business strategy discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking focus for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership positioning as {professional_context.get('professional_role', 'professional')}
|
||||
|
||||
3. ENGAGEMENT OPTIMIZATION:
|
||||
- Professional question frameworks for discussion
|
||||
- Industry-relevant polling strategies
|
||||
- Professional networking call-to-actions
|
||||
- Thought leadership positioning
|
||||
- Community building through professional value
|
||||
|
||||
4. LINKEDIN-SPECIFIC FEATURES:
|
||||
- Native video optimization for professional content
|
||||
- LinkedIn Articles for long-form thought leadership
|
||||
- LinkedIn Polls for industry insights and engagement
|
||||
- LinkedIn Events for professional networking
|
||||
- LinkedIn Carousels for educational content
|
||||
- LinkedIn Live for professional discussions
|
||||
|
||||
5. PROFESSIONAL NETWORKING ELEMENTS:
|
||||
- Industry-specific hashtag strategy
|
||||
- Professional mention and tagging etiquette
|
||||
- Thought leadership positioning
|
||||
- Professional relationship building
|
||||
- Career advancement focus
|
||||
|
||||
6. CONTENT FORMAT OPTIMIZATION:
|
||||
- Hook strategies for professional feed
|
||||
- "See More" optimization for longer posts
|
||||
- Professional call-to-action frameworks
|
||||
- Industry-specific content structures
|
||||
- Professional storytelling techniques
|
||||
|
||||
7. LINKEDIN ALGORITHM OPTIMIZATION:
|
||||
- Professional engagement patterns
|
||||
- Industry-relevant content timing
|
||||
- Professional network interaction strategies
|
||||
- Thought leadership content performance
|
||||
- Professional community building
|
||||
|
||||
8. INDUSTRY-SPECIFIC ADAPTATIONS FOR {industry_focus.upper()}:
|
||||
- Terminology appropriate for {expertise_level} level
|
||||
- Professional development for {professional_context.get('target_demographics', [])}
|
||||
- Trend discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking strategies for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership as {professional_context.get('professional_role', 'professional')}
|
||||
- Content addressing {professional_context.get('psychographic_profile', 'professional needs')}
|
||||
- Business insights for {professional_context.get('conversion_focus', 'business growth')}
|
||||
|
||||
PROFESSIONAL EXCELLENCE STANDARDS:
|
||||
- Maintain high professional standards
|
||||
- Focus on value-driven content
|
||||
- Emphasize thought leadership and expertise
|
||||
- Build professional credibility and authority
|
||||
- Foster meaningful professional relationships
|
||||
- Provide actionable business insights
|
||||
- Support professional development and growth
|
||||
|
||||
Generate a comprehensive LinkedIn-optimized persona that positions the user as a thought leader in {industry_focus} while maintaining professional excellence and maximizing LinkedIn's professional networking potential.
|
||||
"""
|
||||
|
||||
return prompt
|
||||
|
||||
@staticmethod
|
||||
def get_linkedin_platform_constraints() -> Dict[str, Any]:
|
||||
"""Get LinkedIn-specific platform constraints and best practices."""
|
||||
return {
|
||||
"character_limit": 3000,
|
||||
"optimal_length": "150-300 words",
|
||||
"professional_tone": True,
|
||||
"hashtag_limit": 5,
|
||||
"rich_media": True,
|
||||
"long_form": True,
|
||||
"thought_leadership": True,
|
||||
"networking_focus": True,
|
||||
"career_development": True,
|
||||
"industry_insights": True,
|
||||
"professional_storytelling": True,
|
||||
"b2b_optimized": True,
|
||||
"algorithm_engagement": True,
|
||||
"native_video": True,
|
||||
"linkedin_articles": True,
|
||||
"linkedin_polls": True,
|
||||
"linkedin_events": True,
|
||||
"linkedin_carousels": True,
|
||||
"linkedin_live": True
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _extract_professional_context(onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Extract comprehensive professional context from onboarding data."""
|
||||
|
||||
professional_context = {
|
||||
"industry_focus": "general",
|
||||
"expertise_level": "intermediate",
|
||||
"company_size": "Not specified",
|
||||
"business_model": "Not specified",
|
||||
"professional_role": "Not specified",
|
||||
"geographic_focus": "global",
|
||||
"target_demographics": [],
|
||||
"psychographic_profile": "",
|
||||
"content_purpose": "",
|
||||
"conversion_focus": "",
|
||||
"research_depth": "",
|
||||
"content_types": []
|
||||
}
|
||||
|
||||
# Extract from website analysis
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
|
||||
# Target audience information
|
||||
target_audience = website_analysis.get("target_audience", {})
|
||||
if target_audience:
|
||||
professional_context["industry_focus"] = target_audience.get("industry_focus", "general")
|
||||
professional_context["expertise_level"] = target_audience.get("expertise_level", "intermediate")
|
||||
professional_context["geographic_focus"] = target_audience.get("geographic_focus", "global")
|
||||
professional_context["target_demographics"] = target_audience.get("demographics", [])
|
||||
professional_context["psychographic_profile"] = target_audience.get("psychographic_profile", "")
|
||||
|
||||
# Content type and business context
|
||||
content_type = website_analysis.get("content_type", {})
|
||||
if content_type:
|
||||
professional_context["content_purpose"] = content_type.get("purpose", "")
|
||||
professional_context["conversion_focus"] = content_type.get("conversion_focus", "")
|
||||
|
||||
# Company and business information from crawl results
|
||||
crawl_result = website_analysis.get("crawl_result", {})
|
||||
if crawl_result:
|
||||
domain_info = crawl_result.get("domain_info", {})
|
||||
if domain_info:
|
||||
professional_context["company_size"] = domain_info.get("company_size", "Not specified")
|
||||
professional_context["business_model"] = domain_info.get("business_model", "Not specified")
|
||||
|
||||
brand_info = crawl_result.get("brand_info", {})
|
||||
if brand_info:
|
||||
professional_context["professional_role"] = brand_info.get("professional_role", "Not specified")
|
||||
|
||||
# Research preferences
|
||||
research_prefs = onboarding_data.get("research_preferences", {})
|
||||
if research_prefs:
|
||||
professional_context["research_depth"] = research_prefs.get("research_depth", "")
|
||||
professional_context["content_types"] = research_prefs.get("content_types", [])
|
||||
|
||||
# Enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
if enhanced_analysis:
|
||||
audience_intel = enhanced_analysis.get("audience_intelligence", {})
|
||||
if audience_intel:
|
||||
# Override with more detailed information if available
|
||||
if audience_intel.get("industry_focus"):
|
||||
professional_context["industry_focus"] = audience_intel["industry_focus"]
|
||||
if audience_intel.get("expertise_level"):
|
||||
professional_context["expertise_level"] = audience_intel["expertise_level"]
|
||||
if audience_intel.get("psychographic_profile"):
|
||||
professional_context["psychographic_profile"] = audience_intel["psychographic_profile"]
|
||||
|
||||
brand_voice = enhanced_analysis.get("brand_voice_analysis", {})
|
||||
if brand_voice:
|
||||
if brand_voice.get("primary_content_type"):
|
||||
professional_context["content_purpose"] = brand_voice["primary_content_type"]
|
||||
if brand_voice.get("conversion_focus"):
|
||||
professional_context["conversion_focus"] = brand_voice["conversion_focus"]
|
||||
|
||||
return professional_context
|
||||
|
||||
@staticmethod
|
||||
def build_linkedin_system_prompt(core_persona: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build system prompt with core persona for LinkedIn generation.
|
||||
This moves the core persona to system prompt to free up context window.
|
||||
"""
|
||||
import json
|
||||
|
||||
return f"""You are an expert LinkedIn content strategist and professional networking specialist.
|
||||
|
||||
CORE PERSONA FOUNDATION:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
Your task is to create LinkedIn-optimized persona adaptations that maintain the core persona's identity while optimizing for professional networking, thought leadership, and B2B engagement on LinkedIn.
|
||||
|
||||
Focus on:
|
||||
- Professional tone and authority
|
||||
- Industry-specific optimization
|
||||
- LinkedIn algorithm best practices
|
||||
- B2B engagement strategies
|
||||
- Professional networking optimization"""
|
||||
|
||||
@staticmethod
|
||||
def build_focused_linkedin_prompt(onboarding_data: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build focused LinkedIn prompt without core persona JSON to optimize context usage.
|
||||
"""
|
||||
# Extract professional context
|
||||
professional_context = LinkedInPersonaPrompts._extract_professional_context(onboarding_data)
|
||||
|
||||
industry_focus = professional_context.get("industry_focus", "general")
|
||||
expertise_level = professional_context.get("expertise_level", "intermediate")
|
||||
|
||||
return f"""LINKEDIN PROFESSIONAL OPTIMIZATION TASK: Create LinkedIn-specific adaptations for the core persona.
|
||||
|
||||
PROFESSIONAL CONTEXT:
|
||||
- Industry: {industry_focus}
|
||||
- Expertise Level: {expertise_level}
|
||||
- Company Size: {professional_context.get('company_size', 'Not specified')}
|
||||
- Business Model: {professional_context.get('business_model', 'Not specified')}
|
||||
- Professional Role: {professional_context.get('professional_role', 'Not specified')}
|
||||
- Demographics: {professional_context.get('target_demographics', [])}
|
||||
- Psychographic: {professional_context.get('psychographic_profile', 'Not specified')}
|
||||
|
||||
LINKEDIN PLATFORM SPECIFICATIONS:
|
||||
- Character Limit: 3,000 characters
|
||||
- Optimal Post Length: 150-300 words for maximum engagement
|
||||
- Professional Network: B2B focused, career-oriented audience
|
||||
- Algorithm Priority: Engagement, relevance, professional value
|
||||
- Content Types: Posts, Articles, Polls, Videos, Carousels, Events
|
||||
- Hashtag Limit: 3-5 hashtags for optimal reach
|
||||
- Link Strategy: Place external links in first comment for algorithm optimization
|
||||
|
||||
LINKEDIN OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. PROFESSIONAL TONE & VOICE:
|
||||
- Maintain authoritative yet approachable professional tone
|
||||
- Use industry-specific terminology appropriately
|
||||
- Balance expertise with accessibility for {expertise_level} audience
|
||||
- Incorporate thought leadership elements
|
||||
- Include professional storytelling and case studies
|
||||
|
||||
2. CONTENT STRATEGY FOR {industry_focus.upper()}:
|
||||
- Industry insights for {expertise_level} professionals
|
||||
- Professional development content for {professional_context.get('target_demographics', [])}
|
||||
- Business strategy discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking focus for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership positioning as {professional_context.get('professional_role', 'professional')}
|
||||
|
||||
3. LINKEDIN-SPECIFIC ADAPTATIONS:
|
||||
- Optimize sentence structure for professional readability
|
||||
- Create platform-specific vocabulary and terminology
|
||||
- Define engagement patterns for B2B audience
|
||||
- Establish professional networking strategies
|
||||
- Include LinkedIn feature optimization (Articles, Polls, Events, etc.)
|
||||
|
||||
4. ALGORITHM OPTIMIZATION:
|
||||
- Engagement patterns for professional audience
|
||||
- Content timing for maximum reach
|
||||
- Professional value metrics
|
||||
- Network interaction strategies
|
||||
|
||||
5. PROFESSIONAL CONTEXT OPTIMIZATION:
|
||||
- Industry-specific positioning
|
||||
- Expertise level adaptation
|
||||
- Company size considerations
|
||||
- Business model alignment
|
||||
- Professional role authority
|
||||
- Demographic targeting
|
||||
- Psychographic engagement
|
||||
- Conversion optimization
|
||||
|
||||
Generate a comprehensive LinkedIn-optimized persona that maintains the core persona's identity while maximizing professional networking and thought leadership potential on LinkedIn."""
|
||||
115
backend/services/persona/linkedin/linkedin_persona_schemas.py
Normal file
115
backend/services/persona/linkedin/linkedin_persona_schemas.py
Normal file
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
LinkedIn Persona Schemas
|
||||
Contains LinkedIn-specific JSON schemas for persona generation.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class LinkedInPersonaSchemas:
|
||||
"""Handles LinkedIn-specific persona schema definitions."""
|
||||
|
||||
@staticmethod
|
||||
def get_linkedin_platform_schema() -> Dict[str, Any]:
|
||||
"""Get LinkedIn-specific platform persona schema."""
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_type": {"type": "string"},
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_sentence_length": {"type": "number"},
|
||||
"optimal_sentence_length": {"type": "number"},
|
||||
"sentence_variety": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_adaptations": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_specific_words": {"type": "array", "items": {"type": "string"}},
|
||||
"hashtag_strategy": {"type": "string"},
|
||||
"emoji_usage": {"type": "string"},
|
||||
"mention_strategy": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"content_format_rules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"character_limit": {"type": "number"},
|
||||
"paragraph_structure": {"type": "string"},
|
||||
"call_to_action_style": {"type": "string"},
|
||||
"link_placement": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"engagement_patterns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"posting_frequency": {"type": "string"},
|
||||
"optimal_posting_times": {"type": "array", "items": {"type": "string"}},
|
||||
"engagement_tactics": {"type": "array", "items": {"type": "string"}},
|
||||
"community_interaction": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"platform_best_practices": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"required": ["platform_type", "sentence_metrics", "content_format_rules", "engagement_patterns"]
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_enhanced_linkedin_schema() -> Dict[str, Any]:
|
||||
"""Get enhanced LinkedIn schema with additional professional fields."""
|
||||
base_schema = LinkedInPersonaSchemas.get_linkedin_platform_schema()
|
||||
|
||||
# Add LinkedIn-specific professional fields
|
||||
base_schema["properties"]["professional_networking"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"thought_leadership_positioning": {"type": "string"},
|
||||
"industry_authority_building": {"type": "string"},
|
||||
"professional_relationship_strategies": {"type": "array", "items": {"type": "string"}},
|
||||
"career_advancement_focus": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
base_schema["properties"]["linkedin_features"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"articles_strategy": {"type": "string"},
|
||||
"polls_optimization": {"type": "string"},
|
||||
"events_networking": {"type": "string"},
|
||||
"carousels_education": {"type": "string"},
|
||||
"live_discussions": {"type": "string"},
|
||||
"native_video": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
base_schema["properties"]["algorithm_optimization"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"engagement_patterns": {"type": "array", "items": {"type": "string"}},
|
||||
"content_timing": {"type": "array", "items": {"type": "string"}},
|
||||
"professional_value_metrics": {"type": "array", "items": {"type": "string"}},
|
||||
"network_interaction_strategies": {"type": "array", "items": {"type": "string"}}
|
||||
}
|
||||
}
|
||||
|
||||
# Add professional context optimization
|
||||
base_schema["properties"]["professional_context_optimization"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"industry_specific_positioning": {"type": "string"},
|
||||
"expertise_level_adaptation": {"type": "string"},
|
||||
"company_size_considerations": {"type": "string"},
|
||||
"business_model_alignment": {"type": "string"},
|
||||
"professional_role_authority": {"type": "string"},
|
||||
"demographic_targeting": {"type": "array", "items": {"type": "string"}},
|
||||
"psychographic_engagement": {"type": "string"},
|
||||
"conversion_optimization": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
return base_schema
|
||||
539
backend/services/persona/linkedin/linkedin_persona_service.py
Normal file
539
backend/services/persona/linkedin/linkedin_persona_service.py
Normal file
@@ -0,0 +1,539 @@
|
||||
"""
|
||||
LinkedIn Persona Service
|
||||
Handles LinkedIn-specific persona generation and optimization.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any, Optional
|
||||
from loguru import logger
|
||||
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
from .linkedin_persona_prompts import LinkedInPersonaPrompts
|
||||
from .linkedin_persona_schemas import LinkedInPersonaSchemas
|
||||
|
||||
|
||||
class LinkedInPersonaService:
|
||||
"""Service for generating LinkedIn-specific persona adaptations."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the LinkedIn persona service."""
|
||||
self.prompts = LinkedInPersonaPrompts()
|
||||
self.schemas = LinkedInPersonaSchemas()
|
||||
logger.info("LinkedInPersonaService initialized")
|
||||
|
||||
def generate_linkedin_persona(self, core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Generate LinkedIn-specific persona adaptation using optimized chained prompts.
|
||||
|
||||
Args:
|
||||
core_persona: The core writing persona
|
||||
onboarding_data: User's onboarding data
|
||||
|
||||
Returns:
|
||||
LinkedIn-optimized persona data
|
||||
"""
|
||||
try:
|
||||
logger.info("Generating LinkedIn-specific persona with optimized prompts")
|
||||
|
||||
# Build focused LinkedIn prompt (without core persona JSON)
|
||||
prompt = self.prompts.build_focused_linkedin_prompt(onboarding_data)
|
||||
|
||||
# Create system prompt with core persona
|
||||
system_prompt = self.prompts.build_linkedin_system_prompt(core_persona)
|
||||
|
||||
# Get LinkedIn-specific schema
|
||||
schema = self.schemas.get_enhanced_linkedin_schema()
|
||||
|
||||
# Generate structured response using Gemini with optimized prompts
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=schema,
|
||||
temperature=0.2,
|
||||
max_tokens=4096,
|
||||
system_prompt=system_prompt
|
||||
)
|
||||
|
||||
if "error" in response:
|
||||
logger.error(f"LinkedIn persona generation failed: {response['error']}")
|
||||
return {"error": f"LinkedIn persona generation failed: {response['error']}"}
|
||||
|
||||
# Validate the generated persona
|
||||
validation_results = self.validate_linkedin_persona(response)
|
||||
logger.info(f"LinkedIn persona validation: Quality Score: {validation_results['quality_score']:.1f}%, Valid: {validation_results['is_valid']}")
|
||||
|
||||
# Add validation results to persona data
|
||||
response["validation_results"] = validation_results
|
||||
|
||||
# Apply comprehensive algorithm optimization
|
||||
optimized_response = self.optimize_for_linkedin_algorithm(response)
|
||||
logger.info("✅ LinkedIn persona algorithm optimization applied")
|
||||
|
||||
logger.info("✅ LinkedIn persona generated and optimized successfully")
|
||||
return optimized_response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating LinkedIn persona: {str(e)}")
|
||||
return {"error": f"Failed to generate LinkedIn persona: {str(e)}"}
|
||||
|
||||
def get_linkedin_constraints(self) -> Dict[str, Any]:
|
||||
"""Get LinkedIn platform constraints."""
|
||||
return self.prompts.get_linkedin_platform_constraints()
|
||||
|
||||
def validate_linkedin_persona(self, persona_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Comprehensive validation of LinkedIn persona data for completeness and quality.
|
||||
|
||||
Args:
|
||||
persona_data: LinkedIn persona data to validate
|
||||
|
||||
Returns:
|
||||
Detailed validation results with quality metrics and recommendations
|
||||
"""
|
||||
try:
|
||||
validation_results = {
|
||||
"is_valid": True,
|
||||
"quality_score": 0.0,
|
||||
"completeness_score": 0.0,
|
||||
"professional_context_score": 0.0,
|
||||
"linkedin_optimization_score": 0.0,
|
||||
"missing_fields": [],
|
||||
"incomplete_fields": [],
|
||||
"recommendations": [],
|
||||
"quality_issues": [],
|
||||
"strengths": [],
|
||||
"validation_details": {}
|
||||
}
|
||||
|
||||
# 1. CORE FIELDS VALIDATION (30% of score)
|
||||
core_fields_score = self._validate_core_fields(persona_data, validation_results)
|
||||
|
||||
# 2. LINKEDIN-SPECIFIC FIELDS VALIDATION (40% of score)
|
||||
linkedin_fields_score = self._validate_linkedin_specific_fields(persona_data, validation_results)
|
||||
|
||||
# 3. PROFESSIONAL CONTEXT VALIDATION (20% of score)
|
||||
professional_context_score = self._validate_professional_context(persona_data, validation_results)
|
||||
|
||||
# 4. CONTENT QUALITY VALIDATION (10% of score)
|
||||
content_quality_score = self._validate_content_quality(persona_data, validation_results)
|
||||
|
||||
# Calculate overall quality score
|
||||
validation_results["quality_score"] = (
|
||||
core_fields_score * 0.3 +
|
||||
linkedin_fields_score * 0.4 +
|
||||
professional_context_score * 0.2 +
|
||||
content_quality_score * 0.1
|
||||
)
|
||||
|
||||
# Set completeness score
|
||||
validation_results["completeness_score"] = core_fields_score
|
||||
validation_results["professional_context_score"] = professional_context_score
|
||||
validation_results["linkedin_optimization_score"] = linkedin_fields_score
|
||||
|
||||
# Determine if persona is valid
|
||||
validation_results["is_valid"] = (
|
||||
validation_results["quality_score"] >= 70.0 and
|
||||
len(validation_results["missing_fields"]) == 0
|
||||
)
|
||||
|
||||
# Add quality assessment
|
||||
self._assess_persona_quality(validation_results)
|
||||
|
||||
return validation_results
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error validating LinkedIn persona: {str(e)}")
|
||||
return {
|
||||
"is_valid": False,
|
||||
"quality_score": 0.0,
|
||||
"error": str(e)
|
||||
}
|
||||
|
||||
def _validate_core_fields(self, persona_data: Dict[str, Any], validation_results: Dict[str, Any]) -> float:
|
||||
"""Validate core LinkedIn persona fields."""
|
||||
core_fields = {
|
||||
"platform_type": {"required": True, "type": str},
|
||||
"sentence_metrics": {"required": True, "type": dict, "subfields": ["max_sentence_length", "optimal_sentence_length"]},
|
||||
"lexical_adaptations": {"required": True, "type": dict, "subfields": ["platform_specific_words", "hashtag_strategy"]},
|
||||
"content_format_rules": {"required": True, "type": dict, "subfields": ["character_limit", "paragraph_structure"]},
|
||||
"engagement_patterns": {"required": True, "type": dict, "subfields": ["posting_frequency", "optimal_posting_times"]},
|
||||
"platform_best_practices": {"required": True, "type": list}
|
||||
}
|
||||
|
||||
score = 0.0
|
||||
total_fields = len(core_fields)
|
||||
|
||||
for field, config in core_fields.items():
|
||||
if field not in persona_data:
|
||||
validation_results["missing_fields"].append(field)
|
||||
continue
|
||||
|
||||
field_data = persona_data[field]
|
||||
field_score = 0.0
|
||||
|
||||
# Check field type
|
||||
if isinstance(field_data, config["type"]):
|
||||
field_score += 0.5
|
||||
else:
|
||||
validation_results["quality_issues"].append(f"{field} has incorrect type: expected {config['type'].__name__}")
|
||||
|
||||
# Check subfields if specified
|
||||
if "subfields" in config and isinstance(field_data, dict):
|
||||
subfield_score = 0.0
|
||||
for subfield in config["subfields"]:
|
||||
if subfield in field_data and field_data[subfield]:
|
||||
subfield_score += 1.0
|
||||
else:
|
||||
validation_results["incomplete_fields"].append(f"{field}.{subfield}")
|
||||
|
||||
if config["subfields"]:
|
||||
field_score += (subfield_score / len(config["subfields"])) * 0.5
|
||||
|
||||
score += field_score
|
||||
validation_results["validation_details"][field] = {
|
||||
"present": True,
|
||||
"type_correct": isinstance(field_data, config["type"]),
|
||||
"completeness": field_score
|
||||
}
|
||||
|
||||
return (score / total_fields) * 100
|
||||
|
||||
def _validate_linkedin_specific_fields(self, persona_data: Dict[str, Any], validation_results: Dict[str, Any]) -> float:
|
||||
"""Validate LinkedIn-specific optimization fields."""
|
||||
linkedin_fields = {
|
||||
"professional_networking": {
|
||||
"required": True,
|
||||
"subfields": ["thought_leadership_positioning", "industry_authority_building", "professional_relationship_strategies"]
|
||||
},
|
||||
"linkedin_features": {
|
||||
"required": True,
|
||||
"subfields": ["articles_strategy", "polls_optimization", "events_networking", "carousels_education"]
|
||||
},
|
||||
"algorithm_optimization": {
|
||||
"required": True,
|
||||
"subfields": ["engagement_patterns", "content_timing", "professional_value_metrics"]
|
||||
},
|
||||
"professional_context_optimization": {
|
||||
"required": True,
|
||||
"subfields": ["industry_specific_positioning", "expertise_level_adaptation", "demographic_targeting"]
|
||||
}
|
||||
}
|
||||
|
||||
score = 0.0
|
||||
total_fields = len(linkedin_fields)
|
||||
|
||||
for field, config in linkedin_fields.items():
|
||||
if field not in persona_data:
|
||||
validation_results["missing_fields"].append(field)
|
||||
validation_results["recommendations"].append(f"Add {field} for enhanced LinkedIn optimization")
|
||||
continue
|
||||
|
||||
field_data = persona_data[field]
|
||||
if not isinstance(field_data, dict):
|
||||
validation_results["quality_issues"].append(f"{field} should be a dictionary")
|
||||
continue
|
||||
|
||||
field_score = 0.0
|
||||
for subfield in config["subfields"]:
|
||||
if subfield in field_data and field_data[subfield]:
|
||||
field_score += 1.0
|
||||
else:
|
||||
validation_results["incomplete_fields"].append(f"{field}.{subfield}")
|
||||
|
||||
field_score = (field_score / len(config["subfields"])) * 100
|
||||
score += field_score
|
||||
|
||||
validation_results["validation_details"][field] = {
|
||||
"present": True,
|
||||
"completeness": field_score,
|
||||
"subfields_present": len([sf for sf in config["subfields"] if sf in field_data and field_data[sf]])
|
||||
}
|
||||
|
||||
return score / total_fields
|
||||
|
||||
def _validate_professional_context(self, persona_data: Dict[str, Any], validation_results: Dict[str, Any]) -> float:
|
||||
"""Validate professional context optimization."""
|
||||
if "professional_context_optimization" not in persona_data:
|
||||
validation_results["missing_fields"].append("professional_context_optimization")
|
||||
return 0.0
|
||||
|
||||
context_data = persona_data["professional_context_optimization"]
|
||||
if not isinstance(context_data, dict):
|
||||
validation_results["quality_issues"].append("professional_context_optimization should be a dictionary")
|
||||
return 0.0
|
||||
|
||||
professional_fields = [
|
||||
"industry_specific_positioning",
|
||||
"expertise_level_adaptation",
|
||||
"company_size_considerations",
|
||||
"business_model_alignment",
|
||||
"professional_role_authority",
|
||||
"demographic_targeting",
|
||||
"psychographic_engagement",
|
||||
"conversion_optimization"
|
||||
]
|
||||
|
||||
score = 0.0
|
||||
for field in professional_fields:
|
||||
if field in context_data and context_data[field]:
|
||||
score += 1.0
|
||||
# Check for meaningful content (not just placeholder text)
|
||||
if isinstance(context_data[field], str) and len(context_data[field]) > 50:
|
||||
score += 0.5
|
||||
else:
|
||||
validation_results["incomplete_fields"].append(f"professional_context_optimization.{field}")
|
||||
|
||||
return (score / len(professional_fields)) * 100
|
||||
|
||||
def _validate_content_quality(self, persona_data: Dict[str, Any], validation_results: Dict[str, Any]) -> float:
|
||||
"""Validate content quality and depth."""
|
||||
score = 0.0
|
||||
|
||||
# Check for meaningful content in key fields
|
||||
quality_checks = [
|
||||
("sentence_metrics", "optimal_sentence_length"),
|
||||
("lexical_adaptations", "platform_specific_words"),
|
||||
("professional_networking", "thought_leadership_positioning"),
|
||||
("linkedin_features", "articles_strategy")
|
||||
]
|
||||
|
||||
for field, subfield in quality_checks:
|
||||
if field in persona_data and subfield in persona_data[field]:
|
||||
content = persona_data[field][subfield]
|
||||
if isinstance(content, str) and len(content) > 30:
|
||||
score += 1.0
|
||||
elif isinstance(content, list) and len(content) > 3:
|
||||
score += 1.0
|
||||
else:
|
||||
validation_results["quality_issues"].append(f"{field}.{subfield} content too brief")
|
||||
else:
|
||||
validation_results["quality_issues"].append(f"{field}.{subfield} missing or empty")
|
||||
|
||||
return (score / len(quality_checks)) * 100
|
||||
|
||||
def _assess_persona_quality(self, validation_results: Dict[str, Any]) -> None:
|
||||
"""Assess overall persona quality and provide recommendations."""
|
||||
quality_score = validation_results["quality_score"]
|
||||
|
||||
if quality_score >= 90:
|
||||
validation_results["strengths"].append("Excellent LinkedIn persona with comprehensive optimization")
|
||||
elif quality_score >= 80:
|
||||
validation_results["strengths"].append("Strong LinkedIn persona with good optimization")
|
||||
elif quality_score >= 70:
|
||||
validation_results["strengths"].append("Good LinkedIn persona with basic optimization")
|
||||
else:
|
||||
validation_results["quality_issues"].append("LinkedIn persona needs significant improvement")
|
||||
|
||||
# Add specific recommendations based on missing fields
|
||||
if "professional_context_optimization" in validation_results["missing_fields"]:
|
||||
validation_results["recommendations"].append("Add professional context optimization for industry-specific positioning")
|
||||
|
||||
if "algorithm_optimization" in validation_results["missing_fields"]:
|
||||
validation_results["recommendations"].append("Add algorithm optimization for better LinkedIn reach")
|
||||
|
||||
if validation_results["incomplete_fields"]:
|
||||
validation_results["recommendations"].append(f"Complete {len(validation_results['incomplete_fields'])} incomplete fields for better optimization")
|
||||
|
||||
# Add enterprise-grade recommendations
|
||||
if quality_score >= 80:
|
||||
validation_results["recommendations"].append("Persona is enterprise-ready for professional LinkedIn content")
|
||||
else:
|
||||
validation_results["recommendations"].append("Consider regenerating persona with more comprehensive data")
|
||||
|
||||
def optimize_for_linkedin_algorithm(self, persona_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""
|
||||
Comprehensive LinkedIn algorithm optimization for maximum reach and engagement.
|
||||
|
||||
Args:
|
||||
persona_data: LinkedIn persona data to optimize
|
||||
|
||||
Returns:
|
||||
Algorithm-optimized persona data with advanced optimization features
|
||||
"""
|
||||
try:
|
||||
optimized_persona = persona_data.copy()
|
||||
|
||||
# Initialize algorithm optimization if not present
|
||||
if "algorithm_optimization" not in optimized_persona:
|
||||
optimized_persona["algorithm_optimization"] = {}
|
||||
|
||||
# 1. CONTENT QUALITY OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["content_quality_optimization"] = {
|
||||
"original_insights_priority": [
|
||||
"Share proprietary industry insights and case studies",
|
||||
"Publish data-driven analyses and research findings",
|
||||
"Create thought leadership content with unique perspectives",
|
||||
"Avoid generic or recycled content that lacks value"
|
||||
],
|
||||
"professional_credibility_boost": [
|
||||
"Include relevant credentials and expertise indicators",
|
||||
"Reference industry experience and achievements",
|
||||
"Use professional language and terminology appropriately",
|
||||
"Maintain consistent brand voice and messaging"
|
||||
],
|
||||
"content_depth_requirements": [
|
||||
"Provide actionable insights and practical advice",
|
||||
"Include specific examples and real-world applications",
|
||||
"Offer comprehensive analysis rather than surface-level content",
|
||||
"Create content that solves professional problems"
|
||||
]
|
||||
}
|
||||
|
||||
# 2. MULTIMEDIA FORMAT OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["multimedia_strategy"] = {
|
||||
"native_video_optimization": [
|
||||
"Upload videos directly to LinkedIn for maximum reach",
|
||||
"Keep videos 1-3 minutes for optimal engagement",
|
||||
"Include captions for accessibility and broader reach",
|
||||
"Start with compelling hooks to retain viewers"
|
||||
],
|
||||
"carousel_document_strategy": [
|
||||
"Create swipeable educational content and tutorials",
|
||||
"Use 5-10 slides for optimal engagement",
|
||||
"Include clear, scannable text and visuals",
|
||||
"End with strong call-to-action"
|
||||
],
|
||||
"visual_content_optimization": [
|
||||
"Use high-quality, professional images and graphics",
|
||||
"Create infographics that convey complex information simply",
|
||||
"Design visually appealing quote cards and statistics",
|
||||
"Ensure all visuals align with professional brand"
|
||||
]
|
||||
}
|
||||
|
||||
# 3. ENGAGEMENT OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["engagement_optimization"] = {
|
||||
"comment_encouragement_strategies": [
|
||||
"Ask thought-provoking questions that invite discussion",
|
||||
"Pose industry-specific challenges or scenarios",
|
||||
"Request personal experiences and insights",
|
||||
"Create polls and surveys for interactive engagement"
|
||||
],
|
||||
"network_interaction_boost": [
|
||||
"Respond to comments within 2-4 hours for maximum visibility",
|
||||
"Engage meaningfully with others' content before posting",
|
||||
"Share and comment on industry leaders' posts",
|
||||
"Participate actively in relevant LinkedIn groups"
|
||||
],
|
||||
"professional_relationship_building": [
|
||||
"Tag relevant connections when appropriate",
|
||||
"Mention industry experts and thought leaders",
|
||||
"Collaborate with peers on joint content",
|
||||
"Build genuine professional relationships"
|
||||
]
|
||||
}
|
||||
|
||||
# 4. TIMING AND FREQUENCY OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["timing_optimization"] = {
|
||||
"optimal_posting_schedule": [
|
||||
"Tuesday-Thursday: 8-11 AM EST for maximum professional engagement",
|
||||
"Wednesday: Peak day for B2B content and thought leadership",
|
||||
"Avoid posting on weekends unless targeting specific audiences",
|
||||
"Maintain consistent posting schedule for algorithm recognition"
|
||||
],
|
||||
"frequency_optimization": [
|
||||
"Post 3-5 times per week for consistent visibility",
|
||||
"Balance original content with curated industry insights",
|
||||
"Space posts 4-6 hours apart to avoid audience fatigue",
|
||||
"Monitor engagement rates to adjust frequency"
|
||||
],
|
||||
"timezone_considerations": [
|
||||
"Consider global audience time zones for international reach",
|
||||
"Adjust posting times based on target audience location",
|
||||
"Use LinkedIn Analytics to identify peak engagement times",
|
||||
"Test different time slots to optimize reach"
|
||||
]
|
||||
}
|
||||
|
||||
# 5. HASHTAG AND DISCOVERABILITY OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["discoverability_optimization"] = {
|
||||
"strategic_hashtag_usage": [
|
||||
"Use 3-5 relevant hashtags for optimal reach",
|
||||
"Mix broad industry hashtags with niche-specific tags",
|
||||
"Include trending hashtags when relevant to content",
|
||||
"Create branded hashtags for consistent brand recognition"
|
||||
],
|
||||
"keyword_optimization": [
|
||||
"Include industry-specific keywords naturally in content",
|
||||
"Use professional terminology that resonates with target audience",
|
||||
"Optimize for LinkedIn's search algorithm",
|
||||
"Include location-based keywords for local reach"
|
||||
],
|
||||
"content_categorization": [
|
||||
"Tag content appropriately for LinkedIn's content categorization",
|
||||
"Use consistent themes and topics for algorithm recognition",
|
||||
"Create content series for sustained engagement",
|
||||
"Leverage LinkedIn's content suggestions and trending topics"
|
||||
]
|
||||
}
|
||||
|
||||
# 6. LINKEDIN FEATURES OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["linkedin_features_optimization"] = {
|
||||
"articles_strategy": [
|
||||
"Publish long-form articles for thought leadership positioning",
|
||||
"Use compelling headlines that encourage clicks",
|
||||
"Include relevant images and formatting for readability",
|
||||
"Cross-promote articles in regular posts"
|
||||
],
|
||||
"polls_and_surveys": [
|
||||
"Create engaging polls to drive interaction",
|
||||
"Ask industry-relevant questions that spark discussion",
|
||||
"Use poll results to create follow-up content",
|
||||
"Share poll insights to provide value to audience"
|
||||
],
|
||||
"events_and_networking": [
|
||||
"Host or participate in LinkedIn events and webinars",
|
||||
"Use LinkedIn's event features for promotion and networking",
|
||||
"Create virtual networking opportunities",
|
||||
"Leverage LinkedIn Live for real-time engagement"
|
||||
]
|
||||
}
|
||||
|
||||
# 7. PERFORMANCE MONITORING AND OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["performance_monitoring"] = {
|
||||
"key_metrics_tracking": [
|
||||
"Monitor engagement rate (likes, comments, shares, saves)",
|
||||
"Track reach and impression metrics",
|
||||
"Analyze click-through rates on links and CTAs",
|
||||
"Measure follower growth and network expansion"
|
||||
],
|
||||
"content_performance_analysis": [
|
||||
"Identify top-performing content types and topics",
|
||||
"Analyze posting times for optimal engagement",
|
||||
"Track hashtag performance and reach",
|
||||
"Monitor audience demographics and interests"
|
||||
],
|
||||
"optimization_recommendations": [
|
||||
"A/B test different content formats and styles",
|
||||
"Experiment with posting frequencies and timing",
|
||||
"Test various hashtag combinations and strategies",
|
||||
"Continuously refine content based on performance data"
|
||||
]
|
||||
}
|
||||
|
||||
# 8. PROFESSIONAL CONTEXT OPTIMIZATION
|
||||
optimized_persona["algorithm_optimization"]["professional_context_optimization"] = {
|
||||
"industry_specific_optimization": [
|
||||
"Tailor content to industry-specific trends and challenges",
|
||||
"Use industry terminology and references appropriately",
|
||||
"Address current industry issues and developments",
|
||||
"Position as thought leader within specific industry"
|
||||
],
|
||||
"career_stage_targeting": [
|
||||
"Create content relevant to different career stages",
|
||||
"Address professional development and growth topics",
|
||||
"Share career insights and advancement strategies",
|
||||
"Provide value to both junior and senior professionals"
|
||||
],
|
||||
"company_size_considerations": [
|
||||
"Adapt content for different company sizes and structures",
|
||||
"Address challenges specific to startups, SMBs, and enterprises",
|
||||
"Provide relevant insights for different organizational contexts",
|
||||
"Consider decision-making processes and hierarchies"
|
||||
]
|
||||
}
|
||||
|
||||
logger.info("✅ LinkedIn persona comprehensively optimized for 2024 algorithm performance")
|
||||
return optimized_persona
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error optimizing LinkedIn persona for algorithm: {str(e)}")
|
||||
return persona_data
|
||||
@@ -12,13 +12,19 @@ import json
|
||||
from services.database import get_db_session
|
||||
from models.onboarding import OnboardingSession, WebsiteAnalysis, ResearchPreferences
|
||||
from models.persona_models import WritingPersona, PlatformPersona, PersonaAnalysisResult
|
||||
from services.llm_providers.gemini_provider import gemini_structured_json_response
|
||||
from services.persona.core_persona import CorePersonaService, OnboardingDataCollector
|
||||
from services.persona.linkedin.linkedin_persona_service import LinkedInPersonaService
|
||||
from services.persona.facebook.facebook_persona_service import FacebookPersonaService
|
||||
|
||||
class PersonaAnalysisService:
|
||||
"""Service for analyzing onboarding data and generating writing personas using Gemini AI."""
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the persona analysis service."""
|
||||
self.core_persona_service = CorePersonaService()
|
||||
self.data_collector = OnboardingDataCollector()
|
||||
self.linkedin_service = LinkedInPersonaService()
|
||||
self.facebook_service = FacebookPersonaService()
|
||||
logger.info("PersonaAnalysisService initialized")
|
||||
|
||||
def generate_persona_from_onboarding(self, user_id: int, onboarding_session_id: int = None) -> Dict[str, Any]:
|
||||
@@ -36,20 +42,20 @@ class PersonaAnalysisService:
|
||||
logger.info(f"Generating persona for user {user_id}")
|
||||
|
||||
# Get onboarding data
|
||||
onboarding_data = self._collect_onboarding_data(user_id, onboarding_session_id)
|
||||
onboarding_data = self.data_collector.collect_onboarding_data(user_id, onboarding_session_id)
|
||||
|
||||
if not onboarding_data:
|
||||
logger.warning(f"No onboarding data found for user {user_id}")
|
||||
return {"error": "No onboarding data available for persona generation"}
|
||||
|
||||
# Generate core persona using Gemini
|
||||
core_persona = self._generate_core_persona(onboarding_data)
|
||||
core_persona = self.core_persona_service.generate_core_persona(onboarding_data)
|
||||
|
||||
if "error" in core_persona:
|
||||
return core_persona
|
||||
|
||||
# Generate platform-specific adaptations
|
||||
platform_personas = self._generate_platform_adaptations(core_persona, onboarding_data)
|
||||
platform_personas = self.core_persona_service.generate_platform_adaptations(core_persona, onboarding_data)
|
||||
|
||||
# Save to database
|
||||
saved_persona = self._save_persona_to_db(user_id, core_persona, platform_personas, onboarding_data)
|
||||
@@ -60,7 +66,7 @@ class PersonaAnalysisService:
|
||||
"platform_personas": platform_personas,
|
||||
"analysis_metadata": {
|
||||
"confidence_score": core_persona.get("confidence_score", 0.0),
|
||||
"data_sufficiency": self._calculate_data_sufficiency(onboarding_data),
|
||||
"data_sufficiency": self.data_collector.calculate_data_sufficiency(onboarding_data),
|
||||
"generated_at": datetime.utcnow().isoformat()
|
||||
}
|
||||
}
|
||||
@@ -69,318 +75,114 @@ class PersonaAnalysisService:
|
||||
logger.error(f"Error generating persona for user {user_id}: {str(e)}")
|
||||
return {"error": f"Failed to generate persona: {str(e)}"}
|
||||
|
||||
def _collect_onboarding_data(self, user_id: int, session_id: int = None) -> Optional[Dict[str, Any]]:
|
||||
"""Collect comprehensive onboarding data for persona analysis."""
|
||||
try:
|
||||
session = get_db_session()
|
||||
|
||||
# Find onboarding session
|
||||
if session_id:
|
||||
onboarding_session = session.query(OnboardingSession).filter(
|
||||
OnboardingSession.id == session_id,
|
||||
OnboardingSession.user_id == user_id
|
||||
).first()
|
||||
else:
|
||||
onboarding_session = session.query(OnboardingSession).filter(
|
||||
OnboardingSession.user_id == user_id
|
||||
).order_by(OnboardingSession.updated_at.desc()).first()
|
||||
|
||||
if not onboarding_session:
|
||||
return None
|
||||
|
||||
# Get website analysis
|
||||
website_analysis = session.query(WebsiteAnalysis).filter(
|
||||
WebsiteAnalysis.session_id == onboarding_session.id
|
||||
).first()
|
||||
|
||||
# Get research preferences
|
||||
research_prefs = session.query(ResearchPreferences).filter(
|
||||
ResearchPreferences.session_id == onboarding_session.id
|
||||
).first()
|
||||
|
||||
# Compile comprehensive data
|
||||
onboarding_data = {
|
||||
"session_info": {
|
||||
"session_id": onboarding_session.id,
|
||||
"current_step": onboarding_session.current_step,
|
||||
"progress": onboarding_session.progress,
|
||||
"started_at": onboarding_session.started_at.isoformat() if onboarding_session.started_at else None
|
||||
},
|
||||
"website_analysis": website_analysis.to_dict() if website_analysis else None,
|
||||
"research_preferences": research_prefs.to_dict() if research_prefs else None
|
||||
}
|
||||
|
||||
session.close()
|
||||
return onboarding_data
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error collecting onboarding data: {str(e)}")
|
||||
return None
|
||||
|
||||
def _generate_core_persona(self, onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate core writing persona using Gemini structured response."""
|
||||
|
||||
# Build analysis prompt
|
||||
prompt = self._build_persona_analysis_prompt(onboarding_data)
|
||||
|
||||
# Define schema for structured response
|
||||
persona_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"identity": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"persona_name": {"type": "string"},
|
||||
"archetype": {"type": "string"},
|
||||
"core_belief": {"type": "string"},
|
||||
"brand_voice_description": {"type": "string"}
|
||||
},
|
||||
"required": ["persona_name", "archetype", "core_belief"]
|
||||
},
|
||||
"linguistic_fingerprint": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"average_sentence_length_words": {"type": "number"},
|
||||
"preferred_sentence_type": {"type": "string"},
|
||||
"active_to_passive_ratio": {"type": "string"},
|
||||
"complexity_level": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_features": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"go_to_words": {"type": "array", "items": {"type": "string"}},
|
||||
"go_to_phrases": {"type": "array", "items": {"type": "string"}},
|
||||
"avoid_words": {"type": "array", "items": {"type": "string"}},
|
||||
"contractions": {"type": "string"},
|
||||
"filler_words": {"type": "string"},
|
||||
"vocabulary_level": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"rhetorical_devices": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"metaphors": {"type": "string"},
|
||||
"analogies": {"type": "string"},
|
||||
"rhetorical_questions": {"type": "string"},
|
||||
"storytelling_style": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"tonal_range": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"default_tone": {"type": "string"},
|
||||
"permissible_tones": {"type": "array", "items": {"type": "string"}},
|
||||
"forbidden_tones": {"type": "array", "items": {"type": "string"}},
|
||||
"emotional_range": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"stylistic_constraints": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"punctuation": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"ellipses": {"type": "string"},
|
||||
"em_dash": {"type": "string"},
|
||||
"exclamation_points": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"formatting": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"paragraphs": {"type": "string"},
|
||||
"lists": {"type": "string"},
|
||||
"markdown": {"type": "string"}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"confidence_score": {"type": "number"},
|
||||
"analysis_notes": {"type": "string"}
|
||||
},
|
||||
"required": ["identity", "linguistic_fingerprint", "tonal_range", "confidence_score"]
|
||||
}
|
||||
|
||||
try:
|
||||
# Generate structured response using Gemini
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=persona_schema,
|
||||
temperature=0.2, # Low temperature for consistent analysis
|
||||
max_tokens=8192,
|
||||
system_prompt="You are an expert writing style analyst and persona developer. Analyze the provided data to create a precise, actionable writing persona."
|
||||
)
|
||||
|
||||
if "error" in response:
|
||||
logger.error(f"Gemini API error: {response['error']}")
|
||||
return {"error": f"AI analysis failed: {response['error']}"}
|
||||
|
||||
logger.info("✅ Core persona generated successfully")
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating core persona: {str(e)}")
|
||||
return {"error": f"Failed to generate core persona: {str(e)}"}
|
||||
|
||||
def _generate_platform_adaptations(self, core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate platform-specific persona adaptations."""
|
||||
|
||||
platforms = ["twitter", "linkedin", "instagram", "facebook", "blog", "medium", "substack"]
|
||||
platform_personas = {}
|
||||
|
||||
for platform in platforms:
|
||||
try:
|
||||
platform_persona = self._generate_single_platform_persona(core_persona, platform, onboarding_data)
|
||||
if "error" not in platform_persona:
|
||||
platform_personas[platform] = platform_persona
|
||||
else:
|
||||
logger.warning(f"Failed to generate {platform} persona: {platform_persona['error']}")
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating {platform} persona: {str(e)}")
|
||||
|
||||
return platform_personas
|
||||
|
||||
def _generate_single_platform_persona(self, core_persona: Dict[str, Any], platform: str, onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Generate persona adaptation for a specific platform."""
|
||||
|
||||
prompt = self._build_platform_adaptation_prompt(core_persona, platform, onboarding_data)
|
||||
|
||||
# Platform-specific schema
|
||||
platform_schema = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_type": {"type": "string"},
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_sentence_length": {"type": "number"},
|
||||
"optimal_sentence_length": {"type": "number"},
|
||||
"sentence_variety": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_adaptations": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_specific_words": {"type": "array", "items": {"type": "string"}},
|
||||
"hashtag_strategy": {"type": "string"},
|
||||
"emoji_usage": {"type": "string"},
|
||||
"mention_strategy": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"content_format_rules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"character_limit": {"type": "number"},
|
||||
"paragraph_structure": {"type": "string"},
|
||||
"call_to_action_style": {"type": "string"},
|
||||
"link_placement": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"engagement_patterns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"posting_frequency": {"type": "string"},
|
||||
"optimal_posting_times": {"type": "array", "items": {"type": "string"}},
|
||||
"engagement_tactics": {"type": "array", "items": {"type": "string"}},
|
||||
"community_interaction": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"platform_best_practices": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"required": ["platform_type", "sentence_metrics", "content_format_rules", "engagement_patterns"]
|
||||
}
|
||||
|
||||
try:
|
||||
response = gemini_structured_json_response(
|
||||
prompt=prompt,
|
||||
schema=platform_schema,
|
||||
temperature=0.2,
|
||||
max_tokens=4096,
|
||||
system_prompt=f"You are an expert in {platform} content strategy and platform-specific writing optimization."
|
||||
)
|
||||
|
||||
return response
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error generating {platform} persona: {str(e)}")
|
||||
return {"error": f"Failed to generate {platform} persona: {str(e)}"}
|
||||
|
||||
def _build_persona_analysis_prompt(self, onboarding_data: Dict[str, Any]) -> str:
|
||||
"""Build the main persona analysis prompt."""
|
||||
"""Build the main persona analysis prompt with comprehensive data."""
|
||||
|
||||
# Get enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
research_prefs = onboarding_data.get("research_preferences", {}) or {}
|
||||
|
||||
prompt = f"""
|
||||
PERSONA GENERATION TASK: Create a comprehensive writing persona based on user onboarding data.
|
||||
COMPREHENSIVE PERSONA GENERATION TASK: Create a highly detailed, data-driven writing persona based on extensive AI analysis of user's website and content strategy.
|
||||
|
||||
ONBOARDING DATA ANALYSIS:
|
||||
=== COMPREHENSIVE ONBOARDING DATA ANALYSIS ===
|
||||
|
||||
Website Analysis:
|
||||
WEBSITE ANALYSIS OVERVIEW:
|
||||
- URL: {website_analysis.get('website_url', 'Not provided')}
|
||||
- Writing Style: {json.dumps(website_analysis.get('writing_style', {}), indent=2)}
|
||||
- Content Characteristics: {json.dumps(website_analysis.get('content_characteristics', {}) or {}, indent=2)}
|
||||
- Target Audience: {json.dumps(website_analysis.get('target_audience', {}), indent=2)}
|
||||
- Content Type: {json.dumps(website_analysis.get('content_type', {}), indent=2)}
|
||||
- Style Patterns: {json.dumps(website_analysis.get('style_patterns', {}), indent=2)}
|
||||
- Analysis Date: {website_analysis.get('analysis_date', 'Not provided')}
|
||||
- Status: {website_analysis.get('status', 'Not provided')}
|
||||
|
||||
Research Preferences:
|
||||
- Research Depth: {research_prefs.get('research_depth', 'Not set')}
|
||||
- Content Types: {research_prefs.get('content_types', [])}
|
||||
- Auto Research: {research_prefs.get('auto_research', False)}
|
||||
- Factual Content: {research_prefs.get('factual_content', False)}
|
||||
=== DETAILED STYLE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('comprehensive_style_analysis', {}), indent=2)}
|
||||
|
||||
PERSONA GENERATION REQUIREMENTS:
|
||||
=== CONTENT INSIGHTS ===
|
||||
{json.dumps(enhanced_analysis.get('content_insights', {}), indent=2)}
|
||||
|
||||
1. IDENTITY CREATION:
|
||||
- Create a memorable persona name that captures the essence of the writing style
|
||||
- Define a clear archetype (e.g., "The Pragmatic Futurist", "The Thoughtful Educator")
|
||||
- Articulate a core belief that drives the writing philosophy
|
||||
- Write a comprehensive brand voice description
|
||||
=== AUDIENCE INTELLIGENCE ===
|
||||
{json.dumps(enhanced_analysis.get('audience_intelligence', {}), indent=2)}
|
||||
|
||||
2. LINGUISTIC FINGERPRINT (Quantitative Analysis):
|
||||
- Calculate average sentence length based on website analysis
|
||||
- Determine preferred sentence types (simple, compound, complex)
|
||||
- Analyze active vs passive voice ratio
|
||||
- Identify go-to words and phrases from the content analysis
|
||||
- List words and phrases to avoid
|
||||
- Determine contraction usage patterns
|
||||
- Assess vocabulary complexity level
|
||||
=== BRAND VOICE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('brand_voice_analysis', {}), indent=2)}
|
||||
|
||||
3. RHETORICAL ANALYSIS:
|
||||
- Identify metaphor patterns and themes
|
||||
- Analyze analogy usage
|
||||
- Assess rhetorical question frequency and style
|
||||
- Determine storytelling approach
|
||||
=== TECHNICAL WRITING METRICS ===
|
||||
{json.dumps(enhanced_analysis.get('technical_writing_metrics', {}), indent=2)}
|
||||
|
||||
4. TONAL RANGE:
|
||||
- Define the default tone
|
||||
- List permissible tones for different contexts
|
||||
- Identify forbidden tones that don't match the brand
|
||||
- Describe emotional range and expression
|
||||
=== COMPETITIVE ANALYSIS ===
|
||||
{json.dumps(enhanced_analysis.get('competitive_analysis', {}), indent=2)}
|
||||
|
||||
5. STYLISTIC CONSTRAINTS:
|
||||
- Define punctuation preferences and rules
|
||||
- Set formatting guidelines
|
||||
- Establish paragraph structure preferences
|
||||
=== CONTENT STRATEGY INSIGHTS ===
|
||||
{json.dumps(enhanced_analysis.get('content_strategy_insights', {}), indent=2)}
|
||||
|
||||
ANALYSIS INSTRUCTIONS:
|
||||
- Base your analysis on the actual data provided from the website analysis
|
||||
- If data is limited, make reasonable inferences but note the confidence level
|
||||
- Ensure the persona is actionable and specific enough for AI content generation
|
||||
- Provide a confidence score (0-100) based on data availability and quality
|
||||
- Include analysis notes explaining your reasoning
|
||||
=== RESEARCH PREFERENCES ===
|
||||
{json.dumps(enhanced_analysis.get('research_preferences', {}), indent=2)}
|
||||
|
||||
Generate a comprehensive persona profile that can be used to replicate this writing style across different platforms.
|
||||
=== LEGACY DATA (for compatibility) ===
|
||||
Website Analysis: {json.dumps(website_analysis.get('writing_style', {}), indent=2)}
|
||||
Content Characteristics: {json.dumps(website_analysis.get('content_characteristics', {}) or {}, indent=2)}
|
||||
Target Audience: {json.dumps(website_analysis.get('target_audience', {}), indent=2)}
|
||||
Style Patterns: {json.dumps(website_analysis.get('style_patterns', {}), indent=2)}
|
||||
|
||||
=== COMPREHENSIVE PERSONA GENERATION REQUIREMENTS ===
|
||||
|
||||
1. IDENTITY CREATION (Based on Brand Analysis):
|
||||
- Create a memorable persona name that captures the essence of the brand personality and writing style
|
||||
- Define a clear archetype that reflects the brand's positioning and audience appeal
|
||||
- Articulate a core belief that drives the writing philosophy and brand values
|
||||
- Write a comprehensive brand voice description incorporating all style elements
|
||||
|
||||
2. LINGUISTIC FINGERPRINT (Quantitative Analysis from Technical Metrics):
|
||||
- Calculate precise average sentence length from sentence structure analysis
|
||||
- Determine preferred sentence types based on paragraph organization patterns
|
||||
- Analyze active vs passive voice ratio from voice characteristics
|
||||
- Extract go-to words and phrases from vocabulary patterns and style analysis
|
||||
- List words and phrases to avoid based on brand alignment guidelines
|
||||
- Determine contraction usage patterns from formality level
|
||||
- Assess vocabulary complexity level from readability scores
|
||||
|
||||
3. RHETORICAL ANALYSIS (From Style Patterns):
|
||||
- Identify metaphor patterns and themes from rhetorical devices
|
||||
- Analyze analogy usage from content strategy insights
|
||||
- Assess rhetorical question frequency from engagement tips
|
||||
- Determine storytelling approach from content flow analysis
|
||||
|
||||
4. TONAL RANGE (From Comprehensive Style Analysis):
|
||||
- Define the default tone from tone analysis and brand personality
|
||||
- List permissible tones based on emotional appeal and audience considerations
|
||||
- Identify forbidden tones from avoid elements and brand alignment
|
||||
- Describe emotional range from psychographic profile and engagement level
|
||||
|
||||
5. STYLISTIC CONSTRAINTS (From Technical Writing Metrics):
|
||||
- Define punctuation preferences from paragraph structure analysis
|
||||
- Set formatting guidelines from content structure insights
|
||||
- Establish paragraph structure preferences from organization patterns
|
||||
- Include transition phrase preferences from style patterns
|
||||
|
||||
6. PLATFORM-SPECIFIC ADAPTATIONS (From Content Strategy):
|
||||
- Incorporate SEO optimization strategies
|
||||
- Include conversion optimization techniques
|
||||
- Apply engagement tips for different platforms
|
||||
- Use competitive advantages for differentiation
|
||||
|
||||
7. CONTENT STRATEGY INTEGRATION:
|
||||
- Incorporate best practices from content strategy insights
|
||||
- Include AI generation tips for consistent output
|
||||
- Apply content calendar suggestions for timing
|
||||
- Use competitive advantages for positioning
|
||||
|
||||
=== ENHANCED ANALYSIS INSTRUCTIONS ===
|
||||
- Base your analysis on ALL the comprehensive data provided above
|
||||
- Use the detailed technical metrics for precise linguistic analysis
|
||||
- Incorporate brand voice analysis for authentic personality
|
||||
- Apply audience intelligence for targeted communication
|
||||
- Include competitive analysis for market positioning
|
||||
- Use content strategy insights for practical application
|
||||
- Ensure the persona reflects the brand's unique elements and competitive advantages
|
||||
- Provide a confidence score (0-100) based on data richness and quality
|
||||
- Include detailed analysis notes explaining your reasoning and data sources
|
||||
|
||||
Generate a comprehensive, data-driven persona profile that can be used to replicate this writing style across different platforms while maintaining brand authenticity and competitive positioning.
|
||||
"""
|
||||
|
||||
return prompt
|
||||
@@ -442,6 +244,7 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
|
||||
return prompt
|
||||
|
||||
|
||||
def _get_platform_constraints(self, platform: str) -> Dict[str, Any]:
|
||||
"""Get platform-specific constraints and best practices."""
|
||||
|
||||
@@ -454,14 +257,8 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
"thread_support": True,
|
||||
"link_shortening": True
|
||||
},
|
||||
"linkedin": {
|
||||
"character_limit": 3000,
|
||||
"optimal_length": "150-300 words",
|
||||
"professional_tone": True,
|
||||
"hashtag_limit": 5,
|
||||
"rich_media": True,
|
||||
"long_form": True
|
||||
},
|
||||
"linkedin": self.linkedin_service.get_linkedin_constraints(),
|
||||
"facebook": self.facebook_service.get_facebook_constraints(),
|
||||
"instagram": {
|
||||
"caption_limit": 2200,
|
||||
"optimal_length": "125-150 words",
|
||||
@@ -533,6 +330,24 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
|
||||
# Create platform-specific persona records
|
||||
for platform, platform_data in platform_personas.items():
|
||||
# Prepare platform-specific data
|
||||
platform_specific_data = {}
|
||||
if platform.lower() == "linkedin":
|
||||
platform_specific_data = {
|
||||
"professional_networking": platform_data.get("professional_networking", {}),
|
||||
"linkedin_features": platform_data.get("linkedin_features", {}),
|
||||
"algorithm_optimization": platform_data.get("algorithm_optimization", {}),
|
||||
"professional_context_optimization": platform_data.get("professional_context_optimization", {})
|
||||
}
|
||||
elif platform.lower() == "facebook":
|
||||
platform_specific_data = {
|
||||
"facebook_algorithm_optimization": platform_data.get("facebook_algorithm_optimization", {}),
|
||||
"facebook_engagement_strategies": platform_data.get("facebook_engagement_strategies", {}),
|
||||
"facebook_content_formats": platform_data.get("facebook_content_formats", {}),
|
||||
"facebook_audience_targeting": platform_data.get("facebook_audience_targeting", {}),
|
||||
"facebook_community_building": platform_data.get("facebook_community_building", {})
|
||||
}
|
||||
|
||||
platform_persona = PlatformPersona(
|
||||
writing_persona_id=writing_persona.id,
|
||||
platform_type=platform,
|
||||
@@ -543,7 +358,8 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
stylistic_constraints=core_persona.get("stylistic_constraints", {}),
|
||||
content_format_rules=platform_data.get("content_format_rules", {}),
|
||||
engagement_patterns=platform_data.get("engagement_patterns", {}),
|
||||
platform_best_practices={"practices": platform_data.get("platform_best_practices", [])}
|
||||
platform_best_practices={"practices": platform_data.get("platform_best_practices", [])},
|
||||
algorithm_considerations=platform_specific_data if platform_specific_data else platform_data.get("algorithm_considerations", {})
|
||||
)
|
||||
session.add(platform_persona)
|
||||
|
||||
@@ -565,9 +381,10 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
session.add(analysis_result)
|
||||
|
||||
session.commit()
|
||||
persona_id = writing_persona.id
|
||||
session.close()
|
||||
|
||||
logger.info(f"✅ Persona saved to database with ID: {writing_persona.id}")
|
||||
logger.info(f"✅ Persona saved to database with ID: {persona_id}")
|
||||
return writing_persona
|
||||
|
||||
except Exception as e:
|
||||
@@ -581,26 +398,108 @@ Generate a platform-optimized persona adaptation that maintains brand consistenc
|
||||
"""Calculate how sufficient the onboarding data is for persona generation."""
|
||||
score = 0.0
|
||||
|
||||
website_analysis = onboarding_data.get("website_analysis", {})
|
||||
research_prefs = onboarding_data.get("research_preferences", {})
|
||||
# Get enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
research_prefs = onboarding_data.get("research_preferences", {}) or {}
|
||||
|
||||
# Website analysis components (70% of score)
|
||||
if website_analysis.get("writing_style"):
|
||||
score += 25
|
||||
if website_analysis.get("content_characteristics"):
|
||||
score += 20
|
||||
if website_analysis.get("target_audience"):
|
||||
score += 15
|
||||
if website_analysis.get("style_patterns"):
|
||||
score += 10
|
||||
# Enhanced scoring based on comprehensive data availability
|
||||
|
||||
# Research preferences components (30% of score)
|
||||
# Comprehensive Style Analysis (25% of score)
|
||||
style_analysis = enhanced_analysis.get("comprehensive_style_analysis", {})
|
||||
if style_analysis.get("tone_analysis"):
|
||||
score += 5
|
||||
if style_analysis.get("voice_characteristics"):
|
||||
score += 5
|
||||
if style_analysis.get("brand_personality"):
|
||||
score += 5
|
||||
if style_analysis.get("formality_level"):
|
||||
score += 5
|
||||
if style_analysis.get("emotional_appeal"):
|
||||
score += 5
|
||||
|
||||
# Content Insights (20% of score)
|
||||
content_insights = enhanced_analysis.get("content_insights", {})
|
||||
if content_insights.get("sentence_structure_analysis"):
|
||||
score += 4
|
||||
if content_insights.get("vocabulary_level"):
|
||||
score += 4
|
||||
if content_insights.get("readability_score"):
|
||||
score += 4
|
||||
if content_insights.get("content_flow"):
|
||||
score += 4
|
||||
if content_insights.get("visual_elements_usage"):
|
||||
score += 4
|
||||
|
||||
# Audience Intelligence (15% of score)
|
||||
audience_intel = enhanced_analysis.get("audience_intelligence", {})
|
||||
if audience_intel.get("demographics"):
|
||||
score += 3
|
||||
if audience_intel.get("expertise_level"):
|
||||
score += 3
|
||||
if audience_intel.get("industry_focus"):
|
||||
score += 3
|
||||
if audience_intel.get("psychographic_profile"):
|
||||
score += 3
|
||||
if audience_intel.get("pain_points"):
|
||||
score += 3
|
||||
|
||||
# Technical Writing Metrics (15% of score)
|
||||
tech_metrics = enhanced_analysis.get("technical_writing_metrics", {})
|
||||
if tech_metrics.get("vocabulary_patterns"):
|
||||
score += 3
|
||||
if tech_metrics.get("rhetorical_devices"):
|
||||
score += 3
|
||||
if tech_metrics.get("paragraph_structure"):
|
||||
score += 3
|
||||
if tech_metrics.get("style_consistency"):
|
||||
score += 3
|
||||
if tech_metrics.get("unique_elements"):
|
||||
score += 3
|
||||
|
||||
# Content Strategy Insights (15% of score)
|
||||
strategy_insights = enhanced_analysis.get("content_strategy_insights", {})
|
||||
if strategy_insights.get("tone_recommendations"):
|
||||
score += 3
|
||||
if strategy_insights.get("best_practices"):
|
||||
score += 3
|
||||
if strategy_insights.get("competitive_advantages"):
|
||||
score += 3
|
||||
if strategy_insights.get("content_strategy"):
|
||||
score += 3
|
||||
if strategy_insights.get("ai_generation_tips"):
|
||||
score += 3
|
||||
|
||||
# Research Preferences (10% of score)
|
||||
if research_prefs.get("research_depth"):
|
||||
score += 10
|
||||
score += 5
|
||||
if research_prefs.get("content_types"):
|
||||
score += 10
|
||||
if research_prefs.get("writing_style"):
|
||||
score += 10
|
||||
score += 5
|
||||
|
||||
# Legacy compatibility - add points for basic data if enhanced data is missing
|
||||
if score < 50: # If enhanced data is insufficient, fall back to legacy scoring
|
||||
legacy_score = 0.0
|
||||
|
||||
# Website analysis components (70% of legacy score)
|
||||
if website_analysis.get("writing_style"):
|
||||
legacy_score += 25
|
||||
if website_analysis.get("content_characteristics"):
|
||||
legacy_score += 20
|
||||
if website_analysis.get("target_audience"):
|
||||
legacy_score += 15
|
||||
if website_analysis.get("style_patterns"):
|
||||
legacy_score += 10
|
||||
|
||||
# Research preferences components (30% of legacy score)
|
||||
if research_prefs.get("research_depth"):
|
||||
legacy_score += 10
|
||||
if research_prefs.get("content_types"):
|
||||
legacy_score += 10
|
||||
if research_prefs.get("writing_style"):
|
||||
legacy_score += 10
|
||||
|
||||
# Use the higher of enhanced or legacy score
|
||||
score = max(score, legacy_score)
|
||||
|
||||
return min(score, 100.0)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user