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 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
- "-f",
56
- os.path.join(TEMP_DIR, "docker-compose.yaml"),
57
- "down",
58
- "-v",
59
- ],
 
 
 
 
60
  check=True,
 
 
61
  )
62
- print(t("CONTAINERS_STOPPED"))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  except subprocess.CalledProcessError as e:
64
- print(t("CONTAINER_STOP_ERROR", error=str(e)))
 
 
65
 
66
 
67
  def run_docker_compose():
68
  docker_compose_cmd = get_docker_command()
69
  try:
70
- print(t("BUILDING_IMAGES"))
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
- if os.path.exists(ENV_FILE_PATH):
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
- i18n.set("locale", env_language)
33
- else:
34
- i18n.set("locale", get_system_language())
 
 
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": [