refactor: Web 服务内嵌主进程 + 文档移到 docs/ 二级目录
1. Web 服务改为 threading 模式: - 新增 run_web_server(port) / stop_web_server() 函数 - TUI 通过 from web_api import run_web_server 直接调用 - 使用 werkzeug make_server 实现线程内优雅启动/停止 2. 构建脚本精简为单二进制: - 移除 trulymem-web 独立打包步骤 - 添加 werkzeug 到 hidden-imports 3. 详细启动文档移到 docs/zh/quick_start.md 4. README 精简为概述,指向 docs/ 目录
This commit is contained in:
167
README.md
167
README.md
@ -4,190 +4,61 @@
|
||||
<img src="pic/image.png" alt="TrulyMEM Logo" width="200">
|
||||
</p>
|
||||
|
||||
> **📜 开源协议**: [GNU General Public License v3.0 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
> 本项目自由开源,可自由使用、修改和分发,但修改后的作品必须以相同许可证发布。
|
||||
> **📜 开源协议**: [GNU General Public License v3.0 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
> **English**: [Switch to English version](./README_EN.md)
|
||||
> **English**: [README_EN.md](./README_EN.md)
|
||||
|
||||
**让 AI 拥有自知、可塑、有分寸感的长期记忆**
|
||||
|
||||
*The More Human Choice.*
|
||||
**让 AI 拥有自知、可塑、有分寸感的长期记忆** — *The More Human Choice.*
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://www.python.org/downloads/)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
---
|
||||
|
||||
## 故事的开头
|
||||
## 一句话
|
||||
|
||||
行业普遍认为,LLM 海量参数让其涌现了智能。但这个智能是「死的」——它不会真的记住,也不理解「记住」的概念。它输出的一切,都是当前输入的全部文本经历无数次前向传播计算出的概率最优解。LLM 不会因为某次对话意识到错误而去修正权重,也无法因此针对模型进行一次反向传播。它的意识是被冻结的,展现出的智能只是冻结的意识的回响。
|
||||
|
||||
现在的所谓记忆系统,只是将记忆外化,让「系统」去替 LLM 记住。或者就是粗暴地将一切上下文文本丢给 LLM。这就是对模型输入的浪费。
|
||||
|
||||
**TrulyMEM 想,既然 LLM 无法实时纠正模型权重,为什么不把记忆权交还给 LLM 呢?**
|
||||
|
||||
我们提供一系列机制,让 LLM 决定它要记住什么、遗忘,什么是重点、什么是糟粕。LLM 推理的过程,就是思考的过程,也是回忆的过程。完全摒弃传统的 messages 数组上下文,将全部记忆以**三元组(图)**的形式保存在图数据库中。在 LLM 思考时,可以按照图数据库的链接自主跳转、联想相关关系,让 LLM 自然地实现联想与回忆。
|
||||
|
||||
赋予 LLM 真正的记忆。
|
||||
TrulyMEM 将记忆权交还给 LLM。通过图数据库(三元组)替代传统 messages 数组,让 LLM 自主决定记什么、忘什么。
|
||||
|
||||
---
|
||||
|
||||
## 快速开始
|
||||
|
||||
### 方式一:打包后的可执行文件
|
||||
|
||||
```bash
|
||||
# Windows: TrulyMEM.exe
|
||||
# Linux/macOS: TrulyMEM
|
||||
chmod +x TrulyMEM
|
||||
./TrulyMEM
|
||||
python trulymem_entry.py # 从源码
|
||||
./dist/TrulyMEM # 打包后
|
||||
```
|
||||
|
||||
### 方式二:从源码运行
|
||||
首次启动 → TUI 登录页面 → 创建/登录账号 → 按 **F2** 配置 API Key → 开始聊天
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd TrulyMEM-TrueHumanMEM
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
python trulymem_entry.py
|
||||
```
|
||||
|
||||
### 首次使用(TUI 登录)
|
||||
|
||||
首次运行时会检测数据库状态,引导你完成:
|
||||
|
||||
1. **TUI 登录页面** — 如果是新部署或无迁移需求,直接设置账号密码
|
||||
2. **旧版自动迁移** — 如果检测到旧版 `~/.trulymem/config.json`,自动引导迁移为多用户模式
|
||||
3. **首个用户自动成为管理员**
|
||||
|
||||
登录后进入聊天界面:
|
||||
|
||||
1. 按 **F2** 展开右侧配置面板
|
||||
2. 输入 **API Key**(支持 DeepSeek、OpenAI 等兼容 API)
|
||||
3. 按 **Enter** 保存配置
|
||||
4. 开始对话!
|
||||
|
||||
📌 **管理员** 可在右侧面板管理 Web 服务开关、修改 Web 登录凭据。
|
||||
📌 **普通用户** 只能配置 API Key 和模型参数。
|
||||
📖 **详细启动文档**: [docs/zh/quick_start.md](docs/zh/quick_start.md)
|
||||
|
||||
---
|
||||
|
||||
### 多用户系统
|
||||
## 主要特性
|
||||
|
||||
TrulyMEM 支持多用户隔离,每个用户拥有独立的配置和数据目录:
|
||||
|
||||
```
|
||||
~/.trulymem/
|
||||
├── trulymem.db # 全局用户数据库
|
||||
├── .migrated # 旧版迁移标记
|
||||
├── admin/
|
||||
│ ├── config.json # 管理员配置
|
||||
│ └── admin_graph.db # 管理员知识图谱
|
||||
└── user2/
|
||||
├── config.json # user2 配置
|
||||
└── user2_graph.db # user2 知识图谱
|
||||
```
|
||||
|
||||
- **首个注册用户自动成为管理员**
|
||||
- 管理员可在 Web 设置页添加/删除用户
|
||||
- 普通用户无法看到用户管理区域
|
||||
|
||||
### Web 可视化界面
|
||||
|
||||
TUI 启动后,管理员可在右侧面板勾选「启用 Web 服务」自动启动,或手动运行:
|
||||
|
||||
```bash
|
||||
# 手动启动 Web 服务
|
||||
python web_api.py --port 4096
|
||||
```
|
||||
|
||||
然后打开浏览器访问 `http://localhost:4096`。
|
||||
|
||||
**首次访问** → 自动跳转至设置页,创建管理员账号 → 跳转至星图可视化页面。
|
||||
|
||||
**Web 功能:**
|
||||
- 🌟 星图可视化浏览知识图谱
|
||||
- ⚙ 设置页:修改密码、管理用户(管理员专属)
|
||||
- 🔒 会话认证,多用户安全隔离
|
||||
|
||||
---
|
||||
|
||||
## 打包构建
|
||||
|
||||
项目支持 PyInstaller 打包为单文件可执行文件:
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
bash build/build_linux.sh
|
||||
|
||||
# macOS
|
||||
bash build/build_macos.sh
|
||||
|
||||
# Windows
|
||||
build\build_windows.bat
|
||||
|
||||
# AppImage(Linux 通用打包)
|
||||
bash build/build_appimage.sh
|
||||
```
|
||||
|
||||
构建产出在 `dist/` 目录:
|
||||
|
||||
| 文件 | 用途 |
|
||||
| 特性 | 说明 |
|
||||
|------|------|
|
||||
| `TrulyMEM` | TUI 主程序(含 Web 子进程启动能力) |
|
||||
| `trulymem-web` | Web 服务独立二进制(TUI 启动子进程时自动使用) |
|
||||
|
||||
### Web 启动优先级(TUI 内)
|
||||
1. 同目录 `trulymem-web` 二进制(打包环境)
|
||||
2. `sys._MEIPASS/web_api.py`(PyInstaller 数据文件回退)
|
||||
3. `python3 web_api.py`(开发环境回退)
|
||||
| 🧠 **图记忆** | 三元组存储,LLM 自主推理跳转 |
|
||||
| 🔐 **多用户** | 用户隔离 + Admin/User 角色权限 |
|
||||
| 🌐 **Web 可视化** | 内嵌 Flask 服务(线程模式),实时浏览知识图谱 |
|
||||
| 🎮 **TUI 界面** | Textual 终端界面,F2 配置面板 |
|
||||
| 📦 **单文件打包** | PyInstaller 打包,Web 服务内嵌于主二进制 |
|
||||
|
||||
---
|
||||
|
||||
## 文档索引
|
||||
|
||||
详细技术文档请参阅 [docs/zh/](docs/zh/) 目录:
|
||||
|
||||
| 文档 | 内容 |
|
||||
|------|------|
|
||||
| [docs/zh/quick_start.md](docs/zh/quick_start.md) | 🔥 **完整启动指南**(含 Web、多用户、打包) |
|
||||
| [docs/zh/architecture.md](docs/zh/architecture.md) | 系统架构和技术设计 |
|
||||
| [docs/zh/quick_start.md](docs/zh/quick_start.md) | 完整启动指南与配置说明 |
|
||||
| [docs/zh/memory.md](docs/zh/memory.md) | 内部记忆工作机制 |
|
||||
| [docs/zh/persona.md](docs/zh/persona.md) | 人设图机制 |
|
||||
| [docs/zh/working_memory.md](docs/zh/working_memory.md) | 连续性任务处理机制 |
|
||||
| [docs/zh/api.md](docs/zh/api.md) | 后端 API 接口(供扩展开发) |
|
||||
| [docs/zh/api.md](docs/zh/api.md) | 后端 API 接口 |
|
||||
| [docs/zh/prompts.md](docs/zh/prompts.md) | 提示词管理模块 |
|
||||
|
||||
---
|
||||
|
||||
## 贡献
|
||||
|
||||
欢迎提交 Issue 和 Pull Request!
|
||||
|
||||
1. Fork 本仓库
|
||||
2. 创建特性分支 (`git checkout -b feature/AmazingFeature`)
|
||||
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. 推送到分支 (`git push origin feature/AmazingFeature`)
|
||||
5. 创建 Pull Request
|
||||
|
||||
---
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目采用 **GNU General Public License v3.0 (GPLv3)** 许可证开源。
|
||||
详见 [LICENSE](LICENSE) 文件。
|
||||
|
||||
---
|
||||
|
||||
## 特别鸣谢
|
||||
|
||||
- [Prof. Meiting Wang](https://www.xxmu.edu.cn/yxgcxy/info/1260/4252.htm) — 学术指导
|
||||
- [逝水秋生白](https://atomgit.com/cenber) — 架构支持
|
||||
- anzhitinglan — 测试资源支持
|
||||
- 崔莉萍老师 — 理论指导
|
||||
- Annie — 专业指导
|
||||
- 王梓沣、马悦华、隆梦婷 — 神经科学理论支持
|
||||
GNU General Public License v3.0 (GPLv3)
|
||||
|
||||
177
README_EN.md
177
README_EN.md
@ -4,190 +4,61 @@
|
||||
<img src="pic/image.png" alt="TrulyMEM Logo" width="200">
|
||||
</p>
|
||||
|
||||
> **📜 License**: [GNU General Public License v3.0 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
> This project is free and open source. You are free to use, modify, and distribute, but modified works must be distributed under the same license.
|
||||
> **📜 License**: [GNU General Public License v3.0 (GPLv3)](https://www.gnu.org/licenses/gpl-3.0)
|
||||
|
||||
> **中文**: [切换到中文版](./README.md)
|
||||
> **中文**: [README.md](./README.md)
|
||||
|
||||
**Give AI self-awareness, plasticity, and a sense of proportion in long-term memory**
|
||||
|
||||
*The More Human Choice.*
|
||||
**Give AI self-awareness, plasticity, and a sense of proportion in long-term memory** — *The More Human Choice.*
|
||||
|
||||
[](https://www.gnu.org/licenses/gpl-3.0)
|
||||
[](https://www.python.org/downloads/)
|
||||
[]()
|
||||
[]()
|
||||
|
||||
---
|
||||
|
||||
## The Story
|
||||
## In a Nutshell
|
||||
|
||||
Industry believes that LLMs' massive parameters give them emergent intelligence. But this intelligence is "dead" — it cannot truly remember, nor understand the concept of "remembering". Everything it outputs is the probabilistic optimal solution calculated through countless forward passes on the current input text. The LLM cannot correct its weights based on errors in a conversation, nor perform a backward pass. Its consciousness is frozen — what appears as intelligence is merely the echo of this frozen consciousness.
|
||||
|
||||
Current "memory systems" merely externalize memory, letting the "system" remember for the LLM. Or they dump all context text to the LLM. This is a waste of the model's limited input context.
|
||||
|
||||
**TrulyMEM asks: since the LLM cannot correct model weights in real-time, why not give the memory authority back to the LLM?**
|
||||
|
||||
We provide a series of mechanisms for the LLM to decide what to remember, what to forget, what's important, what's trivial. The LLM's reasoning process is also its thinking and recalling process. Abandoning the traditional messages array context, all memories are stored as **triplets (graph)** in the graph database. When the LLM thinks, it can autonomously jump through graph links to associate related relationships, enabling natural association and recall.
|
||||
|
||||
Give the LLM true memory.
|
||||
TrulyMEM gives memory authority back to the LLM. Using graph database (triplets) instead of the traditional messages array, the LLM autonomously decides what to remember and what to forget.
|
||||
|
||||
---
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Method 1: Run Packaged Executable
|
||||
|
||||
```bash
|
||||
# Windows: TrulyMEM.exe
|
||||
# Linux/macOS: TrulyMEM
|
||||
chmod +x TrulyMEM
|
||||
./TrulyMEM
|
||||
python trulymem_entry.py # from source
|
||||
./dist/TrulyMEM # packaged binary
|
||||
```
|
||||
|
||||
### Method 2: Run from Source
|
||||
First run → TUI login screen → create/sign in → press **F2** for API Key → start chatting
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd TrulyMEM-TrueHumanMEM
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
python trulymem_entry.py
|
||||
```
|
||||
|
||||
### First Run (TUI Login)
|
||||
|
||||
On first launch, TrulyMEM will guide you through:
|
||||
|
||||
1. **TUI Login Screen** — Set up your username and password
|
||||
2. **Auto Migration** — If old `~/.trulymem/config.json` is detected, guides you through multi-user migration
|
||||
3. **First user becomes admin automatically**
|
||||
|
||||
After login:
|
||||
|
||||
1. Press **F2** to expand the right-side configuration panel
|
||||
2. Enter your **API Key** (supports DeepSeek, OpenAI, etc.)
|
||||
3. Press **Enter** to save
|
||||
4. Start chatting!
|
||||
|
||||
📌 **Admin users** can manage Web service settings and Web login credentials in the side panel.
|
||||
📌 **Regular users** can only configure API Key and model parameters.
|
||||
📖 **Full guide**: [docs/en/quick_start.md](docs/en/quick_start.md)
|
||||
|
||||
---
|
||||
|
||||
### Multi-User System
|
||||
## Features
|
||||
|
||||
TrulyMEM supports isolated multi-user environments. Each user has their own config and database:
|
||||
|
||||
```
|
||||
~/.trulymem/
|
||||
├── trulymem.db # Global user database
|
||||
├── .migrated # Migration flag
|
||||
├── admin/
|
||||
│ ├── config.json # Admin config
|
||||
│ └── admin_graph.db # Admin knowledge graph
|
||||
└── user2/
|
||||
├── config.json # user2 config
|
||||
└── user2_graph.db # user2 knowledge graph
|
||||
```
|
||||
|
||||
- **First user becomes admin automatically**
|
||||
- Admins can add/delete users on the Web settings page
|
||||
- Regular users cannot see the user management section
|
||||
|
||||
### Web Visualization Interface
|
||||
|
||||
From TUI, admin users can enable Web service via the right-side panel checkbox, or start manually:
|
||||
|
||||
```bash
|
||||
# Start Web service
|
||||
python web_api.py --port 4096
|
||||
```
|
||||
|
||||
Then open `http://localhost:4096` in your browser.
|
||||
|
||||
**First visit** → Auto-redirect to setup page → Create admin account → Redirect to star map visualization.
|
||||
|
||||
**Web features:**
|
||||
- 🌟 Star map visualization for browsing the knowledge graph
|
||||
- ⚙ Settings page: change password, manage users (admin only)
|
||||
- 🔒 Session-based authentication with multi-user isolation
|
||||
| Feature | Description |
|
||||
|---------|-------------|
|
||||
| 🧠 **Graph Memory** | Triplet storage, LLM autonomous navigation |
|
||||
| 🔐 **Multi-User** | Isolated profiles + Admin/User roles |
|
||||
| 🌐 **Web UI** | Embedded Flask server (thread mode) for knowledge graph browsing |
|
||||
| 🎮 **TUI** | Textual-based terminal UI with F2 config panel |
|
||||
| 📦 **Single Binary** | PyInstaller build, Web server embedded |
|
||||
|
||||
---
|
||||
|
||||
## Building
|
||||
|
||||
TrulyMEM supports PyInstaller packaging into single-file executables:
|
||||
|
||||
```bash
|
||||
# Linux
|
||||
bash build/build_linux.sh
|
||||
|
||||
# macOS
|
||||
bash build/build_macos.sh
|
||||
|
||||
# Windows
|
||||
build\build_windows.bat
|
||||
|
||||
# AppImage (Linux universal)
|
||||
bash build/build_appimage.sh
|
||||
```
|
||||
|
||||
Build outputs in `dist/`:
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `TrulyMEM` | TUI main program (can spawn Web subprocess) |
|
||||
| `trulymem-web` | Web service standalone binary (auto-detected by TUI) |
|
||||
|
||||
### Web binary priority (within TUI)
|
||||
1. `trulymem-web` in same directory (packaged)
|
||||
2. `sys._MEIPASS/web_api.py` (PyInstaller data fallback)
|
||||
3. `python3 web_api.py` (development fallback)
|
||||
|
||||
---
|
||||
|
||||
## Documentation Index
|
||||
|
||||
Detailed technical documentation in the [docs/en/](docs/en/) directory:
|
||||
## Documentation
|
||||
|
||||
| Document | Content |
|
||||
|----------|---------|
|
||||
| [docs/en/architecture.md](docs/en/architecture.md) | System architecture and technical design |
|
||||
| [docs/en/quick_start.md](docs/en/quick_start.md) | Complete startup guide and configuration |
|
||||
| [docs/en/memory.md](docs/en/memory.md) | Internal memory working mechanism |
|
||||
| [docs/en/quick_start.md](docs/en/quick_start.md) | 🔥 **Full setup guide** (Web, multi-user, building) |
|
||||
| [docs/en/architecture.md](docs/en/architecture.md) | System architecture and design |
|
||||
| [docs/en/memory.md](docs/en/memory.md) | Memory working mechanism |
|
||||
| [docs/en/persona.md](docs/en/persona.md) | Persona Graph mechanism |
|
||||
| [docs/en/working_memory.md](docs/en/working_memory.md) | Continuous task handling mechanism |
|
||||
| [docs/en/api.md](docs/en/api.md) | BackendServer API (for extension development) |
|
||||
| [docs/en/prompts.md](docs/en/prompts.md) | Prompt management module |
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Welcome to submit Issues and Pull Requests!
|
||||
|
||||
1. Fork this repository
|
||||
2. Create feature branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push to branch (`git push origin feature/AmazingFeature`)
|
||||
5. Create Pull Request
|
||||
| [docs/en/api.md](docs/en/api.md) | Backend API |
|
||||
| [docs/en/prompts.md](docs/en/prompts.md) | Prompt management |
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the **GNU General Public License v3.0 (GPLv3)**.
|
||||
See [LICENSE](LICENSE) file for details.
|
||||
|
||||
---
|
||||
|
||||
## Special Thanks
|
||||
|
||||
- [Prof. Meiting Wang](https://www.xxmu.edu.cn/yxgcxy/info/1260/4252.htm) — Academic guidance
|
||||
- [逝水秋生白](https://atomgit.com/cenber) — Architecture support
|
||||
- anzhitinglan — Testing resource support
|
||||
- 崔莉萍老师 — Theoretical guidance
|
||||
- Annie — Professional guidance
|
||||
- 王梓沣、马悦华、隆梦婷 — Neuroscience theory support
|
||||
GNU General Public License v3.0 (GPLv3)
|
||||
|
||||
@ -1,50 +1,41 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
echo "===== Building TrulyMEM AppImage for Linux ====="
|
||||
|
||||
echo "===== Building TrulyMEM AppImage ====="
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
cd "$PROJECT_ROOT"
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "Error: python3 not found"
|
||||
exit 1
|
||||
fi
|
||||
APPDIR="$PROJECT_ROOT/TrulyMEM.AppDir"
|
||||
rm -rf "$APPDIR"
|
||||
mkdir -p "$APPDIR/usr/bin"
|
||||
mkdir -p "$APPDIR/usr/share/trulymem"
|
||||
mkdir -p "$APPDIR/usr/share/trulymem-web"
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
|
||||
echo "===== Step 1: Build binaries with PyInstaller ====="
|
||||
VENV_DIR="$PROJECT_ROOT/.venv_appimage"
|
||||
rm -rf "$VENV_DIR"
|
||||
# ── 检查依赖 ──────────────────────────────────────────────────────────────
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "Error: python3 not found"; exit 1
|
||||
fi
|
||||
|
||||
APPIMAGE_TOOL="${APPIMAGE_TOOL:-appimagetool}"
|
||||
if ! command -v "$APPIMAGE_TOOL" &> /dev/null && [ ! -f "$APPIMAGE_TOOL" ]; then
|
||||
echo "Warning: $APPIMAGE_TOOL not found, will try to create AppDir only"
|
||||
SKIP_APPIMAGE=1
|
||||
fi
|
||||
|
||||
# ── 虚拟环境 ──────────────────────────────────────────────────────────────
|
||||
VENV_DIR="$PROJECT_ROOT/.venv_build"
|
||||
echo "Creating virtual environment: $VENV_DIR"
|
||||
python3 -m venv "$VENV_DIR"
|
||||
source "$VENV_DIR/bin/activate"
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
pip install pyinstaller
|
||||
rm -rf "$PROJECT_ROOT/build/pyinstaller_build" "$PROJECT_ROOT/dist"
|
||||
|
||||
CORE_HIDDEN=(
|
||||
--hidden-import core
|
||||
--hidden-import core.embedded_db
|
||||
--hidden-import core.graph_client
|
||||
--hidden-import core.tool_executor
|
||||
--hidden-import core.tool_limiter
|
||||
--hidden-import core.tools
|
||||
--hidden-import core.tools.memory_tools
|
||||
--hidden-import core.prompts
|
||||
--hidden-import core.prompts.prompt_manager
|
||||
--hidden-import core.server
|
||||
--hidden-import core.client
|
||||
--hidden-import core.migrate
|
||||
--hidden-import core.activity_recorder
|
||||
)
|
||||
echo "Cleaning previous builds..."
|
||||
rm -rf build/dist build/__pycache__ 2>/dev/null || true
|
||||
|
||||
echo "Running PyInstaller for TUI..."
|
||||
pyinstaller trulymem_entry.py \
|
||||
# ── 打包 ──────────────────────────────────────────────────────────────────
|
||||
echo "================================"
|
||||
echo "Building TrulyMEM (TUI + Web embedded)"
|
||||
echo "================================"
|
||||
python -m PyInstaller trulymem_entry.py \
|
||||
--clean --onefile --console --name TrulyMEM \
|
||||
--distpath "$PROJECT_ROOT/dist" \
|
||||
--workpath "$PROJECT_ROOT/build/pyinstaller_build/tui" \
|
||||
--add-data "ui/styles:ui/styles" \
|
||||
--add-data "core/prompts/templates:core/prompts/templates" \
|
||||
--add-data "static:static" \
|
||||
@ -58,7 +49,19 @@ pyinstaller trulymem_entry.py \
|
||||
--hidden-import openai._client \
|
||||
--hidden-import neo4j \
|
||||
--hidden-import sqlite3 \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--hidden-import core \
|
||||
--hidden-import core.embedded_db \
|
||||
--hidden-import core.graph_client \
|
||||
--hidden-import core.tool_executor \
|
||||
--hidden-import core.tool_limiter \
|
||||
--hidden-import core.tools \
|
||||
--hidden-import core.tools.memory_tools \
|
||||
--hidden-import core.prompts \
|
||||
--hidden-import core.prompts.prompt_manager \
|
||||
--hidden-import core.server \
|
||||
--hidden-import core.client \
|
||||
--hidden-import core.migrate \
|
||||
--hidden-import core.activity_recorder \
|
||||
--hidden-import ui \
|
||||
--hidden-import ui.app \
|
||||
--hidden-import ui.login_screen \
|
||||
@ -74,88 +77,65 @@ pyinstaller trulymem_entry.py \
|
||||
--hidden-import web_api \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
--hidden-import werkzeug \
|
||||
--collect-all textual \
|
||||
--noconfirm
|
||||
|
||||
echo "Running PyInstaller for Web..."
|
||||
pyinstaller web_api.py \
|
||||
--clean --onefile --console --name trulymem-web \
|
||||
--distpath "$PROJECT_ROOT/dist" \
|
||||
--workpath "$PROJECT_ROOT/build/pyinstaller_build/web" \
|
||||
--add-data "templates:templates" \
|
||||
--add-data "static:static" \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--noconfirm
|
||||
# ── 创建 AppDir ───────────────────────────────────────────────────────────
|
||||
APP_NAME="TrulyMEM"
|
||||
APP_DIR="$PROJECT_ROOT/build/${APP_NAME}.AppDir"
|
||||
mkdir -p "$APP_DIR/usr/bin"
|
||||
cp "dist/TrulyMEM" "$APP_DIR/usr/bin/TrulyMEM"
|
||||
|
||||
cp "$PROJECT_ROOT/dist/TrulyMEM" "$APPDIR/usr/bin/"
|
||||
cp "$PROJECT_ROOT/dist/trulymem-web" "$APPDIR/usr/bin/"
|
||||
cp "$PROJECT_ROOT/trulymem_entry.py" "$APPDIR/usr/share/trulymem/"
|
||||
|
||||
echo "===== Step 2: Create AppImage structure ====="
|
||||
cat > "$APPDIR/AppRun" << 'EOF'
|
||||
#!/bin/bash
|
||||
set -e
|
||||
SELF=$(readlink -f "$0")
|
||||
APPDIR=$(dirname "$SELF")
|
||||
export PATH="$APPDIR/usr/bin:$PATH"
|
||||
exec "$APPDIR/usr/bin/TrulyMEM" "$@"
|
||||
EOF
|
||||
chmod +x "$APPDIR/AppRun"
|
||||
|
||||
cat > "$APPDIR/trulymem.desktop" << 'EOF'
|
||||
# Desktop 文件
|
||||
cat > "$APP_DIR/${APP_NAME}.desktop" << EOF
|
||||
[Desktop Entry]
|
||||
Name=TrulyMEM
|
||||
Comment=AI Memory System with Long-term Memory
|
||||
Exec=TrulyMEM %U
|
||||
Icon=trulymem
|
||||
Comment=TrueHumanMEM - AI Memory System
|
||||
Exec=TrulyMEM
|
||||
Icon=${APP_NAME}
|
||||
Terminal=true
|
||||
Type=Application
|
||||
Categories=Utility;X-AI;
|
||||
Categories=Utility;AI;
|
||||
EOF
|
||||
|
||||
# Copy icon
|
||||
if [ -f "$PROJECT_ROOT/pic/TrulyMEM.png" ]; then
|
||||
cp "$PROJECT_ROOT/pic/TrulyMEM.png" "$APPDIR/trulymem.png"
|
||||
elif [ -f "$PROJECT_ROOT/pic/TrulyMEM.iconset/icon_256x256.png" ]; then
|
||||
cp "$PROJECT_ROOT/pic/TrulyMEM.iconset/icon_256x256.png" "$APPDIR/trulymem.png"
|
||||
elif [ -f "$PROJECT_ROOT/pic/TrulyMEM.iconset/icon_128x128.png" ]; then
|
||||
cp "$PROJECT_ROOT/pic/TrulyMEM.iconset/icon_128x128.png" "$APPDIR/trulymem.png"
|
||||
# 图标
|
||||
mkdir -p "$APP_DIR/usr/share/icons/hicolor/256x256/apps"
|
||||
# 如果有图标文件就复制,否则创建占位
|
||||
if [ -f "pic/image.png" ]; then
|
||||
cp "pic/image.png" "$APP_DIR/usr/share/icons/hicolor/256x256/apps/${APP_NAME}.png"
|
||||
cp "pic/image.png" "$APP_DIR/${APP_NAME}.png"
|
||||
else
|
||||
echo "Warning: No icon file found"
|
||||
# 创建最小占位图标(1x1 透明 PNG)
|
||||
echo -n "" > "$APP_DIR/${APP_NAME}.png"
|
||||
fi
|
||||
|
||||
APPIMAGE="$PROJECT_ROOT/TrulyMEM.AppImage"
|
||||
rm -f "$APPIMAGE"
|
||||
# AppRun
|
||||
cat > "$APP_DIR/AppRun" << 'APPRUN'
|
||||
#!/bin/bash
|
||||
HERE="$(dirname "$(readlink -f "${0}")")"
|
||||
export PATH="${HERE}/usr/bin:${PATH}"
|
||||
exec "${HERE}/usr/bin/TrulyMEM" "$@"
|
||||
APPRUN
|
||||
chmod +x "$APP_DIR/AppRun"
|
||||
|
||||
echo "===== Step 3: Package as AppImage ====="
|
||||
cd /tmp
|
||||
if ! command -v appimagetool &> /dev/null; then
|
||||
echo "Downloading appimagetool..."
|
||||
wget -q https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool 2>/dev/null || \
|
||||
curl -sL https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage -o appimagetool
|
||||
chmod +x appimagetool 2>/dev/null || true
|
||||
fi
|
||||
cd "$PROJECT_ROOT"
|
||||
if [ -x /tmp/appimagetool ]; then
|
||||
/tmp/appimagetool "$APPDIR" "$APPIMAGE" || echo "appimagetool failed, keeping AppDir"
|
||||
elif command -v appimagetool &> /dev/null; then
|
||||
appimagetool "$APPDIR" "$APPIMAGE"
|
||||
# ── 构建 AppImage ────────────────────────────────────────────────────────
|
||||
if [ "$SKIP_APPIMAGE" != "1" ]; then
|
||||
echo "================================"
|
||||
echo "Building AppImage"
|
||||
echo "================================"
|
||||
# 支持 ARCH 环境变量
|
||||
ARCH="${ARCH:-$(uname -m)}" "$APPIMAGE_TOOL" "$APP_DIR" "dist/TrulyMEM-${ARCH}.AppImage"
|
||||
echo "AppImage: dist/TrulyMEM-${ARCH}.AppImage"
|
||||
else
|
||||
echo "Warning: appimagetool not available, AppDir at: $APPDIR"
|
||||
echo "(Skipped AppImage packaging, AppDir ready at $APP_DIR)"
|
||||
fi
|
||||
|
||||
echo "================================"
|
||||
echo "===== Build Complete ====="
|
||||
[ -f "$APPIMAGE" ] && echo "AppImage: $APPIMAGE" && ls -la "$APPIMAGE"
|
||||
[ -d "$APPDIR" ] && echo "AppDir: $APPDIR"
|
||||
echo "Binary: dist/TrulyMEM"
|
||||
ls -la dist/
|
||||
|
||||
echo "===== Cleanup ====="
|
||||
deactivate
|
||||
rm -rf "$VENV_DIR"
|
||||
rm -rf "$PROJECT_ROOT/build/pyinstaller_build"
|
||||
rm -f /tmp/appimagetool
|
||||
if [ -f "$APPIMAGE" ]; then
|
||||
rm -rf "$APPDIR"
|
||||
fi
|
||||
echo "Done!"
|
||||
echo "Build finished successfully!"
|
||||
|
||||
@ -22,25 +22,8 @@ pip install -r requirements.txt
|
||||
echo "Cleaning previous builds..."
|
||||
rm -rf build/dist build/__pycache__ 2>/dev/null || true
|
||||
|
||||
# 共用 hidden imports(TUI + Web 都需要的核心库)
|
||||
CORE_HIDDEN=(
|
||||
--hidden-import core
|
||||
--hidden-import core.embedded_db
|
||||
--hidden-import core.graph_client
|
||||
--hidden-import core.tool_executor
|
||||
--hidden-import core.tool_limiter
|
||||
--hidden-import core.tools
|
||||
--hidden-import core.tools.memory_tools
|
||||
--hidden-import core.prompts
|
||||
--hidden-import core.prompts.prompt_manager
|
||||
--hidden-import core.server
|
||||
--hidden-import core.client
|
||||
--hidden-import core.migrate
|
||||
--hidden-import core.activity_recorder
|
||||
)
|
||||
|
||||
echo "================================"
|
||||
echo "1️⃣ Build TUI: TrulyMEM"
|
||||
echo "Building TrulyMEM (TUI + Web embedded)"
|
||||
echo "================================"
|
||||
python -m PyInstaller trulymem_entry.py \
|
||||
--clean --onefile --console --name TrulyMEM \
|
||||
@ -57,7 +40,19 @@ python -m PyInstaller trulymem_entry.py \
|
||||
--hidden-import openai._client \
|
||||
--hidden-import neo4j \
|
||||
--hidden-import sqlite3 \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--hidden-import core \
|
||||
--hidden-import core.embedded_db \
|
||||
--hidden-import core.graph_client \
|
||||
--hidden-import core.tool_executor \
|
||||
--hidden-import core.tool_limiter \
|
||||
--hidden-import core.tools \
|
||||
--hidden-import core.tools.memory_tools \
|
||||
--hidden-import core.prompts \
|
||||
--hidden-import core.prompts.prompt_manager \
|
||||
--hidden-import core.server \
|
||||
--hidden-import core.client \
|
||||
--hidden-import core.migrate \
|
||||
--hidden-import core.activity_recorder \
|
||||
--hidden-import ui \
|
||||
--hidden-import ui.app \
|
||||
--hidden-import ui.login_screen \
|
||||
@ -73,25 +68,13 @@ python -m PyInstaller trulymem_entry.py \
|
||||
--hidden-import web_api \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
--hidden-import werkzeug \
|
||||
--collect-all textual \
|
||||
--noconfirm
|
||||
|
||||
echo "================================"
|
||||
echo "2️⃣ Build Web: trulymem-web"
|
||||
echo "================================"
|
||||
python -m PyInstaller web_api.py \
|
||||
--clean --onefile --console --name trulymem-web \
|
||||
--add-data "templates:templates" \
|
||||
--add-data "static:static" \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--noconfirm
|
||||
|
||||
echo "================================"
|
||||
echo "===== Build Complete ====="
|
||||
echo "Binary: dist/TrulyMEM"
|
||||
echo "Binary: dist/trulymem-web"
|
||||
ls -la dist/
|
||||
|
||||
deactivate
|
||||
|
||||
@ -19,37 +19,14 @@ source "$VENV_DIR/bin/activate"
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 生成图标
|
||||
if [ -d "pic/TrulyMEM.iconset" ]; then
|
||||
iconutil -c icns pic/TrulyMEM.iconset -o pic/TrulyMEM.icns
|
||||
echo "ICNS icon generated: pic/TrulyMEM.icns"
|
||||
fi
|
||||
|
||||
echo "Cleaning previous builds..."
|
||||
rm -rf build/dist build/__pycache__ 2>/dev/null || true
|
||||
|
||||
CORE_HIDDEN=(
|
||||
--hidden-import core
|
||||
--hidden-import core.embedded_db
|
||||
--hidden-import core.graph_client
|
||||
--hidden-import core.tool_executor
|
||||
--hidden-import core.tool_limiter
|
||||
--hidden-import core.tools
|
||||
--hidden-import core.tools.memory_tools
|
||||
--hidden-import core.prompts
|
||||
--hidden-import core.prompts.prompt_manager
|
||||
--hidden-import core.server
|
||||
--hidden-import core.client
|
||||
--hidden-import core.migrate
|
||||
--hidden-import core.activity_recorder
|
||||
)
|
||||
|
||||
echo "================================"
|
||||
echo "1️⃣ Build TUI: TrulyMEM"
|
||||
echo "Building TrulyMEM (TUI + Web embedded)"
|
||||
echo "================================"
|
||||
python -m PyInstaller trulymem_entry.py \
|
||||
--clean --onefile --console --name TrulyMEM \
|
||||
--icon "pic/TrulyMEM.icns" \
|
||||
--add-data "ui/styles:ui/styles" \
|
||||
--add-data "core/prompts/templates:core/prompts/templates" \
|
||||
--add-data "static:static" \
|
||||
@ -63,7 +40,19 @@ python -m PyInstaller trulymem_entry.py \
|
||||
--hidden-import openai._client \
|
||||
--hidden-import neo4j \
|
||||
--hidden-import sqlite3 \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--hidden-import core \
|
||||
--hidden-import core.embedded_db \
|
||||
--hidden-import core.graph_client \
|
||||
--hidden-import core.tool_executor \
|
||||
--hidden-import core.tool_limiter \
|
||||
--hidden-import core.tools \
|
||||
--hidden-import core.tools.memory_tools \
|
||||
--hidden-import core.prompts \
|
||||
--hidden-import core.prompts.prompt_manager \
|
||||
--hidden-import core.server \
|
||||
--hidden-import core.client \
|
||||
--hidden-import core.migrate \
|
||||
--hidden-import core.activity_recorder \
|
||||
--hidden-import ui \
|
||||
--hidden-import ui.app \
|
||||
--hidden-import ui.login_screen \
|
||||
@ -79,25 +68,13 @@ python -m PyInstaller trulymem_entry.py \
|
||||
--hidden-import web_api \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
--hidden-import werkzeug \
|
||||
--collect-all textual \
|
||||
--noconfirm
|
||||
|
||||
echo "================================"
|
||||
echo "2️⃣ Build Web: trulymem-web"
|
||||
echo "================================"
|
||||
python -m PyInstaller web_api.py \
|
||||
--clean --onefile --console --name trulymem-web \
|
||||
--add-data "templates:templates" \
|
||||
--add-data "static:static" \
|
||||
--hidden-import flask \
|
||||
--hidden-import flask_cors \
|
||||
"${CORE_HIDDEN[@]}" \
|
||||
--noconfirm
|
||||
|
||||
echo "================================"
|
||||
echo "===== Build Complete ====="
|
||||
echo "Binary: dist/TrulyMEM"
|
||||
echo "Binary: dist/trulymem-web"
|
||||
ls -la dist/
|
||||
|
||||
deactivate
|
||||
|
||||
@ -1,49 +1,33 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
@echo off
|
||||
setlocal enabledelayedexpansion
|
||||
|
||||
echo "===== Building TrulyMEM for Windows ====="
|
||||
echo ===== Building TrulyMEM for Windows =====
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
cd "$PROJECT_ROOT"
|
||||
echo "Project root: $PROJECT_ROOT"
|
||||
set SCRIPT_DIR=%~dp0
|
||||
set PROJECT_ROOT=%SCRIPT_DIR%..
|
||||
cd /d "%PROJECT_ROOT%"
|
||||
echo Project root: %CD%
|
||||
|
||||
if ! command -v python &> /dev/null; then
|
||||
echo "Error: python not found"
|
||||
exit 1
|
||||
fi
|
||||
where python >nul 2>nul
|
||||
if %ERRORLEVEL% neq 0 (
|
||||
echo Error: python not found
|
||||
exit /b 1
|
||||
)
|
||||
|
||||
VENV_DIR="$PROJECT_ROOT\.venv_build"
|
||||
echo "Creating virtual environment: %VENV_DIR%"
|
||||
set VENV_DIR=%PROJECT_ROOT%\.venv_build
|
||||
echo Creating virtual environment: %VENV_DIR%
|
||||
python -m venv "%VENV_DIR%"
|
||||
call "%VENV_DIR%\Scripts\activate.bat"
|
||||
pip install --upgrade pip
|
||||
pip install -r requirements.txt
|
||||
|
||||
echo "Cleaning previous builds..."
|
||||
rmdir /s /q "build\dist" 2>nul
|
||||
rmdir /s /q "build\__pycache__" 2>nul
|
||||
del /f /q "TrulyMEM.spec" 2>nul
|
||||
echo Cleaning previous builds...
|
||||
if exist build\dist rmdir /s /q build\dist
|
||||
if exist build\__pycache__ rmdir /s /q build\__pycache__
|
||||
|
||||
CORE_HIDDEN=(
|
||||
--hidden-import core
|
||||
--hidden-import core.embedded_db
|
||||
--hidden-import core.graph_client
|
||||
--hidden-import core.tool_executor
|
||||
--hidden-import core.tool_limiter
|
||||
--hidden-import core.tools
|
||||
--hidden-import core.tools.memory_tools
|
||||
--hidden-import core.prompts
|
||||
--hidden-import core.prompts.prompt_manager
|
||||
--hidden-import core.server
|
||||
--hidden-import core.client
|
||||
--hidden-import core.migrate
|
||||
--hidden-import core.activity_recorder
|
||||
)
|
||||
|
||||
echo "================================"
|
||||
echo "1. Build TUI: TrulyMEM.exe"
|
||||
echo "================================"
|
||||
echo ================================
|
||||
echo Building TrulyMEM ^(TUI + Web embedded^)
|
||||
echo ================================
|
||||
python -m PyInstaller trulymem_entry.py ^
|
||||
--clean --onefile --console --name TrulyMEM ^
|
||||
--add-data "ui/styles;ui/styles" ^
|
||||
@ -59,7 +43,19 @@ python -m PyInstaller trulymem_entry.py ^
|
||||
--hidden-import openai._client ^
|
||||
--hidden-import neo4j ^
|
||||
--hidden-import sqlite3 ^
|
||||
%CORE_HIDDEN% ^
|
||||
--hidden-import core ^
|
||||
--hidden-import core.embedded_db ^
|
||||
--hidden-import core.graph_client ^
|
||||
--hidden-import core.tool_executor ^
|
||||
--hidden-import core.tool_limiter ^
|
||||
--hidden-import core.tools ^
|
||||
--hidden-import core.tools.memory_tools ^
|
||||
--hidden-import core.prompts ^
|
||||
--hidden-import core.prompts.prompt_manager ^
|
||||
--hidden-import core.server ^
|
||||
--hidden-import core.client ^
|
||||
--hidden-import core.migrate ^
|
||||
--hidden-import core.activity_recorder ^
|
||||
--hidden-import ui ^
|
||||
--hidden-import ui.app ^
|
||||
--hidden-import ui.login_screen ^
|
||||
@ -75,24 +71,16 @@ python -m PyInstaller trulymem_entry.py ^
|
||||
--hidden-import web_api ^
|
||||
--hidden-import flask ^
|
||||
--hidden-import flask_cors ^
|
||||
--hidden-import werkzeug ^
|
||||
--collect-all textual ^
|
||||
--noconfirm
|
||||
|
||||
echo "================================"
|
||||
echo "2. Build Web: trulymem-web.exe"
|
||||
echo "================================"
|
||||
python -m PyInstaller web_api.py ^
|
||||
--clean --onefile --console --name trulymem-web ^
|
||||
--add-data "templates;templates" ^
|
||||
--add-data "static;static" ^
|
||||
--hidden-import flask ^
|
||||
--hidden-import flask_cors ^
|
||||
%CORE_HIDDEN% ^
|
||||
--noconfirm
|
||||
echo ================================
|
||||
echo ===== Build Complete =====
|
||||
echo Binary: dist\TrulyMEM.exe
|
||||
dir dist\
|
||||
|
||||
echo "===== Build Complete ====="
|
||||
echo "Output: dist/TrulyMEM.exe, dist/trulymem-web.exe"
|
||||
|
||||
deactivate
|
||||
rmdir /s /q "%VENV_DIR%"
|
||||
echo "Build finished successfully!"
|
||||
call deactivate
|
||||
if exist "%VENV_DIR%" rmdir /s /q "%VENV_DIR%"
|
||||
echo Build finished successfully!
|
||||
endlocal
|
||||
|
||||
@ -69,7 +69,7 @@ a = Analysis(
|
||||
'ui.handlers',
|
||||
'ui.services', 'ui.services.config_manager', 'ui.services.config_service',
|
||||
'web_api',
|
||||
'flask', 'flask_cors',
|
||||
'flask', 'flask_cors', 'werkzeug',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
@ -100,46 +100,4 @@ exe = EXE(
|
||||
entitlements_file=None,
|
||||
)
|
||||
|
||||
# ——— Web 服务二进制(trulymem-web)———
|
||||
web_a = Analysis(
|
||||
['web_api.py'],
|
||||
pathex=[project_root],
|
||||
binaries=[],
|
||||
datas=[
|
||||
(os.path.join(project_root, 'templates'), 'templates'),
|
||||
(os.path.join(project_root, 'static'), 'static'),
|
||||
],
|
||||
hiddenimports=[
|
||||
'flask', 'flask_cors',
|
||||
'core', 'core.server', 'core.client',
|
||||
'core.embedded_db', 'core.activity_recorder',
|
||||
'core.migrate',
|
||||
],
|
||||
hookspath=[],
|
||||
hooksconfig={},
|
||||
runtime_hooks=[],
|
||||
excludes=[],
|
||||
noarchive=False,
|
||||
optimize=0,
|
||||
)
|
||||
web_pyz = PYZ(web_a.pure, block_cipher)
|
||||
web_exe = EXE(
|
||||
web_pyz,
|
||||
web_a.scripts,
|
||||
web_a.binaries,
|
||||
web_a.datas,
|
||||
[],
|
||||
name='trulymem-web',
|
||||
debug=False,
|
||||
bootloader_ignore_signals=False,
|
||||
strip=False,
|
||||
upx=True,
|
||||
upx_exclude=[],
|
||||
runtime_tmpdir=None,
|
||||
console=False,
|
||||
disable_windowed_traceback=False,
|
||||
argv_emulation=False,
|
||||
target_arch=None,
|
||||
codesign_identity=None,
|
||||
entitlements_file=None,
|
||||
)
|
||||
|
||||
|
||||
@ -1,123 +1,176 @@
|
||||
# TrulyMEM Quick Start Guide
|
||||
|
||||
## Running Methods
|
||||
> **Version**: Multi-user (v2) — TUI login, user isolation, embedded Web server
|
||||
|
||||
### Run from Source
|
||||
---
|
||||
|
||||
## Running
|
||||
|
||||
### Quick Start
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd TrulyMEM-TrueHumanMEM
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
# From source
|
||||
python trulymem_entry.py
|
||||
|
||||
# Packaged binary
|
||||
./dist/TrulyMEM
|
||||
```
|
||||
|
||||
### Run After Build
|
||||
### First Run — Login Flow
|
||||
|
||||
After building, an executable will be generated:
|
||||
On first launch, TrulyMEM checks for legacy data and presents a **login screen**:
|
||||
|
||||
1. **Clean install** → Enter username/password (first user becomes admin)
|
||||
2. **Legacy upgrade** → Detects `~/.trulymem/config.json`, guides migration setup
|
||||
3. **Returning user** → Login directly
|
||||
|
||||
> 💡 All user data is isolated: `~/.trulymem/{username}/`
|
||||
|
||||
### Chat Configuration
|
||||
|
||||
After login, press **F2** to open the right-side configuration panel:
|
||||
|
||||
1. **API Key** — Required (DeepSeek, OpenAI, etc.)
|
||||
2. **Model** — Optional
|
||||
3. **Base URL** — Optional
|
||||
|
||||
Config saves automatically.
|
||||
|
||||
---
|
||||
|
||||
## Web Visualization
|
||||
|
||||
The Web service now runs **embedded in the main process** (no separate subprocess needed).
|
||||
|
||||
### Start via TUI (Admin only)
|
||||
|
||||
Admin users: press F2 → check "Enable Web Service".
|
||||
|
||||
### Start Manually
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
chmod +x TrulyMEM
|
||||
./TrulyMEM
|
||||
|
||||
# Windows
|
||||
TrulyMEM.exe
|
||||
```
|
||||
|
||||
## System Requirements
|
||||
|
||||
- **Python 3.8+**
|
||||
- **API Key** (DeepSeek, OpenAI, or other compatible APIs)
|
||||
|
||||
## First-Time Configuration
|
||||
|
||||
1. Run the application
|
||||
2. Press **F2** to expand sidebar
|
||||
3. Enter **API Key**, **Model**, **Base URL**
|
||||
4. Press **Enter** to save
|
||||
|
||||
Config will be automatically saved to `~/.trulymem/config.json` and loaded on next startup.
|
||||
|
||||
### Web Visualization (Optional)
|
||||
|
||||
TrulyMEM provides a Web star-map visualization interface for browsing the knowledge graph in real-time:
|
||||
|
||||
```bash
|
||||
# Start Web service
|
||||
python web_api.py --port 4096
|
||||
# Visit http://localhost:4096
|
||||
```
|
||||
|
||||
Then open `http://localhost:4096` in your browser.
|
||||
### First Visit Flow
|
||||
|
||||
**Login Setup:**
|
||||
1. Copy `web_config.example.json` to `web_config.json`
|
||||
2. Set login password (using SHA256) and secret key
|
||||
3. Web service will automatically read the config
|
||||
1. Open `http://localhost:4096` in browser
|
||||
2. **No users** → Auto-redirect to setup page, create admin account
|
||||
3. **Has users** → Login page
|
||||
4. After login → Star map visualization
|
||||
|
||||
Default port is 4096, change with `--port` flag.
|
||||
### Web Features
|
||||
|
||||
| Page | Access | Feature |
|
||||
|------|--------|---------|
|
||||
| 🌟 Star Map | All logged-in | Browse knowledge graph |
|
||||
| ⚙ Settings | All logged-in | Change password |
|
||||
| 🧑💼 User Management | **Admin only** | Add/delete users |
|
||||
|
||||
---
|
||||
|
||||
## Multi-User System
|
||||
|
||||
### Directory Layout
|
||||
|
||||
```
|
||||
~/.trulymem/
|
||||
├── trulymem.db # Global user database (web_users table)
|
||||
├── .migrated # Migration flag
|
||||
├── admin/
|
||||
│ ├── config.json # Admin config
|
||||
│ └── admin_graph.db # Admin knowledge graph
|
||||
└── user2/
|
||||
├── config.json # user2 config
|
||||
└── user2_graph.db # user2 knowledge graph
|
||||
```
|
||||
|
||||
### Role Matrix
|
||||
|
||||
| Feature | User | Admin |
|
||||
|---------|------|-------|
|
||||
| Change password | ✅ | ✅ |
|
||||
| Configure API Key / Model | ✅ | ✅ |
|
||||
| Web service toggle (TUI) | ❌ | ✅ |
|
||||
| Web login credentials | ❌ | ✅ |
|
||||
| View user list | ❌ | ✅ |
|
||||
| Add/delete users | ❌ | ✅ |
|
||||
|
||||
> ⚠️ First registered user becomes admin automatically. Add users via Web settings page.
|
||||
|
||||
---
|
||||
|
||||
## Keyboard Shortcuts
|
||||
|
||||
| Key | Function |
|
||||
|-----|-----------|
|
||||
| Key | Action |
|
||||
|-----|--------|
|
||||
| F1 | Help |
|
||||
| F2 | Toggle sidebar |
|
||||
| F2 | Toggle sidebar (config panel) |
|
||||
| F3 | Tool details |
|
||||
| F5 | Clear screen |
|
||||
| F6 | Exit |
|
||||
| F6 | Quit |
|
||||
|
||||
## Data Storage
|
||||
---
|
||||
|
||||
### Source Mode
|
||||
## Building
|
||||
|
||||
| Data | Location |
|
||||
|------|----------|
|
||||
| Graph database | Project directory `graph_memory.db` |
|
||||
| Config file | Project directory `config.json` (if exists) |
|
||||
| Database format | SQLite |
|
||||
```bash
|
||||
# Linux
|
||||
bash build/build_linux.sh
|
||||
|
||||
### Packaged Mode
|
||||
# macOS
|
||||
bash build/build_macos.sh
|
||||
|
||||
| Data | Location |
|
||||
|------|----------|
|
||||
| Graph database | `~/.trulymem/graph_memory.db` |
|
||||
| Config file | `~/.trulymem/config.json` |
|
||||
| Database format | SQLite |
|
||||
# Windows
|
||||
build\build_windows.bat
|
||||
|
||||
> **Note**: Backend manages config uniformly. Frontend only displays messages; config modifications are persisted to filesystem through the backend.
|
||||
# AppImage
|
||||
bash build/build_appimage.sh
|
||||
```
|
||||
|
||||
## Architecture Explanation
|
||||
Output: `dist/TrulyMEM` (single binary — TUI and Web server embedded)
|
||||
|
||||
### Communication Protocol
|
||||
> 📦 Since v2, the Web server runs as a thread inside the main process. No need for a separate `trulymem-web` binary.
|
||||
|
||||
UI and backend communicate via **Packet Protocol**:
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Communication
|
||||
|
||||
```
|
||||
UI (Textual TUI)
|
||||
↓ BackendClient
|
||||
Packet → queue.Queue → BackendServer (independent thread)
|
||||
↓
|
||||
Process request → Return response
|
||||
TUI (Textual) ←→ BackendClient ←→ queue.Queue ←→ BackendServer (thread)
|
||||
```
|
||||
|
||||
### Config Management
|
||||
|
||||
- **Storage location**: `~/.trulymem/config.json`
|
||||
- **Auto-load**: Load config from file at startup
|
||||
- **Dynamic update**: Config changes take effect immediately at runtime
|
||||
- **Persistence**: Auto-save to file after modification
|
||||
- **Per-user**: `~/.trulymem/{username}/config.json`
|
||||
- **Web config**: `~/.trulymem/trulymem.db` (web_users table)
|
||||
- **Auto-load**: reads config for logged-in user on startup
|
||||
- **Persistent**: saves automatically on change
|
||||
|
||||
## Common Issues
|
||||
### Web Service Architecture
|
||||
|
||||
### Python Not Found
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ TrulyMEM Process │
|
||||
│ ┌──────┐ ┌────────┐ │
|
||||
│ │ TUI │ │ Flask │ │ ← Same process, different threads
|
||||
│ │ │ │ Thread │ │
|
||||
│ └──────┘ └────────┘ │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## FAQ
|
||||
|
||||
### Python not found
|
||||
|
||||
Install Python 3.8+: https://www.python.org/downloads/
|
||||
|
||||
### Dependency Installation Failed
|
||||
### Dependency installation fails
|
||||
|
||||
```bash
|
||||
python -m venv venv
|
||||
@ -128,18 +181,22 @@ pip install -r requirements.txt
|
||||
|
||||
### Invalid API Key
|
||||
|
||||
Check API Key format, ensure no extra spaces.
|
||||
Check format and whitespace. Reconfigure in TUI sidebar.
|
||||
|
||||
## Development Commands
|
||||
### Lost admin account
|
||||
|
||||
The first registered user is always admin. If all users lost admin, delete `trulymem.db` from the user directory and re-register.
|
||||
|
||||
### Legacy data migration
|
||||
|
||||
When old `~/.trulymem/config.json` and `graph_memory.db` are detected, TUI auto-enters migration flow. Legacy files are preserved.
|
||||
|
||||
---
|
||||
|
||||
## Dev Commands
|
||||
|
||||
```bash
|
||||
# Install dependencies
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Run tests
|
||||
pytest tests/
|
||||
|
||||
# Build
|
||||
bash build/build_windows.bat # Windows
|
||||
bash build/build_linux.sh # Linux
|
||||
```
|
||||
bash build/build_linux.sh
|
||||
```
|
||||
|
||||
@ -1,62 +1,103 @@
|
||||
# TrulyMEM 启动指南
|
||||
|
||||
> **版本**: 多用户版 (v2) — 支持 TUI 登录、多用户隔离、Web 服务内嵌
|
||||
|
||||
---
|
||||
|
||||
## 运行方式
|
||||
|
||||
### 从源码运行
|
||||
### 快速启动(推荐)
|
||||
|
||||
```bash
|
||||
git clone <repo-url>
|
||||
cd TrulyMEM-TrueHumanMEM
|
||||
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 从源码
|
||||
python trulymem_entry.py
|
||||
|
||||
# 或打包后
|
||||
./dist/TrulyMEM
|
||||
```
|
||||
|
||||
### 打包后运行
|
||||
### 首次使用 —— 登录流程
|
||||
|
||||
打包后会生成可执行文件:
|
||||
首次启动会自动检查是否需要迁移旧数据,然后进入**登录页面**:
|
||||
|
||||
1. **新部署** → 直接输入用户名和密码创建账户(首个用户自动成为管理员)
|
||||
2. **旧版升级** → 自动检测 `~/.trulymem/config.json`,引导设置用户名密码,迁移数据
|
||||
3. **已有账户** → 直接登录进入聊天界面
|
||||
|
||||
> 💡 所有用户数据隔离存储:`~/.trulymem/{用户名}/`
|
||||
|
||||
### 聊天配置
|
||||
|
||||
登录后按 **F2** 展开右侧配置面板:
|
||||
|
||||
1. **API Key** — 必须(支持 DeepSeek、OpenAI 等)
|
||||
2. **模型** — 可选,默认已配置
|
||||
3. **Base URL** — 可选
|
||||
|
||||
配置自动保存,下次启动自动加载。
|
||||
|
||||
---
|
||||
|
||||
## Web 可视化界面
|
||||
|
||||
TrulyMEM 的 Web 服务现在**内嵌在主进程中**(无需独立启动子进程)。
|
||||
|
||||
### TUI 内启动(管理员专有)
|
||||
|
||||
管理员按 F2 打开右侧面板,勾选「启用 Web 服务」即可。
|
||||
|
||||
### 手动启动
|
||||
|
||||
```bash
|
||||
# Linux/macOS
|
||||
chmod +x TrulyMEM
|
||||
./TrulyMEM
|
||||
|
||||
# Windows
|
||||
TrulyMEM.exe
|
||||
```
|
||||
|
||||
## 系统要求
|
||||
|
||||
- **Python 3.8+**
|
||||
- **API Key**(DeepSeek、OpenAI 或其他兼容 API)
|
||||
|
||||
## 首次配置
|
||||
|
||||
1. 运行应用
|
||||
2. 按 **F2** 展开侧边栏
|
||||
3. 输入 **API Key**、**模型**、**Base URL**
|
||||
4. 按 **Enter** 保存
|
||||
|
||||
配置会自动保存到 `~/.trulymem/config.json`,下次启动自动加载。
|
||||
|
||||
### Web 可视化界面(可选)
|
||||
|
||||
TrulyMEM 提供 Web 星图可视化界面,支持实时浏览知识图谱:
|
||||
|
||||
```bash
|
||||
# 启动 Web 服务
|
||||
python web_api.py --port 4096
|
||||
# 访问 http://localhost:4096
|
||||
```
|
||||
|
||||
然后打开浏览器访问 `http://localhost:4096`。
|
||||
### 首次访问流程
|
||||
|
||||
**登录配置:**
|
||||
1. 复制 `web_config.example.json` 为 `web_config.json`
|
||||
2. 设置登录密码(使用 SHA256)和 secret key
|
||||
3. Web 服务会自动读取该配置
|
||||
1. 浏览器打开 `http://localhost:4096`
|
||||
2. **无用户** → 自动跳转至设置页,创建管理员账号
|
||||
3. **有用户** → 跳转至登录页
|
||||
4. 登录后进入星图可视化页面
|
||||
|
||||
默认端口 4096,可通过 `--port` 参数修改。
|
||||
### Web 功能
|
||||
|
||||
| 页面 | 访问权限 | 功能 |
|
||||
|------|----------|------|
|
||||
| 🌟 星图 | 所有已登录用户 | 浏览知识图谱三元组 |
|
||||
| ⚙ 设置 | 所有已登录用户 | 修改密码 |
|
||||
| 🧑💼 用户管理 | **仅管理员** | 添加/删除用户 |
|
||||
|
||||
---
|
||||
|
||||
## 多用户系统
|
||||
|
||||
### 目录结构
|
||||
|
||||
```
|
||||
~/.trulymem/
|
||||
├── trulymem.db # 全局用户数据库(web_users 表)
|
||||
├── .migrated # 旧版迁移标记
|
||||
├── admin/
|
||||
│ ├── config.json # 管理员配置
|
||||
│ └── admin_graph.db # 管理员知识图谱
|
||||
└── user2/
|
||||
├── config.json # user2 配置
|
||||
└── user2_graph.db # user2 知识图谱
|
||||
```
|
||||
|
||||
### 角色体系
|
||||
|
||||
| 功能 | 普通用户 | 管理员 |
|
||||
|------|---------|--------|
|
||||
| 修改自己密码 | ✅ | ✅ |
|
||||
| 配置 API Key / 模型 | ✅ | ✅ |
|
||||
| Web 服务开关(TUI) | ❌ | ✅ |
|
||||
| Web 登录凭据 | ❌ | ✅ |
|
||||
| 查看用户列表 | ❌ | ✅ |
|
||||
| 添加/删除用户 | ❌ | ✅ |
|
||||
|
||||
> ⚠️ 首个注册用户自动成为管理员。Web 设置页可添加新用户。
|
||||
|
||||
---
|
||||
|
||||
@ -65,30 +106,34 @@ python web_api.py --port 4096
|
||||
| 按键 | 功能 |
|
||||
|------|------|
|
||||
| F1 | 帮助 |
|
||||
| F2 | 切换侧边栏 |
|
||||
| F2 | 切换侧边栏(配置面板) |
|
||||
| F3 | 工具详情 |
|
||||
| F5 | 清屏 |
|
||||
| F6 | 退出 |
|
||||
|
||||
## 数据存储
|
||||
---
|
||||
|
||||
### 源码运行模式
|
||||
## 打包构建
|
||||
|
||||
| 数据 | 位置 |
|
||||
|------|------|
|
||||
| 图数据库 | 项目目录 `graph_memory.db` |
|
||||
| 配置文件 | 项目目录 `config.json`(如存在) |
|
||||
| 数据库格式 | SQLite |
|
||||
```bash
|
||||
# Linux
|
||||
bash build/build_linux.sh
|
||||
|
||||
### 打包运行模式
|
||||
# macOS
|
||||
bash build/build_macos.sh
|
||||
|
||||
| 数据 | 位置 |
|
||||
|------|------|
|
||||
| 图数据库 | `~/.trulymem/graph_memory.db` |
|
||||
| 配置文件 | `~/.trulymem/config.json` |
|
||||
| 数据库格式 | SQLite |
|
||||
# Windows
|
||||
build\build_windows.bat
|
||||
|
||||
> **说明**:后端统一管理配置。前端仅负责消息展示,配置修改通过后端持久化到文件系统。
|
||||
# AppImage
|
||||
bash build/build_appimage.sh
|
||||
```
|
||||
|
||||
构建产出:`dist/TrulyMEM`(单文件,TUI + Web 服务均内嵌于同一二进制)
|
||||
|
||||
> 📦 从 v2 开始,Web 服务作为线程嵌入主程序,不再需要独立打包 `trulymem-web`。
|
||||
|
||||
---
|
||||
|
||||
## 架构说明
|
||||
|
||||
@ -97,19 +142,29 @@ python web_api.py --port 4096
|
||||
UI 与后端通过 **Packet 协议** 通信:
|
||||
|
||||
```
|
||||
UI (Textual TUI)
|
||||
↓ BackendClient
|
||||
Packet → queue.Queue → BackendServer (独立线程)
|
||||
↓
|
||||
处理请求 → 返回响应
|
||||
TUI (Textual) ←→ BackendClient ←→ queue.Queue ←→ BackendServer (独立线程)
|
||||
```
|
||||
|
||||
### 配置管理
|
||||
|
||||
- **存储位置**: `~/.trulymem/config.json`
|
||||
- **自动加载**: 启动时从文件读取配置
|
||||
- **动态更新**: 运行时修改配置立即生效
|
||||
- **持久化**: 修改后自动保存到文件
|
||||
- **用户级存储**: `~/.trulymem/{username}/config.json`
|
||||
- **Web 配置**: `~/.trulymem/trulymem.db`(web_users 表)
|
||||
- **自动加载**: 启动时根据登录用户加载对应配置文件
|
||||
- **动态更新**: 运行时修改配置立即生效,自动持久化
|
||||
|
||||
### Web 服务架构
|
||||
|
||||
```
|
||||
┌──────────────────────┐
|
||||
│ TrulyMEM 主进程 │
|
||||
│ ┌──────┐ ┌────────┐ │
|
||||
│ │ TUI │ │ Flask │ │ ← 同一进程,不同线程
|
||||
│ │ │ │ Thread │ │
|
||||
│ └──────┘ └────────┘ │
|
||||
└──────────────────────┘
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 常见问题
|
||||
|
||||
@ -128,18 +183,22 @@ pip install -r requirements.txt
|
||||
|
||||
### API Key 无效
|
||||
|
||||
检查 API Key 格式,确保无多余空格。
|
||||
检查 API Key 格式,确保无多余空格。可在 TUI 右侧面板重新配置。
|
||||
|
||||
### 管理员账号丢失
|
||||
|
||||
数据库中第一个注册账号总是 admin。如果所有用户都丢失了 admin 权限,删除用户目录下的 `trulymem.db` 后重新注册即可。
|
||||
|
||||
### 旧版数据迁移
|
||||
|
||||
检测到旧版 `~/.trulymem/config.json` 和 `graph_memory.db` 时,TUI 启动时自动进入迁移引导。迁移后旧文件保留,不会删除。
|
||||
|
||||
---
|
||||
|
||||
## 开发命令
|
||||
|
||||
```bash
|
||||
# 安装依赖
|
||||
pip install -r requirements.txt
|
||||
|
||||
# 运行测试
|
||||
pytest tests/
|
||||
|
||||
# 打包
|
||||
bash build/build_windows.bat # Windows
|
||||
bash build/build_linux.sh # Linux
|
||||
```
|
||||
bash build/build_linux.sh
|
||||
```
|
||||
|
||||
59
ui/app.py
59
ui/app.py
@ -1,6 +1,6 @@
|
||||
import asyncio
|
||||
import sys
|
||||
import subprocess
|
||||
import threading
|
||||
import signal
|
||||
from pathlib import Path
|
||||
from textual.app import App, ComposeResult
|
||||
@ -31,7 +31,6 @@ class GraphMemoryApp(App):
|
||||
self._backend_server = backend_server
|
||||
self._backend_client = BackendClient(backend_server) if backend_server else None
|
||||
self._api_configured = False
|
||||
self._web_process: subprocess.Popen | None = None
|
||||
self._web_running = False
|
||||
self.login_user = None # 当前登录用户
|
||||
self.login_user_info = None # 当前登录用户信息
|
||||
@ -138,46 +137,14 @@ class GraphMemoryApp(App):
|
||||
history.add_message(welcome)
|
||||
|
||||
def _start_web_server(self, port: int = 4096) -> None:
|
||||
"""启动 Web 服务器子进程(支持打包和开发模式)"""
|
||||
if self._web_process and self._web_process.poll() is None:
|
||||
"""在当前进程通过线程启动 Web 服务(无需子进程)"""
|
||||
if self._web_running:
|
||||
self.notify("Web 服务已在运行", title="提示")
|
||||
return
|
||||
|
||||
def _find_web_binary() -> str:
|
||||
"""查找 Web 二进制或脚本路径"""
|
||||
# 1. PyInstaller 打包环境下查找同目录的 trulymem-web 二进制
|
||||
if getattr(sys, 'frozen', False):
|
||||
base = Path(sys._MEIPASS).parent
|
||||
for name in ['trulymem-web', 'trulymem-web.exe']:
|
||||
candidate = base / name
|
||||
if candidate.exists():
|
||||
return str(candidate)
|
||||
# 2. 开发模式:同目录下的 web_api.py
|
||||
web_script = Path(__file__).parent.parent / "web_api.py"
|
||||
if web_script.exists():
|
||||
return str(web_script)
|
||||
# 3. 打包环境回退:从 MEIPASS 读取 web_api.py 数据文件
|
||||
if getattr(sys, 'frozen', False):
|
||||
bundled = Path(sys._MEIPASS) / "web_api.py"
|
||||
if bundled.exists():
|
||||
return str(bundled)
|
||||
return ""
|
||||
|
||||
target = _find_web_binary()
|
||||
if not target:
|
||||
self.notify("找不到 Web 服务文件(web_api.py)", severity="error")
|
||||
return
|
||||
|
||||
try:
|
||||
if target.endswith('.py'):
|
||||
cmd = [sys.executable, target, "--port", str(port)]
|
||||
else:
|
||||
cmd = [target, "--port", str(port)]
|
||||
self._web_process = subprocess.Popen(
|
||||
cmd,
|
||||
stdout=subprocess.DEVNULL,
|
||||
stderr=subprocess.DEVNULL
|
||||
)
|
||||
from web_api import run_web_server
|
||||
run_web_server(port=port)
|
||||
self._web_running = True
|
||||
if self._backend_client:
|
||||
self._backend_client.report_web_status(True, port)
|
||||
@ -186,17 +153,13 @@ class GraphMemoryApp(App):
|
||||
self.notify(f"启动 Web 服务失败: {e}", severity="error")
|
||||
|
||||
def _stop_web_server(self) -> None:
|
||||
"""停止 Web 服务器子进程"""
|
||||
if self._web_process:
|
||||
"""停止 Web 服务线程"""
|
||||
if self._web_running:
|
||||
try:
|
||||
self._web_process.terminate()
|
||||
self._web_process.wait(timeout=5)
|
||||
except:
|
||||
try:
|
||||
self._web_process.kill()
|
||||
except:
|
||||
pass
|
||||
self._web_process = None
|
||||
from web_api import stop_web_server
|
||||
stop_web_server()
|
||||
except Exception:
|
||||
pass
|
||||
self._web_running = False
|
||||
if self._backend_client:
|
||||
self._backend_client.report_web_status(False, 0)
|
||||
|
||||
42
web_api.py
42
web_api.py
@ -731,6 +731,48 @@ def get_graph_highlight():
|
||||
})
|
||||
|
||||
|
||||
# ── 可被 TUI 作为线程启动 ──────────────────────────────────────────────────
|
||||
|
||||
_web_thread: threading.Thread | None = None
|
||||
_http_server = None # werkzeug.serving.BaseWSGIServer 引用,用于优雅停止
|
||||
|
||||
|
||||
def run_web_server(port: int = 4096, host: str = '0.0.0.0') -> None:
|
||||
"""在后台线程启动 Flask,供 TUI 在进程中直接调用"""
|
||||
global _web_thread, _http_server
|
||||
|
||||
if _http_server is not None:
|
||||
return # 已在运行
|
||||
|
||||
def _start():
|
||||
global _http_server
|
||||
try:
|
||||
from werkzeug.serving import make_server
|
||||
_http_server = make_server(host, port, app, threaded=True)
|
||||
print(f"Web API 服务启动在 http://{host}:{port}")
|
||||
_http_server.serve_forever()
|
||||
except Exception as e:
|
||||
print(f"Web 服务启动失败: {e}")
|
||||
_http_server = None
|
||||
finally:
|
||||
_http_server = None
|
||||
|
||||
_web_thread = threading.Thread(target=_start, daemon=True)
|
||||
_web_thread.start()
|
||||
|
||||
|
||||
def stop_web_server() -> None:
|
||||
"""停止 Web 服务线程"""
|
||||
global _http_server, _web_thread
|
||||
if _http_server:
|
||||
try:
|
||||
_http_server.shutdown()
|
||||
except Exception:
|
||||
pass
|
||||
_http_server = None
|
||||
_web_thread = None
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
parser = argparse.ArgumentParser(description='TrulyMEM Web API 服务')
|
||||
parser.add_argument('--port', type=int, default=5000, help='服务端口 (默认: 5000)')
|
||||
|
||||
Reference in New Issue
Block a user