Skip to content

Commit aee3aea

Browse files
authored
feat: Integrate AoTai Hike Demo with MemOS Multi-View Memory System (MemTensor#1078)
* feat: initialize demo/aotai-hike * feat: adjust game panel * feat: add small map * feat: multi-step in small map * feat: Switch the level from horizontal to vertical * feat: adjust front page * feat: adjust small map * feat: adjust front panel * feat: add roles * feat: add role in MainMap * feat: add message content in MainMap * feat: add message bubble * feat: add message bubble * chore: front code * feat: adjust game rule * feat: adjust rule * feat: adjust MainMap Roll * feat: voting for teamleader * fix: route choose * feat: add success/fail status; fix: vote rule; * fix: success/fail status; * fix: success/fail status; * feat: adjust weather changing * feat: add weather * feat: init algorithm services * feat: init algorithm services * feat: add algorithm scripts * feat: add algorithm scripts * feat: add log to algotithm scripts * feat: add log to algotithm scripts * feat: add log to algotithm scripts * feat: add log to algotithm scripts * feat: add log to algotithm scripts * feat: add log to algotithm scripts * fix: hovers * fix: fix choose point bug * feat: add prompt; add character feature * fix: choose button bug * feat: add CAMP * fix: camping * feat: add multi-view in mem-reader * feat: add poly-view mem-reader * feat: add role-id to prompt * feat: adjust poly-view prompt * feat: add roleid role name in game * feat: add roleid role name in game * feat: modify cube controll in game; modify prompt * feat: add user feature to itself cube; add realtime-history to chat prompt * fix: role name bug * feat: add llm voting * feat: en comment * fix: conflict * feat: add share button * feat: modify share button * feat: modify share button * feat: modify share button * feat: modify share button * feat: modify share image * feat: modify share image * feat: modify share image * feat: modify share image * feat: modify share image * chore: comment lang * fix: role attributes * doc: aotai hike game * doc: aotai hike game
1 parent 54b8411 commit aee3aea

File tree

101 files changed

+10125
-25
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

101 files changed

+10125
-25
lines changed

demos/AOTAI_Hike/INTRODUCTION_EN.md

Lines changed: 448 additions & 0 deletions
Large diffs are not rendered by default.

demos/AOTAI_Hike/INTRODUCTION_ZH.md

Lines changed: 454 additions & 0 deletions
Large diffs are not rendered by default.

demos/AOTAI_Hike/README.md

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
# 鳌太线徒步模拟器(AoTai Hike)Demo
2+
3+
> A pixel-art interactive narrative game demo based on the MemOS multi-view memory system
4+
5+
<div align="center">
6+
<img src="./banner.png" alt="AoTai Hike × MemOS - Poly-View Memory" width="100%">
7+
</div>
8+
9+
## 📖 Overview
10+
11+
**鳌太线徒步模拟器(AoTai Hike)** is a Web game demo showcasing MemOS's multi-view memory capabilities. Players can create multiple roles, lead a team across the dangerous AoTai route, and experience memory-based intelligent NPC dialogues and dynamic storytelling.
12+
13+
### Key Highlights
14+
15+
- 🎮 **Multi-role roleplay**: Create and switch between multiple roles, each with an independent memory space
16+
- 🧠 **Multi-view memory**: Fully integrated MemOS multi-view memory system
17+
- 💬 **Intelligent NPC dialogue**: Generate personality-consistent dialogue based on role memory
18+
- 🗺️ **Fixed route exploration**: Follow the real AoTai route and experience the full journey
19+
- 🎨 **Pixel-art UI**: Use Phaser 3 to render pixel-art maps and role animations
20+
21+
**📚 For detailed documentation, see: [INTRODUCTION_ZH.md](./INTRODUCTION_ZH.md) | [INTRODUCTION_EN.md](./INTRODUCTION_EN.md)**
22+
23+
## 🚀 Quick Start
24+
25+
### Requirements
26+
27+
- Python 3.8+
28+
- MemOS service (local or remote)
29+
30+
### Installation Steps
31+
32+
1. **Install backend dependencies**
33+
```bash
34+
cd backend
35+
python -m venv .venv && source .venv/bin/activate
36+
pip install -r requirements.txt
37+
```
38+
39+
2. **Configure MemOS service address (optional)**
40+
```bash
41+
export MEMOS_API_BASE_URL=http://localhost:8002
42+
```
43+
44+
3. **Start the service**
45+
```bash
46+
uvicorn app:app --host 0.0.0.0 --port 8010 --reload
47+
```
48+
49+
4. **Access the game**
50+
Open your browser and visit: `http://localhost:8010/demo/ao-tai/`
51+
52+
## 📡 Core API
53+
54+
- `GET /api/demo/ao-tai/map` - Get map information
55+
- `POST /api/demo/ao-tai/session/new` - Create a new session
56+
- `POST /api/demo/ao-tai/roles/upsert` - Create/Update a role
57+
- `POST /api/demo/ao-tai/roles/quickstart` - Quick-create default roles
58+
- `PUT /api/demo/ao-tai/session/active_role` - Switch active role
59+
- `POST /api/demo/ao-tai/act` - Perform an action (core endpoint)
60+
61+
For detailed API documentation, see [INTRODUCTION_EN.md](./INTRODUCTION_EN.md#-api-documentation)
62+
63+
## 🏗️ Project Structure
64+
65+
```
66+
demos/AOTAI_Hike/
67+
├── backend/ # FastAPI backend
68+
│ ├── aotai_hike/ # Game core code
69+
│ │ ├── router.py # API routes
70+
│ │ ├── services/ # Game services
71+
│ │ ├── adapters/ # Adapters (memory/dialogue/background)
72+
│ │ └── world/ # Map data
73+
│ └── app.py # Application entry
74+
├── frontend/ # Frontend (Phaser 3 + DOM UI)
75+
│ ├── src/ # Source code
76+
│ └── assets/ # Asset files
77+
└── README.md # This file
78+
```
79+
80+
## 🔧 Extensible Interfaces
81+
82+
The game is designed to be "lightweight but extensible"; all intelligence-related features are isolated via adapters:
83+
84+
- `adapters/memory.py` - **MemoryAdapter**: Interface with MemOS memory system
85+
- `adapters/companion.py` - **CompanionBrain**: NPC dialogue generation (based on MemOS chat_complete)
86+
- `adapters/background.py` - **BackgroundProvider**: Background asset provider
87+
88+
## 📚 Related Documents
89+
90+
- [INTRODUCTION_ZH.md](./INTRODUCTION_ZH.md) - **Complete project introduction (中文)**
91+
- [INTRODUCTION_EN.md](./INTRODUCTION_EN.md) - **Complete project introduction (English)**
92+
- [backend/MEMORY_INTEGRATION.md](./backend/MEMORY_INTEGRATION.md) - Memory system interaction guide
93+
- [PRD.md](./PRD.md) - Product requirements document
94+
95+
---
96+
97+
**Enjoy your AoTai hike!** 🏔️
Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# 游戏系统与记忆系统交互说明(AoTai Hike)
2+
3+
本文说明 AoTai Hike 中游戏系统与记忆系统的交互方式,并给出关键代码位置。
4+
5+
## 总体流程概览
6+
7+
一次 `act` 的主链路如下:
8+
9+
1. 游戏处理阶段门控与动作执行(更新世界状态)。
10+
2. 写入世界事件记忆(world cube)。
11+
3. 检索世界记忆,作为 NPC 对话上下文。
12+
4. 若触发 NPC 对话:
13+
- 每个 NPC 检索自身记忆(role cube)
14+
- 调用 chat 生成回复
15+
- 将对话写回角色记忆
16+
5. 写入 `chat_history` 供后续对话使用。
17+
18+
## 关键交互点与代码位置
19+
20+
### 1) 游戏事件写入(world 记忆)
21+
22+
- 位置:`GameService.act`
23+
- 作用:把本轮事件结构化写入记忆系统(world cube)
24+
25+
代码位置:
26+
- `demos/AOTAI_Hike/backend/aotai_hike/services/game_service.py`
27+
- `GameService.act()` 内:
28+
- `mem_event = self._format_memory_event(...)`
29+
- `self._memory.add_event(...)`
30+
31+
### 2) 世界记忆检索(world 记忆)
32+
33+
- 位置:`GameService.act`
34+
- 作用:为 NPC 对话提供全局上下文
35+
36+
代码位置:
37+
- `demos/AOTAI_Hike/backend/aotai_hike/services/game_service.py`
38+
- `mem_res = self._memory.search(...)`
39+
40+
### 3) NPC 对话(角色记忆检索 + chat + 回写)
41+
42+
- 位置:`MemoryCompanionBrain._generate_role_reply`
43+
- 作用:每个 NPC 走完整记忆链路生成发言
44+
45+
代码位置:
46+
- `demos/AOTAI_Hike/backend/aotai_hike/adapters/companion.py`
47+
- `self._memory.search_memory(...)` 角色记忆检索
48+
- `self._memory.chat_complete(...)` 调用算法 chat
49+
- `self._memory.add_memory(...)` 写回角色记忆
50+
51+
### 4) 记忆命名空间(cube_id)
52+
53+
- 位置:`MemoryNamespace`
54+
- 规则:
55+
- 角色记忆:`cube_{user_id}_{role_id}`
56+
- 世界记忆:`cube_{user_id}_world`
57+
58+
代码位置:
59+
- `demos/AOTAI_Hike/backend/aotai_hike/adapters/memory.py`
60+
61+
### 5) 记忆适配与客户端
62+
63+
- 位置:`MemOSMemoryClient` / `MemOSMemoryAdapter`
64+
- 作用:封装 MemOS `/product/add``/product/search``/product/chat/complete`
65+
66+
代码位置:
67+
- `demos/AOTAI_Hike/backend/aotai_hike/adapters/memory.py`
68+
69+
### 6) 对话历史记录
70+
71+
- 位置:`GameService._append_chat_history`
72+
- 作用:将系统/发言消息转为 `chat_history`,供后续对话使用
73+
74+
代码位置:
75+
- `demos/AOTAI_Hike/backend/aotai_hike/services/game_service.py`
76+
77+
## 算法回放脚本(调试用)
78+
79+
脚本 `algorithm_tuning.py` 以 1:1 的方式调用 `GameService.act`,并打印记忆/对话日志:
80+
81+
- `demos/AOTAI_Hike/backend/aotai_hike/scripts/algorithm_tuning.py`
82+
83+
常用参数:
84+
- `--user-id`:指定用户
85+
- `--base-url`:MemOS 服务地址
86+
- `--log-world-search`:打印 world 搜索
87+
- `--log-full-prompt`:打印完整 prompt
88+
89+
## 简要链路图
90+
91+
```
92+
GameService.act
93+
├─ add_event (world add)
94+
├─ search (world search)
95+
└─ MemoryCompanionBrain.generate
96+
├─ search_memory (role search)
97+
├─ chat_complete (LLM)
98+
└─ add_memory (role add)
99+
```
100+
101+
## 多视角记忆集成
102+
103+
本游戏完整集成了 MemOS 的多视角记忆系统,实现了每个角色拥有独立记忆空间、从角色视角提取记忆的功能。
104+
105+
**详细文档**
106+
- [多视角记忆集成 PR 文档](../PR_MULTI_VIEW_MEMORY_INTEGRATION.md) - 完整的技术实现说明
107+
- [PR 摘要](../PR_SUMMARY.md) - 快速概览
108+
109+
**核心特性**
110+
- ✅ 自动多视角模式检测(通过 `role_id``role_name` 字段)
111+
- ✅ 角色记忆隔离(每个角色独立的记忆空间)
112+
- ✅ 第一人称视角记忆提取
113+
- ✅ 基于记忆的智能 NPC 对话生成
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
"""AoTai line pixel-hiking demo (single-player, multi-role)."""
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
from __future__ import annotations
2+
3+
import os
4+
import zlib
5+
6+
from dataclasses import dataclass
7+
from pathlib import Path
8+
from typing import ClassVar
9+
from urllib.parse import quote
10+
11+
from aotai_hike.schemas import BackgroundAsset
12+
13+
14+
@dataclass
15+
class BackgroundRequest:
16+
scene_id: str
17+
style: str = "pixel"
18+
animate: bool = False
19+
20+
21+
class BackgroundProvider:
22+
def get_background(self, req: BackgroundRequest) -> BackgroundAsset:
23+
raise NotImplementedError
24+
25+
26+
class StaticBackgroundProvider(BackgroundProvider):
27+
"""Pick a background from the user's local pixel asset library.
28+
29+
Rules (demo-friendly):
30+
- Prefer user-provided raster assets under `frontend/assets/` (png/jpg/webp/gif).
31+
- Exclude avatars and legacy `bg_*.svg`.
32+
- Deterministically map `scene_id` -> one asset, so the same scene is stable.
33+
34+
You can refine selection by setting env vars:
35+
- AOTAI_BG_INCLUDE: substring that must appear in filename (case-insensitive)
36+
- AOTAI_BG_EXCLUDE: substring that must NOT appear in filename (case-insensitive)
37+
"""
38+
39+
_IMG_EXTS: ClassVar[frozenset[str]] = frozenset(
40+
{".png", ".jpg", ".jpeg", ".webp", ".gif", ".svg"}
41+
)
42+
43+
def __init__(
44+
self,
45+
*,
46+
base_url: str = "/demo/ao-tai/assets",
47+
assets_dir: Path | None = None,
48+
):
49+
self._base_url = base_url.rstrip("/")
50+
51+
if assets_dir is None:
52+
# .../AOTAI_Hike/backend/aotai_hike/adapters/background.py -> parents[3] is demo root
53+
assets_dir = Path(__file__).resolve().parents[3] / "frontend" / "assets"
54+
self._assets_dir = assets_dir
55+
56+
inc = os.getenv("AOTAI_BG_INCLUDE", "")
57+
exc = os.getenv("AOTAI_BG_EXCLUDE", "tilemap")
58+
self._include = inc.strip().lower() if inc else ""
59+
self._exclude = exc.strip().lower() if exc else ""
60+
61+
self._candidates = self._discover_candidates()
62+
63+
def _discover_candidates(self) -> list[str]:
64+
if not self._assets_dir.exists():
65+
return []
66+
67+
out: list[str] = []
68+
for p in sorted(self._assets_dir.rglob("*")):
69+
if not p.is_file():
70+
continue
71+
if p.suffix.lower() not in self._IMG_EXTS:
72+
continue
73+
74+
rel = p.relative_to(self._assets_dir).as_posix()
75+
low = rel.lower()
76+
77+
# Skip avatars
78+
if low.startswith("avatars/"):
79+
continue
80+
81+
# Skip legacy demo backgrounds
82+
if low.startswith("bg_") and low.endswith(".svg"):
83+
continue
84+
85+
# Optional include/exclude substrings
86+
if self._include and (self._include not in low):
87+
continue
88+
if self._exclude and (self._exclude in low):
89+
continue
90+
91+
# Skip mock-up style sheets by default
92+
if "mock up" in low or "mock_up" in low:
93+
continue
94+
95+
out.append(rel)
96+
97+
# If filtering is too strict and yields nothing, fall back to all non-avatar images except legacy bg_*.svg
98+
if not out:
99+
for p in sorted(self._assets_dir.rglob("*")):
100+
if not p.is_file():
101+
continue
102+
if p.suffix.lower() not in self._IMG_EXTS:
103+
continue
104+
rel = p.relative_to(self._assets_dir).as_posix()
105+
low = rel.lower()
106+
if low.startswith("avatars/"):
107+
continue
108+
if low.startswith("bg_") and low.endswith(".svg"):
109+
continue
110+
out.append(rel)
111+
112+
return out
113+
114+
def _pick(self, scene_id: str) -> str | None:
115+
if not self._candidates:
116+
return None
117+
h = zlib.crc32(scene_id.encode("utf-8"))
118+
return self._candidates[h % len(self._candidates)]
119+
120+
def get_background(self, req: BackgroundRequest) -> BackgroundAsset:
121+
chosen = self._pick(req.scene_id)
122+
if not chosen:
123+
# last resort: legacy
124+
return BackgroundAsset(
125+
scene_id=req.scene_id,
126+
asset_url=f"{self._base_url}/bg_{req.scene_id}.svg",
127+
type="svg",
128+
meta={"style": req.style, "animate": req.animate, "fallback": True},
129+
)
130+
131+
ext = Path(chosen).suffix.lower().lstrip(".")
132+
# URL encode each segment (handles spaces)
133+
encoded = "/".join(quote(seg) for seg in chosen.split("/"))
134+
return BackgroundAsset(
135+
scene_id=req.scene_id,
136+
asset_url=f"{self._base_url}/{encoded}",
137+
type=ext if ext in {"png", "jpg", "jpeg", "webp", "gif", "svg"} else "none",
138+
meta={
139+
"style": req.style,
140+
"animate": req.animate,
141+
"picked": chosen,
142+
"candidates": len(self._candidates),
143+
},
144+
)

0 commit comments

Comments
 (0)