unframed 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.
- unframed-0.1.0/.gitignore +34 -0
- unframed-0.1.0/LICENSE.txt +18 -0
- unframed-0.1.0/PKG-INFO +271 -0
- unframed-0.1.0/README.md +243 -0
- unframed-0.1.0/build/build.py +78 -0
- unframed-0.1.0/docs/HELP.md +182 -0
- unframed-0.1.0/docs/SEED_SPEC.md +214 -0
- unframed-0.1.0/pyproject.toml +73 -0
- unframed-0.1.0/seeds/cyberpunk.json +4 -0
- unframed-0.1.0/seeds/cyberpunk.md +42 -0
- unframed-0.1.0/seeds/lonely_star.json +4 -0
- unframed-0.1.0/seeds/lonely_star.md +65 -0
- unframed-0.1.0/seeds/loop_day.json +4 -0
- unframed-0.1.0/seeds/loop_day.md +77 -0
- unframed-0.1.0/seeds/neon_verdict.json +4 -0
- unframed-0.1.0/seeds/neon_verdict.md +76 -0
- unframed-0.1.0/seeds/rust_oasis.json +4 -0
- unframed-0.1.0/seeds/rust_oasis.md +62 -0
- unframed-0.1.0/seeds/sudo_apt_survival.json +4 -0
- unframed-0.1.0/seeds/sudo_apt_survival.md +95 -0
- unframed-0.1.0/seeds/tide_prison.json +4 -0
- unframed-0.1.0/seeds/tide_prison.md +61 -0
- unframed-0.1.0/seeds/underground_throne.json +4 -0
- unframed-0.1.0/seeds/underground_throne.md +76 -0
- unframed-0.1.0/src/unframed/__about__.py +4 -0
- unframed-0.1.0/src/unframed/__init__.py +23 -0
- unframed-0.1.0/src/unframed/cli.py +940 -0
- unframed-0.1.0/src/unframed/engine.py +1150 -0
- unframed-0.1.0/src/unframed/render.py +150 -0
- unframed-0.1.0/src/unframed/settings.py +92 -0
- unframed-0.1.0/src/unframed/tui/__init__.py +1 -0
- unframed-0.1.0/src/unframed/tui/app.py +1115 -0
- unframed-0.1.0/tests/__init__.py +3 -0
- unframed-0.1.0/tests/test_engine.py +308 -0
- unframed-0.1.0/tests/test_plot.py +146 -0
- unframed-0.1.0/tests/test_render.py +141 -0
- unframed-0.1.0/tests/test_settings.py +120 -0
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# Python
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*.egg-info/
|
|
5
|
+
venv/
|
|
6
|
+
.venv/
|
|
7
|
+
dist/
|
|
8
|
+
*.spec
|
|
9
|
+
|
|
10
|
+
# PyInstaller output
|
|
11
|
+
build/unframed/
|
|
12
|
+
build/*.exe
|
|
13
|
+
build/*.manifest
|
|
14
|
+
|
|
15
|
+
# IDE
|
|
16
|
+
.vscode/
|
|
17
|
+
.idea/
|
|
18
|
+
|
|
19
|
+
# OS
|
|
20
|
+
.DS_Store
|
|
21
|
+
Thumbs.db
|
|
22
|
+
|
|
23
|
+
# Environment
|
|
24
|
+
.env
|
|
25
|
+
.env.*
|
|
26
|
+
game.json
|
|
27
|
+
.marscode/
|
|
28
|
+
password.txt
|
|
29
|
+
|
|
30
|
+
# Superpowers brainstorming artifacts
|
|
31
|
+
docs/superpowers/
|
|
32
|
+
|
|
33
|
+
# Runtime
|
|
34
|
+
*.log
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026-present zaf-x <baoshuwen2013@outlook.com>
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
|
|
6
|
+
associated documentation files (the "Software"), to deal in the Software without restriction, including
|
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
|
|
9
|
+
following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial
|
|
12
|
+
portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
|
|
15
|
+
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
|
|
16
|
+
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
|
17
|
+
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
|
18
|
+
USE OR OTHER DEALINGS IN THE SOFTWARE.
|
unframed-0.1.0/PKG-INFO
ADDED
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: unframed
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: An unframed AI-driven narrative game - AI builds the world, rules, characters and story from scratch.
|
|
5
|
+
Project-URL: Documentation, https://github.com/zaf-x/unframed#readme
|
|
6
|
+
Project-URL: Issues, https://github.com/zaf-x/unframed/issues
|
|
7
|
+
Project-URL: Source, https://github.com/zaf-x/unframed
|
|
8
|
+
Author-email: zaf-x <baoshuwen2013@outlook.com>
|
|
9
|
+
License-Expression: MIT
|
|
10
|
+
License-File: LICENSE.txt
|
|
11
|
+
Keywords: ai,game,llm,narrative,storytelling
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Programming Language :: Python
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: Implementation :: CPython
|
|
20
|
+
Classifier: Programming Language :: Python :: Implementation :: PyPy
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Requires-Dist: colorama>=0.4.6
|
|
23
|
+
Requires-Dist: openai>=1.0.0
|
|
24
|
+
Requires-Dist: rich>=13.0.0
|
|
25
|
+
Requires-Dist: textual>=0.41.0
|
|
26
|
+
Requires-Dist: zaf-ai-util>=0.4.0
|
|
27
|
+
Description-Content-Type: text/markdown
|
|
28
|
+
|
|
29
|
+
# unframed
|
|
30
|
+
|
|
31
|
+
[]()
|
|
32
|
+
[](LICENSE.txt)
|
|
33
|
+
[]()
|
|
34
|
+
[](https://github.com/zaf-x/unframed)
|
|
35
|
+
|
|
36
|
+
**AI 自举叙事游戏** — AI 从零开始构建世界观、规则、角色与剧情。
|
|
37
|
+
|
|
38
|
+
## 核心设计
|
|
39
|
+
|
|
40
|
+
- **AI 是唯一的创世者**:没有硬编码的游戏机制,所有规则由 AI 在运行时自行定义。
|
|
41
|
+
- **状态即真相**:游戏世界的唯一状态存储在 `vars` 字典中,AI 通过工具调用显式读写。
|
|
42
|
+
- **记忆分层**:核心区 (Pinned) / 活跃区 (Active) / 目录区 (Catalog) 三层显示,防止上下文溢出。
|
|
43
|
+
- **元数据锁定**:变量语义 (`meta`) 一旦定义不可覆盖,确保概念一致性。
|
|
44
|
+
- **剧情规划**:AI 构建剧情树,提前规划走向,跳过的分支自动修剪。
|
|
45
|
+
- **子AI系统**:AI 可创建持久化的 NPC 角色,拥有独立记忆。
|
|
46
|
+
|
|
47
|
+
## 安装
|
|
48
|
+
|
|
49
|
+
Python 3.8+ 环境:
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
pip install git+https://github.com/zaf-x/unframed.git
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
或克隆后本地安装:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
git clone https://github.com/zaf-x/unframed.git
|
|
59
|
+
cd unframed
|
|
60
|
+
pip install .
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## 使用
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
# 需要设置 OPENAI_API_KEY 环境变量,或在 TUI 设置页填写
|
|
67
|
+
export OPENAI_API_KEY="sk-..."
|
|
68
|
+
unframed # 默认启动 TUI
|
|
69
|
+
|
|
70
|
+
unframed --cli # CLI 模式
|
|
71
|
+
|
|
72
|
+
# 指定模型(支持所有 OpenAI 兼容 API)
|
|
73
|
+
unframed --model deepseek-chat
|
|
74
|
+
|
|
75
|
+
# 自定义 API 地址
|
|
76
|
+
unframed --base-url https://api.example.com/v1
|
|
77
|
+
|
|
78
|
+
# 调整温度(越高越有创意,越低越稳定)
|
|
79
|
+
unframed --temperature 0.9
|
|
80
|
+
|
|
81
|
+
# 加载种子(剧本),自动使用 CLI 模式
|
|
82
|
+
unframed --seed seeds/cyberpunk.md
|
|
83
|
+
|
|
84
|
+
# 继续上次游戏,自动使用 CLI 模式
|
|
85
|
+
unframed --continue
|
|
86
|
+
|
|
87
|
+
# 显示帮助
|
|
88
|
+
unframed --help
|
|
89
|
+
```
|
|
90
|
+
|
|
91
|
+
> **注**:使用 `--seed`、`--continue` 或 `--debug` 时会自动切换到 CLI 模式。
|
|
92
|
+
|
|
93
|
+
## CLI 选项
|
|
94
|
+
|
|
95
|
+
```
|
|
96
|
+
unframed [--api-key API_KEY] [--base-url BASE_URL] [--model MODEL]
|
|
97
|
+
[--temperature TEMP] [--seed SEED] [--continue] [--cli]
|
|
98
|
+
[--debug] [--help]
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
| 选项 | 说明 |
|
|
102
|
+
|------|------|
|
|
103
|
+
| `--api-key KEY` | API Key(默认读 `OPENAI_API_KEY` 环境变量或配置文件) |
|
|
104
|
+
| `--base-url URL` | 自定义 API 地址(默认读 `OPENAI_BASE_URL` 或配置文件) |
|
|
105
|
+
| `--model NAME` | 模型名,默认 `gpt-4o`(优先级:参数 > `OPENAI_MODEL` > 配置) |
|
|
106
|
+
| `--temperature NUM` | 采样温度 0-2,默认 `0.7`(优先级:参数 > `OPENAI_TEMPERATURE` > 配置) |
|
|
107
|
+
| `--seed PATH` | 种子文件路径(Markdown),跳过菜单直接加载(自动 CLI) |
|
|
108
|
+
| `--continue` | 继续上次游戏(自动 CLI) |
|
|
109
|
+
| `--cli` | 使用 CLI 模式(默认 TUI) |
|
|
110
|
+
| `--debug` | 显示工具调用详情(自动 CLI) |
|
|
111
|
+
| `--help` | 显示玩家手册 |
|
|
112
|
+
|
|
113
|
+
设置保存在 `~/.unframed_config.json`(权限 0o600),TUI 中主菜单→"设置"即可修改。
|
|
114
|
+
|
|
115
|
+
### 环境变量
|
|
116
|
+
|
|
117
|
+
| 变量 | 说明 |
|
|
118
|
+
|------|------|
|
|
119
|
+
| `OPENAI_API_KEY` | API Key |
|
|
120
|
+
| `OPENAI_BASE_URL` | API 地址(如 `https://api.example.com/v1`) |
|
|
121
|
+
| `OPENAI_MODEL` | 模型名(默认 `gpt-4o`) |
|
|
122
|
+
| `OPENAI_TEMPERATURE` | 采样温度(默认 `0.7`) |
|
|
123
|
+
|
|
124
|
+
读取优先级:**CLI 参数 > 环境变量 > 配置文件 > 内置默认**
|
|
125
|
+
|
|
126
|
+
## TUI 模式
|
|
127
|
+
|
|
128
|
+
### TUI 界面布局
|
|
129
|
+
|
|
130
|
+
```
|
|
131
|
+
┌──────────────────────────────────────────────────┐
|
|
132
|
+
│ U N F R A M E D 14:30:21 │
|
|
133
|
+
├────────────────────────────────┬─────────────────┤
|
|
134
|
+
│ │ ## 角色状态 │
|
|
135
|
+
│ 叙事区域 │ - **生命值**: 85 │
|
|
136
|
+
│ (AI 的故事输出,Markdown 渲染) │ - **位置**: 断指 │
|
|
137
|
+
│ │ 酒吧 │
|
|
138
|
+
│ │ │
|
|
139
|
+
│ │ --- │
|
|
140
|
+
│ │ 回合 12 │
|
|
141
|
+
├────────────────────────────────┴─────────────────┤
|
|
142
|
+
│ AI 正在构思剧情... │
|
|
143
|
+
├──────────────────────────────────────────────────┤
|
|
144
|
+
│ > 输入你的行动... [发送] │
|
|
145
|
+
└──────────────────────────────────────────────────┘
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
- **左侧**:叙事输出区,AI 生成的故事以 Markdown 渲染
|
|
149
|
+
- **右侧**:角色状态面板 — AI 使用 `show_var` 工具标记为玩家可见的变量
|
|
150
|
+
- **底部**:输入框,输入你的行动或对话
|
|
151
|
+
- **状态栏**:AI 处理时显示当前操作(如"正在修改世界状态")
|
|
152
|
+
|
|
153
|
+
### 启动菜单
|
|
154
|
+
|
|
155
|
+
| 选项 | 说明 |
|
|
156
|
+
|------|------|
|
|
157
|
+
| **新建存档** | 输入存档名 → 选择种子 → 开始新游戏 |
|
|
158
|
+
| **继续上一个存档** | 直接回到上次玩的存档(仅在有历史时显示) |
|
|
159
|
+
| **加载存档** | 从已有存档中选择一个加载 |
|
|
160
|
+
| **存档管理** | 查看/保存/删除/重命名所有存档 |
|
|
161
|
+
| **设置** | 配置 API Key、模型、温度等 |
|
|
162
|
+
| **文档** | 查看玩家手册 |
|
|
163
|
+
| **退出** | 退出游戏 |
|
|
164
|
+
|
|
165
|
+
### TUI 快捷键
|
|
166
|
+
|
|
167
|
+
| 快捷键 | 功能 |
|
|
168
|
+
|--------|------|
|
|
169
|
+
| `Enter` | 发送消息 |
|
|
170
|
+
| `Escape` | 返回主菜单(当前回合会先自动存档) |
|
|
171
|
+
| `Ctrl+S` | 打开存档管理器(Enter=保存,Delete=删除,R=重命名) |
|
|
172
|
+
| `Ctrl+L` | 打开读档列表 |
|
|
173
|
+
| `Ctrl+D` | 打开删档列表 |
|
|
174
|
+
|
|
175
|
+
## CLI 模式
|
|
176
|
+
|
|
177
|
+
### 启动菜单
|
|
178
|
+
|
|
179
|
+
| 选项 | 说明 |
|
|
180
|
+
|------|------|
|
|
181
|
+
| **新建存档** | 输入存档名 → 选择种子 → 开始新游戏 |
|
|
182
|
+
| **继续上一个存档** | 直接回到上次玩的存档 |
|
|
183
|
+
| **加载存档** | 从已有存档中选择一个加载 |
|
|
184
|
+
| **帮助文档** | 查看玩家手册 |
|
|
185
|
+
|
|
186
|
+
### 游戏中命令
|
|
187
|
+
|
|
188
|
+
| 命令 | 说明 |
|
|
189
|
+
|------|------|
|
|
190
|
+
| 直接输入 | 你的行动或对话,AI 会推进剧情 |
|
|
191
|
+
| `/save` | 打开存档菜单 |
|
|
192
|
+
| `/save 我的存档` | 快速存到指定名称(新建或覆盖) |
|
|
193
|
+
| `/save list` | 列出所有存档 |
|
|
194
|
+
| `/load` | 打开读档菜单 |
|
|
195
|
+
| `/load 我的存档` | 快速加载指定名称的存档 |
|
|
196
|
+
| `/delete` | 打开删档菜单 |
|
|
197
|
+
| `/quit` | 退出游戏 |
|
|
198
|
+
|
|
199
|
+
## 种子(Seed)
|
|
200
|
+
|
|
201
|
+
种子是游戏的"剧本文件",定义了世界观、规则、角色和目标。每个种子由一对文件组成:`seeds/<名称>.json`(元数据)和 `seeds/<名称>.md`(剧本内容)。游戏启动时自动识别 `seeds/` 下所有 `.json` 索引文件。
|
|
202
|
+
|
|
203
|
+
内置种子:
|
|
204
|
+
|
|
205
|
+
- **赛博朋克:深渊回响** — 2087 年,永夜之城"新重庆"
|
|
206
|
+
- **潮汐监狱** — 2147 年,深海环形海上堡垒
|
|
207
|
+
- **锈蚀边境:绿洲协议** — 2147 年,核冬天后的废土求生
|
|
208
|
+
- **孤星:坠落日** — 2247 年,殖民船坠毁后的外星求生
|
|
209
|
+
- **霓虹裁决** — 2140 年,同步轨道升降梯内
|
|
210
|
+
- **循环日** — 无法逃脱的时间循环
|
|
211
|
+
- **sudo apt 求生记** — 当 Linux 系统故障出现在神秘世界
|
|
212
|
+
- **地下王座** — 地下王国的权力与阴谋
|
|
213
|
+
|
|
214
|
+
你也可以自己编写种子——参考 `docs/SEED_SPEC.md`。
|
|
215
|
+
|
|
216
|
+
## 子AI系统(NPC)
|
|
217
|
+
|
|
218
|
+
unframed 支持 AI 在游戏中创建和管理长期存在的子 AI 角色,作为游戏世界中的 NPC、同伴或组织:
|
|
219
|
+
|
|
220
|
+
| 工具 | 功能 |
|
|
221
|
+
|------|------|
|
|
222
|
+
| **创建角色** | AI 可创建拥有独立性格、知识范围和记忆的 NPC |
|
|
223
|
+
| **与角色对话** | AI 可与已有 NPC 对话,并根据其性格做出回应 |
|
|
224
|
+
| **移除角色** | NPC 死亡或离开时,AI 可终止该角色 |
|
|
225
|
+
|
|
226
|
+
子 AI 可以读取世界状态变量了解当前局势,但不能直接修改它们。它们拥有独立对话记忆,会记住每一次交流。玩家通过主 AI 的叙事感知子 AI 的行为,子 AI 不直接与玩家交互。
|
|
227
|
+
|
|
228
|
+
## 存档
|
|
229
|
+
|
|
230
|
+
存档文件存储在 `~/.unframed_saves/` 目录,每局一个 UUID 文件(`{uuid}.json`)。
|
|
231
|
+
|
|
232
|
+
- **自动保存**:每轮自动保存到当前存档
|
|
233
|
+
- **继续存档**:主菜单"继续上一个存档"可直接回到上次的游戏
|
|
234
|
+
- **存档管理**:TUI 中 `Ctrl+S` 可保存/重命名/删除/新建存档
|
|
235
|
+
- **存档内容**:回合数、变量数据库、对话历史、剧情树、子 AI 状态
|
|
236
|
+
|
|
237
|
+
## 开发
|
|
238
|
+
|
|
239
|
+
```bash
|
|
240
|
+
git clone https://github.com/zaf-x/unframed.git
|
|
241
|
+
cd unframed
|
|
242
|
+
pip install -e .
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
运行测试:
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
pip install pytest
|
|
249
|
+
python -m pytest tests/
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
## 架构
|
|
253
|
+
|
|
254
|
+
```text
|
|
255
|
+
src/unframed/
|
|
256
|
+
├── __about__.py — 版本信息
|
|
257
|
+
├── __init__.py — 公共 API
|
|
258
|
+
├── engine.py — 核心引擎:状态管理、工具定义、Prompt 组装、游戏循环
|
|
259
|
+
├── cli.py — 交互式 CLI 入口(启动菜单、命令行命令)
|
|
260
|
+
├── settings.py — 持久化配置(~/.unframed_config.json)
|
|
261
|
+
├── render.py — BBCode → ANSI 渲染器
|
|
262
|
+
└── tui/
|
|
263
|
+
├── __init__.py — TUI 模块声明
|
|
264
|
+
└── app.py — Textual TUI 前端(图形界面)
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
基于 [ai-util](https://github.com/zaf-x/ai-util) 框架。
|
|
268
|
+
|
|
269
|
+
## License
|
|
270
|
+
|
|
271
|
+
`unframed` 基于 MIT 协议开源。
|
unframed-0.1.0/README.md
ADDED
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
# unframed
|
|
2
|
+
|
|
3
|
+
[]()
|
|
4
|
+
[](LICENSE.txt)
|
|
5
|
+
[]()
|
|
6
|
+
[](https://github.com/zaf-x/unframed)
|
|
7
|
+
|
|
8
|
+
**AI 自举叙事游戏** — AI 从零开始构建世界观、规则、角色与剧情。
|
|
9
|
+
|
|
10
|
+
## 核心设计
|
|
11
|
+
|
|
12
|
+
- **AI 是唯一的创世者**:没有硬编码的游戏机制,所有规则由 AI 在运行时自行定义。
|
|
13
|
+
- **状态即真相**:游戏世界的唯一状态存储在 `vars` 字典中,AI 通过工具调用显式读写。
|
|
14
|
+
- **记忆分层**:核心区 (Pinned) / 活跃区 (Active) / 目录区 (Catalog) 三层显示,防止上下文溢出。
|
|
15
|
+
- **元数据锁定**:变量语义 (`meta`) 一旦定义不可覆盖,确保概念一致性。
|
|
16
|
+
- **剧情规划**:AI 构建剧情树,提前规划走向,跳过的分支自动修剪。
|
|
17
|
+
- **子AI系统**:AI 可创建持久化的 NPC 角色,拥有独立记忆。
|
|
18
|
+
|
|
19
|
+
## 安装
|
|
20
|
+
|
|
21
|
+
Python 3.8+ 环境:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
pip install git+https://github.com/zaf-x/unframed.git
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
或克隆后本地安装:
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
git clone https://github.com/zaf-x/unframed.git
|
|
31
|
+
cd unframed
|
|
32
|
+
pip install .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## 使用
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
# 需要设置 OPENAI_API_KEY 环境变量,或在 TUI 设置页填写
|
|
39
|
+
export OPENAI_API_KEY="sk-..."
|
|
40
|
+
unframed # 默认启动 TUI
|
|
41
|
+
|
|
42
|
+
unframed --cli # CLI 模式
|
|
43
|
+
|
|
44
|
+
# 指定模型(支持所有 OpenAI 兼容 API)
|
|
45
|
+
unframed --model deepseek-chat
|
|
46
|
+
|
|
47
|
+
# 自定义 API 地址
|
|
48
|
+
unframed --base-url https://api.example.com/v1
|
|
49
|
+
|
|
50
|
+
# 调整温度(越高越有创意,越低越稳定)
|
|
51
|
+
unframed --temperature 0.9
|
|
52
|
+
|
|
53
|
+
# 加载种子(剧本),自动使用 CLI 模式
|
|
54
|
+
unframed --seed seeds/cyberpunk.md
|
|
55
|
+
|
|
56
|
+
# 继续上次游戏,自动使用 CLI 模式
|
|
57
|
+
unframed --continue
|
|
58
|
+
|
|
59
|
+
# 显示帮助
|
|
60
|
+
unframed --help
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
> **注**:使用 `--seed`、`--continue` 或 `--debug` 时会自动切换到 CLI 模式。
|
|
64
|
+
|
|
65
|
+
## CLI 选项
|
|
66
|
+
|
|
67
|
+
```
|
|
68
|
+
unframed [--api-key API_KEY] [--base-url BASE_URL] [--model MODEL]
|
|
69
|
+
[--temperature TEMP] [--seed SEED] [--continue] [--cli]
|
|
70
|
+
[--debug] [--help]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
| 选项 | 说明 |
|
|
74
|
+
|------|------|
|
|
75
|
+
| `--api-key KEY` | API Key(默认读 `OPENAI_API_KEY` 环境变量或配置文件) |
|
|
76
|
+
| `--base-url URL` | 自定义 API 地址(默认读 `OPENAI_BASE_URL` 或配置文件) |
|
|
77
|
+
| `--model NAME` | 模型名,默认 `gpt-4o`(优先级:参数 > `OPENAI_MODEL` > 配置) |
|
|
78
|
+
| `--temperature NUM` | 采样温度 0-2,默认 `0.7`(优先级:参数 > `OPENAI_TEMPERATURE` > 配置) |
|
|
79
|
+
| `--seed PATH` | 种子文件路径(Markdown),跳过菜单直接加载(自动 CLI) |
|
|
80
|
+
| `--continue` | 继续上次游戏(自动 CLI) |
|
|
81
|
+
| `--cli` | 使用 CLI 模式(默认 TUI) |
|
|
82
|
+
| `--debug` | 显示工具调用详情(自动 CLI) |
|
|
83
|
+
| `--help` | 显示玩家手册 |
|
|
84
|
+
|
|
85
|
+
设置保存在 `~/.unframed_config.json`(权限 0o600),TUI 中主菜单→"设置"即可修改。
|
|
86
|
+
|
|
87
|
+
### 环境变量
|
|
88
|
+
|
|
89
|
+
| 变量 | 说明 |
|
|
90
|
+
|------|------|
|
|
91
|
+
| `OPENAI_API_KEY` | API Key |
|
|
92
|
+
| `OPENAI_BASE_URL` | API 地址(如 `https://api.example.com/v1`) |
|
|
93
|
+
| `OPENAI_MODEL` | 模型名(默认 `gpt-4o`) |
|
|
94
|
+
| `OPENAI_TEMPERATURE` | 采样温度(默认 `0.7`) |
|
|
95
|
+
|
|
96
|
+
读取优先级:**CLI 参数 > 环境变量 > 配置文件 > 内置默认**
|
|
97
|
+
|
|
98
|
+
## TUI 模式
|
|
99
|
+
|
|
100
|
+
### TUI 界面布局
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
┌──────────────────────────────────────────────────┐
|
|
104
|
+
│ U N F R A M E D 14:30:21 │
|
|
105
|
+
├────────────────────────────────┬─────────────────┤
|
|
106
|
+
│ │ ## 角色状态 │
|
|
107
|
+
│ 叙事区域 │ - **生命值**: 85 │
|
|
108
|
+
│ (AI 的故事输出,Markdown 渲染) │ - **位置**: 断指 │
|
|
109
|
+
│ │ 酒吧 │
|
|
110
|
+
│ │ │
|
|
111
|
+
│ │ --- │
|
|
112
|
+
│ │ 回合 12 │
|
|
113
|
+
├────────────────────────────────┴─────────────────┤
|
|
114
|
+
│ AI 正在构思剧情... │
|
|
115
|
+
├──────────────────────────────────────────────────┤
|
|
116
|
+
│ > 输入你的行动... [发送] │
|
|
117
|
+
└──────────────────────────────────────────────────┘
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
- **左侧**:叙事输出区,AI 生成的故事以 Markdown 渲染
|
|
121
|
+
- **右侧**:角色状态面板 — AI 使用 `show_var` 工具标记为玩家可见的变量
|
|
122
|
+
- **底部**:输入框,输入你的行动或对话
|
|
123
|
+
- **状态栏**:AI 处理时显示当前操作(如"正在修改世界状态")
|
|
124
|
+
|
|
125
|
+
### 启动菜单
|
|
126
|
+
|
|
127
|
+
| 选项 | 说明 |
|
|
128
|
+
|------|------|
|
|
129
|
+
| **新建存档** | 输入存档名 → 选择种子 → 开始新游戏 |
|
|
130
|
+
| **继续上一个存档** | 直接回到上次玩的存档(仅在有历史时显示) |
|
|
131
|
+
| **加载存档** | 从已有存档中选择一个加载 |
|
|
132
|
+
| **存档管理** | 查看/保存/删除/重命名所有存档 |
|
|
133
|
+
| **设置** | 配置 API Key、模型、温度等 |
|
|
134
|
+
| **文档** | 查看玩家手册 |
|
|
135
|
+
| **退出** | 退出游戏 |
|
|
136
|
+
|
|
137
|
+
### TUI 快捷键
|
|
138
|
+
|
|
139
|
+
| 快捷键 | 功能 |
|
|
140
|
+
|--------|------|
|
|
141
|
+
| `Enter` | 发送消息 |
|
|
142
|
+
| `Escape` | 返回主菜单(当前回合会先自动存档) |
|
|
143
|
+
| `Ctrl+S` | 打开存档管理器(Enter=保存,Delete=删除,R=重命名) |
|
|
144
|
+
| `Ctrl+L` | 打开读档列表 |
|
|
145
|
+
| `Ctrl+D` | 打开删档列表 |
|
|
146
|
+
|
|
147
|
+
## CLI 模式
|
|
148
|
+
|
|
149
|
+
### 启动菜单
|
|
150
|
+
|
|
151
|
+
| 选项 | 说明 |
|
|
152
|
+
|------|------|
|
|
153
|
+
| **新建存档** | 输入存档名 → 选择种子 → 开始新游戏 |
|
|
154
|
+
| **继续上一个存档** | 直接回到上次玩的存档 |
|
|
155
|
+
| **加载存档** | 从已有存档中选择一个加载 |
|
|
156
|
+
| **帮助文档** | 查看玩家手册 |
|
|
157
|
+
|
|
158
|
+
### 游戏中命令
|
|
159
|
+
|
|
160
|
+
| 命令 | 说明 |
|
|
161
|
+
|------|------|
|
|
162
|
+
| 直接输入 | 你的行动或对话,AI 会推进剧情 |
|
|
163
|
+
| `/save` | 打开存档菜单 |
|
|
164
|
+
| `/save 我的存档` | 快速存到指定名称(新建或覆盖) |
|
|
165
|
+
| `/save list` | 列出所有存档 |
|
|
166
|
+
| `/load` | 打开读档菜单 |
|
|
167
|
+
| `/load 我的存档` | 快速加载指定名称的存档 |
|
|
168
|
+
| `/delete` | 打开删档菜单 |
|
|
169
|
+
| `/quit` | 退出游戏 |
|
|
170
|
+
|
|
171
|
+
## 种子(Seed)
|
|
172
|
+
|
|
173
|
+
种子是游戏的"剧本文件",定义了世界观、规则、角色和目标。每个种子由一对文件组成:`seeds/<名称>.json`(元数据)和 `seeds/<名称>.md`(剧本内容)。游戏启动时自动识别 `seeds/` 下所有 `.json` 索引文件。
|
|
174
|
+
|
|
175
|
+
内置种子:
|
|
176
|
+
|
|
177
|
+
- **赛博朋克:深渊回响** — 2087 年,永夜之城"新重庆"
|
|
178
|
+
- **潮汐监狱** — 2147 年,深海环形海上堡垒
|
|
179
|
+
- **锈蚀边境:绿洲协议** — 2147 年,核冬天后的废土求生
|
|
180
|
+
- **孤星:坠落日** — 2247 年,殖民船坠毁后的外星求生
|
|
181
|
+
- **霓虹裁决** — 2140 年,同步轨道升降梯内
|
|
182
|
+
- **循环日** — 无法逃脱的时间循环
|
|
183
|
+
- **sudo apt 求生记** — 当 Linux 系统故障出现在神秘世界
|
|
184
|
+
- **地下王座** — 地下王国的权力与阴谋
|
|
185
|
+
|
|
186
|
+
你也可以自己编写种子——参考 `docs/SEED_SPEC.md`。
|
|
187
|
+
|
|
188
|
+
## 子AI系统(NPC)
|
|
189
|
+
|
|
190
|
+
unframed 支持 AI 在游戏中创建和管理长期存在的子 AI 角色,作为游戏世界中的 NPC、同伴或组织:
|
|
191
|
+
|
|
192
|
+
| 工具 | 功能 |
|
|
193
|
+
|------|------|
|
|
194
|
+
| **创建角色** | AI 可创建拥有独立性格、知识范围和记忆的 NPC |
|
|
195
|
+
| **与角色对话** | AI 可与已有 NPC 对话,并根据其性格做出回应 |
|
|
196
|
+
| **移除角色** | NPC 死亡或离开时,AI 可终止该角色 |
|
|
197
|
+
|
|
198
|
+
子 AI 可以读取世界状态变量了解当前局势,但不能直接修改它们。它们拥有独立对话记忆,会记住每一次交流。玩家通过主 AI 的叙事感知子 AI 的行为,子 AI 不直接与玩家交互。
|
|
199
|
+
|
|
200
|
+
## 存档
|
|
201
|
+
|
|
202
|
+
存档文件存储在 `~/.unframed_saves/` 目录,每局一个 UUID 文件(`{uuid}.json`)。
|
|
203
|
+
|
|
204
|
+
- **自动保存**:每轮自动保存到当前存档
|
|
205
|
+
- **继续存档**:主菜单"继续上一个存档"可直接回到上次的游戏
|
|
206
|
+
- **存档管理**:TUI 中 `Ctrl+S` 可保存/重命名/删除/新建存档
|
|
207
|
+
- **存档内容**:回合数、变量数据库、对话历史、剧情树、子 AI 状态
|
|
208
|
+
|
|
209
|
+
## 开发
|
|
210
|
+
|
|
211
|
+
```bash
|
|
212
|
+
git clone https://github.com/zaf-x/unframed.git
|
|
213
|
+
cd unframed
|
|
214
|
+
pip install -e .
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
运行测试:
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
pip install pytest
|
|
221
|
+
python -m pytest tests/
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## 架构
|
|
225
|
+
|
|
226
|
+
```text
|
|
227
|
+
src/unframed/
|
|
228
|
+
├── __about__.py — 版本信息
|
|
229
|
+
├── __init__.py — 公共 API
|
|
230
|
+
├── engine.py — 核心引擎:状态管理、工具定义、Prompt 组装、游戏循环
|
|
231
|
+
├── cli.py — 交互式 CLI 入口(启动菜单、命令行命令)
|
|
232
|
+
├── settings.py — 持久化配置(~/.unframed_config.json)
|
|
233
|
+
├── render.py — BBCode → ANSI 渲染器
|
|
234
|
+
└── tui/
|
|
235
|
+
├── __init__.py — TUI 模块声明
|
|
236
|
+
└── app.py — Textual TUI 前端(图形界面)
|
|
237
|
+
```
|
|
238
|
+
|
|
239
|
+
基于 [ai-util](https://github.com/zaf-x/ai-util) 框架。
|
|
240
|
+
|
|
241
|
+
## License
|
|
242
|
+
|
|
243
|
+
`unframed` 基于 MIT 协议开源。
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Build script for PyInstaller.
|
|
3
|
+
|
|
4
|
+
Usage:
|
|
5
|
+
pip install pyinstaller
|
|
6
|
+
python build/build.py
|
|
7
|
+
|
|
8
|
+
Output:
|
|
9
|
+
dist/unframed/ # Directory with all dependencies
|
|
10
|
+
dist/unframed.exe # Windows executable (on Windows)
|
|
11
|
+
dist/unframed # Linux/macOS executable
|
|
12
|
+
"""
|
|
13
|
+
|
|
14
|
+
import os
|
|
15
|
+
import sys
|
|
16
|
+
import subprocess
|
|
17
|
+
from pathlib import Path
|
|
18
|
+
|
|
19
|
+
ROOT = Path(__file__).resolve().parent.parent
|
|
20
|
+
DIST = ROOT / "dist"
|
|
21
|
+
SPEC = ROOT / "build" / "unframed.spec"
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def main():
|
|
25
|
+
# Ensure seeds/ and docs/ are included
|
|
26
|
+
data_args = []
|
|
27
|
+
seeds_dir = ROOT / "seeds"
|
|
28
|
+
docs_dir = ROOT / "docs"
|
|
29
|
+
|
|
30
|
+
if seeds_dir.is_dir():
|
|
31
|
+
data_args.append(f"--add-data={seeds_dir}{os.pathsep}seeds")
|
|
32
|
+
if docs_dir.is_dir():
|
|
33
|
+
data_args.append(f"--add-data={docs_dir}{os.pathsep}docs")
|
|
34
|
+
|
|
35
|
+
cmd = [
|
|
36
|
+
sys.executable or "python",
|
|
37
|
+
"-m", "PyInstaller",
|
|
38
|
+
"--name=unframed",
|
|
39
|
+
"--onefile", # Single executable
|
|
40
|
+
"--console", # Console window
|
|
41
|
+
"--clean",
|
|
42
|
+
"--noconfirm",
|
|
43
|
+
# Add ai-util as a hidden import (git dependency)
|
|
44
|
+
"--hidden-import=ai_util",
|
|
45
|
+
"--hidden-import=ai_util.bot",
|
|
46
|
+
"--hidden-import=ai_util.agent",
|
|
47
|
+
"--hidden-import=ai_util.tools",
|
|
48
|
+
"--hidden-import=ai_util.sandbox",
|
|
49
|
+
# Textual hidden imports
|
|
50
|
+
"--hidden-import=textual",
|
|
51
|
+
"--hidden-import=textual.app",
|
|
52
|
+
"--hidden-import=textual.screen",
|
|
53
|
+
"--hidden-import=textual.widgets",
|
|
54
|
+
"--hidden-import=textual.containers",
|
|
55
|
+
"--hidden-import=textual.keys",
|
|
56
|
+
# Rich hidden imports
|
|
57
|
+
"--hidden-import=rich.markdown",
|
|
58
|
+
"--hidden-import=rich.console",
|
|
59
|
+
"--hidden-import=rich.panel",
|
|
60
|
+
"--hidden-import=rich.text",
|
|
61
|
+
# Colorama
|
|
62
|
+
"--hidden-import=colorama",
|
|
63
|
+
# OpenAI
|
|
64
|
+
"--hidden-import=openai",
|
|
65
|
+
*data_args,
|
|
66
|
+
str(ROOT / "src" / "unframed" / "__init__.py"),
|
|
67
|
+
]
|
|
68
|
+
|
|
69
|
+
print("Running PyInstaller...")
|
|
70
|
+
print(" ".join(cmd))
|
|
71
|
+
subprocess.check_call(cmd, cwd=ROOT)
|
|
72
|
+
|
|
73
|
+
print(f"\nDone! Executable at: {DIST / 'unframed'}{'.exe' if sys.platform == 'win32' else ''}")
|
|
74
|
+
print("Note: seeds/ and docs/ are bundled inside the executable.")
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
if __name__ == "__main__":
|
|
78
|
+
main()
|