yuanbot-cli 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,4 @@
1
+ # YuanBot CLI — 安装引导工具
2
+ #
3
+ # 这是一个轻量级独立包,仅包含安装和版本检查功能。
4
+ # 完整 YuanBot 通过 `yuanbot install` 自动部署。
@@ -0,0 +1,4 @@
1
+ from yuanbot_cli.cli import main
2
+
3
+ if __name__ == "__main__":
4
+ main()
yuanbot_cli/cli.py ADDED
@@ -0,0 +1,338 @@
1
+ """YuanBot CLI — 安装引导工具
2
+
3
+ 用法:
4
+ yuanbot install 全自动交互式安装 YuanBot
5
+ yuanbot install --help 查看帮助
6
+ yuanbot version 查看版本
7
+ """
8
+
9
+ from __future__ import annotations
10
+
11
+ import argparse
12
+ import os
13
+ import shutil
14
+ import subprocess
15
+ import sys
16
+ from pathlib import Path
17
+
18
+
19
+ # ── ANSI 颜色 ──────────────────────────────
20
+
21
+ _CYAN = "\033[36m"
22
+ _GREEN = "\033[32m"
23
+ _YELLOW = "\033[33m"
24
+ _RED = "\033[31m"
25
+ _BOLD = "\033[1m"
26
+ _DIM = "\033[2m"
27
+ _RESET = "\033[0m"
28
+
29
+
30
+ def _c(text: str, color: str) -> str:
31
+ if not sys.stderr.isatty():
32
+ return text
33
+ return f"{color}{text}{_RESET}"
34
+
35
+
36
+ def _header(title: str) -> None:
37
+ print(f"\n {_c('==', _CYAN + _BOLD)} {title}")
38
+
39
+
40
+ def _ok(msg: str) -> None:
41
+ print(f" {_c('✅', '')} {msg}")
42
+
43
+
44
+ def _fail(msg: str) -> None:
45
+ print(f" {_c('❌', '')} {_c(msg, _RED)}")
46
+
47
+
48
+ def _warn(msg: str) -> None:
49
+ print(f" {_c('⚠️', '')} {_c(msg, _YELLOW)}")
50
+
51
+
52
+ def _info(msg: str) -> None:
53
+ print(f" {_c('ℹ️', '')} {msg}")
54
+
55
+
56
+ # ── 核心安装逻辑 ──────────────────────────
57
+
58
+ VERSION = "1.0.0"
59
+ REPO_URL = "https://github.com/Grabrun/YuanBot.git"
60
+ MIN_PYTHON = (3, 12)
61
+
62
+ # 支持的 AI 提供商
63
+ PROVIDERS = {
64
+ "deepseek": {
65
+ "name": "DeepSeek",
66
+ "file": "deepseek.yaml",
67
+ "model": "deepseek-v4-flash",
68
+ "key_hint": "sk-...",
69
+ },
70
+ "openai": {
71
+ "name": "OpenAI",
72
+ "file": "openai.yaml",
73
+ "model": "gpt-5.5",
74
+ "key_hint": "sk-...",
75
+ },
76
+ "anthropic": {
77
+ "name": "Anthropic Claude",
78
+ "file": "anthropic.yaml",
79
+ "model": "claude-sonnet-4-6",
80
+ "key_hint": "sk-ant-...",
81
+ },
82
+ }
83
+
84
+
85
+ def _run_install(args: argparse.Namespace) -> None:
86
+ """全自动安装 YuanBot"""
87
+
88
+ provider_id: str | None = args.provider
89
+ api_key: str | None = args.api_key
90
+ non_interactive: bool = args.non_interactive
91
+
92
+ # ── 1. 欢迎 ─────────────────────────
93
+ print()
94
+ print(f" {_c('🌸 YuanBot 安装程序', _CYAN + _BOLD)}")
95
+ print(f" {_c('版本', _DIM)} {VERSION}")
96
+ print(f" {_c('—' * 40, _DIM)}")
97
+ print()
98
+
99
+ # ── 2. Python 版本 ───────────────────
100
+ _header("环境检查")
101
+ if sys.version_info < MIN_PYTHON:
102
+ _fail(f"需要 Python 3.12+,当前 {sys.version_info.major}.{sys.version_info.minor}")
103
+ sys.exit(1)
104
+ _ok(f"Python {sys.version_info.major}.{sys.version_info.minor}.{sys.version_info.micro}")
105
+
106
+ if not shutil.which("git"):
107
+ _warn("未检测到 git,将跳过版本控制")
108
+ else:
109
+ _ok("git 已安装")
110
+ print()
111
+
112
+ # ── 3. 确定安装目录 ─────────────────
113
+ _header("安装位置")
114
+ target_dir: Path
115
+ if args.dir:
116
+ target_dir = Path(args.dir).resolve()
117
+ target_dir.mkdir(parents=True, exist_ok=True)
118
+ _info(f"目标目录: {target_dir}")
119
+ else:
120
+ target_dir = Path.cwd() / "YuanBot"
121
+ _info(f"默认目录: {target_dir}")
122
+
123
+ # 检查是否已存在
124
+ is_existing = (target_dir / "pyproject.toml").exists() and (target_dir / "src" / "yuanbot").exists()
125
+ if is_existing:
126
+ if args.force:
127
+ _warn("目录已有 YuanBot 项目,--force 模式下将覆盖安装")
128
+ else:
129
+ _info("检测到已有 YuanBot 项目")
130
+ answer = input(f" {_c('?', _CYAN)} 是否重新安装?(y/N): ").strip().lower()
131
+ if answer not in ("y", "yes"):
132
+ _info("已取消")
133
+ return
134
+ print()
135
+
136
+ # ── 4. 克隆/更新代码 ────────────────
137
+ _header("获取代码")
138
+ if target_dir.exists() and is_existing:
139
+ _info("拉取最新代码...")
140
+ subprocess.run(["git", "pull"], cwd=target_dir, capture_output=True)
141
+ _ok("代码已更新")
142
+ else:
143
+ _info(f"正在从 GitHub 克隆...")
144
+ result = subprocess.run(
145
+ ["git", "clone", "--depth=1", REPO_URL, str(target_dir)],
146
+ capture_output=True, text=True,
147
+ )
148
+ if result.returncode != 0:
149
+ _fail(f"克隆失败: {result.stderr.strip()}")
150
+ sys.exit(1)
151
+ _ok("代码已下载")
152
+ print()
153
+
154
+ # ── 5. 创建虚拟环境 ─────────────────
155
+ _header("虚拟环境")
156
+ venv_path = target_dir / ".venv"
157
+ if not venv_path.exists():
158
+ _info("创建中...")
159
+ result = subprocess.run(
160
+ [sys.executable, "-m", "venv", str(venv_path)],
161
+ capture_output=True, text=True,
162
+ )
163
+ if result.returncode != 0:
164
+ _fail(f"创建失败: {result.stderr.strip()}")
165
+ sys.exit(1)
166
+ _ok(".venv 已创建")
167
+ else:
168
+ _ok(".venv 已存在")
169
+
170
+ # venv 里的 python/pip
171
+ if sys.platform == "win32":
172
+ py_venv = venv_path / "Scripts" / "python"
173
+ pip_venv = venv_path / "Scripts" / "pip"
174
+ else:
175
+ py_venv = venv_path / "bin" / "python"
176
+ pip_venv = venv_path / "bin" / "pip"
177
+ print()
178
+
179
+ # ── 6. 安装依赖 ─────────────────────
180
+ _header("安装依赖")
181
+ _info("正在安装 YuanBot (这可能需要几分钟)...")
182
+ result = subprocess.run(
183
+ [str(pip_venv), "install", "-e", str(target_dir)],
184
+ capture_output=True, text=True, timeout=300,
185
+ )
186
+ if result.returncode != 0:
187
+ _warn(f"安装输出: {result.stderr[-200:]}")
188
+ # 额外安装开发依赖
189
+ subprocess.run(
190
+ [str(pip_venv), "install", "-e", str(target_dir) + "[dev]"],
191
+ capture_output=True, timeout=300,
192
+ )
193
+ _ok("YuanBot 已安装")
194
+ print()
195
+
196
+ # ── 7. 初始化配置 ───────────────────
197
+ _header("初始化配置")
198
+ result = subprocess.run(
199
+ [str(py_venv), "-m", "yuanbot.cli", "config", "init"],
200
+ capture_output=True, text=True, cwd=target_dir,
201
+ )
202
+ if result.returncode == 0:
203
+ _ok("配置模板已生成")
204
+ else:
205
+ _warn(f"config init 输出: {result.stderr[-200:]}")
206
+ print()
207
+
208
+ # ── 8. 配置 AI 提供商 ───────────────
209
+ if not non_interactive and not (provider_id and api_key):
210
+ _header("AI 提供商")
211
+ print(f" {_c('选择 AI 提供商:', _BOLD)}")
212
+ choices = list(PROVIDERS.keys())
213
+ for i, pid in enumerate(choices, 1):
214
+ p = PROVIDERS[pid]
215
+ print(f" {i}. {p['name']} ({p['model']})")
216
+ print(f" {len(choices) + 1}. 稍后手动配置")
217
+
218
+ try:
219
+ sel = input(f"\n {_c('?', _CYAN)} 请选择 [1-{len(choices) + 1}] (默认 1): ").strip()
220
+ if not sel or sel == "1":
221
+ provider_id = "deepseek"
222
+ else:
223
+ idx = int(sel) - 1
224
+ provider_id = choices[idx] if 0 <= idx < len(choices) else None
225
+ except (ValueError, IndexError):
226
+ provider_id = None
227
+
228
+ if provider_id:
229
+ p = PROVIDERS[provider_id]
230
+ api_key = input(f" {_c('?', _CYAN)} 输入 {p['name']} API Key (如 {p['key_hint']}): ").strip()
231
+
232
+ if provider_id and api_key:
233
+ _header("写入配置")
234
+ p = PROVIDERS[provider_id]
235
+
236
+ # 写 API Key 到 provider 配置
237
+ provider_path = target_dir / "configs" / "Providers" / p["file"]
238
+ if provider_path.exists():
239
+ import yaml # type: ignore[import-untyped]
240
+ with open(provider_path) as f:
241
+ cfg = yaml.safe_load(f) or {}
242
+ cfg.setdefault("config", {})["api_key"] = api_key
243
+ cfg["enabled"] = True
244
+ with open(provider_path, "w") as f:
245
+ yaml.safe_dump(cfg, f, allow_unicode=True, default_flow_style=False)
246
+ _ok(f"API Key 已配置到 {p['file']}")
247
+
248
+ # 写默认提供商到 bot.yaml
249
+ bot_path = target_dir / "configs" / "bot.yaml"
250
+ if bot_path.exists():
251
+ import yaml
252
+ with open(bot_path) as f:
253
+ bot_cfg = yaml.safe_load(f) or {}
254
+ bot_cfg.setdefault("ai", {})["default_provider"] = provider_id
255
+ bot_cfg["ai"]["default_model"] = p["model"]
256
+ with open(bot_path, "w") as f:
257
+ yaml.safe_dump(bot_cfg, f, allow_unicode=True, default_flow_style=False)
258
+ _ok(f"默认提供商设为 {p['name']}")
259
+
260
+ print()
261
+
262
+ # ── 9. 运行诊断 ─────────────────────
263
+ _header("运行诊断")
264
+ subprocess.run(
265
+ [str(py_venv), "-m", "yuanbot.cli", "doctor"],
266
+ cwd=target_dir,
267
+ )
268
+ print()
269
+
270
+ # ── 10. 完成 ─────────────────────────
271
+ if sys.platform == "win32":
272
+ activate_cmd = f"{venv_path}\\Scripts\\activate"
273
+ else:
274
+ activate_cmd = f"source {venv_path / 'bin' / 'activate'}"
275
+
276
+ print(f" {_c('🎉 YuanBot 安装成功!', _GREEN + _BOLD)}")
277
+ print()
278
+ _info(f"安装目录: {target_dir}")
279
+ print()
280
+ _header("下一步")
281
+ print(f" {_c(activate_cmd, _CYAN)} # 激活虚拟环境")
282
+ print(f" {_c('yuanbot start', _CYAN)} # 启动服务")
283
+ print(f" {_c('yuanbot tui', _CYAN)} # 终端聊天")
284
+ print(f" 打开 {_c('http://localhost:8000', _CYAN)} # WebUI")
285
+ print()
286
+ _info(f"📖 文档: https://grabrun.github.io/YuanBot")
287
+ print()
288
+
289
+
290
+ # ── CLI 入口 ──────────────────────────────
291
+
292
+
293
+ def main() -> None:
294
+ parser = argparse.ArgumentParser(
295
+ prog="yuanbot",
296
+ description="YuanBot 安装引导工具 — 一行命令部署 AI 虚拟伴侣",
297
+ )
298
+ parser.add_argument(
299
+ "-v", "--version",
300
+ action="version",
301
+ version=f"yuanbot-cli {VERSION}",
302
+ help="显示版本号",
303
+ )
304
+
305
+ sub = parser.add_subparsers(dest="command")
306
+
307
+ # yuanbot install
308
+ install_parser = sub.add_parser("install", help="全自动安装 YuanBot")
309
+ install_parser.add_argument(
310
+ "--dir", default="",
311
+ help="安装目录(默认当前目录下的 YuanBot/)",
312
+ )
313
+ install_parser.add_argument(
314
+ "--provider", default=None,
315
+ help="AI 提供商 (deepseek/openai/anthropic)",
316
+ )
317
+ install_parser.add_argument(
318
+ "--api-key", default=None,
319
+ help="API Key",
320
+ )
321
+ install_parser.add_argument(
322
+ "--non-interactive", action="store_true",
323
+ help="非交互式安装(需同时指定 --provider 和 --api-key)",
324
+ )
325
+ install_parser.add_argument(
326
+ "--force", action="store_true",
327
+ help="强制重新安装",
328
+ )
329
+
330
+ # yuanbot version
331
+ sub.add_parser("version", help="显示版本号")
332
+
333
+ args = parser.parse_args()
334
+
335
+ if args.command == "install":
336
+ _run_install(args)
337
+ else:
338
+ parser.print_help()
@@ -0,0 +1,123 @@
1
+ Metadata-Version: 2.4
2
+ Name: yuanbot-cli
3
+ Version: 1.0.0
4
+ Summary: YuanBot 安装引导工具 — 一行命令部署 YuanBot AI 虚拟伴侣
5
+ Project-URL: Homepage, https://grabrun.github.io/YuanBot
6
+ Project-URL: Repository, https://github.com/Grabrun/YuanBot
7
+ Project-URL: Documentation, https://grabrun.github.io/YuanBot/guide/getting-started
8
+ Author-email: Grabrun <grabrun@users.noreply.github.com>
9
+ License: MIT
10
+ Keywords: ai,chatbot,companion,installer,yuanbot
11
+ Classifier: Development Status :: 4 - Beta
12
+ Classifier: Environment :: Console
13
+ Classifier: Intended Audience :: Developers
14
+ Classifier: Intended Audience :: End Users/Desktop
15
+ Classifier: License :: OSI Approved :: MIT License
16
+ Classifier: Natural Language :: Chinese (Simplified)
17
+ Classifier: Natural Language :: English
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.12
21
+ Classifier: Programming Language :: Python :: 3.13
22
+ Classifier: Topic :: Utilities
23
+ Requires-Python: >=3.12
24
+ Provides-Extra: dev
25
+ Requires-Dist: build>=1.0; extra == 'dev'
26
+ Requires-Dist: twine>=4.0; extra == 'dev'
27
+ Description-Content-Type: text/markdown
28
+
29
+ # yuanbot-cli
30
+
31
+ > YuanBot 安装引导工具 — 一行命令部署完整的 [YuanBot](https://github.com/Grabrun/YuanBot) AI 虚拟伴侣。
32
+
33
+ ```bash
34
+ pip install yuanbot-cli
35
+ yuanbot install
36
+ ```
37
+
38
+ ## 这是什么
39
+
40
+ `yuanbot-cli` 是一个**轻量级安装器**,只有一个任务:帮你把完整的 YuanBot 部署到本地。
41
+
42
+ 你只需要安装这一个 100KB 的小包,然后 `yuanbot install` 就会自动完成剩下的所有事情:
43
+
44
+ 1. ✅ 检查 Python 3.12+ 环境
45
+ 2. ✅ 从 GitHub 克隆最新代码
46
+ 3. ✅ 创建虚拟环境
47
+ 4. ✅ 安装 YuanBot 及其依赖
48
+ 5. ✅ 生成初始配置
49
+ 6. ✅ 交互式配置 AI 提供商和 API Key
50
+ 7. ✅ 运行系统诊断验证
51
+ 8. ✅ 打印下一步指引
52
+
53
+ ## 快速开始
54
+
55
+ ```bash
56
+ # 1. 安装
57
+ pip install yuanbot-cli
58
+
59
+ # 2. 全自动安装 YuanBot
60
+ yuanbot install
61
+
62
+ # 3. 根据提示选择 AI 提供商并输入 API Key
63
+
64
+ # 4. 安装完成后
65
+ cd YuanBot
66
+ source .venv/bin/activate
67
+ yuanbot start
68
+ ```
69
+
70
+ ## 非交互式安装
71
+
72
+ 适合 Docker 和自动化脚本:
73
+
74
+ ```bash
75
+ pip install yuanbot-cli
76
+ yuanbot install \
77
+ --provider deepseek \
78
+ --api-key "sk-..." \
79
+ --non-interactive
80
+ ```
81
+
82
+ ## 指定安装目录
83
+
84
+ ```bash
85
+ yuanbot install --dir /opt/yuanbot
86
+ ```
87
+
88
+ ## 工作原理
89
+
90
+ ```
91
+ yuanbot install
92
+
93
+ ├── git clone https://github.com/Grabrun/YuanBot.git
94
+ ├── python -m venv .venv
95
+ ├── pip install -e .[dev] ← 这里安装完整的 yuanbot 包
96
+ ├── yuanbot config init
97
+ ├── 配置 AI 提供商 + API Key
98
+ └── yuanbot doctor ← 验证安装
99
+ ```
100
+
101
+ 安装完成后,完整的 `yuanbot` 命令(包含 start/tui/webui/doctor 等所有功能)会在虚拟环境中可用。
102
+
103
+ ## 与完整 yuanbot 包的关系
104
+
105
+ | | yuanbot-cli | yuanbot (完整版) |
106
+ |---|---|---|
107
+ | 大小 | ~100KB | ~10MB (含依赖) |
108
+ | 安装方式 | `pip install yuanbot-cli` | 由 `yuanbot install` 自动安装 |
109
+ | 命令 | `install`, `version` | `start`, `tui`, `doctor`, `config`, `provider`, `persona`, ... |
110
+ | 用途 | 安装引导 | 日常使用 |
111
+
112
+ ## 发布到 PyPI
113
+
114
+ ```bash
115
+ pip install build twine
116
+ cd yuanbot-cli
117
+ python -m build
118
+ twine upload dist/*
119
+ ```
120
+
121
+ ## License
122
+
123
+ MIT
@@ -0,0 +1,7 @@
1
+ yuanbot_cli/__init__.py,sha256=glfFmbhEeABhBICj79j08KnOAAGcLD6Cgb2QoaLEJTY,172
2
+ yuanbot_cli/__main__.py,sha256=eLHNITuzlCTtK4YqyDDZvFyCmpxw85VzCF6KRJrylUU,72
3
+ yuanbot_cli/cli.py,sha256=FvsH4mnsaIPMo2NZV0ilqCdIGVqvXW9QrUtQUApUJUE,11089
4
+ yuanbot_cli-1.0.0.dist-info/METADATA,sha256=CIUClQVKpwmG9YQQJplHeSz_VCRenZ2uQ80HAGUK4mY,3340
5
+ yuanbot_cli-1.0.0.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
6
+ yuanbot_cli-1.0.0.dist-info/entry_points.txt,sha256=nXH4qBd5EpCwgyTwlvrZ1T-fMNGBAG2HBz4As442WGo,49
7
+ yuanbot_cli-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.30.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,2 @@
1
+ [console_scripts]
2
+ yuanbot = yuanbot_cli.cli:main