Metadata-Version: 2.4
Name: atlisp-dwg-kb
Version: 0.1.7
Summary: Ontology-based CAD DWG knowledge graph system
License: MIT
Project-URL: Homepage, https://github.com/atlisp/dwg-knowledge-base
Project-URL: Repository, https://github.com/atlisp/dwg-knowledge-base
Keywords: cad,dwg,knowledge-graph,ontology,rdf,bim
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Intended Audience :: Science/Research
Classifier: License :: OSI Approved :: MIT License
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Information Analysis
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: rdflib>=7.0
Requires-Dist: networkx>=3.0
Requires-Dist: scipy>=1.10
Requires-Dist: fastapi>=0.100
Requires-Dist: uvicorn>=0.20
Requires-Dist: pydantic>=2.0
Provides-Extra: dwg
Requires-Dist: ezdxf>=1.0; extra == "dwg"
Provides-Extra: ui
Requires-Dist: gradio>=4.0; extra == "ui"
Provides-Extra: neo4j
Requires-Dist: neo4j>=5.0; extra == "neo4j"
Provides-Extra: watch
Requires-Dist: psutil>=5.9; extra == "watch"
Provides-Extra: service
Requires-Dist: pywin32>=306; sys_platform == "win32" and extra == "service"
Provides-Extra: tray
Requires-Dist: pystray>=0.19; extra == "tray"
Requires-Dist: Pillow>=9.0; extra == "tray"
Provides-Extra: all
Requires-Dist: ezdxf>=1.0; extra == "all"
Requires-Dist: neo4j>=5.0; extra == "all"
Requires-Dist: psutil>=5.9; extra == "all"
Requires-Dist: pywin32>=306; sys_platform == "win32" and extra == "all"
Requires-Dist: pystray>=0.19; extra == "all"
Requires-Dist: Pillow>=9.0; extra == "all"
Provides-Extra: dev
Requires-Dist: pytest>=7.0; extra == "dev"
Requires-Dist: ruff>=0.1; extra == "dev"
Dynamic: license-file

# atlisp-dwg-kb

基于本体(Ontology)的 CAD 图纸知识库管理系统。将历史 DWG 图纸转化为可检索、可追溯的知识图谱。

## 功能

- **DWG 元数据提取**: 从 DWG 文件提取图层、块、文字标注等元数据（支持多进程并行、断点续传）
- **OWL 本体**: 形式化知识表示 (15类 + 20属性)
- **RDF 三元组存储**: rdflib 图存储，规模随图纸量增长
- **自动推断**: 设计演进链、跨专业关联、共享构件
- **SPARQL 查询**: 支持自然语言关键词和 SPARQL 查询
- **REST API**: FastAPI 服务端 (15+ 端点)
- **Web 管理界面**: FastAPI 内置浏览器界面 (`/ui`)，零额外依赖
- **系统托盘**: Windows 托盘管理器 (服务控制/统计/查询/日志)
- **Neo4j 导出**: 可选导出到 Neo4j 图数据库

## 对设计人员的价值

十年积累的图纸散落在几百个项目目录里，找一张图要翻目录、记文件名、问老同事。本系统把这些 DWG 变成**可提问的档案库**：

### 1. 秒级找图，告别翻目录

```
"列出所有暖通图纸"
"2023 年港达项目有哪些结构图"
"所有节点详图"
```

按专业（建筑/结构/暖通/电气/给排水）、项目、年份、图纸类型直接筛选，不再依赖个人记忆和目录命名习惯。

### 2. 版本与审图轮次自动追溯

系统自动识别 `_t3`、`(1)`、日期等版本标记，以及"意见/审图/二次意见/答复"等审图轮次关键词，还原每张图的**设计演进链**：

- 这个节点大样改过几版？每版属于哪一轮审查？
- 初版和最终版之间图纸经历了什么过程？

### 3. 跨专业关联一目了然

自动发现图纸间的坐标/引用关系和共享构件——做专业协调时，快速定位"这张建筑图对应哪些结构图、机电图"，减少扯皮和漏配。

### 4. 标准件与详图复用

识别跨项目重复使用的图块（标准节点、设备图例、大样），新项目直接参考过往做法，**不再重复画详图**。

### 5. 团队经验沉淀

历史方案（绿建、人防、消防等专题图纸）从"存在某人电脑里"变成全团队可检索的素材库，人员流动不再带走经验。

> 定位：它是**图纸档案的检索与追溯工具**，不替代 CAD——设计、绘图仍在 CAD 中完成，本系统解决"找、查、追、复用"的问题。

## 安装

```bash
# 本地开发（全部依赖）
pip install -e ".[all]"

# 按需选择 extras
#   [dwg]     ezdxf (DWG 提取)
#   [neo4j]   neo4j (图数据库导出)
#   [watch]   psutil (CPU 空闲自动构建)
#   [service] pywin32 (Windows 服务)
#   [tray]    pystray + Pillow (Windows 系统托盘)
#   [ui]      gradio (旧版 Web 界面，已弃用)
#   [all]     以上全部（不含已弃用的 gradio）
```

安装后提供 `atlisp-dwg-kb` 命令；未安装时也可从仓库根直接运行：

```bash
PYTHONPATH=src python -m atlisp_dwg_kb.cli <command>
```

系统依赖：DWG 提取（`atlisp-dwg-kb extract`）需要 `[dwg]` extra（ezdxf），且需要 **dwg2dxf**（libredwg）——Windows 下 PyPI 包已内置（`atlisp_dwg_kb/bin/`），其他平台需安装到系统 PATH：

```bash
# Ubuntu/Debian
sudo apt install libredwg-tools
# Windows：PyPI 包自带 dwg2dxf.exe 及依赖 DLL，无需额外安装
```

## 数据处理流程

```
raw/ (DWG 源) ──atlisp-dwg-kb extract──▶ dwg-extract/ (JSON+MD)
                                               │
                              atlisp-dwg-kb build
                                               │
                                    ~/.dwg-kb/ (RDF + 图谱)
                                               │
                     query / stats / API(:8260) / UI(:8260/ui) / export-neo4j
```

## 使用

### 1. 提取 DWG 元数据

```bash
# 试跑 50 个文件
atlisp-dwg-kb extract raw --limit 50

# 全量提取（默认 8 进程并行，--workers/-w 可调）
atlisp-dwg-kb extract raw -w 8

# 断点续传（跳过 dwg-extract/.processed.json 中已处理的文件）
atlisp-dwg-kb extract raw --resume

# 只处理某年份子目录 / 指定输出目录
atlisp-dwg-kb extract raw --project 2025
atlisp-dwg-kb extract raw -o /data/dwg-extract
```

- 源目录需按年份组织（2016–2025），项目名取自年份目录的下一层
- 输出为每张图一个 `<stem>.json` + `<stem>.md`，保留源目录结构
- 另有 `extraction.log` 与 `summary.json` 记录运行日志和统计

#### 元数据内容

每张 DWG 经 `dwg2dxf` → DXF → `ezdxf` 提取，JSON 主要字段：

| 字段 | 内容 |
|------|------|
| `source_file` | 源 DWG 路径 |
| `layers` | 图层：名称、颜色、线型、开关/冻结/锁定、描述 |
| `blocks` | 块定义（排除 `*` 内部块）：名称 + 属性 tag/text |
| `texts` / `text_items` | 模型空间 + 块定义内 TEXT/MTEXT 全文（单条上限 10 万字符；`text_items` 带图层+坐标，最多 10 万条，供定位分析） |
| `text_paragraphs` | 按阅读顺序（上→下、左→右）聚类的文字段落，便于还原**工程说明**等密集多行文本 |
| `layer_text_stats` | 各图层文字数量分布 |
| `block_attribs` | 块属性实例（block/tag/value） |
| `title_block` | 图签/标题栏：图号、图名、工程名称、建设单位、比例、日期、阶段、工号、版次、设计/制图/校对/审核等 |
| `xrefs` | 外部参照 XREF（名称+路径），用于图纸间真实关联 |
| `extents` | 模型空间图形范围（`$EXTMIN/$EXTMAX`，回退 bbox） |
| `hatches` | 填充数量 + 图案 top20 |
| `media` | 光栅图像、OLE 对象计数 |
| `entity_stats` | 实体类型统计（LINE/INSERT/…） |
| `layouts` / `layout_texts` | 布局名 + 图纸空间文字全文（图签常在布局中） |
| `*_count` | 层/块/文字计数 |

文本尽量完整：内容理解暂不依赖几何曲线，工程说明等密集文字不做条数/短截断（仅防病态超长的安全上限）；Markdown 同步输出全部段落与 `text_items` 定位。

下游用途：专业识别（图层名+文字关键词）、本体 RDF 填充、版本/审图轮次（文件名关键词 + `title_block.revision`）、跨专业关联（`xrefs` + 共享图层/块）。

### 2. 构建知识库

```bash
atlisp-dwg-kb build --extract-dir raw/dwg-extract
```

产物（默认写入 `~/.dwg-kb/`）：
- `rdf/knowledge.trig` — RDF 三元组
- `graph/knowledge.json` — NetworkX 图谱 + 社区检测
- `graph/graph.html` — 自包含交互式图谱（Sigma.js/WebGL，可直接浏览器打开；构建期算好节点坐标，图结构未变时复用 `graph/layout.json` 缓存，打开即渲染）

### 3. 查询

```bash
atlisp-dwg-kb query "列出所有暖通图纸"
atlisp-dwg-kb stats
```

### 4. 启动服务

```bash
atlisp-dwg-kb serve          # API: http://localhost:8260  (自动打开管理界面 /ui)
atlisp-dwg-kb serve --no-browser   # 仅启动服务，不打开浏览器
atlisp-dwg-kb all            # 同 serve（启动 API + 内置浏览器界面）
atlisp-dwg-kb ui             # 旧版 Gradio 界面 http://localhost:7860 (已弃用)
atlisp-dwg-kb export-neo4j   # 导出 Neo4j Cypher 到 ~/.dwg-kb/graph/
```

浏览器打开 `http://localhost:8260/ui` 即为管理界面，包含 7 个标签页：

| 标签页 | 功能 | 对应 API |
|--------|------|----------|
| 统计概览 | 三元组/图纸/专业/图层统计 | `GET /stats` |
| 智能查询 | 自然语言或 SPARQL 查询 | `POST /query` |
| 图纸浏览 | 按专业筛选图纸 | `GET /drawings` |
| 设计演进 | 追踪图纸版本演进链 | `GET /drawings/{id}/evolution`、`GET /evolution/chains` |
| 跨专业关联 | 关联查询、协调矩阵、共享图层 | `GET /cross_ref/*` |
| 图谱可视化 | 内嵌 Sigma.js/WebGL 交互图谱 | `GET /graph/html`（带 ETag，未变更时 304） |
| 构建知识库 | 选择目录与提取方式，无元数据则先提取再构建 | `POST /build`、`GET /fs/list` |

- 管理界面为原生 HTML/CSS/JS，由 FastAPI 直接提供，**无需 gradio 等额外依赖**。
- 「构建知识库」标签页通过「选择目录…」弹出服务端目录浏览器（`GET /fs/list`）选择目录，再选择提取方式后点击「开始构建」，调用 `POST /build?path=<dir>&mode=<mode>`：
  - `auto`（默认）— 目录含元数据（`*.json`）或其 `dwg-extract/` 含元数据 → 直接构建；只含 `*.dwg` → 先提取（`--resume`）再构建；
  - `resume` — 强制提取，跳过 `.processed.json` 中已处理的文件（**补齐缺失/不完整的结果**）；
  - `full` — 强制重新提取所有 DWG（忽略 `.processed.json`，耗时较长）；
  - `build` — 只构建，不提取。
  - 目录既无元数据也无 `*.dwg` → 返回 400 并提示。
- 构建为**后台任务**：`POST /build` 立即返回，页面通过 `GET /build/status` 每秒轮询，实时显示阶段（提取中/构建中/完成/失败）、提取进度条（`[已完成/总数]`）与日志；刷新页面后会自动恢复显示正在进行的任务。
- `POST /build` 仍接受旧参数 `?extract_dir=<path>`；`path` 留空则依次尝试 `DWG_EXTRACT_DIR`、`./dwg-extract`、`~/.dwg-kb/dwg-extract`。
- 交互式 API 文档：`http://localhost:8260/docs`。

### 5. 管理多个 DWG 目录

**合并为一个知识库**：各目录分别提取到不同输出目录，构建时指向它们的共同父目录。`build` 会递归加载所有 `*.json`，同名图纸按源文件绝对路径区分，不会互相覆盖：

```bash
atlisp-dwg-kb extract /data/root1 -o /kb/extract/root1
atlisp-dwg-kb extract /data/root2 -o /kb/extract/root2
atlisp-dwg-kb build --extract-dir /kb/extract        # 合并 root1 + root2
```

**各自独立知识库**：用 `DWG_KB_DATA_DIR` 隔离存储（build / query / stats / serve / ui 需带同一变量）：

```bash
DWG_KB_DATA_DIR=~/.dwg-kb/root1 atlisp-dwg-kb build --extract-dir /data/root1/dwg-extract
DWG_KB_DATA_DIR=~/.dwg-kb/root1 atlisp-dwg-kb query "列出所有暖通图纸"
```

注意：不要让两个源目录提取到同一个 `-o` 目录（每张图输出为 `<相对目录>/<stem>.json`，相对结构重叠时会互相覆盖）。

### 6. 空闲时自动构建（autobuild）

常驻守护：定时采样 CPU，连续多次低于阈值（默认 30%）且源目录有更新时，自动执行 `extract --resume` + `build` 全流程。适合放在夜间/空闲时段自动跟进新图纸。

```bash
# 需要 [watch] extra (psutil) 与 [dwg] extra (ezdxf)
atlisp-dwg-kb autobuild raw

# 自定义：采样 30s，CPU<20%，连续 3 次空闲触发，仅提取 2025 年
atlisp-dwg-kb autobuild raw --interval 30 --cpu-threshold 20 --idle-checks 3 --project 2025

# 只跑一轮（等到空闲构建一次即退出），适合 cron/计划任务
atlisp-dwg-kb autobuild raw --once
```

- 触发条件：`knowledge.trig` 不存在，或源 `*.dwg` / 提取 `*.json` 的 mtime 晚于上次构建
- `--interval` 既是 CPU 采样窗口也是检查周期；需连续 `--idle-checks` 次空闲才触发（默认 3 次 × 60s ≈ 3 分钟）
- 后台/服务场景用 `--log-file <path>` 追加带时间戳的日志
- 按 `Ctrl-C` 退出

## Windows 后台运行（服务）

在 Windows 上把 `autobuild` 注册为服务：开机自启、崩溃重启、无需登录。两种方式任选。

### 方式一：内置命令（pywin32，推荐）

```powershell
pip install -e ".[dwg,watch,service]"     # [service] = pywin32
# 以管理员 PowerShell 运行：
atlisp-dwg-kb service install D:\dwg --interval 60 --cpu-threshold 30 --idle-checks 3 --log-file D:\dwg\dwg-kb-service.log

atlisp-dwg-kb service status
atlisp-dwg-kb service stop
atlisp-dwg-kb service start
atlisp-dwg-kb service uninstall
```

- `service install` 把运行参数写入 `%PROGRAMDATA%\atlisp-dwg-kb\service.json`，再注册并启动服务（`SERVICE_AUTO_START`）。
- 需管理员权限；若 pywin32 的服务宿主未注册，运行 `python Scripts\pywin32_postinstall.py -install`。
- 仅 Windows 可用，其他平台会提示 `Windows service is only supported on Windows`。

### 方式二：NSSM 脚本

1. 下载 [NSSM](https://nssm.cc/download)，将 `nssm.exe` 加入 PATH。
2. `pip install -e ".[dwg,watch]"`。
3. 管理员 PowerShell 运行仓库脚本：

```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\windows\install-service.ps1 -DwgRoot D:\dwg
```

管理：

```cmd
nssm status atlisp-dwg-kb
nssm restart atlisp-dwg-kb
powershell -ExecutionPolicy Bypass -File .\scripts\windows\install-service.ps1 -Uninstall
```

注意：提取依赖 `dwg2dxf.exe`（libredwg）——Windows 下 PyPI 包已内置，其他平台需安装到 PATH。

### 方式三：系统托盘图标（交互式管理）

在 Windows 系统托盘显示图标，提供图形化管理界面：

```powershell
pip install -e ".[dwg,watch,tray]"        # [tray] = pystray + Pillow

# 启动托盘图标（前台运行）
atlisp-dwg-kb tray D:\dwg

# 最小化到托盘启动
atlisp-dwg-kb tray D:\dwg --background
```

功能：
- **服务控制**: 启动/停止/重启 autobuild 服务
- **状态监控**: 实时显示 CPU 使用率、服务状态、最后构建时间
- **手动触发**: 立即执行一次构建
- **日志查看**: 弹窗显示构建日志
- **配置管理**: 查看/修改服务配置
- **知识库统计**: 显示图纸数量、专业分布
- **快速查询**: 通过自然语言查询知识库

## 配置

通过环境变量配置（见 `src/atlisp_dwg_kb/config.py`）：

| 变量 | 说明 | 默认值 |
|------|------|--------|
| `DWG_KB_DATA_DIR` | 知识库存储目录 | `~/.dwg-kb` |
| `DWG_EXTRACT_DIR` | DWG 提取结果目录（build 默认读取） | `./dwg-extract` |
| `NEO4J_URI` | Neo4j 连接地址 | `bolt://localhost:7687` |
| `NEO4J_USER` | Neo4j 用户名 | `neo4j` |
| `NEO4J_PASSWORD` | Neo4j 密码 | (空) |

```bash
# 自定义知识库存储目录
export DWG_KB_DATA_DIR=/my/data
atlisp-dwg-kb build --extract-dir /my/dwg-extract
```

注意：仓库内的 `data/` 是本地构建产物（已 gitignore），不是运行时默认路径。

## 命令一览

| 命令 | 说明 |
|------|------|
| `atlisp-dwg-kb extract <dwg-root> [--limit N] [--resume] [--project YYYY] [-w N] [-o DIR]` | 从 DWG 提取元数据 |
| `atlisp-dwg-kb build --extract-dir <dir>` | 从提取结果构建知识库 |
| `atlisp-dwg-kb autobuild <dwg-root> [--interval N] [--cpu-threshold P] [--idle-checks K] [--once] [--log-file F]` | CPU 空闲时自动提取+构建 |
| `atlisp-dwg-kb service {install,uninstall,start,stop,status}` | Windows 服务管理 (pywin32) |
| `atlisp-dwg-kb query "..."` | 命令行查询 |
| `atlisp-dwg-kb stats` | 显示统计 |
| `atlisp-dwg-kb serve [--port N] [--no-browser]` | 启动 FastAPI 服务并打开管理界面 (默认 8260) |
| `atlisp-dwg-kb ui [--port N]` | 启动 Gradio 界面 (默认 7860，已弃用) |
| `atlisp-dwg-kb all [--port N] [--no-browser]` | 启动 API + 内置浏览器界面 |
| `atlisp-dwg-kb export-neo4j` | 导出 Neo4j Cypher |
| `atlisp-dwg-kb tray <dwg-root> [--background]` | 启动系统托盘图标管理器 (Windows) |

## 项目结构

```
dwg-knowledge-base/
├── src/
│   └── atlisp_dwg_kb/          # 核心包
│       ├── extract.py          # DWG 元数据提取 (DWG→DXF→JSON/MD)
│       ├── ontology/           # 本体(ttl) + RDF 填充 + SPARQL 查询
│       ├── graph/              # 图谱构建 + 演进追踪 + 跨专业 + Neo4j 导出
│       ├── api/                # FastAPI REST
│       ├── ui/static/          # 浏览器管理界面 (HTML/CSS/JS，无框架)
│       ├── bin/                # 内置 dwg2dxf 等 libredwg 二进制 (Windows)
│       ├── tray.py             # 系统托盘图标管理器 (Windows)
│       ├── cli.py              # CLI 入口
│       └── config.py           # 配置 + 领域关键词表
├── tests/                      # pytest 测试
├── raw -> /media/data/...      # 本机 DWG 档案符号链接（勿提交）
├── data/                       # 本地构建产物（gitignore）
└── pyproject.toml
```

## 本体类层次

```
owl:Thing
├── Project
├── Drawing
│   ├── ArchitecturalDrawing
│   ├── StructuralDrawing
│   ├── HVACDrawing
│   ├── ElectricalDrawing
│   ├── DetailDrawing
│   └── GeneralDrawing
├── Layer
├── Block
│   ├── BuildingComponent
│   └── Equipment
├── ReviewRound
├── Discipline
└── TextAnnotation
```

## 依赖

- Python 3.10+
- rdflib (RDF 处理)
- networkx + scipy (图算法 + 构建期力导向布局)
- fastapi + uvicorn (API 服务)
- ezdxf (可选, DWG 提取)
- pystray + Pillow (可选, Windows 系统托盘)
- gradio (可选, 旧版 Web 界面，已弃用)
- dwg2dxf (libredwg, DWG 转 DXF；Windows PyPI 包已内置)
