refactor: simplify deployment - unified env and startup script
- Remove Docker deployment files (1panel doesn't use Docker) - Unify .env files: .env.example -> .env (single config file) - Merge start.sh and start-prod.sh into unified start.sh with --prod flag - Update setup_dev_env.sh to use .env instead of .env.local - Add DEPLOY.md with 1panel deployment guide 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
111
.env
111
.env
@@ -1,49 +1,116 @@
|
||||
# Tool_OCR - Production/Docker Environment Configuration
|
||||
# For local development, copy .env.example to .env.local and configure there
|
||||
#
|
||||
# This file is for Docker deployment or production use.
|
||||
# Sensitive values should be set via environment variables or secrets management.
|
||||
# Tool_OCR - Environment Configuration Template
|
||||
# Copy this file to .env and fill in your actual values
|
||||
|
||||
# ===== Database Configuration =====
|
||||
# Set these via Docker secrets or environment variables in production
|
||||
MYSQL_HOST=${MYSQL_HOST:-localhost}
|
||||
MYSQL_PORT=${MYSQL_PORT:-3306}
|
||||
MYSQL_USER=${MYSQL_USER:-}
|
||||
MYSQL_PASSWORD=${MYSQL_PASSWORD:-}
|
||||
MYSQL_DATABASE=${MYSQL_DATABASE:-}
|
||||
MYSQL_HOST=mysql.theaken.com
|
||||
MYSQL_PORT=33306
|
||||
MYSQL_USER=A060
|
||||
MYSQL_PASSWORD=WLeSCi0yhtc7
|
||||
MYSQL_DATABASE=db_A060
|
||||
|
||||
# ===== Application Configuration =====
|
||||
# Production port (different from development)
|
||||
FRONTEND_PORT=12010
|
||||
# Server ports
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_PORT=5173
|
||||
|
||||
# Security - MUST be set via environment variable in production
|
||||
SECRET_KEY=${SECRET_KEY:-change-this-in-production}
|
||||
# Security
|
||||
SECRET_KEY=your-secret-key-here-please-change-this-to-random-string
|
||||
ALGORITHM=HS256
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
||||
|
||||
# ===== External Authentication Configuration =====
|
||||
EXTERNAL_AUTH_API_URL=${EXTERNAL_AUTH_API_URL:-https://your-auth-api.example.com}
|
||||
# External authentication API URL
|
||||
EXTERNAL_AUTH_API_URL=https://pj-auth-api.vercel.app
|
||||
# Authentication endpoint path
|
||||
EXTERNAL_AUTH_ENDPOINT=/api/auth/login
|
||||
# API request timeout in seconds
|
||||
EXTERNAL_AUTH_TIMEOUT=30
|
||||
# Token refresh buffer in seconds (refresh tokens X seconds before expiry)
|
||||
TOKEN_REFRESH_BUFFER=300
|
||||
|
||||
# ===== Task Management Configuration =====
|
||||
# Database table prefix for clear namespace separation
|
||||
DATABASE_TABLE_PREFIX=tool_ocr_
|
||||
# Enable task history feature
|
||||
ENABLE_TASK_HISTORY=true
|
||||
# Auto-delete old tasks after X days (0 to disable)
|
||||
TASK_RETENTION_DAYS=30
|
||||
# Maximum tasks per user (0 for unlimited)
|
||||
MAX_TASKS_PER_USER=1000
|
||||
|
||||
# ===== OCR Configuration =====
|
||||
# Note: PaddleOCR/PaddleX models are stored in ~/.paddleocr/ and ~/.paddlex/ by default
|
||||
# Supported languages (comma-separated)
|
||||
OCR_LANGUAGES=ch,en,japan,korean
|
||||
# Default confidence threshold
|
||||
OCR_CONFIDENCE_THRESHOLD=0.5
|
||||
# Maximum concurrent OCR workers
|
||||
MAX_OCR_WORKERS=4
|
||||
|
||||
# ===== File Configuration =====
|
||||
# GPU Acceleration Configuration
|
||||
# Force CPU mode even if GPU is available (default: false)
|
||||
FORCE_CPU_MODE=false
|
||||
# GPU memory fraction (0.0-1.0, default: 0.8)
|
||||
GPU_MEMORY_FRACTION=0.8
|
||||
# GPU device ID to use (default: 0, -1 for CPU)
|
||||
GPU_DEVICE_ID=0
|
||||
|
||||
# ===== File Upload Configuration =====
|
||||
# Maximum file size in bytes (50MB default)
|
||||
MAX_UPLOAD_SIZE=52428800
|
||||
# Allowed file extensions (comma-separated)
|
||||
ALLOWED_EXTENSIONS=png,jpg,jpeg,pdf,bmp,tiff,doc,docx,ppt,pptx
|
||||
# Upload directories
|
||||
UPLOAD_DIR=./uploads
|
||||
TEMP_DIR=./uploads/temp
|
||||
PROCESSED_DIR=./uploads/processed
|
||||
IMAGES_DIR=./uploads/images
|
||||
|
||||
# ===== Export Configuration =====
|
||||
# Storage directories
|
||||
STORAGE_DIR=./storage
|
||||
MARKDOWN_DIR=./storage/markdown
|
||||
JSON_DIR=./storage/json
|
||||
EXPORTS_DIR=./storage/exports
|
||||
|
||||
# ===== PDF Generation Configuration =====
|
||||
# Pandoc path (Linux)
|
||||
PANDOC_PATH=/usr/bin/pandoc
|
||||
# WeasyPrint font directory
|
||||
FONT_DIR=/usr/share/fonts
|
||||
# Default PDF page size
|
||||
PDF_PAGE_SIZE=A4
|
||||
# Default PDF margins (mm)
|
||||
PDF_MARGIN_TOP=20
|
||||
PDF_MARGIN_BOTTOM=20
|
||||
PDF_MARGIN_LEFT=20
|
||||
PDF_MARGIN_RIGHT=20
|
||||
|
||||
# ===== Translation Configuration (DIFY API) =====
|
||||
ENABLE_TRANSLATION=${ENABLE_TRANSLATION:-false}
|
||||
DIFY_BASE_URL=${DIFY_BASE_URL:-}
|
||||
DIFY_API_KEY=${DIFY_API_KEY:-}
|
||||
# Enable translation feature
|
||||
ENABLE_TRANSLATION=true
|
||||
# DIFY API base URL
|
||||
DIFY_BASE_URL=https://dify.theaken.com/v1
|
||||
# DIFY API key (required for translation)
|
||||
DIFY_API_KEY=app-YOPrF2ro5fshzMkCZviIuUJd
|
||||
# API request timeout in seconds
|
||||
DIFY_TIMEOUT=120.0
|
||||
# Maximum retry attempts
|
||||
DIFY_MAX_RETRIES=3
|
||||
# Batch translation limits
|
||||
DIFY_MAX_BATCH_CHARS=5000
|
||||
DIFY_MAX_BATCH_ITEMS=20
|
||||
|
||||
# ===== Background Tasks Configuration =====
|
||||
# Task queue type: memory (default) or redis (future)
|
||||
TASK_QUEUE_TYPE=memory
|
||||
# Redis URL (if using redis)
|
||||
# REDIS_URL=redis://localhost:6379/0
|
||||
|
||||
# ===== CORS Configuration =====
|
||||
CORS_ORIGINS=http://localhost:12010,http://127.0.0.1:12010
|
||||
# Allowed origins (comma-separated, * for all)
|
||||
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
|
||||
|
||||
# ===== Logging Configuration =====
|
||||
LOG_LEVEL=INFO
|
||||
LOG_LEVEL=DEBUG
|
||||
LOG_FILE=./logs/app.log
|
||||
|
||||
64
.env.example
64
.env.example
@@ -1,69 +1,35 @@
|
||||
# Tool_OCR - Environment Configuration Template
|
||||
# Copy this file to .env.local and fill in your actual values
|
||||
#
|
||||
# Note: Most path configurations have sensible defaults in config.py
|
||||
# Only override if you need custom paths
|
||||
# Tool_OCR - 環境變數配置
|
||||
# 複製此檔案為 .env 並填入實際值
|
||||
# cp .env.example .env
|
||||
|
||||
# ===== Database Configuration (Required) =====
|
||||
# ===== 資料庫 =====
|
||||
MYSQL_HOST=your-mysql-host
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USER=your-username
|
||||
MYSQL_PASSWORD=your-password
|
||||
MYSQL_DATABASE=your-database
|
||||
|
||||
# ===== Application Configuration =====
|
||||
# Server ports
|
||||
BACKEND_HOST=0.0.0.0
|
||||
# ===== 服務端口 =====
|
||||
# IT 會指派實際端口
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_HOST=0.0.0.0
|
||||
FRONTEND_PORT=5173
|
||||
|
||||
# Security (generate a random string for production: openssl rand -hex 32)
|
||||
SECRET_KEY=your-secret-key-here-please-change-this-to-random-string
|
||||
ALGORITHM=HS256
|
||||
ACCESS_TOKEN_EXPIRE_MINUTES=1440
|
||||
# ===== 安全性 =====
|
||||
# 生產環境請使用: openssl rand -hex 32
|
||||
SECRET_KEY=your-secret-key-change-this
|
||||
|
||||
# ===== External Authentication Configuration (Required) =====
|
||||
# ===== 外部認證 =====
|
||||
EXTERNAL_AUTH_API_URL=https://your-auth-api.example.com
|
||||
EXTERNAL_AUTH_ENDPOINT=/api/auth/login
|
||||
EXTERNAL_AUTH_TIMEOUT=30
|
||||
TOKEN_REFRESH_BUFFER=300
|
||||
|
||||
# ===== Task Management Configuration =====
|
||||
DATABASE_TABLE_PREFIX=tool_ocr_
|
||||
ENABLE_TASK_HISTORY=true
|
||||
TASK_RETENTION_DAYS=30
|
||||
MAX_TASKS_PER_USER=1000
|
||||
|
||||
# ===== OCR Configuration =====
|
||||
# Note: PaddleOCR/PaddleX models are stored in ~/.paddleocr/ and ~/.paddlex/ by default
|
||||
OCR_LANGUAGES=ch,en,japan,korean
|
||||
OCR_CONFIDENCE_THRESHOLD=0.5
|
||||
MAX_OCR_WORKERS=4
|
||||
|
||||
# GPU Acceleration Configuration
|
||||
FORCE_CPU_MODE=false
|
||||
GPU_MEMORY_FRACTION=0.8
|
||||
GPU_DEVICE_ID=0
|
||||
|
||||
# ===== File Upload Configuration =====
|
||||
MAX_UPLOAD_SIZE=52428800
|
||||
ALLOWED_EXTENSIONS=png,jpg,jpeg,pdf,bmp,tiff,doc,docx,ppt,pptx
|
||||
# Path defaults to backend/uploads - only override if needed
|
||||
# UPLOAD_DIR=./uploads
|
||||
|
||||
# ===== Translation Configuration (DIFY API) =====
|
||||
# ===== 翻譯 API (DIFY) =====
|
||||
ENABLE_TRANSLATION=true
|
||||
DIFY_BASE_URL=https://your-dify-instance.example.com/v1
|
||||
DIFY_API_KEY=your-dify-api-key
|
||||
DIFY_TIMEOUT=120.0
|
||||
DIFY_MAX_RETRIES=3
|
||||
DIFY_MAX_BATCH_CHARS=5000
|
||||
DIFY_MAX_BATCH_ITEMS=20
|
||||
|
||||
# ===== CORS Configuration =====
|
||||
CORS_ORIGINS=http://localhost:5173,http://127.0.0.1:5173
|
||||
# ===== CORS =====
|
||||
# 根據實際部署的前端 URL 設定
|
||||
CORS_ORIGINS=http://localhost:5173
|
||||
|
||||
# ===== Logging Configuration =====
|
||||
# ===== 日誌 =====
|
||||
LOG_LEVEL=INFO
|
||||
# LOG_FILE defaults to backend/logs/app.log
|
||||
|
||||
8
.gitignore
vendored
8
.gitignore
vendored
@@ -49,11 +49,9 @@ AGENTS.md
|
||||
CLAUDE.md
|
||||
|
||||
# ===== Environment Variables =====
|
||||
# Local environment files (contain secrets, never commit)
|
||||
.env.local
|
||||
.env.*.local
|
||||
frontend/.env.local
|
||||
frontend/.env.*.local
|
||||
# 實際配置檔案包含敏感資訊,不追蹤
|
||||
.env
|
||||
frontend/.env
|
||||
|
||||
# ===== Process ID Files =====
|
||||
.pid/
|
||||
|
||||
163
DEPLOY.md
Normal file
163
DEPLOY.md
Normal file
@@ -0,0 +1,163 @@
|
||||
# Tool_OCR 佈署指南
|
||||
|
||||
本指南說明如何在 1panel 或其他 Linux 環境中佈署 Tool_OCR。
|
||||
|
||||
## 快速佈署
|
||||
|
||||
```bash
|
||||
# 1. 複製並配置環境變數
|
||||
cp .env.example .env
|
||||
# 編輯 .env 填入實際的資料庫、API 金鑰等配置
|
||||
|
||||
# 2. 安裝依賴並初始化
|
||||
./setup_dev_env.sh
|
||||
|
||||
# 3. 啟動服務
|
||||
./start.sh --prod
|
||||
```
|
||||
|
||||
## 詳細步驟
|
||||
|
||||
### 1. 系統需求
|
||||
|
||||
- Ubuntu 20.04+ 或相容的 Linux 發行版
|
||||
- Python 3.10+
|
||||
- Node.js 18+ (透過 nvm 自動安裝)
|
||||
- 至少 4GB RAM
|
||||
- 至少 10GB 磁碟空間
|
||||
|
||||
### 2. 環境配置
|
||||
|
||||
複製範例配置檔:
|
||||
```bash
|
||||
cp .env.example .env
|
||||
```
|
||||
|
||||
編輯 `.env` 填入實際值:
|
||||
```bash
|
||||
# 資料庫 (必填)
|
||||
MYSQL_HOST=your-mysql-host
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USER=your-username
|
||||
MYSQL_PASSWORD=your-password
|
||||
MYSQL_DATABASE=your-database
|
||||
|
||||
# 服務端口 (由 IT 指派)
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_PORT=5173
|
||||
|
||||
# 安全性 (必填,請使用隨機字串)
|
||||
SECRET_KEY=your-random-secret-key
|
||||
|
||||
# 外部認證 (必填)
|
||||
EXTERNAL_AUTH_API_URL=https://your-auth-api.example.com
|
||||
|
||||
# 翻譯 API (選填)
|
||||
ENABLE_TRANSLATION=true
|
||||
DIFY_BASE_URL=https://your-dify-instance.example.com/v1
|
||||
DIFY_API_KEY=your-dify-api-key
|
||||
|
||||
# CORS (根據前端 URL 設定)
|
||||
CORS_ORIGINS=http://localhost:5173
|
||||
```
|
||||
|
||||
### 3. 安裝依賴
|
||||
|
||||
執行設置腳本:
|
||||
```bash
|
||||
./setup_dev_env.sh
|
||||
```
|
||||
|
||||
此腳本會:
|
||||
- 安裝系統依賴 (pandoc, fonts, opencv 等)
|
||||
- 安裝 Node.js (透過 nvm)
|
||||
- 建立 Python 虛擬環境
|
||||
- 自動偵測 GPU 並安裝對應的 PaddlePaddle 版本
|
||||
- 安裝前端依賴
|
||||
- 初始化資料庫
|
||||
|
||||
### 4. 啟動服務
|
||||
|
||||
**開發模式** (hot-reload):
|
||||
```bash
|
||||
./start.sh
|
||||
```
|
||||
|
||||
**正式模式** (無 hot-reload,多 worker):
|
||||
```bash
|
||||
./start.sh --prod
|
||||
```
|
||||
|
||||
**自訂端口**:
|
||||
```bash
|
||||
BACKEND_PORT=8088 FRONTEND_PORT=3000 ./start.sh --prod
|
||||
```
|
||||
|
||||
### 5. 服務管理
|
||||
|
||||
```bash
|
||||
# 查看狀態
|
||||
./start.sh --status
|
||||
|
||||
# 停止服務
|
||||
./start.sh --stop
|
||||
|
||||
# 僅啟動後端
|
||||
./start.sh backend
|
||||
|
||||
# 僅啟動前端
|
||||
./start.sh frontend
|
||||
```
|
||||
|
||||
### 6. 日誌
|
||||
|
||||
```bash
|
||||
# 後端日誌
|
||||
tail -f .pid/backend.log
|
||||
|
||||
# 前端日誌
|
||||
tail -f .pid/frontend.log
|
||||
```
|
||||
|
||||
## 1panel 設定
|
||||
|
||||
在 1panel 中設定為「應用」或「腳本任務」:
|
||||
|
||||
1. 工作目錄設為專案根目錄
|
||||
2. 啟動指令:`./start.sh --prod`
|
||||
3. 停止指令:`./start.sh --stop`
|
||||
4. 環境變數:可在 `.env` 中配置,或透過 1panel 的環境變數功能設定端口
|
||||
|
||||
## 常見問題
|
||||
|
||||
### GPU 支援
|
||||
|
||||
如果有 NVIDIA GPU,`setup_dev_env.sh` 會自動偵測並安裝 GPU 版本的 PaddlePaddle。
|
||||
|
||||
強制使用 CPU 版本:
|
||||
```bash
|
||||
./setup_dev_env.sh --cpu-only
|
||||
```
|
||||
|
||||
### 資料庫連線失敗
|
||||
|
||||
1. 確認 `.env` 中的資料庫配置正確
|
||||
2. 手動執行資料庫遷移:
|
||||
```bash
|
||||
source venv/bin/activate
|
||||
cd backend
|
||||
alembic upgrade head
|
||||
```
|
||||
|
||||
### 端口被佔用
|
||||
|
||||
檢查並終止佔用端口的程序:
|
||||
```bash
|
||||
lsof -i :8000 # 檢查後端端口
|
||||
lsof -i :5173 # 檢查前端端口
|
||||
```
|
||||
|
||||
或使用不同端口:
|
||||
```bash
|
||||
BACKEND_PORT=8088 FRONTEND_PORT=3000 ./start.sh --prod
|
||||
```
|
||||
@@ -1,24 +0,0 @@
|
||||
# Tool_OCR - 1Panel Docker Deployment Configuration
|
||||
# Copy this file to .env and fill in your values
|
||||
|
||||
# ===== Service Ports =====
|
||||
BACKEND_PORT=8000
|
||||
FRONTEND_PORT=12010
|
||||
|
||||
# ===== Database Configuration =====
|
||||
MYSQL_HOST=your-mysql-host
|
||||
MYSQL_PORT=3306
|
||||
MYSQL_USER=your-username
|
||||
MYSQL_PASSWORD=your-password
|
||||
MYSQL_DATABASE=your-database
|
||||
|
||||
# ===== Security =====
|
||||
# Generate a random string for production: openssl rand -hex 32
|
||||
SECRET_KEY=your-secret-key-change-this
|
||||
|
||||
# ===== Translation API (DIFY) =====
|
||||
DIFY_BASE_URL=https://your-dify-instance.example.com/v1
|
||||
DIFY_API_KEY=your-dify-api-key
|
||||
|
||||
# ===== Logging =====
|
||||
LOG_LEVEL=INFO
|
||||
@@ -1,67 +0,0 @@
|
||||
# Tool_OCR Backend Dockerfile
|
||||
# Multi-stage build for optimized image size
|
||||
|
||||
# Stage 1: Build environment
|
||||
FROM python:3.12-slim as builder
|
||||
|
||||
WORKDIR /build
|
||||
|
||||
# Install build dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
build-essential \
|
||||
git \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy requirements and install dependencies
|
||||
COPY backend/requirements.txt .
|
||||
RUN pip install --no-cache-dir --user -r requirements.txt
|
||||
|
||||
# Stage 2: Runtime environment
|
||||
FROM python:3.12-slim
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Install runtime dependencies
|
||||
RUN apt-get update && apt-get install -y --no-install-recommends \
|
||||
libgl1-mesa-glx \
|
||||
libglib2.0-0 \
|
||||
libsm6 \
|
||||
libxext6 \
|
||||
libxrender1 \
|
||||
libgomp1 \
|
||||
pandoc \
|
||||
poppler-utils \
|
||||
fonts-dejavu-core \
|
||||
fonts-noto-cjk \
|
||||
curl \
|
||||
&& rm -rf /var/lib/apt/lists/*
|
||||
|
||||
# Copy Python packages from builder
|
||||
COPY --from=builder /root/.local /root/.local
|
||||
ENV PATH=/root/.local/bin:$PATH
|
||||
|
||||
# Copy application code
|
||||
COPY backend/ /app/backend/
|
||||
|
||||
# Create necessary directories
|
||||
RUN mkdir -p /app/backend/uploads/{temp,processed,images} \
|
||||
&& mkdir -p /app/backend/storage/{markdown,json,exports,results} \
|
||||
&& mkdir -p /app/backend/models/paddleocr \
|
||||
&& mkdir -p /app/backend/logs
|
||||
|
||||
# Set working directory
|
||||
WORKDIR /app/backend
|
||||
|
||||
# Environment variables
|
||||
ENV PYTHONUNBUFFERED=1
|
||||
ENV PYTHONDONTWRITEBYTECODE=1
|
||||
|
||||
# Expose port
|
||||
EXPOSE 8000
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --start-period=60s --retries=3 \
|
||||
CMD curl -f http://localhost:8000/health || exit 1
|
||||
|
||||
# Run application
|
||||
CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8000", "--workers", "4"]
|
||||
@@ -1,38 +0,0 @@
|
||||
# Tool_OCR Frontend Dockerfile
|
||||
# Multi-stage build for optimized image size
|
||||
|
||||
# Stage 1: Build
|
||||
FROM node:20-alpine as builder
|
||||
|
||||
WORKDIR /app
|
||||
|
||||
# Copy package files
|
||||
COPY frontend/package*.json ./
|
||||
|
||||
# Install dependencies
|
||||
RUN npm ci
|
||||
|
||||
# Copy source code
|
||||
COPY frontend/ ./
|
||||
|
||||
# Build application
|
||||
RUN npm run build
|
||||
|
||||
# Stage 2: Production
|
||||
FROM nginx:alpine
|
||||
|
||||
# Copy built files
|
||||
COPY --from=builder /app/dist /usr/share/nginx/html
|
||||
|
||||
# Copy nginx configuration
|
||||
COPY deploy/1panel/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Expose port
|
||||
EXPOSE 80
|
||||
|
||||
# Health check
|
||||
HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
|
||||
CMD curl -f http://localhost:80 || exit 1
|
||||
|
||||
# Run nginx
|
||||
CMD ["nginx", "-g", "daemon off;"]
|
||||
@@ -1,125 +0,0 @@
|
||||
# Tool_OCR - 1Panel Docker 佈署指南
|
||||
|
||||
本目錄包含 1Panel 平台的 Docker 佈署配置。
|
||||
|
||||
## 前置需求
|
||||
|
||||
- Docker 20.10+
|
||||
- Docker Compose 2.0+
|
||||
- NVIDIA Container Toolkit(GPU 加速)
|
||||
- MySQL 8.0+(外部資料庫)
|
||||
|
||||
## 佈署步驟
|
||||
|
||||
### 1. 配置環境變數
|
||||
|
||||
```bash
|
||||
# 複製環境變數範本
|
||||
cp .env.example .env
|
||||
|
||||
# 編輯配置
|
||||
nano .env
|
||||
```
|
||||
|
||||
必要配置項:
|
||||
- `MYSQL_*` - 資料庫連線設定
|
||||
- `SECRET_KEY` - JWT 簽名金鑰(使用 `openssl rand -hex 32` 生成)
|
||||
- `DIFY_*` - 翻譯 API 設定
|
||||
|
||||
### 2. 建置映像
|
||||
|
||||
```bash
|
||||
# 建置所有服務
|
||||
docker-compose build
|
||||
|
||||
# 或分別建置
|
||||
docker-compose build backend
|
||||
docker-compose build frontend
|
||||
```
|
||||
|
||||
### 3. 啟動服務
|
||||
|
||||
```bash
|
||||
# 啟動所有服務
|
||||
docker-compose up -d
|
||||
|
||||
# 查看日誌
|
||||
docker-compose logs -f
|
||||
|
||||
# 查看狀態
|
||||
docker-compose ps
|
||||
```
|
||||
|
||||
### 4. 存取服務
|
||||
|
||||
- 前端介面:http://your-server:12010
|
||||
- API 文件:http://your-server:8000/docs
|
||||
- 健康檢查:http://your-server:8000/health
|
||||
|
||||
## 服務管理
|
||||
|
||||
```bash
|
||||
# 停止服務
|
||||
docker-compose down
|
||||
|
||||
# 重啟服務
|
||||
docker-compose restart
|
||||
|
||||
# 更新服務
|
||||
docker-compose pull
|
||||
docker-compose up -d --build
|
||||
|
||||
# 查看資源使用
|
||||
docker stats
|
||||
```
|
||||
|
||||
## 資料持久化
|
||||
|
||||
以下 Docker volumes 會自動建立:
|
||||
|
||||
| Volume | 用途 |
|
||||
|--------|------|
|
||||
| `tool_ocr_uploads` | 上傳檔案 |
|
||||
| `tool_ocr_storage` | 處理結果 |
|
||||
| `tool_ocr_logs` | 應用日誌 |
|
||||
| `tool_ocr_models` | OCR 模型快取 |
|
||||
|
||||
## GPU 加速
|
||||
|
||||
預設配置會使用 NVIDIA GPU。如果不需要 GPU 加速,請修改 `docker-compose.yml`,移除 `deploy.resources.reservations` 區塊。
|
||||
|
||||
## 常見問題
|
||||
|
||||
### Q: 服務啟動失敗?
|
||||
|
||||
檢查日誌:
|
||||
```bash
|
||||
docker-compose logs backend
|
||||
docker-compose logs frontend
|
||||
```
|
||||
|
||||
### Q: 資料庫連線失敗?
|
||||
|
||||
確認:
|
||||
1. MySQL 服務正在運行
|
||||
2. 防火牆允許連接
|
||||
3. 使用者權限正確
|
||||
|
||||
### Q: GPU 不可用?
|
||||
|
||||
確認 NVIDIA Container Toolkit 已安裝:
|
||||
```bash
|
||||
nvidia-smi
|
||||
docker run --rm --gpus all nvidia/cuda:11.8.0-base-ubuntu22.04 nvidia-smi
|
||||
```
|
||||
|
||||
## 1Panel 整合
|
||||
|
||||
在 1Panel 中:
|
||||
|
||||
1. 進入「應用商店」→「自訂應用」
|
||||
2. 上傳此目錄的所有檔案
|
||||
3. 配置環境變數
|
||||
4. 點擊「安裝」
|
||||
|
||||
或使用 1Panel 的「容器」功能直接導入 `docker-compose.yml`。
|
||||
@@ -1,68 +0,0 @@
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
backend:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/1panel/Dockerfile.backend
|
||||
container_name: tool_ocr_backend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${BACKEND_PORT:-8000}:8000"
|
||||
environment:
|
||||
- MYSQL_HOST=${MYSQL_HOST}
|
||||
- MYSQL_PORT=${MYSQL_PORT}
|
||||
- MYSQL_USER=${MYSQL_USER}
|
||||
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
|
||||
- MYSQL_DATABASE=${MYSQL_DATABASE}
|
||||
- SECRET_KEY=${SECRET_KEY}
|
||||
- DIFY_BASE_URL=${DIFY_BASE_URL}
|
||||
- DIFY_API_KEY=${DIFY_API_KEY}
|
||||
- CORS_ORIGINS=http://localhost:${FRONTEND_PORT:-12010}
|
||||
- LOG_LEVEL=${LOG_LEVEL:-INFO}
|
||||
volumes:
|
||||
- tool_ocr_uploads:/app/backend/uploads
|
||||
- tool_ocr_storage:/app/backend/storage
|
||||
- tool_ocr_logs:/app/backend/logs
|
||||
- tool_ocr_models:/app/backend/models
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
start_period: 60s
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: 1
|
||||
capabilities: [gpu]
|
||||
|
||||
frontend:
|
||||
build:
|
||||
context: ../..
|
||||
dockerfile: deploy/1panel/Dockerfile.frontend
|
||||
container_name: tool_ocr_frontend
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "${FRONTEND_PORT:-12010}:80"
|
||||
environment:
|
||||
- VITE_API_BASE_URL=http://localhost:${BACKEND_PORT:-8000}
|
||||
depends_on:
|
||||
- backend
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:80"]
|
||||
interval: 30s
|
||||
timeout: 10s
|
||||
retries: 3
|
||||
|
||||
volumes:
|
||||
tool_ocr_uploads:
|
||||
tool_ocr_storage:
|
||||
tool_ocr_logs:
|
||||
tool_ocr_models:
|
||||
|
||||
networks:
|
||||
default:
|
||||
name: tool_ocr_network
|
||||
@@ -1,37 +0,0 @@
|
||||
server {
|
||||
listen 80;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Gzip compression
|
||||
gzip on;
|
||||
gzip_vary on;
|
||||
gzip_min_length 1024;
|
||||
gzip_proxied expired no-cache no-store private auth;
|
||||
gzip_types text/plain text/css text/xml text/javascript application/x-javascript application/xml application/javascript;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
add_header X-XSS-Protection "1; mode=block" always;
|
||||
|
||||
# SPA routing - all routes go to index.html
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
}
|
||||
|
||||
# Static assets caching
|
||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Health check endpoint
|
||||
location /health {
|
||||
access_log off;
|
||||
return 200 "healthy\n";
|
||||
add_header Content-Type text/plain;
|
||||
}
|
||||
}
|
||||
@@ -227,17 +227,17 @@ init_database() {
|
||||
echo "初始化數據庫..."
|
||||
cd "$SCRIPT_DIR/backend"
|
||||
|
||||
# 檢查 .env.local 是否存在
|
||||
if [ ! -f "$SCRIPT_DIR/.env.local" ]; then
|
||||
print_warning "未找到 .env.local,跳過數據庫初始化"
|
||||
echo " 請複製 .env.example 到 .env.local 並配置後,手動執行:"
|
||||
# 檢查 .env 是否存在
|
||||
if [ ! -f "$SCRIPT_DIR/.env" ]; then
|
||||
print_warning "未找到 .env,跳過數據庫初始化"
|
||||
echo " 請複製 .env.example 到 .env 並配置後,手動執行:"
|
||||
echo " cd backend && alembic upgrade head"
|
||||
cd "$SCRIPT_DIR"
|
||||
return
|
||||
fi
|
||||
|
||||
# 載入環境變量
|
||||
export $(grep -v '^#' "$SCRIPT_DIR/.env.local" | xargs)
|
||||
export $(grep -v '^#' "$SCRIPT_DIR/.env" | xargs)
|
||||
|
||||
# 執行遷移
|
||||
if alembic upgrade head 2>/dev/null; then
|
||||
@@ -414,8 +414,8 @@ echo ""
|
||||
echo "下一步操作:"
|
||||
echo ""
|
||||
echo "1. 配置環境變量 (如尚未配置):"
|
||||
echo " cp .env.example .env.local"
|
||||
echo " # 編輯 .env.local 填入實際配置"
|
||||
echo " cp .env.example .env"
|
||||
echo " # 編輯 .env 填入實際配置"
|
||||
echo ""
|
||||
echo "2. 啟動應用:"
|
||||
echo " ./start.sh # 同時啟動前後端"
|
||||
|
||||
375
start-prod.sh
375
start-prod.sh
@@ -1,375 +0,0 @@
|
||||
#!/bin/bash
|
||||
# Tool_OCR - Production Server Startup Script
|
||||
# Usage:
|
||||
# ./start-prod.sh Start all services (backend + frontend)
|
||||
# ./start-prod.sh backend Start only backend
|
||||
# ./start-prod.sh frontend Start only frontend
|
||||
# ./start-prod.sh --stop Stop all services
|
||||
# ./start-prod.sh --status Show service status
|
||||
# ./start-prod.sh --help Show help
|
||||
|
||||
# Note: We don't use 'set -e' here because stop commands may fail gracefully
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m'
|
||||
|
||||
# Configuration
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PID_DIR="$SCRIPT_DIR/.pid-prod"
|
||||
BACKEND_PID_FILE="$PID_DIR/backend.pid"
|
||||
FRONTEND_PID_FILE="$PID_DIR/frontend.pid"
|
||||
|
||||
# Production defaults (different from development)
|
||||
BACKEND_HOST=${BACKEND_HOST:-0.0.0.0}
|
||||
BACKEND_PORT=${BACKEND_PORT:-8000}
|
||||
FRONTEND_HOST=${FRONTEND_HOST:-0.0.0.0}
|
||||
FRONTEND_PORT=${FRONTEND_PORT:-12010}
|
||||
|
||||
# Production-specific settings
|
||||
UVICORN_WORKERS=${UVICORN_WORKERS:-4}
|
||||
|
||||
# Create PID directory
|
||||
mkdir -p "$PID_DIR"
|
||||
|
||||
# Functions
|
||||
print_header() {
|
||||
echo ""
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo -e "${BLUE} Tool_OCR Production Server${NC}"
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "Tool_OCR - Production Server Manager"
|
||||
echo ""
|
||||
echo "Usage: ./start-prod.sh [command]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " (none) Start all services (backend + frontend)"
|
||||
echo " backend Start only backend service"
|
||||
echo " frontend Start only frontend service"
|
||||
echo " --stop Stop all running services"
|
||||
echo " --status Show status of services"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Environment Variables:"
|
||||
echo " BACKEND_PORT Backend port (default: 8000)"
|
||||
echo " FRONTEND_PORT Frontend port (default: 12010)"
|
||||
echo " UVICORN_WORKERS Number of uvicorn workers (default: 4)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " ./start-prod.sh # Start everything"
|
||||
echo " ./start-prod.sh backend # Start only backend"
|
||||
echo " FRONTEND_PORT=3000 ./start-prod.sh # Custom port"
|
||||
echo " ./start-prod.sh --stop # Stop all services"
|
||||
echo ""
|
||||
}
|
||||
|
||||
check_requirements() {
|
||||
local missing=0
|
||||
|
||||
# Check virtual environment
|
||||
if [ ! -d "$SCRIPT_DIR/venv" ]; then
|
||||
echo -e "${RED}Error: Python virtual environment not found${NC}"
|
||||
echo "Please run: ./setup_dev_env.sh"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
# Check node_modules
|
||||
if [ ! -d "$SCRIPT_DIR/frontend/node_modules" ]; then
|
||||
echo -e "${RED}Error: Frontend dependencies not found${NC}"
|
||||
echo "Please run: ./setup_dev_env.sh"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
# Check .env (production uses .env, not .env.local)
|
||||
if [ ! -f "$SCRIPT_DIR/.env" ]; then
|
||||
echo -e "${YELLOW}Warning: .env not found, using defaults${NC}"
|
||||
fi
|
||||
|
||||
return $missing
|
||||
}
|
||||
|
||||
load_env() {
|
||||
# Production loads .env only (not .env.local)
|
||||
# For production, you should use .env with production settings
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$SCRIPT_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
}
|
||||
|
||||
is_running() {
|
||||
local pid_file=$1
|
||||
if [ -f "$pid_file" ]; then
|
||||
local pid=$(cat "$pid_file")
|
||||
if ps -p "$pid" > /dev/null 2>&1; then
|
||||
return 0
|
||||
else
|
||||
# PID file exists but process is not running, clean up
|
||||
rm -f "$pid_file"
|
||||
fi
|
||||
fi
|
||||
return 1
|
||||
}
|
||||
|
||||
get_pid() {
|
||||
local pid_file=$1
|
||||
if [ -f "$pid_file" ]; then
|
||||
cat "$pid_file"
|
||||
fi
|
||||
}
|
||||
|
||||
start_backend() {
|
||||
if is_running "$BACKEND_PID_FILE"; then
|
||||
echo -e "${YELLOW}Backend already running (PID: $(get_pid $BACKEND_PID_FILE))${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Starting backend server (production mode)...${NC}"
|
||||
|
||||
# Activate virtual environment
|
||||
source "$SCRIPT_DIR/venv/bin/activate"
|
||||
|
||||
# Load environment variables
|
||||
load_env
|
||||
|
||||
# Start backend in background
|
||||
cd "$SCRIPT_DIR/backend"
|
||||
|
||||
# Create necessary directories
|
||||
mkdir -p uploads/{temp,processed,images}
|
||||
mkdir -p storage/{markdown,json,exports,results}
|
||||
mkdir -p models/paddleocr
|
||||
mkdir -p logs
|
||||
|
||||
# Start uvicorn in production mode (no --reload, with workers)
|
||||
nohup uvicorn app.main:app \
|
||||
--host "$BACKEND_HOST" \
|
||||
--port "$BACKEND_PORT" \
|
||||
--workers "$UVICORN_WORKERS" \
|
||||
--access-log \
|
||||
--log-level info \
|
||||
> "$PID_DIR/backend.log" 2>&1 &
|
||||
local pid=$!
|
||||
echo $pid > "$BACKEND_PID_FILE"
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Wait a moment and verify
|
||||
sleep 3
|
||||
if is_running "$BACKEND_PID_FILE"; then
|
||||
echo -e "${GREEN}Backend started (PID: $pid, Workers: $UVICORN_WORKERS)${NC}"
|
||||
echo -e " API Docs: http://localhost:$BACKEND_PORT/docs"
|
||||
echo -e " Health: http://localhost:$BACKEND_PORT/health"
|
||||
else
|
||||
echo -e "${RED}Backend failed to start. Check $PID_DIR/backend.log${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
start_frontend() {
|
||||
if is_running "$FRONTEND_PID_FILE"; then
|
||||
echo -e "${YELLOW}Frontend already running (PID: $(get_pid $FRONTEND_PID_FILE))${NC}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Starting frontend server (production mode)...${NC}"
|
||||
|
||||
# Load environment variables
|
||||
load_env
|
||||
|
||||
# Load nvm
|
||||
export NVM_DIR="$HOME/.nvm"
|
||||
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
|
||||
|
||||
cd "$SCRIPT_DIR/frontend"
|
||||
|
||||
# Build frontend if dist doesn't exist or is older than src
|
||||
if [ ! -d "dist" ] || [ "$(find src -newer dist -type f 2>/dev/null | head -1)" ]; then
|
||||
echo -e "${YELLOW}Building frontend...${NC}"
|
||||
npm run build
|
||||
fi
|
||||
|
||||
# Start production preview server
|
||||
# Note: For real production, use nginx to serve dist/ folder
|
||||
nohup npm run preview -- --host "$FRONTEND_HOST" --port "$FRONTEND_PORT" > "$PID_DIR/frontend.log" 2>&1 &
|
||||
local pid=$!
|
||||
echo $pid > "$FRONTEND_PID_FILE"
|
||||
|
||||
cd "$SCRIPT_DIR"
|
||||
|
||||
# Wait a moment and verify
|
||||
sleep 3
|
||||
if is_running "$FRONTEND_PID_FILE"; then
|
||||
echo -e "${GREEN}Frontend started (PID: $pid)${NC}"
|
||||
echo -e " URL: http://localhost:$FRONTEND_PORT"
|
||||
else
|
||||
echo -e "${RED}Frontend failed to start. Check $PID_DIR/frontend.log${NC}"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
kill_process_tree() {
|
||||
local pid=$1
|
||||
# Kill all child processes first
|
||||
pkill -TERM -P "$pid" 2>/dev/null || true
|
||||
# Then kill the parent
|
||||
kill -TERM "$pid" 2>/dev/null || true
|
||||
}
|
||||
|
||||
force_kill_process_tree() {
|
||||
local pid=$1
|
||||
# Force kill all child processes
|
||||
pkill -9 -P "$pid" 2>/dev/null || true
|
||||
# Force kill the parent
|
||||
kill -9 "$pid" 2>/dev/null || true
|
||||
}
|
||||
|
||||
kill_by_port() {
|
||||
local port=$1
|
||||
local pids=$(lsof -ti :$port 2>/dev/null)
|
||||
if [ -n "$pids" ]; then
|
||||
echo "$pids" | xargs kill -TERM 2>/dev/null || true
|
||||
sleep 1
|
||||
# Force kill if still running
|
||||
pids=$(lsof -ti :$port 2>/dev/null)
|
||||
if [ -n "$pids" ]; then
|
||||
echo "$pids" | xargs kill -9 2>/dev/null || true
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
stop_service() {
|
||||
local name=$1
|
||||
local pid_file=$2
|
||||
local port=$3
|
||||
|
||||
if is_running "$pid_file"; then
|
||||
local pid=$(get_pid "$pid_file")
|
||||
echo -e "${YELLOW}Stopping $name (PID: $pid)...${NC}"
|
||||
|
||||
# Kill the entire process tree
|
||||
kill_process_tree "$pid"
|
||||
|
||||
# Wait up to 5 seconds
|
||||
local count=0
|
||||
while [ $count -lt 5 ] && is_running "$pid_file"; do
|
||||
sleep 1
|
||||
count=$((count + 1))
|
||||
done
|
||||
|
||||
# Force kill if still running
|
||||
if is_running "$pid_file"; then
|
||||
force_kill_process_tree "$pid"
|
||||
fi
|
||||
|
||||
rm -f "$pid_file"
|
||||
fi
|
||||
|
||||
# Also kill any orphaned processes by port (fallback)
|
||||
if [ -n "$port" ]; then
|
||||
local port_pids=$(lsof -ti :$port 2>/dev/null)
|
||||
if [ -n "$port_pids" ]; then
|
||||
echo -e "${YELLOW}Cleaning up orphaned processes on port $port...${NC}"
|
||||
kill_by_port "$port"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}$name stopped${NC}"
|
||||
}
|
||||
|
||||
stop_all() {
|
||||
echo -e "${YELLOW}Stopping all production services...${NC}"
|
||||
stop_service "Backend" "$BACKEND_PID_FILE" "$BACKEND_PORT"
|
||||
stop_service "Frontend" "$FRONTEND_PID_FILE" "$FRONTEND_PORT"
|
||||
echo -e "${GREEN}All services stopped${NC}"
|
||||
}
|
||||
|
||||
show_status() {
|
||||
echo -e "${BLUE}Production Service Status:${NC}"
|
||||
echo ""
|
||||
|
||||
if is_running "$BACKEND_PID_FILE"; then
|
||||
local pid=$(get_pid "$BACKEND_PID_FILE")
|
||||
echo -e " Backend: ${GREEN}Running${NC} (PID: $pid, Workers: $UVICORN_WORKERS)"
|
||||
echo -e " http://localhost:$BACKEND_PORT"
|
||||
else
|
||||
echo -e " Backend: ${RED}Stopped${NC}"
|
||||
fi
|
||||
|
||||
if is_running "$FRONTEND_PID_FILE"; then
|
||||
local pid=$(get_pid "$FRONTEND_PID_FILE")
|
||||
echo -e " Frontend: ${GREEN}Running${NC} (PID: $pid)"
|
||||
echo -e " http://localhost:$FRONTEND_PORT"
|
||||
else
|
||||
echo -e " Frontend: ${RED}Stopped${NC}"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Main
|
||||
case "${1:-all}" in
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
--stop)
|
||||
stop_all
|
||||
;;
|
||||
--status)
|
||||
show_status
|
||||
;;
|
||||
backend)
|
||||
print_header
|
||||
check_requirements || exit 1
|
||||
start_backend
|
||||
echo ""
|
||||
echo -e "${YELLOW}Logs: tail -f $PID_DIR/backend.log${NC}"
|
||||
;;
|
||||
frontend)
|
||||
print_header
|
||||
check_requirements || exit 1
|
||||
start_frontend
|
||||
echo ""
|
||||
echo -e "${YELLOW}Logs: tail -f $PID_DIR/frontend.log${NC}"
|
||||
;;
|
||||
all|"")
|
||||
print_header
|
||||
check_requirements || exit 1
|
||||
start_backend
|
||||
start_frontend
|
||||
echo ""
|
||||
echo -e "${GREEN}================================${NC}"
|
||||
echo -e "${GREEN}All production services started!${NC}"
|
||||
echo -e "${GREEN}================================${NC}"
|
||||
echo ""
|
||||
echo "Access the application:"
|
||||
echo -e " Frontend: ${BLUE}http://localhost:$FRONTEND_PORT${NC}"
|
||||
echo -e " API Docs: ${BLUE}http://localhost:$BACKEND_PORT/docs${NC}"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Use ./start-prod.sh --stop to stop all services${NC}"
|
||||
echo -e "${YELLOW}Use ./start-prod.sh --status to check status${NC}"
|
||||
echo ""
|
||||
echo "Logs:"
|
||||
echo " Backend: tail -f $PID_DIR/backend.log"
|
||||
echo " Frontend: tail -f $PID_DIR/frontend.log"
|
||||
echo ""
|
||||
echo -e "${YELLOW}Note: For real production deployment, consider using:${NC}"
|
||||
echo " - nginx as reverse proxy"
|
||||
echo " - systemd for service management"
|
||||
echo " - Docker for containerization"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown command: $1${NC}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
122
start.sh
122
start.sh
@@ -1,9 +1,10 @@
|
||||
#!/bin/bash
|
||||
# Tool_OCR - Unified Development Server Startup Script
|
||||
# Tool_OCR - Unified Server Startup Script
|
||||
# Usage:
|
||||
# ./start.sh Start all services (backend + frontend)
|
||||
# ./start.sh backend Start only backend
|
||||
# ./start.sh frontend Start only frontend
|
||||
# ./start.sh --prod Start in production mode (no hot-reload)
|
||||
# ./start.sh --stop Stop all services
|
||||
# ./start.sh --status Show service status
|
||||
# ./start.sh --help Show help
|
||||
@@ -27,6 +28,10 @@ BACKEND_PORT=${BACKEND_PORT:-8000}
|
||||
FRONTEND_HOST=${FRONTEND_HOST:-0.0.0.0}
|
||||
FRONTEND_PORT=${FRONTEND_PORT:-5173}
|
||||
|
||||
# Production settings
|
||||
PROD_MODE=false
|
||||
UVICORN_WORKERS=${UVICORN_WORKERS:-4}
|
||||
|
||||
# Create PID directory
|
||||
mkdir -p "$PID_DIR"
|
||||
|
||||
@@ -34,15 +39,19 @@ mkdir -p "$PID_DIR"
|
||||
print_header() {
|
||||
echo ""
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo -e "${BLUE} Tool_OCR Development Server${NC}"
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
echo -e "${BLUE} Tool_OCR Server (Production)${NC}"
|
||||
else
|
||||
echo -e "${BLUE} Tool_OCR Server (Development)${NC}"
|
||||
fi
|
||||
echo -e "${BLUE}================================${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
show_help() {
|
||||
echo "Tool_OCR - Development Server Manager"
|
||||
echo "Tool_OCR - Server Manager"
|
||||
echo ""
|
||||
echo "Usage: ./start.sh [command]"
|
||||
echo "Usage: ./start.sh [options] [command]"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " (none) Start all services (backend + frontend)"
|
||||
@@ -52,10 +61,19 @@ show_help() {
|
||||
echo " --status Show status of services"
|
||||
echo " --help Show this help message"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " --prod Run in production mode (no hot-reload, multiple workers)"
|
||||
echo ""
|
||||
echo "Environment Variables:"
|
||||
echo " BACKEND_PORT Backend port (default: 8000)"
|
||||
echo " FRONTEND_PORT Frontend port (default: 5173)"
|
||||
echo " UVICORN_WORKERS Number of workers in prod mode (default: 4)"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " ./start.sh # Start everything"
|
||||
echo " ./start.sh backend # Start only backend"
|
||||
echo " ./start.sh --stop # Stop all services"
|
||||
echo " ./start.sh # Start in dev mode"
|
||||
echo " ./start.sh --prod # Start in production mode"
|
||||
echo " BACKEND_PORT=8088 ./start.sh # Use custom port"
|
||||
echo " ./start.sh --stop # Stop all services"
|
||||
echo ""
|
||||
}
|
||||
|
||||
@@ -76,10 +94,10 @@ check_requirements() {
|
||||
missing=1
|
||||
fi
|
||||
|
||||
# Check .env.local
|
||||
if [ ! -f "$SCRIPT_DIR/.env.local" ]; then
|
||||
echo -e "${RED}Error: .env.local not found${NC}"
|
||||
echo "Please copy .env.example to .env.local and configure"
|
||||
# Check .env
|
||||
if [ ! -f "$SCRIPT_DIR/.env" ]; then
|
||||
echo -e "${RED}Error: .env not found${NC}"
|
||||
echo "Please copy .env.example to .env and configure"
|
||||
missing=1
|
||||
fi
|
||||
|
||||
@@ -87,12 +105,12 @@ check_requirements() {
|
||||
}
|
||||
|
||||
load_env() {
|
||||
# Load environment variables from root .env.local (if present).
|
||||
# Load environment variables from root .env (if present).
|
||||
# This keeps backend/frontend config in sync without hardcoding ports/URLs in scripts.
|
||||
if [ -f "$SCRIPT_DIR/.env.local" ]; then
|
||||
if [ -f "$SCRIPT_DIR/.env" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1090
|
||||
source "$SCRIPT_DIR/.env.local"
|
||||
source "$SCRIPT_DIR/.env"
|
||||
set +a
|
||||
fi
|
||||
}
|
||||
@@ -124,7 +142,11 @@ start_backend() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Starting backend server...${NC}"
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
echo -e "${GREEN}Starting backend server (production mode)...${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Starting backend server (development mode)...${NC}"
|
||||
fi
|
||||
|
||||
# Activate virtual environment
|
||||
source "$SCRIPT_DIR/venv/bin/activate"
|
||||
@@ -141,8 +163,18 @@ start_backend() {
|
||||
mkdir -p models/paddleocr
|
||||
mkdir -p logs
|
||||
|
||||
# Start uvicorn
|
||||
nohup uvicorn app.main:app --reload --host "$BACKEND_HOST" --port "$BACKEND_PORT" > "$SCRIPT_DIR/.pid/backend.log" 2>&1 &
|
||||
# Start uvicorn (different modes)
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
nohup uvicorn app.main:app \
|
||||
--host "$BACKEND_HOST" \
|
||||
--port "$BACKEND_PORT" \
|
||||
--workers "$UVICORN_WORKERS" \
|
||||
--access-log \
|
||||
--log-level info \
|
||||
> "$SCRIPT_DIR/.pid/backend.log" 2>&1 &
|
||||
else
|
||||
nohup uvicorn app.main:app --reload --host "$BACKEND_HOST" --port "$BACKEND_PORT" > "$SCRIPT_DIR/.pid/backend.log" 2>&1 &
|
||||
fi
|
||||
local pid=$!
|
||||
echo $pid > "$BACKEND_PID_FILE"
|
||||
|
||||
@@ -151,7 +183,11 @@ start_backend() {
|
||||
# Wait a moment and verify
|
||||
sleep 2
|
||||
if is_running "$BACKEND_PID_FILE"; then
|
||||
echo -e "${GREEN}Backend started (PID: $pid)${NC}"
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
echo -e "${GREEN}Backend started (PID: $pid, Workers: $UVICORN_WORKERS)${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Backend started (PID: $pid)${NC}"
|
||||
fi
|
||||
echo -e " API Docs: http://localhost:$BACKEND_PORT/docs"
|
||||
echo -e " Health: http://localhost:$BACKEND_PORT/health"
|
||||
else
|
||||
@@ -166,7 +202,11 @@ start_frontend() {
|
||||
return 0
|
||||
fi
|
||||
|
||||
echo -e "${GREEN}Starting frontend server...${NC}"
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
echo -e "${GREEN}Starting frontend server (production mode)...${NC}"
|
||||
else
|
||||
echo -e "${GREEN}Starting frontend server (development mode)...${NC}"
|
||||
fi
|
||||
|
||||
# Load environment variables so Vite config can use FRONTEND_PORT/FRONTEND_HOST/etc.
|
||||
load_env
|
||||
@@ -177,8 +217,19 @@ start_frontend() {
|
||||
|
||||
cd "$SCRIPT_DIR/frontend"
|
||||
|
||||
# Start vite in background
|
||||
nohup npm run dev > "$SCRIPT_DIR/.pid/frontend.log" 2>&1 &
|
||||
# Start frontend (different modes)
|
||||
if [ "$PROD_MODE" = true ]; then
|
||||
# Build if needed
|
||||
if [ ! -d "dist" ] || [ "$(find src -newer dist -type f 2>/dev/null | head -1)" ]; then
|
||||
echo -e "${YELLOW}Building frontend...${NC}"
|
||||
npm run build
|
||||
fi
|
||||
# Start production preview server
|
||||
nohup npm run preview -- --host "$FRONTEND_HOST" --port "$FRONTEND_PORT" > "$SCRIPT_DIR/.pid/frontend.log" 2>&1 &
|
||||
else
|
||||
# Start vite dev server
|
||||
nohup npm run dev > "$SCRIPT_DIR/.pid/frontend.log" 2>&1 &
|
||||
fi
|
||||
local pid=$!
|
||||
echo $pid > "$FRONTEND_PID_FILE"
|
||||
|
||||
@@ -294,8 +345,31 @@ show_status() {
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Parse arguments
|
||||
COMMAND=""
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
--prod)
|
||||
PROD_MODE=true
|
||||
shift
|
||||
;;
|
||||
--help|-h|--stop|--status|backend|frontend|all)
|
||||
COMMAND=$1
|
||||
shift
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown option: $1${NC}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Default command
|
||||
COMMAND=${COMMAND:-all}
|
||||
|
||||
# Main
|
||||
case "${1:-all}" in
|
||||
case "$COMMAND" in
|
||||
--help|-h)
|
||||
show_help
|
||||
;;
|
||||
@@ -321,7 +395,7 @@ case "${1:-all}" in
|
||||
echo -e "${YELLOW}Press Ctrl+C to stop (or use ./start.sh --stop)${NC}"
|
||||
echo -e "${YELLOW}Logs: tail -f .pid/frontend.log${NC}"
|
||||
;;
|
||||
all|"")
|
||||
all)
|
||||
print_header
|
||||
check_requirements || exit 1
|
||||
start_backend
|
||||
@@ -343,7 +417,7 @@ case "${1:-all}" in
|
||||
echo " Frontend: tail -f .pid/frontend.log"
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Unknown command: $1${NC}"
|
||||
echo -e "${RED}Unknown command: $COMMAND${NC}"
|
||||
show_help
|
||||
exit 1
|
||||
;;
|
||||
|
||||
Reference in New Issue
Block a user