hubrelay 0.2.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.
Files changed (44) hide show
  1. hubrelay-0.2.0/LICENSE +21 -0
  2. hubrelay-0.2.0/PKG-INFO +126 -0
  3. hubrelay-0.2.0/README.md +105 -0
  4. hubrelay-0.2.0/hubrelay.egg-info/PKG-INFO +126 -0
  5. hubrelay-0.2.0/hubrelay.egg-info/SOURCES.txt +42 -0
  6. hubrelay-0.2.0/hubrelay.egg-info/dependency_links.txt +1 -0
  7. hubrelay-0.2.0/hubrelay.egg-info/entry_points.txt +2 -0
  8. hubrelay-0.2.0/hubrelay.egg-info/top_level.txt +1 -0
  9. hubrelay-0.2.0/pyproject.toml +30 -0
  10. hubrelay-0.2.0/relayhub/__init__.py +7 -0
  11. hubrelay-0.2.0/relayhub/backup.py +91 -0
  12. hubrelay-0.2.0/relayhub/gateway/__init__.py +52 -0
  13. hubrelay-0.2.0/relayhub/gateway/__main__.py +1278 -0
  14. hubrelay-0.2.0/relayhub/gateway/admin.py +2211 -0
  15. hubrelay-0.2.0/relayhub/gateway/audit.py +64 -0
  16. hubrelay-0.2.0/relayhub/gateway/clients.py +171 -0
  17. hubrelay-0.2.0/relayhub/gateway/conformance.py +469 -0
  18. hubrelay-0.2.0/relayhub/gateway/discovery.py +164 -0
  19. hubrelay-0.2.0/relayhub/gateway/localscan.py +209 -0
  20. hubrelay-0.2.0/relayhub/gateway/pairing.py +263 -0
  21. hubrelay-0.2.0/relayhub/gateway/policy.py +196 -0
  22. hubrelay-0.2.0/relayhub/gateway/pool.py +562 -0
  23. hubrelay-0.2.0/relayhub/gateway/reqlog.py +177 -0
  24. hubrelay-0.2.0/relayhub/gateway/router.py +405 -0
  25. hubrelay-0.2.0/relayhub/gateway/service.py +1987 -0
  26. hubrelay-0.2.0/relayhub/gateway/tokens.py +440 -0
  27. hubrelay-0.2.0/relayhub/gateway/upstream.py +919 -0
  28. hubrelay-0.2.0/relayhub/gateway/users.py +401 -0
  29. hubrelay-0.2.0/relayhub/paths.py +109 -0
  30. hubrelay-0.2.0/setup.cfg +4 -0
  31. hubrelay-0.2.0/tests/test_admin.py +486 -0
  32. hubrelay-0.2.0/tests/test_admin_console.py +149 -0
  33. hubrelay-0.2.0/tests/test_audit.py +44 -0
  34. hubrelay-0.2.0/tests/test_discovery.py +118 -0
  35. hubrelay-0.2.0/tests/test_gateway.py +790 -0
  36. hubrelay-0.2.0/tests/test_localscan.py +199 -0
  37. hubrelay-0.2.0/tests/test_multimodal.py +137 -0
  38. hubrelay-0.2.0/tests/test_pairing.py +344 -0
  39. hubrelay-0.2.0/tests/test_policy.py +159 -0
  40. hubrelay-0.2.0/tests/test_pool.py +1181 -0
  41. hubrelay-0.2.0/tests/test_pool_tiers.py +171 -0
  42. hubrelay-0.2.0/tests/test_reqlog.py +146 -0
  43. hubrelay-0.2.0/tests/test_tokens.py +283 -0
  44. hubrelay-0.2.0/tests/test_users.py +247 -0
hubrelay-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 relay-hub contributors
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,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: hubrelay
3
+ Version: 0.2.0
4
+ Summary: Self-hosted LLM relay/gateway for LAN: multi-upstream key pool, downstream tokens, usage accounting, conformance probing (局域网大模型中转站)
5
+ License: MIT
6
+ Keywords: llm,gateway,relay,proxy,openai,anthropic,one-api,self-hosted,ollama,lm-studio,api-gateway,key-pool,chatgpt-proxy,localai,中转站,大模型
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: System :: Networking
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ # relay-hub · 局域网/自托管大模型中转站
23
+
24
+ [![CI](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml/badge.svg)](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml)
25
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
26
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)
27
+ ![Dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)
28
+
29
+ A self-hosted LLM relay/gateway for your LAN: multi-upstream key pool, downstream
30
+ tokens, usage accounting, circuit breaking, and conformance probing. Pure Python
31
+ standard library — no third-party runtime dependencies.
32
+
33
+ 一个自托管的大模型中转站:把多家上游(官方 API Key、本地自托管推理服务)统一成一个
34
+ OpenAI/Anthropic 兼容入口,带号池调度、下游令牌、用量记账、分级熔断和一致性探测。
35
+ 纯 Python 标准库实现,零第三方运行时依赖。
36
+
37
+ ## 功能 Features
38
+
39
+ - **上游号池** Upstream key pool:多渠道轮询/最少失败/额度感知调度,优先级与权重,
40
+ 四档分级冷却(额度耗尽 / 限流 / 5xx / 鉴权失效),热加载。
41
+ - **下游令牌** Downstream tokens:per-device 令牌(对标 one-api 的「令牌」),模型白名单、
42
+ RPM/每日限额、用量记账,明文只在发放时出现一次。
43
+ - **双协议入口** Dual protocol:`POST /v1/messages`(Anthropic)与
44
+ `POST /v1/chat/completions`(OpenAI),同一令牌两种鉴权头都认。
45
+ - **配对发放** Pairing:带外配对码(成功即焚、限次)+ 可选的局域网免码配对。
46
+ - **管理控制台** Admin console:本地网页,管理渠道/令牌/策略/请求明细/用量/审计。
47
+ - **一致性探测** Conformance probe:对着任意兼容网关跑合规探测,抓出不合规实现。
48
+ - **请求审计** Request audit:控制面操作审计与请求明细(脱敏)。
49
+
50
+ ## 特色 Highlights
51
+
52
+ - **三层防环路** Loop protection:转发链路标识(`Via` / `X-Relay-Hub-Hops` /
53
+ `X-Request-ID`,逐跳累加,本站实例标记一现即判环)+ 入口请求内容指纹在飞计数 +
54
+ 出口「同指纹 × 同上游」时间窗查重。就算中间隔了会改写参数的第三方网关也能兜住,
55
+ 专治「上游指回自己」的拓扑环。
56
+ - **语义指纹应答缓存** Response cache:非流式 200 应答按语义指纹缓存 5 分钟——指纹只含
57
+ 模型、规范化 messages、tools、采样参数等语义字段,绝不混入链路标识/鉴权/时间戳
58
+ (否则永不命中);按调用者隔离,不跨用户串答案;命中即回、不触上游、不预扣额度。
59
+ - **缓存记账** Cache accounting:上游 usage 中的缓存命中量(Anthropic 的
60
+ `cache_read/cache_creation_input_tokens`、OpenAI 的 `cached_tokens` 折算)记入
61
+ 渠道用量与请求明细,管理控制台直接可见。
62
+ - **额度预扣与多退少补** Pre-consume:绑定用户的请求先按输入体量预估冻结额度,
63
+ 完工后按实际用量结算,上游失败全额退——堵「发大 prompt 中途断开白嫖上游」的洞。
64
+ - **排队而非硬拒** Concurrency gate:并发满员进入 VIP/普通双等待池排队(优先名单
65
+ 设备/IP 插队),队满或超时才 429;叠加单 IP 与令牌双层 RPM 限流。
66
+ - **本机推理服务扫描** Local scan:Ollama / LM Studio / vLLM / llama.cpp 等一键扫进号池,
67
+ 与官方 API 渠道同权参与调度、熔断与记账。
68
+
69
+ ## 快速开始 Quick Start
70
+
71
+ > ⚠️ **注意**:PyPI 上的 `relay-hub` 是**别人的同名项目**,与本仓库无关,请勿 `pip install relay-hub`。
72
+ > 本项目在 PyPI 上的分发名是 **`hubrelay`**。
73
+
74
+ ```bash
75
+ pip install hubrelay # PyPI 安装(推荐)
76
+ # 或源码安装:pip install git+https://github.com/bilibiliUID1480494301/relay-hub.git
77
+
78
+ # 1) 建号池并添加一个上游 Key
79
+ python -m relayhub.gateway pool init
80
+ python -m relayhub.gateway pool add --base-url https://api.example.com \
81
+ --api-key sk-xxx --protocol openai-chat --model my-model
82
+
83
+ # 2) 启动中转站
84
+ python -m relayhub.gateway serve --pool pool.json --api-key rh_master
85
+
86
+ # 3)(可选)本地网页控制台
87
+ python -m relayhub.gateway admin
88
+ ```
89
+
90
+ 更多子命令(`token` / `clients` / `pair` / `audit` / `check` / `scan` / `requests` /
91
+ `usage`)见各自主命令的 `--help`。See each subcommand's `--help` for details.
92
+
93
+ ## 运行环境 Requirements
94
+
95
+ - Python 3.10+(仅标准库)
96
+ - Windows / macOS / Linux
97
+
98
+ ## 免责声明 Disclaimer
99
+
100
+ > **中文**:本项目仅供学习、研究与个人自托管用途。使用者应自行确保其使用行为符合
101
+ > 所在地区法律法规,以及其接入的上游服务的用户协议与服务条款。本项目按「现状」提供,
102
+ > 不附带任何明示或暗示的担保;作者不对任何人因使用本项目而产生的直接或间接损失负责。
103
+ > 请勿将本项目用于任何违反上游服务条款或损害第三方权益的用途,由此产生的一切风险与
104
+ > 责任由使用者自行承担。
105
+ >
106
+ > **English**: This project is provided for learning, research, and personal
107
+ > self-hosting purposes only. You are solely responsible for ensuring that your
108
+ > use complies with applicable laws and regulations in your jurisdiction as well
109
+ > as the terms of service of any upstream services you connect to. The software
110
+ > is provided "AS IS", without warranty of any kind. In no event shall the
111
+ > authors be liable for any claim, damages, or other liability arising from the
112
+ > use of this software. Any risk arising from use in violation of upstream terms
113
+ > of service rests solely with the user.
114
+
115
+ ## 安全须知 Security Notes
116
+
117
+ - 上游 Key 以明文 JSON 存放在本地号池文件中(与常见客户端做法一致);请自行做好
118
+ 文件权限与磁盘加密,**不要**把号池文件提交进版本库或分享给他人。
119
+ - 绑定非回环地址(公网/局域网)前,网关强制要求已配置凭证(master Key 或下游令牌),
120
+ 且所有流量都必须携带凭证。
121
+ - 管理控制台默认只监听回环地址;绑非回环地址必须显式提供 `--token`。
122
+ - 遇到疑似密钥泄露请立即吊销(`token rm` / 更换上游 Key)。
123
+
124
+ ## 许可证 License
125
+
126
+ [MIT](./LICENSE)
@@ -0,0 +1,105 @@
1
+ # relay-hub · 局域网/自托管大模型中转站
2
+
3
+ [![CI](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml/badge.svg)](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
5
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)
6
+ ![Dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)
7
+
8
+ A self-hosted LLM relay/gateway for your LAN: multi-upstream key pool, downstream
9
+ tokens, usage accounting, circuit breaking, and conformance probing. Pure Python
10
+ standard library — no third-party runtime dependencies.
11
+
12
+ 一个自托管的大模型中转站:把多家上游(官方 API Key、本地自托管推理服务)统一成一个
13
+ OpenAI/Anthropic 兼容入口,带号池调度、下游令牌、用量记账、分级熔断和一致性探测。
14
+ 纯 Python 标准库实现,零第三方运行时依赖。
15
+
16
+ ## 功能 Features
17
+
18
+ - **上游号池** Upstream key pool:多渠道轮询/最少失败/额度感知调度,优先级与权重,
19
+ 四档分级冷却(额度耗尽 / 限流 / 5xx / 鉴权失效),热加载。
20
+ - **下游令牌** Downstream tokens:per-device 令牌(对标 one-api 的「令牌」),模型白名单、
21
+ RPM/每日限额、用量记账,明文只在发放时出现一次。
22
+ - **双协议入口** Dual protocol:`POST /v1/messages`(Anthropic)与
23
+ `POST /v1/chat/completions`(OpenAI),同一令牌两种鉴权头都认。
24
+ - **配对发放** Pairing:带外配对码(成功即焚、限次)+ 可选的局域网免码配对。
25
+ - **管理控制台** Admin console:本地网页,管理渠道/令牌/策略/请求明细/用量/审计。
26
+ - **一致性探测** Conformance probe:对着任意兼容网关跑合规探测,抓出不合规实现。
27
+ - **请求审计** Request audit:控制面操作审计与请求明细(脱敏)。
28
+
29
+ ## 特色 Highlights
30
+
31
+ - **三层防环路** Loop protection:转发链路标识(`Via` / `X-Relay-Hub-Hops` /
32
+ `X-Request-ID`,逐跳累加,本站实例标记一现即判环)+ 入口请求内容指纹在飞计数 +
33
+ 出口「同指纹 × 同上游」时间窗查重。就算中间隔了会改写参数的第三方网关也能兜住,
34
+ 专治「上游指回自己」的拓扑环。
35
+ - **语义指纹应答缓存** Response cache:非流式 200 应答按语义指纹缓存 5 分钟——指纹只含
36
+ 模型、规范化 messages、tools、采样参数等语义字段,绝不混入链路标识/鉴权/时间戳
37
+ (否则永不命中);按调用者隔离,不跨用户串答案;命中即回、不触上游、不预扣额度。
38
+ - **缓存记账** Cache accounting:上游 usage 中的缓存命中量(Anthropic 的
39
+ `cache_read/cache_creation_input_tokens`、OpenAI 的 `cached_tokens` 折算)记入
40
+ 渠道用量与请求明细,管理控制台直接可见。
41
+ - **额度预扣与多退少补** Pre-consume:绑定用户的请求先按输入体量预估冻结额度,
42
+ 完工后按实际用量结算,上游失败全额退——堵「发大 prompt 中途断开白嫖上游」的洞。
43
+ - **排队而非硬拒** Concurrency gate:并发满员进入 VIP/普通双等待池排队(优先名单
44
+ 设备/IP 插队),队满或超时才 429;叠加单 IP 与令牌双层 RPM 限流。
45
+ - **本机推理服务扫描** Local scan:Ollama / LM Studio / vLLM / llama.cpp 等一键扫进号池,
46
+ 与官方 API 渠道同权参与调度、熔断与记账。
47
+
48
+ ## 快速开始 Quick Start
49
+
50
+ > ⚠️ **注意**:PyPI 上的 `relay-hub` 是**别人的同名项目**,与本仓库无关,请勿 `pip install relay-hub`。
51
+ > 本项目在 PyPI 上的分发名是 **`hubrelay`**。
52
+
53
+ ```bash
54
+ pip install hubrelay # PyPI 安装(推荐)
55
+ # 或源码安装:pip install git+https://github.com/bilibiliUID1480494301/relay-hub.git
56
+
57
+ # 1) 建号池并添加一个上游 Key
58
+ python -m relayhub.gateway pool init
59
+ python -m relayhub.gateway pool add --base-url https://api.example.com \
60
+ --api-key sk-xxx --protocol openai-chat --model my-model
61
+
62
+ # 2) 启动中转站
63
+ python -m relayhub.gateway serve --pool pool.json --api-key rh_master
64
+
65
+ # 3)(可选)本地网页控制台
66
+ python -m relayhub.gateway admin
67
+ ```
68
+
69
+ 更多子命令(`token` / `clients` / `pair` / `audit` / `check` / `scan` / `requests` /
70
+ `usage`)见各自主命令的 `--help`。See each subcommand's `--help` for details.
71
+
72
+ ## 运行环境 Requirements
73
+
74
+ - Python 3.10+(仅标准库)
75
+ - Windows / macOS / Linux
76
+
77
+ ## 免责声明 Disclaimer
78
+
79
+ > **中文**:本项目仅供学习、研究与个人自托管用途。使用者应自行确保其使用行为符合
80
+ > 所在地区法律法规,以及其接入的上游服务的用户协议与服务条款。本项目按「现状」提供,
81
+ > 不附带任何明示或暗示的担保;作者不对任何人因使用本项目而产生的直接或间接损失负责。
82
+ > 请勿将本项目用于任何违反上游服务条款或损害第三方权益的用途,由此产生的一切风险与
83
+ > 责任由使用者自行承担。
84
+ >
85
+ > **English**: This project is provided for learning, research, and personal
86
+ > self-hosting purposes only. You are solely responsible for ensuring that your
87
+ > use complies with applicable laws and regulations in your jurisdiction as well
88
+ > as the terms of service of any upstream services you connect to. The software
89
+ > is provided "AS IS", without warranty of any kind. In no event shall the
90
+ > authors be liable for any claim, damages, or other liability arising from the
91
+ > use of this software. Any risk arising from use in violation of upstream terms
92
+ > of service rests solely with the user.
93
+
94
+ ## 安全须知 Security Notes
95
+
96
+ - 上游 Key 以明文 JSON 存放在本地号池文件中(与常见客户端做法一致);请自行做好
97
+ 文件权限与磁盘加密,**不要**把号池文件提交进版本库或分享给他人。
98
+ - 绑定非回环地址(公网/局域网)前,网关强制要求已配置凭证(master Key 或下游令牌),
99
+ 且所有流量都必须携带凭证。
100
+ - 管理控制台默认只监听回环地址;绑非回环地址必须显式提供 `--token`。
101
+ - 遇到疑似密钥泄露请立即吊销(`token rm` / 更换上游 Key)。
102
+
103
+ ## 许可证 License
104
+
105
+ [MIT](./LICENSE)
@@ -0,0 +1,126 @@
1
+ Metadata-Version: 2.4
2
+ Name: hubrelay
3
+ Version: 0.2.0
4
+ Summary: Self-hosted LLM relay/gateway for LAN: multi-upstream key pool, downstream tokens, usage accounting, conformance probing (局域网大模型中转站)
5
+ License: MIT
6
+ Keywords: llm,gateway,relay,proxy,openai,anthropic,one-api,self-hosted,ollama,lm-studio,api-gateway,key-pool,chatgpt-proxy,localai,中转站,大模型
7
+ Classifier: Development Status :: 4 - Beta
8
+ Classifier: Intended Audience :: Developers
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: 3.10
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Topic :: System :: Networking
16
+ Classifier: Topic :: Software Development :: Libraries
17
+ Requires-Python: >=3.10
18
+ Description-Content-Type: text/markdown
19
+ License-File: LICENSE
20
+ Dynamic: license-file
21
+
22
+ # relay-hub · 局域网/自托管大模型中转站
23
+
24
+ [![CI](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml/badge.svg)](https://github.com/bilibiliUID1480494301/relay-hub/actions/workflows/ci.yml)
25
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
26
+ ![Python](https://img.shields.io/badge/python-3.10%2B-blue.svg)
27
+ ![Dependencies](https://img.shields.io/badge/dependencies-none-brightgreen.svg)
28
+
29
+ A self-hosted LLM relay/gateway for your LAN: multi-upstream key pool, downstream
30
+ tokens, usage accounting, circuit breaking, and conformance probing. Pure Python
31
+ standard library — no third-party runtime dependencies.
32
+
33
+ 一个自托管的大模型中转站:把多家上游(官方 API Key、本地自托管推理服务)统一成一个
34
+ OpenAI/Anthropic 兼容入口,带号池调度、下游令牌、用量记账、分级熔断和一致性探测。
35
+ 纯 Python 标准库实现,零第三方运行时依赖。
36
+
37
+ ## 功能 Features
38
+
39
+ - **上游号池** Upstream key pool:多渠道轮询/最少失败/额度感知调度,优先级与权重,
40
+ 四档分级冷却(额度耗尽 / 限流 / 5xx / 鉴权失效),热加载。
41
+ - **下游令牌** Downstream tokens:per-device 令牌(对标 one-api 的「令牌」),模型白名单、
42
+ RPM/每日限额、用量记账,明文只在发放时出现一次。
43
+ - **双协议入口** Dual protocol:`POST /v1/messages`(Anthropic)与
44
+ `POST /v1/chat/completions`(OpenAI),同一令牌两种鉴权头都认。
45
+ - **配对发放** Pairing:带外配对码(成功即焚、限次)+ 可选的局域网免码配对。
46
+ - **管理控制台** Admin console:本地网页,管理渠道/令牌/策略/请求明细/用量/审计。
47
+ - **一致性探测** Conformance probe:对着任意兼容网关跑合规探测,抓出不合规实现。
48
+ - **请求审计** Request audit:控制面操作审计与请求明细(脱敏)。
49
+
50
+ ## 特色 Highlights
51
+
52
+ - **三层防环路** Loop protection:转发链路标识(`Via` / `X-Relay-Hub-Hops` /
53
+ `X-Request-ID`,逐跳累加,本站实例标记一现即判环)+ 入口请求内容指纹在飞计数 +
54
+ 出口「同指纹 × 同上游」时间窗查重。就算中间隔了会改写参数的第三方网关也能兜住,
55
+ 专治「上游指回自己」的拓扑环。
56
+ - **语义指纹应答缓存** Response cache:非流式 200 应答按语义指纹缓存 5 分钟——指纹只含
57
+ 模型、规范化 messages、tools、采样参数等语义字段,绝不混入链路标识/鉴权/时间戳
58
+ (否则永不命中);按调用者隔离,不跨用户串答案;命中即回、不触上游、不预扣额度。
59
+ - **缓存记账** Cache accounting:上游 usage 中的缓存命中量(Anthropic 的
60
+ `cache_read/cache_creation_input_tokens`、OpenAI 的 `cached_tokens` 折算)记入
61
+ 渠道用量与请求明细,管理控制台直接可见。
62
+ - **额度预扣与多退少补** Pre-consume:绑定用户的请求先按输入体量预估冻结额度,
63
+ 完工后按实际用量结算,上游失败全额退——堵「发大 prompt 中途断开白嫖上游」的洞。
64
+ - **排队而非硬拒** Concurrency gate:并发满员进入 VIP/普通双等待池排队(优先名单
65
+ 设备/IP 插队),队满或超时才 429;叠加单 IP 与令牌双层 RPM 限流。
66
+ - **本机推理服务扫描** Local scan:Ollama / LM Studio / vLLM / llama.cpp 等一键扫进号池,
67
+ 与官方 API 渠道同权参与调度、熔断与记账。
68
+
69
+ ## 快速开始 Quick Start
70
+
71
+ > ⚠️ **注意**:PyPI 上的 `relay-hub` 是**别人的同名项目**,与本仓库无关,请勿 `pip install relay-hub`。
72
+ > 本项目在 PyPI 上的分发名是 **`hubrelay`**。
73
+
74
+ ```bash
75
+ pip install hubrelay # PyPI 安装(推荐)
76
+ # 或源码安装:pip install git+https://github.com/bilibiliUID1480494301/relay-hub.git
77
+
78
+ # 1) 建号池并添加一个上游 Key
79
+ python -m relayhub.gateway pool init
80
+ python -m relayhub.gateway pool add --base-url https://api.example.com \
81
+ --api-key sk-xxx --protocol openai-chat --model my-model
82
+
83
+ # 2) 启动中转站
84
+ python -m relayhub.gateway serve --pool pool.json --api-key rh_master
85
+
86
+ # 3)(可选)本地网页控制台
87
+ python -m relayhub.gateway admin
88
+ ```
89
+
90
+ 更多子命令(`token` / `clients` / `pair` / `audit` / `check` / `scan` / `requests` /
91
+ `usage`)见各自主命令的 `--help`。See each subcommand's `--help` for details.
92
+
93
+ ## 运行环境 Requirements
94
+
95
+ - Python 3.10+(仅标准库)
96
+ - Windows / macOS / Linux
97
+
98
+ ## 免责声明 Disclaimer
99
+
100
+ > **中文**:本项目仅供学习、研究与个人自托管用途。使用者应自行确保其使用行为符合
101
+ > 所在地区法律法规,以及其接入的上游服务的用户协议与服务条款。本项目按「现状」提供,
102
+ > 不附带任何明示或暗示的担保;作者不对任何人因使用本项目而产生的直接或间接损失负责。
103
+ > 请勿将本项目用于任何违反上游服务条款或损害第三方权益的用途,由此产生的一切风险与
104
+ > 责任由使用者自行承担。
105
+ >
106
+ > **English**: This project is provided for learning, research, and personal
107
+ > self-hosting purposes only. You are solely responsible for ensuring that your
108
+ > use complies with applicable laws and regulations in your jurisdiction as well
109
+ > as the terms of service of any upstream services you connect to. The software
110
+ > is provided "AS IS", without warranty of any kind. In no event shall the
111
+ > authors be liable for any claim, damages, or other liability arising from the
112
+ > use of this software. Any risk arising from use in violation of upstream terms
113
+ > of service rests solely with the user.
114
+
115
+ ## 安全须知 Security Notes
116
+
117
+ - 上游 Key 以明文 JSON 存放在本地号池文件中(与常见客户端做法一致);请自行做好
118
+ 文件权限与磁盘加密,**不要**把号池文件提交进版本库或分享给他人。
119
+ - 绑定非回环地址(公网/局域网)前,网关强制要求已配置凭证(master Key 或下游令牌),
120
+ 且所有流量都必须携带凭证。
121
+ - 管理控制台默认只监听回环地址;绑非回环地址必须显式提供 `--token`。
122
+ - 遇到疑似密钥泄露请立即吊销(`token rm` / 更换上游 Key)。
123
+
124
+ ## 许可证 License
125
+
126
+ [MIT](./LICENSE)
@@ -0,0 +1,42 @@
1
+ LICENSE
2
+ README.md
3
+ pyproject.toml
4
+ hubrelay.egg-info/PKG-INFO
5
+ hubrelay.egg-info/SOURCES.txt
6
+ hubrelay.egg-info/dependency_links.txt
7
+ hubrelay.egg-info/entry_points.txt
8
+ hubrelay.egg-info/top_level.txt
9
+ relayhub/__init__.py
10
+ relayhub/backup.py
11
+ relayhub/paths.py
12
+ relayhub/gateway/__init__.py
13
+ relayhub/gateway/__main__.py
14
+ relayhub/gateway/admin.py
15
+ relayhub/gateway/audit.py
16
+ relayhub/gateway/clients.py
17
+ relayhub/gateway/conformance.py
18
+ relayhub/gateway/discovery.py
19
+ relayhub/gateway/localscan.py
20
+ relayhub/gateway/pairing.py
21
+ relayhub/gateway/policy.py
22
+ relayhub/gateway/pool.py
23
+ relayhub/gateway/reqlog.py
24
+ relayhub/gateway/router.py
25
+ relayhub/gateway/service.py
26
+ relayhub/gateway/tokens.py
27
+ relayhub/gateway/upstream.py
28
+ relayhub/gateway/users.py
29
+ tests/test_admin.py
30
+ tests/test_admin_console.py
31
+ tests/test_audit.py
32
+ tests/test_discovery.py
33
+ tests/test_gateway.py
34
+ tests/test_localscan.py
35
+ tests/test_multimodal.py
36
+ tests/test_pairing.py
37
+ tests/test_policy.py
38
+ tests/test_pool.py
39
+ tests/test_pool_tiers.py
40
+ tests/test_reqlog.py
41
+ tests/test_tokens.py
42
+ tests/test_users.py
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ hubrelay = relayhub.gateway.__main__:main
@@ -0,0 +1 @@
1
+ relayhub
@@ -0,0 +1,30 @@
1
+ [project]
2
+ name = "hubrelay"
3
+ version = "0.2.0"
4
+ description = "Self-hosted LLM relay/gateway for LAN: multi-upstream key pool, downstream tokens, usage accounting, conformance probing (局域网大模型中转站)"
5
+ readme = "README.md"
6
+ license = {text = "MIT"}
7
+ requires-python = ">=3.10"
8
+ dependencies = []
9
+ keywords = ["llm", "gateway", "relay", "proxy", "openai", "anthropic", "one-api",
10
+ "self-hosted", "ollama", "lm-studio", "api-gateway", "key-pool",
11
+ "chatgpt-proxy", "localai", "中转站", "大模型"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Intended Audience :: Developers",
15
+ "License :: OSI Approved :: MIT License",
16
+ "Operating System :: OS Independent",
17
+ "Programming Language :: Python :: 3",
18
+ "Programming Language :: Python :: 3.10",
19
+ "Programming Language :: Python :: 3.11",
20
+ "Programming Language :: Python :: 3.12",
21
+ "Topic :: System :: Networking",
22
+ "Topic :: Software Development :: Libraries",
23
+ ]
24
+
25
+ [project.scripts]
26
+ hubrelay = "relayhub.gateway.__main__:main"
27
+
28
+ [tool.pytest.ini_options]
29
+ pythonpath = ["."]
30
+ testpaths = ["tests"]
@@ -0,0 +1,7 @@
1
+ """relay-hub:局域网/自托管大模型中转站。
2
+
3
+ 上游号池(多 Key 轮转、熔断冷却)+ 双协议适配(Anthropic/OpenAI)
4
+ + HTTP 网关服务(鉴权、配对、用量记账)。
5
+ """
6
+
7
+ __version__ = "0.1.0"
@@ -0,0 +1,91 @@
1
+ """写入前的带时间戳备份与回滚。
2
+
3
+ 约定(与 oj 项目一致):时间戳文件名不含冒号,避免 WinError 123。
4
+ """
5
+
6
+ from __future__ import annotations
7
+
8
+ import json
9
+ import shutil
10
+ from dataclasses import dataclass
11
+ from datetime import datetime
12
+ from pathlib import Path
13
+
14
+ STAMP_FMT = "%Y%m%dT%H%M%S"
15
+ MANIFEST_NAME = "manifest.json"
16
+
17
+
18
+ @dataclass(frozen=True)
19
+ class Snapshot:
20
+ snapshot_id: str
21
+ root: Path
22
+
23
+ @property
24
+ def manifest_path(self) -> Path:
25
+ return self.root / self.snapshot_id / MANIFEST_NAME
26
+
27
+ def read_manifest(self) -> dict:
28
+ return json.loads(self.manifest_path.read_text(encoding="utf-8"))
29
+
30
+
31
+ def make_snapshot(paths: list[Path], root: Path) -> Snapshot:
32
+ """把 paths 里存在的文件复制到 <root>/<stamp>/,返回快照句柄。"""
33
+ stamp = datetime.now().strftime(STAMP_FMT)
34
+ target = root / stamp
35
+ # 同一秒内重复快照时避免互相覆盖
36
+ suffix = 1
37
+ while target.exists():
38
+ suffix += 1
39
+ target = root / f"{stamp}-{suffix}"
40
+
41
+ target.mkdir(parents=True, exist_ok=False)
42
+ entries = []
43
+ for src in paths:
44
+ if not src.is_file():
45
+ entries.append({"path": str(src), "existed": False})
46
+ continue
47
+ dst = target / src.name
48
+ shutil.copy2(src, dst)
49
+ entries.append({"path": str(src), "existed": True, "bytes": dst.stat().st_size})
50
+
51
+ manifest = {"created_at": datetime.now().isoformat(timespec="seconds"), "files": entries}
52
+ (target / MANIFEST_NAME).write_text(
53
+ json.dumps(manifest, ensure_ascii=False, indent=2), encoding="utf-8"
54
+ )
55
+ return Snapshot(snapshot_id=target.name, root=root)
56
+
57
+
58
+ def list_snapshots(root: Path) -> list[Snapshot]:
59
+ if not root.is_dir():
60
+ return []
61
+ items = [p for p in root.iterdir() if p.is_dir() and (p / MANIFEST_NAME).is_file()]
62
+ return [Snapshot(snapshot_id=p.name, root=root) for p in sorted(items, reverse=True)]
63
+
64
+
65
+ def latest_snapshot(root: Path) -> Snapshot | None:
66
+ found = list_snapshots(root)
67
+ return found[0] if found else None
68
+
69
+
70
+ def restore(snapshot: Snapshot, dry_run: bool = False) -> list[str]:
71
+ """把快照里的文件写回原位。返回人类可读的操作说明。"""
72
+ lines: list[str] = []
73
+ manifest = snapshot.read_manifest()
74
+ for entry in manifest["files"]:
75
+ dst = Path(entry["path"])
76
+ if not entry.get("existed"):
77
+ if dst.is_file():
78
+ lines.append(f"删除 {dst}(快照时不存在)")
79
+ if not dry_run:
80
+ dst.unlink()
81
+ else:
82
+ lines.append(f"跳过 {dst}(快照时不存在,当前也不存在)")
83
+ continue
84
+ src = snapshot.root / snapshot.snapshot_id / dst.name
85
+ if not src.is_file():
86
+ lines.append(f"缺少备份文件 {src},跳过")
87
+ continue
88
+ lines.append(f"还原 {dst}")
89
+ if not dry_run:
90
+ shutil.copy2(src, dst)
91
+ return lines
@@ -0,0 +1,52 @@
1
+ """中转站层:号池 + 路由 + 参考实现 + 一致性探测器。
2
+
3
+ 真跑中转站用 `KeyPoolRouter`(发真实上游请求);
4
+ `DemoRouter` 只返回固定文本,是测试靶子。
5
+ """
6
+
7
+ from .conformance import CheckResult, Probe, run_checks
8
+ from .pool import (
9
+ PROTOCOL_ANTHROPIC,
10
+ PROTOCOL_OPENAI_CHAT,
11
+ KeyPool,
12
+ PoolError,
13
+ UpstreamKey,
14
+ key_from_spec,
15
+ )
16
+ from .router import KeyPoolRouter, RelayOutcome, RouterError
17
+ from .service import Channel, ChannelPool, DemoRouter, RelayServer, demo_pool, demo_router
18
+ from .upstream import (
19
+ UpstreamError,
20
+ UpstreamReply,
21
+ call_once,
22
+ normalize_base,
23
+ stream_events,
24
+ to_anthropic_request,
25
+ )
26
+
27
+ __all__ = [
28
+ "PROTOCOL_ANTHROPIC",
29
+ "PROTOCOL_OPENAI_CHAT",
30
+ "Channel",
31
+ "ChannelPool",
32
+ "CheckResult",
33
+ "DemoRouter",
34
+ "KeyPool",
35
+ "KeyPoolRouter",
36
+ "PoolError",
37
+ "Probe",
38
+ "RelayOutcome",
39
+ "RelayServer",
40
+ "RouterError",
41
+ "UpstreamError",
42
+ "UpstreamKey",
43
+ "UpstreamReply",
44
+ "call_once",
45
+ "demo_pool",
46
+ "demo_router",
47
+ "key_from_spec",
48
+ "normalize_base",
49
+ "run_checks",
50
+ "stream_events",
51
+ "to_anthropic_request",
52
+ ]