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,190 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Output: Vibe TTS
|
|
3
|
+
Connect to VibeVoice server for natural text-to-speech
|
|
4
|
+
|
|
5
|
+
Max 5000 chars per request - splits longer texts into parts
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
import aiohttp
|
|
9
|
+
import asyncio
|
|
10
|
+
import re
|
|
11
|
+
import tempfile
|
|
12
|
+
import subprocess
|
|
13
|
+
from pathlib import Path
|
|
14
|
+
|
|
15
|
+
VOICE_OUTPUT_PATH = "/tmp/alive_ai_voice.ogg"
|
|
16
|
+
MAX_CHARS = 5000 # VibeTTS limit
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class VibeTTS:
|
|
20
|
+
"""Text-to-speech via VibeVoice server"""
|
|
21
|
+
|
|
22
|
+
DEFAULT_VOICE = "en-Emma_woman"
|
|
23
|
+
|
|
24
|
+
CFG_MOOD = {
|
|
25
|
+
"chill": 1.5, "neutral": 1.5, "happy": 1.6,
|
|
26
|
+
"flirty": 1.6, "excited": 1.7, "high_desire": 1.9, "intense": 2.0
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
def __init__(self, url: str = "http://localhost:8080"):
|
|
30
|
+
self.url = url.rstrip("/")
|
|
31
|
+
|
|
32
|
+
def prepare_text(self, text: str) -> str:
|
|
33
|
+
"""Clean text for TTS - removes formatting and EMOJIS"""
|
|
34
|
+
# Remove markdown formatting
|
|
35
|
+
text = re.sub(r'\*+[^*]+\*+', '', text) # Remove *bold*/**bold** content
|
|
36
|
+
text = text.replace("__", "").replace("_", "").replace("~", "")
|
|
37
|
+
text = re.sub(r'\.{3,}', '...', text)
|
|
38
|
+
text = re.sub(r'!{2,}', '!', text)
|
|
39
|
+
text = re.sub(r'\?{2,}', '?', text)
|
|
40
|
+
|
|
41
|
+
# Remove ALL emojis - they break TTS
|
|
42
|
+
text = re.sub(r'[\U00010000-\U0010ffff]', '', text)
|
|
43
|
+
# Remove common emoji ranges
|
|
44
|
+
text = re.sub(r'[\U0001F600-\U0001F64F]', '', text) # emoticons
|
|
45
|
+
text = re.sub(r'[\U0001F300-\U0001F5FF]', '', text) # symbols & pictographs
|
|
46
|
+
text = re.sub(r'[\U0001F680-\U0001F6FF]', '', text) # transport & map
|
|
47
|
+
text = re.sub(r'[\U0001F700-\U0001F77F]', '', text) # alchemical
|
|
48
|
+
text = re.sub(r'[\U0001F780-\U0001F7FF]', '', text) # Geometric Shapes
|
|
49
|
+
text = re.sub(r'[\U0001F800-\U0001F8FF]', '', text) # Supplemental Arrows-C
|
|
50
|
+
text = re.sub(r'[\U0001F900-\U0001F9FF]', '', text) # Supplemental Symbols and Pictographs
|
|
51
|
+
text = re.sub(r'[\U0001FA00-\U0001FA6F]', '', text) # Chess Symbols
|
|
52
|
+
text = re.sub(r'[\U0001FA70-\U0001FAFF]', '', text) # Symbols and Pictographs Extended-A
|
|
53
|
+
text = re.sub(r'[\U00002702-\U000027B0]', '', text) # Dingbats
|
|
54
|
+
text = re.sub(r'[\U000024C2-\U0001F251]', '', text) # Enclosed characters
|
|
55
|
+
text = re.sub(r'[\U0001F1E0-\U0001F1FF]', '', text) # Flags
|
|
56
|
+
|
|
57
|
+
# Clean up extra spaces
|
|
58
|
+
text = re.sub(r'\s+', ' ', text)
|
|
59
|
+
return text.strip()
|
|
60
|
+
|
|
61
|
+
def split_text(self, text: str) -> list:
|
|
62
|
+
"""Split long text at paragraph boundaries"""
|
|
63
|
+
if len(text) <= MAX_CHARS:
|
|
64
|
+
return [text]
|
|
65
|
+
|
|
66
|
+
parts = []
|
|
67
|
+
paragraphs = text.split('\n\n')
|
|
68
|
+
current = ""
|
|
69
|
+
|
|
70
|
+
for para in paragraphs:
|
|
71
|
+
if len(current) + len(para) + 2 <= MAX_CHARS:
|
|
72
|
+
current = current + "\n\n" + para if current else para
|
|
73
|
+
else:
|
|
74
|
+
if current:
|
|
75
|
+
parts.append(current)
|
|
76
|
+
# If single paragraph is too long, split by sentences
|
|
77
|
+
if len(para) > MAX_CHARS:
|
|
78
|
+
sentences = para.replace('. ', '.\n').split('\n')
|
|
79
|
+
chunk = ""
|
|
80
|
+
for s in sentences:
|
|
81
|
+
if len(chunk) + len(s) + 1 <= MAX_CHARS:
|
|
82
|
+
chunk = chunk + " " + s if chunk else s
|
|
83
|
+
else:
|
|
84
|
+
if chunk:
|
|
85
|
+
parts.append(chunk)
|
|
86
|
+
chunk = s
|
|
87
|
+
if chunk:
|
|
88
|
+
parts.append(chunk)
|
|
89
|
+
else:
|
|
90
|
+
current = para
|
|
91
|
+
|
|
92
|
+
if current:
|
|
93
|
+
parts.append(current)
|
|
94
|
+
|
|
95
|
+
return parts
|
|
96
|
+
|
|
97
|
+
def get_cfg_for_mood(self, mood: str) -> float:
|
|
98
|
+
return self.CFG_MOOD.get(mood, 1.5)
|
|
99
|
+
|
|
100
|
+
async def generate(self, text: str, voice: str = None,
|
|
101
|
+
cfg: float = None, mood: str = "neutral") -> str:
|
|
102
|
+
"""Generate audio - handles long texts by splitting"""
|
|
103
|
+
if voice is None:
|
|
104
|
+
voice = self.DEFAULT_VOICE
|
|
105
|
+
if cfg is None:
|
|
106
|
+
cfg = self.get_cfg_for_mood(mood)
|
|
107
|
+
|
|
108
|
+
text = self.prepare_text(text)
|
|
109
|
+
print(f"[VibeTTS] Generating voice for {len(text)} chars...")
|
|
110
|
+
|
|
111
|
+
# Split if needed
|
|
112
|
+
parts = self.split_text(text)
|
|
113
|
+
if len(parts) > 1:
|
|
114
|
+
print(f"[VibeTTS] Split into {len(parts)} parts")
|
|
115
|
+
|
|
116
|
+
audio_parts = []
|
|
117
|
+
for i, part in enumerate(parts):
|
|
118
|
+
print(f"[VibeTTS] Processing part {i+1}/{len(parts)} ({len(part)} chars)")
|
|
119
|
+
audio = await self._generate_single(part, voice, cfg)
|
|
120
|
+
if audio:
|
|
121
|
+
audio_parts.append(audio)
|
|
122
|
+
else:
|
|
123
|
+
print(f"[VibeTTS] Part {i+1} failed")
|
|
124
|
+
|
|
125
|
+
if not audio_parts:
|
|
126
|
+
return ""
|
|
127
|
+
|
|
128
|
+
# Combine all parts
|
|
129
|
+
if len(audio_parts) == 1:
|
|
130
|
+
Path(VOICE_OUTPUT_PATH).write_bytes(audio_parts[0])
|
|
131
|
+
else:
|
|
132
|
+
# Use ffmpeg to properly concatenate OGG files
|
|
133
|
+
temp_files = []
|
|
134
|
+
try:
|
|
135
|
+
for i, part in enumerate(audio_parts):
|
|
136
|
+
tf = tempfile.NamedTemporaryFile(suffix=".ogg", delete=False)
|
|
137
|
+
tf.write(part)
|
|
138
|
+
tf.close()
|
|
139
|
+
temp_files.append(tf.name)
|
|
140
|
+
# Create concat list file
|
|
141
|
+
list_file = tempfile.NamedTemporaryFile(mode="w", suffix=".txt", delete=False)
|
|
142
|
+
for tf_name in temp_files:
|
|
143
|
+
list_file.write(f"file '{tf_name}'\n")
|
|
144
|
+
list_file.close()
|
|
145
|
+
subprocess.run(
|
|
146
|
+
["ffmpeg", "-y", "-f", "concat", "-safe", "0",
|
|
147
|
+
"-i", list_file.name, "-c", "copy", VOICE_OUTPUT_PATH],
|
|
148
|
+
capture_output=True, timeout=30
|
|
149
|
+
)
|
|
150
|
+
Path(list_file.name).unlink(missing_ok=True)
|
|
151
|
+
except Exception as e:
|
|
152
|
+
print(f"[VibeTTS] ffmpeg concat failed, using first part: {e}")
|
|
153
|
+
Path(VOICE_OUTPUT_PATH).write_bytes(audio_parts[0])
|
|
154
|
+
finally:
|
|
155
|
+
for tf_name in temp_files:
|
|
156
|
+
Path(tf_name).unlink(missing_ok=True)
|
|
157
|
+
print(f"[VibeTTS] Generated audio file")
|
|
158
|
+
return VOICE_OUTPUT_PATH
|
|
159
|
+
|
|
160
|
+
async def _generate_single(self, text: str, voice: str, cfg: float) -> bytes:
|
|
161
|
+
"""Generate single audio part"""
|
|
162
|
+
try:
|
|
163
|
+
async with aiohttp.ClientSession() as session:
|
|
164
|
+
params = {"text": text, "voice": voice, "cfg": str(cfg)}
|
|
165
|
+
async with session.get(
|
|
166
|
+
f"{self.url}/tts",
|
|
167
|
+
params=params,
|
|
168
|
+
timeout=aiohttp.ClientTimeout(total=600)
|
|
169
|
+
) as resp:
|
|
170
|
+
if resp.status == 200:
|
|
171
|
+
return await resp.read()
|
|
172
|
+
else:
|
|
173
|
+
error = await resp.text()
|
|
174
|
+
print(f"[VibeTTS] Error {resp.status}: {error[:200]}")
|
|
175
|
+
return b""
|
|
176
|
+
except asyncio.TimeoutError:
|
|
177
|
+
print("[VibeTTS] Timeout")
|
|
178
|
+
return b""
|
|
179
|
+
except Exception as e:
|
|
180
|
+
print(f"[VibeTTS] Error: {e}")
|
|
181
|
+
return b""
|
|
182
|
+
|
|
183
|
+
async def is_available(self) -> bool:
|
|
184
|
+
"""Check if server is available"""
|
|
185
|
+
try:
|
|
186
|
+
async with aiohttp.ClientSession() as session:
|
|
187
|
+
async with session.get(f"{self.url}/health", timeout=2) as resp:
|
|
188
|
+
return resp.status == 200
|
|
189
|
+
except:
|
|
190
|
+
return False
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "alive-ai",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Local-first emotional AI runtime with memory, impulses, and a live dashboard.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"homepage": "https://vindepemarte.github.io/alive-ai/",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/vindepemarte/alive-ai.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/vindepemarte/alive-ai/issues"
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"alive-ai": "cli/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"alive_ai",
|
|
19
|
+
"brain",
|
|
20
|
+
"cli",
|
|
21
|
+
"config/*.example.json",
|
|
22
|
+
"config/*.example.md",
|
|
23
|
+
"core",
|
|
24
|
+
"demo",
|
|
25
|
+
"docs",
|
|
26
|
+
"heart",
|
|
27
|
+
"input",
|
|
28
|
+
"main.py",
|
|
29
|
+
"manifest.md",
|
|
30
|
+
"mypics/.gitkeep",
|
|
31
|
+
"myvids/.gitkeep",
|
|
32
|
+
"output",
|
|
33
|
+
"requirements.txt",
|
|
34
|
+
"skills",
|
|
35
|
+
"webui",
|
|
36
|
+
"Dockerfile",
|
|
37
|
+
"docker-compose.yml",
|
|
38
|
+
"LICENSE",
|
|
39
|
+
"README.md",
|
|
40
|
+
"pyproject.toml"
|
|
41
|
+
],
|
|
42
|
+
"keywords": [
|
|
43
|
+
"ai",
|
|
44
|
+
"agent",
|
|
45
|
+
"companion",
|
|
46
|
+
"emotional-ai",
|
|
47
|
+
"local-first",
|
|
48
|
+
"memory",
|
|
49
|
+
"telegram",
|
|
50
|
+
"dashboard"
|
|
51
|
+
],
|
|
52
|
+
"engines": {
|
|
53
|
+
"node": ">=18"
|
|
54
|
+
},
|
|
55
|
+
"scripts": {
|
|
56
|
+
"smoke": "node cli/index.js --help && python3 -m compileall -q alive_ai brain core heart input output skills webui"
|
|
57
|
+
}
|
|
58
|
+
}
|
package/pyproject.toml
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
[project]
|
|
2
|
+
name = "alive-ai-runtime"
|
|
3
|
+
version = "0.1.0"
|
|
4
|
+
description = "Local-first emotional AI runtime with memory, impulses, and a live dashboard."
|
|
5
|
+
readme = "README.md"
|
|
6
|
+
requires-python = ">=3.11"
|
|
7
|
+
license = { text = "MIT" }
|
|
8
|
+
authors = [{ name = "Vindepemarte" }]
|
|
9
|
+
|
|
10
|
+
[tool.setuptools]
|
|
11
|
+
py-modules = ["main"]
|
|
12
|
+
|
|
13
|
+
[tool.setuptools.packages.find]
|
|
14
|
+
include = [
|
|
15
|
+
"alive_ai*",
|
|
16
|
+
"brain*",
|
|
17
|
+
"core*",
|
|
18
|
+
"heart*",
|
|
19
|
+
"input*",
|
|
20
|
+
"output*",
|
|
21
|
+
"skills*",
|
|
22
|
+
"webui*"
|
|
23
|
+
]
|
package/requirements.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
aiohttp>=3.9.0
|
|
2
|
+
python-telegram-bot>=20.0
|
|
3
|
+
SpeechRecognition>=3.10.0
|
|
4
|
+
|
|
5
|
+
# Embedding model
|
|
6
|
+
sentence-transformers>=2.2.0
|
|
7
|
+
torch>=2.0.0
|
|
8
|
+
|
|
9
|
+
# Redis with vector search
|
|
10
|
+
redis>=5.0.0
|
|
11
|
+
watchdog
|
|
12
|
+
fastapi>=0.100.0
|
|
13
|
+
uvicorn>=0.23.0
|
|
14
|
+
sse-starlette>=1.6.0
|
|
15
|
+
|
|
16
|
+
# TTS
|
|
17
|
+
gtts>=2.3.0
|
|
18
|
+
pydub>=0.25.0
|
|
19
|
+
|
|
20
|
+
# Memory monitoring
|
|
21
|
+
psutil>=5.9.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""Skills"""
|