diff --git a/run.sh b/run.sh index bbb1217c..fe6ef830 100644 --- a/run.sh +++ b/run.sh @@ -9,7 +9,6 @@ set -e RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[0;33m' -BLUE='\033[0;34m' CYAN='\033[0;36m' BOLD='\033[1m' NC='\033[0m' @@ -159,20 +158,18 @@ clone_project() { if ! command -v git &> /dev/null; then echo -e "${YELLOW}⚠️ Git not available. Trying wget/curl...${NC}" + local zip_url="https://gitee.com/zhayujie/chatgpt-on-wechat/repository/archive/master.zip" if command -v wget &> /dev/null; then - wget https://gitee.com/zhayujie/chatgpt-on-wechat/repository/archive/master.zip -O chatgpt-on-wechat.zip - unzip chatgpt-on-wechat.zip - mv chatgpt-on-wechat-master chatgpt-on-wechat - rm chatgpt-on-wechat.zip + wget "$zip_url" -O chatgpt-on-wechat.zip elif command -v curl &> /dev/null; then - curl -L https://gitee.com/zhayujie/chatgpt-on-wechat/repository/archive/master.zip -o chatgpt-on-wechat.zip - unzip chatgpt-on-wechat.zip - mv chatgpt-on-wechat-master chatgpt-on-wechat - rm chatgpt-on-wechat.zip + curl -L "$zip_url" -o chatgpt-on-wechat.zip else echo -e "${RED}❌ Cannot download project. Please install Git, wget, or curl.${NC}" exit 1 fi + unzip chatgpt-on-wechat.zip + mv chatgpt-on-wechat-master chatgpt-on-wechat + rm chatgpt-on-wechat.zip else git clone https://github.com/zhayujie/chatgpt-on-wechat.git || \ git clone https://gitee.com/zhayujie/chatgpt-on-wechat.git @@ -198,69 +195,52 @@ clone_project() { # Install dependencies install_dependencies() { echo -e "${GREEN}📦 Installing dependencies...${NC}" - - # For Python 3.11+, use --break-system-packages to avoid externally-managed-environment errors + local PIP_MIRROR="-i https://pypi.tuna.tsinghua.edu.cn/simple" + PIP_EXTRA_ARGS="" if $PYTHON_CMD -c "import sys; exit(0 if sys.version_info >= (3, 11) else 1)" 2>/dev/null; then PIP_EXTRA_ARGS="--break-system-packages" echo -e "${YELLOW}Python 3.11+ detected, using --break-system-packages for pip installations${NC}" fi - - # Upgrade pip and basic tools (ignore existing system packages to avoid conflicts) + echo -e "${YELLOW}Upgrading pip and basic tools...${NC}" set +e - $PYTHON_CMD -m pip install --upgrade pip setuptools wheel importlib_metadata --ignore-installed $PIP_EXTRA_ARGS -i https://pypi.tuna.tsinghua.edu.cn/simple > /tmp/pip_upgrade.log 2>&1 - if [ $? -ne 0 ]; then - echo -e "${YELLOW}⚠️ Some tools failed to upgrade, but continuing...${NC}" - cat /tmp/pip_upgrade.log | head -20 - fi + $PYTHON_CMD -m pip install --upgrade pip setuptools wheel importlib_metadata --ignore-installed $PIP_EXTRA_ARGS $PIP_MIRROR > /tmp/pip_upgrade.log 2>&1 + [ $? -ne 0 ] && echo -e "${YELLOW}⚠️ Some tools failed to upgrade, but continuing...${NC}" set -e rm -f /tmp/pip_upgrade.log - - # Common packages that may have distutils/system conflicts - COMMON_CONFLICT_PACKAGES="PyYAML setuptools wheel certifi charset-normalizer" - - # Try normal installation first + echo -e "${YELLOW}Installing project dependencies...${NC}" - - # Save output and capture exit code correctly - set +e # Temporarily disable exit on error - $PYTHON_CMD -m pip install -r requirements.txt $PIP_EXTRA_ARGS -i https://pypi.tuna.tsinghua.edu.cn/simple > /tmp/pip_install.log 2>&1 - INSTALL_EXIT_CODE=$? - set -e # Re-enable exit on error - - # Show output + set +e + $PYTHON_CMD -m pip install -r requirements.txt $PIP_EXTRA_ARGS $PIP_MIRROR > /tmp/pip_install.log 2>&1 + local exit_code=$? + set -e cat /tmp/pip_install.log - - if [ $INSTALL_EXIT_CODE -eq 0 ]; then + + if [ $exit_code -eq 0 ]; then echo -e "${GREEN}✅ Dependencies installed successfully.${NC}" + elif grep -qE "distutils installed project|uninstall-no-record-file|installed by debian" /tmp/pip_install.log; then + echo -e "${YELLOW}⚠️ Detected system package conflict, retrying with workaround...${NC}" + local IGNORE_PACKAGES="" + for pkg in PyYAML setuptools wheel certifi charset-normalizer; do + IGNORE_PACKAGES="$IGNORE_PACKAGES --ignore-installed $pkg" + done + set +e + $PYTHON_CMD -m pip install -r requirements.txt $IGNORE_PACKAGES $PIP_EXTRA_ARGS $PIP_MIRROR \ + && echo -e "${GREEN}✅ Dependencies installed successfully (workaround applied).${NC}" \ + || echo -e "${YELLOW}⚠️ Some dependencies may have issues, but continuing...${NC}" + set -e + elif grep -q "externally-managed-environment" /tmp/pip_install.log; then + echo -e "${YELLOW}⚠️ Detected externally-managed environment, retrying with --break-system-packages...${NC}" + set +e + $PYTHON_CMD -m pip install -r requirements.txt --break-system-packages $PIP_MIRROR \ + && echo -e "${GREEN}✅ Dependencies installed successfully (system packages override applied).${NC}" \ + || echo -e "${YELLOW}⚠️ Some dependencies may have issues, but continuing...${NC}" + set -e else - # Check if it's a distutils/system package conflict error - if grep -qE "distutils installed project|uninstall-no-record-file|installed by debian" /tmp/pip_install.log; then - echo -e "${YELLOW}⚠️ Detected system package conflict, retrying with workaround...${NC}" - # Only ignore common conflict packages - IGNORE_PACKAGES="" - for pkg in $COMMON_CONFLICT_PACKAGES; do - IGNORE_PACKAGES="$IGNORE_PACKAGES --ignore-installed $pkg" - done - - if $PYTHON_CMD -m pip install -r requirements.txt $IGNORE_PACKAGES $PIP_EXTRA_ARGS -i https://pypi.tuna.tsinghua.edu.cn/simple; then - echo -e "${GREEN}✅ Dependencies installed successfully (workaround applied).${NC}" - else - echo -e "${YELLOW}⚠️ Some dependencies may have issues, but continuing...${NC}" - fi - elif grep -q "externally-managed-environment" /tmp/pip_install.log; then - echo -e "${YELLOW}⚠️ Detected externally-managed environment, retrying with --break-system-packages...${NC}" - if $PYTHON_CMD -m pip install -r requirements.txt --break-system-packages -i https://pypi.tuna.tsinghua.edu.cn/simple; then - echo -e "${GREEN}✅ Dependencies installed successfully (system packages override applied).${NC}" - else - echo -e "${YELLOW}⚠️ Some dependencies may have issues, but continuing...${NC}" - fi - else - echo -e "${YELLOW}⚠️ Installation had errors, but continuing...${NC}" - fi + echo -e "${YELLOW}⚠️ Installation had errors, but continuing...${NC}" fi - + rm -f /tmp/pip_install.log } @@ -295,108 +275,48 @@ select_model() { done } +# Read model config: provider, default_model, key_variable_name +read_model_config() { + local provider=$1 default_model=$2 key_var=$3 + echo -e "${GREEN}Configuring ${provider}...${NC}" + read -p "Enter ${provider} API Key: " _api_key + read -p "Enter model name [press Enter for default: ${default_model}]: " model_name + model_name=${model_name:-$default_model} + MODEL_NAME="$model_name" + eval "${key_var}=\"\$_api_key\"" +} + +# Read optional API base URL +read_api_base() { + local base_var=$1 default_url=$2 + read -p "Enter API Base URL [press Enter for default: ${default_url}]: " api_base + api_base=${api_base:-$default_url} + eval "${base_var}=\"\$api_base\"" +} + # Configure model configure_model() { case "$model_choice" in - 1) - # MiniMax - echo -e "${GREEN}Configuring MiniMax...${NC}" - read -p "Enter MiniMax API Key: " minimax_key - read -p "Enter model name [press Enter for default: MiniMax-M2.7]: " model_name - model_name=${model_name:-MiniMax-M2.7} - - MODEL_NAME="$model_name" - MINIMAX_KEY="$minimax_key" - ;; - 2) - # Zhipu AI - echo -e "${GREEN}Configuring Zhipu AI...${NC}" - read -p "Enter Zhipu AI API Key: " zhipu_key - read -p "Enter model name [press Enter for default: glm-5-turbo]: " model_name - model_name=${model_name:-glm-5-turbo} - - MODEL_NAME="$model_name" - ZHIPU_KEY="$zhipu_key" - ;; - 3) - # Kimi (Moonshot) - echo -e "${GREEN}Configuring Kimi (Moonshot)...${NC}" - read -p "Enter Moonshot API Key: " moonshot_key - read -p "Enter model name [press Enter for default: kimi-k2.5]: " model_name - model_name=${model_name:-kimi-k2.5} - - MODEL_NAME="$model_name" - MOONSHOT_KEY="$moonshot_key" - ;; - 4) - # Doubao (Volcengine Ark) - echo -e "${GREEN}Configuring Doubao (Volcengine Ark)...${NC}" - read -p "Enter Ark API Key: " ark_key - read -p "Enter model name [press Enter for default: doubao-seed-2-0-code-preview-260215]: " model_name - model_name=${model_name:-doubao-seed-2-0-code-preview-260215} - - MODEL_NAME="$model_name" - ARK_KEY="$ark_key" - ;; - 5) - # Qwen (DashScope) - echo -e "${GREEN}Configuring Qwen (DashScope)...${NC}" - read -p "Enter DashScope API Key: " dashscope_key - read -p "Enter model name [press Enter for default: qwen3.5-plus]: " model_name - model_name=${model_name:-qwen3.5-plus} - - MODEL_NAME="$model_name" - DASHSCOPE_KEY="$dashscope_key" - ;; + 1) read_model_config "MiniMax" "MiniMax-M2.7" "MINIMAX_KEY" ;; + 2) read_model_config "Zhipu AI" "glm-5-turbo" "ZHIPU_KEY" ;; + 3) read_model_config "Kimi (Moonshot)" "kimi-k2.5" "MOONSHOT_KEY" ;; + 4) read_model_config "Doubao (Volcengine Ark)" "doubao-seed-2-0-code-preview-260215" "ARK_KEY" ;; + 5) read_model_config "Qwen (DashScope)" "qwen3.5-plus" "DASHSCOPE_KEY" ;; 6) - # Claude - echo -e "${GREEN}Configuring Claude...${NC}" - read -p "Enter Claude API Key: " claude_key - read -p "Enter model name [press Enter for default: claude-sonnet-4-6]: " model_name - model_name=${model_name:-claude-sonnet-4-6} - read -p "Enter API Base URL [press Enter for default: https://api.anthropic.com/v1]: " api_base - api_base=${api_base:-https://api.anthropic.com/v1} - - MODEL_NAME="$model_name" - CLAUDE_KEY="$claude_key" - CLAUDE_BASE="$api_base" + read_model_config "Claude" "claude-sonnet-4-6" "CLAUDE_KEY" + read_api_base "CLAUDE_BASE" "https://api.anthropic.com/v1" ;; 7) - # Gemini - echo -e "${GREEN}Configuring Gemini...${NC}" - read -p "Enter Gemini API Key: " gemini_key - read -p "Enter model name [press Enter for default: gemini-3.1-pro-preview]: " model_name - model_name=${model_name:-gemini-3.1-pro-preview} - read -p "Enter API Base URL [press Enter for default: https://generativelanguage.googleapis.com]: " api_base - api_base=${api_base:-https://generativelanguage.googleapis.com} - - MODEL_NAME="$model_name" - GEMINI_KEY="$gemini_key" - GEMINI_BASE="$api_base" + read_model_config "Gemini" "gemini-3.1-pro-preview" "GEMINI_KEY" + read_api_base "GEMINI_BASE" "https://generativelanguage.googleapis.com" ;; 8) - # OpenAI - echo -e "${GREEN}Configuring OpenAI GPT...${NC}" - read -p "Enter OpenAI API Key: " openai_key - read -p "Enter model name [press Enter for default: gpt-5.4]: " model_name - model_name=${model_name:-gpt-5.4} - read -p "Enter API Base URL [press Enter for default: https://api.openai.com/v1]: " api_base - api_base=${api_base:-https://api.openai.com/v1} - - MODEL_NAME="$model_name" - OPENAI_KEY="$openai_key" - OPENAI_BASE="$api_base" + read_model_config "OpenAI GPT" "gpt-5.4" "OPENAI_KEY" + read_api_base "OPENAI_BASE" "https://api.openai.com/v1" ;; 9) - # LinkAI - echo -e "${GREEN}Configuring LinkAI...${NC}" - read -p "Enter LinkAI API Key: " linkai_key - read -p "Enter model name [press Enter for default: MiniMax-M2.7]: " model_name - model_name=${model_name:-MiniMax-M2.7} - - MODEL_NAME="$model_name" + read_model_config "LinkAI" "MiniMax-M2.7" "LINKAI_KEY" USE_LINKAI="true" - LINKAI_KEY="$linkai_key" ;; esac } @@ -514,227 +434,86 @@ configure_channel() { # Generate config file create_config_file() { echo -e "${GREEN}📝 Generating config.json...${NC}" - - # Build JSON based on channel type - case "$CHANNEL_TYPE" in - feishu) - cat > config.json < config.json < config.json < config.json < config.json < config.json </dev/null || PYTHON_CMD="python3" fi - pid=$(ps ax | grep -i app.py | grep "${BASE_DIR}" | grep "$PYTHON_CMD" | grep -v grep | awk '{print $1}') - [ -n "$pid" ] } -# Get service PID +# Get service PID (empty string if not running) get_pid() { - if [ -z "$PYTHON_CMD" ]; then - detect_python_command 2>/dev/null || PYTHON_CMD="python3" - fi + ensure_python_cmd ps ax | grep -i app.py | grep "${BASE_DIR}" | grep "$PYTHON_CMD" | grep -v grep | awk '{print $1}' } +# Check if service is running +is_running() { + [ -n "$(get_pid)" ] +} + # Start service cmd_start() { # Check if config.json exists @@ -1023,67 +803,38 @@ install_mode() { fi } +# Require running inside the project directory +require_project_dir() { + if [ "$IS_PROJECT_DIR" = false ]; then + echo -e "${RED}${EMOJI_CROSS} Must run in project directory${NC}" + exit 1 + fi +} + # Main function main() { case "$1" in - start) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_start - ;; - stop) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_stop - ;; - restart) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_restart - ;; - status) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_status - ;; - logs) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_logs - ;; - config) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_config - ;; - update) - if [ "$IS_PROJECT_DIR" = false ]; then - echo -e "${RED}❌ Must run in project directory${NC}" - exit 1 - fi - cmd_update + start|stop|restart|status|logs|config|update) + require_project_dir ;; + esac + + case "$1" in + start) cmd_start ;; + stop) cmd_stop ;; + restart) cmd_restart ;; + status) cmd_status ;; + logs) cmd_logs ;; + config) cmd_config ;; + update) cmd_update ;; help|--help|-h) show_usage ;; "") - # No command - install/configure mode install_mode ;; *) - echo -e "${RED}❌ Unknown command: $1${NC}" + echo -e "${RED}${EMOJI_CROSS} Unknown command: $1${NC}" echo "" show_usage exit 1