Skip to main content
Glama
vitalune

Personal Knowledge Assistant

by vitalune
data_models.py12 kB
""" Data Models for Personal Knowledge Assistant MCP Server This module defines Pydantic models for all data structures used throughout the system. These models ensure type safety, validation, and serialization consistency. """ from datetime import datetime, date from typing import List, Optional, Dict, Any, Union from enum import Enum from pydantic import BaseModel, Field, EmailStr, HttpUrl, validator import uuid class PriorityLevel(str, Enum): """Priority levels for tasks and projects.""" LOW = "low" MEDIUM = "medium" HIGH = "high" URGENT = "urgent" class ProjectStatus(str, Enum): """Project status options.""" PLANNING = "planning" ACTIVE = "active" ON_HOLD = "on_hold" COMPLETED = "completed" CANCELLED = "cancelled" class SocialPlatform(str, Enum): """Supported social media platforms.""" TWITTER = "twitter" LINKEDIN = "linkedin" FACEBOOK = "facebook" INSTAGRAM = "instagram" class MetricType(str, Enum): """Types of personal metrics that can be tracked.""" PRODUCTIVITY = "productivity" HABITS = "habits" GOALS = "goals" MOOD = "mood" ENERGY = "energy" # Email Data Models class EmailAddress(BaseModel): """Represents an email address with optional display name.""" email: EmailStr name: Optional[str] = None def __str__(self) -> str: if self.name: return f"{self.name} <{self.email}>" return str(self.email) class EmailAttachment(BaseModel): """Represents an email attachment.""" filename: str content_type: str size_bytes: int file_path: Optional[str] = None content_id: Optional[str] = None # For inline attachments class EmailMessage(BaseModel): """Represents an email message.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) message_id: Optional[str] = None # External message ID from email provider thread_id: Optional[str] = None # Recipients and sender from_address: EmailAddress to_addresses: List[EmailAddress] cc_addresses: Optional[List[EmailAddress]] = [] bcc_addresses: Optional[List[EmailAddress]] = [] reply_to: Optional[EmailAddress] = None # Content subject: str body_text: Optional[str] = None body_html: Optional[str] = None attachments: Optional[List[EmailAttachment]] = [] # Metadata sent_at: datetime received_at: Optional[datetime] = None read_at: Optional[datetime] = None # Flags and labels is_read: bool = False is_starred: bool = False is_important: bool = False labels: Optional[List[str]] = [] # Analysis fields sentiment_score: Optional[float] = Field(None, ge=-1.0, le=1.0) priority_score: Optional[float] = Field(None, ge=0.0, le=1.0) response_required: Optional[bool] = None class EmailThread(BaseModel): """Represents a conversation thread of emails.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) subject: str participants: List[EmailAddress] messages: List[EmailMessage] created_at: datetime last_message_at: datetime message_count: int # Thread analysis avg_response_time_hours: Optional[float] = None conversation_sentiment: Optional[float] = Field(None, ge=-1.0, le=1.0) # Social Media Data Models class SocialMediaPost(BaseModel): """Represents a social media post.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) platform: SocialPlatform external_id: Optional[str] = None # Platform-specific post ID # Content content: str media_urls: Optional[List[HttpUrl]] = [] hashtags: Optional[List[str]] = [] mentions: Optional[List[str]] = [] # Scheduling and publishing scheduled_at: Optional[datetime] = None published_at: Optional[datetime] = None is_published: bool = False # Engagement metrics likes_count: int = 0 shares_count: int = 0 comments_count: int = 0 clicks_count: int = 0 impressions_count: int = 0 reach_count: int = 0 # Analysis engagement_rate: Optional[float] = Field(None, ge=0.0) sentiment_score: Optional[float] = Field(None, ge=-1.0, le=1.0) performance_score: Optional[float] = Field(None, ge=0.0, le=1.0) class SocialMediaAccount(BaseModel): """Represents a social media account configuration.""" platform: SocialPlatform username: str display_name: Optional[str] = None account_id: Optional[str] = None # Authentication (will be handled by security-privacy-guardian) is_authenticated: bool = False auth_expires_at: Optional[datetime] = None # Account metrics followers_count: Optional[int] = None following_count: Optional[int] = None posts_count: Optional[int] = None # Configuration auto_post_enabled: bool = False optimal_posting_times: Optional[List[str]] = [] # Hour strings like "09:00", "14:30" # Project and Task Management Models class ProjectTask(BaseModel): """Represents a task within a project.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) title: str description: Optional[str] = None # Status and priority is_completed: bool = False priority: PriorityLevel = PriorityLevel.MEDIUM # Dates created_at: datetime = Field(default_factory=datetime.now) due_date: Optional[datetime] = None completed_at: Optional[datetime] = None # Organization tags: Optional[List[str]] = [] assignee: Optional[str] = None # Time tracking estimated_hours: Optional[float] = Field(None, gt=0) actual_hours: Optional[float] = Field(None, gt=0) class Project(BaseModel): """Represents a project with tasks and context.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) name: str description: Optional[str] = None # Status and priority status: ProjectStatus = ProjectStatus.PLANNING priority: PriorityLevel = PriorityLevel.MEDIUM # Dates created_at: datetime = Field(default_factory=datetime.now) start_date: Optional[date] = None due_date: Optional[date] = None completed_at: Optional[datetime] = None # Organization tags: Optional[List[str]] = [] team_members: Optional[List[str]] = [] # Tasks and progress tasks: Optional[List[ProjectTask]] = [] completion_percentage: float = Field(0.0, ge=0.0, le=100.0) # Context and notes notes: Optional[str] = None related_emails: Optional[List[str]] = [] # Email IDs related_documents: Optional[List[str]] = [] # File paths or URLs # Personal Metrics Models class MetricEntry(BaseModel): """Base class for metric entries.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) metric_type: MetricType timestamp: datetime = Field(default_factory=datetime.now) value: Union[float, int, str, bool] notes: Optional[str] = None tags: Optional[List[str]] = [] class ProductivityMetric(MetricEntry): """Productivity-specific metric entry.""" metric_type: MetricType = MetricType.PRODUCTIVITY # Productivity-specific fields hours_worked: Optional[float] = Field(None, ge=0) tasks_completed: Optional[int] = Field(None, ge=0) focus_score: Optional[float] = Field(None, ge=0.0, le=10.0) interruptions_count: Optional[int] = Field(None, ge=0) class HabitMetric(MetricEntry): """Habit tracking metric entry.""" metric_type: MetricType = MetricType.HABITS # Habit-specific fields habit_name: str completed: bool streak_count: Optional[int] = Field(None, ge=0) target_frequency: Optional[str] = None # e.g., "daily", "weekly" class GoalMetric(MetricEntry): """Goal tracking metric entry.""" metric_type: MetricType = MetricType.GOALS # Goal-specific fields goal_name: str current_value: float target_value: float unit: Optional[str] = None deadline: Optional[date] = None @validator('current_value', 'target_value') def validate_values(cls, v): if v < 0: raise ValueError('Values must be non-negative') return v class MoodMetric(MetricEntry): """Mood tracking metric entry.""" metric_type: MetricType = MetricType.MOOD # Mood-specific fields mood_score: float = Field(ge=1.0, le=10.0) # 1-10 scale energy_level: Optional[float] = Field(None, ge=1.0, le=10.0) stress_level: Optional[float] = Field(None, ge=1.0, le=10.0) sleep_hours: Optional[float] = Field(None, ge=0, le=24) weather: Optional[str] = None activities: Optional[List[str]] = [] # Communication Pattern Models class CommunicationPattern(BaseModel): """Represents patterns in communication behavior.""" contact: str # Email address or social media handle contact_type: str # "email" or social platform name # Temporal patterns avg_response_time_hours: Optional[float] = Field(None, ge=0) preferred_contact_hours: Optional[List[int]] = [] # Hours 0-23 preferred_contact_days: Optional[List[int]] = [] # Days 0-6 (Monday=0) # Communication frequency messages_per_week: Optional[float] = Field(None, ge=0) initiated_conversations_ratio: Optional[float] = Field(None, ge=0.0, le=1.0) # Content analysis avg_message_length: Optional[float] = Field(None, ge=0) common_topics: Optional[List[str]] = [] sentiment_trend: Optional[float] = Field(None, ge=-1.0, le=1.0) # Relationship insights relationship_strength: Optional[float] = Field(None, ge=0.0, le=1.0) communication_style: Optional[str] = None # e.g., "formal", "casual", "technical" # Time-based data first_contact_date: Optional[date] = None last_contact_date: Optional[date] = None analysis_period_start: date analysis_period_end: date # Report and Analysis Models class InsightReport(BaseModel): """Represents a generated insights report.""" id: str = Field(default_factory=lambda: str(uuid.uuid4())) report_type: str title: str # Generation metadata generated_at: datetime = Field(default_factory=datetime.now) period_start: date period_end: date data_sources: List[str] # Content summary: str sections: Dict[str, Any] # Flexible structure for different report types recommendations: Optional[List[str]] = [] key_metrics: Optional[Dict[str, Any]] = {} # Export options format: str = "markdown" # markdown, html, json, pdf file_path: Optional[str] = None # Utility Models class TimeRange(BaseModel): """Represents a time range for queries and analysis.""" start: datetime end: datetime @validator('end') def end_after_start(cls, v, values): if 'start' in values and v <= values['start']: raise ValueError('End time must be after start time') return v class DataFilter(BaseModel): """Generic filter for data queries.""" field: str operator: str # eq, ne, gt, lt, gte, lte, in, contains value: Any @validator('operator') def valid_operator(cls, v): valid_ops = {'eq', 'ne', 'gt', 'lt', 'gte', 'lte', 'in', 'contains', 'startswith', 'endswith'} if v not in valid_ops: raise ValueError(f'Operator must be one of: {valid_ops}') return v class QueryParams(BaseModel): """Parameters for data queries.""" filters: Optional[List[DataFilter]] = [] time_range: Optional[TimeRange] = None sort_by: Optional[str] = None sort_order: str = "asc" # asc or desc limit: Optional[int] = Field(None, gt=0, le=10000) offset: int = Field(0, ge=0) @validator('sort_order') def valid_sort_order(cls, v): if v not in ['asc', 'desc']: raise ValueError('Sort order must be "asc" or "desc"') return v

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/vitalune/Nexus-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server