1
This commit is contained in:
@@ -0,0 +1,47 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# 创建内部员工账号
|
||||||
|
# 用法: bash create-admin.sh 用户名 邮箱 密码
|
||||||
|
# 示例: bash create-admin.sh zhangsan zhang@company.com 12345678
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
USERNAME=${1:-admin}
|
||||||
|
EMAIL=${2:-admin@company.com}
|
||||||
|
PASSWORD=${3:-Lzcc6-01}
|
||||||
|
|
||||||
|
echo "创建内部员工: $USERNAME ($EMAIL)"
|
||||||
|
|
||||||
|
docker compose exec -T backend python -c "
|
||||||
|
from app.core.db import get_session_factory
|
||||||
|
from app.models.user import User
|
||||||
|
from app.models.plan import Plan
|
||||||
|
from app.core.security import hash_password
|
||||||
|
from sqlalchemy import select
|
||||||
|
|
||||||
|
factory = get_session_factory()
|
||||||
|
with factory() as session:
|
||||||
|
existing = session.scalars(select(User).where(User.username == '$USERNAME')).first()
|
||||||
|
if existing:
|
||||||
|
print(f'用户 $USERNAME 已存在,更新密码...')
|
||||||
|
existing.password_hash = hash_password('$PASSWORD')
|
||||||
|
existing.role = 'internal'
|
||||||
|
session.commit()
|
||||||
|
print('密码已更新')
|
||||||
|
else:
|
||||||
|
plan = session.scalars(select(Plan).where(Plan.code == 'free')).first()
|
||||||
|
if not plan:
|
||||||
|
plan = Plan(code='free', name='免费版', storage_quota=104857600, max_file_size=20971520, is_active=True)
|
||||||
|
session.add(plan)
|
||||||
|
session.flush()
|
||||||
|
user = User(
|
||||||
|
username='$USERNAME',
|
||||||
|
email='$EMAIL',
|
||||||
|
password_hash=hash_password('$PASSWORD'),
|
||||||
|
status='active',
|
||||||
|
role='internal',
|
||||||
|
plan_id=plan.id,
|
||||||
|
)
|
||||||
|
session.add(user)
|
||||||
|
session.commit()
|
||||||
|
print(f'内部员工创建成功: $USERNAME / $PASSWORD')
|
||||||
|
"
|
||||||
@@ -0,0 +1,85 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# AI Knowledge Link — 一键部署脚本
|
||||||
|
# 在服务器项目目录执行:bash deploy.sh
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=== AI Knowledge Link 部署 ==="
|
||||||
|
|
||||||
|
# 1. 检查 .env
|
||||||
|
if [ ! -f .env ]; then
|
||||||
|
echo "创建 .env ..."
|
||||||
|
cp .env.production .env
|
||||||
|
|
||||||
|
# 自动生成 SECRET_KEY
|
||||||
|
SECRET=$(python3 -c "import secrets; print(secrets.token_urlsafe(48))" 2>/dev/null || openssl rand -base64 48)
|
||||||
|
sed -i "s/change-me-to-a-real-secret-key/$SECRET/" .env
|
||||||
|
echo "SECRET_KEY 已自动生成"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 2. 创建数据目录
|
||||||
|
mkdir -p data
|
||||||
|
|
||||||
|
# 3. 构建并启动
|
||||||
|
echo "构建镜像..."
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
echo "启动服务..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 4. 等待 MySQL 就绪
|
||||||
|
echo "等待 MySQL 就绪..."
|
||||||
|
sleep 10
|
||||||
|
|
||||||
|
# 5. 数据库迁移
|
||||||
|
echo "执行数据库迁移..."
|
||||||
|
docker compose exec -T backend alembic upgrade head
|
||||||
|
|
||||||
|
# 6. 创建内部管理员账号(如果不存在)
|
||||||
|
echo "检查管理员账号..."
|
||||||
|
docker compose exec -T backend python -c "
|
||||||
|
from app.core.db import get_session_factory
|
||||||
|
from app.models.user import User
|
||||||
|
from app.models.plan import Plan
|
||||||
|
from app.core.security import hash_password
|
||||||
|
from sqlalchemy import select
|
||||||
|
|
||||||
|
factory = get_session_factory()
|
||||||
|
with factory() as session:
|
||||||
|
admin = session.scalars(select(User).where(User.username == 'admin')).first()
|
||||||
|
if not admin:
|
||||||
|
plan = session.scalars(select(Plan).where(Plan.code == 'free')).first()
|
||||||
|
if not plan:
|
||||||
|
plan = Plan(code='free', name='免费版', storage_quota=104857600, max_file_size=20971520, is_active=True)
|
||||||
|
session.add(plan)
|
||||||
|
session.flush()
|
||||||
|
admin = User(
|
||||||
|
username='admin',
|
||||||
|
email='admin@company.com',
|
||||||
|
password_hash=hash_password('Lzcc6-01'),
|
||||||
|
status='active',
|
||||||
|
role='internal',
|
||||||
|
plan_id=plan.id,
|
||||||
|
)
|
||||||
|
session.add(admin)
|
||||||
|
session.commit()
|
||||||
|
print('管理员账号已创建: admin / Lzcc6-01')
|
||||||
|
else:
|
||||||
|
print('管理员账号已存在,跳过')
|
||||||
|
"
|
||||||
|
|
||||||
|
# 7. 完成
|
||||||
|
echo ""
|
||||||
|
echo "=========================================="
|
||||||
|
echo " 部署完成!"
|
||||||
|
echo ""
|
||||||
|
echo " 访问地址: http://$(curl -s ifconfig.me 2>/dev/null || echo '你的服务器IP')"
|
||||||
|
echo " 内部登录: http://$(curl -s ifconfig.me 2>/dev/null || echo '你的服务器IP')/internal-login"
|
||||||
|
echo ""
|
||||||
|
echo " 管理员: admin"
|
||||||
|
echo " 密码: Lzcc6-01"
|
||||||
|
echo ""
|
||||||
|
echo " 更新部署: bash update.sh"
|
||||||
|
echo "=========================================="
|
||||||
+50
-10
@@ -1,30 +1,65 @@
|
|||||||
# AI Knowledge Link — Docker Compose (生产)
|
# AI Knowledge Link — Docker Compose (生产)
|
||||||
# Ubuntu 服务器部署用。Windows 开发不需要 Docker。
|
|
||||||
#
|
|
||||||
# 数据持久化:./data 挂载到 backend,SQLite + 用户文件均在其中。
|
|
||||||
# 删除容器后数据不丢失。
|
|
||||||
#
|
#
|
||||||
# 用法:
|
# 用法:
|
||||||
# cp .env.example .env # 修改密钥
|
# 1. 把代码上传到服务器
|
||||||
# mkdir -p data
|
# 2. cp .env.example .env && 修改 SECRET_KEY
|
||||||
# docker compose up -d --build
|
# 3. docker compose up -d --build
|
||||||
|
# 4. docker compose exec backend alembic upgrade head (首次)
|
||||||
|
# 5. 访问 http://服务器IP
|
||||||
|
#
|
||||||
|
# 更新部署:
|
||||||
|
# git pull && docker compose up -d --build
|
||||||
|
|
||||||
services:
|
services:
|
||||||
|
# ---------- MySQL ----------
|
||||||
|
mysql:
|
||||||
|
image: mysql:8.0
|
||||||
|
restart: unless-stopped
|
||||||
|
environment:
|
||||||
|
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD:-Lzcc6-01}
|
||||||
|
MYSQL_DATABASE: amb_rag
|
||||||
|
MYSQL_USER: amb
|
||||||
|
MYSQL_PASSWORD: ${MYSQL_PASSWORD:-Lzcc6-01}
|
||||||
|
command: --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci
|
||||||
|
volumes:
|
||||||
|
- mysql_data:/var/lib/mysql
|
||||||
|
ports:
|
||||||
|
- "3306:3306"
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
|
||||||
|
interval: 10s
|
||||||
|
timeout: 5s
|
||||||
|
retries: 10
|
||||||
|
|
||||||
|
# ---------- 后端 ----------
|
||||||
backend:
|
backend:
|
||||||
build:
|
build:
|
||||||
context: ./backend
|
context: ./backend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
env_file: .env
|
environment:
|
||||||
|
ENVIRONMENT: production
|
||||||
|
SECRET_KEY: ${SECRET_KEY:-change-me-to-a-real-secret-key}
|
||||||
|
DATABASE_URL: mysql+pymysql://amb:${MYSQL_PASSWORD:-Lzcc6-01}@mysql:3306/amb_rag?charset=utf8mb4
|
||||||
|
STORAGE_ROOT: /app/data
|
||||||
|
DEFAULT_STORAGE_QUOTA: "104857600"
|
||||||
|
DEFAULT_MAX_FILE_SIZE: "20971520"
|
||||||
|
RATE_LIMIT_PER_TOKEN_PER_MIN: "60"
|
||||||
|
RATE_LIMIT_PER_IP_PER_MIN: "30"
|
||||||
|
FRONTEND_ORIGIN: http://localhost
|
||||||
volumes:
|
volumes:
|
||||||
- ./data:/app/data
|
- app_data:/app/data
|
||||||
expose:
|
expose:
|
||||||
- "8000"
|
- "8000"
|
||||||
|
depends_on:
|
||||||
|
mysql:
|
||||||
|
condition: service_healthy
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/healthz')"]
|
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://localhost:8000/api/healthz')"]
|
||||||
interval: 10s
|
interval: 10s
|
||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
retries: 5
|
||||||
|
|
||||||
|
# ---------- 前端 ----------
|
||||||
frontend:
|
frontend:
|
||||||
build:
|
build:
|
||||||
context: ./frontend
|
context: ./frontend
|
||||||
@@ -32,6 +67,7 @@ services:
|
|||||||
expose:
|
expose:
|
||||||
- "80"
|
- "80"
|
||||||
|
|
||||||
|
# ---------- Nginx ----------
|
||||||
nginx:
|
nginx:
|
||||||
image: nginx:1.27-alpine
|
image: nginx:1.27-alpine
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
@@ -42,4 +78,8 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
backend:
|
backend:
|
||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
- frontend
|
- frontend
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
mysql_data:
|
||||||
|
app_data:
|
||||||
@@ -0,0 +1,39 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# ============================================================
|
||||||
|
# AI Knowledge Link — 一键更新脚本
|
||||||
|
# 在服务器项目目录执行:bash update.sh
|
||||||
|
#
|
||||||
|
# 功能:
|
||||||
|
# 1. 拉取最新代码
|
||||||
|
# 2. 重新构建镜像
|
||||||
|
# 3. 重启服务(数据库不丢失)
|
||||||
|
# 4. 执行数据库迁移(如有新迁移)
|
||||||
|
# ============================================================
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "=== AI Knowledge Link 更新 ==="
|
||||||
|
echo "时间: $(date '+%Y-%m-%d %H:%M:%S')"
|
||||||
|
|
||||||
|
# 1. 拉取最新代码
|
||||||
|
echo "[1/4] 拉取最新代码..."
|
||||||
|
git pull
|
||||||
|
|
||||||
|
# 2. 重新构建
|
||||||
|
echo "[2/4] 重新构建镜像..."
|
||||||
|
docker compose build
|
||||||
|
|
||||||
|
# 3. 重启服务
|
||||||
|
echo "[3/4] 重启服务..."
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
# 4. 数据库迁移
|
||||||
|
echo "[4/4] 执行数据库迁移..."
|
||||||
|
sleep 5
|
||||||
|
docker compose exec -T backend alembic upgrade head
|
||||||
|
|
||||||
|
# 5. 完成
|
||||||
|
echo ""
|
||||||
|
echo "更新完成!$(date '+%H:%M:%S')"
|
||||||
|
echo "服务状态:"
|
||||||
|
docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}"
|
||||||
Reference in New Issue
Block a user