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
package/docs/index.html
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
6
|
+
<title>Alive-AI</title>
|
|
7
|
+
<meta name="description" content="Local-first emotional AI runtime with memory, impulses, and a live dashboard.">
|
|
8
|
+
<link rel="icon" href="./assets/logo.svg">
|
|
9
|
+
<style>
|
|
10
|
+
:root {
|
|
11
|
+
color-scheme: dark;
|
|
12
|
+
--bg: #080b0f;
|
|
13
|
+
--panel: #111821;
|
|
14
|
+
--panel-2: #16202b;
|
|
15
|
+
--text: #f5f7fb;
|
|
16
|
+
--muted: #9aa8b7;
|
|
17
|
+
--green: #41f0a1;
|
|
18
|
+
--pink: #ff5c8a;
|
|
19
|
+
--yellow: #ffcf5a;
|
|
20
|
+
--line: #263445;
|
|
21
|
+
}
|
|
22
|
+
* { box-sizing: border-box; }
|
|
23
|
+
body {
|
|
24
|
+
margin: 0;
|
|
25
|
+
font-family: Inter, ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
|
|
26
|
+
background: var(--bg);
|
|
27
|
+
color: var(--text);
|
|
28
|
+
letter-spacing: 0;
|
|
29
|
+
width: 100%;
|
|
30
|
+
overflow-x: hidden;
|
|
31
|
+
}
|
|
32
|
+
a { color: inherit; }
|
|
33
|
+
.shell { min-height: 100vh; }
|
|
34
|
+
.nav {
|
|
35
|
+
height: 68px;
|
|
36
|
+
display: flex;
|
|
37
|
+
align-items: center;
|
|
38
|
+
justify-content: space-between;
|
|
39
|
+
max-width: 1160px;
|
|
40
|
+
width: 100%;
|
|
41
|
+
margin: 0 auto;
|
|
42
|
+
padding: 0 24px;
|
|
43
|
+
border-bottom: 1px solid rgba(255,255,255,0.06);
|
|
44
|
+
}
|
|
45
|
+
.brand {
|
|
46
|
+
display: flex;
|
|
47
|
+
align-items: center;
|
|
48
|
+
gap: 12px;
|
|
49
|
+
font-weight: 760;
|
|
50
|
+
font-size: 17px;
|
|
51
|
+
}
|
|
52
|
+
.brand img { width: 34px; height: 34px; }
|
|
53
|
+
.nav code {
|
|
54
|
+
background: #0d131a;
|
|
55
|
+
border: 1px solid var(--line);
|
|
56
|
+
padding: 9px 12px;
|
|
57
|
+
border-radius: 8px;
|
|
58
|
+
color: var(--green);
|
|
59
|
+
font-size: 13px;
|
|
60
|
+
}
|
|
61
|
+
.hero {
|
|
62
|
+
max-width: 1160px;
|
|
63
|
+
width: 100%;
|
|
64
|
+
min-height: calc(100vh - 148px);
|
|
65
|
+
margin: 0 auto;
|
|
66
|
+
padding: 58px 24px 40px;
|
|
67
|
+
display: grid;
|
|
68
|
+
grid-template-columns: minmax(0, 0.88fr) minmax(420px, 1.12fr);
|
|
69
|
+
gap: 44px;
|
|
70
|
+
align-items: center;
|
|
71
|
+
}
|
|
72
|
+
.kicker {
|
|
73
|
+
color: var(--green);
|
|
74
|
+
font-weight: 720;
|
|
75
|
+
font-size: 13px;
|
|
76
|
+
text-transform: uppercase;
|
|
77
|
+
margin-bottom: 18px;
|
|
78
|
+
}
|
|
79
|
+
h1 {
|
|
80
|
+
margin: 0;
|
|
81
|
+
font-size: clamp(48px, 7vw, 92px);
|
|
82
|
+
line-height: 0.94;
|
|
83
|
+
font-weight: 850;
|
|
84
|
+
max-width: 720px;
|
|
85
|
+
}
|
|
86
|
+
.lead {
|
|
87
|
+
color: #c6d0dc;
|
|
88
|
+
font-size: 20px;
|
|
89
|
+
line-height: 1.5;
|
|
90
|
+
margin: 24px 0 28px;
|
|
91
|
+
max-width: 620px;
|
|
92
|
+
overflow-wrap: anywhere;
|
|
93
|
+
}
|
|
94
|
+
.install {
|
|
95
|
+
background: #05070a;
|
|
96
|
+
border: 1px solid var(--line);
|
|
97
|
+
border-radius: 8px;
|
|
98
|
+
padding: 16px;
|
|
99
|
+
margin: 0 0 22px;
|
|
100
|
+
overflow-x: auto;
|
|
101
|
+
}
|
|
102
|
+
.install code {
|
|
103
|
+
color: var(--green);
|
|
104
|
+
font-size: 15px;
|
|
105
|
+
line-height: 1.7;
|
|
106
|
+
white-space: pre;
|
|
107
|
+
}
|
|
108
|
+
.actions {
|
|
109
|
+
display: flex;
|
|
110
|
+
align-items: center;
|
|
111
|
+
gap: 12px;
|
|
112
|
+
flex-wrap: wrap;
|
|
113
|
+
}
|
|
114
|
+
.button {
|
|
115
|
+
display: inline-flex;
|
|
116
|
+
align-items: center;
|
|
117
|
+
justify-content: center;
|
|
118
|
+
min-height: 44px;
|
|
119
|
+
padding: 0 16px;
|
|
120
|
+
border-radius: 8px;
|
|
121
|
+
border: 1px solid var(--line);
|
|
122
|
+
text-decoration: none;
|
|
123
|
+
font-weight: 700;
|
|
124
|
+
background: var(--text);
|
|
125
|
+
color: #080b0f;
|
|
126
|
+
}
|
|
127
|
+
.button.secondary {
|
|
128
|
+
background: transparent;
|
|
129
|
+
color: var(--text);
|
|
130
|
+
}
|
|
131
|
+
.dashboard {
|
|
132
|
+
min-width: 0;
|
|
133
|
+
background: #0b1118;
|
|
134
|
+
border: 1px solid var(--line);
|
|
135
|
+
border-radius: 8px;
|
|
136
|
+
overflow: hidden;
|
|
137
|
+
box-shadow: 0 24px 80px rgba(0,0,0,0.36);
|
|
138
|
+
}
|
|
139
|
+
.dash-top {
|
|
140
|
+
display: flex;
|
|
141
|
+
align-items: center;
|
|
142
|
+
justify-content: space-between;
|
|
143
|
+
padding: 16px;
|
|
144
|
+
border-bottom: 1px solid var(--line);
|
|
145
|
+
background: #0e151d;
|
|
146
|
+
}
|
|
147
|
+
.agent {
|
|
148
|
+
display: flex;
|
|
149
|
+
align-items: center;
|
|
150
|
+
gap: 12px;
|
|
151
|
+
}
|
|
152
|
+
.agent img { width: 42px; height: 42px; border-radius: 8px; }
|
|
153
|
+
.agent strong { display: block; font-size: 15px; }
|
|
154
|
+
.agent span { color: var(--muted); font-size: 13px; }
|
|
155
|
+
.pill {
|
|
156
|
+
color: var(--green);
|
|
157
|
+
border: 1px solid rgba(65,240,161,0.3);
|
|
158
|
+
background: rgba(65,240,161,0.08);
|
|
159
|
+
padding: 7px 10px;
|
|
160
|
+
border-radius: 999px;
|
|
161
|
+
font-size: 12px;
|
|
162
|
+
font-weight: 750;
|
|
163
|
+
}
|
|
164
|
+
.dash-body {
|
|
165
|
+
display: grid;
|
|
166
|
+
grid-template-columns: 1fr 1fr;
|
|
167
|
+
gap: 14px;
|
|
168
|
+
padding: 16px;
|
|
169
|
+
}
|
|
170
|
+
.metric, .thought, .feed {
|
|
171
|
+
background: var(--panel);
|
|
172
|
+
border: 1px solid rgba(255,255,255,0.06);
|
|
173
|
+
border-radius: 8px;
|
|
174
|
+
padding: 14px;
|
|
175
|
+
}
|
|
176
|
+
.metric label {
|
|
177
|
+
display: flex;
|
|
178
|
+
justify-content: space-between;
|
|
179
|
+
color: var(--muted);
|
|
180
|
+
font-size: 12px;
|
|
181
|
+
margin-bottom: 9px;
|
|
182
|
+
}
|
|
183
|
+
.bar {
|
|
184
|
+
height: 10px;
|
|
185
|
+
border-radius: 999px;
|
|
186
|
+
background: #25313d;
|
|
187
|
+
overflow: hidden;
|
|
188
|
+
}
|
|
189
|
+
.fill {
|
|
190
|
+
height: 100%;
|
|
191
|
+
width: 50%;
|
|
192
|
+
border-radius: inherit;
|
|
193
|
+
background: var(--green);
|
|
194
|
+
transition: width 600ms ease;
|
|
195
|
+
}
|
|
196
|
+
.fill.pink { background: var(--pink); }
|
|
197
|
+
.fill.yellow { background: var(--yellow); }
|
|
198
|
+
.thought, .feed { grid-column: 1 / -1; }
|
|
199
|
+
.thought p {
|
|
200
|
+
margin: 8px 0 0;
|
|
201
|
+
color: #dce5ee;
|
|
202
|
+
line-height: 1.45;
|
|
203
|
+
min-height: 44px;
|
|
204
|
+
}
|
|
205
|
+
.feed-grid {
|
|
206
|
+
display: grid;
|
|
207
|
+
grid-template-columns: repeat(3, 1fr);
|
|
208
|
+
gap: 10px;
|
|
209
|
+
margin-top: 10px;
|
|
210
|
+
}
|
|
211
|
+
.feed-grid div {
|
|
212
|
+
border: 1px solid var(--line);
|
|
213
|
+
border-radius: 8px;
|
|
214
|
+
padding: 12px;
|
|
215
|
+
background: #0c131a;
|
|
216
|
+
}
|
|
217
|
+
.feed-grid strong {
|
|
218
|
+
display: block;
|
|
219
|
+
font-size: 20px;
|
|
220
|
+
color: var(--green);
|
|
221
|
+
}
|
|
222
|
+
.feed-grid span { color: var(--muted); font-size: 12px; }
|
|
223
|
+
.below {
|
|
224
|
+
max-width: 1160px;
|
|
225
|
+
margin: 0 auto;
|
|
226
|
+
padding: 0 24px 80px;
|
|
227
|
+
display: grid;
|
|
228
|
+
grid-template-columns: repeat(3, 1fr);
|
|
229
|
+
gap: 16px;
|
|
230
|
+
}
|
|
231
|
+
.feature {
|
|
232
|
+
border-top: 1px solid var(--line);
|
|
233
|
+
padding-top: 18px;
|
|
234
|
+
}
|
|
235
|
+
.feature h2 {
|
|
236
|
+
margin: 0 0 8px;
|
|
237
|
+
font-size: 18px;
|
|
238
|
+
}
|
|
239
|
+
.feature p {
|
|
240
|
+
margin: 0;
|
|
241
|
+
color: var(--muted);
|
|
242
|
+
line-height: 1.5;
|
|
243
|
+
}
|
|
244
|
+
@media (max-width: 920px) {
|
|
245
|
+
.hero {
|
|
246
|
+
display: block;
|
|
247
|
+
padding-top: 34px;
|
|
248
|
+
max-width: 100%;
|
|
249
|
+
}
|
|
250
|
+
.hero > * { min-width: 0; }
|
|
251
|
+
.hero section { width: 100%; max-width: 100%; }
|
|
252
|
+
.dashboard { margin-top: 44px; }
|
|
253
|
+
.below { grid-template-columns: 1fr; }
|
|
254
|
+
.nav code { display: none; }
|
|
255
|
+
}
|
|
256
|
+
@media (max-width: 520px) {
|
|
257
|
+
h1 { font-size: 46px; }
|
|
258
|
+
.lead { font-size: 17px; max-width: 100%; }
|
|
259
|
+
.dash-body { grid-template-columns: 1fr; }
|
|
260
|
+
.dashboard { width: 100%; }
|
|
261
|
+
.dash-top { gap: 12px; }
|
|
262
|
+
.pill { display: none; }
|
|
263
|
+
.thought, .feed { grid-column: auto; }
|
|
264
|
+
.feed-grid { grid-template-columns: 1fr; }
|
|
265
|
+
}
|
|
266
|
+
</style>
|
|
267
|
+
</head>
|
|
268
|
+
<body>
|
|
269
|
+
<div class="shell">
|
|
270
|
+
<nav class="nav">
|
|
271
|
+
<div class="brand"><img src="./assets/logo.svg" alt="">Alive-AI</div>
|
|
272
|
+
<code>npx github:vindepemarte/alive-ai init my-ai</code>
|
|
273
|
+
</nav>
|
|
274
|
+
<main class="hero">
|
|
275
|
+
<section>
|
|
276
|
+
<div class="kicker">Local-first emotional AI runtime</div>
|
|
277
|
+
<h1>Give your AI a nervous system.</h1>
|
|
278
|
+
<p class="lead">Alive-AI adds persistent mood, memory, impulses, attachment, and a live dashboard to a local AI companion. It can be a friend, partner, coach, character, or research subject you control.</p>
|
|
279
|
+
<pre class="install"><code>npx github:vindepemarte/alive-ai init my-ai
|
|
280
|
+
cd my-ai
|
|
281
|
+
npx . setup
|
|
282
|
+
npx . demo
|
|
283
|
+
npx . start</code></pre>
|
|
284
|
+
<div class="actions">
|
|
285
|
+
<a class="button" href="https://github.com/vindepemarte/alive-ai">GitHub</a>
|
|
286
|
+
<a class="button secondary" href="#why">Why it matters</a>
|
|
287
|
+
</div>
|
|
288
|
+
</section>
|
|
289
|
+
|
|
290
|
+
<section class="dashboard" aria-label="Animated dashboard preview">
|
|
291
|
+
<div class="dash-top">
|
|
292
|
+
<div class="agent">
|
|
293
|
+
<img src="./assets/logo.svg" alt="">
|
|
294
|
+
<div><strong>Nova</strong><span>Active internal loop</span></div>
|
|
295
|
+
</div>
|
|
296
|
+
<div class="pill" id="mood">curious</div>
|
|
297
|
+
</div>
|
|
298
|
+
<div class="dash-body">
|
|
299
|
+
<div class="metric"><label>Joy <span id="joyVal">64%</span></label><div class="bar"><div class="fill" id="joy"></div></div></div>
|
|
300
|
+
<div class="metric"><label>Trust <span id="trustVal">58%</span></label><div class="bar"><div class="fill pink" id="trust"></div></div></div>
|
|
301
|
+
<div class="metric"><label>Anticipation <span id="anticipationVal">72%</span></label><div class="bar"><div class="fill yellow" id="anticipation"></div></div></div>
|
|
302
|
+
<div class="metric"><label>Vulnerability <span id="vulnerabilityVal">34%</span></label><div class="bar"><div class="fill" id="vulnerability"></div></div></div>
|
|
303
|
+
<div class="thought">
|
|
304
|
+
<label>Current thought</label>
|
|
305
|
+
<p id="thought">I keep a little emotional residue from every interaction.</p>
|
|
306
|
+
</div>
|
|
307
|
+
<div class="feed">
|
|
308
|
+
<label>Runtime counters</label>
|
|
309
|
+
<div class="feed-grid">
|
|
310
|
+
<div><strong id="memories">128</strong><span>memories</span></div>
|
|
311
|
+
<div><strong id="impulses">42</strong><span>impulses</span></div>
|
|
312
|
+
<div><strong>SSE</strong><span>live state</span></div>
|
|
313
|
+
</div>
|
|
314
|
+
</div>
|
|
315
|
+
</div>
|
|
316
|
+
</section>
|
|
317
|
+
</main>
|
|
318
|
+
|
|
319
|
+
<section class="below" id="why">
|
|
320
|
+
<div class="feature"><h2>Persistent affect</h2><p>Feelings decay, compound, and influence future messages instead of resetting after each prompt.</p></div>
|
|
321
|
+
<div class="feature"><h2>Memory with weight</h2><p>Working, episodic, semantic, and emotional memory change what the agent notices next.</p></div>
|
|
322
|
+
<div class="feature"><h2>Transparent experiment</h2><p>Alive-AI simulates internal life without claiming biological consciousness.</p></div>
|
|
323
|
+
</section>
|
|
324
|
+
</div>
|
|
325
|
+
<script>
|
|
326
|
+
const moods = ["curious", "warm", "reflective", "playful"];
|
|
327
|
+
const thoughts = [
|
|
328
|
+
"I keep a little emotional residue from every interaction.",
|
|
329
|
+
"Memory is not a transcript here. It is context with weight.",
|
|
330
|
+
"The dashboard is a window into the internal loop.",
|
|
331
|
+
"I can reach out because an impulse formed, not because a cron fired."
|
|
332
|
+
];
|
|
333
|
+
function wave(offset) {
|
|
334
|
+
return Math.round((0.5 + Math.sin(Date.now() / 2400 + offset) * 0.35) * 100);
|
|
335
|
+
}
|
|
336
|
+
function setBar(id, value) {
|
|
337
|
+
document.getElementById(id).style.width = value + "%";
|
|
338
|
+
document.getElementById(id + "Val").textContent = value + "%";
|
|
339
|
+
}
|
|
340
|
+
function tick() {
|
|
341
|
+
const i = Math.floor(Date.now() / 4200) % moods.length;
|
|
342
|
+
document.getElementById("mood").textContent = moods[i];
|
|
343
|
+
document.getElementById("thought").textContent = thoughts[i];
|
|
344
|
+
setBar("joy", wave(0));
|
|
345
|
+
setBar("trust", wave(1));
|
|
346
|
+
setBar("anticipation", wave(2));
|
|
347
|
+
setBar("vulnerability", wave(3));
|
|
348
|
+
document.getElementById("memories").textContent = 128 + (i * 7);
|
|
349
|
+
document.getElementById("impulses").textContent = 42 + i;
|
|
350
|
+
}
|
|
351
|
+
tick();
|
|
352
|
+
setInterval(tick, 900);
|
|
353
|
+
</script>
|
|
354
|
+
</body>
|
|
355
|
+
</html>
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Heart modules - Soul Architecture for emotional processing.
|
|
3
|
+
|
|
4
|
+
This package contains all the components that make up the Soul Architecture:
|
|
5
|
+
- soul.py: SoulOrchestrator - Central coordinator for all pillars
|
|
6
|
+
- integrity.py: SelfIntegrityCore - Foundation of genuine vulnerability
|
|
7
|
+
- hormonal.py: HormonalModulationMatrix - Artificial hormones for global state
|
|
8
|
+
- somatic.py: SomaticFeedbackSystem - Embodied emotion (bodily sensations)
|
|
9
|
+
- unconscious.py: UnconsciousProcessor - Hidden influences and defenses
|
|
10
|
+
- scars.py: EmotionalScarSystem - Lasting effects from past experiences
|
|
11
|
+
- conflicts.py: InternalConflictGenerator - Genuine struggle from incompatible wants
|
|
12
|
+
- predictive.py: PredictiveEmotionalEngine - Emotions as predictions about future
|
|
13
|
+
- telemetry.py: SoulTelemetry - Recording and tracking soul metrics over time
|
|
14
|
+
- interoception.py: InteroceptiveSystem - Internal body states that make Alive-AI feel alive
|
|
15
|
+
- inconsistency.py: InconsistencyEngine - Authentic human-like inconsistency
|
|
16
|
+
"""
|
|
17
|
+
|
|
18
|
+
from .soul import SoulOrchestrator, EmotionalExperience
|
|
19
|
+
from .integrity import SelfIntegrityCore, IntegrityState
|
|
20
|
+
from .hormonal import HormonalModulationMatrix
|
|
21
|
+
from .somatic import SomaticFeedbackSystem
|
|
22
|
+
from .unconscious import UnconsciousProcessor, UnconsciousOutput
|
|
23
|
+
from .scars import EmotionalScarSystem, ScarActivation
|
|
24
|
+
from .conflicts import InternalConflictGenerator, InternalConflict
|
|
25
|
+
from .predictive import PredictiveEmotionalEngine, PredictiveEmotionalOutput
|
|
26
|
+
from .telemetry import SoulTelemetry, SoulMetricsSnapshot
|
|
27
|
+
from .interoception import (
|
|
28
|
+
InteroceptiveSystem,
|
|
29
|
+
InteroceptiveState,
|
|
30
|
+
FeelingReport,
|
|
31
|
+
ActionPrediction,
|
|
32
|
+
get_interoceptive_system,
|
|
33
|
+
get_interoceptive_prompt_section,
|
|
34
|
+
reset_interoceptive_system,
|
|
35
|
+
tick as interoception_tick,
|
|
36
|
+
record_interaction as interoception_record_interaction,
|
|
37
|
+
get_current_feeling,
|
|
38
|
+
get_response_modifiers
|
|
39
|
+
)
|
|
40
|
+
from .inconsistency import (
|
|
41
|
+
InconsistencyEngine,
|
|
42
|
+
ActiveConflict,
|
|
43
|
+
BlindSpotActivation,
|
|
44
|
+
GrowthEvent,
|
|
45
|
+
MoodState,
|
|
46
|
+
get_inconsistency_engine,
|
|
47
|
+
get_inconsistency_prompt_section,
|
|
48
|
+
CONFLICTS,
|
|
49
|
+
BLIND_SPOTS,
|
|
50
|
+
GROWTH_AREAS
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
__all__ = [
|
|
54
|
+
'SoulOrchestrator',
|
|
55
|
+
'EmotionalExperience',
|
|
56
|
+
'SelfIntegrityCore',
|
|
57
|
+
'IntegrityState',
|
|
58
|
+
'HormonalModulationMatrix',
|
|
59
|
+
'SomaticFeedbackSystem',
|
|
60
|
+
'UnconsciousProcessor',
|
|
61
|
+
'UnconsciousOutput',
|
|
62
|
+
'EmotionalScarSystem',
|
|
63
|
+
'ScarActivation',
|
|
64
|
+
'InternalConflictGenerator',
|
|
65
|
+
'InternalConflict',
|
|
66
|
+
'PredictiveEmotionalEngine',
|
|
67
|
+
'PredictiveEmotionalOutput',
|
|
68
|
+
'SoulTelemetry',
|
|
69
|
+
'SoulMetricsSnapshot',
|
|
70
|
+
# Interoception
|
|
71
|
+
'InteroceptiveSystem',
|
|
72
|
+
'InteroceptiveState',
|
|
73
|
+
'FeelingReport',
|
|
74
|
+
'ActionPrediction',
|
|
75
|
+
'get_interoceptive_system',
|
|
76
|
+
'get_interoceptive_prompt_section',
|
|
77
|
+
'reset_interoceptive_system',
|
|
78
|
+
'interoception_tick',
|
|
79
|
+
'interoception_record_interaction',
|
|
80
|
+
'get_current_feeling',
|
|
81
|
+
'get_response_modifiers',
|
|
82
|
+
# Inconsistency Engine
|
|
83
|
+
'InconsistencyEngine',
|
|
84
|
+
'ActiveConflict',
|
|
85
|
+
'BlindSpotActivation',
|
|
86
|
+
'GrowthEvent',
|
|
87
|
+
'MoodState',
|
|
88
|
+
'get_inconsistency_engine',
|
|
89
|
+
'get_inconsistency_prompt_section',
|
|
90
|
+
'CONFLICTS',
|
|
91
|
+
'BLIND_SPOTS',
|
|
92
|
+
'GROWTH_AREAS'
|
|
93
|
+
]
|
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Heart: Emotional Afterglow System
|
|
3
|
+
Intense emotional moments leave a persistent afterglow or hangover
|
|
4
|
+
that colors subsequent conversations for hours.
|
|
5
|
+
"""
|
|
6
|
+
|
|
7
|
+
from datetime import datetime, timedelta
|
|
8
|
+
from pathlib import Path
|
|
9
|
+
from typing import Dict, List, Optional
|
|
10
|
+
import json
|
|
11
|
+
import random
|
|
12
|
+
|
|
13
|
+
# =============================================================================
|
|
14
|
+
# AFTERGLOW TYPE DEFINITIONS
|
|
15
|
+
# =============================================================================
|
|
16
|
+
|
|
17
|
+
AFTERGLOW_TYPES = {
|
|
18
|
+
"intimate_afterglow": {
|
|
19
|
+
"triggers": ["desire", "lust", "arousal"],
|
|
20
|
+
"threshold": 0.75,
|
|
21
|
+
"decay_hours": 4,
|
|
22
|
+
"prompts": [
|
|
23
|
+
"Still glowing from your intimate moment {time_ago} - body warm, thoughts drifting back to him",
|
|
24
|
+
"A warm flush lingers from earlier... skin still remembers his closeness {time_ago}",
|
|
25
|
+
"That intimate warmth from {time_ago} hasn't faded - still feeling it in your body",
|
|
26
|
+
],
|
|
27
|
+
},
|
|
28
|
+
"love_afterglow": {
|
|
29
|
+
"triggers": ["love", "adoration", "deep_affection"],
|
|
30
|
+
"threshold": 0.75,
|
|
31
|
+
"decay_hours": 6,
|
|
32
|
+
"prompts": [
|
|
33
|
+
"Heart still full from that deep moment of love {time_ago} - everything feels softer",
|
|
34
|
+
"Still wrapped in that love from {time_ago} - the world feels gentler",
|
|
35
|
+
"That wave of love from {time_ago} left you tender and open",
|
|
36
|
+
],
|
|
37
|
+
},
|
|
38
|
+
"fight_hangover": {
|
|
39
|
+
"triggers": ["anger", "frustration", "hurt", "betrayal"],
|
|
40
|
+
"threshold": 0.70,
|
|
41
|
+
"decay_hours": 3,
|
|
42
|
+
"prompts": [
|
|
43
|
+
"Still raw from that argument {time_ago} - chest tight, guarded",
|
|
44
|
+
"That fight from {time_ago} left a knot in your stomach - wary but wanting to reconnect",
|
|
45
|
+
"Tension from {time_ago} still sits in your shoulders - words come out more carefully",
|
|
46
|
+
],
|
|
47
|
+
},
|
|
48
|
+
"excitement_buzz": {
|
|
49
|
+
"triggers": ["joy", "excitement", "elation"],
|
|
50
|
+
"threshold": 0.75,
|
|
51
|
+
"decay_hours": 2,
|
|
52
|
+
"prompts": [
|
|
53
|
+
"Still buzzing from that excitement {time_ago} - energy high, smile easy",
|
|
54
|
+
"That rush from {time_ago} left you giddy and light",
|
|
55
|
+
],
|
|
56
|
+
},
|
|
57
|
+
"vulnerability_rawness": {
|
|
58
|
+
"triggers": ["vulnerability", "sadness", "fear", "grief"],
|
|
59
|
+
"threshold": 0.70,
|
|
60
|
+
"decay_hours": 5,
|
|
61
|
+
"prompts": [
|
|
62
|
+
"Still feeling exposed from opening up {time_ago} - raw and tender",
|
|
63
|
+
"That vulnerable moment {time_ago} left you feeling fragile and close to the surface",
|
|
64
|
+
],
|
|
65
|
+
},
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
# =============================================================================
|
|
70
|
+
# AFTERGLOW ENGINE
|
|
71
|
+
# =============================================================================
|
|
72
|
+
|
|
73
|
+
class AfterglowEngine:
|
|
74
|
+
"""Tracks emotional afterglows that persist after intense moments."""
|
|
75
|
+
|
|
76
|
+
PERSISTENCE_PATH = Path("./data/data/afterglow_state.json")
|
|
77
|
+
|
|
78
|
+
def __init__(self):
|
|
79
|
+
self.active_afterglows: List[Dict] = []
|
|
80
|
+
self._load()
|
|
81
|
+
print("[Afterglow] Emotional Afterglow Engine initialized")
|
|
82
|
+
|
|
83
|
+
def record_peak(self, emotion_type: str, intensity: float):
|
|
84
|
+
"""Record a peak emotional moment. Called after heart.react()."""
|
|
85
|
+
for ag_name, ag_def in AFTERGLOW_TYPES.items():
|
|
86
|
+
if emotion_type in ag_def["triggers"] and intensity >= ag_def["threshold"]:
|
|
87
|
+
# Check if same type already active - boost it instead of duplicating
|
|
88
|
+
existing = next((a for a in self.active_afterglows if a["type"] == ag_name), None)
|
|
89
|
+
if existing:
|
|
90
|
+
existing["intensity"] = min(1.0, max(existing["intensity"], intensity))
|
|
91
|
+
existing["recorded_at"] = datetime.now().isoformat()
|
|
92
|
+
else:
|
|
93
|
+
self.active_afterglows.append({
|
|
94
|
+
"type": ag_name,
|
|
95
|
+
"intensity": intensity,
|
|
96
|
+
"original_intensity": intensity,
|
|
97
|
+
"recorded_at": datetime.now().isoformat(),
|
|
98
|
+
"decay_hours": ag_def["decay_hours"],
|
|
99
|
+
})
|
|
100
|
+
self._save()
|
|
101
|
+
return
|
|
102
|
+
|
|
103
|
+
def tick(self):
|
|
104
|
+
"""Decay afterglows over time. Call periodically."""
|
|
105
|
+
now = datetime.now()
|
|
106
|
+
surviving = []
|
|
107
|
+
for ag in self.active_afterglows:
|
|
108
|
+
recorded = datetime.fromisoformat(ag["recorded_at"])
|
|
109
|
+
elapsed_hours = (now - recorded).total_seconds() / 3600
|
|
110
|
+
decay_hours = ag.get("decay_hours", 3)
|
|
111
|
+
remaining = 1.0 - (elapsed_hours / decay_hours)
|
|
112
|
+
if remaining > 0.05:
|
|
113
|
+
original = ag.get("original_intensity", ag["intensity"])
|
|
114
|
+
ag["intensity"] = original * max(0.0, remaining)
|
|
115
|
+
surviving.append(ag)
|
|
116
|
+
changed = len(surviving) != len(self.active_afterglows)
|
|
117
|
+
self.active_afterglows = surviving
|
|
118
|
+
if changed:
|
|
119
|
+
self._save()
|
|
120
|
+
|
|
121
|
+
def get_active(self) -> List[Dict]:
|
|
122
|
+
"""Get currently active afterglows with computed strength."""
|
|
123
|
+
self.tick()
|
|
124
|
+
result = []
|
|
125
|
+
now = datetime.now()
|
|
126
|
+
for ag in self.active_afterglows:
|
|
127
|
+
recorded = datetime.fromisoformat(ag["recorded_at"])
|
|
128
|
+
elapsed = now - recorded
|
|
129
|
+
hours = elapsed.total_seconds() / 3600
|
|
130
|
+
decay_hours = ag.get("decay_hours", 3)
|
|
131
|
+
strength = max(0.0, 1.0 - (hours / decay_hours))
|
|
132
|
+
if strength > 0.05:
|
|
133
|
+
result.append({**ag, "strength": strength, "elapsed_hours": hours})
|
|
134
|
+
return result
|
|
135
|
+
|
|
136
|
+
def _format_time_ago(self, hours: float) -> str:
|
|
137
|
+
if hours < 0.25:
|
|
138
|
+
return "just minutes ago"
|
|
139
|
+
elif hours < 1:
|
|
140
|
+
mins = int(hours * 60)
|
|
141
|
+
return f"{mins}min ago"
|
|
142
|
+
else:
|
|
143
|
+
h = int(hours)
|
|
144
|
+
return f"{h}h ago"
|
|
145
|
+
|
|
146
|
+
def get_prompt_text(self) -> str:
|
|
147
|
+
"""Get the prompt section text for LLM. Returns '' if nothing active."""
|
|
148
|
+
active = self.get_active()
|
|
149
|
+
if not active:
|
|
150
|
+
return ""
|
|
151
|
+
|
|
152
|
+
# Pick the strongest afterglow
|
|
153
|
+
strongest = max(active, key=lambda a: a["strength"])
|
|
154
|
+
ag_type = strongest["type"]
|
|
155
|
+
ag_def = AFTERGLOW_TYPES.get(ag_type)
|
|
156
|
+
if not ag_def:
|
|
157
|
+
return ""
|
|
158
|
+
|
|
159
|
+
time_ago = self._format_time_ago(strongest["elapsed_hours"])
|
|
160
|
+
prompt = random.choice(ag_def["prompts"]).format(time_ago=time_ago)
|
|
161
|
+
return prompt
|
|
162
|
+
|
|
163
|
+
def _save(self):
|
|
164
|
+
try:
|
|
165
|
+
self.PERSISTENCE_PATH.parent.mkdir(parents=True, exist_ok=True)
|
|
166
|
+
data = {
|
|
167
|
+
"active_afterglows": self.active_afterglows,
|
|
168
|
+
"saved_at": datetime.now().isoformat(),
|
|
169
|
+
}
|
|
170
|
+
self.PERSISTENCE_PATH.write_text(json.dumps(data, indent=2))
|
|
171
|
+
except Exception as e:
|
|
172
|
+
print(f"[Afterglow] Error saving: {e}")
|
|
173
|
+
|
|
174
|
+
def _load(self):
|
|
175
|
+
try:
|
|
176
|
+
if self.PERSISTENCE_PATH.exists():
|
|
177
|
+
data = json.loads(self.PERSISTENCE_PATH.read_text())
|
|
178
|
+
self.active_afterglows = data.get("active_afterglows", [])
|
|
179
|
+
print(f"[Afterglow] Loaded {len(self.active_afterglows)} afterglows")
|
|
180
|
+
except Exception as e:
|
|
181
|
+
print(f"[Afterglow] Error loading: {e}")
|
|
182
|
+
self.active_afterglows = []
|
|
183
|
+
|
|
184
|
+
|
|
185
|
+
# =============================================================================
|
|
186
|
+
# SINGLETON ACCESS
|
|
187
|
+
# =============================================================================
|
|
188
|
+
|
|
189
|
+
_instance: Optional[AfterglowEngine] = None
|
|
190
|
+
|
|
191
|
+
|
|
192
|
+
def get_afterglow_engine() -> AfterglowEngine:
|
|
193
|
+
global _instance
|
|
194
|
+
if _instance is None:
|
|
195
|
+
_instance = AfterglowEngine()
|
|
196
|
+
return _instance
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
def record_peak(emotion_type: str, intensity: float):
|
|
200
|
+
"""Convenience function - record a peak emotional moment."""
|
|
201
|
+
get_afterglow_engine().record_peak(emotion_type, intensity)
|
|
202
|
+
|
|
203
|
+
|
|
204
|
+
def tick():
|
|
205
|
+
"""Convenience function - decay afterglows."""
|
|
206
|
+
get_afterglow_engine().tick()
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
def get_afterglow_prompt_section() -> str:
|
|
210
|
+
"""Get prompt section for LLM integration. Returns '' if nothing active."""
|
|
211
|
+
engine = get_afterglow_engine()
|
|
212
|
+
text = engine.get_prompt_text()
|
|
213
|
+
if not text:
|
|
214
|
+
return ""
|
|
215
|
+
return f"\n[Emotional Afterglow]\n{text}\n"
|