affective-longing 0.1.0__tar.gz

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.
Files changed (26) hide show
  1. affective_longing-0.1.0/PKG-INFO +260 -0
  2. affective_longing-0.1.0/README.md +241 -0
  3. affective_longing-0.1.0/pyproject.toml +47 -0
  4. affective_longing-0.1.0/setup.cfg +4 -0
  5. affective_longing-0.1.0/src/affective_longing/__init__.py +47 -0
  6. affective_longing-0.1.0/src/affective_longing/emotion/__init__.py +18 -0
  7. affective_longing-0.1.0/src/affective_longing/emotion/engine.py +235 -0
  8. affective_longing-0.1.0/src/affective_longing/emotion/vad.py +116 -0
  9. affective_longing-0.1.0/src/affective_longing/engine.py +288 -0
  10. affective_longing-0.1.0/src/affective_longing/memory/__init__.py +7 -0
  11. affective_longing-0.1.0/src/affective_longing/memory/memory_store.py +100 -0
  12. affective_longing-0.1.0/src/affective_longing/memory/store.py +87 -0
  13. affective_longing-0.1.0/src/affective_longing/memory/trigger_engine.py +78 -0
  14. affective_longing-0.1.0/src/affective_longing/relationship/__init__.py +22 -0
  15. affective_longing-0.1.0/src/affective_longing/relationship/ou_process.py +94 -0
  16. affective_longing-0.1.0/src/affective_longing/relationship/stages.py +79 -0
  17. affective_longing-0.1.0/src/affective_longing/relationship/state_machine.py +397 -0
  18. affective_longing-0.1.0/src/affective_longing.egg-info/PKG-INFO +260 -0
  19. affective_longing-0.1.0/src/affective_longing.egg-info/SOURCES.txt +24 -0
  20. affective_longing-0.1.0/src/affective_longing.egg-info/dependency_links.txt +1 -0
  21. affective_longing-0.1.0/src/affective_longing.egg-info/requires.txt +9 -0
  22. affective_longing-0.1.0/src/affective_longing.egg-info/top_level.txt +1 -0
  23. affective_longing-0.1.0/tests/test_emotion.py +119 -0
  24. affective_longing-0.1.0/tests/test_integration.py +104 -0
  25. affective_longing-0.1.0/tests/test_memory.py +115 -0
  26. affective_longing-0.1.0/tests/test_relationship.py +149 -0
@@ -0,0 +1,260 @@
1
+ Metadata-Version: 2.4
2
+ Name: affective-longing
3
+ Version: 0.1.0
4
+ Summary: Emotional extension for AI companions โ€” memory triggers, relationship states, self-emotion.
5
+ Author-email: pear think <gangwang694@gmail.com>
6
+ License: MIT
7
+ Project-URL: Homepage, https://github.com/pearthink123/affective-longing
8
+ Project-URL: Repository, https://github.com/pearthink123/affective-longing
9
+ Keywords: ai,companion,emotion,memory,longing,relationship
10
+ Requires-Python: >=3.10
11
+ Description-Content-Type: text/markdown
12
+ Requires-Dist: revive-companion>=1.0.0
13
+ Requires-Dist: numpy>=1.23
14
+ Provides-Extra: memory
15
+ Requires-Dist: sentence-transformers>=3.0.0; extra == "memory"
16
+ Requires-Dist: chromadb>=0.5.0; extra == "memory"
17
+ Provides-Extra: test
18
+ Requires-Dist: pytest>=7.0; extra == "test"
19
+
20
+ # affective-longing ๐Ÿง ๐Ÿ’ซ
21
+
22
+ **Emotional extension for AI companions โ€” beyond timing, into feeling.**
23
+
24
+ Built on [revive-companion](https://github.com/pearthink123/revive-companion) (Poisson timing + Bayesian inference).
25
+
26
+ ## Architecture
27
+
28
+ ```
29
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
30
+ โ”‚ AffectiveLonging โ”‚
31
+ โ”‚ โ”‚
32
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
33
+ โ”‚ โ”‚ Memory โ”‚ โ”‚ Relationship โ”‚ โ”‚ Emotion โ”‚ โ”‚
34
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
35
+ โ”‚ โ”‚ ChromaDB โ”‚ โ”‚ HMM โ”‚ โ”‚ VAD Model โ”‚ โ”‚
36
+ โ”‚ โ”‚ Embeddings โ”‚ โ”‚ OU Process โ”‚ โ”‚ Valence โ”‚ โ”‚
37
+ โ”‚ โ”‚ Similarity โ”‚ โ”‚ 6 Stages โ”‚ โ”‚ Arousal โ”‚ โ”‚
38
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Dominance โ”‚ โ”‚
39
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
40
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
41
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
42
+ โ”‚ โ–ผ โ”‚
43
+ โ”‚ tick() โ†’ AffectiveResult โ”‚
44
+ โ”‚ โ”‚
45
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
46
+ โ”‚ โ”‚ revive-companion (base) โ”‚ โ”‚
47
+ โ”‚ โ”‚ Poisson Process โ†’ InfoGain โ†’ Bayesian โ†’ Decision โ”‚ โ”‚
48
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
49
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
50
+ ```
51
+
52
+ ## Three Layers
53
+
54
+ ### 1. Memory โ€” Past triggers present
55
+
56
+ Store conversations as embeddings. When current context matches past memories, longing probability gets a boost.
57
+
58
+ ```python
59
+ engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
60
+ engine.remember("ๆˆ‘ไปฌ็ฌฌไธ€ๆฌก็œ‹็”ตๅฝฑๆ˜ฏใ€Šๆ˜Ÿ้™…็ฉฟ่ถŠใ€‹", tags=["movie"])
61
+
62
+ # Later...
63
+ result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")
64
+ # โ†’ Triggers "ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ" with similarity 0.988
65
+ # โ†’ Longing boost: +15%
66
+ ```
67
+
68
+ **Theory:** [Sentence embeddings](https://arxiv.org/abs/1708.00055) (all-MiniLM-L6-v2) + cosine similarity. Memory decay via [Ebbinghaus forgetting curve](https://en.wikipedia.org/wiki/Forgetting_curve).
69
+
70
+ ### 2. Relationship โ€” 6-stage lifecycle
71
+
72
+ Models relationship dynamics through discrete state transitions (HMM) + continuous emotional drift (Ornstein-Uhlenbeck process).
73
+
74
+ ```
75
+ ่ฟฝๆฑ‚ โ†’ ็”œ่œœ โ†’ ็ƒญๆ‹ โ†’ ๅนณ็จณ
76
+ โ†‘ โ†“
77
+ โ””โ”€โ”€โ”€โ”€ ไฟฎๅค โ† ๅ†ทๆˆ˜ โ†โ”€โ”€โ”˜
78
+ ```
79
+
80
+ ```python
81
+ engine.observe("affection") # intimacy +0.10
82
+ engine.observe("fight") # conflict +0.20, may โ†’ ๅ†ทๆˆ˜
83
+ engine.step_time(hours=24) # OU decay toward baseline
84
+ ```
85
+
86
+ **Theory:**
87
+ - **HMM:** Hidden states (relationship stages), observed events (user actions). Transition matrix modulated by intimacy/conflict levels.
88
+ - **Ornstein-Uhlenbeck:** Mean-reverting stochastic process. `dX = ฮธ(ฮผ - X)dt + ฯƒdW`. Models how intimacy/conflict drift toward baselines over time.
89
+
90
+ ### 3. Emotion โ€” VAD model
91
+
92
+ AI companion's internal emotional state modeled as 3D vector (Valence, Arousal, Dominance). Mapped to 11 discrete emotions.
93
+
94
+ ```python
95
+ state = engine.emotion.current_state
96
+ # EmotionalState(๐Ÿ˜Š joy, V=+0.65, A=0.58, D=0.55)
97
+ ```
98
+
99
+ | Dimension | Range | Meaning |
100
+ |-----------|-------|---------|
101
+ | Valence | -1 to +1 | Unhappy โ†” Happy |
102
+ | Arousal | 0 to 1 | Calm โ†” Excited |
103
+ | Dominance | 0 to 1 | Submissive โ†” Dominant |
104
+
105
+ **Theory:** [Russell's Circumplex Model (1980)](https://psycnet.apa.org/record/1981-25703-001) + [Mehrabian's PAD model (1996)](https://psycnet.apa.org/record/1996-97463-000). OU process for time decay, event-driven bumps for state changes.
106
+
107
+ ## Install
108
+
109
+ ```bash
110
+ # Base (Poisson + Bayesian from revive-companion)
111
+ pip install affective-longing
112
+
113
+ # With memory support (sentence-transformers + chromadb)
114
+ pip install affective-longing[memory]
115
+ ```
116
+
117
+ ## Quick Start
118
+
119
+ ```python
120
+ from affective_longing import AffectiveLonging
121
+
122
+ engine = AffectiveLonging(seed=42)
123
+
124
+ # 1. Store memories
125
+ engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
126
+ engine.remember("ไฝ ่ฏด่ฟ‡ๆœ€ๅ–œๆฌขๅƒ่‰่Ž“่›‹็ณ•", tags=["food"])
127
+
128
+ # 2. Observe events
129
+ engine.observe("reply_fast")
130
+ engine.observe("affection")
131
+
132
+ # 3. Let time pass
133
+ engine.step_time(hours=12)
134
+
135
+ # 4. Tick with context
136
+ result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")
137
+
138
+ print(f"Base probability: {result.base_probability:.1%}")
139
+ print(f"Memory trigger: {result.memory_trigger}")
140
+ print(f"Similarity: {result.memory_similarity:.3f}")
141
+ print(f"Boosted probability: {result.boosted_probability:.1%}")
142
+ print(f"Relationship: {result.relationship_stage.value}")
143
+ print(f"Emotion: {result.emotional_state.emoji} {result.emotional_state.emotion.value}")
144
+
145
+ if result.should_send:
146
+ send_message(result.prompt)
147
+ engine.record_send()
148
+ ```
149
+
150
+ ## API Reference
151
+
152
+ ### AffectiveLonging
153
+
154
+ ```python
155
+ engine = AffectiveLonging(
156
+ memory_persist_dir="./companion_memory_db", # Where to store embeddings
157
+ relationship_seed=None, # For reproducibility
158
+ emotion_seed=None,
159
+ **kwargs # Passed to PoissonLove
160
+ )
161
+ ```
162
+
163
+ **Methods:**
164
+
165
+ | Method | Description |
166
+ |--------|-------------|
167
+ | `remember(text, tags, **metadata)` | Store a memory. Returns memory ID. |
168
+ | `observe(event)` | Update relationship + emotion. Events: `reply_fast`, `reply_slow`, `no_reply`, `long_silence`, `affection`, `fight`, `apology`, `initiate`, `reject`, `long_message` |
169
+ | `step_time(hours)` | Advance time โ€” OU decay on all dimensions |
170
+ | `tick(now, context)` | Full pipeline. Returns `AffectiveResult`. |
171
+ | `record_reply(**kwargs)` | Record user reply (passthrough to base) |
172
+ | `record_send()` | Record that we sent (passthrough to base) |
173
+ | `get_state()` | Snapshot of all 3 layers |
174
+
175
+ ### AffectiveResult
176
+
177
+ ```python
178
+ @dataclass
179
+ class AffectiveResult:
180
+ # Decision
181
+ should_send: bool
182
+ base_probability: float
183
+
184
+ # Memory
185
+ memory_trigger: str | None
186
+ memory_similarity: float
187
+ longing_boost: float
188
+ boosted_probability: float
189
+
190
+ # Relationship
191
+ relationship_stage: Stage
192
+ intimacy: float
193
+ conflict: float
194
+
195
+ # Emotion
196
+ emotional_state: EmotionalState
197
+
198
+ # Output
199
+ prompt: str
200
+ reason: str
201
+ ```
202
+
203
+ ### Events
204
+
205
+ | Event | Description | Intimacy | Conflict |
206
+ |-------|-------------|----------|----------|
207
+ | `reply_fast` | User replied quickly | +0.05 | -0.02 |
208
+ | `reply_slow` | User replied slowly | -0.02 | +0.01 |
209
+ | `no_reply` | User didn't reply | -0.05 | +0.03 |
210
+ | `long_silence` | No contact >24h | -0.10 | +0.05 |
211
+ | `affection` | User showed warmth | +0.10 | -0.05 |
212
+ | `fight` | Conflict | -0.15 | +0.20 |
213
+ | `apology` | Someone apologized | +0.05 | -0.15 |
214
+ | `initiate` | User initiated contact | +0.08 | -0.02 |
215
+ | `reject` | User rejected us | -0.12 | +0.10 |
216
+
217
+ ## Examples
218
+
219
+ Run the quickstarts:
220
+
221
+ ```bash
222
+ # Memory triggers
223
+ python examples/quickstart.py
224
+
225
+ # Relationship state machine
226
+ python examples/quickstart_relationship.py
227
+
228
+ # VAD emotion engine
229
+ python examples/quickstart_emotion.py
230
+
231
+ # Full integration
232
+ python examples/quickstart_integrated.py
233
+ ```
234
+
235
+ ## Tests
236
+
237
+ ```bash
238
+ pip install -e ".[memory,test]"
239
+ pytest tests/ -v
240
+ ```
241
+
242
+ 62 tests covering all modules.
243
+
244
+ ## Theoretical Foundations
245
+
246
+ | Module | Theory | Reference |
247
+ |--------|--------|-----------|
248
+ | Memory | Sentence embeddings | [Reimers & Gurevych, 2019](https://arxiv.org/abs/1908.10084) |
249
+ | Memory | Forgetting curve | [Ebbinghaus, 1885](https://en.wikipedia.org/wiki/Forgetting_curve) |
250
+ | Relationship | Hidden Markov Model | [Rabiner, 1989](https://ieeexplore.ieee.org/document/18626) |
251
+ | Relationship | Ornstein-Uhlenbeck | [Uhlenbeck & Ornstein, 1930](https://journals.aps.org/pr/abstract/10.1103/PhysRev.36.823) |
252
+ | Emotion | Circumplex Model | [Russell, 1980](https://psycnet.apa.org/record/1981-25703-001) |
253
+ | Emotion | PAD Model | [Mehrabian, 1996](https://psycnet.apa.org/record/1996-97463-000) |
254
+ | Base | Poisson Process | [Poisson, 1837](https://en.wikipedia.org/wiki/Poisson_point_process) |
255
+ | Base | Bayesian Inference | [Bayes, 1763](https://en.wikipedia.org/wiki/Bayesian_inference) |
256
+ | Base | Information Gain | [Shannon, 1948](https://en.wikipedia.org/wiki/Information_gain) |
257
+
258
+ ## License
259
+
260
+ MIT
@@ -0,0 +1,241 @@
1
+ # affective-longing ๐Ÿง ๐Ÿ’ซ
2
+
3
+ **Emotional extension for AI companions โ€” beyond timing, into feeling.**
4
+
5
+ Built on [revive-companion](https://github.com/pearthink123/revive-companion) (Poisson timing + Bayesian inference).
6
+
7
+ ## Architecture
8
+
9
+ ```
10
+ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
11
+ โ”‚ AffectiveLonging โ”‚
12
+ โ”‚ โ”‚
13
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
14
+ โ”‚ โ”‚ Memory โ”‚ โ”‚ Relationship โ”‚ โ”‚ Emotion โ”‚ โ”‚
15
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
16
+ โ”‚ โ”‚ ChromaDB โ”‚ โ”‚ HMM โ”‚ โ”‚ VAD Model โ”‚ โ”‚
17
+ โ”‚ โ”‚ Embeddings โ”‚ โ”‚ OU Process โ”‚ โ”‚ Valence โ”‚ โ”‚
18
+ โ”‚ โ”‚ Similarity โ”‚ โ”‚ 6 Stages โ”‚ โ”‚ Arousal โ”‚ โ”‚
19
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚ Dominance โ”‚ โ”‚
20
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
21
+ โ”‚ โ”‚ โ”‚ โ”‚ โ”‚
22
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
23
+ โ”‚ โ–ผ โ”‚
24
+ โ”‚ tick() โ†’ AffectiveResult โ”‚
25
+ โ”‚ โ”‚
26
+ โ”‚ โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ” โ”‚
27
+ โ”‚ โ”‚ revive-companion (base) โ”‚ โ”‚
28
+ โ”‚ โ”‚ Poisson Process โ†’ InfoGain โ†’ Bayesian โ†’ Decision โ”‚ โ”‚
29
+ โ”‚ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜ โ”‚
30
+ โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
31
+ ```
32
+
33
+ ## Three Layers
34
+
35
+ ### 1. Memory โ€” Past triggers present
36
+
37
+ Store conversations as embeddings. When current context matches past memories, longing probability gets a boost.
38
+
39
+ ```python
40
+ engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
41
+ engine.remember("ๆˆ‘ไปฌ็ฌฌไธ€ๆฌก็œ‹็”ตๅฝฑๆ˜ฏใ€Šๆ˜Ÿ้™…็ฉฟ่ถŠใ€‹", tags=["movie"])
42
+
43
+ # Later...
44
+ result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")
45
+ # โ†’ Triggers "ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ" with similarity 0.988
46
+ # โ†’ Longing boost: +15%
47
+ ```
48
+
49
+ **Theory:** [Sentence embeddings](https://arxiv.org/abs/1708.00055) (all-MiniLM-L6-v2) + cosine similarity. Memory decay via [Ebbinghaus forgetting curve](https://en.wikipedia.org/wiki/Forgetting_curve).
50
+
51
+ ### 2. Relationship โ€” 6-stage lifecycle
52
+
53
+ Models relationship dynamics through discrete state transitions (HMM) + continuous emotional drift (Ornstein-Uhlenbeck process).
54
+
55
+ ```
56
+ ่ฟฝๆฑ‚ โ†’ ็”œ่œœ โ†’ ็ƒญๆ‹ โ†’ ๅนณ็จณ
57
+ โ†‘ โ†“
58
+ โ””โ”€โ”€โ”€โ”€ ไฟฎๅค โ† ๅ†ทๆˆ˜ โ†โ”€โ”€โ”˜
59
+ ```
60
+
61
+ ```python
62
+ engine.observe("affection") # intimacy +0.10
63
+ engine.observe("fight") # conflict +0.20, may โ†’ ๅ†ทๆˆ˜
64
+ engine.step_time(hours=24) # OU decay toward baseline
65
+ ```
66
+
67
+ **Theory:**
68
+ - **HMM:** Hidden states (relationship stages), observed events (user actions). Transition matrix modulated by intimacy/conflict levels.
69
+ - **Ornstein-Uhlenbeck:** Mean-reverting stochastic process. `dX = ฮธ(ฮผ - X)dt + ฯƒdW`. Models how intimacy/conflict drift toward baselines over time.
70
+
71
+ ### 3. Emotion โ€” VAD model
72
+
73
+ AI companion's internal emotional state modeled as 3D vector (Valence, Arousal, Dominance). Mapped to 11 discrete emotions.
74
+
75
+ ```python
76
+ state = engine.emotion.current_state
77
+ # EmotionalState(๐Ÿ˜Š joy, V=+0.65, A=0.58, D=0.55)
78
+ ```
79
+
80
+ | Dimension | Range | Meaning |
81
+ |-----------|-------|---------|
82
+ | Valence | -1 to +1 | Unhappy โ†” Happy |
83
+ | Arousal | 0 to 1 | Calm โ†” Excited |
84
+ | Dominance | 0 to 1 | Submissive โ†” Dominant |
85
+
86
+ **Theory:** [Russell's Circumplex Model (1980)](https://psycnet.apa.org/record/1981-25703-001) + [Mehrabian's PAD model (1996)](https://psycnet.apa.org/record/1996-97463-000). OU process for time decay, event-driven bumps for state changes.
87
+
88
+ ## Install
89
+
90
+ ```bash
91
+ # Base (Poisson + Bayesian from revive-companion)
92
+ pip install affective-longing
93
+
94
+ # With memory support (sentence-transformers + chromadb)
95
+ pip install affective-longing[memory]
96
+ ```
97
+
98
+ ## Quick Start
99
+
100
+ ```python
101
+ from affective_longing import AffectiveLonging
102
+
103
+ engine = AffectiveLonging(seed=42)
104
+
105
+ # 1. Store memories
106
+ engine.remember("ไฝ ๅ–œๆฌขไธ‹้›จๅคฉ", tags=["weather"])
107
+ engine.remember("ไฝ ่ฏด่ฟ‡ๆœ€ๅ–œๆฌขๅƒ่‰่Ž“่›‹็ณ•", tags=["food"])
108
+
109
+ # 2. Observe events
110
+ engine.observe("reply_fast")
111
+ engine.observe("affection")
112
+
113
+ # 3. Let time pass
114
+ engine.step_time(hours=12)
115
+
116
+ # 4. Tick with context
117
+ result = engine.tick(context="ไปŠๅคฉไธ‹้›จไบ†")
118
+
119
+ print(f"Base probability: {result.base_probability:.1%}")
120
+ print(f"Memory trigger: {result.memory_trigger}")
121
+ print(f"Similarity: {result.memory_similarity:.3f}")
122
+ print(f"Boosted probability: {result.boosted_probability:.1%}")
123
+ print(f"Relationship: {result.relationship_stage.value}")
124
+ print(f"Emotion: {result.emotional_state.emoji} {result.emotional_state.emotion.value}")
125
+
126
+ if result.should_send:
127
+ send_message(result.prompt)
128
+ engine.record_send()
129
+ ```
130
+
131
+ ## API Reference
132
+
133
+ ### AffectiveLonging
134
+
135
+ ```python
136
+ engine = AffectiveLonging(
137
+ memory_persist_dir="./companion_memory_db", # Where to store embeddings
138
+ relationship_seed=None, # For reproducibility
139
+ emotion_seed=None,
140
+ **kwargs # Passed to PoissonLove
141
+ )
142
+ ```
143
+
144
+ **Methods:**
145
+
146
+ | Method | Description |
147
+ |--------|-------------|
148
+ | `remember(text, tags, **metadata)` | Store a memory. Returns memory ID. |
149
+ | `observe(event)` | Update relationship + emotion. Events: `reply_fast`, `reply_slow`, `no_reply`, `long_silence`, `affection`, `fight`, `apology`, `initiate`, `reject`, `long_message` |
150
+ | `step_time(hours)` | Advance time โ€” OU decay on all dimensions |
151
+ | `tick(now, context)` | Full pipeline. Returns `AffectiveResult`. |
152
+ | `record_reply(**kwargs)` | Record user reply (passthrough to base) |
153
+ | `record_send()` | Record that we sent (passthrough to base) |
154
+ | `get_state()` | Snapshot of all 3 layers |
155
+
156
+ ### AffectiveResult
157
+
158
+ ```python
159
+ @dataclass
160
+ class AffectiveResult:
161
+ # Decision
162
+ should_send: bool
163
+ base_probability: float
164
+
165
+ # Memory
166
+ memory_trigger: str | None
167
+ memory_similarity: float
168
+ longing_boost: float
169
+ boosted_probability: float
170
+
171
+ # Relationship
172
+ relationship_stage: Stage
173
+ intimacy: float
174
+ conflict: float
175
+
176
+ # Emotion
177
+ emotional_state: EmotionalState
178
+
179
+ # Output
180
+ prompt: str
181
+ reason: str
182
+ ```
183
+
184
+ ### Events
185
+
186
+ | Event | Description | Intimacy | Conflict |
187
+ |-------|-------------|----------|----------|
188
+ | `reply_fast` | User replied quickly | +0.05 | -0.02 |
189
+ | `reply_slow` | User replied slowly | -0.02 | +0.01 |
190
+ | `no_reply` | User didn't reply | -0.05 | +0.03 |
191
+ | `long_silence` | No contact >24h | -0.10 | +0.05 |
192
+ | `affection` | User showed warmth | +0.10 | -0.05 |
193
+ | `fight` | Conflict | -0.15 | +0.20 |
194
+ | `apology` | Someone apologized | +0.05 | -0.15 |
195
+ | `initiate` | User initiated contact | +0.08 | -0.02 |
196
+ | `reject` | User rejected us | -0.12 | +0.10 |
197
+
198
+ ## Examples
199
+
200
+ Run the quickstarts:
201
+
202
+ ```bash
203
+ # Memory triggers
204
+ python examples/quickstart.py
205
+
206
+ # Relationship state machine
207
+ python examples/quickstart_relationship.py
208
+
209
+ # VAD emotion engine
210
+ python examples/quickstart_emotion.py
211
+
212
+ # Full integration
213
+ python examples/quickstart_integrated.py
214
+ ```
215
+
216
+ ## Tests
217
+
218
+ ```bash
219
+ pip install -e ".[memory,test]"
220
+ pytest tests/ -v
221
+ ```
222
+
223
+ 62 tests covering all modules.
224
+
225
+ ## Theoretical Foundations
226
+
227
+ | Module | Theory | Reference |
228
+ |--------|--------|-----------|
229
+ | Memory | Sentence embeddings | [Reimers & Gurevych, 2019](https://arxiv.org/abs/1908.10084) |
230
+ | Memory | Forgetting curve | [Ebbinghaus, 1885](https://en.wikipedia.org/wiki/Forgetting_curve) |
231
+ | Relationship | Hidden Markov Model | [Rabiner, 1989](https://ieeexplore.ieee.org/document/18626) |
232
+ | Relationship | Ornstein-Uhlenbeck | [Uhlenbeck & Ornstein, 1930](https://journals.aps.org/pr/abstract/10.1103/PhysRev.36.823) |
233
+ | Emotion | Circumplex Model | [Russell, 1980](https://psycnet.apa.org/record/1981-25703-001) |
234
+ | Emotion | PAD Model | [Mehrabian, 1996](https://psycnet.apa.org/record/1996-97463-000) |
235
+ | Base | Poisson Process | [Poisson, 1837](https://en.wikipedia.org/wiki/Poisson_point_process) |
236
+ | Base | Bayesian Inference | [Bayes, 1763](https://en.wikipedia.org/wiki/Bayesian_inference) |
237
+ | Base | Information Gain | [Shannon, 1948](https://en.wikipedia.org/wiki/Information_gain) |
238
+
239
+ ## License
240
+
241
+ MIT
@@ -0,0 +1,47 @@
1
+ [build-system]
2
+ requires = ["setuptools>=68.0", "wheel"]
3
+ build-backend = "setuptools.build_meta"
4
+
5
+ [project]
6
+ name = "affective-longing"
7
+ version = "0.1.0"
8
+ description = "Emotional extension for AI companions โ€” memory triggers, relationship states, self-emotion."
9
+ readme = "README.md"
10
+ license = { text = "MIT" }
11
+ requires-python = ">=3.10"
12
+ authors = [
13
+ { name = "pear think", email = "gangwang694@gmail.com" },
14
+ ]
15
+ keywords = ["ai", "companion", "emotion", "memory", "longing", "relationship"]
16
+ dependencies = [
17
+ "revive-companion>=1.0.0",
18
+ "numpy>=1.23",
19
+ ]
20
+
21
+ [project.optional-dependencies]
22
+ memory = [
23
+ "sentence-transformers>=3.0.0",
24
+ "chromadb>=0.5.0",
25
+ ]
26
+ test = ["pytest>=7.0"]
27
+
28
+ [project.urls]
29
+ Homepage = "https://github.com/pearthink123/affective-longing"
30
+ Repository = "https://github.com/pearthink123/affective-longing"
31
+
32
+ [tool.setuptools.packages.find]
33
+ where = ["src"]
34
+
35
+ [tool.ruff]
36
+ target-version = "py310"
37
+ line-length = 100
38
+ src = ["src", "tests"]
39
+
40
+ [tool.ruff.lint]
41
+ select = ["E", "F", "W", "I", "UP", "B"]
42
+ ignore = ["E501"]
43
+
44
+ [tool.mypy]
45
+ python_version = "3.10"
46
+ ignore_missing_imports = true
47
+ check_untyped_defs = true
@@ -0,0 +1,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -0,0 +1,47 @@
1
+ """
2
+ affective-longing: Emotional extension for AI companions.
3
+
4
+ Built on revive-companion, adds:
5
+ - Memory triggers (embedding similarity)
6
+ - Relationship state machine (HMM + OU process)
7
+ - AI self-emotion modeling (VAD model)
8
+
9
+ Three layers, one decision:
10
+ 1. Memory โ€” past memories trigger present longing
11
+ 2. Relationship โ€” 6-stage lifecycle with OU decay
12
+ 3. Emotion โ€” VAD model for AI's internal state
13
+ """
14
+
15
+ from .emotion import Emotion, EmotionEngine, EmotionEngineConfig, EmotionalState
16
+ from .engine import AffectiveLonging, AffectiveResult
17
+ from .memory import MemoryStore, TriggerEngine
18
+ from .relationship import (
19
+ Event,
20
+ OUProcess,
21
+ RelationshipStateMachine,
22
+ RelationshipState,
23
+ Stage,
24
+ TransitionConfig,
25
+ )
26
+
27
+ __all__ = [
28
+ # Core engine
29
+ "AffectiveLonging",
30
+ "AffectiveResult",
31
+ # Memory
32
+ "MemoryStore",
33
+ "TriggerEngine",
34
+ # Relationship
35
+ "Stage",
36
+ "RelationshipState",
37
+ "Event",
38
+ "RelationshipStateMachine",
39
+ "TransitionConfig",
40
+ "OUProcess",
41
+ # Emotion
42
+ "Emotion",
43
+ "EmotionalState",
44
+ "EmotionEngine",
45
+ "EmotionEngineConfig",
46
+ ]
47
+ __version__ = "0.1.0"
@@ -0,0 +1,18 @@
1
+ """
2
+ Emotion module โ€” VAD model for AI companion's internal state.
3
+
4
+ Components:
5
+ - Emotion: Discrete emotion labels (joy, sadness, anger, etc.)
6
+ - EmotionalState: VAD snapshot with emotion label
7
+ - EmotionEngine: Manages emotional state with OU decay + events
8
+ """
9
+
10
+ from .engine import EmotionEngine, EmotionEngineConfig
11
+ from .vad import Emotion, EmotionalState
12
+
13
+ __all__ = [
14
+ "Emotion",
15
+ "EmotionalState",
16
+ "EmotionEngine",
17
+ "EmotionEngineConfig",
18
+ ]