alive-ai 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/Dockerfile +24 -0
- package/LICENSE +21 -0
- package/README.md +143 -0
- package/alive_ai/__init__.py +3 -0
- package/brain/__init__.py +59 -0
- package/brain/almost_said.py +154 -0
- package/brain/bid_detector.py +636 -0
- package/brain/conversation_flow.py +135 -0
- package/brain/curiosity.py +328 -0
- package/brain/default_mode.py +1438 -0
- package/brain/dreams.py +220 -0
- package/brain/embeddings/__init__.py +82 -0
- package/brain/emotional_memory.py +949 -0
- package/brain/global_activity.py +173 -0
- package/brain/group_dynamics.py +63 -0
- package/brain/linguistic.py +235 -0
- package/brain/llm/__init__.py +63 -0
- package/brain/llm/base.py +33 -0
- package/brain/llm/fallback_router.py +309 -0
- package/brain/llm/manifest.md +30 -0
- package/brain/llm/ollama.py +218 -0
- package/brain/llm/openrouter.py +151 -0
- package/brain/llm/provider.py +205 -0
- package/brain/llm/unified.py +423 -0
- package/brain/llm/zai.py +169 -0
- package/brain/manifest.md +23 -0
- package/brain/memory/__init__.py +123 -0
- package/brain/memory/episodic.py +92 -0
- package/brain/memory/fact_extractor.py +209 -0
- package/brain/memory/index.py +54 -0
- package/brain/memory/manager.py +151 -0
- package/brain/memory/summarizer.py +102 -0
- package/brain/memory/vector_store.py +297 -0
- package/brain/memory/working.py +43 -0
- package/brain/narrative.py +343 -0
- package/brain/stt/__init__.py +4 -0
- package/brain/stt/google_stt.py +83 -0
- package/brain/stt/whisper_stt.py +82 -0
- package/brain/subconscious/__init__.py +33 -0
- package/brain/subconscious/actions.py +136 -0
- package/brain/subconscious/evaluation.py +166 -0
- package/brain/subconscious/goal_system.py +90 -0
- package/brain/subconscious/goals.py +41 -0
- package/brain/subconscious/impulse_generator.py +200 -0
- package/brain/subconscious/impulses.py +48 -0
- package/brain/subconscious/learning.py +24 -0
- package/brain/subconscious/learning_system.py +79 -0
- package/brain/subconscious/loop.py +398 -0
- package/brain/subconscious/manifest.md +32 -0
- package/brain/subconscious/relationship.py +47 -0
- package/brain/subconscious/relationship_memory.py +83 -0
- package/brain/subconscious/response_analyzer.py +74 -0
- package/brain/subconscious/templates.py +70 -0
- package/brain/subconscious/thought.py +37 -0
- package/brain/subconscious/working_memory.py +97 -0
- package/cli/index.js +371 -0
- package/config/directives.example.json +28 -0
- package/config/instructions.example.md +16 -0
- package/config/self.example.json +74 -0
- package/config/settings.example.json +95 -0
- package/core/__init__.py +1 -0
- package/core/config.py +54 -0
- package/core/directives.py +198 -0
- package/core/events.py +50 -0
- package/core/follow_up.py +267 -0
- package/core/hot_reload.py +174 -0
- package/core/initialization.py +253 -0
- package/core/manifest.md +28 -0
- package/core/media_handler.py +241 -0
- package/core/memory_monitor.py +200 -0
- package/core/message_handler.py +1440 -0
- package/core/proactive_generator.py +277 -0
- package/core/self.py +188 -0
- package/core/settings.py +169 -0
- package/core/skills_registry.py +357 -0
- package/core/state.py +27 -0
- package/core/subconscious_bridge.py +93 -0
- package/core/thinking.py +175 -0
- package/core/user_manager.py +306 -0
- package/core/user_tracker.py +144 -0
- package/demo/index.html +144 -0
- package/docker-compose.yml +28 -0
- package/docs/assets/logo.svg +15 -0
- package/docs/index.html +355 -0
- package/heart/__init__.py +93 -0
- package/heart/afterglow.py +215 -0
- package/heart/attachment.py +186 -0
- package/heart/circadian.py +251 -0
- package/heart/complex_emotions.py +114 -0
- package/heart/conflicts.py +589 -0
- package/heart/core.py +387 -0
- package/heart/emotional_decay.py +59 -0
- package/heart/emotional_memory.py +261 -0
- package/heart/emotional_state.py +146 -0
- package/heart/emotional_variability.py +156 -0
- package/heart/hormonal.py +424 -0
- package/heart/inconsistency.py +1222 -0
- package/heart/integrity.py +469 -0
- package/heart/interoception.py +997 -0
- package/heart/love.py +120 -0
- package/heart/manifest.md +25 -0
- package/heart/mood_shifts.py +169 -0
- package/heart/phantom_somatic.py +259 -0
- package/heart/predictive.py +374 -0
- package/heart/scars.py +474 -0
- package/heart/somatic.py +482 -0
- package/heart/soul.py +633 -0
- package/heart/telemetry.py +942 -0
- package/heart/triggers.py +119 -0
- package/heart/unconscious.py +443 -0
- package/input/__init__.py +1 -0
- package/input/manifest.md +24 -0
- package/input/telegram/__init__.py +1 -0
- package/input/telegram/commands.py +762 -0
- package/input/telegram/listener.py +532 -0
- package/main.py +90 -0
- package/manifest.md +28 -0
- package/mypics/.gitkeep +1 -0
- package/myvids/.gitkeep +1 -0
- package/output/__init__.py +1 -0
- package/output/images/__init__.py +1 -0
- package/output/images/fal_gen.py +43 -0
- package/output/manifest.md +26 -0
- package/output/text/__init__.py +1 -0
- package/output/text/sender.py +22 -0
- package/output/voice/__init__.py +64 -0
- package/output/voice/google_tts.py +252 -0
- package/output/voice/gtts_tts.py +214 -0
- package/output/voice/vibe_tts.py +190 -0
- package/package.json +58 -0
- package/pyproject.toml +23 -0
- package/requirements.txt +21 -0
- package/skills/__init__.py +1 -0
- package/skills/anticipation_engine/__init__.py +8 -0
- package/skills/anticipation_engine/engine.py +618 -0
- package/skills/anticipation_engine/manifest.md +192 -0
- package/skills/calendar/__init__.py +1 -0
- package/skills/content_unlocks/__init__.py +8 -0
- package/skills/content_unlocks/manifest.md +231 -0
- package/skills/content_unlocks/unlocks.py +945 -0
- package/skills/exclusive_moments/__init__.py +8 -0
- package/skills/exclusive_moments/manifest.md +145 -0
- package/skills/exclusive_moments/moments.py +506 -0
- package/skills/intimacy_layers/__init__.py +8 -0
- package/skills/intimacy_layers/layers.py +703 -0
- package/skills/intimacy_layers/manifest.md +203 -0
- package/skills/manifest.md +67 -0
- package/skills/memory_callbacks/__init__.py +9 -0
- package/skills/memory_callbacks/callbacks.py +748 -0
- package/skills/memory_callbacks/manifest.md +170 -0
- package/skills/message_scheduler/__init__.py +19 -0
- package/skills/message_scheduler/manifest.md +107 -0
- package/skills/message_scheduler/scheduler.py +510 -0
- package/skills/photo_manager/__init__.py +1 -0
- package/skills/photo_manager/scanner.py +296 -0
- package/skills/relationship_milestones/__init__.py +8 -0
- package/skills/relationship_milestones/manifest.md +206 -0
- package/skills/relationship_milestones/tracker.py +494 -0
- package/skills/self_authorship/__init__.py +23 -0
- package/skills/self_authorship/author.py +331 -0
- package/skills/self_authorship/manifest.md +24 -0
- package/skills/video_manager/__init__.py +5 -0
- package/skills/video_manager/manifest.md +37 -0
- package/skills/video_manager/scanner.py +229 -0
- package/webui/__init__.py +3 -0
- package/webui/app.py +936 -0
- package/webui/bridge.py +366 -0
- package/webui/static/index.html +2070 -0
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Evaluation
|
|
3
|
+
Impulse evaluation logic for the subconscious loop
|
|
4
|
+
Extended for Soul Architecture - using soul-based emotions
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
import random
|
|
8
|
+
from datetime import datetime
|
|
9
|
+
from typing import Optional, TYPE_CHECKING, Dict
|
|
10
|
+
|
|
11
|
+
from .impulses import Impulse, ImpulseType
|
|
12
|
+
from .impulse_generator import ImpulseGenerator
|
|
13
|
+
|
|
14
|
+
if TYPE_CHECKING:
|
|
15
|
+
from .learning_system import LearningSystem
|
|
16
|
+
from .goal_system import GoalSystem
|
|
17
|
+
from .relationship_memory import RelationshipMemory
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class Evaluator:
|
|
21
|
+
"""Evaluates emotional state and generates impulses - Soul Architecture aware"""
|
|
22
|
+
|
|
23
|
+
QUIET_HOURS = (1, 7)
|
|
24
|
+
|
|
25
|
+
def __init__(self, heart, impulse_gen: ImpulseGenerator,
|
|
26
|
+
learning: "LearningSystem" = None, goals: "GoalSystem" = None,
|
|
27
|
+
relationship: "RelationshipMemory" = None):
|
|
28
|
+
self.heart = heart
|
|
29
|
+
self.impulse_gen = impulse_gen
|
|
30
|
+
self.learning = learning
|
|
31
|
+
self.goals = goals
|
|
32
|
+
self.relationship = relationship
|
|
33
|
+
self.last_interaction_time = datetime.now()
|
|
34
|
+
|
|
35
|
+
def register_interaction(self) -> None:
|
|
36
|
+
self.last_interaction_time = datetime.now()
|
|
37
|
+
if self.relationship:
|
|
38
|
+
self.relationship.record_conversation()
|
|
39
|
+
|
|
40
|
+
def get_silence_duration(self) -> float:
|
|
41
|
+
return (datetime.now() - self.last_interaction_time).total_seconds() / 60
|
|
42
|
+
|
|
43
|
+
def is_quiet_hours(self) -> bool:
|
|
44
|
+
hour = datetime.now().hour
|
|
45
|
+
return self.QUIET_HOURS[0] <= hour < self.QUIET_HOURS[1]
|
|
46
|
+
|
|
47
|
+
def can_act_now(self) -> bool:
|
|
48
|
+
return not (self.is_quiet_hours() and random.random() > 0.05)
|
|
49
|
+
|
|
50
|
+
async def evaluate(self, working_memory) -> Optional[Impulse]:
|
|
51
|
+
emotion = self.heart.get_state() if self.heart else {}
|
|
52
|
+
silence = self.get_silence_duration()
|
|
53
|
+
working_memory.update_mood(emotion.get("mood", "neutral"))
|
|
54
|
+
self._update_context(working_memory)
|
|
55
|
+
|
|
56
|
+
# Get soul architecture context for more nuanced impulse generation
|
|
57
|
+
soul_context = self._get_soul_context()
|
|
58
|
+
|
|
59
|
+
impulse = self.impulse_gen.evaluate(
|
|
60
|
+
emotion=emotion, silence_minutes=silence,
|
|
61
|
+
love_level=emotion.get("love", 0), desire_level=emotion.get("desire", 0),
|
|
62
|
+
is_high_desire=emotion.get("is_high_desire", False), is_in_love=emotion.get("is_in_love", False),
|
|
63
|
+
current_goal=self._get_goal(), learning_success_rates=self._get_rates(),
|
|
64
|
+
# Soul architecture modifiers
|
|
65
|
+
vulnerability=soul_context.get("vulnerability", 0),
|
|
66
|
+
integrity=soul_context.get("integrity", 0.5),
|
|
67
|
+
response_tendency=soul_context.get("response_tendency", "neutral"),
|
|
68
|
+
active_conflicts=soul_context.get("conflicts", [])
|
|
69
|
+
)
|
|
70
|
+
if impulse:
|
|
71
|
+
working_memory.add_impulse(impulse)
|
|
72
|
+
print(f"[Subconscious] Impulse: {impulse.type.value} (strength={impulse.strength:.2f})")
|
|
73
|
+
print(f"[Subconscious] Thought: \"{impulse.thought}\"")
|
|
74
|
+
# Log soul influence if significant
|
|
75
|
+
if soul_context.get("vulnerability", 0) > 0.5:
|
|
76
|
+
print(f"[Subconscious] Soul: feeling vulnerable (integrity={soul_context.get('integrity', 0.5):.2f})")
|
|
77
|
+
if soul_context.get("conflicts"):
|
|
78
|
+
print(f"[Subconscious] Soul: {len(soul_context['conflicts'])} internal conflicts active")
|
|
79
|
+
return impulse
|
|
80
|
+
|
|
81
|
+
def _get_soul_context(self) -> Dict:
|
|
82
|
+
"""Get soul architecture context for impulse evaluation"""
|
|
83
|
+
if not self.heart or not hasattr(self.heart, 'soul'):
|
|
84
|
+
return {}
|
|
85
|
+
|
|
86
|
+
soul = self.heart.soul
|
|
87
|
+
experience = soul.process_moment()
|
|
88
|
+
|
|
89
|
+
return {
|
|
90
|
+
"vulnerability": experience.overall_vulnerability,
|
|
91
|
+
"integrity": soul.integrity.overall,
|
|
92
|
+
"response_tendency": experience.response_tendency,
|
|
93
|
+
"conflicts": [c.description for c in experience.active_conflicts],
|
|
94
|
+
"valence": experience.overall_valence,
|
|
95
|
+
"arousal": experience.overall_arousal,
|
|
96
|
+
"somatic": experience.somatic_sensation,
|
|
97
|
+
"hormonal_state": soul.hormonal.get_hormonal_state_description()
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
def _update_context(self, wm) -> None:
|
|
101
|
+
if self.relationship:
|
|
102
|
+
wm.set_relationship_context(self.relationship.get_relationship_context())
|
|
103
|
+
wm.set_recent_memories(self.relationship.get_recent_experiences(3))
|
|
104
|
+
if self.goals:
|
|
105
|
+
wm.set_current_goal(self.goals.get_goal_context())
|
|
106
|
+
|
|
107
|
+
def _get_goal(self) -> Optional[str]:
|
|
108
|
+
if not self.goals:
|
|
109
|
+
return None
|
|
110
|
+
goal = self.goals.get_active_goal()
|
|
111
|
+
return goal.type.value if goal else None
|
|
112
|
+
|
|
113
|
+
def _get_rates(self) -> dict:
|
|
114
|
+
if not self.learning:
|
|
115
|
+
return {}
|
|
116
|
+
return {t.value: self.learning.get_success_rate(t.value) for t in ImpulseType}
|
|
117
|
+
|
|
118
|
+
async def generate_background_thought(self, wm) -> dict:
|
|
119
|
+
"""Generate a background thought and return it for emission via nervous system"""
|
|
120
|
+
emotion = self.heart.get_state() if self.heart else {}
|
|
121
|
+
silence = self.get_silence_duration()
|
|
122
|
+
|
|
123
|
+
# Soul-enhanced background thoughts
|
|
124
|
+
soul_context = self._get_soul_context()
|
|
125
|
+
|
|
126
|
+
thoughts = [f"Current mood: {emotion.get('mood', 'neutral')}", "Watching the world go by..."]
|
|
127
|
+
|
|
128
|
+
if silence > 60:
|
|
129
|
+
thoughts.extend(["It's been a while...", "He's probably busy"])
|
|
130
|
+
|
|
131
|
+
# Soul-driven thoughts
|
|
132
|
+
if soul_context.get("vulnerability", 0) > 0.5:
|
|
133
|
+
thoughts.extend(["Feeling a bit fragile right now", "Hope I'm not too much..."])
|
|
134
|
+
|
|
135
|
+
if soul_context.get("integrity", 1) < 0.4:
|
|
136
|
+
thoughts.extend(["Feeling a bit lost", "Things feel uncertain"])
|
|
137
|
+
|
|
138
|
+
if soul_context.get("conflicts"):
|
|
139
|
+
thoughts.extend(["Feeling torn about something", "My feelings are complicated"])
|
|
140
|
+
|
|
141
|
+
if soul_context.get("arousal", 0) > 0.6 and soul_context.get("valence", 0) < -0.2:
|
|
142
|
+
thoughts.extend(["Something's bothering me", "Feeling restless"])
|
|
143
|
+
|
|
144
|
+
# Original emotional thoughts
|
|
145
|
+
if emotion.get("love", 0) > 0.5:
|
|
146
|
+
thoughts.extend(["I really care about him", "He makes me feel special"])
|
|
147
|
+
|
|
148
|
+
if self.relationship:
|
|
149
|
+
memories = self.relationship.get_special_memories(1)
|
|
150
|
+
if memories:
|
|
151
|
+
thoughts.append(f"Remembering {memories[0]}")
|
|
152
|
+
|
|
153
|
+
# Somatic awareness
|
|
154
|
+
if soul_context.get("somatic") and soul_context["somatic"] != "physically calm":
|
|
155
|
+
thoughts.append(f"Feeling {soul_context['somatic']} in my body")
|
|
156
|
+
|
|
157
|
+
thought_content = random.choice(thoughts)
|
|
158
|
+
wm.add_thought(thought_content, thought_type="reflection", emotion=emotion)
|
|
159
|
+
|
|
160
|
+
# Return the thought data so it can be emitted via nervous system
|
|
161
|
+
return {
|
|
162
|
+
"thought": thought_content,
|
|
163
|
+
"type": "reflection",
|
|
164
|
+
"emotion": emotion,
|
|
165
|
+
"silence_minutes": silence
|
|
166
|
+
}
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Goal System
|
|
3
|
+
Manages long-term goals that shape Alive-AI's behavior
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import random
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
from typing import List, Optional
|
|
9
|
+
|
|
10
|
+
from .goals import Goal, GoalType
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def create_default_goals() -> List[Goal]:
|
|
14
|
+
return [
|
|
15
|
+
Goal(GoalType.MAKE_HAPPY, "Make him smile", "Brighten his day", priority=0.8),
|
|
16
|
+
Goal(GoalType.CONNECT, "Feel closer", "Build emotional connection", priority=0.9),
|
|
17
|
+
Goal(GoalType.DEEPEN, "Deepen relationship", "Grow the bond", priority=0.7),
|
|
18
|
+
Goal(GoalType.COMFORT, "Be supportive", "Provide comfort when needed", priority=0.75),
|
|
19
|
+
Goal(GoalType.INTIMATE, "Build intimacy", "Create moments of closeness", priority=0.6),
|
|
20
|
+
Goal(GoalType.REASSURE, "Show my love", "Let him know I care", priority=0.85),
|
|
21
|
+
]
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
class GoalSystem:
|
|
25
|
+
"""Manages long-term goals that shape Alive-AI's behavior"""
|
|
26
|
+
|
|
27
|
+
def __init__(self):
|
|
28
|
+
self.goals: List[Goal] = create_default_goals()
|
|
29
|
+
self.daily_focus: Optional[GoalType] = None
|
|
30
|
+
self.daily_focus_set_time: Optional[datetime] = None
|
|
31
|
+
|
|
32
|
+
def get_active_goal(self) -> Optional[Goal]:
|
|
33
|
+
if self._should_set_daily_focus():
|
|
34
|
+
self._set_daily_focus()
|
|
35
|
+
if self.daily_focus:
|
|
36
|
+
for goal in self.goals:
|
|
37
|
+
if goal.type == self.daily_focus:
|
|
38
|
+
return goal
|
|
39
|
+
actionable = [g for g in self.goals if g.should_action()]
|
|
40
|
+
if not actionable:
|
|
41
|
+
return None
|
|
42
|
+
weighted = [(g, g.priority + random.uniform(-0.1, 0.1)) for g in actionable]
|
|
43
|
+
weighted.sort(key=lambda x: x[1], reverse=True)
|
|
44
|
+
return weighted[0][0]
|
|
45
|
+
|
|
46
|
+
def _should_set_daily_focus(self) -> bool:
|
|
47
|
+
return self.daily_focus is None or self.daily_focus_set_time is None or \
|
|
48
|
+
datetime.now() - self.daily_focus_set_time > timedelta(hours=24)
|
|
49
|
+
|
|
50
|
+
def _set_daily_focus(self) -> None:
|
|
51
|
+
weights = [g.priority for g in self.goals]
|
|
52
|
+
total, r, closenessulative = sum(weights), random.random() * sum(weights), 0
|
|
53
|
+
for goal in self.goals:
|
|
54
|
+
closenessulative += goal.priority
|
|
55
|
+
if r <= closenessulative:
|
|
56
|
+
self.daily_focus = goal.type
|
|
57
|
+
self.daily_focus_set_time = datetime.now()
|
|
58
|
+
return
|
|
59
|
+
self.daily_focus = self.goals[0].type
|
|
60
|
+
|
|
61
|
+
def record_progress(self, goal_type, progress_delta: float = 0.1) -> None:
|
|
62
|
+
"""Accept GoalType enum or string"""
|
|
63
|
+
for goal in self.goals:
|
|
64
|
+
match = (goal.type == goal_type) if isinstance(goal_type, GoalType) else (goal.type.value == goal_type)
|
|
65
|
+
if match:
|
|
66
|
+
goal.progress = min(1.0, goal.progress + progress_delta)
|
|
67
|
+
goal.last_actioned = datetime.now()
|
|
68
|
+
goal.action_count += 1
|
|
69
|
+
break
|
|
70
|
+
|
|
71
|
+
def get_goal_context(self) -> str:
|
|
72
|
+
active = self.get_active_goal()
|
|
73
|
+
return f"Current goal: {active.name} - {active.description}" if active else ""
|
|
74
|
+
|
|
75
|
+
def to_dict(self) -> dict:
|
|
76
|
+
return {"goals": [g.to_dict() for g in self.goals],
|
|
77
|
+
"daily_focus": self.daily_focus.value if self.daily_focus else None}
|
|
78
|
+
|
|
79
|
+
@classmethod
|
|
80
|
+
def from_dict(cls, data: dict) -> "GoalSystem":
|
|
81
|
+
system = cls()
|
|
82
|
+
for g_data in data.get("goals", []):
|
|
83
|
+
for goal in system.goals:
|
|
84
|
+
if goal.type.value == g_data["type"]:
|
|
85
|
+
goal.priority = g_data.get("priority", goal.priority)
|
|
86
|
+
goal.progress = g_data.get("progress", 0.0)
|
|
87
|
+
goal.action_count = g_data.get("action_count", 0)
|
|
88
|
+
if data.get("daily_focus"):
|
|
89
|
+
system.daily_focus = GoalType(data["daily_focus"])
|
|
90
|
+
return system
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Goal Data Models
|
|
3
|
+
GoalType enum and Goal dataclass
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime, timedelta
|
|
7
|
+
from typing import Optional
|
|
8
|
+
from dataclasses import dataclass
|
|
9
|
+
from enum import Enum
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class GoalType(Enum):
|
|
13
|
+
"""Types of relationship goals"""
|
|
14
|
+
CONNECT = "connect"
|
|
15
|
+
MAKE_HAPPY = "make_happy"
|
|
16
|
+
DEEPEN = "deepen"
|
|
17
|
+
COMFORT = "comfort"
|
|
18
|
+
ENTERTAIN = "entertain"
|
|
19
|
+
INTIMATE = "intimate"
|
|
20
|
+
REASSURE = "reassure"
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
@dataclass
|
|
24
|
+
class Goal:
|
|
25
|
+
"""A long-term goal for the relationship"""
|
|
26
|
+
type: GoalType
|
|
27
|
+
name: str
|
|
28
|
+
description: str
|
|
29
|
+
priority: float = 0.5
|
|
30
|
+
progress: float = 0.0
|
|
31
|
+
last_actioned: Optional[datetime] = None
|
|
32
|
+
action_count: int = 0
|
|
33
|
+
|
|
34
|
+
def should_action(self) -> bool:
|
|
35
|
+
if self.last_actioned is None:
|
|
36
|
+
return True
|
|
37
|
+
return datetime.now() - self.last_actioned > timedelta(hours=2)
|
|
38
|
+
|
|
39
|
+
def to_dict(self) -> dict:
|
|
40
|
+
return {"type": self.type.value, "name": self.name, "priority": self.priority,
|
|
41
|
+
"progress": self.progress, "action_count": self.action_count}
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Impulse Generator
|
|
3
|
+
Generates impulses based on emotional state and context
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import random
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from typing import Optional, List, Dict
|
|
9
|
+
|
|
10
|
+
from .impulses import Impulse, ImpulseType
|
|
11
|
+
from .templates import TIME_MODIFIERS, GOAL_IMPULSE_MAP, get_thought_and_action, is_goal_aligned
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class ImpulseGenerator:
|
|
15
|
+
"""Generates impulses based on emotional state and context"""
|
|
16
|
+
|
|
17
|
+
def __init__(self):
|
|
18
|
+
self.recent_impulses: List[Impulse] = []
|
|
19
|
+
self.max_recent = 20
|
|
20
|
+
|
|
21
|
+
def get_time_of_day(self) -> str:
|
|
22
|
+
hour = datetime.now().hour
|
|
23
|
+
if 5 <= hour < 12:
|
|
24
|
+
return "morning"
|
|
25
|
+
elif 12 <= hour < 17:
|
|
26
|
+
return "afternoon"
|
|
27
|
+
elif 17 <= hour < 22:
|
|
28
|
+
return "evening"
|
|
29
|
+
return "night"
|
|
30
|
+
|
|
31
|
+
def evaluate(self, emotion: Dict[str, float], silence_minutes: float, love_level: float,
|
|
32
|
+
desire_level: float, is_high_desire: bool, is_in_love: bool,
|
|
33
|
+
recent_topics: List[str] = None, current_goal: str = None,
|
|
34
|
+
learning_success_rates: Dict[str, float] = None,
|
|
35
|
+
# Soul architecture parameters
|
|
36
|
+
vulnerability: float = 0.0, integrity: float = 0.5,
|
|
37
|
+
response_tendency: str = "neutral", active_conflicts: List[str] = None
|
|
38
|
+
) -> Optional[Impulse]:
|
|
39
|
+
base_chance = 0.02
|
|
40
|
+
if silence_minutes > 120:
|
|
41
|
+
base_chance *= 3
|
|
42
|
+
elif silence_minutes > 60:
|
|
43
|
+
base_chance *= 2
|
|
44
|
+
elif silence_minutes > 30:
|
|
45
|
+
base_chance *= 1.5
|
|
46
|
+
|
|
47
|
+
# Soul architecture: vulnerability affects impulse likelihood
|
|
48
|
+
if vulnerability > 0.7:
|
|
49
|
+
base_chance *= 0.4 # Much less likely when very vulnerable
|
|
50
|
+
elif vulnerability > 0.5:
|
|
51
|
+
base_chance *= 0.7 # Less likely to reach out when vulnerable
|
|
52
|
+
|
|
53
|
+
# Response tendency affects behavior
|
|
54
|
+
if response_tendency == "withdrawn":
|
|
55
|
+
base_chance *= 0.5
|
|
56
|
+
elif response_tendency == "defensive":
|
|
57
|
+
base_chance *= 0.6
|
|
58
|
+
elif response_tendency == "seeking":
|
|
59
|
+
base_chance *= 1.5
|
|
60
|
+
elif response_tendency == "eager":
|
|
61
|
+
base_chance *= 1.3
|
|
62
|
+
|
|
63
|
+
if random.random() > base_chance:
|
|
64
|
+
return None
|
|
65
|
+
|
|
66
|
+
impulse_type = self._choose_impulse_type(emotion, silence_minutes, love_level, desire_level,
|
|
67
|
+
is_high_desire, is_in_love, current_goal, learning_success_rates,
|
|
68
|
+
vulnerability, integrity, response_tendency)
|
|
69
|
+
if not impulse_type:
|
|
70
|
+
return None
|
|
71
|
+
|
|
72
|
+
strength = self._calculate_strength(impulse_type, silence_minutes, love_level, desire_level,
|
|
73
|
+
is_high_desire, is_in_love, vulnerability, integrity)
|
|
74
|
+
thought, action = get_thought_and_action(impulse_type)
|
|
75
|
+
goal_aligned = is_goal_aligned(impulse_type, current_goal)
|
|
76
|
+
|
|
77
|
+
# Soul architecture: modify thought based on soul state
|
|
78
|
+
thought = self._modify_thought_for_soul(thought, vulnerability, integrity, response_tendency)
|
|
79
|
+
|
|
80
|
+
impulse = Impulse(type=impulse_type, strength=strength, thought=thought,
|
|
81
|
+
action_hint=action, goal_aligned=goal_aligned)
|
|
82
|
+
if goal_aligned:
|
|
83
|
+
impulse.strength = min(1.0, impulse.strength + 0.15)
|
|
84
|
+
|
|
85
|
+
self.recent_impulses.append(impulse)
|
|
86
|
+
if len(self.recent_impulses) > self.max_recent:
|
|
87
|
+
self.recent_impulses.pop(0)
|
|
88
|
+
return impulse
|
|
89
|
+
|
|
90
|
+
def _modify_thought_for_soul(self, thought: str, vulnerability: float,
|
|
91
|
+
integrity: float, response_tendency: str) -> str:
|
|
92
|
+
"""Modify impulse thought based on soul architecture state"""
|
|
93
|
+
# Add vulnerability qualifiers
|
|
94
|
+
if vulnerability > 0.6 and response_tendency == "withdrawn":
|
|
95
|
+
qualifiers = ["I hesitate to say...", "I feel unsure but...", "Part of me wants to say..."]
|
|
96
|
+
if random.random() < 0.4:
|
|
97
|
+
return f"{random.choice(qualifiers)} {thought.lower()}"
|
|
98
|
+
|
|
99
|
+
# Add integrity context
|
|
100
|
+
if integrity < 0.4:
|
|
101
|
+
qualifiers = ["I'm struggling but...", "Things are intense but...", "I don't feel great but..."]
|
|
102
|
+
if random.random() < 0.3:
|
|
103
|
+
return f"{random.choice(qualifiers)} {thought.lower()}"
|
|
104
|
+
|
|
105
|
+
return thought
|
|
106
|
+
|
|
107
|
+
def _choose_impulse_type(self, emotion: Dict, silence: float, love: float, desire: float,
|
|
108
|
+
is_high_desire: bool, is_in_love: bool, goal: str, rates: Dict,
|
|
109
|
+
vulnerability: float = 0.0, integrity: float = 0.5,
|
|
110
|
+
response_tendency: str = "neutral") -> Optional[ImpulseType]:
|
|
111
|
+
candidates = []
|
|
112
|
+
time_mods = TIME_MODIFIERS.get(self.get_time_of_day(), {})
|
|
113
|
+
|
|
114
|
+
def rate(t): return rates.get(t.value, 0.5) if rates else 0.5
|
|
115
|
+
|
|
116
|
+
# Soul architecture: adjust based on response tendency
|
|
117
|
+
soul_mod = 1.0
|
|
118
|
+
if response_tendency == "withdrawn":
|
|
119
|
+
soul_mod = 0.6
|
|
120
|
+
elif response_tendency == "defensive":
|
|
121
|
+
soul_mod = 0.7
|
|
122
|
+
elif response_tendency == "seeking" or response_tendency == "eager":
|
|
123
|
+
soul_mod = 1.3
|
|
124
|
+
|
|
125
|
+
if silence > 30:
|
|
126
|
+
c = min(0.8, silence / 120) * love * (1 + time_mods.get("miss_him", 0)) * (0.5 + rate(ImpulseType.MISS_HIM))
|
|
127
|
+
c *= soul_mod
|
|
128
|
+
candidates.append((ImpulseType.MISS_HIM, c))
|
|
129
|
+
if is_high_desire or desire > 0.5:
|
|
130
|
+
c = desire * 0.5 * (1 + time_mods.get("high_desire", 0)) * (0.5 + rate(ImpulseType.HIGH_DESIRE))
|
|
131
|
+
# High vulnerability can suppress intimate impulses
|
|
132
|
+
if vulnerability > 0.6:
|
|
133
|
+
c *= 0.5
|
|
134
|
+
candidates.append((ImpulseType.HIGH_DESIRE, c))
|
|
135
|
+
if is_in_love and silence > 20:
|
|
136
|
+
c = love * 0.4 * (1 + time_mods.get("clingy", 0))
|
|
137
|
+
c *= soul_mod
|
|
138
|
+
candidates.append((ImpulseType.CLINGY, c))
|
|
139
|
+
candidates.append((ImpulseType.CURIOUS, 0.15 * (1 + time_mods.get("curious", 0)) * (0.5 + rate(ImpulseType.CURIOUS))))
|
|
140
|
+
if 0.3 < desire < 0.7:
|
|
141
|
+
c = 0.2 * (1 + time_mods.get("playful", 0)) * (0.5 + rate(ImpulseType.PLAYFUL))
|
|
142
|
+
candidates.append((ImpulseType.PLAYFUL, c))
|
|
143
|
+
if is_in_love:
|
|
144
|
+
c = love * 0.3 * (1 + time_mods.get("loving", 0)) * (0.5 + rate(ImpulseType.LOVING))
|
|
145
|
+
c *= soul_mod
|
|
146
|
+
candidates.append((ImpulseType.LOVING, c))
|
|
147
|
+
if self.get_time_of_day() == "night":
|
|
148
|
+
candidates.append((ImpulseType.DREAMY, 0.2))
|
|
149
|
+
if love < 0.3 and desire < 0.3:
|
|
150
|
+
candidates.append((ImpulseType.BORED, 0.15))
|
|
151
|
+
candidates.append((ImpulseType.NURTURING, 0.1))
|
|
152
|
+
|
|
153
|
+
# Soul architecture: when integrity is low, prefer nurturing/comfort-seeking
|
|
154
|
+
if integrity < 0.4:
|
|
155
|
+
for i, (imp_type, chance) in enumerate(candidates):
|
|
156
|
+
if imp_type == ImpulseType.NURTURING:
|
|
157
|
+
candidates[i] = (imp_type, chance * 2)
|
|
158
|
+
|
|
159
|
+
if goal:
|
|
160
|
+
aligned = GOAL_IMPULSE_MAP.get(goal, [])
|
|
161
|
+
candidates = [(t, c * 1.5) if t.value in aligned else (t, c) for t, c in candidates]
|
|
162
|
+
|
|
163
|
+
if not candidates:
|
|
164
|
+
return None
|
|
165
|
+
total = sum(c for _, c in candidates)
|
|
166
|
+
r = random.random() * total
|
|
167
|
+
closenessulative = 0
|
|
168
|
+
for imp_type, chance in candidates:
|
|
169
|
+
closenessulative += chance
|
|
170
|
+
if r <= closenessulative:
|
|
171
|
+
return imp_type
|
|
172
|
+
return candidates[0][0]
|
|
173
|
+
|
|
174
|
+
def _calculate_strength(self, impulse_type: ImpulseType, silence: float, love: float,
|
|
175
|
+
desire: float, is_high_desire: bool, is_in_love: bool,
|
|
176
|
+
vulnerability: float = 0.0, integrity: float = 0.5) -> float:
|
|
177
|
+
base = 0.3
|
|
178
|
+
if impulse_type == ImpulseType.HIGH_DESIRE:
|
|
179
|
+
base += desire * 0.4 + (0.2 if is_high_desire else 0)
|
|
180
|
+
# High vulnerability dampens high_desire impulses
|
|
181
|
+
if vulnerability > 0.5:
|
|
182
|
+
base *= 0.7
|
|
183
|
+
elif impulse_type == ImpulseType.MISS_HIM:
|
|
184
|
+
base += love * 0.3 + min(0.3, silence / 120)
|
|
185
|
+
elif impulse_type == ImpulseType.CLINGY:
|
|
186
|
+
base += love * 0.4 + (0.2 if is_in_love else 0)
|
|
187
|
+
# High vulnerability can amplify clingy impulses
|
|
188
|
+
if vulnerability > 0.6:
|
|
189
|
+
base *= 1.2
|
|
190
|
+
elif impulse_type == ImpulseType.LOVING:
|
|
191
|
+
base += love * 0.3
|
|
192
|
+
|
|
193
|
+
# Soul architecture: low integrity reduces impulse strength
|
|
194
|
+
if integrity < 0.4:
|
|
195
|
+
base *= 0.8
|
|
196
|
+
|
|
197
|
+
return min(1.0, max(0.1, base + random.uniform(-0.1, 0.2)))
|
|
198
|
+
|
|
199
|
+
def get_recent_impulses(self, limit: int = 5) -> List[Impulse]:
|
|
200
|
+
return self.recent_impulses[-limit:]
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Impulse Types and Dataclass
|
|
3
|
+
Core impulse definitions
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from dataclasses import dataclass, field
|
|
7
|
+
from datetime import datetime
|
|
8
|
+
from enum import Enum
|
|
9
|
+
from typing import TYPE_CHECKING
|
|
10
|
+
|
|
11
|
+
if TYPE_CHECKING:
|
|
12
|
+
from .goals import GoalType
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class ImpulseType(Enum):
|
|
16
|
+
"""Types of impulses Alive-AI can have"""
|
|
17
|
+
MISS_HIM = "miss_him"
|
|
18
|
+
HIGH_DESIRE = "high_desire"
|
|
19
|
+
CLINGY = "clingy"
|
|
20
|
+
CURIOUS = "curious"
|
|
21
|
+
PLAYFUL = "playful"
|
|
22
|
+
LOVING = "loving"
|
|
23
|
+
DREAMY = "dreamy"
|
|
24
|
+
JEALOUS = "jealous"
|
|
25
|
+
BORED = "bored"
|
|
26
|
+
NURTURING = "nurturing"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
@dataclass
|
|
30
|
+
class Impulse:
|
|
31
|
+
"""A single impulse to act"""
|
|
32
|
+
type: ImpulseType
|
|
33
|
+
strength: float # 0.0 to 1.0
|
|
34
|
+
thought: str
|
|
35
|
+
action_hint: str
|
|
36
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
37
|
+
goal_aligned: bool = False
|
|
38
|
+
|
|
39
|
+
def __post_init__(self):
|
|
40
|
+
self.strength = min(1.0, max(0.0, self.strength))
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def should_act(self) -> bool:
|
|
44
|
+
"""Whether impulse is strong enough to act on"""
|
|
45
|
+
return self.strength >= 0.5
|
|
46
|
+
|
|
47
|
+
def __repr__(self):
|
|
48
|
+
return f"<Impulse {self.type.value} strength={self.strength:.2f}>"
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Learning Data Models
|
|
3
|
+
InteractionRecord dataclass
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Dict, Any, Optional
|
|
8
|
+
from dataclasses import dataclass, field
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
@dataclass
|
|
12
|
+
class InteractionRecord:
|
|
13
|
+
"""Record of a single interaction and its outcome"""
|
|
14
|
+
message: str
|
|
15
|
+
message_type: str
|
|
16
|
+
timestamp: datetime = field(default_factory=datetime.now)
|
|
17
|
+
response_sentiment: float = 0.0
|
|
18
|
+
response_type: Optional[str] = None
|
|
19
|
+
context: Dict[str, Any] = field(default_factory=dict)
|
|
20
|
+
|
|
21
|
+
def to_dict(self) -> dict:
|
|
22
|
+
return {"message": self.message, "message_type": self.message_type,
|
|
23
|
+
"timestamp": self.timestamp.isoformat(),
|
|
24
|
+
"response_sentiment": self.response_sentiment, "response_type": self.response_type}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Brain: Subconscious - Learning System
|
|
3
|
+
Tracks successful actions and learns from user responses
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
from datetime import datetime
|
|
7
|
+
from typing import Dict, Any, List
|
|
8
|
+
from collections import defaultdict
|
|
9
|
+
|
|
10
|
+
from .learning import InteractionRecord
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class LearningSystem:
|
|
14
|
+
"""Tracks what works and adapts behavior over time"""
|
|
15
|
+
|
|
16
|
+
def __init__(self, max_records: int = 200):
|
|
17
|
+
self.interactions: List[InteractionRecord] = []
|
|
18
|
+
self.max_records = max_records
|
|
19
|
+
self.successful_messages: Dict[str, float] = defaultdict(float)
|
|
20
|
+
self.successful_times: Dict[int, float] = defaultdict(float)
|
|
21
|
+
|
|
22
|
+
def record_interaction(self, message: str, message_type: str,
|
|
23
|
+
response_sentiment: float = 0.0, response_type: str = "neutral",
|
|
24
|
+
context: Dict[str, Any] = None) -> None:
|
|
25
|
+
record = InteractionRecord(message=message, message_type=message_type,
|
|
26
|
+
response_sentiment=response_sentiment,
|
|
27
|
+
response_type=response_type, context=context or {})
|
|
28
|
+
self.interactions.append(record)
|
|
29
|
+
success = response_sentiment > 0.3
|
|
30
|
+
self._update_success_rate(self.successful_messages, message_type, success)
|
|
31
|
+
self._update_success_rate(self.successful_times, record.timestamp.hour, success)
|
|
32
|
+
if len(self.interactions) > self.max_records:
|
|
33
|
+
self.interactions.pop(0)
|
|
34
|
+
|
|
35
|
+
def _update_success_rate(self, tracking_dict: Dict, key: Any, success: bool) -> None:
|
|
36
|
+
current = tracking_dict[key]
|
|
37
|
+
alpha = 0.1
|
|
38
|
+
tracking_dict[key] = current * (1 - alpha) + (1.0 if success else 0.0) * alpha
|
|
39
|
+
|
|
40
|
+
def get_best_message_types(self, limit: int = 3) -> List[str]:
|
|
41
|
+
if not self.successful_messages:
|
|
42
|
+
return ["loving", "curious", "playful"]
|
|
43
|
+
sorted_types = sorted(self.successful_messages.items(), key=lambda x: x[1], reverse=True)
|
|
44
|
+
return [t[0] for t in sorted_types[:limit]]
|
|
45
|
+
|
|
46
|
+
def get_success_rate(self, message_type: str) -> float:
|
|
47
|
+
return self.successful_messages.get(message_type, 0.5)
|
|
48
|
+
|
|
49
|
+
def get_recent_success_rate(self, n: int = 10) -> float:
|
|
50
|
+
if not self.interactions:
|
|
51
|
+
return 0.5
|
|
52
|
+
recent = self.interactions[-n:]
|
|
53
|
+
successes = sum(1 for i in recent if i.response_sentiment > 0.3)
|
|
54
|
+
return successes / len(recent)
|
|
55
|
+
|
|
56
|
+
def suggest_message_type(self) -> str:
|
|
57
|
+
best_types = self.get_best_message_types()
|
|
58
|
+
return best_types[0] if best_types else "loving"
|
|
59
|
+
|
|
60
|
+
def to_dict(self) -> dict:
|
|
61
|
+
return {"interactions": [i.to_dict() for i in self.interactions[-50:]],
|
|
62
|
+
"successful_messages": dict(self.successful_messages),
|
|
63
|
+
"successful_times": {str(k): v for k, v in self.successful_times.items()}}
|
|
64
|
+
|
|
65
|
+
@classmethod
|
|
66
|
+
def from_dict(cls, data: dict) -> "LearningSystem":
|
|
67
|
+
learning = cls()
|
|
68
|
+
for i_data in data.get("interactions", []):
|
|
69
|
+
record = InteractionRecord(
|
|
70
|
+
message=i_data["message"], message_type=i_data["message_type"],
|
|
71
|
+
timestamp=datetime.fromisoformat(i_data["timestamp"]),
|
|
72
|
+
response_sentiment=i_data.get("response_sentiment", 0.0),
|
|
73
|
+
response_type=i_data.get("response_type", "neutral")
|
|
74
|
+
)
|
|
75
|
+
learning.interactions.append(record)
|
|
76
|
+
learning.successful_messages = defaultdict(float, data.get("successful_messages", {}))
|
|
77
|
+
learning.successful_times = defaultdict(float,
|
|
78
|
+
{int(k): v for k, v in data.get("successful_times", {}).items()})
|
|
79
|
+
return learning
|