diff --git a/scripts/setup_pro.sh b/scripts/setup_pro.sh index e40fa7e0..149555a4 100644 --- a/scripts/setup_pro.sh +++ b/scripts/setup_pro.sh @@ -47,10 +47,10 @@ fi # Check if /etc/docker/daemon.json exists and modify it if [ -e /etc/docker/daemon.json ]; then echo "daemon.json exists, updating it..." - jq '.["insecure-registries"] += ["harbor.nanjiren.online:8099"]' /etc/docker/daemon.json > /tmp/daemon.json && mv /tmp/daemon.json /etc/docker/daemon.json + jq '.["insecure-registries"] += ["https://harbor.nanjiren.online"]' /etc/docker/daemon.json > /tmp/daemon.json && mv /tmp/daemon.json /etc/docker/daemon.json else echo "daemon.json does not exist, creating it..." - echo '{"insecure-registries": ["harbor.nanjiren.online:8099"]}' > /etc/docker/daemon.json + echo '{"insecure-registries": ["https://harbor.nanjiren.online"]}' > /etc/docker/daemon.json fi # Restart Docker daemon @@ -67,7 +67,7 @@ while true; do # Log in to the AIChat Pro private registry echo "" echo "Logging in to Docker private registry..." - if docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD http://harbor.nanjiren.online:8099; then + if docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD https://harbor.nanjiren.online; then break else echo "AIChat Pro authorization failed, please re-enter your account and password." @@ -102,9 +102,90 @@ else exit 1 fi +# Check current Web Secret in docker-compose.yml and prompt for change if needed +CURRENT_WEB_SECRET=$(grep 'WEB_SECRET:' docker-compose.yml | cut -d ':' -f2 | xargs) +echo "Current Web Secret is: $CURRENT_WEB_SECRET" +read -p "Do you want to change the Web Secret? (y/N): " DECISION + +if [[ "$DECISION" =~ ^[Yy]$ ]]; then + echo "Please input the new Web Secret (at least 8 characters):" + read -p "Web Secret: " NEW_WEB_SECRET + regex='^[A-Za-z0-9]{8,}$' + if [[ $NEW_WEB_SECRET =~ $regex ]]; then + sed -i "s/WEB_SECRET:.*/WEB_SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + echo "Web Secret updated." + else + echo "Invalid Web Secret. Keeping the current one." + fi +fi + +# Check for STORE_TYPE and prompt for configuration +STORE_TYPE=$(grep 'STORE_TYPE:' docker-compose.yml | cut -d ':' -f2 | xargs) + +if [ -z "$STORE_TYPE" ]; then + echo "Store type is not set. Please choose the store type by typing (local/oss):" + read -p "Store Type: " STORE_TYPE_CHOICE + STORE_TYPE=${STORE_TYPE_CHOICE:-local} +fi + +attempt_count=0 +max_attempts=3 + +while [ $attempt_count -lt $max_attempts ]; do + read -p "Please choose the store type by typing 'local' or 'oss' (Attempt $((attempt_count + 1))/$max_attempts): " STORE_TYPE_CHOICE + if [[ "$STORE_TYPE_CHOICE" == "local" ]] || [[ "$STORE_TYPE_CHOICE" == "oss" ]]; then + STORE_TYPE=$STORE_TYPE_CHOICE + break + else + echo "Invalid input. Please type 'local' or 'oss'." + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "Maximum attempts reached. Exiting script." + exit 1 + fi +done + +if [[ "$STORE_TYPE" == "local" ]]; then + # Handle local storage configuration + EXISTING_LOCAL_PATH=$(grep 'LOCAL_PATH:' docker-compose.yml | cut -d ':' -f2 | xargs) + echo "Using local storage. Current path is: ${EXISTING_LOCAL_PATH:-/app/aichat/images}" + read -p "New local storage path (press enter to use existing/default): " NEW_LOCAL_PATH + LOCAL_PATH=${NEW_LOCAL_PATH:-$EXISTING_LOCAL_PATH} + sed -i "s#LOCAL_PATH:.*#LOCAL_PATH: $LOCAL_PATH#g" docker-compose.yml +else + # Handle OSS storage configuration + EXISTING_OSS_ENDPOINT=$(grep 'OSS_ENDPOINT:' docker-compose.yml | cut -d ':' -f2 | xargs) + EXISTING_OSS_BUCKET_NAME=$(grep 'OSS_BUCKET_NAME:' docker-compose.yml | cut -d ':' -f2 | xargs) + EXISTING_OSS_ACCESS_KEY_ID=$(grep 'OSS_ACCESS_KEY_ID:' docker-compose.yml | cut -d ':' -f2 | xargs) + EXISTING_OSS_ACCESS_KEY_SECRET=$(grep 'OSS_ACCESS_KEY_SECRET:' docker-compose.yml | cut -d ':' -f2 | xargs) + + echo "Using OSS storage. Please input the OSS configurations." + read -p "OSS Endpoint [${EXISTING_OSS_ENDPOINT}]: " OSS_ENDPOINT + OSS_ENDPOINT=${OSS_ENDPOINT:-$EXISTING_OSS_ENDPOINT} + read -p "OSS Bucket Name [${EXISTING_OSS_BUCKET_NAME}]: " OSS_BUCKET_NAME + OSS_BUCKET_NAME=${OSS_BUCKET_NAME:-$EXISTING_OSS_BUCKET_NAME} + read -p "OSS Access Key ID [${EXISTING_OSS_ACCESS_KEY_ID}]: " OSS_ACCESS_KEY_ID + OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID:-$EXISTING_OSS_ACCESS_KEY_ID} + read -p "OSS Access Key Secret [${EXISTING_OSS_ACCESS_KEY_SECRET}]: " OSS_ACCESS_KEY_SECRET + OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET:-$EXISTING_OSS_ACCESS_KEY_SECRET} + + sed -i "s/STORE_TYPE:.*/STORE_TYPE: oss/g" docker-compose.yml + sed -i "s/OSS_ENDPOINT:.*/OSS_ENDPOINT: $OSS_ENDPOINT/g" docker-compose.yml + sed -i "s/OSS_BUCKET_NAME:.*/OSS_BUCKET_NAME: $OSS_BUCKET_NAME/g" docker-compose.yml + sed -i "s/OSS_ACCESS_KEY_ID:.*/OSS_ACCESS_KEY_ID: $OSS_ACCESS_KEY_ID/g" docker-compose.yml + sed -i "s/OSS_ACCESS_KEY_SECRET:.*/OSS_ACCESS_KEY_SECRET: $OSS_ACCESS_KEY_SECRET/g" docker-compose.yml +fi + sed -i "s/SUPERADMIN_USERNAME:.*/SUPERADMIN_USERNAME: $SUPER_USERNAME/g" docker-compose.yml sed -i "s/SUPERADMIN_PASSWORD:.*/SUPERADMIN_PASSWORD: $SUPER_PASSWORD/g" docker-compose.yml +sed -i "s/WEB_SECRET:.*/WEB_SECRET: $WEB_SECRET/g" docker-compose.yml +sed -i "s/SECRET:.*/SECRET: $WEB_SECRET/g" docker-compose.yml +sed -i "s/LOG_LEVEL:.*/LOG_LEVEL: INFO/g" docker-compose.yml + +# Pull and start the Docker containers docker compose pull docker compose up -d \ No newline at end of file diff --git a/scripts/setup_pro_cn.sh b/scripts/setup_pro_cn.sh new file mode 100644 index 00000000..5aaf325e --- /dev/null +++ b/scripts/setup_pro_cn.sh @@ -0,0 +1,221 @@ +#!/bin/bash + +# Check if running on a supported system +case "$(uname -s)" in + Linux) + echo "Running on Linux" + ;; + Darwin) + echo "This script only works on Linux, not Mac OS." + exit 1 + ;; + *) + echo "Unsupported operating system." + exit 1 + ;; +esac + +# check whether installed docker & compose + +# Check if needed dependencies are installed and install if necessary +if ! command -v docker >/dev/null; then + case "$(uname -s)" in + Linux) + echo "curl -o install-docker-v20.10.21.sh..." + curl -o install-docker-v20.10.21.sh https://releases.rancher.com/install-docker/20.10.21.sh + chmod +x install-docker-v20.10.21.sh + ./install-docker-v20.10.21.sh + + # auto start on boot + systemctl enable docker + ;; + Darwin) + # /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" + # brew install node git yarn + ;; + esac +fi + +systemctl start docker + +# 检查是否安装了 jq 并在必要时进行安装 +if ! command -v jq >/dev/null; then + echo "jq 未安装,正在安装..." + yum install -y jq +fi + +# 检查 /etc/docker/daemon.json 是否存在并进行修改 +if [ -e /etc/docker/daemon.json ]; then + echo "daemon.json 存在,正在更新..." + jq '.["insecure-registries"] += ["https://harbor.nanjiren.online"]' /etc/docker/daemon.json > /tmp/daemon.json && mv /tmp/daemon.json /etc/docker/daemon.json +else + echo "daemon.json 不存在,正在创建..." + echo '{"insecure-registries": ["https://harbor.nanjiren.online"]}' > /etc/docker/daemon.json +fi + +# 重启 Docker 守护进程 +echo "正在重启 Docker 守护进程..." +systemctl restart docker + +# 提示输入 AIChat Pro 私有仓库凭据 +while true; do + echo "请输入 AIChat Pro 授权账户用户名:" + read -p "授权账户用户名: " DOCKER_REGISTRY_USERNAME + echo "请输入 AIChat Pro 授权账户密码:" + read -s -p "授权账户密码: " DOCKER_REGISTRY_PASSWORD + + # 登录 AIChat Pro 私有仓库 + echo "" + echo "正在登录 Docker 私有仓库..." + if docker login -u $DOCKER_REGISTRY_USERNAME -p $DOCKER_REGISTRY_PASSWORD https://harbor.nanjiren.online; then + break + else + echo "AIChat Pro 授权失败,请重新输入您的账户和密码。" + fi +done + +# 克隆仓库并安装依赖 +echo "正在下载 docker-compose.yml..." +curl -o docker-compose.yml https://raw.githubusercontent.com/Nanjiren01/AIChatWeb/pro/docker-compose.yml + + + +echo "请输入超级管理员用户名。" +echo "仅支持字母和数字,长度应在6到20之间,且不能以数字开头。" +read -p "用户名: " SUPER_USERNAME +regex='^[A-Za-z][A-Za-z0-9]{5,19}$' +if [[ $SUPER_USERNAME =~ $regex ]]; then + echo "超级管理员用户名有效。" +else + echo "超级管理员用户名无效。" + exit 1 +fi + +echo "请输入超级管理员密码。" +echo "仅支持字母和数字,长度应在6到20之间。" +echo "应用程序运行后,您可以在网页上更改密码。" +read -p "密码: " SUPER_PASSWORD +regex='^[A-Za-z0-9]{6,20}$' +if [[ $SUPER_PASSWORD =~ $regex ]]; then + echo "超级管理员密码有效。" +else + echo "超级管理员密码无效。" + exit 1 +fi + + +# Check current Web Secret in docker-compose.yml and prompt for updates +CURRENT_WEB_SECRET=$(grep 'WEB_SECRET:' docker-compose.yml | cut -d ':' -f2 | xargs) +echo "当前的 Web Secret 为: $CURRENT_WEB_SECRET" +read -p "您想更改 Web Secret 吗?(y/N): " DECISION + +if [[ "$DECISION" =~ ^[Yy]$ ]]; then + attempt_count=0 + max_attempts=3 + regex='^[A-Za-z0-9#@$%^&*()_+]{8,}$' + + while [ $attempt_count -lt $max_attempts ]; do + echo "请输入新的 Web Secret (尽量复杂,至少 8 个字符):" + read -p "Web Secret: " NEW_WEB_SECRET + + if [[ $NEW_WEB_SECRET =~ $regex ]]; then + # Update Web Secret for both admin and web services + sed -i "s/WEB_SECRET:.*/WEB_SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + sed -i "s/SECRET:.*/SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + echo "Web Secret 已更新。" + break + else + echo "Web Secret 无效,请重新输入。" + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "尝试次数达到上限。正在退出脚本..." + restore_original_docker_compose + exit 1 + fi + done +fi + +# Check for STORE_TYPE and prompt for configuration +STORE_TYPE=$(grep 'STORE_TYPE:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + +echo "当前的 Store Type 为: ${STORE_TYPE:-local}" +read -p "请输入以选择存储类型(输入 'local' 或 'oss'):" STORE_TYPE_CHOICE +STORE_TYPE=${STORE_TYPE_CHOICE:-$STORE_TYPE} + +attempt_count=0 +max_attempts=3 + +while [ $attempt_count -lt $max_attempts ]; do + if [[ "$STORE_TYPE" == "local" || "$STORE_TYPE" == "oss" ]]; then + break + fi + + read -p "输入无效。请输入 'local' 或 'oss'。 (尝试次数 $((attempt_count + 1))/$max_attempts): " STORE_TYPE_CHOICE + if [[ "$STORE_TYPE_CHOICE" == "local" || "$STORE_TYPE_CHOICE" == "oss" ]]; then + STORE_TYPE=$STORE_TYPE_CHOICE + break + else + echo "输入无效。请输入 'local' 或 'oss'。" + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "尝试次数达到上限。正在退出脚本..." + restore_original_docker_compose + exit 1 + fi +done + +if [[ "$STORE_TYPE" == "local" ]]; then + # Handle local storage configuration + EXISTING_LOCAL_PATH=$(grep 'LOCAL_PATH:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + echo "使用本地存储。当前路径为: ${EXISTING_LOCAL_PATH:-/app/aichat/images}" + read -p "输入新的本地存储路径(按Enter键使用现有/默认值): " NEW_LOCAL_PATH + LOCAL_PATH=${NEW_LOCAL_PATH:-$EXISTING_LOCAL_PATH} + sed -i "s#LOCAL_PATH:.*#LOCAL_PATH: $LOCAL_PATH#g" docker-compose.yml +else + # Handle OSS storage configuration + EXISTING_OSS_ENDPOINT=$(grep 'OSS_ENDPOINT:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_BUCKET_NAME=$(grep 'OSS_BUCKET_NAME:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_ID=$(grep 'OSS_ACCESS_KEY_ID:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_SECRET=$(grep 'OSS_ACCESS_KEY_SECRET:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + + echo "使用 OSS 存储。请输入新的 OSS 配置或直接按Enter键以使用现有值。" + + echo "当前 OSS Endpoint: $EXISTING_OSS_ENDPOINT" + read -p "输入新的 OSS Endpoint 或直接按Enter键保留原有值: " OSS_ENDPOINT + OSS_ENDPOINT=${OSS_ENDPOINT:-$EXISTING_OSS_ENDPOINT} + + echo "当前 OSS Bucket Name: $EXISTING_OSS_BUCKET_NAME" + read -p "输入新的 OSS Bucket Name 或直接按Enter键保留原有值: " OSS_BUCKET_NAME + OSS_BUCKET_NAME=${OSS_BUCKET_NAME:-$EXISTING_OSS_BUCKET_NAME} + + echo "当前 OSS Access Key ID: $EXISTING_OSS_ACCESS_KEY_ID" + read -p "输入新的 OSS Access Key ID 或直接按Enter键保留原有值: " OSS_ACCESS_KEY_ID + OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID:-$EXISTING_OSS_ACCESS_KEY_ID} + + echo "当前 OSS Access Key Secret: $EXISTING_OSS_ACCESS_KEY_SECRET" + read -p "输入新的 OSS Access Key Secret 或直接按Enter键保留原有值: " OSS_ACCESS_KEY_SECRET + OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET:-$EXISTING_OSS_ACCESS_KEY_SECRET} + + sed -i "s#STORE_TYPE:.*#STORE_TYPE: oss#g" docker-compose.yml + sed -i "s#OSS_ENDPOINT:.*#OSS_ENDPOINT: $OSS_ENDPOINT#g" docker-compose.yml + sed -i "s#OSS_BUCKET_NAME:.*#OSS_BUCKET_NAME: $OSS_BUCKET_NAME#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_ID:.*#OSS_ACCESS_KEY_ID: $OSS_ACCESS_KEY_ID#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_SECRET:.*#OSS_ACCESS_KEY_SECRET: $OSS_ACCESS_KEY_SECRET#g" docker-compose.yml + +fi + +sed -i "s/SUPERADMIN_USERNAME:.*/SUPERADMIN_USERNAME: $SUPER_USERNAME/g" docker-compose.yml +sed -i "s/SUPERADMIN_PASSWORD:.*/SUPERADMIN_PASSWORD: $SUPER_PASSWORD/g" docker-compose.yml +sed -i "s/WEB_SECRET:.*/WEB_SECRET: $WEB_SECRET/g" docker-compose.yml +sed -i "s/SECRET:.*/SECRET: $WEB_SECRET/g" docker-compose.yml +sed -i "s/LOG_LEVEL:.*/LOG_LEVEL: INFO/g" docker-compose.yml + + +# Pull and start the Docker containers +docker compose pull + +docker compose up -d \ No newline at end of file diff --git a/scripts/upgrade.sh b/scripts/upgrade.sh index a05d367e..93707480 100644 --- a/scripts/upgrade.sh +++ b/scripts/upgrade.sh @@ -1,10 +1,245 @@ #!/bin/bash +# AIChat Pro Update 0.9.x to 0.11.x +# Copyright © 2024 GAI Group. All Rights Reserved. +# Latest: 2024/01/23 +echo "*******************************************************************************" +echo "****** ******" +echo "****** ******" +echo "****** AIChat Pro Update 0.9.x to 0.11.x ******" +echo "****** ******" +echo "****** ******" +echo "****** Copyright © 2024 GAI Group. All Rights Reserved. ******" +echo "****** ******" +echo "****** 2024/01/23 ******" +echo "****** ******" +echo "****** ******" +echo "*******************************************************************************" + +# Add a warning and confirmation before the update begins +echo "请注意:该程序用于AIChat专业版系统0.9.x版本升级到0.11.x版本,请确保官方宣布的AIChat专业版系统最新版是0.11.x,而不是比0.11.x还要新的版本,请及时关注官网https://nanjiren.online获取最新资讯。" +while true; do + read -p "如您已经知悉上述内容,请输入y后回车开始更新,更新过程中会停止已经运行的AIChat专业版系统,否则请输入n后回车退出更新程序。 (y/n): " DECISION + if [[ $DECISION =~ ^[Yy]$ ]]; then + break + elif [[ $DECISION =~ ^[Nn]$ ]]; then + echo "更新程序已退出。" + exit 1 + else + echo "无效输入,请输入 'y' 或 'n'。" + fi +done + +# Stop the current docker-compose services docker compose down -# Clone the repository and install dependencies -echo "update docker-compose.yml..." -curl -o docker-compose.yml https://raw.githubusercontent.com/Nanjiren01/AIChatWeb/main/docker-compose.yml +# Function to restore the original docker-compose.yml +restore_original_docker_compose() { + echo "Restoring the original docker-compose.yml file..." + cp "docker-compose-backup-$BACKUP_TIME.yml" docker-compose.yml +} + +# Install yq for YAML processing +REQUIRED_YQ_VERSION="4.40.5" + +# 检查yq是否已安装 +if [ -x "$(command -v yq)" ]; then + # 获取当前yq版本 + CURRENT_YQ_VERSION=$(yq --version | awk '{print $3}') + + # 比较当前版本和所需版本 + if [ "$CURRENT_YQ_VERSION" != "$REQUIRED_YQ_VERSION" ]; then + echo "Updating yq to the required version ($REQUIRED_YQ_VERSION)..." + # 删除旧版本 + sudo rm $(which yq) + else + echo "yq is already at the required version ($REQUIRED_YQ_VERSION)." + exit 0 + fi +else + echo "yq is not installed. Installing now..." +fi + +# 安装或更新yq到指定版本 +# 确定操作系统架构 +case $(uname -m) in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) echo "Unsupported architecture" >&2; exit 1 ;; +esac + +# 下载并安装yq +sudo wget "https://github.com/mikefarah/yq/releases/download/v${REQUIRED_YQ_VERSION}/yq_linux_${ARCH}" -O /usr/local/bin/yq +sudo chmod +x /usr/local/bin/yq + +echo "yq 已更新到 $REQUIRED_YQ_VERSION." + + + +# Backup current docker-compose.yml with current timestamp +BACKUP_TIME=$(date +%Y%m%d%H%M%S) +echo "Backing up current docker-compose.yml to docker-compose-backup-$BACKUP_TIME.yml..." +cp docker-compose.yml "docker-compose-backup-$BACKUP_TIME.yml" + +# Clone the repository and get the latest docker-compose.yml +echo "Updating docker-compose.yml..." +curl -o docker-compose-new.yml https://raw.githubusercontent.com/Nanjiren01/AIChatWeb/pro/docker-compose.yml + +# Merge new and old docker-compose.yml, prioritizing old file values +yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' docker-compose-new.yml docker-compose-backup-$BACKUP_TIME.yml > temp.yml + +# Use sed to add empty lines before each service definition in the merged file +sed -i '/^[[:space:]]*$/d' temp.yml # Remove existing empty lines +sed -i '/^ [a-z].*:/i\\' temp.yml # Add an empty line before each service definition + +# Move the merged content back to the original docker-compose.yml file +mv temp.yml docker-compose.yml +rm docker-compose-new.yml + + +# Check if db service is used in the backup file +if awk '/depends_on:/ {found=1; next} found && /^\s*-\s*db/ {exit 1} /^\S/ {found=0}' "docker-compose-backup-$BACKUP_TIME.yml"; then + echo "Using external database. Please ensure you have backed up your database before proceeding." + + # Prompt user for confirmation + read -p "Have you backed up your external database? (y/N): " confirmation + if [[ ! $confirmation =~ ^[Yy]$ ]]; then + echo "Please backup your database before running this script." + restore_original_docker_compose + exit 1 + fi + + echo "Continuing with the script as the database has been backed up." + + # Comment out the '- db' line under 'depends_on' in 'admin' service + sed -i '/admin:/,/environment:/ s/^\(.*- db\)/ #\1/' docker-compose.yml + + # Comment out the entire 'db' service configuration + sed -i '/^ db:/,/^$/ s/^/#/' docker-compose.yml + +else + # Backup MySQL files + backup_dir="./backups" + backup_filename="mysql_data_backup_$(date +%Y%m%d_%H%M%S).tar.gz" + mysql_data_dir="./mysql_data" + + # Pack MySQL files + mkdir -p "$backup_dir" + tar -czvf "$backup_dir/$backup_filename" "$mysql_data_dir" || { + echo "Internal database backup failed"; + restore_original_docker_compose + exit 1; + } + + echo "MySQL 数据目录已备份到 $backup_dir/$backup_filename" +fi + +# Check current Web Secret in docker-compose.yml and prompt for updates +CURRENT_WEB_SECRET=$(grep 'WEB_SECRET:' docker-compose.yml | cut -d ':' -f2 | xargs) +echo "Current Web Secret is: $CURRENT_WEB_SECRET" +read -p "Do you want to change the Web Secret? (y/N): " DECISION + +if [[ "$DECISION" =~ ^[Yy]$ ]]; then + attempt_count=0 + max_attempts=3 + regex='^[A-Za-z0-9#@$%^&*()_+]{8,}$' + + while [ $attempt_count -lt $max_attempts ]; do + echo "Please input the new Web Secret (at least 8 characters):" + read -p "Web Secret: " NEW_WEB_SECRET + + if [[ $NEW_WEB_SECRET =~ $regex ]]; then + # Update Web Secret for both admin and web services + sed -i "s/WEB_SECRET:.*/WEB_SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + sed -i "s/SECRET:.*/SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + echo "Web Secret updated." + break + else + echo "Invalid Web Secret." + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "Maximum attempts reached. Exiting script." + restore_original_docker_compose + exit 1 + fi + done +fi + + +# Check for STORE_TYPE and prompt for configuration +STORE_TYPE=$(grep 'STORE_TYPE:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + +echo "Current Store Type is: ${STORE_TYPE:-local}" +read -p "Please choose the store type by typing 'local' or 'oss': " STORE_TYPE_CHOICE +STORE_TYPE=${STORE_TYPE_CHOICE:-$STORE_TYPE} + +attempt_count=0 +max_attempts=3 + +while [ $attempt_count -lt $max_attempts ]; do + if [[ "$STORE_TYPE" == "local" || "$STORE_TYPE" == "oss" ]]; then + break + fi + + read -p "Please choose the store type by typing 'local' or 'oss' (Attempt $((attempt_count + 1))/$max_attempts): " STORE_TYPE_CHOICE + if [[ "$STORE_TYPE_CHOICE" == "local" || "$STORE_TYPE_CHOICE" == "oss" ]]; then + STORE_TYPE=$STORE_TYPE_CHOICE + break + else + echo "Invalid input. Please type 'local' or 'oss'." + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "Maximum attempts reached. Exiting script." + restore_original_docker_compose + exit 1 + fi +done + +if [[ "$STORE_TYPE" == "local" ]]; then + # Handle local storage configuration + EXISTING_LOCAL_PATH=$(grep 'LOCAL_PATH:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + echo "Using local storage. Current path is: ${EXISTING_LOCAL_PATH:-/app/aichat/images}" + read -p "New local storage path (press enter to use existing/default): " NEW_LOCAL_PATH + LOCAL_PATH=${NEW_LOCAL_PATH:-$EXISTING_LOCAL_PATH} + sed -i "s#LOCAL_PATH:.*#LOCAL_PATH: $LOCAL_PATH#g" docker-compose.yml +else + # Handle OSS storage configuration + EXISTING_OSS_ENDPOINT=$(grep 'OSS_ENDPOINT:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_BUCKET_NAME=$(grep 'OSS_BUCKET_NAME:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_ID=$(grep 'OSS_ACCESS_KEY_ID:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_SECRET=$(grep 'OSS_ACCESS_KEY_SECRET:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + + echo "Using OSS storage. Please input the new OSS configurations or leave blank to use existing values." + + echo "Current OSS Endpoint: $EXISTING_OSS_ENDPOINT" + read -p "Enter new OSS Endpoint or leave blank: " OSS_ENDPOINT + OSS_ENDPOINT=${OSS_ENDPOINT:-$EXISTING_OSS_ENDPOINT} + + echo "Current OSS Bucket Name: $EXISTING_OSS_BUCKET_NAME" + read -p "Enter new OSS Bucket Name or leave blank: " OSS_BUCKET_NAME + OSS_BUCKET_NAME=${OSS_BUCKET_NAME:-$EXISTING_OSS_BUCKET_NAME} + + echo "Current OSS Access Key ID: $EXISTING_OSS_ACCESS_KEY_ID" + read -p "Enter new OSS Access Key ID or leave blank: " OSS_ACCESS_KEY_ID + OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID:-$EXISTING_OSS_ACCESS_KEY_ID} + + echo "Current OSS Access Key Secret: $EXISTING_OSS_ACCESS_KEY_SECRET" + read -p "Enter new OSS Access Key Secret or leave blank: " OSS_ACCESS_KEY_SECRET + OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET:-$EXISTING_OSS_ACCESS_KEY_SECRET} + + sed -i "s#STORE_TYPE:.*#STORE_TYPE: oss#g" docker-compose.yml + sed -i "s#OSS_ENDPOINT:.*#OSS_ENDPOINT: $OSS_ENDPOINT#g" docker-compose.yml + sed -i "s#OSS_BUCKET_NAME:.*#OSS_BUCKET_NAME: $OSS_BUCKET_NAME#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_ID:.*#OSS_ACCESS_KEY_ID: $OSS_ACCESS_KEY_ID#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_SECRET:.*#OSS_ACCESS_KEY_SECRET: $OSS_ACCESS_KEY_SECRET#g" docker-compose.yml + +fi + +# Start the updated docker-compose services docker compose up -d diff --git a/scripts/upgrade_cn.sh b/scripts/upgrade_cn.sh new file mode 100644 index 00000000..ecef3852 --- /dev/null +++ b/scripts/upgrade_cn.sh @@ -0,0 +1,278 @@ +#!/bin/bash + +# AIChat Pro Update 0.9.x to 0.11.x +# Copyright © 2024 GAI Group. All Rights Reserved. +# Latest: 2024/01/23 +echo "*******************************************************************************" +echo "****** ******" +echo "****** ******" +echo "****** AIChat Pro Update 0.9.x to 0.11.x ******" +echo "****** ******" +echo "****** ******" +echo "****** Copyright © 2024 GAI Group. All Rights Reserved. ******" +echo "****** ******" +echo "****** 2024/01/23 ******" +echo "****** ******" +echo "****** ******" +echo "*******************************************************************************" + +# Add a warning and confirmation before the update begins +echo "请注意:该程序用于AIChat专业版系统0.9.x版本升级到0.11.x版本,请确保官方宣布的AIChat专业版系统最新版是0.11.x,而不是比0.11.x还要新的版本,请及时关注官网https://nanjiren.online获取最新资讯。" +while true; do + read -p "如您已经知悉上述内容,请输入y后回车开始更新,更新过程中会停止已经运行的AIChat专业版系统,否则请输入n后回车退出更新程序。 (y/n): " DECISION + if [[ $DECISION =~ ^[Yy]$ ]]; then + break + elif [[ $DECISION =~ ^[Nn]$ ]]; then + echo "更新程序已退出。" + exit 1 + else + echo "无效输入,请输入 'y' 或 'n'。" + fi +done + +# Stop the current docker-compose services +docker compose down + +# Function to restore the original docker-compose.yml +restore_original_docker_compose() { + echo "正在恢复原始的 docker-compose.yml 文件..." + cp "docker-compose-backup-$BACKUP_TIME.yml" docker-compose.yml +} + +# Install yq for YAML processing +REQUIRED_YQ_VERSION="4.40.5" + +# 检查yq是否已安装 +if [ -x "$(command -v yq)" ]; then + # 获取当前yq版本 + CURRENT_YQ_VERSION=$(yq --version | awk '{print $3}') + + # 比较当前版本和所需版本 + if [ "$CURRENT_YQ_VERSION" != "$REQUIRED_YQ_VERSION" ]; then + echo "Updating yq to the required version ($REQUIRED_YQ_VERSION)..." + # 删除旧版本 + sudo rm $(which yq) + else + echo "yq is already at the required version ($REQUIRED_YQ_VERSION)." + exit 0 + fi +else + echo "yq is not installed. Installing now..." +fi + +# 安装或更新yq到指定版本 +# 确定操作系统架构 +case $(uname -m) in + x86_64) ARCH="amd64" ;; + aarch64) ARCH="arm64" ;; + *) echo "Unsupported architecture" >&2; exit 1 ;; +esac + +# 下载并安装yq +sudo wget "https://github.com/mikefarah/yq/releases/download/v${REQUIRED_YQ_VERSION}/yq_linux_${ARCH}" -O /usr/local/bin/yq +sudo chmod +x /usr/local/bin/yq + +echo "yq 已更新到 $REQUIRED_YQ_VERSION." + + +# Backup current docker-compose.yml with current timestamp +BACKUP_TIME=$(date +%Y%m%d%H%M%S) +echo "正在备份当前的 docker-compose.yml 到 docker-compose-backup-$BACKUP_TIME.yml..." +cp docker-compose.yml "docker-compose-backup-$BACKUP_TIME.yml" + +# Clone the repository and get the latest docker-compose.yml +echo "正在更新 docker-compose.yml..." +curl -o docker-compose-new.yml https://raw.githubusercontent.com/Nanjiren01/AIChatWeb/pro/docker-compose.yml + +# Merge new and old docker-compose.yml, prioritizing old file values +yq eval-all 'select(fileIndex == 0) * select(fileIndex == 1)' docker-compose-new.yml docker-compose-backup-$BACKUP_TIME.yml > temp.yml + +# Use sed to add empty lines before each service definition in the merged file +sed -i '/^[[:space:]]*$/d' temp.yml # Remove existing empty lines +sed -i '/^ [a-z].*:/i\\' temp.yml # Add an empty line before each service definition + +# Move the merged content back to the original docker-compose.yml file +mv temp.yml docker-compose.yml +rm docker-compose-new.yml + + +# Check if db service is used in the backup file +if awk '/depends_on:/ {found=1; next} found && /^\s*-\s*db/ {exit 1} /^\S/ {found=0}' "docker-compose-backup-$BACKUP_TIME.yml"; then + echo "AIChat正在使用外部数据库。请确保在继续之前已备份您的数据库。" + + # Prompt user for confirmation + read -p "您已备份外部数据库了吗?(y/N):" confirmation + if [[ $confirmation =~ ^[Yy]$ ]] || [[ $confirmation =~ ^[Nn]$ ]] || [[ -z $confirmation ]]; then + break + else + echo "无效输入,请输入 'y' 或 'n'。" + fi + + echo "数据库已备份,继续执行后续操作..." + + # Comment out the '- db' line under 'depends_on' in 'admin' service + sed -i '/admin:/,/environment:/ s/^\(.*- db\)/ #\1/' docker-compose.yml + + # Comment out the entire 'db' service configuration + sed -i '/^ db:/,/^$/ s/^/#/' docker-compose.yml + +else + # Backup MySQL files + backup_dir="./backups" + backup_filename="mysql_data_backup_$(date +%Y%m%d_%H%M%S).tar.gz" + mysql_data_dir="./mysql_data" + + # Pack MySQL files + mkdir -p "$backup_dir" + tar -czvf "$backup_dir/$backup_filename" "$mysql_data_dir" || { + echo "内部数据库备份失败,如果你在使用外部数据库,请先删掉yml中的db部分依赖"; + restore_original_docker_compose + exit 1; + } + + echo "MySQL 数据目录已压缩备份到 $backup_dir/$backup_filename" +fi + +# Check current Web Secret in docker-compose.yml and prompt for updates +CURRENT_WEB_SECRET=$(grep 'WEB_SECRET:' docker-compose.yml | cut -d ':' -f2 | xargs) +echo "当前的 Web Secret 为: $CURRENT_WEB_SECRET" +while true; do + read -p "您想更改 Web Secret 吗?(y/N): " DECISION + if [[ $DECISION =~ ^[Yy]$ ]] || [[ $DECISION =~ ^[Nn]$ ]] || [[ -z $DECISION ]]; then + break + else + echo "无效输入,请输入 'y' 或 'n'。" + fi +done + +if [[ "$DECISION" =~ ^[Yy]$ ]]; then + attempt_count=0 + max_attempts=3 + regex='^[A-Za-z0-9#@$%^&*()_+]{8,}$' + + while [ $attempt_count -lt $max_attempts ]; do + echo "请输入新的 Web Secret (尽量复杂,至少 8 个字符):" + read -p "Web Secret: " NEW_WEB_SECRET + + if [[ $NEW_WEB_SECRET =~ $regex ]]; then + # Update Web Secret for both admin and web services + sed -i "s/WEB_SECRET:.*/WEB_SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + sed -i "s/SECRET:.*/SECRET: $NEW_WEB_SECRET/g" docker-compose.yml + echo "Web Secret 已更新。" + break + else + echo "Web Secret 无效,请重新输入。" + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "尝试次数达到上限。正在退出脚本..." + restore_original_docker_compose + exit 1 + fi + done +fi + + +# Check for STORE_TYPE and prompt for configuration +STORE_TYPE=$(grep 'STORE_TYPE:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + +echo "当前的 Store Type 为: ${STORE_TYPE:-local}" +read -p "请输入以选择存储类型(输入 'local' 或 'oss'):" STORE_TYPE_CHOICE +STORE_TYPE=${STORE_TYPE_CHOICE:-$STORE_TYPE} + +attempt_count=0 +max_attempts=3 + +while [ $attempt_count -lt $max_attempts ]; do + if [[ "$STORE_TYPE" == "local" || "$STORE_TYPE" == "oss" ]]; then + break + fi + + read -p "输入无效。请输入 'local' 或 'oss'。 (尝试次数 $((attempt_count + 1))/$max_attempts): " STORE_TYPE_CHOICE + if [[ "$STORE_TYPE_CHOICE" == "local" || "$STORE_TYPE_CHOICE" == "oss" ]]; then + STORE_TYPE=$STORE_TYPE_CHOICE + break + else + echo "输入无效。请输入 'local' 或 'oss'。" + attempt_count=$((attempt_count + 1)) + fi + + if [ $attempt_count -eq $max_attempts ]; then + echo "尝试次数达到上限。正在退出脚本..." + restore_original_docker_compose + exit 1 + fi +done + + if [[ "$STORE_TYPE" == "local" ]]; then + # Handle local storage configuration + EXISTING_LOCAL_PATH=$(grep 'LOCAL_PATH:' "docker-compose-backup-$BACKUP_TIME.yml" | cut -d ':' -f2 | xargs) + echo "使用本地存储。当前路径为: ${EXISTING_LOCAL_PATH:-/app/aichat/images}" + read -p "输入新的本地存储路径(按Enter键使用现有/默认值): " NEW_LOCAL_PATH + LOCAL_PATH=${NEW_LOCAL_PATH:-$EXISTING_LOCAL_PATH} + sed -i "s#LOCAL_PATH:.*#LOCAL_PATH: $LOCAL_PATH#g" docker-compose.yml + else + # Handle OSS storage configuration + EXISTING_OSS_ENDPOINT=$(grep 'OSS_ENDPOINT:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_BUCKET_NAME=$(grep 'OSS_BUCKET_NAME:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_ID=$(grep 'OSS_ACCESS_KEY_ID:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + EXISTING_OSS_ACCESS_KEY_SECRET=$(grep 'OSS_ACCESS_KEY_SECRET:' "docker-compose-backup-$BACKUP_TIME.yml" | tail -n1 | cut -d ':' -f2- | xargs) + + echo "使用 OSS 存储。请输入新的 OSS 配置或直接按Enter键以使用现有值。" + + echo "当前 OSS Endpoint: $EXISTING_OSS_ENDPOINT" + read -p "输入新的 OSS Endpoint 或直接按Enter键保留原有值: " OSS_ENDPOINT + OSS_ENDPOINT=${OSS_ENDPOINT:-$EXISTING_OSS_ENDPOINT} + + echo "当前 OSS Bucket Name: $EXISTING_OSS_BUCKET_NAME" + read -p "输入新的 OSS Bucket Name 或直接按Enter键保留原有值: " OSS_BUCKET_NAME + OSS_BUCKET_NAME=${OSS_BUCKET_NAME:-$EXISTING_OSS_BUCKET_NAME} + + echo "当前 OSS Access Key ID: $EXISTING_OSS_ACCESS_KEY_ID" + read -p "输入新的 OSS Access Key ID 或直接按Enter键保留原有值: " OSS_ACCESS_KEY_ID + OSS_ACCESS_KEY_ID=${OSS_ACCESS_KEY_ID:-$EXISTING_OSS_ACCESS_KEY_ID} + + echo "当前 OSS Access Key Secret: $EXISTING_OSS_ACCESS_KEY_SECRET" + read -p "输入新的 OSS Access Key Secret 或直接按Enter键保留原有值: " OSS_ACCESS_KEY_SECRET + OSS_ACCESS_KEY_SECRET=${OSS_ACCESS_KEY_SECRET:-$EXISTING_OSS_ACCESS_KEY_SECRET} + + sed -i "s#STORE_TYPE:.*#STORE_TYPE: oss#g" docker-compose.yml + sed -i "s#OSS_ENDPOINT:.*#OSS_ENDPOINT: $OSS_ENDPOINT#g" docker-compose.yml + sed -i "s#OSS_BUCKET_NAME:.*#OSS_BUCKET_NAME: $OSS_BUCKET_NAME#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_ID:.*#OSS_ACCESS_KEY_ID: $OSS_ACCESS_KEY_ID#g" docker-compose.yml + sed -i "s#OSS_ACCESS_KEY_SECRET:.*#OSS_ACCESS_KEY_SECRET: $OSS_ACCESS_KEY_SECRET#g" docker-compose.yml + + fi + +# modify old docker repo http to https +sed -i 's/harbor.nanjiren.online:8099/harbor.nanjiren.online/g' docker-compose.yml + +while true; do + echo "请到QQ群公告查看账户信息" + echo "请输入 AIChat Pro 私有库账户用户名:" + read -p "用户名: " DOCKER_REGISTRY_USERNAME + echo "请输入 AIChat Pro 私有库账户密码:" + read -s -p "密码: " DOCKER_REGISTRY_PASSWORD + + # 登录 AIChat Pro 私有仓库 + echo "" + echo "正在登录 Docker 私有仓库..." + + echo $DOCKER_REGISTRY_PASSWORD | docker login -u $DOCKER_REGISTRY_USERNAME --password-stdin http://harbor.nanjiren.online + if [ $? -eq 0 ]; then + break + else + echo "AIChat Pro 登录失败,请到QQ群查看账户信息,重新输入账户和密码。" + fi +done + +if [ -f "docker-compose-new.yml" ]; then + rm -rf docker-compose-new.yml +fi + +# Start the updated docker-compose services +docker compose up -d + +docker compose ps +