""" LinkedIn Content Generation Models for ALwrity This module defines the data models for LinkedIn content generation endpoints. """ from pydantic import BaseModel, Field, validator from typing import List, Optional, Dict, Any, Literal from datetime import datetime from enum import Enum class LinkedInPostType(str, Enum): """Types of LinkedIn posts.""" PROFESSIONAL = "professional" THOUGHT_LEADERSHIP = "thought_leadership" INDUSTRY_NEWS = "industry_news" PERSONAL_STORY = "personal_story" COMPANY_UPDATE = "company_update" POLL = "poll" class LinkedInTone(str, Enum): """LinkedIn content tone options.""" PROFESSIONAL = "professional" CONVERSATIONAL = "conversational" AUTHORITATIVE = "authoritative" INSPIRATIONAL = "inspirational" EDUCATIONAL = "educational" FRIENDLY = "friendly" class SearchEngine(str, Enum): """Available search engines for research.""" METAPHOR = "metaphor" GOOGLE = "google" TAVILY = "tavily" class LinkedInPostRequest(BaseModel): """Request model for LinkedIn post generation.""" topic: str = Field(..., description="Main topic for the post", min_length=3, max_length=200) industry: str = Field(..., description="Target industry context", min_length=2, max_length=100) post_type: LinkedInPostType = Field(default=LinkedInPostType.PROFESSIONAL, description="Type of LinkedIn post") tone: LinkedInTone = Field(default=LinkedInTone.PROFESSIONAL, description="Tone of the post") target_audience: Optional[str] = Field(None, description="Specific target audience", max_length=200) key_points: Optional[List[str]] = Field(None, description="Key points to include", max_items=10) include_hashtags: bool = Field(default=True, description="Whether to include hashtags") include_call_to_action: bool = Field(default=True, description="Whether to include call to action") research_enabled: bool = Field(default=True, description="Whether to include research-backed content") search_engine: SearchEngine = Field(default=SearchEngine.METAPHOR, description="Search engine for research") max_length: int = Field(default=3000, description="Maximum character count", ge=100, le=3000) class Config: schema_extra = { "example": { "topic": "AI in healthcare transformation", "industry": "Healthcare", "post_type": "thought_leadership", "tone": "professional", "target_audience": "Healthcare executives and professionals", "key_points": ["AI diagnostics", "Patient outcomes", "Cost reduction"], "include_hashtags": True, "include_call_to_action": True, "research_enabled": True, "search_engine": "metaphor", "max_length": 2000 } } class LinkedInArticleRequest(BaseModel): """Request model for LinkedIn article generation.""" topic: str = Field(..., description="Main topic for the article", min_length=3, max_length=200) industry: str = Field(..., description="Target industry context", min_length=2, max_length=100) tone: LinkedInTone = Field(default=LinkedInTone.PROFESSIONAL, description="Tone of the article") target_audience: Optional[str] = Field(None, description="Specific target audience", max_length=200) key_sections: Optional[List[str]] = Field(None, description="Key sections to include", max_items=10) include_images: bool = Field(default=True, description="Whether to generate image suggestions") seo_optimization: bool = Field(default=True, description="Whether to include SEO optimization") research_enabled: bool = Field(default=True, description="Whether to include research-backed content") search_engine: SearchEngine = Field(default=SearchEngine.METAPHOR, description="Search engine for research") word_count: int = Field(default=1500, description="Target word count", ge=500, le=5000) class Config: schema_extra = { "example": { "topic": "Digital transformation in manufacturing", "industry": "Manufacturing", "tone": "professional", "target_audience": "Manufacturing leaders and technology professionals", "key_sections": ["Current challenges", "Technology solutions", "Implementation strategies"], "include_images": True, "seo_optimization": True, "research_enabled": True, "search_engine": "metaphor", "word_count": 2000 } } class LinkedInCarouselRequest(BaseModel): """Request model for LinkedIn carousel post generation.""" topic: str = Field(..., description="Main topic for the carousel", min_length=3, max_length=200) industry: str = Field(..., description="Target industry context", min_length=2, max_length=100) slide_count: int = Field(default=8, description="Number of slides", ge=3, le=15) tone: LinkedInTone = Field(default=LinkedInTone.PROFESSIONAL, description="Tone of the carousel") target_audience: Optional[str] = Field(None, description="Specific target audience", max_length=200) key_takeaways: Optional[List[str]] = Field(None, description="Key takeaways to include", max_items=10) include_cover_slide: bool = Field(default=True, description="Whether to include a cover slide") include_cta_slide: bool = Field(default=True, description="Whether to include a call-to-action slide") visual_style: Optional[str] = Field("modern", description="Visual style preference") class Config: schema_extra = { "example": { "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" } } class LinkedInVideoScriptRequest(BaseModel): """Request model for LinkedIn video script generation.""" topic: str = Field(..., description="Main topic for the video", min_length=3, max_length=200) industry: str = Field(..., description="Target industry context", min_length=2, max_length=100) video_length: int = Field(default=60, description="Target video length in seconds", ge=15, le=300) tone: LinkedInTone = Field(default=LinkedInTone.PROFESSIONAL, description="Tone of the video") target_audience: Optional[str] = Field(None, description="Specific target audience", max_length=200) key_messages: Optional[List[str]] = Field(None, description="Key messages to include", max_items=5) include_hook: bool = Field(default=True, description="Whether to include an attention-grabbing hook") include_captions: bool = Field(default=True, description="Whether to include caption suggestions") class Config: schema_extra = { "example": { "topic": "Quick tips for remote team management", "industry": "Human Resources", "video_length": 90, "tone": "conversational", "target_audience": "Remote team managers", "key_messages": ["Communication tools", "Regular check-ins", "Team building"], "include_hook": True, "include_captions": True } } class LinkedInCommentResponseRequest(BaseModel): """Request model for LinkedIn comment response generation.""" original_post: str = Field(..., description="Content of the original post", min_length=10, max_length=3000) comment: str = Field(..., description="Comment to respond to", min_length=1, max_length=1000) response_type: Literal["professional", "appreciative", "clarifying", "disagreement", "value_add"] = Field( default="professional", description="Type of response" ) tone: LinkedInTone = Field(default=LinkedInTone.PROFESSIONAL, description="Tone of the response") include_question: bool = Field(default=False, description="Whether to include a follow-up question") brand_voice: Optional[str] = Field(None, description="Specific brand voice guidelines", max_length=500) class Config: schema_extra = { "example": { "original_post": "Just published an article about AI transformation in healthcare...", "comment": "Great insights! How do you see this affecting smaller healthcare providers?", "response_type": "value_add", "tone": "professional", "include_question": True, "brand_voice": "Expert but approachable, data-driven" } } class ResearchSource(BaseModel): """Model for research source information.""" title: str url: str content: str relevance_score: Optional[float] = None class HashtagSuggestion(BaseModel): """Model for hashtag suggestions.""" hashtag: str category: str popularity_score: Optional[float] = None class ImageSuggestion(BaseModel): """Model for image suggestions.""" description: str alt_text: str style: Optional[str] = None placement: Optional[str] = None class PostContent(BaseModel): """Model for generated post content.""" content: str character_count: int hashtags: List[HashtagSuggestion] call_to_action: Optional[str] = None engagement_prediction: Optional[Dict[str, Any]] = None class ArticleContent(BaseModel): """Model for generated article content.""" title: str content: str word_count: int sections: List[Dict[str, str]] seo_metadata: Optional[Dict[str, Any]] = None image_suggestions: List[ImageSuggestion] reading_time: Optional[int] = None class CarouselSlide(BaseModel): """Model for carousel slide content.""" slide_number: int title: str content: str visual_elements: List[str] design_notes: Optional[str] = None class CarouselContent(BaseModel): """Model for generated carousel content.""" title: str slides: List[CarouselSlide] cover_slide: Optional[CarouselSlide] = None cta_slide: Optional[CarouselSlide] = None design_guidelines: Dict[str, str] class VideoScript(BaseModel): """Model for video script content.""" hook: str main_content: List[Dict[str, str]] # scene_number, content, duration, visual_notes conclusion: str captions: Optional[List[str]] = None thumbnail_suggestions: List[str] video_description: str class LinkedInPostResponse(BaseModel): """Response model for LinkedIn post generation.""" success: bool = True data: Optional[PostContent] = None research_sources: List[ResearchSource] = [] generation_metadata: Dict[str, Any] = {} error: Optional[str] = None class Config: schema_extra = { "example": { "success": True, "data": { "content": "🚀 AI is revolutionizing healthcare...", "character_count": 1250, "hashtags": [ {"hashtag": "#AIinHealthcare", "category": "industry", "popularity_score": 0.9}, {"hashtag": "#DigitalTransformation", "category": "general", "popularity_score": 0.8} ], "call_to_action": "What's your experience with AI in healthcare? Share in the comments!", "engagement_prediction": {"estimated_likes": 120, "estimated_comments": 15} }, "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": { "model_used": "gemini-2.0-flash-001", "generation_time": 3.2, "research_time": 5.1 } } } class LinkedInArticleResponse(BaseModel): """Response model for LinkedIn article generation.""" success: bool = True data: Optional[ArticleContent] = None research_sources: List[ResearchSource] = [] generation_metadata: Dict[str, Any] = {} error: Optional[str] = None class LinkedInCarouselResponse(BaseModel): """Response model for LinkedIn carousel generation.""" success: bool = True data: Optional[CarouselContent] = None generation_metadata: Dict[str, Any] = {} error: Optional[str] = None class LinkedInVideoScriptResponse(BaseModel): """Response model for LinkedIn video script generation.""" success: bool = True data: Optional[VideoScript] = None generation_metadata: Dict[str, Any] = {} error: Optional[str] = None class LinkedInCommentResponseResult(BaseModel): """Response model for LinkedIn comment response generation.""" success: bool = True response: Optional[str] = None alternative_responses: List[str] = [] tone_analysis: Optional[Dict[str, Any]] = None generation_metadata: Dict[str, Any] = {} error: Optional[str] = None