Base code
This commit is contained in:
10
backend/services/persona/linkedin/__init__.py
Normal file
10
backend/services/persona/linkedin/__init__.py
Normal file
@@ -0,0 +1,10 @@
|
||||
"""
|
||||
LinkedIn Persona Services
|
||||
Contains LinkedIn-specific persona generation and optimization services.
|
||||
"""
|
||||
|
||||
from .linkedin_persona_service import LinkedInPersonaService
|
||||
from .linkedin_persona_prompts import LinkedInPersonaPrompts
|
||||
from .linkedin_persona_schemas import LinkedInPersonaSchemas
|
||||
|
||||
__all__ = ['LinkedInPersonaService', 'LinkedInPersonaPrompts', 'LinkedInPersonaSchemas']
|
||||
319
backend/services/persona/linkedin/linkedin_persona_prompts.py
Normal file
319
backend/services/persona/linkedin/linkedin_persona_prompts.py
Normal file
@@ -0,0 +1,319 @@
|
||||
"""
|
||||
LinkedIn Persona Prompts
|
||||
Contains LinkedIn-specific prompt generation for persona analysis.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
import json
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class LinkedInPersonaPrompts:
|
||||
"""Handles LinkedIn-specific persona prompt generation."""
|
||||
|
||||
@staticmethod
|
||||
def build_enhanced_linkedin_prompt(core_persona: Dict[str, Any], onboarding_data: Dict[str, Any]) -> str:
|
||||
"""Build enhanced LinkedIn-specific persona prompt with professional optimization."""
|
||||
|
||||
# Extract comprehensive professional context
|
||||
professional_context = LinkedInPersonaPrompts._extract_professional_context(onboarding_data)
|
||||
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
target_audience = website_analysis.get("target_audience", {})
|
||||
industry_focus = professional_context.get("industry_focus", "general")
|
||||
expertise_level = professional_context.get("expertise_level", "intermediate")
|
||||
|
||||
prompt = f"""
|
||||
LINKEDIN PROFESSIONAL PERSONA OPTIMIZATION TASK: Create a comprehensive LinkedIn-optimized writing persona for professional networking and thought leadership.
|
||||
|
||||
CORE PERSONA FOUNDATION:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
PROFESSIONAL CONTEXT:
|
||||
- Industry: {industry_focus}
|
||||
- Expertise Level: {expertise_level}
|
||||
- Company Size: {professional_context.get('company_size', 'Not specified')}
|
||||
- Business Model: {professional_context.get('business_model', 'Not specified')}
|
||||
- Professional Role: {professional_context.get('professional_role', 'Not specified')}
|
||||
- Demographics: {professional_context.get('target_demographics', [])}
|
||||
- Psychographic: {professional_context.get('psychographic_profile', 'Not specified')}
|
||||
|
||||
LINKEDIN PLATFORM SPECIFICATIONS:
|
||||
- Character Limit: 3,000 characters
|
||||
- Optimal Post Length: 150-300 words for maximum engagement
|
||||
- Professional Network: B2B focused, career-oriented audience
|
||||
- Algorithm Priority: Engagement, relevance, professional value
|
||||
- Content Types: Posts, Articles, Polls, Videos, Carousels, Events
|
||||
- Hashtag Limit: 3-5 hashtags for optimal reach
|
||||
- Link Strategy: Place external links in first comment for algorithm optimization
|
||||
|
||||
LINKEDIN PROFESSIONAL OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. PROFESSIONAL TONE & VOICE:
|
||||
- Maintain authoritative yet approachable professional tone
|
||||
- Use industry-specific terminology appropriately
|
||||
- Balance expertise with accessibility for {expertise_level} audience
|
||||
- Incorporate thought leadership elements
|
||||
- Include professional storytelling and case studies
|
||||
|
||||
2. CONTENT STRATEGY FOR {industry_focus.upper()}:
|
||||
- Industry insights for {expertise_level} professionals
|
||||
- Professional development content for {professional_context.get('target_demographics', [])}
|
||||
- Business strategy discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking focus for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership positioning as {professional_context.get('professional_role', 'professional')}
|
||||
|
||||
3. ENGAGEMENT OPTIMIZATION:
|
||||
- Professional question frameworks for discussion
|
||||
- Industry-relevant polling strategies
|
||||
- Professional networking call-to-actions
|
||||
- Thought leadership positioning
|
||||
- Community building through professional value
|
||||
|
||||
4. LINKEDIN-SPECIFIC FEATURES:
|
||||
- Native video optimization for professional content
|
||||
- LinkedIn Articles for long-form thought leadership
|
||||
- LinkedIn Polls for industry insights and engagement
|
||||
- LinkedIn Events for professional networking
|
||||
- LinkedIn Carousels for educational content
|
||||
- LinkedIn Live for professional discussions
|
||||
|
||||
5. PROFESSIONAL NETWORKING ELEMENTS:
|
||||
- Industry-specific hashtag strategy
|
||||
- Professional mention and tagging etiquette
|
||||
- Thought leadership positioning
|
||||
- Professional relationship building
|
||||
- Career advancement focus
|
||||
|
||||
6. CONTENT FORMAT OPTIMIZATION:
|
||||
- Hook strategies for professional feed
|
||||
- "See More" optimization for longer posts
|
||||
- Professional call-to-action frameworks
|
||||
- Industry-specific content structures
|
||||
- Professional storytelling techniques
|
||||
|
||||
7. LINKEDIN ALGORITHM OPTIMIZATION:
|
||||
- Professional engagement patterns
|
||||
- Industry-relevant content timing
|
||||
- Professional network interaction strategies
|
||||
- Thought leadership content performance
|
||||
- Professional community building
|
||||
|
||||
8. INDUSTRY-SPECIFIC ADAPTATIONS FOR {industry_focus.upper()}:
|
||||
- Terminology appropriate for {expertise_level} level
|
||||
- Professional development for {professional_context.get('target_demographics', [])}
|
||||
- Trend discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking strategies for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership as {professional_context.get('professional_role', 'professional')}
|
||||
- Content addressing {professional_context.get('psychographic_profile', 'professional needs')}
|
||||
- Business insights for {professional_context.get('conversion_focus', 'business growth')}
|
||||
|
||||
PROFESSIONAL EXCELLENCE STANDARDS:
|
||||
- Maintain high professional standards
|
||||
- Focus on value-driven content
|
||||
- Emphasize thought leadership and expertise
|
||||
- Build professional credibility and authority
|
||||
- Foster meaningful professional relationships
|
||||
- Provide actionable business insights
|
||||
- Support professional development and growth
|
||||
|
||||
Generate a comprehensive LinkedIn-optimized persona that positions the user as a thought leader in {industry_focus} while maintaining professional excellence and maximizing LinkedIn's professional networking potential.
|
||||
"""
|
||||
|
||||
return prompt
|
||||
|
||||
@staticmethod
|
||||
def get_linkedin_platform_constraints() -> Dict[str, Any]:
|
||||
"""Get LinkedIn-specific platform constraints and best practices."""
|
||||
return {
|
||||
"character_limit": 3000,
|
||||
"optimal_length": "150-300 words",
|
||||
"professional_tone": True,
|
||||
"hashtag_limit": 5,
|
||||
"rich_media": True,
|
||||
"long_form": True,
|
||||
"thought_leadership": True,
|
||||
"networking_focus": True,
|
||||
"career_development": True,
|
||||
"industry_insights": True,
|
||||
"professional_storytelling": True,
|
||||
"b2b_optimized": True,
|
||||
"algorithm_engagement": True,
|
||||
"native_video": True,
|
||||
"linkedin_articles": True,
|
||||
"linkedin_polls": True,
|
||||
"linkedin_events": True,
|
||||
"linkedin_carousels": True,
|
||||
"linkedin_live": True
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def _extract_professional_context(onboarding_data: Dict[str, Any]) -> Dict[str, Any]:
|
||||
"""Extract comprehensive professional context from onboarding data."""
|
||||
|
||||
professional_context = {
|
||||
"industry_focus": "general",
|
||||
"expertise_level": "intermediate",
|
||||
"company_size": "Not specified",
|
||||
"business_model": "Not specified",
|
||||
"professional_role": "Not specified",
|
||||
"geographic_focus": "global",
|
||||
"target_demographics": [],
|
||||
"psychographic_profile": "",
|
||||
"content_purpose": "",
|
||||
"conversion_focus": "",
|
||||
"research_depth": "",
|
||||
"content_types": []
|
||||
}
|
||||
|
||||
# Extract from website analysis
|
||||
website_analysis = onboarding_data.get("website_analysis", {}) or {}
|
||||
|
||||
# Target audience information
|
||||
target_audience = website_analysis.get("target_audience", {})
|
||||
if target_audience:
|
||||
professional_context["industry_focus"] = target_audience.get("industry_focus", "general")
|
||||
professional_context["expertise_level"] = target_audience.get("expertise_level", "intermediate")
|
||||
professional_context["geographic_focus"] = target_audience.get("geographic_focus", "global")
|
||||
professional_context["target_demographics"] = target_audience.get("demographics", [])
|
||||
professional_context["psychographic_profile"] = target_audience.get("psychographic_profile", "")
|
||||
|
||||
# Content type and business context
|
||||
content_type = website_analysis.get("content_type", {})
|
||||
if content_type:
|
||||
professional_context["content_purpose"] = content_type.get("purpose", "")
|
||||
professional_context["conversion_focus"] = content_type.get("conversion_focus", "")
|
||||
|
||||
# Company and business information from crawl results
|
||||
crawl_result = website_analysis.get("crawl_result", {})
|
||||
if crawl_result:
|
||||
domain_info = crawl_result.get("domain_info", {})
|
||||
if domain_info:
|
||||
professional_context["company_size"] = domain_info.get("company_size", "Not specified")
|
||||
professional_context["business_model"] = domain_info.get("business_model", "Not specified")
|
||||
|
||||
brand_info = crawl_result.get("brand_info", {})
|
||||
if brand_info:
|
||||
professional_context["professional_role"] = brand_info.get("professional_role", "Not specified")
|
||||
|
||||
# Research preferences
|
||||
research_prefs = onboarding_data.get("research_preferences", {})
|
||||
if research_prefs:
|
||||
professional_context["research_depth"] = research_prefs.get("research_depth", "")
|
||||
professional_context["content_types"] = research_prefs.get("content_types", [])
|
||||
|
||||
# Enhanced analysis data
|
||||
enhanced_analysis = onboarding_data.get("enhanced_analysis", {})
|
||||
if enhanced_analysis:
|
||||
audience_intel = enhanced_analysis.get("audience_intelligence", {})
|
||||
if audience_intel:
|
||||
# Override with more detailed information if available
|
||||
if audience_intel.get("industry_focus"):
|
||||
professional_context["industry_focus"] = audience_intel["industry_focus"]
|
||||
if audience_intel.get("expertise_level"):
|
||||
professional_context["expertise_level"] = audience_intel["expertise_level"]
|
||||
if audience_intel.get("psychographic_profile"):
|
||||
professional_context["psychographic_profile"] = audience_intel["psychographic_profile"]
|
||||
|
||||
brand_voice = enhanced_analysis.get("brand_voice_analysis", {})
|
||||
if brand_voice:
|
||||
if brand_voice.get("primary_content_type"):
|
||||
professional_context["content_purpose"] = brand_voice["primary_content_type"]
|
||||
if brand_voice.get("conversion_focus"):
|
||||
professional_context["conversion_focus"] = brand_voice["conversion_focus"]
|
||||
|
||||
return professional_context
|
||||
|
||||
@staticmethod
|
||||
def build_linkedin_system_prompt(core_persona: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build system prompt with core persona for LinkedIn generation.
|
||||
This moves the core persona to system prompt to free up context window.
|
||||
"""
|
||||
import json
|
||||
|
||||
return f"""You are an expert LinkedIn content strategist and professional networking specialist.
|
||||
|
||||
CORE PERSONA FOUNDATION:
|
||||
{json.dumps(core_persona, indent=2)}
|
||||
|
||||
Your task is to create LinkedIn-optimized persona adaptations that maintain the core persona's identity while optimizing for professional networking, thought leadership, and B2B engagement on LinkedIn.
|
||||
|
||||
Focus on:
|
||||
- Professional tone and authority
|
||||
- Industry-specific optimization
|
||||
- LinkedIn algorithm best practices
|
||||
- B2B engagement strategies
|
||||
- Professional networking optimization"""
|
||||
|
||||
@staticmethod
|
||||
def build_focused_linkedin_prompt(onboarding_data: Dict[str, Any]) -> str:
|
||||
"""
|
||||
Build focused LinkedIn prompt without core persona JSON to optimize context usage.
|
||||
"""
|
||||
# Extract professional context
|
||||
professional_context = LinkedInPersonaPrompts._extract_professional_context(onboarding_data)
|
||||
|
||||
industry_focus = professional_context.get("industry_focus", "general")
|
||||
expertise_level = professional_context.get("expertise_level", "intermediate")
|
||||
|
||||
return f"""LINKEDIN PROFESSIONAL OPTIMIZATION TASK: Create LinkedIn-specific adaptations for the core persona.
|
||||
|
||||
PROFESSIONAL CONTEXT:
|
||||
- Industry: {industry_focus}
|
||||
- Expertise Level: {expertise_level}
|
||||
- Company Size: {professional_context.get('company_size', 'Not specified')}
|
||||
- Business Model: {professional_context.get('business_model', 'Not specified')}
|
||||
- Professional Role: {professional_context.get('professional_role', 'Not specified')}
|
||||
- Demographics: {professional_context.get('target_demographics', [])}
|
||||
- Psychographic: {professional_context.get('psychographic_profile', 'Not specified')}
|
||||
|
||||
LINKEDIN PLATFORM SPECIFICATIONS:
|
||||
- Character Limit: 3,000 characters
|
||||
- Optimal Post Length: 150-300 words for maximum engagement
|
||||
- Professional Network: B2B focused, career-oriented audience
|
||||
- Algorithm Priority: Engagement, relevance, professional value
|
||||
- Content Types: Posts, Articles, Polls, Videos, Carousels, Events
|
||||
- Hashtag Limit: 3-5 hashtags for optimal reach
|
||||
- Link Strategy: Place external links in first comment for algorithm optimization
|
||||
|
||||
LINKEDIN OPTIMIZATION REQUIREMENTS:
|
||||
|
||||
1. PROFESSIONAL TONE & VOICE:
|
||||
- Maintain authoritative yet approachable professional tone
|
||||
- Use industry-specific terminology appropriately
|
||||
- Balance expertise with accessibility for {expertise_level} audience
|
||||
- Incorporate thought leadership elements
|
||||
- Include professional storytelling and case studies
|
||||
|
||||
2. CONTENT STRATEGY FOR {industry_focus.upper()}:
|
||||
- Industry insights for {expertise_level} professionals
|
||||
- Professional development content for {professional_context.get('target_demographics', [])}
|
||||
- Business strategy discussions for {professional_context.get('business_model', 'general business')}
|
||||
- Networking focus for {professional_context.get('company_size', 'all company sizes')}
|
||||
- Thought leadership positioning as {professional_context.get('professional_role', 'professional')}
|
||||
|
||||
3. LINKEDIN-SPECIFIC ADAPTATIONS:
|
||||
- Optimize sentence structure for professional readability
|
||||
- Create platform-specific vocabulary and terminology
|
||||
- Define engagement patterns for B2B audience
|
||||
- Establish professional networking strategies
|
||||
- Include LinkedIn feature optimization (Articles, Polls, Events, etc.)
|
||||
|
||||
4. ALGORITHM OPTIMIZATION:
|
||||
- Engagement patterns for professional audience
|
||||
- Content timing for maximum reach
|
||||
- Professional value metrics
|
||||
- Network interaction strategies
|
||||
|
||||
5. PROFESSIONAL CONTEXT OPTIMIZATION:
|
||||
- Industry-specific positioning
|
||||
- Expertise level adaptation
|
||||
- Company size considerations
|
||||
- Business model alignment
|
||||
- Professional role authority
|
||||
- Demographic targeting
|
||||
- Psychographic engagement
|
||||
- Conversion optimization
|
||||
|
||||
Generate a comprehensive LinkedIn-optimized persona that maintains the core persona's identity while maximizing professional networking and thought leadership potential on LinkedIn."""
|
||||
115
backend/services/persona/linkedin/linkedin_persona_schemas.py
Normal file
115
backend/services/persona/linkedin/linkedin_persona_schemas.py
Normal file
@@ -0,0 +1,115 @@
|
||||
"""
|
||||
LinkedIn Persona Schemas
|
||||
Contains LinkedIn-specific JSON schemas for persona generation.
|
||||
"""
|
||||
|
||||
from typing import Dict, Any
|
||||
|
||||
|
||||
class LinkedInPersonaSchemas:
|
||||
"""Handles LinkedIn-specific persona schema definitions."""
|
||||
|
||||
@staticmethod
|
||||
def get_linkedin_platform_schema() -> Dict[str, Any]:
|
||||
"""Get LinkedIn-specific platform persona schema."""
|
||||
return {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_type": {"type": "string"},
|
||||
"sentence_metrics": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"max_sentence_length": {"type": "number"},
|
||||
"optimal_sentence_length": {"type": "number"},
|
||||
"sentence_variety": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"lexical_adaptations": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"platform_specific_words": {"type": "array", "items": {"type": "string"}},
|
||||
"hashtag_strategy": {"type": "string"},
|
||||
"emoji_usage": {"type": "string"},
|
||||
"mention_strategy": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"content_format_rules": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"character_limit": {"type": "number"},
|
||||
"paragraph_structure": {"type": "string"},
|
||||
"call_to_action_style": {"type": "string"},
|
||||
"link_placement": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"engagement_patterns": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"posting_frequency": {"type": "string"},
|
||||
"optimal_posting_times": {"type": "array", "items": {"type": "string"}},
|
||||
"engagement_tactics": {"type": "array", "items": {"type": "string"}},
|
||||
"community_interaction": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"platform_best_practices": {
|
||||
"type": "array",
|
||||
"items": {"type": "string"}
|
||||
}
|
||||
},
|
||||
"required": ["platform_type", "sentence_metrics", "content_format_rules", "engagement_patterns"]
|
||||
}
|
||||
|
||||
@staticmethod
|
||||
def get_enhanced_linkedin_schema() -> Dict[str, Any]:
|
||||
"""Get enhanced LinkedIn schema with additional professional fields."""
|
||||
base_schema = LinkedInPersonaSchemas.get_linkedin_platform_schema()
|
||||
|
||||
# Add LinkedIn-specific professional fields
|
||||
base_schema["properties"]["professional_networking"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"thought_leadership_positioning": {"type": "string"},
|
||||
"industry_authority_building": {"type": "string"},
|
||||
"professional_relationship_strategies": {"type": "array", "items": {"type": "string"}},
|
||||
"career_advancement_focus": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
base_schema["properties"]["linkedin_features"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"articles_strategy": {"type": "string"},
|
||||
"polls_optimization": {"type": "string"},
|
||||
"events_networking": {"type": "string"},
|
||||
"carousels_education": {"type": "string"},
|
||||
"live_discussions": {"type": "string"},
|
||||
"native_video": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
base_schema["properties"]["algorithm_optimization"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"engagement_patterns": {"type": "array", "items": {"type": "string"}},
|
||||
"content_timing": {"type": "array", "items": {"type": "string"}},
|
||||
"professional_value_metrics": {"type": "array", "items": {"type": "string"}},
|
||||
"network_interaction_strategies": {"type": "array", "items": {"type": "string"}}
|
||||
}
|
||||
}
|
||||
|
||||
# Add professional context optimization
|
||||
base_schema["properties"]["professional_context_optimization"] = {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"industry_specific_positioning": {"type": "string"},
|
||||
"expertise_level_adaptation": {"type": "string"},
|
||||
"company_size_considerations": {"type": "string"},
|
||||
"business_model_alignment": {"type": "string"},
|
||||
"professional_role_authority": {"type": "string"},
|
||||
"demographic_targeting": {"type": "array", "items": {"type": "string"}},
|
||||
"psychographic_engagement": {"type": "string"},
|
||||
"conversion_optimization": {"type": "string"}
|
||||
}
|
||||
}
|
||||
|
||||
return base_schema
|
||||
550
backend/services/persona/linkedin/linkedin_persona_service.py
Normal file
550
backend/services/persona/linkedin/linkedin_persona_service.py
Normal file
@@ -0,0 +1,550 @@
|
||||
"""
|
||||
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."""
|
||||
|
||||
_instance = None
|
||||
_initialized = False
|
||||
|
||||
def __new__(cls):
|
||||
"""Implement singleton pattern to prevent multiple initializations."""
|
||||
if cls._instance is None:
|
||||
cls._instance = super(LinkedInPersonaService, cls).__new__(cls)
|
||||
return cls._instance
|
||||
|
||||
def __init__(self):
|
||||
"""Initialize the LinkedIn persona service (only once)."""
|
||||
if not self._initialized:
|
||||
self.prompts = LinkedInPersonaPrompts()
|
||||
self.schemas = LinkedInPersonaSchemas()
|
||||
logger.debug("LinkedInPersonaService initialized")
|
||||
self._initialized = True
|
||||
|
||||
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
|
||||
Reference in New Issue
Block a user