openwiki-server 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.
- openwiki_server-0.1.0/.gitignore +17 -0
- openwiki_server-0.1.0/LICENSE +21 -0
- openwiki_server-0.1.0/PKG-INFO +269 -0
- openwiki_server-0.1.0/README.md +225 -0
- openwiki_server-0.1.0/openwiki_engine/__init__.py +3 -0
- openwiki_server-0.1.0/openwiki_engine/adapters/__init__.py +1 -0
- openwiki_server-0.1.0/openwiki_engine/adapters/openwiki.py +342 -0
- openwiki_server-0.1.0/openwiki_engine/application/__init__.py +1 -0
- openwiki_server-0.1.0/openwiki_engine/application/service.py +481 -0
- openwiki_server-0.1.0/openwiki_engine/config.py +80 -0
- openwiki_server-0.1.0/openwiki_engine/domain/__init__.py +18 -0
- openwiki_server-0.1.0/openwiki_engine/domain/ids.py +30 -0
- openwiki_server-0.1.0/openwiki_engine/domain/merge.py +43 -0
- openwiki_server-0.1.0/openwiki_engine/domain/models.py +117 -0
- openwiki_server-0.1.0/openwiki_engine/domain/wiki_config.py +68 -0
- openwiki_server-0.1.0/openwiki_engine/errors.py +50 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/__init__.py +1 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/celery_app.py +116 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/cli.py +309 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/grpc_server.py +253 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/http_app.py +203 -0
- openwiki_server-0.1.0/openwiki_engine/interfaces/mcp_server.py +147 -0
- openwiki_server-0.1.0/openwiki_engine/persistence/__init__.py +1 -0
- openwiki_server-0.1.0/openwiki_engine/persistence/sqlite_store.py +459 -0
- openwiki_server-0.1.0/openwiki_engine/protocol.py +31 -0
- openwiki_server-0.1.0/openwiki_engine/runtime.py +45 -0
- openwiki_server-0.1.0/proto/wiki/v1/wiki.proto +35 -0
- openwiki_server-0.1.0/pyproject.toml +75 -0
- openwiki_server-0.1.0/sdk/python/README.md +140 -0
- openwiki_server-0.1.0/sdk/python/examples/async_quickstart.py +33 -0
- openwiki_server-0.1.0/sdk/python/examples/quickstart.py +70 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/__init__.py +83 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/_bootstrap.py +71 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/_version.py +1 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/async_client.py +287 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/client.py +306 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/envelope.py +39 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/errors.py +80 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/headers.py +42 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/models/__init__.py +3 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/models/wiki.py +506 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/trace.py +20 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/transport.py +207 -0
- openwiki_server-0.1.0/sdk/python/openwiki_server_sdk/transport_async.py +147 -0
- openwiki_server-0.1.0/sdk/python/pyproject.toml +21 -0
- openwiki_server-0.1.0/sdk/python/tests/conftest.py +6 -0
- openwiki_server-0.1.0/sdk/python/tests/test_async.py +90 -0
- openwiki_server-0.1.0/sdk/python/tests/test_bootstrap.py +47 -0
- openwiki_server-0.1.0/sdk/python/tests/test_client.py +196 -0
- openwiki_server-0.1.0/sdk/python/tests/test_envelope.py +33 -0
- openwiki_server-0.1.0/sdk/python/tests/test_errors.py +30 -0
- openwiki_server-0.1.0/sdk/python/tests/test_models.py +68 -0
- openwiki_server-0.1.0/sdk/python/tests/test_trace.py +19 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 shark8848 <admin@sharky-ai.com>
|
|
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,269 @@
|
|
|
1
|
+
Metadata-Version: 2.5
|
|
2
|
+
Name: openwiki-server
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Lightweight SDK + Server for OpenWiki — wiki engine as standalone service with HTTP/gRPC/Celery/MCP/CLI interfaces and application integration SDK.
|
|
5
|
+
Author-email: shark8848 <admin@sharky-ai.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
License-File: LICENSE
|
|
8
|
+
Keywords: knowledge-base,llm,openwiki,rag,sdk,server,wiki
|
|
9
|
+
Classifier: Development Status :: 4 - Beta
|
|
10
|
+
Classifier: Intended Audience :: Developers
|
|
11
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
16
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
17
|
+
Classifier: Topic :: Text Processing :: Markup :: Markdown
|
|
18
|
+
Requires-Python: >=3.10
|
|
19
|
+
Requires-Dist: httpx<1.0,>=0.27
|
|
20
|
+
Provides-Extra: all
|
|
21
|
+
Requires-Dist: celery>=5.3; extra == 'all'
|
|
22
|
+
Requires-Dist: fastapi>=0.115; extra == 'all'
|
|
23
|
+
Requires-Dist: grpcio>=1.81; extra == 'all'
|
|
24
|
+
Requires-Dist: protobuf>=5.29; extra == 'all'
|
|
25
|
+
Requires-Dist: pydantic>=2.0; extra == 'all'
|
|
26
|
+
Requires-Dist: redis>=5.0; extra == 'all'
|
|
27
|
+
Requires-Dist: typer>=0.12; extra == 'all'
|
|
28
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'all'
|
|
29
|
+
Provides-Extra: dev
|
|
30
|
+
Requires-Dist: httpx<1.0,>=0.27; extra == 'dev'
|
|
31
|
+
Requires-Dist: pytest-asyncio>=0.21; extra == 'dev'
|
|
32
|
+
Requires-Dist: pytest>=8.0; extra == 'dev'
|
|
33
|
+
Requires-Dist: ruff>=0.1; extra == 'dev'
|
|
34
|
+
Provides-Extra: server
|
|
35
|
+
Requires-Dist: celery>=5.3; extra == 'server'
|
|
36
|
+
Requires-Dist: fastapi>=0.115; extra == 'server'
|
|
37
|
+
Requires-Dist: grpcio>=1.81; extra == 'server'
|
|
38
|
+
Requires-Dist: protobuf>=5.29; extra == 'server'
|
|
39
|
+
Requires-Dist: pydantic>=2.0; extra == 'server'
|
|
40
|
+
Requires-Dist: redis>=5.0; extra == 'server'
|
|
41
|
+
Requires-Dist: typer>=0.12; extra == 'server'
|
|
42
|
+
Requires-Dist: uvicorn[standard]>=0.30; extra == 'server'
|
|
43
|
+
Description-Content-Type: text/markdown
|
|
44
|
+
|
|
45
|
+
# OpenWiki Server
|
|
46
|
+
|
|
47
|
+
把 LangChain **OpenWiki**(`langchain-ai/openwiki`,Markdown wiki 内核)封装为独立对外服务的 Wiki 引擎,
|
|
48
|
+
供 `/home/open-ikc` 的 Wiki 库能力消费;对外提供 **HTTP / gRPC / Celery / MCP / CLI** 五类接口。
|
|
49
|
+
|
|
50
|
+
<p align="center">
|
|
51
|
+
<a href="https://pypi.org/project/openwiki-server/"><img src="https://img.shields.io/pypi/v/openwiki-server" alt="PyPI" /></a>
|
|
52
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT" /></a>
|
|
53
|
+
<img src="https://img.shields.io/badge/Python-3.10%2B-blue" alt="Python 3.10+" />
|
|
54
|
+
</p>
|
|
55
|
+
|
|
56
|
+
- 设计方案:`docs/解决方案.md`
|
|
57
|
+
- gRPC 权威契约:`proto/wiki/v1/wiki.proto`
|
|
58
|
+
- 配置样例:`config/engine.example.yaml`(全部可用环境变量覆盖)
|
|
59
|
+
- 命令行测试与调用指南:`docs/命令行测试与调用指南.md`(五类接口全部命令,已用仓库真实文档实测)
|
|
60
|
+
- 独立承载服务与 SDK 集成设计:`docs/独立承载服务与SDK集成设计.md`(应用侧快速集成)
|
|
61
|
+
|
|
62
|
+
## 安装(PyPI)
|
|
63
|
+
|
|
64
|
+
```bash
|
|
65
|
+
pip install openwiki-server # SDK(httpx,应用侧集成)
|
|
66
|
+
pip install openwiki-server[server] # + 独立承载服务(HTTP/gRPC/Celery/MCP/CLI)
|
|
67
|
+
pip install openwiki-server[all] # 全部依赖
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
PyPI 包同时包含引擎(`openwiki_engine`)与应用集成 SDK(`openwiki_server_sdk`),
|
|
71
|
+
与 `ikc-log-center` 的发布形态一致。SDK 快速开始见
|
|
72
|
+
[`sdk/python/README.md`](sdk/python/README.md)。
|
|
73
|
+
|
|
74
|
+
发布到 PyPI:
|
|
75
|
+
|
|
76
|
+
```bash
|
|
77
|
+
cp config/pypi.env.example config/pypi.env # 填入 OPENWIKI_PYPI_TOKEN
|
|
78
|
+
./scripts/publish-pypi.sh # 构建 + 上传
|
|
79
|
+
./scripts/publish-pypi.sh --test # 上传到 TestPyPI
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
## 内核说明
|
|
83
|
+
|
|
84
|
+
- OpenWiki 为 Node CLI(`npm i openwiki`,项目内 `node_modules/.bin/openwiki`),引擎以子进程方式调用,
|
|
85
|
+
`HOME` 指向 wiki 实例目录实现多租户隔离(`~/.openwiki` 配置与 `~/.openwiki/wiki` 产物均落在实例目录内)。
|
|
86
|
+
- **守卫式降级**:openwiki 未安装 / LLM 调用失败 / 无网络时,`build_from_doc` 自动切规则切页
|
|
87
|
+
(`granularity=heading/section/page` + `extractFields` 行抽取),全链路离线可用。
|
|
88
|
+
- 稳定 ID 与 open-ikc 完全兼容:`wikiId = wiki_ + sha1(kbId)[:12]`,
|
|
89
|
+
`pageId = wiki_ + sha1(kbId:stableKey)[:12]`,`stableKey = normalize_title(title)`。
|
|
90
|
+
|
|
91
|
+
## 快速开始
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
# 依赖(复用已有 venv;本机可用 semantica-graph-server/.venv)
|
|
95
|
+
pip install -e . --no-build-isolation
|
|
96
|
+
|
|
97
|
+
# 启动 HTTP 服务(默认 18011)
|
|
98
|
+
openwiki-server serve http
|
|
99
|
+
|
|
100
|
+
# CLI 走通全链路(离线规则模式)
|
|
101
|
+
export OPENWIKI_SERVER_DATA_DIR=/tmp/ow-demo OPENWIKI_SERVER_OPENWIKI=0
|
|
102
|
+
openwiki-server create --kb-id kb_demo --name 演示Wiki \
|
|
103
|
+
--config '{"granularity":"heading","extractFields":["负责人"]}'
|
|
104
|
+
openwiki-server build wiki_fb42912a4348 --doc-id doc1 --title 产品手册 \
|
|
105
|
+
--markdown '# 产品手册\n\n## 安装\n\n安装说明。负责人:张三'
|
|
106
|
+
openwiki-server tree wiki_fb42912a4348
|
|
107
|
+
openwiki-server search wiki_fb42912a4348 --q 安装
|
|
108
|
+
openwiki-server stat wiki_fb42912a4348
|
|
109
|
+
openwiki-server export wiki_fb42912a4348
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## Docker 部署(单镜像,含 HAProxy)
|
|
113
|
+
|
|
114
|
+
参考 `/home/open-ikc` 的单镜像代理拓扑:**Python 引擎 + Node openwiki 内核 + HAProxy 代理层构建到同一镜像**,
|
|
115
|
+
引擎进程(uvicorn 18011 / gRPC 50052)只监听容器回环,对外唯一入口为 HAProxy
|
|
116
|
+
(HTTP `:8080` 反代 uvicorn、gRPC `:50052` TCP 透传、stats `:8404`)。
|
|
117
|
+
|
|
118
|
+
```
|
|
119
|
+
宿主机 client
|
|
120
|
+
│ http://127.0.0.1:18011 grpc://127.0.0.1:50052 http://127.0.0.1:8404(stats)
|
|
121
|
+
▼
|
|
122
|
+
┌────────────────────────────────────────────────┐
|
|
123
|
+
│ 容器 openwiki-server │
|
|
124
|
+
│ HAProxy(:8080 HTTP / :50052 gRPC / :8404 stats)│
|
|
125
|
+
│ │ 反向代理 / TCP 透传 │
|
|
126
|
+
│ ▼ │
|
|
127
|
+
│ uvicorn(127.0.0.1:18011) + gRPC(127.0.0.1:50052)│
|
|
128
|
+
└────────────────────────────────────────────────┘
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```bash
|
|
132
|
+
# 构建镜像(openwiki-server:<package.json version>,含 openwiki 内核与 HAProxy)
|
|
133
|
+
bash scripts/build_docker.sh
|
|
134
|
+
# 启动(默认入口 http://127.0.0.1:18011;stats http://127.0.0.1:8404)
|
|
135
|
+
docker compose up -d
|
|
136
|
+
# 启用 Celery worker(broker/backend 用外部 redis,默认 redis://host.docker.internal:6379/0)
|
|
137
|
+
docker compose --profile worker up -d
|
|
138
|
+
# 冒烟验证(7 项断言,--force-build 可强制重建)
|
|
139
|
+
bash scripts/docker_smoke.sh
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
- 镜像内 HAProxy 配置模板 `/etc/haproxy/haproxy.cfg.tmpl` 由入口脚本 envsubst 渲染
|
|
143
|
+
`HAPROXY_STATS_USER / HAPROXY_STATS_PASSWORD`(默认 `admin/change-me`,生产必改)。
|
|
144
|
+
- 数据卷 `app_data` 挂载 `/app/data`(SQLite 与 wiki 产物持久化);worker 与 app 共用同一数据卷。
|
|
145
|
+
- 环境变量模板:`cp docker/.env.example .env`(生产密码、端口、LLM 内核配置)。
|
|
146
|
+
- Celery 使用**外部 redis**(compose 不再内置 redis 服务);默认指向宿主机
|
|
147
|
+
`host.docker.internal:6379`,远程实例在 `.env` 用 `OPENWIKI_SERVER_CELERY_BROKER` /
|
|
148
|
+
`OPENWIKI_SERVER_CELERY_BACKEND` 覆盖;本机 redis 若需密码写成
|
|
149
|
+
`redis://:<密码>@host.docker.internal:6379/0`(未启用 worker 时 app 不主动连接)。
|
|
150
|
+
- `OPENWIKI_SERVER_OPENWIKI=0` 可强制离线规则切页(镜像内已含 Node 22 + openwiki 内核,
|
|
151
|
+
默认启用、LLM 失败自动降级)。
|
|
152
|
+
- 异步加工:build/merge 等请求带 `async=1` 时登记为 job 并经 Celery 投递(broker 不可达时
|
|
153
|
+
保持 `pending`,可调 `POST /api/v1/wiki/jobs/{job_id}/run` 手动执行;轮询
|
|
154
|
+
`GET /api/v1/wiki/jobs/{job_id}` 查看结果)。
|
|
155
|
+
|
|
156
|
+
## 五类接口
|
|
157
|
+
|
|
158
|
+
| 协议面 | 入口 | 说明 |
|
|
159
|
+
| --- | --- | --- |
|
|
160
|
+
| HTTP | `openwiki-server serve http` | FastAPI,`/api/v1/wiki/*`,envelope 对齐 open-ikc |
|
|
161
|
+
| gRPC | `openwiki-server serve grpc` | `wiki.v1.WikiService`,动态 descriptor 实现 |
|
|
162
|
+
| Celery | `openwiki-server serve worker` | 任务 `openwiki_server.build / merge / deprecate_doc / export / update / ingest` |
|
|
163
|
+
| MCP | `openwiki-server serve mcp` | stdio JSON-RPC,`initialize / tools/list / tools/call` |
|
|
164
|
+
| CLI | `openwiki-server ...` | typer,退出码 0/1/6 约定同 open-ikc `ikc` |
|
|
165
|
+
|
|
166
|
+
## SDK(应用侧快速集成)
|
|
167
|
+
|
|
168
|
+
openwiki-server 可作**独立承载服务**(本地进程或 Docker 单镜像栈),应用侧用
|
|
169
|
+
`openwiki-server-sdk`(参考 open-ikc `open-ikc-sdk` 定义)快速接入全部 wiki 能力:
|
|
170
|
+
|
|
171
|
+
```bash
|
|
172
|
+
pip install sdk/python
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
```python
|
|
176
|
+
from openwiki_server_sdk import OpenWikiServerClient
|
|
177
|
+
|
|
178
|
+
with OpenWikiServerClient(base_url="http://127.0.0.1:18011") as client:
|
|
179
|
+
wiki = client.wikis.create(kbId="kb_demo", name="产品知识库",
|
|
180
|
+
wikiConfig={"granularity": "heading"})
|
|
181
|
+
result = client.wikis.build(
|
|
182
|
+
wiki.wikiId, docId="doc_1", title="产品手册",
|
|
183
|
+
markdown=open("docs/进展.md", encoding="utf-8").read())
|
|
184
|
+
print(result.mode, result.total)
|
|
185
|
+
hits = client.wikis.search(wiki.wikiId, q="HAProxy")
|
|
186
|
+
job = client.wikis.build(wiki.wikiId, docId="doc_2", title="异步", async_=True)
|
|
187
|
+
print(client.jobs.run(job.jobId).status)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
- 领域方法:`client.wikis.create/list/get/delete/tree/page/search/stat/export/
|
|
191
|
+
build/merge/deprecate_doc/update/ingest` 与 `client.jobs.run/get/list`;
|
|
192
|
+
同步 `OpenWikiServerClient` / 异步 `AsyncOpenWikiServerClient` 共享同一套模型。
|
|
193
|
+
- 环境变量引导:`OPENWIKI_SERVER_BASE_URL`(默认 `http://127.0.0.1:18011`)/
|
|
194
|
+
`OPENWIKI_SERVER_TOKEN` / `OPENWIKI_SERVER_USER_ID` / `OPENWIKI_SERVER_TENANT_ID` /
|
|
195
|
+
`OPENWIKI_SERVER_ROLES`,经 `client_from_env()` 构造。
|
|
196
|
+
- 自测与冒烟:`cd sdk/python && PYTHONPATH=. python -m pytest tests -q`(36 例 MockTransport);
|
|
197
|
+
真实联调 `python sdk/python/examples/quickstart.py`。
|
|
198
|
+
- 完整设计(包结构 / 异常层级 / 请求链路 / API 对照表 / 独立承载部署):见
|
|
199
|
+
`docs/独立承载服务与SDK集成设计.md`;SDK 使用说明见 `sdk/python/README.md`。
|
|
200
|
+
|
|
201
|
+
## 环境变量
|
|
202
|
+
|
|
203
|
+
`OPENWIKI_SERVER_DATA_DIR` / `_DB_PATH` / `_HTTP_HOST` / `_HTTP_PORT`(18011)/
|
|
204
|
+
`_GRPC_HOST` / `_GRPC_PORT`(50052)/ `_CELERY_BROKER` / `_CELERY_BACKEND` /
|
|
205
|
+
`_OPENWIKI_BIN` / `_OPENWIKI`(0 关闭内核)/ `_PROVIDER` / `_MODEL_ID` /
|
|
206
|
+
`_UPDATE_TIMEOUT` / `_LOG_LEVEL`;Docker 额外使用 `HAPROXY_STATS_USER` /
|
|
207
|
+
`HAPROXY_STATS_PASSWORD`(HAProxy stats 登录)与 `OPENWIKI_HTTP_PORT` /
|
|
208
|
+
`OPENWIKI_GRPC_PORT` / `HAPROXY_STATS_PORT`(宿主端口映射)
|
|
209
|
+
|
|
210
|
+
## 测试
|
|
211
|
+
|
|
212
|
+
### 单元 / 冒烟(pytest)
|
|
213
|
+
|
|
214
|
+
```bash
|
|
215
|
+
PYTHONPATH=. python -m pytest tests -q
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
> 沙箱/CI 若禁止绑定 socket,gRPC 真链路测试自动 skip(进程内 handler 语义仍覆盖)。
|
|
219
|
+
|
|
220
|
+
### 命令行测试与调用(五类接口)
|
|
221
|
+
|
|
222
|
+
详细手册见 `docs/命令行测试与调用指南.md`:HTTP(curl) / CLI / gRPC / MCP / Celery(jobs) 全部命令,
|
|
223
|
+
已用仓库真实文档(`docs/进展.md`、`docs/解决方案.md`、`README.md`)实测通过。
|
|
224
|
+
|
|
225
|
+
一键全链路演练(探针 → CRUD → 真实文档 build → tree/page/search/stat/export →
|
|
226
|
+
merge/deprecate → 异步 job → CLI 等价命令,全部断言通过后打印 `ALL PASS`):
|
|
227
|
+
|
|
228
|
+
```bash
|
|
229
|
+
bash scripts/wiki_api_drill.sh
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
常用命令速查(离线规则模式 `OPENWIKI_SERVER_OPENWIKI=0`,服务默认 `127.0.0.1:18011`):
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
BASE=http://127.0.0.1:18011
|
|
236
|
+
|
|
237
|
+
# 起服务
|
|
238
|
+
export OPENWIKI_SERVER_DATA_DIR=/tmp/ow-live OPENWIKI_SERVER_OPENWIKI=0
|
|
239
|
+
openwiki-server serve http
|
|
240
|
+
|
|
241
|
+
# 创建 wiki(WID 取返回 data.wikiId)
|
|
242
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis" -H 'Content-Type: application/json' \
|
|
243
|
+
-d '{"kbId":"kb_live_demo","name":"演示","wikiConfig":{"granularity":"heading"}}'
|
|
244
|
+
|
|
245
|
+
# 用真实文档建页(docs/进展.md,heading 粒度切 11 页)
|
|
246
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis/$WID/build" -H 'Content-Type: application/json' \
|
|
247
|
+
-d "$(python -c "import json;print(json.dumps({'docId':'d1','title':'任务进展记录','tags':['运维'],'markdown':open('docs/进展.md',encoding='utf-8').read()}))")"
|
|
248
|
+
|
|
249
|
+
# 查询 / 检索 / 导出
|
|
250
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/tree?page=1&pageSize=20"
|
|
251
|
+
curl -sS --get "$BASE/api/v1/wiki/wikis/$WID/search" --data-urlencode "q=检索"
|
|
252
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/stat"
|
|
253
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/export?format=json"
|
|
254
|
+
|
|
255
|
+
# 异步任务:async=1 提交(JOB_ID 取返回 data.jobId)→ 手动执行 → 查询
|
|
256
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis/$WID/build" -H 'Content-Type: application/json' \
|
|
257
|
+
-d '{"async":"1","docId":"d_async","title":"异步示例","markdown":"# 异步示例"}'
|
|
258
|
+
curl -sS -X POST "$BASE/api/v1/wiki/jobs/$JOB_ID/run"
|
|
259
|
+
curl -sS "$BASE/api/v1/wiki/jobs/$JOB_ID"
|
|
260
|
+
|
|
261
|
+
# gRPC / MCP
|
|
262
|
+
python - <<'PY'
|
|
263
|
+
from openwiki_engine.interfaces.grpc_server import grpc_client
|
|
264
|
+
client = grpc_client("127.0.0.1", 50052)
|
|
265
|
+
print(client("Stat", {"wikiId": "wiki_<id>"}))
|
|
266
|
+
PY
|
|
267
|
+
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' \
|
|
268
|
+
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | openwiki-server serve mcp
|
|
269
|
+
```
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
# OpenWiki Server
|
|
2
|
+
|
|
3
|
+
把 LangChain **OpenWiki**(`langchain-ai/openwiki`,Markdown wiki 内核)封装为独立对外服务的 Wiki 引擎,
|
|
4
|
+
供 `/home/open-ikc` 的 Wiki 库能力消费;对外提供 **HTTP / gRPC / Celery / MCP / CLI** 五类接口。
|
|
5
|
+
|
|
6
|
+
<p align="center">
|
|
7
|
+
<a href="https://pypi.org/project/openwiki-server/"><img src="https://img.shields.io/pypi/v/openwiki-server" alt="PyPI" /></a>
|
|
8
|
+
<a href="https://opensource.org/licenses/MIT"><img src="https://img.shields.io/badge/License-MIT-green.svg" alt="MIT" /></a>
|
|
9
|
+
<img src="https://img.shields.io/badge/Python-3.10%2B-blue" alt="Python 3.10+" />
|
|
10
|
+
</p>
|
|
11
|
+
|
|
12
|
+
- 设计方案:`docs/解决方案.md`
|
|
13
|
+
- gRPC 权威契约:`proto/wiki/v1/wiki.proto`
|
|
14
|
+
- 配置样例:`config/engine.example.yaml`(全部可用环境变量覆盖)
|
|
15
|
+
- 命令行测试与调用指南:`docs/命令行测试与调用指南.md`(五类接口全部命令,已用仓库真实文档实测)
|
|
16
|
+
- 独立承载服务与 SDK 集成设计:`docs/独立承载服务与SDK集成设计.md`(应用侧快速集成)
|
|
17
|
+
|
|
18
|
+
## 安装(PyPI)
|
|
19
|
+
|
|
20
|
+
```bash
|
|
21
|
+
pip install openwiki-server # SDK(httpx,应用侧集成)
|
|
22
|
+
pip install openwiki-server[server] # + 独立承载服务(HTTP/gRPC/Celery/MCP/CLI)
|
|
23
|
+
pip install openwiki-server[all] # 全部依赖
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
PyPI 包同时包含引擎(`openwiki_engine`)与应用集成 SDK(`openwiki_server_sdk`),
|
|
27
|
+
与 `ikc-log-center` 的发布形态一致。SDK 快速开始见
|
|
28
|
+
[`sdk/python/README.md`](sdk/python/README.md)。
|
|
29
|
+
|
|
30
|
+
发布到 PyPI:
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
cp config/pypi.env.example config/pypi.env # 填入 OPENWIKI_PYPI_TOKEN
|
|
34
|
+
./scripts/publish-pypi.sh # 构建 + 上传
|
|
35
|
+
./scripts/publish-pypi.sh --test # 上传到 TestPyPI
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## 内核说明
|
|
39
|
+
|
|
40
|
+
- OpenWiki 为 Node CLI(`npm i openwiki`,项目内 `node_modules/.bin/openwiki`),引擎以子进程方式调用,
|
|
41
|
+
`HOME` 指向 wiki 实例目录实现多租户隔离(`~/.openwiki` 配置与 `~/.openwiki/wiki` 产物均落在实例目录内)。
|
|
42
|
+
- **守卫式降级**:openwiki 未安装 / LLM 调用失败 / 无网络时,`build_from_doc` 自动切规则切页
|
|
43
|
+
(`granularity=heading/section/page` + `extractFields` 行抽取),全链路离线可用。
|
|
44
|
+
- 稳定 ID 与 open-ikc 完全兼容:`wikiId = wiki_ + sha1(kbId)[:12]`,
|
|
45
|
+
`pageId = wiki_ + sha1(kbId:stableKey)[:12]`,`stableKey = normalize_title(title)`。
|
|
46
|
+
|
|
47
|
+
## 快速开始
|
|
48
|
+
|
|
49
|
+
```bash
|
|
50
|
+
# 依赖(复用已有 venv;本机可用 semantica-graph-server/.venv)
|
|
51
|
+
pip install -e . --no-build-isolation
|
|
52
|
+
|
|
53
|
+
# 启动 HTTP 服务(默认 18011)
|
|
54
|
+
openwiki-server serve http
|
|
55
|
+
|
|
56
|
+
# CLI 走通全链路(离线规则模式)
|
|
57
|
+
export OPENWIKI_SERVER_DATA_DIR=/tmp/ow-demo OPENWIKI_SERVER_OPENWIKI=0
|
|
58
|
+
openwiki-server create --kb-id kb_demo --name 演示Wiki \
|
|
59
|
+
--config '{"granularity":"heading","extractFields":["负责人"]}'
|
|
60
|
+
openwiki-server build wiki_fb42912a4348 --doc-id doc1 --title 产品手册 \
|
|
61
|
+
--markdown '# 产品手册\n\n## 安装\n\n安装说明。负责人:张三'
|
|
62
|
+
openwiki-server tree wiki_fb42912a4348
|
|
63
|
+
openwiki-server search wiki_fb42912a4348 --q 安装
|
|
64
|
+
openwiki-server stat wiki_fb42912a4348
|
|
65
|
+
openwiki-server export wiki_fb42912a4348
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Docker 部署(单镜像,含 HAProxy)
|
|
69
|
+
|
|
70
|
+
参考 `/home/open-ikc` 的单镜像代理拓扑:**Python 引擎 + Node openwiki 内核 + HAProxy 代理层构建到同一镜像**,
|
|
71
|
+
引擎进程(uvicorn 18011 / gRPC 50052)只监听容器回环,对外唯一入口为 HAProxy
|
|
72
|
+
(HTTP `:8080` 反代 uvicorn、gRPC `:50052` TCP 透传、stats `:8404`)。
|
|
73
|
+
|
|
74
|
+
```
|
|
75
|
+
宿主机 client
|
|
76
|
+
│ http://127.0.0.1:18011 grpc://127.0.0.1:50052 http://127.0.0.1:8404(stats)
|
|
77
|
+
▼
|
|
78
|
+
┌────────────────────────────────────────────────┐
|
|
79
|
+
│ 容器 openwiki-server │
|
|
80
|
+
│ HAProxy(:8080 HTTP / :50052 gRPC / :8404 stats)│
|
|
81
|
+
│ │ 反向代理 / TCP 透传 │
|
|
82
|
+
│ ▼ │
|
|
83
|
+
│ uvicorn(127.0.0.1:18011) + gRPC(127.0.0.1:50052)│
|
|
84
|
+
└────────────────────────────────────────────────┘
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
# 构建镜像(openwiki-server:<package.json version>,含 openwiki 内核与 HAProxy)
|
|
89
|
+
bash scripts/build_docker.sh
|
|
90
|
+
# 启动(默认入口 http://127.0.0.1:18011;stats http://127.0.0.1:8404)
|
|
91
|
+
docker compose up -d
|
|
92
|
+
# 启用 Celery worker(broker/backend 用外部 redis,默认 redis://host.docker.internal:6379/0)
|
|
93
|
+
docker compose --profile worker up -d
|
|
94
|
+
# 冒烟验证(7 项断言,--force-build 可强制重建)
|
|
95
|
+
bash scripts/docker_smoke.sh
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
- 镜像内 HAProxy 配置模板 `/etc/haproxy/haproxy.cfg.tmpl` 由入口脚本 envsubst 渲染
|
|
99
|
+
`HAPROXY_STATS_USER / HAPROXY_STATS_PASSWORD`(默认 `admin/change-me`,生产必改)。
|
|
100
|
+
- 数据卷 `app_data` 挂载 `/app/data`(SQLite 与 wiki 产物持久化);worker 与 app 共用同一数据卷。
|
|
101
|
+
- 环境变量模板:`cp docker/.env.example .env`(生产密码、端口、LLM 内核配置)。
|
|
102
|
+
- Celery 使用**外部 redis**(compose 不再内置 redis 服务);默认指向宿主机
|
|
103
|
+
`host.docker.internal:6379`,远程实例在 `.env` 用 `OPENWIKI_SERVER_CELERY_BROKER` /
|
|
104
|
+
`OPENWIKI_SERVER_CELERY_BACKEND` 覆盖;本机 redis 若需密码写成
|
|
105
|
+
`redis://:<密码>@host.docker.internal:6379/0`(未启用 worker 时 app 不主动连接)。
|
|
106
|
+
- `OPENWIKI_SERVER_OPENWIKI=0` 可强制离线规则切页(镜像内已含 Node 22 + openwiki 内核,
|
|
107
|
+
默认启用、LLM 失败自动降级)。
|
|
108
|
+
- 异步加工:build/merge 等请求带 `async=1` 时登记为 job 并经 Celery 投递(broker 不可达时
|
|
109
|
+
保持 `pending`,可调 `POST /api/v1/wiki/jobs/{job_id}/run` 手动执行;轮询
|
|
110
|
+
`GET /api/v1/wiki/jobs/{job_id}` 查看结果)。
|
|
111
|
+
|
|
112
|
+
## 五类接口
|
|
113
|
+
|
|
114
|
+
| 协议面 | 入口 | 说明 |
|
|
115
|
+
| --- | --- | --- |
|
|
116
|
+
| HTTP | `openwiki-server serve http` | FastAPI,`/api/v1/wiki/*`,envelope 对齐 open-ikc |
|
|
117
|
+
| gRPC | `openwiki-server serve grpc` | `wiki.v1.WikiService`,动态 descriptor 实现 |
|
|
118
|
+
| Celery | `openwiki-server serve worker` | 任务 `openwiki_server.build / merge / deprecate_doc / export / update / ingest` |
|
|
119
|
+
| MCP | `openwiki-server serve mcp` | stdio JSON-RPC,`initialize / tools/list / tools/call` |
|
|
120
|
+
| CLI | `openwiki-server ...` | typer,退出码 0/1/6 约定同 open-ikc `ikc` |
|
|
121
|
+
|
|
122
|
+
## SDK(应用侧快速集成)
|
|
123
|
+
|
|
124
|
+
openwiki-server 可作**独立承载服务**(本地进程或 Docker 单镜像栈),应用侧用
|
|
125
|
+
`openwiki-server-sdk`(参考 open-ikc `open-ikc-sdk` 定义)快速接入全部 wiki 能力:
|
|
126
|
+
|
|
127
|
+
```bash
|
|
128
|
+
pip install sdk/python
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
from openwiki_server_sdk import OpenWikiServerClient
|
|
133
|
+
|
|
134
|
+
with OpenWikiServerClient(base_url="http://127.0.0.1:18011") as client:
|
|
135
|
+
wiki = client.wikis.create(kbId="kb_demo", name="产品知识库",
|
|
136
|
+
wikiConfig={"granularity": "heading"})
|
|
137
|
+
result = client.wikis.build(
|
|
138
|
+
wiki.wikiId, docId="doc_1", title="产品手册",
|
|
139
|
+
markdown=open("docs/进展.md", encoding="utf-8").read())
|
|
140
|
+
print(result.mode, result.total)
|
|
141
|
+
hits = client.wikis.search(wiki.wikiId, q="HAProxy")
|
|
142
|
+
job = client.wikis.build(wiki.wikiId, docId="doc_2", title="异步", async_=True)
|
|
143
|
+
print(client.jobs.run(job.jobId).status)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
- 领域方法:`client.wikis.create/list/get/delete/tree/page/search/stat/export/
|
|
147
|
+
build/merge/deprecate_doc/update/ingest` 与 `client.jobs.run/get/list`;
|
|
148
|
+
同步 `OpenWikiServerClient` / 异步 `AsyncOpenWikiServerClient` 共享同一套模型。
|
|
149
|
+
- 环境变量引导:`OPENWIKI_SERVER_BASE_URL`(默认 `http://127.0.0.1:18011`)/
|
|
150
|
+
`OPENWIKI_SERVER_TOKEN` / `OPENWIKI_SERVER_USER_ID` / `OPENWIKI_SERVER_TENANT_ID` /
|
|
151
|
+
`OPENWIKI_SERVER_ROLES`,经 `client_from_env()` 构造。
|
|
152
|
+
- 自测与冒烟:`cd sdk/python && PYTHONPATH=. python -m pytest tests -q`(36 例 MockTransport);
|
|
153
|
+
真实联调 `python sdk/python/examples/quickstart.py`。
|
|
154
|
+
- 完整设计(包结构 / 异常层级 / 请求链路 / API 对照表 / 独立承载部署):见
|
|
155
|
+
`docs/独立承载服务与SDK集成设计.md`;SDK 使用说明见 `sdk/python/README.md`。
|
|
156
|
+
|
|
157
|
+
## 环境变量
|
|
158
|
+
|
|
159
|
+
`OPENWIKI_SERVER_DATA_DIR` / `_DB_PATH` / `_HTTP_HOST` / `_HTTP_PORT`(18011)/
|
|
160
|
+
`_GRPC_HOST` / `_GRPC_PORT`(50052)/ `_CELERY_BROKER` / `_CELERY_BACKEND` /
|
|
161
|
+
`_OPENWIKI_BIN` / `_OPENWIKI`(0 关闭内核)/ `_PROVIDER` / `_MODEL_ID` /
|
|
162
|
+
`_UPDATE_TIMEOUT` / `_LOG_LEVEL`;Docker 额外使用 `HAPROXY_STATS_USER` /
|
|
163
|
+
`HAPROXY_STATS_PASSWORD`(HAProxy stats 登录)与 `OPENWIKI_HTTP_PORT` /
|
|
164
|
+
`OPENWIKI_GRPC_PORT` / `HAPROXY_STATS_PORT`(宿主端口映射)
|
|
165
|
+
|
|
166
|
+
## 测试
|
|
167
|
+
|
|
168
|
+
### 单元 / 冒烟(pytest)
|
|
169
|
+
|
|
170
|
+
```bash
|
|
171
|
+
PYTHONPATH=. python -m pytest tests -q
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
> 沙箱/CI 若禁止绑定 socket,gRPC 真链路测试自动 skip(进程内 handler 语义仍覆盖)。
|
|
175
|
+
|
|
176
|
+
### 命令行测试与调用(五类接口)
|
|
177
|
+
|
|
178
|
+
详细手册见 `docs/命令行测试与调用指南.md`:HTTP(curl) / CLI / gRPC / MCP / Celery(jobs) 全部命令,
|
|
179
|
+
已用仓库真实文档(`docs/进展.md`、`docs/解决方案.md`、`README.md`)实测通过。
|
|
180
|
+
|
|
181
|
+
一键全链路演练(探针 → CRUD → 真实文档 build → tree/page/search/stat/export →
|
|
182
|
+
merge/deprecate → 异步 job → CLI 等价命令,全部断言通过后打印 `ALL PASS`):
|
|
183
|
+
|
|
184
|
+
```bash
|
|
185
|
+
bash scripts/wiki_api_drill.sh
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
常用命令速查(离线规则模式 `OPENWIKI_SERVER_OPENWIKI=0`,服务默认 `127.0.0.1:18011`):
|
|
189
|
+
|
|
190
|
+
```bash
|
|
191
|
+
BASE=http://127.0.0.1:18011
|
|
192
|
+
|
|
193
|
+
# 起服务
|
|
194
|
+
export OPENWIKI_SERVER_DATA_DIR=/tmp/ow-live OPENWIKI_SERVER_OPENWIKI=0
|
|
195
|
+
openwiki-server serve http
|
|
196
|
+
|
|
197
|
+
# 创建 wiki(WID 取返回 data.wikiId)
|
|
198
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis" -H 'Content-Type: application/json' \
|
|
199
|
+
-d '{"kbId":"kb_live_demo","name":"演示","wikiConfig":{"granularity":"heading"}}'
|
|
200
|
+
|
|
201
|
+
# 用真实文档建页(docs/进展.md,heading 粒度切 11 页)
|
|
202
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis/$WID/build" -H 'Content-Type: application/json' \
|
|
203
|
+
-d "$(python -c "import json;print(json.dumps({'docId':'d1','title':'任务进展记录','tags':['运维'],'markdown':open('docs/进展.md',encoding='utf-8').read()}))")"
|
|
204
|
+
|
|
205
|
+
# 查询 / 检索 / 导出
|
|
206
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/tree?page=1&pageSize=20"
|
|
207
|
+
curl -sS --get "$BASE/api/v1/wiki/wikis/$WID/search" --data-urlencode "q=检索"
|
|
208
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/stat"
|
|
209
|
+
curl -sS "$BASE/api/v1/wiki/wikis/$WID/export?format=json"
|
|
210
|
+
|
|
211
|
+
# 异步任务:async=1 提交(JOB_ID 取返回 data.jobId)→ 手动执行 → 查询
|
|
212
|
+
curl -sS -X POST "$BASE/api/v1/wiki/wikis/$WID/build" -H 'Content-Type: application/json' \
|
|
213
|
+
-d '{"async":"1","docId":"d_async","title":"异步示例","markdown":"# 异步示例"}'
|
|
214
|
+
curl -sS -X POST "$BASE/api/v1/wiki/jobs/$JOB_ID/run"
|
|
215
|
+
curl -sS "$BASE/api/v1/wiki/jobs/$JOB_ID"
|
|
216
|
+
|
|
217
|
+
# gRPC / MCP
|
|
218
|
+
python - <<'PY'
|
|
219
|
+
from openwiki_engine.interfaces.grpc_server import grpc_client
|
|
220
|
+
client = grpc_client("127.0.0.1", 50052)
|
|
221
|
+
print(client("Stat", {"wikiId": "wiki_<id>"}))
|
|
222
|
+
PY
|
|
223
|
+
printf '%s\n' '{"jsonrpc":"2.0","id":1,"method":"initialize"}' \
|
|
224
|
+
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | openwiki-server serve mcp
|
|
225
|
+
```
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"""适配层:OpenWiki CLI 子进程适配 + OKF 解析 + 规则切页(守卫式导入)。"""
|