diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..aa4ab12 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,51 @@ +# Python +__pycache__/ +*.py[cod] +*$py.class +*.egg-info/ +dist/ +build/ +.eggs/ +.venv/ +venv/ +env/ + +# Git +.git/ +.gitignore + +# Docker +Dockerfile +docker-compose.yml +.dockerignore + +# 文档 +README.md +CONTRIBUTING.md +CHANGELOG.md +LICENSE +Todo.md +mcp.md +*.md + +# 敏感文件 +config.json +cookies.json + +# 备份文件 +main_v1_backup.py +config copy.json +*_backup.py + +# IDE +.vscode/ +.idea/ + +# 日志 & 临时 +*.log +*.tmp +*.bak + +# 系统文件 +.DS_Store +Thumbs.db diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..99a709f --- /dev/null +++ b/Dockerfile @@ -0,0 +1,50 @@ +# ---------- 构建阶段 ---------- +FROM python:3.11-slim AS builder + +WORKDIR /app + +# 安装构建依赖(matplotlib 需要) +RUN apt-get update && \ + apt-get install -y --no-install-recommends gcc && \ + rm -rf /var/lib/apt/lists/* + +COPY requirements.txt . +RUN pip install --no-cache-dir --prefix=/install -r requirements.txt + +# ---------- 运行阶段 ---------- +FROM python:3.11-slim + +LABEL maintainer="xhs-autobot" +LABEL description="小红书 AI 爆文生产工坊" + +WORKDIR /app + +# matplotlib 中文字体 + 运行时依赖 +RUN apt-get update && \ + apt-get install -y --no-install-recommends fonts-noto-cjk curl && \ + rm -rf /var/lib/apt/lists/* + +# 从构建阶段复制 Python 包 +COPY --from=builder /install /usr/local + +# 复制项目代码 +COPY config_manager.py llm_service.py sd_service.py mcp_client.py main.py ./ +COPY requirements.txt ./ +COPY config.example.json ./ + +# 创建工作目录 +RUN mkdir -p xhs_workspace + +# Gradio 默认端口 +EXPOSE 7860 + +# 环境变量 +ENV GRADIO_SERVER_NAME="0.0.0.0" +ENV GRADIO_SERVER_PORT="7860" +ENV PYTHONUNBUFFERED=1 +ENV MPLCONFIGDIR=/tmp/matplotlib + +HEALTHCHECK --interval=30s --timeout=5s --retries=3 \ + CMD curl -f http://localhost:7860/ || exit 1 + +CMD ["python", "main.py"] diff --git a/README.md b/README.md index e19c64e..2ae3d59 100644 --- a/README.md +++ b/README.md @@ -93,6 +93,64 @@ python main.py 启动后会自动打开浏览器,访问 `http://127.0.0.1:7860`。 +### 🐳 Docker 部署(推荐) + +使用 Docker Compose 一键启动所有服务,无需手动安装 Python 环境: + +```bash +# 1. 克隆项目 +git clone https://github.com/your-username/xhs-autobot.git +cd xhs-autobot + +# 2. 准备配置文件 +cp config.example.json config.json +# 编辑 config.json,填写 api_key、base_url 等 +# ⚠️ mcp_url 改为容器网络地址: +# "mcp_url": "http://xhs-mcp:18060/mcp" + +# 3. 一键启动 +docker compose up -d + +# 4. 查看日志 +docker compose logs -f xhs-autobot +``` + +启动后访问 `http://localhost:7860`。 + +#### Docker 服务说明 + +| 服务 | 容器名 | 端口 | 说明 | +|------|--------|------|------| +| `xhs-autobot` | xhs-autobot | 7860 | 主应用(Gradio UI) | +| `xhs-mcp` | xhs-mcp | 18060 | 小红书 MCP 服务 | +| `sd-webui` | sd-webui | 7861 | SD WebUI(可选,需 GPU) | + +#### 常用命令 + +```bash +# 停止所有服务 +docker compose down + +# 重新构建(代码更新后) +docker compose up -d --build + +# 查看运行状态 +docker compose ps + +# 进入主容器调试 +docker compose exec xhs-autobot bash +``` + +#### 启用 Stable Diffusion(需要 NVIDIA GPU) + +编辑 `docker-compose.yml`,取消 `sd-webui` 部分的注释,并将 `config.json` 中的 `sd_url` 改为: + +```json +"sd_url": "http://sd-webui:7860" +``` + +--- + ### 前置服务 #### xiaohongshu-mcp(必须) @@ -183,6 +241,9 @@ xhs-autobot/ ├── config.json # 运行时配置 (gitignore) ├── config.example.json # 配置模板 ├── requirements.txt # Python 依赖 +├── Dockerfile # Docker 镜像构建 +├── docker-compose.yml # Docker Compose 编排 +├── .dockerignore # Docker 构建排除规则 ├── xhs_workspace/ # 导出的文案和图片 (gitignore) └── autobot.log # 运行日志 (gitignore) ``` diff --git a/config.json b/config.json index 0b11c37..fff8b35 100644 --- a/config.json +++ b/config.json @@ -1,7 +1,7 @@ { "api_key": "sk-NPZECL5m3BmZv0S9YO9KOd179pepRH08iYeAn1Tk07Jux9Br", "base_url": "https://wolfai.top/v1", - "sd_url": "http://127.0.0.1:7860", + "sd_url": "http://127.0.0.1:7861", "mcp_url": "http://localhost:18060/mcp", "model": "gemini-3-flash-preview", "persona": "温柔知性的时尚博主", diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..c352f3c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,80 @@ +version: "3.8" + +services: + # ============================================================ + # 小红书 AI 爆文工坊(主应用) + # ============================================================ + xhs-autobot: + build: . + container_name: xhs-autobot + restart: unless-stopped + ports: + - "7860:7860" + volumes: + # 配置文件挂载(首次请从 config.example.json 复制并填写) + - ./config.json:/app/config.json + # 工作目录(导出的文案 & 图片) + - ./xhs_workspace:/app/xhs_workspace + environment: + - GRADIO_SERVER_NAME=0.0.0.0 + - GRADIO_SERVER_PORT=7860 + depends_on: + xhs-mcp: + condition: service_started + networks: + - xhs-net + + # ============================================================ + # xiaohongshu-mcp 服务(小红书 API 代理) + # ============================================================ + xhs-mcp: + image: node:20-slim + container_name: xhs-mcp + restart: unless-stopped + ports: + - "18060:18060" + working_dir: /app + # 首次启动自动安装并运行 xiaohongshu-mcp + command: > + sh -c " + npm install -g xiaohongshu-mcp && + npx xiaohongshu-mcp --port 18060 --host 0.0.0.0 + " + volumes: + # cookies 持久化(登录后保留会话) + - xhs-mcp-data:/root/.xiaohongshu-mcp + networks: + - xhs-net + + # ============================================================ + # Stable Diffusion WebUI(可选 — 取消注释启用) + # ⚠ 需要 NVIDIA GPU + nvidia-docker + # ============================================================ + # sd-webui: + # image: ghcr.io/AUTOMATIC1111/stable-diffusion-webui:latest + # container_name: sd-webui + # restart: unless-stopped + # ports: + # - "7861:7860" + # volumes: + # - sd-models:/app/models + # - sd-outputs:/app/outputs + # deploy: + # resources: + # reservations: + # devices: + # - driver: nvidia + # count: all + # capabilities: [gpu] + # command: ["python", "launch.py", "--api", "--listen"] + # networks: + # - xhs-net + +volumes: + xhs-mcp-data: + # sd-models: + # sd-outputs: + +networks: + xhs-net: + driver: bridge diff --git a/main.py b/main.py index e6b11a7..8ff5347 100644 --- a/main.py +++ b/main.py @@ -2252,4 +2252,9 @@ with gr.Blocks( # ================================================== if __name__ == "__main__": logger.info("🍒 小红书 AI 爆文工坊 V2.0 启动中...") - app.launch(inbrowser=True, share=False) + app.launch( + server_name=os.environ.get("GRADIO_SERVER_NAME", "127.0.0.1"), + server_port=int(os.environ.get("GRADIO_SERVER_PORT", "7860")), + inbrowser=True, + share=False, + )