Spaces:
Sleeping
Sleeping
Upload 12 files
Browse files- .env.example +2 -23
- .gitignore +2 -0
- deploy.bat +121 -0
- deploy.sh +123 -0
- main.py +146 -3
- requirements.txt +18 -14
- update.bat +111 -0
- update.sh +104 -0
.env.example
CHANGED
|
@@ -5,10 +5,6 @@
|
|
| 5 |
# 管理员密钥(必需,用于登录管理面板)
|
| 6 |
# 明文示例:
|
| 7 |
ADMIN_KEY=your-admin-secret-key
|
| 8 |
-
# Hash 示例(SHA256):ADMIN_KEY=sha256:你的32字节hex
|
| 9 |
-
|
| 10 |
-
# API密钥(可选,用于API端点认证,优先级:环境变量 > settings.yaml)
|
| 11 |
-
# API_KEY=your-api-key
|
| 12 |
|
| 13 |
# 服务端口(可选,默认 7860)
|
| 14 |
# PORT=7860
|
|
@@ -34,24 +30,7 @@ ADMIN_KEY=your-admin-secret-key
|
|
| 34 |
# ============================================
|
| 35 |
# 账户配置
|
| 36 |
# ============================================
|
| 37 |
-
#
|
| 38 |
# 账户配置保存在 accounts.json 文件中
|
| 39 |
# 首次启动时会自动创建空配置
|
| 40 |
-
# 请在管理面板中添加账户,或直接编辑 accounts.json
|
| 41 |
-
#
|
| 42 |
-
# 方式2:使用环境变量(适用于容器化部署,如抱脸等平台)
|
| 43 |
-
# 设置 ACCOUNTS_CONFIG 环境变量,值为 JSON 数组字符串
|
| 44 |
-
# 优先级:环境变量 > 文件
|
| 45 |
-
#
|
| 46 |
-
# ACCOUNTS_CONFIG='[{"id":"account_1","secure_c_ses":"your-cookie","csesidx":"your-idx","config_id":"your-config","expires_at":"2025-12-31 23:59:59"}]'
|
| 47 |
-
#
|
| 48 |
-
# 账户配置格式示例:
|
| 49 |
-
# [
|
| 50 |
-
# {
|
| 51 |
-
# "id": "account_1",
|
| 52 |
-
# "secure_c_ses": "your-cookie-here",
|
| 53 |
-
# "csesidx": "your-idx",
|
| 54 |
-
# "config_id": "your-config",
|
| 55 |
-
# "expires_at": "2025-12-31 23:59:59"
|
| 56 |
-
# }
|
| 57 |
-
# ]
|
|
|
|
| 5 |
# 管理员密钥(必需,用于登录管理面板)
|
| 6 |
# 明文示例:
|
| 7 |
ADMIN_KEY=your-admin-secret-key
|
|
|
|
|
|
|
|
|
|
|
|
|
| 8 |
|
| 9 |
# 服务端口(可选,默认 7860)
|
| 10 |
# PORT=7860
|
|
|
|
| 30 |
# ============================================
|
| 31 |
# 账户配置
|
| 32 |
# ============================================
|
| 33 |
+
# 使用 accounts.json 文件
|
| 34 |
# 账户配置保存在 accounts.json 文件中
|
| 35 |
# 首次启动时会自动创建空配置
|
| 36 |
+
# 请在管理面板中添加账户,或直接编辑 accounts.json
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
.gitignore
CHANGED
|
@@ -39,7 +39,9 @@ ENV/
|
|
| 39 |
# Generated files
|
| 40 |
data/
|
| 41 |
logs/
|
|
|
|
| 42 |
|
| 43 |
# OS
|
| 44 |
.DS_Store
|
| 45 |
Thumbs.db
|
|
|
|
|
|
| 39 |
# Generated files
|
| 40 |
data/
|
| 41 |
logs/
|
| 42 |
+
static/
|
| 43 |
|
| 44 |
# OS
|
| 45 |
.DS_Store
|
| 46 |
Thumbs.db
|
| 47 |
+
old_version.py
|
deploy.bat
ADDED
|
@@ -0,0 +1,121 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@echo off
|
| 2 |
+
REM Gemini Business2API Deployment Script for Windows
|
| 3 |
+
REM This script automates the initial deployment process
|
| 4 |
+
|
| 5 |
+
setlocal enabledelayedexpansion
|
| 6 |
+
|
| 7 |
+
echo ==========================================
|
| 8 |
+
echo Gemini Business2API Deployment Script
|
| 9 |
+
echo ==========================================
|
| 10 |
+
echo.
|
| 11 |
+
|
| 12 |
+
REM Check if git is installed
|
| 13 |
+
where git >nul 2>nul
|
| 14 |
+
if %errorlevel% neq 0 (
|
| 15 |
+
echo [ERROR] Git is not installed. Please install git first.
|
| 16 |
+
exit /b 1
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
REM Check if python is installed
|
| 20 |
+
where python >nul 2>nul
|
| 21 |
+
if %errorlevel% neq 0 (
|
| 22 |
+
echo [ERROR] Python is not installed. Please install Python 3.11+ first.
|
| 23 |
+
exit /b 1
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
REM Check if npm is installed
|
| 27 |
+
where npm >nul 2>nul
|
| 28 |
+
if %errorlevel% neq 0 (
|
| 29 |
+
echo [ERROR] npm is not installed. Please install Node.js and npm first.
|
| 30 |
+
exit /b 1
|
| 31 |
+
)
|
| 32 |
+
|
| 33 |
+
REM Step 1: Build frontend
|
| 34 |
+
echo [STEP] Step 1: Building frontend...
|
| 35 |
+
if exist "frontend" (
|
| 36 |
+
cd frontend
|
| 37 |
+
echo [INFO] Installing frontend dependencies...
|
| 38 |
+
call npm install
|
| 39 |
+
if %errorlevel% neq 0 (
|
| 40 |
+
echo [ERROR] Failed to install frontend dependencies
|
| 41 |
+
exit /b 1
|
| 42 |
+
)
|
| 43 |
+
|
| 44 |
+
echo [INFO] Building frontend...
|
| 45 |
+
call npm run build
|
| 46 |
+
if %errorlevel% neq 0 (
|
| 47 |
+
echo [ERROR] Failed to build frontend
|
| 48 |
+
exit /b 1
|
| 49 |
+
)
|
| 50 |
+
|
| 51 |
+
echo [SUCCESS] Frontend built successfully
|
| 52 |
+
cd ..
|
| 53 |
+
) else (
|
| 54 |
+
echo [ERROR] Frontend directory not found. Are you in the project root?
|
| 55 |
+
exit /b 1
|
| 56 |
+
)
|
| 57 |
+
|
| 58 |
+
REM Step 2: Create virtual environment
|
| 59 |
+
echo [STEP] Step 2: Setting up Python virtual environment...
|
| 60 |
+
if exist ".venv" (
|
| 61 |
+
echo [INFO] Virtual environment already exists, skipping creation
|
| 62 |
+
) else (
|
| 63 |
+
echo [INFO] Creating virtual environment...
|
| 64 |
+
python -m venv .venv
|
| 65 |
+
if %errorlevel% neq 0 (
|
| 66 |
+
echo [ERROR] Failed to create virtual environment
|
| 67 |
+
exit /b 1
|
| 68 |
+
)
|
| 69 |
+
echo [SUCCESS] Virtual environment created
|
| 70 |
+
)
|
| 71 |
+
|
| 72 |
+
REM Activate virtual environment
|
| 73 |
+
echo [INFO] Activating virtual environment...
|
| 74 |
+
call .venv\Scripts\activate.bat
|
| 75 |
+
|
| 76 |
+
REM Step 3: Install Python dependencies
|
| 77 |
+
echo [STEP] Step 3: Installing Python dependencies...
|
| 78 |
+
python -m pip install --upgrade pip
|
| 79 |
+
python -m pip install -r requirements.txt
|
| 80 |
+
if %errorlevel% neq 0 (
|
| 81 |
+
echo [ERROR] Failed to install Python dependencies
|
| 82 |
+
exit /b 1
|
| 83 |
+
)
|
| 84 |
+
echo [SUCCESS] Python dependencies installed
|
| 85 |
+
|
| 86 |
+
REM Step 4: Setup .env file
|
| 87 |
+
echo [STEP] Step 4: Setting up configuration...
|
| 88 |
+
if exist ".env" (
|
| 89 |
+
echo [INFO] .env file already exists, skipping
|
| 90 |
+
) else (
|
| 91 |
+
if exist ".env.example" (
|
| 92 |
+
copy /Y ".env.example" ".env" >nul
|
| 93 |
+
echo [SUCCESS] .env file created from .env.example
|
| 94 |
+
) else (
|
| 95 |
+
echo [ERROR] .env.example not found
|
| 96 |
+
exit /b 1
|
| 97 |
+
)
|
| 98 |
+
)
|
| 99 |
+
|
| 100 |
+
REM Step 5: Show completion message
|
| 101 |
+
echo.
|
| 102 |
+
echo ==========================================
|
| 103 |
+
echo [SUCCESS] Deployment completed successfully!
|
| 104 |
+
echo ==========================================
|
| 105 |
+
echo.
|
| 106 |
+
echo [INFO] Next steps:
|
| 107 |
+
echo.
|
| 108 |
+
echo 1. Edit .env file and set your ADMIN_KEY:
|
| 109 |
+
echo notepad .env
|
| 110 |
+
echo.
|
| 111 |
+
echo 2. Start the service:
|
| 112 |
+
echo python main.py
|
| 113 |
+
echo.
|
| 114 |
+
echo 3. Access the admin panel:
|
| 115 |
+
echo http://localhost:7860/
|
| 116 |
+
echo.
|
| 117 |
+
echo [INFO] Optional: To activate virtual environment later, run:
|
| 118 |
+
echo .venv\Scripts\activate.bat
|
| 119 |
+
echo.
|
| 120 |
+
|
| 121 |
+
endlocal
|
deploy.sh
ADDED
|
@@ -0,0 +1,123 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Gemini Business2API Deployment Script for Linux/macOS
|
| 4 |
+
# This script automates the initial deployment process
|
| 5 |
+
|
| 6 |
+
set -e # Exit on error
|
| 7 |
+
|
| 8 |
+
echo "=========================================="
|
| 9 |
+
echo "Gemini Business2API Deployment Script"
|
| 10 |
+
echo "=========================================="
|
| 11 |
+
echo ""
|
| 12 |
+
|
| 13 |
+
# Color codes for output
|
| 14 |
+
RED='\033[0;31m'
|
| 15 |
+
GREEN='\033[0;32m'
|
| 16 |
+
YELLOW='\033[1;33m'
|
| 17 |
+
BLUE='\033[0;34m'
|
| 18 |
+
NC='\033[0m' # No Color
|
| 19 |
+
|
| 20 |
+
# Function to print colored messages
|
| 21 |
+
print_success() {
|
| 22 |
+
echo -e "${GREEN}[SUCCESS] $1${NC}"
|
| 23 |
+
}
|
| 24 |
+
|
| 25 |
+
print_error() {
|
| 26 |
+
echo -e "${RED}[ERROR] $1${NC}"
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
print_info() {
|
| 30 |
+
echo -e "${YELLOW}[INFO] $1${NC}"
|
| 31 |
+
}
|
| 32 |
+
|
| 33 |
+
print_step() {
|
| 34 |
+
echo -e "${BLUE}[STEP] $1${NC}"
|
| 35 |
+
}
|
| 36 |
+
|
| 37 |
+
# Check if git is installed
|
| 38 |
+
if ! command -v git &> /dev/null; then
|
| 39 |
+
print_error "Git is not installed. Please install git first."
|
| 40 |
+
exit 1
|
| 41 |
+
fi
|
| 42 |
+
|
| 43 |
+
# Check if python3 is installed
|
| 44 |
+
if ! command -v python3 &> /dev/null; then
|
| 45 |
+
print_error "Python3 is not installed. Please install Python 3.11+ first."
|
| 46 |
+
exit 1
|
| 47 |
+
fi
|
| 48 |
+
|
| 49 |
+
# Check if npm is installed
|
| 50 |
+
if ! command -v npm &> /dev/null; then
|
| 51 |
+
print_error "npm is not installed. Please install Node.js and npm first."
|
| 52 |
+
exit 1
|
| 53 |
+
fi
|
| 54 |
+
|
| 55 |
+
# Step 1: Build frontend
|
| 56 |
+
print_step "Step 1: Building frontend..."
|
| 57 |
+
if [ -d "frontend" ]; then
|
| 58 |
+
cd frontend
|
| 59 |
+
print_info "Installing frontend dependencies..."
|
| 60 |
+
npm install
|
| 61 |
+
print_info "Building frontend..."
|
| 62 |
+
npm run build
|
| 63 |
+
print_success "Frontend built successfully"
|
| 64 |
+
cd ..
|
| 65 |
+
else
|
| 66 |
+
print_error "Frontend directory not found. Are you in the project root?"
|
| 67 |
+
exit 1
|
| 68 |
+
fi
|
| 69 |
+
|
| 70 |
+
# Step 2: Create virtual environment
|
| 71 |
+
print_step "Step 2: Setting up Python virtual environment..."
|
| 72 |
+
if [ -d ".venv" ]; then
|
| 73 |
+
print_info "Virtual environment already exists, skipping creation"
|
| 74 |
+
else
|
| 75 |
+
print_info "Creating virtual environment..."
|
| 76 |
+
python3 -m venv .venv
|
| 77 |
+
print_success "Virtual environment created"
|
| 78 |
+
fi
|
| 79 |
+
|
| 80 |
+
# Activate virtual environment
|
| 81 |
+
print_info "Activating virtual environment..."
|
| 82 |
+
source .venv/bin/activate
|
| 83 |
+
|
| 84 |
+
# Step 3: Install Python dependencies
|
| 85 |
+
print_step "Step 3: Installing Python dependencies..."
|
| 86 |
+
pip install --upgrade pip
|
| 87 |
+
pip install -r requirements.txt
|
| 88 |
+
print_success "Python dependencies installed"
|
| 89 |
+
|
| 90 |
+
# Step 4: Setup .env file
|
| 91 |
+
print_step "Step 4: Setting up configuration..."
|
| 92 |
+
if [ -f ".env" ]; then
|
| 93 |
+
print_info ".env file already exists, skipping"
|
| 94 |
+
else
|
| 95 |
+
if [ -f ".env.example" ]; then
|
| 96 |
+
cp .env.example .env
|
| 97 |
+
print_success ".env file created from .env.example"
|
| 98 |
+
else
|
| 99 |
+
print_error ".env.example not found"
|
| 100 |
+
exit 1
|
| 101 |
+
fi
|
| 102 |
+
fi
|
| 103 |
+
|
| 104 |
+
# Step 5: Show completion message
|
| 105 |
+
echo ""
|
| 106 |
+
echo "=========================================="
|
| 107 |
+
print_success "Deployment completed successfully!"
|
| 108 |
+
echo "=========================================="
|
| 109 |
+
echo ""
|
| 110 |
+
print_info "Next steps:"
|
| 111 |
+
echo ""
|
| 112 |
+
echo " 1. Edit .env file and set your ADMIN_KEY:"
|
| 113 |
+
echo " ${BLUE}nano .env${NC} or ${BLUE}vim .env${NC}"
|
| 114 |
+
echo ""
|
| 115 |
+
echo " 2. Start the service:"
|
| 116 |
+
echo " ${BLUE}python main.py${NC}"
|
| 117 |
+
echo ""
|
| 118 |
+
echo " 3. Access the admin panel:"
|
| 119 |
+
echo " ${BLUE}http://localhost:7860/${NC}"
|
| 120 |
+
echo ""
|
| 121 |
+
print_info "Optional: To activate virtual environment later, run:"
|
| 122 |
+
echo " ${BLUE}source .venv/bin/activate${NC}"
|
| 123 |
+
echo ""
|
main.py
CHANGED
|
@@ -321,6 +321,49 @@ multi_account_mgr = load_multi_account_config(
|
|
| 321 |
global_stats
|
| 322 |
)
|
| 323 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 324 |
# 验证必需的环境变量
|
| 325 |
if not ADMIN_KEY:
|
| 326 |
logger.error("[SYSTEM] 未配置 ADMIN_KEY 环境变量,请设置后重启")
|
|
@@ -534,6 +577,16 @@ async def startup_event():
|
|
| 534 |
elif storage.is_database_enabled():
|
| 535 |
logger.info("[SYSTEM] 自动刷新账号功能已禁用(配置为0)")
|
| 536 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 537 |
# ---------- 日志脱敏函数 ----------
|
| 538 |
def get_sanitized_logs(limit: int = 100) -> list:
|
| 539 |
"""获取脱敏后的日志列表,按请求ID分组并提取关键事件"""
|
|
@@ -943,6 +996,70 @@ async def admin_update_config(request: Request, accounts_data: list = Body(...))
|
|
| 943 |
logger.error(f"[CONFIG] 更新配置失败: {str(e)}")
|
| 944 |
raise HTTPException(500, f"更新失败: {str(e)}")
|
| 945 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 946 |
@app.delete("/admin/accounts/{account_id}")
|
| 947 |
@require_login()
|
| 948 |
async def admin_delete_account(request: Request, account_id: str):
|
|
@@ -1010,7 +1127,14 @@ async def admin_get_settings(request: Request):
|
|
| 1010 |
"basic": {
|
| 1011 |
"api_key": config.basic.api_key,
|
| 1012 |
"base_url": config.basic.base_url,
|
| 1013 |
-
"proxy": config.basic.proxy
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1014 |
},
|
| 1015 |
"image_generation": {
|
| 1016 |
"enabled": config.image_generation.enabled,
|
|
@@ -1023,7 +1147,8 @@ async def admin_get_settings(request: Request):
|
|
| 1023 |
"max_account_switch_tries": config.retry.max_account_switch_tries,
|
| 1024 |
"account_failure_threshold": config.retry.account_failure_threshold,
|
| 1025 |
"rate_limit_cooldown_seconds": config.retry.rate_limit_cooldown_seconds,
|
| 1026 |
-
"session_cache_ttl_seconds": config.retry.session_cache_ttl_seconds
|
|
|
|
| 1027 |
},
|
| 1028 |
"public_display": {
|
| 1029 |
"logo_url": config.public_display.logo_url,
|
|
@@ -1041,10 +1166,23 @@ async def admin_update_settings(request: Request, new_settings: dict = Body(...)
|
|
| 1041 |
global API_KEY, PROXY, BASE_URL, LOGO_URL, CHAT_URL
|
| 1042 |
global IMAGE_GENERATION_ENABLED, IMAGE_GENERATION_MODELS
|
| 1043 |
global MAX_NEW_SESSION_TRIES, MAX_REQUEST_RETRIES, MAX_ACCOUNT_SWITCH_TRIES
|
| 1044 |
-
global ACCOUNT_FAILURE_THRESHOLD, RATE_LIMIT_COOLDOWN_SECONDS, SESSION_CACHE_TTL_SECONDS
|
| 1045 |
global SESSION_EXPIRE_HOURS, multi_account_mgr, http_client
|
| 1046 |
|
| 1047 |
try:
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1048 |
image_generation = dict(new_settings.get("image_generation") or {})
|
| 1049 |
output_format = str(image_generation.get("output_format") or config_manager.image_output_format).lower()
|
| 1050 |
if output_format not in ("base64", "url"):
|
|
@@ -1052,6 +1190,10 @@ async def admin_update_settings(request: Request, new_settings: dict = Body(...)
|
|
| 1052 |
image_generation["output_format"] = output_format
|
| 1053 |
new_settings["image_generation"] = image_generation
|
| 1054 |
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1055 |
# 保存旧配置用于对比
|
| 1056 |
old_proxy = PROXY
|
| 1057 |
old_retry_config = {
|
|
@@ -1080,6 +1222,7 @@ async def admin_update_settings(request: Request, new_settings: dict = Body(...)
|
|
| 1080 |
ACCOUNT_FAILURE_THRESHOLD = config.retry.account_failure_threshold
|
| 1081 |
RATE_LIMIT_COOLDOWN_SECONDS = config.retry.rate_limit_cooldown_seconds
|
| 1082 |
SESSION_CACHE_TTL_SECONDS = config.retry.session_cache_ttl_seconds
|
|
|
|
| 1083 |
SESSION_EXPIRE_HOURS = config.session.expire_hours
|
| 1084 |
|
| 1085 |
# 检查是否需要重建 HTTP 客户端(代理变化)
|
|
|
|
| 321 |
global_stats
|
| 322 |
)
|
| 323 |
|
| 324 |
+
# ---------- 自动注册/刷新服务 ----------
|
| 325 |
+
register_service = None
|
| 326 |
+
login_service = None
|
| 327 |
+
|
| 328 |
+
def _set_multi_account_mgr(new_mgr):
|
| 329 |
+
global multi_account_mgr
|
| 330 |
+
multi_account_mgr = new_mgr
|
| 331 |
+
if register_service:
|
| 332 |
+
register_service.multi_account_mgr = new_mgr
|
| 333 |
+
if login_service:
|
| 334 |
+
login_service.multi_account_mgr = new_mgr
|
| 335 |
+
|
| 336 |
+
def _get_global_stats():
|
| 337 |
+
return global_stats
|
| 338 |
+
|
| 339 |
+
try:
|
| 340 |
+
from core.register_service import RegisterService
|
| 341 |
+
from core.login_service import LoginService
|
| 342 |
+
register_service = RegisterService(
|
| 343 |
+
multi_account_mgr,
|
| 344 |
+
http_client,
|
| 345 |
+
USER_AGENT,
|
| 346 |
+
ACCOUNT_FAILURE_THRESHOLD,
|
| 347 |
+
RATE_LIMIT_COOLDOWN_SECONDS,
|
| 348 |
+
SESSION_CACHE_TTL_SECONDS,
|
| 349 |
+
_get_global_stats,
|
| 350 |
+
_set_multi_account_mgr,
|
| 351 |
+
)
|
| 352 |
+
login_service = LoginService(
|
| 353 |
+
multi_account_mgr,
|
| 354 |
+
http_client,
|
| 355 |
+
USER_AGENT,
|
| 356 |
+
ACCOUNT_FAILURE_THRESHOLD,
|
| 357 |
+
RATE_LIMIT_COOLDOWN_SECONDS,
|
| 358 |
+
SESSION_CACHE_TTL_SECONDS,
|
| 359 |
+
_get_global_stats,
|
| 360 |
+
_set_multi_account_mgr,
|
| 361 |
+
)
|
| 362 |
+
except Exception as e:
|
| 363 |
+
logger.warning("[SYSTEM] 自动注册/刷新服务不可用: %s", e)
|
| 364 |
+
register_service = None
|
| 365 |
+
login_service = None
|
| 366 |
+
|
| 367 |
# 验证必需的环境变量
|
| 368 |
if not ADMIN_KEY:
|
| 369 |
logger.error("[SYSTEM] 未配置 ADMIN_KEY 环境变量,请设置后重启")
|
|
|
|
| 577 |
elif storage.is_database_enabled():
|
| 578 |
logger.info("[SYSTEM] 自动刷新账号功能已禁用(配置为0)")
|
| 579 |
|
| 580 |
+
# 启动自动登录刷新轮询
|
| 581 |
+
if login_service:
|
| 582 |
+
try:
|
| 583 |
+
asyncio.create_task(login_service.start_polling())
|
| 584 |
+
logger.info("[SYSTEM] 账户过期检查轮询已启动(间隔: 30分钟)")
|
| 585 |
+
except Exception as e:
|
| 586 |
+
logger.error(f"[SYSTEM] 启动登录服务失败: {e}")
|
| 587 |
+
else:
|
| 588 |
+
logger.info("[SYSTEM] 自动登录刷新未启用或依赖不可用")
|
| 589 |
+
|
| 590 |
# ---------- 日志脱敏函数 ----------
|
| 591 |
def get_sanitized_logs(limit: int = 100) -> list:
|
| 592 |
"""获取脱敏后的日志列表,按请求ID分组并提取关键事件"""
|
|
|
|
| 996 |
logger.error(f"[CONFIG] 更新配置失败: {str(e)}")
|
| 997 |
raise HTTPException(500, f"更新失败: {str(e)}")
|
| 998 |
|
| 999 |
+
@app.post("/admin/register/start")
|
| 1000 |
+
@require_login()
|
| 1001 |
+
async def admin_start_register(request: Request, count: Optional[int] = Body(default=None), domain: Optional[str] = Body(default=None)):
|
| 1002 |
+
if not register_service:
|
| 1003 |
+
raise HTTPException(503, "register service unavailable")
|
| 1004 |
+
task = await register_service.start_register(count=count, domain=domain)
|
| 1005 |
+
return task.to_dict()
|
| 1006 |
+
|
| 1007 |
+
@app.get("/admin/register/task/{task_id}")
|
| 1008 |
+
@require_login()
|
| 1009 |
+
async def admin_get_register_task(request: Request, task_id: str):
|
| 1010 |
+
if not register_service:
|
| 1011 |
+
raise HTTPException(503, "register service unavailable")
|
| 1012 |
+
task = register_service.get_task(task_id)
|
| 1013 |
+
if not task:
|
| 1014 |
+
raise HTTPException(404, "task not found")
|
| 1015 |
+
return task.to_dict()
|
| 1016 |
+
|
| 1017 |
+
@app.get("/admin/register/current")
|
| 1018 |
+
@require_login()
|
| 1019 |
+
async def admin_get_current_register_task(request: Request):
|
| 1020 |
+
if not register_service:
|
| 1021 |
+
raise HTTPException(503, "register service unavailable")
|
| 1022 |
+
task = register_service.get_current_task()
|
| 1023 |
+
if not task:
|
| 1024 |
+
return {"status": "idle"}
|
| 1025 |
+
return task.to_dict()
|
| 1026 |
+
|
| 1027 |
+
@app.post("/admin/login/start")
|
| 1028 |
+
@require_login()
|
| 1029 |
+
async def admin_start_login(request: Request, account_ids: List[str] = Body(...)):
|
| 1030 |
+
if not login_service:
|
| 1031 |
+
raise HTTPException(503, "login service unavailable")
|
| 1032 |
+
task = await login_service.start_login(account_ids)
|
| 1033 |
+
return task.to_dict()
|
| 1034 |
+
|
| 1035 |
+
@app.get("/admin/login/task/{task_id}")
|
| 1036 |
+
@require_login()
|
| 1037 |
+
async def admin_get_login_task(request: Request, task_id: str):
|
| 1038 |
+
if not login_service:
|
| 1039 |
+
raise HTTPException(503, "login service unavailable")
|
| 1040 |
+
task = login_service.get_task(task_id)
|
| 1041 |
+
if not task:
|
| 1042 |
+
raise HTTPException(404, "task not found")
|
| 1043 |
+
return task.to_dict()
|
| 1044 |
+
|
| 1045 |
+
@app.get("/admin/login/current")
|
| 1046 |
+
@require_login()
|
| 1047 |
+
async def admin_get_current_login_task(request: Request):
|
| 1048 |
+
if not login_service:
|
| 1049 |
+
raise HTTPException(503, "login service unavailable")
|
| 1050 |
+
task = login_service.get_current_task()
|
| 1051 |
+
if not task:
|
| 1052 |
+
return {"status": "idle"}
|
| 1053 |
+
return task.to_dict()
|
| 1054 |
+
|
| 1055 |
+
@app.post("/admin/login/check")
|
| 1056 |
+
@require_login()
|
| 1057 |
+
async def admin_check_login_refresh(request: Request):
|
| 1058 |
+
if not login_service:
|
| 1059 |
+
raise HTTPException(503, "login service unavailable")
|
| 1060 |
+
await login_service.check_and_refresh()
|
| 1061 |
+
return {"status": "ok"}
|
| 1062 |
+
|
| 1063 |
@app.delete("/admin/accounts/{account_id}")
|
| 1064 |
@require_login()
|
| 1065 |
async def admin_delete_account(request: Request, account_id: str):
|
|
|
|
| 1127 |
"basic": {
|
| 1128 |
"api_key": config.basic.api_key,
|
| 1129 |
"base_url": config.basic.base_url,
|
| 1130 |
+
"proxy": config.basic.proxy,
|
| 1131 |
+
"duckmail_base_url": config.basic.duckmail_base_url,
|
| 1132 |
+
"duckmail_api_key": config.basic.duckmail_api_key,
|
| 1133 |
+
"duckmail_verify_ssl": config.basic.duckmail_verify_ssl,
|
| 1134 |
+
"browser_headless": config.basic.browser_headless,
|
| 1135 |
+
"refresh_window_hours": config.basic.refresh_window_hours,
|
| 1136 |
+
"register_default_count": config.basic.register_default_count,
|
| 1137 |
+
"register_domain": config.basic.register_domain,
|
| 1138 |
},
|
| 1139 |
"image_generation": {
|
| 1140 |
"enabled": config.image_generation.enabled,
|
|
|
|
| 1147 |
"max_account_switch_tries": config.retry.max_account_switch_tries,
|
| 1148 |
"account_failure_threshold": config.retry.account_failure_threshold,
|
| 1149 |
"rate_limit_cooldown_seconds": config.retry.rate_limit_cooldown_seconds,
|
| 1150 |
+
"session_cache_ttl_seconds": config.retry.session_cache_ttl_seconds,
|
| 1151 |
+
"auto_refresh_accounts_seconds": config.retry.auto_refresh_accounts_seconds
|
| 1152 |
},
|
| 1153 |
"public_display": {
|
| 1154 |
"logo_url": config.public_display.logo_url,
|
|
|
|
| 1166 |
global API_KEY, PROXY, BASE_URL, LOGO_URL, CHAT_URL
|
| 1167 |
global IMAGE_GENERATION_ENABLED, IMAGE_GENERATION_MODELS
|
| 1168 |
global MAX_NEW_SESSION_TRIES, MAX_REQUEST_RETRIES, MAX_ACCOUNT_SWITCH_TRIES
|
| 1169 |
+
global ACCOUNT_FAILURE_THRESHOLD, RATE_LIMIT_COOLDOWN_SECONDS, SESSION_CACHE_TTL_SECONDS, AUTO_REFRESH_ACCOUNTS_SECONDS
|
| 1170 |
global SESSION_EXPIRE_HOURS, multi_account_mgr, http_client
|
| 1171 |
|
| 1172 |
try:
|
| 1173 |
+
basic = dict(new_settings.get("basic") or {})
|
| 1174 |
+
basic.setdefault("duckmail_base_url", config.basic.duckmail_base_url)
|
| 1175 |
+
basic.setdefault("duckmail_api_key", config.basic.duckmail_api_key)
|
| 1176 |
+
basic.setdefault("duckmail_verify_ssl", config.basic.duckmail_verify_ssl)
|
| 1177 |
+
basic.setdefault("browser_headless", config.basic.browser_headless)
|
| 1178 |
+
basic.setdefault("refresh_window_hours", config.basic.refresh_window_hours)
|
| 1179 |
+
basic.setdefault("register_default_count", config.basic.register_default_count)
|
| 1180 |
+
basic.setdefault("register_domain", config.basic.register_domain)
|
| 1181 |
+
if not isinstance(basic.get("register_domain"), str):
|
| 1182 |
+
basic["register_domain"] = ""
|
| 1183 |
+
basic.pop("duckmail_proxy", None)
|
| 1184 |
+
new_settings["basic"] = basic
|
| 1185 |
+
|
| 1186 |
image_generation = dict(new_settings.get("image_generation") or {})
|
| 1187 |
output_format = str(image_generation.get("output_format") or config_manager.image_output_format).lower()
|
| 1188 |
if output_format not in ("base64", "url"):
|
|
|
|
| 1190 |
image_generation["output_format"] = output_format
|
| 1191 |
new_settings["image_generation"] = image_generation
|
| 1192 |
|
| 1193 |
+
retry = dict(new_settings.get("retry") or {})
|
| 1194 |
+
retry.setdefault("auto_refresh_accounts_seconds", config.retry.auto_refresh_accounts_seconds)
|
| 1195 |
+
new_settings["retry"] = retry
|
| 1196 |
+
|
| 1197 |
# 保存旧配置用于对比
|
| 1198 |
old_proxy = PROXY
|
| 1199 |
old_retry_config = {
|
|
|
|
| 1222 |
ACCOUNT_FAILURE_THRESHOLD = config.retry.account_failure_threshold
|
| 1223 |
RATE_LIMIT_COOLDOWN_SECONDS = config.retry.rate_limit_cooldown_seconds
|
| 1224 |
SESSION_CACHE_TTL_SECONDS = config.retry.session_cache_ttl_seconds
|
| 1225 |
+
AUTO_REFRESH_ACCOUNTS_SECONDS = config.retry.auto_refresh_accounts_seconds
|
| 1226 |
SESSION_EXPIRE_HOURS = config.session.expire_hours
|
| 1227 |
|
| 1228 |
# 检查是否需要重建 HTTP 客户端(代理变化)
|
requirements.txt
CHANGED
|
@@ -1,14 +1,18 @@
|
|
| 1 |
-
fastapi==0.110.0
|
| 2 |
-
uvicorn[standard]==0.29.0
|
| 3 |
-
httpx==0.27.0
|
| 4 |
-
pydantic==2.7.0
|
| 5 |
-
aiofiles==24.1.0
|
| 6 |
-
python-dotenv==1.0.1
|
| 7 |
-
itsdangerous==2.1.2
|
| 8 |
-
python-multipart==0.0.6
|
| 9 |
-
pyyaml>=6.0
|
| 10 |
-
jinja2>=3.1.0
|
| 11 |
-
|
| 12 |
-
|
| 13 |
-
|
| 14 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
fastapi==0.110.0
|
| 2 |
+
uvicorn[standard]==0.29.0
|
| 3 |
+
httpx==0.27.0
|
| 4 |
+
pydantic==2.7.0
|
| 5 |
+
aiofiles==24.1.0
|
| 6 |
+
python-dotenv==1.0.1
|
| 7 |
+
itsdangerous==2.1.2
|
| 8 |
+
python-multipart==0.0.6
|
| 9 |
+
pyyaml>=6.0
|
| 10 |
+
jinja2>=3.1.0
|
| 11 |
+
requests==2.32.3
|
| 12 |
+
DrissionPage==4.0.5.6
|
| 13 |
+
undetected-chromedriver>=3.5.5
|
| 14 |
+
selenium>=4.15.0
|
| 15 |
+
|
| 16 |
+
# 可选:PostgreSQL 数据库支持(用于 HF Spaces 等无持久化存储的环境)
|
| 17 |
+
# 如需使用,请取消下行注释并设置 DATABASE_URL 环境变量
|
| 18 |
+
asyncpg>=0.29.0
|
update.bat
ADDED
|
@@ -0,0 +1,111 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
@echo off
|
| 2 |
+
REM Gemini Business2API Update Script for Windows
|
| 3 |
+
REM This script updates the project to the latest version
|
| 4 |
+
|
| 5 |
+
setlocal enabledelayedexpansion
|
| 6 |
+
|
| 7 |
+
echo ==========================================
|
| 8 |
+
echo Gemini Business2API Update Script
|
| 9 |
+
echo ==========================================
|
| 10 |
+
echo.
|
| 11 |
+
|
| 12 |
+
REM Check if git is installed
|
| 13 |
+
where git >nul 2>nul
|
| 14 |
+
if %errorlevel% neq 0 (
|
| 15 |
+
echo [ERROR] Git is not installed. Please install git first.
|
| 16 |
+
exit /b 1
|
| 17 |
+
)
|
| 18 |
+
|
| 19 |
+
REM Check if python is installed
|
| 20 |
+
where python >nul 2>nul
|
| 21 |
+
if %errorlevel% neq 0 (
|
| 22 |
+
echo [ERROR] Python is not installed. Please install Python 3.11+ first.
|
| 23 |
+
exit /b 1
|
| 24 |
+
)
|
| 25 |
+
|
| 26 |
+
REM Step 1: Backup current .env file
|
| 27 |
+
echo [INFO] Backing up .env file...
|
| 28 |
+
if exist ".env" (
|
| 29 |
+
copy /Y ".env" ".env.backup" >nul
|
| 30 |
+
echo [SUCCESS] .env backed up to .env.backup
|
| 31 |
+
) else (
|
| 32 |
+
echo [INFO] No .env file found, skipping backup
|
| 33 |
+
)
|
| 34 |
+
|
| 35 |
+
REM Step 2: Pull latest code from git
|
| 36 |
+
echo [INFO] Pulling latest code from git...
|
| 37 |
+
git fetch origin
|
| 38 |
+
git pull origin main 2>nul
|
| 39 |
+
if %errorlevel% neq 0 (
|
| 40 |
+
git pull origin master 2>nul
|
| 41 |
+
if %errorlevel% neq 0 (
|
| 42 |
+
echo [ERROR] Failed to pull latest code
|
| 43 |
+
exit /b 1
|
| 44 |
+
)
|
| 45 |
+
)
|
| 46 |
+
echo [SUCCESS] Code updated successfully
|
| 47 |
+
|
| 48 |
+
REM Step 3: Restore .env file
|
| 49 |
+
if exist ".env.backup" (
|
| 50 |
+
echo [INFO] Restoring .env file...
|
| 51 |
+
move /Y ".env.backup" ".env" >nul
|
| 52 |
+
echo [SUCCESS] .env restored
|
| 53 |
+
)
|
| 54 |
+
|
| 55 |
+
REM Step 4: Update Python dependencies
|
| 56 |
+
echo [INFO] Updating Python dependencies...
|
| 57 |
+
|
| 58 |
+
REM Check if virtual environment exists
|
| 59 |
+
if exist ".venv\Scripts\activate.bat" (
|
| 60 |
+
echo [INFO] Virtual environment detected, activating...
|
| 61 |
+
call .venv\Scripts\activate.bat
|
| 62 |
+
)
|
| 63 |
+
|
| 64 |
+
python -m pip install -r requirements.txt --upgrade
|
| 65 |
+
if %errorlevel% neq 0 (
|
| 66 |
+
echo [ERROR] Failed to update Python dependencies
|
| 67 |
+
exit /b 1
|
| 68 |
+
)
|
| 69 |
+
echo [SUCCESS] Python dependencies updated
|
| 70 |
+
|
| 71 |
+
REM Step 5: Update frontend dependencies
|
| 72 |
+
if exist "frontend" (
|
| 73 |
+
echo [INFO] Updating frontend dependencies...
|
| 74 |
+
cd frontend
|
| 75 |
+
|
| 76 |
+
REM Check if npm is installed
|
| 77 |
+
where npm >nul 2>nul
|
| 78 |
+
if %errorlevel% equ 0 (
|
| 79 |
+
call npm install
|
| 80 |
+
if %errorlevel% equ 0 (
|
| 81 |
+
call npm run build
|
| 82 |
+
if %errorlevel% equ 0 (
|
| 83 |
+
echo [SUCCESS] Frontend dependencies updated and built
|
| 84 |
+
) else (
|
| 85 |
+
echo [ERROR] Frontend build failed
|
| 86 |
+
)
|
| 87 |
+
) else (
|
| 88 |
+
echo [ERROR] npm install failed
|
| 89 |
+
)
|
| 90 |
+
) else (
|
| 91 |
+
echo [WARNING] npm is not installed. Skipping frontend update.
|
| 92 |
+
)
|
| 93 |
+
|
| 94 |
+
cd ..
|
| 95 |
+
)
|
| 96 |
+
|
| 97 |
+
REM Step 6: Show completion message
|
| 98 |
+
echo.
|
| 99 |
+
echo ==========================================
|
| 100 |
+
echo [SUCCESS] Update completed successfully!
|
| 101 |
+
echo ==========================================
|
| 102 |
+
echo.
|
| 103 |
+
echo [INFO] To restart the service, run:
|
| 104 |
+
echo python main.py
|
| 105 |
+
echo.
|
| 106 |
+
echo [INFO] Or if running as a Windows service:
|
| 107 |
+
echo net stop gemini-business2api
|
| 108 |
+
echo net start gemini-business2api
|
| 109 |
+
echo.
|
| 110 |
+
|
| 111 |
+
endlocal
|
update.sh
ADDED
|
@@ -0,0 +1,104 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
#!/bin/bash
|
| 2 |
+
|
| 3 |
+
# Gemini Business2API Update Script for Linux/macOS
|
| 4 |
+
# This script updates the project to the latest version
|
| 5 |
+
|
| 6 |
+
set -e # Exit on error
|
| 7 |
+
|
| 8 |
+
echo "=========================================="
|
| 9 |
+
echo "Gemini Business2API Update Script"
|
| 10 |
+
echo "=========================================="
|
| 11 |
+
echo ""
|
| 12 |
+
|
| 13 |
+
# Color codes for output
|
| 14 |
+
RED='\033[0;31m'
|
| 15 |
+
GREEN='\033[0;32m'
|
| 16 |
+
YELLOW='\033[1;33m'
|
| 17 |
+
NC='\033[0m' # No Color
|
| 18 |
+
|
| 19 |
+
# Function to print colored messages
|
| 20 |
+
print_success() {
|
| 21 |
+
echo -e "${GREEN}✓ $1${NC}"
|
| 22 |
+
}
|
| 23 |
+
|
| 24 |
+
print_error() {
|
| 25 |
+
echo -e "${RED}✗ $1${NC}"
|
| 26 |
+
}
|
| 27 |
+
|
| 28 |
+
print_info() {
|
| 29 |
+
echo -e "${YELLOW}→ $1${NC}"
|
| 30 |
+
}
|
| 31 |
+
|
| 32 |
+
# Check if git is installed
|
| 33 |
+
if ! command -v git &> /dev/null; then
|
| 34 |
+
print_error "Git is not installed. Please install git first."
|
| 35 |
+
exit 1
|
| 36 |
+
fi
|
| 37 |
+
|
| 38 |
+
# Check if python3 is installed
|
| 39 |
+
if ! command -v python3 &> /dev/null; then
|
| 40 |
+
print_error "Python3 is not installed. Please install Python 3.11+ first."
|
| 41 |
+
exit 1
|
| 42 |
+
fi
|
| 43 |
+
|
| 44 |
+
# Step 1: Backup current .env file
|
| 45 |
+
print_info "Backing up .env file..."
|
| 46 |
+
if [ -f ".env" ]; then
|
| 47 |
+
cp .env .env.backup
|
| 48 |
+
print_success ".env backed up to .env.backup"
|
| 49 |
+
else
|
| 50 |
+
print_info "No .env file found, skipping backup"
|
| 51 |
+
fi
|
| 52 |
+
|
| 53 |
+
# Step 2: Pull latest code from git
|
| 54 |
+
print_info "Pulling latest code from git..."
|
| 55 |
+
git fetch origin
|
| 56 |
+
git pull origin main || git pull origin master
|
| 57 |
+
print_success "Code updated successfully"
|
| 58 |
+
|
| 59 |
+
# Step 3: Restore .env file
|
| 60 |
+
if [ -f ".env.backup" ]; then
|
| 61 |
+
print_info "Restoring .env file..."
|
| 62 |
+
mv .env.backup .env
|
| 63 |
+
print_success ".env restored"
|
| 64 |
+
fi
|
| 65 |
+
|
| 66 |
+
# Step 4: Update Python dependencies
|
| 67 |
+
print_info "Updating Python dependencies..."
|
| 68 |
+
if [ -d ".venv" ]; then
|
| 69 |
+
print_info "Virtual environment detected, activating..."
|
| 70 |
+
source .venv/bin/activate
|
| 71 |
+
fi
|
| 72 |
+
|
| 73 |
+
pip install -r requirements.txt --upgrade
|
| 74 |
+
print_success "Python dependencies updated"
|
| 75 |
+
|
| 76 |
+
# Step 5: Update frontend dependencies
|
| 77 |
+
if [ -d "frontend" ]; then
|
| 78 |
+
print_info "Updating frontend dependencies..."
|
| 79 |
+
cd frontend
|
| 80 |
+
|
| 81 |
+
# Check if npm is installed
|
| 82 |
+
if command -v npm &> /dev/null; then
|
| 83 |
+
npm install
|
| 84 |
+
npm run build
|
| 85 |
+
print_success "Frontend dependencies updated and built"
|
| 86 |
+
else
|
| 87 |
+
print_error "npm is not installed. Skipping frontend update."
|
| 88 |
+
fi
|
| 89 |
+
|
| 90 |
+
cd ..
|
| 91 |
+
fi
|
| 92 |
+
|
| 93 |
+
# Step 6: Show completion message
|
| 94 |
+
echo ""
|
| 95 |
+
echo "=========================================="
|
| 96 |
+
print_success "Update completed successfully!"
|
| 97 |
+
echo "=========================================="
|
| 98 |
+
echo ""
|
| 99 |
+
print_info "To restart the service, run:"
|
| 100 |
+
echo " python main.py"
|
| 101 |
+
echo ""
|
| 102 |
+
print_info "Or if using systemd:"
|
| 103 |
+
echo " sudo systemctl restart gemini-business2api"
|
| 104 |
+
echo ""
|