Add personality system with emote variations and animations
- Rotating optimal faces with paired animations (breathing, floating, bouncing, swaying) - Occasional idle expressions (winks/blinks) with 15% chance - Recovery celebration emote with bounce animation - Connection lost state with searching animation - Face rotation every 5 minutes Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,6 +4,7 @@ A lightweight event broker that manages priority-based system status.
|
||||
"""
|
||||
|
||||
import json
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from datetime import datetime
|
||||
@@ -16,6 +17,22 @@ ROOT_DIR = Path(__file__).parent
|
||||
# Configuration
|
||||
STATUS_FILE = Path(__file__).parent / "status.json"
|
||||
DEFAULT_NOTIFY_TTL = 10 # Default TTL for Priority 3 (Notify) events
|
||||
CELEBRATION_DURATION = 5 # Seconds to show celebration after recovery
|
||||
|
||||
# Emote variations with paired animations
|
||||
OPTIMAL_EMOTES = [
|
||||
("( ^_^)", "breathing"), # calm, content
|
||||
("( ᵔᴥᵔ)", "floating"), # dreamy
|
||||
("(◕‿◕)", "bouncing"), # cheerful
|
||||
("( ・ω・)", "swaying"), # curious
|
||||
("( ˘▽˘)", "breathing"), # cozy
|
||||
]
|
||||
IDLE_EMOTES = [
|
||||
("( -_^)", "blink"), # wink
|
||||
("( ^_~)", "blink"), # wink
|
||||
("( ᵕ.ᵕ)", "blink"), # blink
|
||||
]
|
||||
CELEBRATION_EMOTE = ("\\(^o^)/", "celebrating")
|
||||
|
||||
# Priority definitions
|
||||
PRIORITY_CONFIG = {
|
||||
@@ -29,9 +46,20 @@ PRIORITY_CONFIG = {
|
||||
events_lock = threading.Lock()
|
||||
active_events = {} # id -> {priority, message, timestamp, ttl}
|
||||
|
||||
# State tracking for personality
|
||||
previous_priority = 4
|
||||
celebrating_until = 0
|
||||
last_emote_change = 0
|
||||
current_optimal_emote = OPTIMAL_EMOTES[0][0]
|
||||
current_optimal_animation = OPTIMAL_EMOTES[0][1]
|
||||
|
||||
|
||||
def get_current_state():
|
||||
"""Determine current state based on active events."""
|
||||
global previous_priority, celebrating_until, last_emote_change, current_optimal_emote, current_optimal_animation
|
||||
|
||||
now = time.time()
|
||||
|
||||
with events_lock:
|
||||
if not active_events:
|
||||
priority = 4
|
||||
@@ -45,11 +73,38 @@ def get_current_state():
|
||||
]
|
||||
|
||||
config = PRIORITY_CONFIG[priority]
|
||||
emote = config["emote"]
|
||||
animation = config["animation"]
|
||||
color = config["color"]
|
||||
|
||||
# Check for recovery (was bad, now optimal)
|
||||
if priority == 4 and previous_priority < 4:
|
||||
celebrating_until = now + CELEBRATION_DURATION
|
||||
|
||||
previous_priority = priority
|
||||
|
||||
# Handle optimal state personality
|
||||
if priority == 4:
|
||||
if now < celebrating_until:
|
||||
# Celebration mode
|
||||
emote, animation = CELEBRATION_EMOTE
|
||||
else:
|
||||
# Rotate optimal emotes every 5 minutes, occasional idle expression
|
||||
if now - last_emote_change > 300:
|
||||
last_emote_change = now
|
||||
# 15% chance of an idle expression (wink/blink)
|
||||
if random.random() < 0.15:
|
||||
current_optimal_emote, current_optimal_animation = random.choice(IDLE_EMOTES)
|
||||
else:
|
||||
current_optimal_emote, current_optimal_animation = random.choice(OPTIMAL_EMOTES)
|
||||
emote = current_optimal_emote
|
||||
animation = current_optimal_animation
|
||||
|
||||
return {
|
||||
"current_state": config["name"].lower(),
|
||||
"active_emote": config["emote"],
|
||||
"color": config["color"],
|
||||
"animation": config["animation"],
|
||||
"active_emote": emote,
|
||||
"color": color,
|
||||
"animation": animation,
|
||||
"message": config["name"] if priority == 4 else f"{config['name']} state active",
|
||||
"active_events": sorted(events_list, key=lambda x: x["priority"]),
|
||||
"last_updated": datetime.now().isoformat(timespec="seconds"),
|
||||
|
||||
Reference in New Issue
Block a user