palacelite 0.3.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.
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 fajknli
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,140 @@
1
+ Metadata-Version: 2.4
2
+ Name: palacelite
3
+ Version: 0.3.0
4
+ Summary: 轻量级 AI 记忆系统
5
+ Author: fajknli
6
+ Project-URL: Changelog, https://github.com/fajknli/palacelite/blob/main/CHANGELOG.md
7
+ Requires-Python: >=3.9
8
+ Description-Content-Type: text/markdown
9
+ License-File: LICENSE
10
+ Requires-Dist: chromadb>=1.5.0
11
+ Requires-Dist: sentence-transformers>=5.0.0
12
+ Requires-Dist: click>=8.0.0
13
+ Requires-Dist: rich>=13.0.0
14
+ Dynamic: license-file
15
+
16
+ # PalaceLite
17
+
18
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
19
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
20
+ [![Version](https://img.shields.io/badge/version-0.3.0-blue)](https://github.com/fajknli/palacelite/releases)
21
+
22
+ 轻量级 AI 记忆系统,灵感来自MemPalace。默认离线运行,数据完全本地化。
23
+
24
+ ## 核心概念
25
+
26
+ 采用三层结构组织记忆:**Wing**(项目或人)→ **Room**(具体话题)→ **Drawer**(记忆条目)。每条记忆存储原文和向量,支持混合检索(向量相似度 + 时间衰减 + 重要性加权)。
27
+
28
+ ## 安装
29
+
30
+ ```bash
31
+ git clone https://github.com/fajknli/palacelite.git
32
+ cd palacelite
33
+ pip install -e .
34
+ pip install -r requirements.txt
35
+ ```
36
+
37
+ 首次使用需下载嵌入模型(约百MB,BAAI/bge-small-zh-v1.5),添加 `--online` 参数即可自动下载,之后可永久离线运行。
38
+
39
+ ## 快速开始
40
+
41
+ ### CLI
42
+
43
+ ```bash
44
+ # 添加记忆
45
+ palacelite add -w default -r chat -c "用户喜欢 PostgreSQL"
46
+
47
+ # 搜索
48
+ palacelite search -q "数据库"
49
+
50
+ # 列出活跃记忆
51
+ palacelite list
52
+
53
+ # 归档超过90天且重要性低于2的记忆
54
+ palacelite archive-old --days 90 --importance 2
55
+
56
+ # 导出已归档记忆(自动保存到 ~/.palacelite/exports/)
57
+ palacelite export-archived
58
+
59
+ # 永久删除已归档记忆
60
+ palacelite delete-archived
61
+
62
+ # 统计
63
+ palacelite stats
64
+ ```
65
+
66
+ ### Python API
67
+
68
+ ```python
69
+ from palacelite import PalaceLite
70
+
71
+ p = PalaceLite() # 默认离线,offline=False 可联网下载模型
72
+
73
+ p.add_memory("用户喜欢 PostgreSQL", "default", "chat")
74
+ results = p.search("数据库")
75
+ context = p.build_context("数据库选型") # 构建 LLM 上下文
76
+ ```
77
+
78
+ 验证安装:
79
+
80
+ ```bash
81
+ python -c "from palacelite import PalaceLite; print('OK')"
82
+ ```
83
+
84
+ ### 带记忆对话
85
+
86
+ `examples/` 目录提供了完整的对话示例:
87
+
88
+ ```bash
89
+ # 离线模式(默认)
90
+ python examples/chat.py -m /path/to/model.gguf
91
+
92
+ # 联网模式(首次下载嵌入模型)
93
+ python examples/chat.py -m /path/to/model.gguf --online
94
+
95
+ # 指定 GPU 层数
96
+ python examples/chat.py -m /path/to/model.gguf -g 30
97
+ ```
98
+
99
+ 对话命令:`/help`、`/mem`、`/list`、`/stats`、`/clear`、`/quit`。
100
+
101
+ ## 命令速查
102
+
103
+ | 命令 | 说明 |
104
+ |------|------|
105
+ | `add -w <wing> -r <room> -c <内容>` | 添加记忆 |
106
+ | `search -q <关键词>` | 搜索记忆 |
107
+ | `list [-w wing] [-r room]` | 列出活跃记忆 |
108
+ | `archive-old [--days 90] [--importance 2]` | 批量归档旧记忆 |
109
+ | `list-archived` | 列出已归档记忆 |
110
+ | `export-archived [-o 路径]` | 导出归档到 JSON |
111
+ | `delete-archived` | 永久删除归档记忆 |
112
+ | `stats` | 显示统计信息 |
113
+ | `wings` | 列出所有 Wing |
114
+ | `rooms <wing>` | 列出指定 Wing 下的 Room |
115
+
116
+ ## 配置
117
+
118
+ | 环境变量 | 默认值 | 说明 |
119
+ |----------|--------|------|
120
+ | `PALACE_MODEL_PATH` | - | GGUF 模型文件路径 |
121
+ | `PALACE_MODEL_DIR` | `~/Public/ai/models` | 模型存放目录 |
122
+ | `GPU_LAYERS` | `20` | GPU 加速层数 |
123
+
124
+ 工作目录默认为 `~/.palacelite`,可通过 `PalaceLite(workspace="/path")` 自定义。
125
+
126
+ ## 数据维护
127
+
128
+ 导出数据清洗(用于微调):
129
+ ```bash
130
+ python scripts/clean_memories.py ~/backup.json ~/cleaned.json
131
+ ```
132
+
133
+ 更换嵌入模型后重建向量库:
134
+ ```bash
135
+ python scripts/rebuild_embeddings.py
136
+ ```
137
+
138
+ ## 许可证
139
+
140
+ MIT
@@ -0,0 +1,125 @@
1
+ # PalaceLite
2
+
3
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
4
+ [![Python 3.9+](https://img.shields.io/badge/python-3.9+-blue.svg)](https://www.python.org/downloads/)
5
+ [![Version](https://img.shields.io/badge/version-0.3.0-blue)](https://github.com/fajknli/palacelite/releases)
6
+
7
+ 轻量级 AI 记忆系统,灵感来自MemPalace。默认离线运行,数据完全本地化。
8
+
9
+ ## 核心概念
10
+
11
+ 采用三层结构组织记忆:**Wing**(项目或人)→ **Room**(具体话题)→ **Drawer**(记忆条目)。每条记忆存储原文和向量,支持混合检索(向量相似度 + 时间衰减 + 重要性加权)。
12
+
13
+ ## 安装
14
+
15
+ ```bash
16
+ git clone https://github.com/fajknli/palacelite.git
17
+ cd palacelite
18
+ pip install -e .
19
+ pip install -r requirements.txt
20
+ ```
21
+
22
+ 首次使用需下载嵌入模型(约百MB,BAAI/bge-small-zh-v1.5),添加 `--online` 参数即可自动下载,之后可永久离线运行。
23
+
24
+ ## 快速开始
25
+
26
+ ### CLI
27
+
28
+ ```bash
29
+ # 添加记忆
30
+ palacelite add -w default -r chat -c "用户喜欢 PostgreSQL"
31
+
32
+ # 搜索
33
+ palacelite search -q "数据库"
34
+
35
+ # 列出活跃记忆
36
+ palacelite list
37
+
38
+ # 归档超过90天且重要性低于2的记忆
39
+ palacelite archive-old --days 90 --importance 2
40
+
41
+ # 导出已归档记忆(自动保存到 ~/.palacelite/exports/)
42
+ palacelite export-archived
43
+
44
+ # 永久删除已归档记忆
45
+ palacelite delete-archived
46
+
47
+ # 统计
48
+ palacelite stats
49
+ ```
50
+
51
+ ### Python API
52
+
53
+ ```python
54
+ from palacelite import PalaceLite
55
+
56
+ p = PalaceLite() # 默认离线,offline=False 可联网下载模型
57
+
58
+ p.add_memory("用户喜欢 PostgreSQL", "default", "chat")
59
+ results = p.search("数据库")
60
+ context = p.build_context("数据库选型") # 构建 LLM 上下文
61
+ ```
62
+
63
+ 验证安装:
64
+
65
+ ```bash
66
+ python -c "from palacelite import PalaceLite; print('OK')"
67
+ ```
68
+
69
+ ### 带记忆对话
70
+
71
+ `examples/` 目录提供了完整的对话示例:
72
+
73
+ ```bash
74
+ # 离线模式(默认)
75
+ python examples/chat.py -m /path/to/model.gguf
76
+
77
+ # 联网模式(首次下载嵌入模型)
78
+ python examples/chat.py -m /path/to/model.gguf --online
79
+
80
+ # 指定 GPU 层数
81
+ python examples/chat.py -m /path/to/model.gguf -g 30
82
+ ```
83
+
84
+ 对话命令:`/help`、`/mem`、`/list`、`/stats`、`/clear`、`/quit`。
85
+
86
+ ## 命令速查
87
+
88
+ | 命令 | 说明 |
89
+ |------|------|
90
+ | `add -w <wing> -r <room> -c <内容>` | 添加记忆 |
91
+ | `search -q <关键词>` | 搜索记忆 |
92
+ | `list [-w wing] [-r room]` | 列出活跃记忆 |
93
+ | `archive-old [--days 90] [--importance 2]` | 批量归档旧记忆 |
94
+ | `list-archived` | 列出已归档记忆 |
95
+ | `export-archived [-o 路径]` | 导出归档到 JSON |
96
+ | `delete-archived` | 永久删除归档记忆 |
97
+ | `stats` | 显示统计信息 |
98
+ | `wings` | 列出所有 Wing |
99
+ | `rooms <wing>` | 列出指定 Wing 下的 Room |
100
+
101
+ ## 配置
102
+
103
+ | 环境变量 | 默认值 | 说明 |
104
+ |----------|--------|------|
105
+ | `PALACE_MODEL_PATH` | - | GGUF 模型文件路径 |
106
+ | `PALACE_MODEL_DIR` | `~/Public/ai/models` | 模型存放目录 |
107
+ | `GPU_LAYERS` | `20` | GPU 加速层数 |
108
+
109
+ 工作目录默认为 `~/.palacelite`,可通过 `PalaceLite(workspace="/path")` 自定义。
110
+
111
+ ## 数据维护
112
+
113
+ 导出数据清洗(用于微调):
114
+ ```bash
115
+ python scripts/clean_memories.py ~/backup.json ~/cleaned.json
116
+ ```
117
+
118
+ 更换嵌入模型后重建向量库:
119
+ ```bash
120
+ python scripts/rebuild_embeddings.py
121
+ ```
122
+
123
+ ## 许可证
124
+
125
+ MIT
@@ -0,0 +1,7 @@
1
+ """PalaceLite - 轻量级 AI 记忆系统"""
2
+
3
+ from .core import PalaceLite
4
+ from .models import Drawer, Room, SearchResult, Wing
5
+
6
+ __version__ = "0.3.0"
7
+ __all__ = ["PalaceLite", "Wing", "Room", "Drawer", "SearchResult"]
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env python3
2
+ # -*- coding: utf-8 -*-
3
+ """
4
+ PalaceLite 命令行工具
5
+
6
+ 用法:
7
+ palacelite add --wing <wing> --room <room> --content "记忆内容"
8
+ palacelite search --query "搜索内容"
9
+ palacelite list --wing <wing>
10
+ palacelite stats
11
+ """
12
+
13
+ from datetime import datetime
14
+
15
+ import click
16
+ from rich.console import Console
17
+ from rich.panel import Panel
18
+ from rich.table import Table
19
+
20
+ from .core import PalaceLite
21
+
22
+ console = Console()
23
+
24
+
25
+ @click.group(context_settings={"help_option_names": ["-h", "--help"]})
26
+ def cli():
27
+ """PalaceLite - 轻量级 AI 记忆系统"""
28
+
29
+
30
+ @cli.command()
31
+ @click.option("--wing", "-w", required=True, help="Wing 名称(项目或人)")
32
+ @click.option("--room", "-r", required=True, help="Room 名称(话题)")
33
+ @click.option("--content", "-c", required=True, help="记忆内容")
34
+ @click.option("--tags", "-t", help="标签,逗号分隔")
35
+ @click.option("--importance", "-i", default=1, help="重要性(1-10)")
36
+ def add(wing, room, content, tags, importance):
37
+ """添加记忆"""
38
+ p = PalaceLite()
39
+
40
+ # 确保 wing 存在
41
+ if not p.get_wing(wing):
42
+ p.add_wing(wing)
43
+ console.print(f"[yellow]自动创建 Wing: {wing}[/yellow]")
44
+
45
+ # 确保 room 存在
46
+ if not p.get_room(wing, room):
47
+ p.add_room(wing, room)
48
+ console.print(f"[yellow]自动创建 Room: {wing}/{room}[/yellow]")
49
+
50
+ tag_list = tags.split(",") if tags else []
51
+ drawer = p.add_memory(content, wing, room, tag_list, importance)
52
+
53
+ console.print(f"[green]✓[/green] 已添加记忆 (id: {drawer.id[:8]}...)")
54
+
55
+
56
+ @cli.command()
57
+ @click.option("--query", "-q", required=True, help="搜索内容")
58
+ @click.option("--wing", "-w", help="限定 Wing")
59
+ @click.option("--room", "-r", help="限定 Room(需与 --wing 一起使用)")
60
+ @click.option("--top", "-k", default=5, help="返回结果数量")
61
+ def search(query, wing, room, top):
62
+ """搜索记忆"""
63
+ p = PalaceLite()
64
+
65
+ if wing and room:
66
+ results = p.search_by_room(query, wing, room, top)
67
+ title = f"在 {wing}/{room} 中搜索: {query}"
68
+ elif wing:
69
+ results = p.search_by_wing(query, wing, top)
70
+ title = f"在 {wing} 中搜索: {query}"
71
+ else:
72
+ results = p.search(query, top_k=top)
73
+ title = f"搜索: {query}"
74
+
75
+ if not results:
76
+ console.print("[yellow]未找到相关记忆[/yellow]")
77
+ return
78
+
79
+ table = Table(title=title)
80
+ table.add_column("#", style="dim")
81
+ table.add_column("位置", style="cyan")
82
+ table.add_column("记忆内容", style="white")
83
+ table.add_column("得分", style="green")
84
+
85
+ for i, r in enumerate(results, 1):
86
+ location = f"{r.wing_name}/{r.room_name}"
87
+ content = r.drawer.content[:80] + ("..." if len(r.drawer.content) > 80 else "")
88
+ table.add_row(str(i), location, content, f"{r.score:.3f}")
89
+
90
+ console.print(table)
91
+
92
+
93
+ @cli.command()
94
+ @click.option("--wing", "-w", help="限定 Wing")
95
+ @click.option("--room", "-r", help="限定 Room(需与 --wing 一起使用)")
96
+ def list(wing, room):
97
+ """列出记忆"""
98
+ p = PalaceLite()
99
+
100
+ if wing and room:
101
+ memories = p.list_memories(wing, room)
102
+ title = f"记忆列表: {wing}/{room}"
103
+ elif wing:
104
+ memories = p.list_memories(wing)
105
+ title = f"记忆列表: {wing}"
106
+ else:
107
+ memories = p.list_memories()
108
+ title = "所有记忆"
109
+
110
+ if not memories:
111
+ console.print("[yellow]没有记忆[/yellow]")
112
+ return
113
+
114
+ table = Table(title=title)
115
+ table.add_column("ID", style="dim")
116
+ table.add_column("位置", style="cyan")
117
+ table.add_column("记忆内容", style="white")
118
+ table.add_column("重要性", style="green")
119
+
120
+ for m in memories[:20]:
121
+ # 获取位置
122
+ room_obj = p.get_room_by_id(m.room_id)
123
+ if room_obj:
124
+ wing_obj = p.get_wing_by_id(room_obj.wing_id)
125
+ wing_name = wing_obj.name if wing_obj else "?"
126
+ room_name = room_obj.name
127
+ else:
128
+ wing_name = "?"
129
+ room_name = "?"
130
+
131
+ content = m.content[:60] + ("..." if len(m.content) > 60 else "")
132
+ table.add_row(m.id[:8], f"{wing_name}/{room_name}", content, str(m.importance))
133
+
134
+ console.print(table)
135
+
136
+
137
+ @cli.command()
138
+ def stats():
139
+ """显示统计信息"""
140
+ p = PalaceLite()
141
+ stats = p.stats()
142
+
143
+ panel = Panel(
144
+ f"[bold]Wings:[/bold] {stats['wings']}\n"
145
+ f"[bold]Rooms:[/bold] {stats['rooms']}\n"
146
+ f"[bold]Drawers:[/bold] {stats['drawers']}\n"
147
+ f"[bold]总重要性:[/bold] {stats['total_importance']}\n"
148
+ f"[bold]数据库大小:[/bold] {stats['db_size_bytes'] / 1024:.1f} KB\n"
149
+ f"[bold]工作目录:[/bold] {stats['workspace']}",
150
+ title="PalaceLite 统计",
151
+ border_style="green",
152
+ )
153
+ console.print(panel)
154
+
155
+
156
+ @cli.command()
157
+ @click.option("--days", "-d", default=90, help="归档超过多少天的记忆")
158
+ @click.option("--importance", "-i", default=2, help="重要性低于此值的记忆")
159
+ def archive_old(days, importance):
160
+ """归档旧记忆"""
161
+ p = PalaceLite()
162
+ count = p.archive_old_memories(min_importance=importance, days_old=days)
163
+ console.print(f"[green]✓ 已归档 {count} 条记忆[/green]")
164
+
165
+
166
+ @cli.command()
167
+ def list_archived():
168
+ """列出已归档的记忆"""
169
+ p = PalaceLite()
170
+ memories = p.list_archived_memories()
171
+
172
+ if not memories:
173
+ console.print("[yellow]没有已归档的记忆[/yellow]")
174
+ return
175
+
176
+ table = Table(title="已归档的记忆")
177
+ table.add_column("#", style="dim")
178
+ table.add_column("ID", style="dim")
179
+ table.add_column("内容", style="white")
180
+
181
+ for i, m in enumerate(memories[:20], 1):
182
+ content = m.content[:60] + ("..." if len(m.content) > 60 else "")
183
+ table.add_row(str(i), m.id[:8], content)
184
+
185
+ console.print(table)
186
+
187
+
188
+ @cli.command()
189
+ @click.option("--output", "-o", help="输出文件路径(可选,默认自动生成)")
190
+ def export_archived(output):
191
+ """导出已归档的记忆到 JSON"""
192
+ p = PalaceLite()
193
+ count, path = p.export_archived_memories(output)
194
+ console.print(f"[green]已导出 {count} 条记忆到 {path}[/green]")
195
+
196
+
197
+ @cli.command()
198
+ @click.confirmation_option(prompt="确定要永久删除所有已归档的记忆吗?")
199
+ def delete_archived():
200
+ """永久删除已归档的记忆"""
201
+ p = PalaceLite()
202
+ count = p.delete_archived_memories()
203
+ console.print(f"[green]✓ 已永久删除 {count} 条记忆[/green]")
204
+
205
+
206
+ @cli.command()
207
+ def wings():
208
+ """列出所有 Wing"""
209
+ p = PalaceLite()
210
+ wings = p.list_wings()
211
+
212
+ if not wings:
213
+ console.print("[yellow]没有 Wing[/yellow]")
214
+ return
215
+
216
+ table = Table(title="Wings 列表")
217
+ table.add_column("名称", style="cyan")
218
+ table.add_column("类型", style="green")
219
+ table.add_column("创建时间", style="dim")
220
+
221
+ for w in wings:
222
+ created = datetime.fromtimestamp(w.created_at).strftime("%Y-%m-%d %H:%M")
223
+ table.add_row(w.name, w.type, created)
224
+
225
+ console.print(table)
226
+
227
+
228
+ @cli.command()
229
+ @click.argument("wing_name")
230
+ def rooms(wing_name):
231
+ """列出指定 Wing 下的 Rooms"""
232
+ p = PalaceLite()
233
+ rooms = p.list_rooms(wing_name)
234
+
235
+ if not rooms:
236
+ console.print(f"[yellow]Wing '{wing_name}' 下没有 Room[/yellow]")
237
+ return
238
+
239
+ table = Table(title=f"Rooms 列表: {wing_name}")
240
+ table.add_column("名称", style="cyan")
241
+ table.add_column("创建时间", style="dim")
242
+
243
+ for r in rooms:
244
+ created = datetime.fromtimestamp(r.created_at).strftime("%Y-%m-%d %H:%M")
245
+ table.add_row(r.name, created)
246
+
247
+ console.print(table)
248
+
249
+
250
+ if __name__ == "__main__":
251
+ cli()