BladeSzaSza's picture
🥚 Initial DigiPal deployment to HuggingFace Spaces🤖 Generated with [Claude Code](https://claude.ai/code)Co-Authored-By: Claude <noreply@anthropic.com>
4399e64
"""
Core data models for DigiPal application.
"""
from dataclasses import dataclass, field
from datetime import datetime
from typing import Dict, List, Optional, Set, Any
import json
import uuid
from .enums import EggType, LifeStage, CareActionType, AttributeType, CommandType, InteractionResult
@dataclass
class DigiPal:
"""
Core DigiPal model representing a digital pet with all attributes and lifecycle properties.
"""
# Identity and Basic Info
id: str = field(default_factory=lambda: str(uuid.uuid4()))
user_id: str = ""
name: str = "DigiPal"
egg_type: EggType = EggType.RED
life_stage: LifeStage = LifeStage.EGG
generation: int = 1
# Primary Attributes (Digimon World 1 inspired)
hp: int = 100
mp: int = 50
offense: int = 10
defense: int = 10
speed: int = 10
brains: int = 10
# Secondary Attributes
discipline: int = 0
happiness: int = 50
weight: int = 20
care_mistakes: int = 0
energy: int = 100
# Lifecycle Management
birth_time: datetime = field(default_factory=datetime.now)
last_interaction: datetime = field(default_factory=datetime.now)
evolution_timer: float = 0.0 # Hours until next evolution check
# Memory and Context
conversation_history: List['Interaction'] = field(default_factory=list)
learned_commands: Set[str] = field(default_factory=set)
personality_traits: Dict[str, float] = field(default_factory=dict)
# Visual Representation
current_image_path: str = ""
image_generation_prompt: str = ""
def __post_init__(self):
"""Initialize DigiPal with egg-type specific attributes."""
if self.life_stage == LifeStage.EGG:
self._initialize_egg_attributes()
# Initialize basic learned commands for baby stage
if self.life_stage == LifeStage.BABY:
self.learned_commands = {"eat", "sleep", "good", "bad"}
def _initialize_egg_attributes(self):
"""Set initial attributes based on egg type."""
base_attributes = {
EggType.RED: {
'offense': 15,
'defense': 8,
'speed': 12,
'brains': 8,
'hp': 90,
'mp': 40
},
EggType.BLUE: {
'offense': 8,
'defense': 15,
'speed': 8,
'brains': 12,
'hp': 110,
'mp': 60
},
EggType.GREEN: {
'offense': 10,
'defense': 12,
'speed': 10,
'brains': 10,
'hp': 120,
'mp': 50
}
}
if self.egg_type in base_attributes:
attrs = base_attributes[self.egg_type]
for attr, value in attrs.items():
setattr(self, attr, value)
def get_age_hours(self) -> float:
"""Calculate age in hours since birth."""
return (datetime.now() - self.birth_time).total_seconds() / 3600
def get_attribute(self, attribute: AttributeType) -> int:
"""Get attribute value by type."""
return getattr(self, attribute.value, 0)
def set_attribute(self, attribute: AttributeType, value: int):
"""Set attribute value with bounds checking."""
# Define attribute bounds
bounds = {
AttributeType.HP: (1, 999),
AttributeType.MP: (0, 999),
AttributeType.OFFENSE: (0, 999),
AttributeType.DEFENSE: (0, 999),
AttributeType.SPEED: (0, 999),
AttributeType.BRAINS: (0, 999),
AttributeType.DISCIPLINE: (0, 100),
AttributeType.HAPPINESS: (0, 100),
AttributeType.WEIGHT: (1, 99),
AttributeType.CARE_MISTAKES: (0, 999),
AttributeType.ENERGY: (0, 100)
}
min_val, max_val = bounds.get(attribute, (0, 999))
clamped_value = max(min_val, min(max_val, value))
setattr(self, attribute.value, clamped_value)
def modify_attribute(self, attribute: AttributeType, change: int):
"""Modify attribute by a delta amount."""
current_value = self.get_attribute(attribute)
self.set_attribute(attribute, current_value + change)
def can_understand_command(self, command: str) -> bool:
"""Check if DigiPal can understand a command based on life stage."""
stage_commands = {
LifeStage.EGG: set(),
LifeStage.BABY: {"eat", "sleep", "good", "bad"},
LifeStage.CHILD: {"eat", "sleep", "good", "bad", "play", "train"},
LifeStage.TEEN: {"eat", "sleep", "good", "bad", "play", "train", "status", "talk"},
LifeStage.YOUNG_ADULT: {"eat", "sleep", "good", "bad", "play", "train", "status", "talk", "battle"},
LifeStage.ADULT: {"eat", "sleep", "good", "bad", "play", "train", "status", "talk", "battle", "teach"},
LifeStage.ELDERLY: {"eat", "sleep", "good", "bad", "play", "train", "status", "talk", "battle", "teach", "wisdom"}
}
available_commands = stage_commands.get(self.life_stage, set())
return command.lower() in available_commands or command.lower() in self.learned_commands
def to_dict(self) -> Dict[str, Any]:
"""Convert DigiPal to dictionary for serialization."""
return {
'id': self.id,
'user_id': self.user_id,
'name': self.name,
'egg_type': self.egg_type.value,
'life_stage': self.life_stage.value,
'generation': self.generation,
'hp': self.hp,
'mp': self.mp,
'offense': self.offense,
'defense': self.defense,
'speed': self.speed,
'brains': self.brains,
'discipline': self.discipline,
'happiness': self.happiness,
'weight': self.weight,
'care_mistakes': self.care_mistakes,
'energy': self.energy,
'birth_time': self.birth_time.isoformat(),
'last_interaction': self.last_interaction.isoformat(),
'evolution_timer': self.evolution_timer,
'conversation_history': [interaction.to_dict() for interaction in self.conversation_history],
'learned_commands': list(self.learned_commands),
'personality_traits': self.personality_traits,
'current_image_path': self.current_image_path,
'image_generation_prompt': self.image_generation_prompt
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'DigiPal':
"""Create DigiPal from dictionary."""
# Convert string enums back to enum objects
data['egg_type'] = EggType(data['egg_type'])
data['life_stage'] = LifeStage(data['life_stage'])
# Convert ISO strings back to datetime objects
data['birth_time'] = datetime.fromisoformat(data['birth_time'])
data['last_interaction'] = datetime.fromisoformat(data['last_interaction'])
# Convert conversation history
data['conversation_history'] = [
Interaction.from_dict(interaction_data)
for interaction_data in data.get('conversation_history', [])
]
# Convert learned commands to set
data['learned_commands'] = set(data.get('learned_commands', []))
return cls(**data)
@dataclass
class Interaction:
"""Represents a single interaction between user and DigiPal."""
timestamp: datetime = field(default_factory=datetime.now)
user_input: str = ""
interpreted_command: str = ""
pet_response: str = ""
attribute_changes: Dict[str, int] = field(default_factory=dict)
success: bool = True
result: InteractionResult = InteractionResult.SUCCESS
def to_dict(self) -> Dict[str, Any]:
"""Convert Interaction to dictionary."""
return {
'timestamp': self.timestamp.isoformat(),
'user_input': self.user_input,
'interpreted_command': self.interpreted_command,
'pet_response': self.pet_response,
'attribute_changes': self.attribute_changes,
'success': self.success,
'result': self.result.value
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Interaction':
"""Create Interaction from dictionary."""
data['timestamp'] = datetime.fromisoformat(data['timestamp'])
data['result'] = InteractionResult(data['result'])
return cls(**data)
@dataclass
class Command:
"""Represents a parsed command from user input."""
action: str = ""
parameters: Dict[str, Any] = field(default_factory=dict)
stage_appropriate: bool = True
energy_required: int = 0
command_type: CommandType = CommandType.UNKNOWN
def to_dict(self) -> Dict[str, Any]:
"""Convert Command to dictionary."""
return {
'action': self.action,
'parameters': self.parameters,
'stage_appropriate': self.stage_appropriate,
'energy_required': self.energy_required,
'command_type': self.command_type.value
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'Command':
"""Create Command from dictionary."""
data['command_type'] = CommandType(data['command_type'])
return cls(**data)
@dataclass
class AttributeModifier:
"""Represents a modification to DigiPal attributes."""
attribute: AttributeType
change: int
conditions: List[str] = field(default_factory=list)
def to_dict(self) -> Dict[str, Any]:
"""Convert AttributeModifier to dictionary."""
return {
'attribute': self.attribute.value,
'change': self.change,
'conditions': self.conditions
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'AttributeModifier':
"""Create AttributeModifier from dictionary."""
data['attribute'] = AttributeType(data['attribute'])
return cls(**data)
@dataclass
class CareAction:
"""Represents a care action that can be performed on DigiPal."""
name: str
action_type: CareActionType
energy_cost: int
happiness_change: int
attribute_modifiers: List[AttributeModifier] = field(default_factory=list)
success_conditions: List[str] = field(default_factory=list)
failure_effects: List[AttributeModifier] = field(default_factory=list)
def to_dict(self) -> Dict[str, Any]:
"""Convert CareAction to dictionary."""
return {
'name': self.name,
'action_type': self.action_type.value,
'energy_cost': self.energy_cost,
'happiness_change': self.happiness_change,
'attribute_modifiers': [mod.to_dict() for mod in self.attribute_modifiers],
'success_conditions': self.success_conditions,
'failure_effects': [mod.to_dict() for mod in self.failure_effects]
}
@classmethod
def from_dict(cls, data: Dict[str, Any]) -> 'CareAction':
"""Create CareAction from dictionary."""
data['action_type'] = CareActionType(data['action_type'])
data['attribute_modifiers'] = [
AttributeModifier.from_dict(mod_data)
for mod_data in data.get('attribute_modifiers', [])
]
data['failure_effects'] = [
AttributeModifier.from_dict(mod_data)
for mod_data in data.get('failure_effects', [])
]
return cls(**data)