Spaces:
Runtime error
Runtime error
lcolok
commited on
Commit
·
c5f093a
1
Parent(s):
dca8a47
Optimize Docker launcher's i18n setup, environment handling, and add automatic temp folder generation (#193)
Browse files* feat: Create TEMP_DIR if it doesn't exist
* chore: Update Docker Compose configuration and Dockerfile for MindSearch Docker launcher
* feat: Update Docker Compose configuration and Dockerfile modifying logic
* feat: Add new translations for current containers stop failure and container stopped and removed
* feat: Update Docker Compose configuration and Dockerfile for MindSearch Docker launcher
- docker/msdl/__main__.py +5 -0
- docker/msdl/docker_manager.py +63 -23
- docker/msdl/i18n.py +13 -9
- docker/msdl/translations/en.yaml +8 -0
- docker/msdl/translations/zh_CN.yaml +8 -0
- docker/msdl/utils.py +9 -0
- docker/setup.py +1 -0
docker/msdl/__main__.py
CHANGED
@@ -162,6 +162,11 @@ def main():
|
|
162 |
signal.signal(signal.SIGTERM, signal_handler)
|
163 |
|
164 |
try:
|
|
|
|
|
|
|
|
|
|
|
165 |
check_docker_install()
|
166 |
|
167 |
# Get user choices
|
|
|
162 |
signal.signal(signal.SIGTERM, signal_handler)
|
163 |
|
164 |
try:
|
165 |
+
# Check if TEMP_DIR exists, if not, create it
|
166 |
+
if not TEMP_DIR.exists():
|
167 |
+
TEMP_DIR.mkdir(parents=True, exist_ok=True)
|
168 |
+
print(t("TEMP_DIR_CREATED", dir=str(TEMP_DIR)))
|
169 |
+
|
170 |
check_docker_install()
|
171 |
|
172 |
# Get user choices
|
docker/msdl/docker_manager.py
CHANGED
@@ -48,39 +48,78 @@ def check_docker_install():
|
|
48 |
|
49 |
def stop_and_remove_containers():
|
50 |
docker_compose_cmd = get_docker_command()
|
|
|
|
|
|
|
51 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
52 |
subprocess.run(
|
53 |
-
docker_compose_cmd
|
54 |
-
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
59 |
-
|
|
|
|
|
|
|
|
|
60 |
check=True,
|
|
|
|
|
61 |
)
|
62 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
63 |
except subprocess.CalledProcessError as e:
|
64 |
-
print(t("
|
|
|
|
|
65 |
|
66 |
|
67 |
def run_docker_compose():
|
68 |
docker_compose_cmd = get_docker_command()
|
69 |
try:
|
70 |
-
print(t("
|
71 |
-
subprocess.run(
|
72 |
-
docker_compose_cmd
|
73 |
-
+ [
|
74 |
-
"-f",
|
75 |
-
os.path.join(TEMP_DIR, "docker-compose.yaml"),
|
76 |
-
"--env-file",
|
77 |
-
os.path.join(TEMP_DIR, ".env"),
|
78 |
-
"build",
|
79 |
-
],
|
80 |
-
check=True,
|
81 |
-
)
|
82 |
-
print(t("IMAGES_BUILT"))
|
83 |
-
print(t("STARTING_CONTAINERS"))
|
84 |
subprocess.run(
|
85 |
docker_compose_cmd
|
86 |
+ [
|
@@ -90,6 +129,7 @@ def run_docker_compose():
|
|
90 |
os.path.join(TEMP_DIR, ".env"),
|
91 |
"up",
|
92 |
"-d",
|
|
|
93 |
],
|
94 |
check=True,
|
95 |
)
|
|
|
48 |
|
49 |
def stop_and_remove_containers():
|
50 |
docker_compose_cmd = get_docker_command()
|
51 |
+
compose_file = os.path.join(TEMP_DIR, "docker-compose.yaml")
|
52 |
+
|
53 |
+
# Read the docker-compose.yaml file
|
54 |
try:
|
55 |
+
with open(compose_file, "r") as file:
|
56 |
+
compose_config = yaml.safe_load(file)
|
57 |
+
except Exception as e:
|
58 |
+
print(t("COMPOSE_FILE_READ_ERROR", error=str(e)))
|
59 |
+
return
|
60 |
+
|
61 |
+
# Get project name and service names
|
62 |
+
project_name = compose_config.get("name", "mindsearch")
|
63 |
+
service_names = list(compose_config.get("services", {}).keys())
|
64 |
+
|
65 |
+
# Use only the project name as the container prefix
|
66 |
+
container_prefix = f"{project_name}_"
|
67 |
+
|
68 |
+
try:
|
69 |
+
# 1. Try to stop containers using the current docker-compose.yaml
|
70 |
subprocess.run(
|
71 |
+
docker_compose_cmd + ["-f", compose_file, "down", "-v", "--remove-orphans"],
|
72 |
+
check=True,
|
73 |
+
)
|
74 |
+
except subprocess.CalledProcessError:
|
75 |
+
print(t("CURRENT_COMPOSE_STOP_FAILED"))
|
76 |
+
|
77 |
+
# 2. Attempt to clean up potentially existing containers, regardless of the success of the previous step
|
78 |
+
try:
|
79 |
+
# List all containers (including stopped ones)
|
80 |
+
result = subprocess.run(
|
81 |
+
["docker", "ps", "-a", "--format", "{{.Names}}"],
|
82 |
check=True,
|
83 |
+
capture_output=True,
|
84 |
+
text=True,
|
85 |
)
|
86 |
+
all_containers = result.stdout.splitlines()
|
87 |
+
|
88 |
+
# 3. Filter out containers belonging to our project
|
89 |
+
project_containers = [
|
90 |
+
c
|
91 |
+
for c in all_containers
|
92 |
+
if c.startswith(container_prefix)
|
93 |
+
or any(c == f"{project_name}-{service}" for service in service_names)
|
94 |
+
]
|
95 |
+
|
96 |
+
if project_containers:
|
97 |
+
# 4. Force stop and remove these containers
|
98 |
+
for container in project_containers:
|
99 |
+
try:
|
100 |
+
subprocess.run(["docker", "stop", container], check=True)
|
101 |
+
subprocess.run(["docker", "rm", "-f", container], check=True)
|
102 |
+
print(t("CONTAINER_STOPPED_AND_REMOVED", container=container))
|
103 |
+
except subprocess.CalledProcessError as e:
|
104 |
+
print(t("CONTAINER_STOP_ERROR", container=container, error=str(e)))
|
105 |
+
|
106 |
+
# 5. Clean up potentially leftover networks
|
107 |
+
try:
|
108 |
+
subprocess.run(["docker", "network", "prune", "-f"], check=True)
|
109 |
+
print(t("NETWORKS_PRUNED"))
|
110 |
+
except subprocess.CalledProcessError as e:
|
111 |
+
print(t("NETWORK_PRUNE_ERROR", error=str(e)))
|
112 |
+
|
113 |
except subprocess.CalledProcessError as e:
|
114 |
+
print(t("DOCKER_LIST_ERROR", error=str(e)))
|
115 |
+
|
116 |
+
print(t("CONTAINERS_STOPPED_AND_REMOVED"))
|
117 |
|
118 |
|
119 |
def run_docker_compose():
|
120 |
docker_compose_cmd = get_docker_command()
|
121 |
try:
|
122 |
+
print(t("STARTING_CONTAINERS_WITH_BUILD"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
123 |
subprocess.run(
|
124 |
docker_compose_cmd
|
125 |
+ [
|
|
|
129 |
os.path.join(TEMP_DIR, ".env"),
|
130 |
"up",
|
131 |
"-d",
|
132 |
+
"--build",
|
133 |
],
|
134 |
check=True,
|
135 |
)
|
docker/msdl/i18n.py
CHANGED
@@ -3,18 +3,20 @@
|
|
3 |
import os
|
4 |
import i18n
|
5 |
import locale
|
|
|
6 |
from msdl.config import TRANSLATIONS_DIR, ENV_FILE_PATH
|
7 |
|
8 |
|
9 |
def get_env_variable(var_name, default=None):
|
10 |
-
|
11 |
-
with open(ENV_FILE_PATH, "r") as env_file:
|
12 |
-
for line in env_file:
|
13 |
-
if line.startswith(f"{var_name}="):
|
14 |
-
return line.strip().split("=", 1)[1]
|
15 |
return os.getenv(var_name, default)
|
16 |
|
17 |
|
|
|
|
|
|
|
|
|
|
|
18 |
def get_system_language():
|
19 |
try:
|
20 |
return locale.getlocale()[0].split("_")[0]
|
@@ -28,10 +30,12 @@ def setup_i18n():
|
|
28 |
i18n.set("file_format", "yaml")
|
29 |
|
30 |
env_language = get_env_variable("LAUNCHER_INTERACTION_LANGUAGE")
|
31 |
-
if env_language:
|
32 |
-
|
33 |
-
|
34 |
-
|
|
|
|
|
35 |
|
36 |
|
37 |
def t(key, **kwargs):
|
|
|
3 |
import os
|
4 |
import i18n
|
5 |
import locale
|
6 |
+
from dotenv import load_dotenv, set_key, find_dotenv
|
7 |
from msdl.config import TRANSLATIONS_DIR, ENV_FILE_PATH
|
8 |
|
9 |
|
10 |
def get_env_variable(var_name, default=None):
|
11 |
+
load_dotenv(ENV_FILE_PATH)
|
|
|
|
|
|
|
|
|
12 |
return os.getenv(var_name, default)
|
13 |
|
14 |
|
15 |
+
def set_env_variable(var_name, value):
|
16 |
+
dotenv_file = find_dotenv(ENV_FILE_PATH)
|
17 |
+
set_key(dotenv_file, var_name, value)
|
18 |
+
|
19 |
+
|
20 |
def get_system_language():
|
21 |
try:
|
22 |
return locale.getlocale()[0].split("_")[0]
|
|
|
30 |
i18n.set("file_format", "yaml")
|
31 |
|
32 |
env_language = get_env_variable("LAUNCHER_INTERACTION_LANGUAGE")
|
33 |
+
if not env_language:
|
34 |
+
system_language = get_system_language()
|
35 |
+
set_env_variable("LAUNCHER_INTERACTION_LANGUAGE", system_language)
|
36 |
+
env_language = system_language
|
37 |
+
|
38 |
+
i18n.set("locale", env_language)
|
39 |
|
40 |
|
41 |
def t(key, **kwargs):
|
docker/msdl/translations/en.yaml
CHANGED
@@ -12,6 +12,7 @@ en:
|
|
12 |
BUILDING_IMAGES: "Starting to build Docker images..."
|
13 |
IMAGES_BUILT: "Docker images built successfully"
|
14 |
STARTING_CONTAINERS: "Starting Docker containers..."
|
|
|
15 |
CONTAINERS_STARTED: "Docker containers started successfully"
|
16 |
DOCKER_ERROR: "Error while building or starting Docker containers: %{error}"
|
17 |
DOCKER_OUTPUT: "Docker command output:"
|
@@ -48,3 +49,10 @@ en:
|
|
48 |
UNKNOWN_MODEL_TYPE: "Unknown model type: %{model_type}"
|
49 |
BACKEND_DOCKERFILE_COPIED: "Backend Dockerfile copied from %{source_path} to %{dest_path}"
|
50 |
FRONTEND_DOCKERFILE_COPIED: "Frontend Dockerfile copied from %{source_path} to %{dest_path}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
BUILDING_IMAGES: "Starting to build Docker images..."
|
13 |
IMAGES_BUILT: "Docker images built successfully"
|
14 |
STARTING_CONTAINERS: "Starting Docker containers..."
|
15 |
+
STARTING_CONTAINERS_WITH_BUILD: "Starting to build and start Docker containers..."
|
16 |
CONTAINERS_STARTED: "Docker containers started successfully"
|
17 |
DOCKER_ERROR: "Error while building or starting Docker containers: %{error}"
|
18 |
DOCKER_OUTPUT: "Docker command output:"
|
|
|
49 |
UNKNOWN_MODEL_TYPE: "Unknown model type: %{model_type}"
|
50 |
BACKEND_DOCKERFILE_COPIED: "Backend Dockerfile copied from %{source_path} to %{dest_path}"
|
51 |
FRONTEND_DOCKERFILE_COPIED: "Frontend Dockerfile copied from %{source_path} to %{dest_path}"
|
52 |
+
TEMP_DIR_CREATED: "Temporary directory created at %{dir}"
|
53 |
+
CURRENT_COMPOSE_STOP_FAILED: "Current containers stop failed"
|
54 |
+
CONTAINER_STOPPED_AND_REMOVED: "Container stopped and removed"
|
55 |
+
NETWORKS_PRUNED: "Corresponding Docker networks pruned"
|
56 |
+
NETWORK_PRUNE_ERROR: "Error pruning corresponding Docker networks: %{error}"
|
57 |
+
DOCKER_LIST_ERROR: "Error listing Docker containers: %{error}"
|
58 |
+
CONTAINERS_STOPPED_AND_REMOVED: "Docker containers stopped and removed"
|
docker/msdl/translations/zh_CN.yaml
CHANGED
@@ -12,6 +12,7 @@ zh_CN:
|
|
12 |
BUILDING_IMAGES: "开始构建Docker镜像..."
|
13 |
IMAGES_BUILT: "Docker镜像构建成功"
|
14 |
STARTING_CONTAINERS: "开始启动Docker容器..."
|
|
|
15 |
CONTAINERS_STARTED: "Docker 容器已成功启动"
|
16 |
DOCKER_ERROR: "构建或启动 Docker 容器时出错:%{error}"
|
17 |
DOCKER_OUTPUT: "Docker 命令输出:"
|
@@ -48,3 +49,10 @@ zh_CN:
|
|
48 |
UNKNOWN_MODEL_TYPE: "未知的模型类型:%{model_type}"
|
49 |
BACKEND_DOCKERFILE_COPIED: "后端 Dockerfile 已经从 %{source_path} 复制为 %{dest_path}"
|
50 |
FRONTEND_DOCKERFILE_COPIED: "前端 Dockerfile 已经从 %{source_path} 复制为 %{dest_path}"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
12 |
BUILDING_IMAGES: "开始构建Docker镜像..."
|
13 |
IMAGES_BUILT: "Docker镜像构建成功"
|
14 |
STARTING_CONTAINERS: "开始启动Docker容器..."
|
15 |
+
STARTING_CONTAINERS_WITH_BUILD: "开始构建并启动Docker容器..."
|
16 |
CONTAINERS_STARTED: "Docker 容器已成功启动"
|
17 |
DOCKER_ERROR: "构建或启动 Docker 容器时出错:%{error}"
|
18 |
DOCKER_OUTPUT: "Docker 命令输出:"
|
|
|
49 |
UNKNOWN_MODEL_TYPE: "未知的模型类型:%{model_type}"
|
50 |
BACKEND_DOCKERFILE_COPIED: "后端 Dockerfile 已经从 %{source_path} 复制为 %{dest_path}"
|
51 |
FRONTEND_DOCKERFILE_COPIED: "前端 Dockerfile 已经从 %{source_path} 复制为 %{dest_path}"
|
52 |
+
TEMP_DIR_CREATED: "已在 %{dir} 创建临时目录"
|
53 |
+
CURRENT_COMPOSE_STOP_FAILED: "当前的容器停止失败"
|
54 |
+
CONTAINER_STOPPED_AND_REMOVED: "容器已停止并删除"
|
55 |
+
NETWORKS_PRUNED: "已清理对应的Docker网络"
|
56 |
+
NETWORK_PRUNE_ERROR: "清理对应的Docker网络时出错:%{error}"
|
57 |
+
DOCKER_LIST_ERROR: "列出 Docker 容器时出错:%{error}"
|
58 |
+
CONTAINERS_STOPPED_AND_REMOVED: "已停止并删除 Docker 容器"
|
docker/msdl/utils.py
CHANGED
@@ -120,6 +120,9 @@ def modify_docker_compose(selected_dockerfile, backend_language, model_format):
|
|
120 |
with docker_compose_path.open("r") as file:
|
121 |
compose_data = yaml.safe_load(file)
|
122 |
|
|
|
|
|
|
|
123 |
backend_service = compose_data["services"]["backend"]
|
124 |
|
125 |
if "env_file" not in backend_service:
|
@@ -128,10 +131,14 @@ def modify_docker_compose(selected_dockerfile, backend_language, model_format):
|
|
128 |
backend_service["env_file"].append(".env")
|
129 |
|
130 |
command = f"python -m mindsearch.app --lang {backend_language} --model_format {model_format}"
|
|
|
131 |
if selected_dockerfile == CLOUD_LLM_DOCKERFILE:
|
132 |
if "deploy" in backend_service:
|
133 |
del backend_service["deploy"]
|
134 |
backend_service["command"] = command
|
|
|
|
|
|
|
135 |
elif selected_dockerfile == LOCAL_LLM_DOCKERFILE:
|
136 |
if "deploy" not in backend_service:
|
137 |
backend_service["deploy"] = {
|
@@ -144,6 +151,8 @@ def modify_docker_compose(selected_dockerfile, backend_language, model_format):
|
|
144 |
}
|
145 |
}
|
146 |
backend_service["command"] = command
|
|
|
|
|
147 |
else:
|
148 |
raise ValueError(t("UNKNOWN_DOCKERFILE", dockerfile=selected_dockerfile))
|
149 |
|
|
|
120 |
with docker_compose_path.open("r") as file:
|
121 |
compose_data = yaml.safe_load(file)
|
122 |
|
123 |
+
# Set the name of the project (Docker Compose will convert it to lowercase)
|
124 |
+
compose_data["name"] = "mindsearch"
|
125 |
+
|
126 |
backend_service = compose_data["services"]["backend"]
|
127 |
|
128 |
if "env_file" not in backend_service:
|
|
|
131 |
backend_service["env_file"].append(".env")
|
132 |
|
133 |
command = f"python -m mindsearch.app --lang {backend_language} --model_format {model_format}"
|
134 |
+
|
135 |
if selected_dockerfile == CLOUD_LLM_DOCKERFILE:
|
136 |
if "deploy" in backend_service:
|
137 |
del backend_service["deploy"]
|
138 |
backend_service["command"] = command
|
139 |
+
# Use Cloud LLM Dockerfile: Remove volumes
|
140 |
+
if "volumes" in backend_service:
|
141 |
+
del backend_service["volumes"]
|
142 |
elif selected_dockerfile == LOCAL_LLM_DOCKERFILE:
|
143 |
if "deploy" not in backend_service:
|
144 |
backend_service["deploy"] = {
|
|
|
151 |
}
|
152 |
}
|
153 |
backend_service["command"] = command
|
154 |
+
# Use Local LLM Dockerfile: Add volume for cache
|
155 |
+
backend_service["volumes"] = ["/root/.cache:/root/.cache"]
|
156 |
else:
|
157 |
raise ValueError(t("UNKNOWN_DOCKERFILE", dockerfile=selected_dockerfile))
|
158 |
|
docker/setup.py
CHANGED
@@ -10,6 +10,7 @@ setup(
|
|
10 |
"pyyaml>=6.0",
|
11 |
"python-i18n>=0.3.9",
|
12 |
"inquirerpy>=0.3.4",
|
|
|
13 |
],
|
14 |
entry_points={
|
15 |
"console_scripts": [
|
|
|
10 |
"pyyaml>=6.0",
|
11 |
"python-i18n>=0.3.9",
|
12 |
"inquirerpy>=0.3.4",
|
13 |
+
"python-dotenv>=0.19.1",
|
14 |
],
|
15 |
entry_points={
|
16 |
"console_scripts": [
|