mirror of
https://github.com/csunny/DB-GPT.git
synced 2025-07-27 13:57:46 +00:00
720 lines
29 KiB
Python
Executable File
720 lines
29 KiB
Python
Executable File
#!/usr/bin/env python
|
||
# /// script
|
||
# dependencies = [
|
||
# "tomli",
|
||
# "click",
|
||
# "inquirer",
|
||
# ]
|
||
# [tool.uv]
|
||
# exclude-newer = "2025-03-07T00:00:00Z"
|
||
# ///
|
||
import os
|
||
import tomli
|
||
import glob
|
||
import click
|
||
import inquirer
|
||
from pathlib import Path
|
||
from typing import Dict, Any
|
||
|
||
|
||
# For I18N support, we use a simple class to store translations and a global instance
|
||
# to access it.
|
||
class I18N:
|
||
# Define supported languages in current install help script
|
||
SUPPORTED_LANGUAGES = ["en", "zh"]
|
||
|
||
# The translation dictionary contains a mapping from language code to a dictionary
|
||
TRANSLATIONS = {
|
||
"en": {
|
||
# Common
|
||
"workspace_not_found": "Workspace root not found.",
|
||
"cannot_parse": "Cannot parse {}: {}",
|
||
"no_extras_defined": "No extras defined",
|
||
"no_extras_found": "No workspace or extras found.",
|
||
"operation_canceled": "Operation canceled.",
|
||
"available_packages": "Available packages: {}",
|
||
"copy_command": "Please copy the above command to execute in terminal. For more help, run:",
|
||
"finished": "Finished!",
|
||
# Description of the CLI command
|
||
"cli_description": "UV Workspace Extras Helper - Manage optional dependencies in UV workspace",
|
||
"list_cmd_description": "List all extras in the workspace",
|
||
"install_cmd_description": "Generate installation commands for extras",
|
||
"deploy_cmd_description": "Use predefined deployment templates",
|
||
# Option descriptions
|
||
"verbose_option": "Show detailed dependency information",
|
||
"interactive_option": "Interactive guide to generate installation commands",
|
||
"all_option": "Generate command to install all extras",
|
||
"china_option": "Use Tsinghua PyPI mirror for faster installation in China",
|
||
"preset_option": "Use predefined deployment template",
|
||
"list_presets_option": "List all predefined deployment templates",
|
||
"language_option": "Specify language (en/zh)",
|
||
# List command
|
||
"extras_in_workspace": "Extras in workspace:\n",
|
||
"available_extras": "Available extras:",
|
||
"dependencies": "dependencies",
|
||
# Installation command
|
||
"install_all_extras": "# Install all optional features:",
|
||
"install_extras_for": "# Install {} feature for {}:",
|
||
"package_not_in_workspace": "Error: Package '{}' not in workspace or has no extras defined.",
|
||
"package_no_extras": "Package '{}' has no extras defined.",
|
||
"extra_not_in_package": "Error: Extra '{}' not found in package '{}'.",
|
||
"available_extras_in_package": "Available extras: {}",
|
||
# Interactive installation
|
||
"welcome": "Welcome to DB-GPT Installation Assistant!",
|
||
"help_message": "This tool will help you generate the correct installation commands.\n",
|
||
"select_mode": "Please select installation mode",
|
||
"select_extras": "Please select extras to install (space to select/deselect, enter to confirm)",
|
||
"installation_info": "📋 Installation Information",
|
||
"selected_mode": "📦 Selected mode: {}",
|
||
"description": "📝 Description: {}",
|
||
"note": "ℹ️ Note: {}",
|
||
"will_install": "🧩 Will install the following extras: {}",
|
||
"config_file": "⚙️ Configuration file: {}",
|
||
"generate_command": "Generate installation command?",
|
||
"installation_command": "🚀 Installation Command",
|
||
"startup_command": "🏃 Startup Command",
|
||
"further_configuration": "⚠️ Further Configuration",
|
||
"set_api_key": "Please make sure you set the correct API Key in the configuration file {}",
|
||
"set_model_path": "Please make sure you set the correct model path in the configuration file {}",
|
||
# Deployment command
|
||
"available_presets": "Available deployment presets:",
|
||
"specify_preset": "Please specify a deployment preset name, or use --list to view all presets",
|
||
"preset_not_found": "Error: Preset '{}' not found",
|
||
"available_presets_list": "Available presets: {}",
|
||
"using_preset": "Using preset '{}' to generate deployment command",
|
||
# Preset descriptions
|
||
"openai_preset": "OpenAI Proxy Mode",
|
||
"openai_desc": "Using OpenAI API as proxy, suitable for environments without GPU",
|
||
"openai_note": "Requires OpenAI API Key",
|
||
"deepseek_preset": "DeepSeek Proxy Mode",
|
||
"deepseek_desc": "Using DeepSeek API as proxy, suitable for environments without GPU",
|
||
"deepseek_note": "Requires DeepSeek API Key",
|
||
"glm4_preset": "GLM4 Local Mode",
|
||
"glm4_desc": "Using local GLM4 model, requires GPU environment",
|
||
"glm4_note": "Requires local model path configuration",
|
||
"vllm_preset": "VLLM Local Mode",
|
||
"vllm_desc": "Using VLLM framework to load local model, requires GPU environment",
|
||
"vllm_note": "Requires local model path configuration",
|
||
"llama_cpp_preset": "LLAMA_CPP Local Mode",
|
||
"llama_cpp_desc": "Using LLAMA.cpp framework to load local model, can run on CPU but GPU recommended",
|
||
"llama_cpp_note": 'Requires local model path configuration, for CUDA support set CMAKE_ARGS="-DGGML_CUDA=ON"',
|
||
"ollama_preset": "Ollama Proxy Mode",
|
||
"ollama_desc": "Using Ollama as proxy, suitable for environments without GPU",
|
||
"ollama_note": "Requires Ollama API Base",
|
||
"custom_preset": "Custom Mode",
|
||
"custom_desc": "Manually select needed extras",
|
||
"custom_note": "Suitable for advanced users",
|
||
},
|
||
"zh": {
|
||
# Common
|
||
"workspace_not_found": "未找到工作区根目录",
|
||
"cannot_parse": "无法解析 {}: {}",
|
||
"no_extras_defined": "没有定义 extras",
|
||
"no_extras_found": "未找到工作区或没有可选依赖。",
|
||
"operation_canceled": "操作已取消。",
|
||
"available_packages": "可用的包: {}",
|
||
"copy_command": "请复制上面的命令到终端执行。如需更多帮助,请运行:",
|
||
"finished": "完成!",
|
||
# Description of the CLI command
|
||
"cli_description": "UV Workspace Extras Helper - 管理UV工作区的可选依赖",
|
||
"list_cmd_description": "列出工作区中的所有extras",
|
||
"install_cmd_description": "生成安装extras的命令",
|
||
"deploy_cmd_description": "使用预设的部署方案",
|
||
# Option descriptions
|
||
"verbose_option": "显示详细依赖信息",
|
||
"interactive_option": "交互式引导生成安装命令",
|
||
"all_option": "生成安装所有extras的命令",
|
||
"china_option": "使用清华pip镜像源加速安装",
|
||
"preset_option": "使用预设的部署方案",
|
||
"list_presets_option": "列出所有预设部署方案",
|
||
"language_option": "指定语言 (en/zh)",
|
||
# List command
|
||
"extras_in_workspace": "工作区中的可选依赖 (extras):\n",
|
||
"available_extras": "可用的 extras:",
|
||
"dependencies": "个依赖",
|
||
# Installation command
|
||
"install_all_extras": "# 安装所有可选功能:",
|
||
"install_extras_for": "# 安装 {} 的 {} 功能:",
|
||
"package_not_in_workspace": "错误: 包 '{}' 不在工作区中或没有定义extras。",
|
||
"package_no_extras": "包 '{}' 没有定义extras。",
|
||
"extra_not_in_package": "错误: 包 '{}' 中没有名为 '{}' 的extra。",
|
||
"available_extras_in_package": "可用的extras: {}",
|
||
# Interactive installation
|
||
"welcome": "欢迎使用 DB-GPT 安装引导助手!",
|
||
"help_message": "这个工具将帮助你生成正确的安装命令。\n",
|
||
"select_mode": "请选择安装模式",
|
||
"select_extras": "请选择需要安装的extras(空格选择/取消,回车确认)",
|
||
"installation_info": "📋 安装信息",
|
||
"selected_mode": "📦 选择的模式: {}",
|
||
"description": "📝 描述: {}",
|
||
"note": "ℹ️ 注意事项: {}",
|
||
"will_install": "🧩 将安装以下extras: {}",
|
||
"config_file": "⚙️ 配置文件: {}",
|
||
"generate_command": "是否生成安装命令?",
|
||
"installation_command": "🚀 安装命令",
|
||
"startup_command": "🏃 启动命令",
|
||
"further_configuration": "⚠️ 后续配置",
|
||
"set_api_key": "请确保在配置文件 {} 中设置了正确的API Key",
|
||
"set_model_path": "请确保在配置文件 {} 中设置了正确的模型路径",
|
||
# Deployment command
|
||
"available_presets": "可用的部署预设:",
|
||
"specify_preset": "请指定部署预设名称,或使用 --list 查看所有预设",
|
||
"preset_not_found": "错误: 未找到预设 '{}'",
|
||
"available_presets_list": "可用的预设: {}",
|
||
"using_preset": "使用预设 '{}' 生成部署命令",
|
||
# Preset descriptions
|
||
"openai_preset": "OpenAI 代理模式",
|
||
"openai_desc": "使用OpenAI API作为代理,适合无GPU环境",
|
||
"openai_note": "需要提供OpenAI API Key",
|
||
"deepseek_preset": "DeepSeek 代理模式",
|
||
"deepseek_desc": "使用DeepSeek API作为代理,适合无GPU环境",
|
||
"deepseek_note": "需要提供DeepSeek API Key",
|
||
"glm4_preset": "GLM4 本地模式",
|
||
"glm4_desc": "使用本地GLM4模型,需要GPU环境",
|
||
"glm4_note": "需要配置本地模型路径",
|
||
"vllm_preset": "VLLM 本地模式",
|
||
"vllm_desc": "使用VLLM框架加载本地模型,需要GPU环境",
|
||
"vllm_note": "需要配置本地模型路径",
|
||
"llama_cpp_preset": "LLAMA_CPP 本地模式",
|
||
"llama_cpp_desc": "使用LLAMA.cpp框架加载本地模型,CPU也可运行但推荐GPU",
|
||
"llama_cpp_note": '需要配置本地模型路径,启用CUDA需设置CMAKE_ARGS="-DGGML_CUDA=ON"',
|
||
"ollama_preset": "Ollama 代理模式",
|
||
"ollama_desc": "使用Ollama作为代理,适合无GPU环境",
|
||
"ollama_note": "需要提供Ollama API Base",
|
||
"custom_preset": "自定义模式",
|
||
"custom_desc": "手动选择需要的extras",
|
||
"custom_note": "适合高级用户",
|
||
},
|
||
}
|
||
|
||
def __init__(self, lang=None):
|
||
"""Initialize the I18N instance with the specified language"""
|
||
# If language is not specified, try to get from environment
|
||
if not lang:
|
||
try:
|
||
import locale
|
||
|
||
try:
|
||
# First try to get the locale from the environment
|
||
lang = locale.getlocale()[0]
|
||
except (AttributeError, ValueError):
|
||
try:
|
||
lang = locale.getdefaultlocale()[0]
|
||
except (AttributeError, ValueError):
|
||
lang = "en"
|
||
|
||
if lang:
|
||
lang = lang.split("_")[0]
|
||
else:
|
||
lang = "en"
|
||
except (ImportError, AttributeError, ValueError):
|
||
lang = "en"
|
||
|
||
# If the language is not supported, default to English
|
||
if lang not in self.SUPPORTED_LANGUAGES:
|
||
lang = "en"
|
||
|
||
self.lang = lang
|
||
|
||
def get(self, key):
|
||
"""Get the translation for the specified key"""
|
||
return self.TRANSLATIONS.get(self.lang, {}).get(key, key)
|
||
|
||
|
||
i18n = I18N()
|
||
|
||
|
||
def set_language(lang):
|
||
"""Set the global language for the script"""
|
||
global i18n
|
||
i18n = I18N(lang)
|
||
|
||
|
||
def extract_workspace_extras():
|
||
"""Determine the workspace root and extract extras dependencies for all packages"""
|
||
# First locate the workspace root (directory containing pyproject.toml with
|
||
# tool.uv.workspace)
|
||
current_dir = os.getcwd()
|
||
workspace_root = None
|
||
|
||
# Find the workspace root
|
||
while current_dir != os.path.dirname(current_dir): # Stop at root
|
||
pyproject_path = os.path.join(current_dir, "pyproject.toml")
|
||
if os.path.exists(pyproject_path):
|
||
try:
|
||
with open(pyproject_path, "rb") as f:
|
||
pyproject_data = tomli.load(f)
|
||
if pyproject_data.get("tool", {}).get("uv", {}).get("workspace"):
|
||
workspace_root = current_dir
|
||
break
|
||
except Exception as e:
|
||
print(i18n.get("cannot_parse").format(pyproject_path, e))
|
||
current_dir = os.path.dirname(current_dir)
|
||
|
||
if not workspace_root:
|
||
print(i18n.get("workspace_not_found"))
|
||
return {}
|
||
|
||
# Read the workspace configuration
|
||
with open(os.path.join(workspace_root, "pyproject.toml"), "rb") as f:
|
||
root_data = tomli.load(f)
|
||
|
||
workspace_config = root_data.get("tool", {}).get("uv", {}).get("workspace", {})
|
||
members_patterns = workspace_config.get("members", [])
|
||
exclude_patterns = workspace_config.get("exclude", [])
|
||
|
||
# Extract all member packages
|
||
member_dirs = []
|
||
for pattern in members_patterns:
|
||
# Convert glob pattern to absolute path
|
||
full_pattern = os.path.join(workspace_root, pattern)
|
||
matches = glob.glob(full_pattern, recursive=True)
|
||
|
||
for match in matches:
|
||
if os.path.isdir(match) and os.path.exists(
|
||
os.path.join(match, "pyproject.toml")
|
||
):
|
||
# Check if the directory should be excluded
|
||
should_exclude = False
|
||
for exclude_pattern in exclude_patterns:
|
||
if Path(match).match(os.path.join(workspace_root, exclude_pattern)):
|
||
should_exclude = True
|
||
break
|
||
|
||
if not should_exclude:
|
||
member_dirs.append(match)
|
||
|
||
# Add the workspace root as a member package
|
||
member_dirs.append(workspace_root)
|
||
|
||
# Extract extras for each member package
|
||
all_extras = {}
|
||
|
||
for member_dir in member_dirs:
|
||
member_path = os.path.join(member_dir, "pyproject.toml")
|
||
try:
|
||
with open(member_path, "rb") as f:
|
||
member_data = tomli.load(f)
|
||
|
||
project_name = member_data.get("project", {}).get(
|
||
"name", os.path.basename(member_dir)
|
||
)
|
||
optional_deps = member_data.get("project", {}).get(
|
||
"optional-dependencies", {}
|
||
)
|
||
|
||
if optional_deps:
|
||
all_extras[project_name] = {
|
||
"path": member_dir,
|
||
"extras": list(optional_deps.keys()),
|
||
"details": optional_deps,
|
||
}
|
||
|
||
except Exception as e:
|
||
print(i18n.get("cannot_parse").format(member_path, e))
|
||
|
||
return all_extras
|
||
|
||
|
||
# Preset deployment templates
|
||
def get_deployment_presets():
|
||
"""Get localized deployment presets"""
|
||
return {
|
||
i18n.get("openai_preset"): {
|
||
"extras": ["base", "proxy_openai", "rag", "storage_chromadb", "dbgpts"],
|
||
"config": "configs/dbgpt-proxy-openai.toml",
|
||
"description": i18n.get("openai_desc"),
|
||
"note": i18n.get("openai_note"),
|
||
},
|
||
i18n.get("deepseek_preset"): {
|
||
"extras": ["base", "proxy_openai", "rag", "storage_chromadb", "dbgpts"],
|
||
"config": "configs/dbgpt-proxy-deepseek.toml",
|
||
"description": i18n.get("deepseek_desc"),
|
||
"note": i18n.get("deepseek_note"),
|
||
},
|
||
i18n.get("glm4_preset"): {
|
||
"extras": [
|
||
"base",
|
||
"hf",
|
||
"cuda121",
|
||
"rag",
|
||
"storage_chromadb",
|
||
"quant_bnb",
|
||
"dbgpts",
|
||
],
|
||
"config": "configs/dbgpt-local-glm.toml",
|
||
"description": i18n.get("glm4_desc"),
|
||
"note": i18n.get("glm4_note"),
|
||
},
|
||
i18n.get("vllm_preset"): {
|
||
"extras": [
|
||
"base",
|
||
"hf",
|
||
"cuda121",
|
||
"vllm",
|
||
"rag",
|
||
"storage_chromadb",
|
||
"quant_bnb",
|
||
"dbgpts",
|
||
],
|
||
"config": "configs/dbgpt-local-vllm.toml",
|
||
"description": i18n.get("vllm_desc"),
|
||
"note": i18n.get("vllm_note"),
|
||
},
|
||
i18n.get("llama_cpp_preset"): {
|
||
"extras": [
|
||
"base",
|
||
"hf",
|
||
"cuda121",
|
||
"llama_cpp",
|
||
"rag",
|
||
"storage_chromadb",
|
||
"quant_bnb",
|
||
"dbgpts",
|
||
],
|
||
"config": "configs/dbgpt-local-llama-cpp.toml",
|
||
"description": i18n.get("llama_cpp_desc"),
|
||
"note": i18n.get("llama_cpp_note"),
|
||
},
|
||
i18n.get("ollama_preset"): {
|
||
"extras": ["base", "proxy_ollama", "rag", "storage_chromadb", "dbgpts"],
|
||
"config": "configs/dbgpt-proxy-ollama.toml",
|
||
"description": i18n.get("ollama_desc"),
|
||
"note": i18n.get("ollama_note"),
|
||
},
|
||
i18n.get("custom_preset"): {
|
||
"extras": [],
|
||
"config": "",
|
||
"description": i18n.get("custom_desc"),
|
||
"note": i18n.get("custom_note"),
|
||
},
|
||
}
|
||
|
||
|
||
@click.group()
|
||
@click.option(
|
||
"--language",
|
||
"-l",
|
||
type=click.Choice(["en", "zh"]),
|
||
help=I18N().get("language_option"),
|
||
)
|
||
def cli(language):
|
||
"""UV Workspace Extras Helper - Manage optional dependencies in UV workspace"""
|
||
if language:
|
||
set_language(language)
|
||
# Update command descriptions to the current language
|
||
cli.help = i18n.get("cli_description")
|
||
list_extras.help = i18n.get("list_cmd_description")
|
||
install_command.help = i18n.get("install_cmd_description")
|
||
deploy_preset.help = i18n.get("deploy_cmd_description")
|
||
|
||
|
||
@cli.command("list")
|
||
@click.option("--verbose", "-v", is_flag=True, help=i18n.get("verbose_option"))
|
||
def list_extras(verbose):
|
||
"""List all extras in the workspace"""
|
||
extras = extract_workspace_extras()
|
||
|
||
if not extras:
|
||
click.echo(i18n.get("no_extras_found"))
|
||
return
|
||
|
||
click.echo(i18n.get("extras_in_workspace"))
|
||
|
||
for package, info in extras.items():
|
||
click.echo(
|
||
click.style(f"📦 {package}", fg="green")
|
||
+ click.style(f" ({os.path.relpath(info['path'])})", fg="blue")
|
||
)
|
||
|
||
if info["extras"]:
|
||
click.echo(f" {i18n.get('available_extras')}")
|
||
for extra in info["extras"]:
|
||
deps = info["details"][extra]
|
||
click.echo(
|
||
f" - {click.style(extra, fg='yellow')}: {len(deps)} {i18n.get('dependencies')}"
|
||
)
|
||
|
||
if verbose:
|
||
for dep in deps:
|
||
click.echo(f" • {dep}")
|
||
else:
|
||
click.echo(f" {i18n.get('no_extras_defined')}")
|
||
click.echo()
|
||
|
||
|
||
@cli.command("install-cmd")
|
||
@click.option("--interactive", "-i", is_flag=True, help=i18n.get("interactive_option"))
|
||
@click.option("--all", "install_all", is_flag=True, help=i18n.get("all_option"))
|
||
@click.option("--china", is_flag=True, help=i18n.get("china_option"))
|
||
@click.argument("package", required=False)
|
||
@click.argument("extra", required=False)
|
||
def install_command(interactive, install_all, china, package, extra):
|
||
"""Generate installation commands for extras"""
|
||
extras = extract_workspace_extras()
|
||
|
||
if not extras:
|
||
click.echo(i18n.get("no_extras_found"))
|
||
return
|
||
|
||
# Interactive mode
|
||
if interactive:
|
||
_interactive_install_guide(extras, china)
|
||
return
|
||
|
||
# Install all extras
|
||
if install_all:
|
||
all_extras = []
|
||
for pkg_info in extras.values():
|
||
all_extras.extend(pkg_info["extras"])
|
||
|
||
if all_extras:
|
||
cmd = "uv sync --all-packages " + " ".join(
|
||
[f'--extra "{e}"' for e in all_extras]
|
||
)
|
||
if china:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
click.echo(i18n.get("install_all_extras"))
|
||
click.echo(cmd)
|
||
else:
|
||
click.echo(i18n.get("no_extras_found"))
|
||
return
|
||
|
||
# If no package or extra is provided, show all possible installation commands
|
||
if not package:
|
||
for pkg, info in extras.items():
|
||
if info["extras"]:
|
||
for e in info["extras"]:
|
||
cmd = f'uv sync --extra "{e}"'
|
||
if china:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
click.echo(i18n.get("install_extras_for").format(pkg, e))
|
||
click.echo(cmd)
|
||
click.echo()
|
||
return
|
||
|
||
# Check if the specified package exists
|
||
if package not in extras:
|
||
click.echo(i18n.get("package_not_in_workspace").format(package))
|
||
click.echo(i18n.get("available_packages").format(", ".join(extras.keys())))
|
||
return
|
||
|
||
# If no extra is provided, show all extras for the package
|
||
if not extra:
|
||
pkg_extras = extras[package]["extras"]
|
||
if not pkg_extras:
|
||
click.echo(i18n.get("package_no_extras").format(package))
|
||
return
|
||
|
||
cmd = "uv sync " + " ".join([f'--extra "{e}"' for e in pkg_extras])
|
||
if china:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
click.echo(i18n.get("install_extras_for").format(package, " ".join(pkg_extras)))
|
||
click.echo(cmd)
|
||
return
|
||
|
||
# Check if the specified extra exists
|
||
if extra not in extras[package]["extras"]:
|
||
click.echo(i18n.get("extra_not_in_package").format(extra, package))
|
||
click.echo(
|
||
i18n.get("available_extras_in_package").format(
|
||
", ".join(extras[package]["extras"])
|
||
)
|
||
)
|
||
return
|
||
|
||
# Show the command to install the specified extra
|
||
cmd = f'uv sync --extra "{extra}"'
|
||
if china:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
click.echo(i18n.get("install_extras_for").format(package, extra))
|
||
click.echo(cmd)
|
||
|
||
|
||
def _interactive_install_guide(extras: Dict[str, Any], use_china_mirror: bool = False):
|
||
"""Interactive installation guide"""
|
||
click.echo(click.style(i18n.get("welcome"), fg="green", bold=True))
|
||
click.echo(i18n.get("help_message"))
|
||
|
||
# Get deployment presets
|
||
deployment_presets = get_deployment_presets()
|
||
|
||
# First step: select installation mode
|
||
questions = [
|
||
inquirer.List(
|
||
"preset",
|
||
message=i18n.get("select_mode"),
|
||
choices=[
|
||
(f"{name} - {info['description']}", name)
|
||
for name, info in deployment_presets.items()
|
||
],
|
||
carousel=True,
|
||
)
|
||
]
|
||
answers = inquirer.prompt(questions)
|
||
|
||
if not answers:
|
||
return # Operation canceled
|
||
|
||
selected_preset = answers["preset"]
|
||
preset_info = deployment_presets[selected_preset]
|
||
|
||
# Custom mode: let user select extras
|
||
if selected_preset == i18n.get("custom_preset"):
|
||
# Collect all available extras
|
||
all_available_extras = set()
|
||
for pkg_info in extras.values():
|
||
all_available_extras.update(pkg_info["extras"])
|
||
|
||
questions = [
|
||
inquirer.Checkbox(
|
||
"selected_extras",
|
||
message=i18n.get("select_extras"),
|
||
choices=sorted(list(all_available_extras)),
|
||
carousel=True,
|
||
)
|
||
]
|
||
answers = inquirer.prompt(questions)
|
||
|
||
if not answers or not answers["selected_extras"]:
|
||
click.echo(i18n.get("operation_canceled"))
|
||
return
|
||
|
||
preset_info["extras"] = answers["selected_extras"]
|
||
|
||
# Show installation information
|
||
click.echo("\n" + click.style(i18n.get("installation_info"), fg="blue", bold=True))
|
||
click.echo(
|
||
f"{i18n.get('selected_mode')} {click.style(selected_preset, fg='green')}"
|
||
)
|
||
click.echo(f"{i18n.get('description')} {preset_info['description']}")
|
||
click.echo(f"{i18n.get('note')} {preset_info['note']}")
|
||
click.echo(f"{i18n.get('will_install')} {', '.join(preset_info['extras'])}")
|
||
|
||
if preset_info["config"]:
|
||
click.echo(f"{i18n.get('config_file')} {preset_info['config']}")
|
||
|
||
# Confirm installation
|
||
questions = [
|
||
inquirer.Confirm("confirm", message=i18n.get("generate_command"), default=True)
|
||
]
|
||
answers = inquirer.prompt(questions)
|
||
|
||
if not answers or not answers["confirm"]:
|
||
click.echo(i18n.get("operation_canceled"))
|
||
return
|
||
|
||
# Create installation command
|
||
cmd = "uv sync --all-packages " + " ".join(
|
||
[f'--extra "{e}"' for e in preset_info["extras"]]
|
||
)
|
||
if use_china_mirror:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
|
||
click.echo(
|
||
"\n" + click.style(i18n.get("installation_command"), fg="green", bold=True)
|
||
)
|
||
click.echo(cmd)
|
||
|
||
if preset_info.get("config"):
|
||
click.echo(
|
||
"\n" + click.style(i18n.get("startup_command"), fg="green", bold=True)
|
||
)
|
||
click.echo(f"uv run dbgpt start webserver --config {preset_info['config']}")
|
||
|
||
# The step to configure the API key or model path
|
||
if (
|
||
i18n.get("openai_note") in preset_info["note"]
|
||
or i18n.get("deepseek_note") in preset_info["note"]
|
||
):
|
||
click.echo(
|
||
"\n"
|
||
+ click.style(i18n.get("further_configuration"), fg="yellow", bold=True)
|
||
)
|
||
if (
|
||
i18n.get("openai_note") in preset_info["note"]
|
||
or i18n.get("deepseek_note") in preset_info["note"]
|
||
):
|
||
click.echo(i18n.get("set_api_key").format(preset_info["config"]))
|
||
elif (
|
||
i18n.get("glm4_note") in preset_info["note"]
|
||
or i18n.get("vllm_note") in preset_info["note"]
|
||
or i18n.get("llama_cpp_note") in preset_info["note"]
|
||
):
|
||
click.echo(
|
||
"\n"
|
||
+ click.style(i18n.get("further_configuration"), fg="yellow", bold=True)
|
||
)
|
||
if (
|
||
i18n.get("glm4_note") in preset_info["note"]
|
||
or i18n.get("vllm_note") in preset_info["note"]
|
||
or i18n.get("llama_cpp_note") in preset_info["note"]
|
||
):
|
||
click.echo(i18n.get("set_model_path").format(preset_info["config"]))
|
||
|
||
click.echo("\n" + click.style(f"🎉 {i18n.get('finished')}", fg="green", bold=True))
|
||
click.echo(i18n.get("copy_command"))
|
||
click.echo("uv run install_help.py --help")
|
||
|
||
|
||
@cli.command("deploy")
|
||
@click.option("--preset", "-p", help=i18n.get("preset_option"))
|
||
@click.option("--china", is_flag=True, help=i18n.get("china_option"))
|
||
@click.option(
|
||
"--list", "list_presets", is_flag=True, help=i18n.get("list_presets_option")
|
||
)
|
||
def deploy_preset(preset, china, list_presets):
|
||
"""Use predefined deployment templates"""
|
||
deployment_presets = get_deployment_presets()
|
||
|
||
if list_presets:
|
||
click.echo(click.style(i18n.get("available_presets"), fg="green", bold=True))
|
||
for name, info in deployment_presets.items():
|
||
click.echo(f"\n{click.style(name, fg='yellow', bold=True)}")
|
||
click.echo(f"{i18n.get('description')} {info['description']}")
|
||
click.echo(f"{i18n.get('note')} {info['note']}")
|
||
click.echo(f"Extras: {', '.join(info['extras'])}")
|
||
if info["config"]:
|
||
click.echo(f"{i18n.get('config_file')} {info['config']}")
|
||
return
|
||
|
||
if not preset:
|
||
click.echo(i18n.get("specify_preset"))
|
||
return
|
||
|
||
if preset not in deployment_presets:
|
||
click.echo(i18n.get("preset_not_found").format(preset))
|
||
click.echo(
|
||
i18n.get("available_presets_list").format(
|
||
", ".join(deployment_presets.keys())
|
||
)
|
||
)
|
||
return
|
||
|
||
preset_info = deployment_presets[preset]
|
||
|
||
click.echo(i18n.get("using_preset").format(preset))
|
||
click.echo(f"{i18n.get('description')} {preset_info['description']}")
|
||
click.echo(f"{i18n.get('note')} {preset_info['note']}")
|
||
|
||
cmd = "uv sync --all-packages " + " ".join(
|
||
[f'--extra "{e}"' for e in preset_info["extras"]]
|
||
)
|
||
if china:
|
||
cmd += " --index-url=https://pypi.tuna.tsinghua.edu.cn/simple"
|
||
|
||
click.echo(
|
||
"\n" + click.style(i18n.get("installation_command"), fg="green", bold=True)
|
||
)
|
||
click.echo(cmd)
|
||
|
||
if preset_info.get("config"):
|
||
click.echo(
|
||
"\n" + click.style(i18n.get("startup_command"), fg="green", bold=True)
|
||
)
|
||
click.echo(f"uv run dbgpt start webserver --config {preset_info['config']}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
cli()
|