ALwrity persona system

This commit is contained in:
ajaysi
2025-09-05 15:22:43 +05:30
parent ccbdc9e8c6
commit f82ada0361
38 changed files with 5673 additions and 1240 deletions

View File

@@ -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)}"
)

View File

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

View File

@@ -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.

View File

@@ -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.

View File

@@ -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."""

View 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

View 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']

View 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'
]

View 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, {})

View 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)

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

View 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."""

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

View 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
}

View 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']

View 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."""

View 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

View 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

View File

@@ -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)