Spaces:
Sleeping
Sleeping
| """User professional profile configuration for personalized content generation.""" | |
| import re | |
| from dataclasses import dataclass, field | |
| from pathlib import Path | |
| from typing import Any | |
| import yaml | |
| class UserProfile: | |
| """Professional profile configuration for content personalization. | |
| This profile helps tailor content to your expertise, positioning, | |
| and professional goals for maximum opportunity generation. | |
| """ | |
| # Professional Identity | |
| name: str = "Your Name" | |
| target_role: str = "AI Consultant" # AI Consultant, ML Engineer, AI Architect, etc. | |
| expertise_areas: list[str] = field( | |
| default_factory=lambda: ["Machine Learning", "Artificial Intelligence", "Deep Learning"] | |
| ) | |
| # Professional Goals | |
| content_goals: list[str] = field( | |
| default_factory=lambda: [ | |
| "opportunities", # Attract freelance/job opportunities | |
| "credibility", # Build professional credibility | |
| "visibility", # Increase visibility in the field | |
| ] | |
| ) | |
| # Geographic & Market | |
| region: str = "Europe" # Europe, US, Asia, Global, etc. | |
| languages: list[str] = field(default_factory=lambda: ["English"]) | |
| target_industries: list[str] = field( | |
| default_factory=lambda: ["Technology", "Finance", "Healthcare", "Consulting"] | |
| ) | |
| # Portfolio & Experience | |
| github_username: str = "" # Your GitHub username | |
| linkedin_url: str = "" # Your LinkedIn profile URL | |
| portfolio_url: str = "" # Personal website/portfolio | |
| kaggle_username: str = "" # Your Kaggle username | |
| # Key Projects (to mention in content) | |
| notable_projects: list[dict[str, str]] = field( | |
| default_factory=lambda: [ | |
| { | |
| "name": "Project Name", | |
| "description": "Brief description of what you built", | |
| "technologies": "PyTorch, FastAPI, Docker", | |
| "url": "https://github.com/username/project", | |
| } | |
| ] | |
| ) | |
| # Technical Skills & Tools | |
| primary_skills: list[str] = field( | |
| default_factory=lambda: ["Python", "PyTorch", "TensorFlow", "Scikit-learn", "MLflow"] | |
| ) | |
| # Content Preferences | |
| content_tone: str = ( | |
| "professional-conversational" # professional-formal, professional-conversational, technical | |
| ) | |
| use_emojis: bool = True # Use emojis in LinkedIn posts | |
| posting_frequency: str = "2-3x per week" # daily, 2-3x per week, weekly | |
| # SEO & Positioning | |
| unique_value_proposition: str = ( | |
| "I help companies turn AI research into production-ready solutions" | |
| ) | |
| key_differentiators: list[str] = field( | |
| default_factory=lambda: [ | |
| "Bridging research and production", | |
| "End-to-end AI implementation", | |
| "Business-focused technical expertise", | |
| ] | |
| ) | |
| def to_dict(self) -> dict[str, Any]: | |
| """Convert profile to dictionary for agent context.""" | |
| return { | |
| "name": self.name, | |
| "target_role": self.target_role, | |
| "expertise_areas": self.expertise_areas, | |
| "content_goals": self.content_goals, | |
| "region": self.region, | |
| "languages": self.languages, | |
| "target_industries": self.target_industries, | |
| "github_username": self.github_username, | |
| "linkedin_url": self.linkedin_url, | |
| "portfolio_url": self.portfolio_url, | |
| "kaggle_username": self.kaggle_username, | |
| "notable_projects": self.notable_projects, | |
| "primary_skills": self.primary_skills, | |
| "content_tone": self.content_tone, | |
| "use_emojis": self.use_emojis, | |
| "posting_frequency": self.posting_frequency, | |
| "unique_value_proposition": self.unique_value_proposition, | |
| "key_differentiators": self.key_differentiators, | |
| } | |
| def get_profile_summary(self) -> str: | |
| """Generate a text summary of the profile for agent instructions.""" | |
| expertise_str = ", ".join(self.expertise_areas) | |
| skills_str = ", ".join(self.primary_skills[:5]) | |
| goals_str = ", ".join(self.content_goals) | |
| summary = f""" | |
| **Professional Profile**: | |
| - Role: {self.target_role} | |
| - Expertise: {expertise_str} | |
| - Key Skills: {skills_str} | |
| - Region: {self.region} | |
| - Content Goals: {goals_str} | |
| - Value Proposition: {self.unique_value_proposition} | |
| - Tone: {self.content_tone} | |
| """ | |
| if self.github_username: | |
| summary += f"- GitHub: github.com/{self.github_username}\n" | |
| if self.linkedin_url: | |
| summary += f"- LinkedIn: {self.linkedin_url}\n" | |
| if self.notable_projects and self.notable_projects[0]["name"] != "Project Name": | |
| summary += "\n**Notable Projects to Mention**:\n" | |
| for project in self.notable_projects[:3]: | |
| summary += ( | |
| f"- {project['name']}: {project['description']} ({project['technologies']})\n" | |
| ) | |
| return summary | |
| def validate(self) -> dict[str, list[str]]: | |
| """Validate profile completeness and correctness. | |
| Returns: | |
| Dictionary with 'errors' and 'warnings' lists | |
| """ | |
| errors = [] | |
| warnings = [] | |
| # Validate required fields | |
| if self.name == "Your Name" or not self.name.strip(): | |
| warnings.append("⚠️ Name is not set. Please update 'name' field in profile.yaml") | |
| if not self.expertise_areas or ( | |
| len(self.expertise_areas) == 3 | |
| and self.expertise_areas[0] == "Machine Learning" | |
| and self.expertise_areas[1] == "Artificial Intelligence" | |
| ): | |
| warnings.append( | |
| "⚠️ Using default expertise areas. Update 'expertise_areas' with your specific skills" | |
| ) | |
| # Validate URLs | |
| url_pattern = re.compile( | |
| r"^https?://" # http:// or https:// | |
| r"(?:(?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\.)+[A-Z]{2,6}\.?|" # domain... | |
| r"localhost|" # localhost... | |
| r"\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})" # ...or ip | |
| r"(?::\d+)?" # optional port | |
| r"(?:/?|[/?]\S+)$", | |
| re.IGNORECASE, | |
| ) | |
| if self.linkedin_url and not url_pattern.match(self.linkedin_url): | |
| errors.append( | |
| f"❌ Invalid LinkedIn URL: '{self.linkedin_url}'. Must start with http:// or https://" | |
| ) | |
| if self.portfolio_url and not url_pattern.match(self.portfolio_url): | |
| errors.append( | |
| f"❌ Invalid portfolio URL: '{self.portfolio_url}'. Must start with http:// or https://" | |
| ) | |
| # Validate GitHub username (no special URL validation, just username) | |
| if self.github_username and "/" in self.github_username: | |
| warnings.append( | |
| f"⚠️ GitHub username should be just the username, not a URL: '{self.github_username}'" | |
| ) | |
| # Validate Kaggle username | |
| if self.kaggle_username and "/" in self.kaggle_username: | |
| warnings.append( | |
| f"⚠️ Kaggle username should be just the username, not a URL: '{self.kaggle_username}'" | |
| ) | |
| # Validate content_tone enum | |
| valid_tones = ["professional-formal", "professional-conversational", "technical", "casual"] | |
| if self.content_tone not in valid_tones: | |
| errors.append( | |
| f"❌ Invalid content_tone: '{self.content_tone}'. " | |
| f"Valid options: {', '.join(valid_tones)}" | |
| ) | |
| # Validate content_goals | |
| valid_goals = [ | |
| "opportunities", | |
| "credibility", | |
| "visibility", | |
| "thought-leadership", | |
| "networking", | |
| ] | |
| invalid_goals = [g for g in self.content_goals if g not in valid_goals] | |
| if invalid_goals: | |
| warnings.append( | |
| f"⚠️ Unrecognized content goals: {', '.join(invalid_goals)}. " | |
| f"Valid options: {', '.join(valid_goals)}" | |
| ) | |
| # Validate posting_frequency | |
| valid_frequencies = ["daily", "2-3x per week", "weekly", "biweekly", "monthly"] | |
| if self.posting_frequency not in valid_frequencies: | |
| warnings.append( | |
| f"⚠️ Unrecognized posting frequency: '{self.posting_frequency}'. " | |
| f"Valid options: {', '.join(valid_frequencies)}" | |
| ) | |
| # Validate lists are not empty | |
| if not self.expertise_areas: | |
| errors.append( | |
| "❌ 'expertise_areas' cannot be empty. Add at least one area of expertise" | |
| ) | |
| if not self.primary_skills: | |
| warnings.append("⚠️ 'primary_skills' is empty. Consider adding your technical skills") | |
| if not self.target_industries: | |
| warnings.append("⚠️ 'target_industries' is empty. Consider adding target industries") | |
| # Validate notable_projects structure | |
| for idx, project in enumerate(self.notable_projects): | |
| required_keys = ["name", "description", "technologies", "url"] | |
| missing_keys = [key for key in required_keys if key not in project] | |
| if missing_keys: | |
| warnings.append(f"⚠️ Project {idx + 1} missing keys: {', '.join(missing_keys)}") | |
| # Check if still using default project | |
| if project.get("name") == "Project Name": | |
| warnings.append( | |
| "⚠️ Using default project placeholder. Update 'notable_projects' with your actual projects" | |
| ) | |
| break # Only warn once | |
| # Validate unique_value_proposition | |
| if ( | |
| self.unique_value_proposition | |
| == "I help companies turn AI research into production-ready solutions" | |
| ): | |
| warnings.append( | |
| "⚠️ Using default value proposition. Update 'unique_value_proposition' with your unique offering" | |
| ) | |
| return {"errors": errors, "warnings": warnings} | |
| # Default profile (users should customize this) | |
| DEFAULT_PROFILE = UserProfile() | |
| # Path to user profile configuration | |
| PROFILE_DIR = Path.home() / ".agentic-content-generation" | |
| PROFILE_PATH = PROFILE_DIR / "profile.yaml" | |
| # Ensure directory exists (critical for HF Spaces and first-time setup) | |
| PROFILE_DIR.mkdir(parents=True, exist_ok=True) | |
| def load_profile_from_yaml(path: Path) -> UserProfile: | |
| """Load user profile from YAML file. | |
| Args: | |
| path: Path to the YAML file | |
| Returns: | |
| UserProfile instance | |
| """ | |
| if not path.exists(): | |
| return DEFAULT_PROFILE | |
| try: | |
| with open(path, encoding="utf-8") as f: | |
| data = yaml.safe_load(f) | |
| if not data: | |
| return DEFAULT_PROFILE | |
| # Filter out any keys that don't exist in UserProfile | |
| valid_keys = UserProfile.__annotations__.keys() | |
| filtered_data = {k: v for k, v in data.items() if k in valid_keys} | |
| return UserProfile(**filtered_data) | |
| except Exception as e: | |
| print(f"Warning: Failed to load profile from {path}: {e}") | |
| return DEFAULT_PROFILE | |
| def save_profile_to_yaml(profile: UserProfile, path: Path) -> None: | |
| """Save user profile to YAML file. | |
| Args: | |
| profile: UserProfile instance | |
| path: Path to save the YAML file | |
| """ | |
| # Create directory if it doesn't exist | |
| path.parent.mkdir(parents=True, exist_ok=True) | |
| with open(path, "w", encoding="utf-8") as f: | |
| yaml.dump(profile.to_dict(), f, default_flow_style=False, sort_keys=False) | |
| def load_user_profile(validate: bool = True) -> UserProfile: | |
| """Load user profile from configuration. | |
| Checks ~/.agentic-content-generation/profile.yaml first. | |
| Falls back to default profile if not found. | |
| Args: | |
| validate: Whether to run validation and display warnings/errors | |
| Returns: | |
| UserProfile instance | |
| """ | |
| if PROFILE_PATH.exists(): | |
| print(f"👤 Loading profile from {PROFILE_PATH}") | |
| profile = load_profile_from_yaml(PROFILE_PATH) | |
| else: | |
| print("👤 Using default profile (no custom profile found)") | |
| print(f"💡 Run with --init-profile to create one at {PROFILE_PATH}") | |
| profile = DEFAULT_PROFILE | |
| # Validate profile if requested | |
| if validate: | |
| validation = profile.validate() | |
| errors = validation["errors"] | |
| warnings = validation["warnings"] | |
| if errors: | |
| print("\n❌ Profile Validation Errors:") | |
| for error in errors: | |
| print(f" {error}") | |
| print("\n⚠️ Please fix these errors in your profile.yaml before continuing.\n") | |
| raise ValueError(f"Profile validation failed with {len(errors)} error(s)") | |
| if warnings: | |
| print("\n📋 Profile Validation Warnings:") | |
| for warning in warnings: | |
| print(f" {warning}") | |
| print() | |
| return profile | |
| def create_custom_profile( | |
| name: str, target_role: str, expertise_areas: list[str], **kwargs | |
| ) -> UserProfile: | |
| """Create a custom user profile. | |
| Args: | |
| name: Your name | |
| target_role: Target professional role | |
| expertise_areas: List of expertise areas | |
| **kwargs: Additional profile fields | |
| Returns: | |
| UserProfile instance | |
| """ | |
| return UserProfile( | |
| name=name, target_role=target_role, expertise_areas=expertise_areas, **kwargs | |
| ) | |