revert useless dockfile change

This commit is contained in:
sylarchen1389 2025-11-13 11:13:13 +08:00
parent 73af7a4a4f
commit 88396a16e6
24 changed files with 653 additions and 944 deletions

View file

@ -1,10 +1,7 @@
{
"permissions": {
"allow": [
"Bash(tree:*)",
"Bash(node:*)",
"Bash(npm --version:*)",
"Bash(test:*)"
"Bash(tree:*)"
],
"deny": [],
"ask": []

View file

@ -1,137 +0,0 @@
name: Docker Image CI
on:
push:
branches: [ main ]
pull_request:
branches: [ main ]
workflow_dispatch: # 允许手动触发
env:
IMAGE_NAME: open-webui-next
OUTPUT_DIR: /tmp/docker-images
KEEP_VERSIONS: 2
jobs:
build:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: 检出代码
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: 设置环境变量
run: |
echo "IMAGE_TAG=${{ github.run_number }}" >> $GITHUB_ENV
echo "BUILD_NUMBER=${{ github.run_number }}" >> $GITHUB_ENV
echo "✓ 代码检出完成"
ls -la
- name: 验证 Dockerfile
run: |
if [ ! -f "Dockerfile" ]; then
echo "❌ 找不到 Dockerfile"
exit 1
fi
echo "✓ Dockerfile 存在"
head -10 Dockerfile
- name: 设置 Docker Buildx
uses: docker/setup-buildx-action@v3
- name: 构建 Docker 镜像
uses: docker/build-push-action@v5
with:
context: .
load: true
tags: |
${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }}
${{ env.IMAGE_NAME }}:latest
build-args: |
USE_SLIM=true
cache-from: type=gha
cache-to: type=gha,mode=max
- name: 验证镜像构建
run: |
echo "✓ 镜像构建完成"
docker images | grep ${{ env.IMAGE_NAME }}
- name: 创建输出目录
run: |
mkdir -p ${{ env.OUTPUT_DIR }}
echo "输出目录: ${{ env.OUTPUT_DIR }}"
- name: 导出镜像
run: |
echo "导出镜像..."
docker save ${{ env.IMAGE_NAME }}:${{ env.IMAGE_TAG }} | gzip > ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}-${{ env.IMAGE_TAG }}.tar.gz
docker save ${{ env.IMAGE_NAME }}:latest | gzip > ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}-latest.tar.gz
echo "✓ 镜像导出完成"
ls -lh ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}*.tar.gz
- name: 上传镜像制品
uses: actions/upload-artifact@v4
with:
name: docker-images-${{ env.IMAGE_TAG }}
path: |
${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}-${{ env.IMAGE_TAG }}.tar.gz
${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}-latest.tar.gz
retention-days: 30
- name: 清理本地资源
if: always()
run: |
echo "========================================="
echo "当前构建: ${{ env.BUILD_NUMBER }}"
VERSION_TO_DELETE=$((BUILD_NUMBER - 2))
echo "准备清理版本: ${VERSION_TO_DELETE}"
echo "========================================="
# 清理旧版本的 Docker 镜像
echo "清理 Docker 镜像..."
docker rmi ${{ env.IMAGE_NAME }}:${VERSION_TO_DELETE} 2>/dev/null || echo "镜像 ${VERSION_TO_DELETE} 不存在或已清理"
# 清理旧版本的 tar.gz 文件
echo "清理导出文件..."
rm -f ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}-${VERSION_TO_DELETE}.tar.gz
# 清理未使用的 Docker 资源
echo "清理未使用的 Docker 资源..."
docker image prune -f
echo "✓ 清理完成"
echo ""
echo "剩余镜像:"
docker images | grep ${{ env.IMAGE_NAME }} || echo "无相关镜像"
echo ""
echo "剩余文件:"
ls -lh ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}*.tar.gz 2>/dev/null || echo "无相关文件"
- name: 显示磁盘使用情况
if: always()
run: |
echo "最终磁盘使用情况:"
df -h ${{ env.OUTPUT_DIR }}
- name: 构建摘要
if: success()
run: |
echo "=========================================" >> $GITHUB_STEP_SUMMARY
echo "✅ 构建成功!" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**镜像信息:**" >> $GITHUB_STEP_SUMMARY
echo "- 镜像名称: \`${{ env.IMAGE_NAME }}\`" >> $GITHUB_STEP_SUMMARY
echo "- 镜像标签: \`${{ env.IMAGE_TAG }}\`, \`latest\`" >> $GITHUB_STEP_SUMMARY
echo "- 构建编号: \`${{ github.run_number }}\`" >> $GITHUB_STEP_SUMMARY
echo "" >> $GITHUB_STEP_SUMMARY
echo "**导出文件:**" >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
ls -lh ${{ env.OUTPUT_DIR }}/${{ env.IMAGE_NAME }}*.tar.gz >> $GITHUB_STEP_SUMMARY
echo "\`\`\`" >> $GITHUB_STEP_SUMMARY
echo "=========================================" >> $GITHUB_STEP_SUMMARY

View file

@ -1,92 +1,45 @@
# syntax=docker/dockerfile:1
# Initialize device type args
# use build args in the docker build command with --build-arg="BUILDARG=true"
ARG USE_CUDA=false
ARG USE_OLLAMA=false
ARG USE_SLIM=false
ARG USE_PERMISSION_HARDENING=false
# Tested with cu117 for CUDA 11 and cu121 for CUDA 12 (default)
ARG USE_CUDA_VER=cu128
# any sentence transformer model; models to use can be found at https://huggingface.co/models?library=sentence-transformers
# Leaderboard: https://huggingface.co/spaces/mteb/leaderboard
# for better performance and multilangauge support use "intfloat/multilingual-e5-large" (~2.5GB) or "intfloat/multilingual-e5-base" (~1.5GB)
# IMPORTANT: If you change the embedding model (sentence-transformers/all-MiniLM-L6-v2) and vice versa, you aren't able to use RAG Chat with your previous documents loaded in the WebUI! You need to re-embed them.
ARG USE_EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
ARG USE_RERANKING_MODEL=""
# Tiktoken encoding name; models to use can be found at https://huggingface.co/models?library=tiktoken
ARG USE_TIKTOKEN_ENCODING_NAME="cl100k_base"
ARG BUILD_HASH=dev-build
# Override at your own risk - non-root configurations are untested
ARG UID=0
ARG GID=0
######## WebUI frontend ########
FROM --platform=$BUILDPLATFORM node:20-alpine3.20 AS build
FROM --platform=$BUILDPLATFORM node:22-alpine3.20 AS build
ARG BUILD_HASH
# ========== 配置 Alpine 镜像源 ==========
RUN echo "https://mirrors.aliyun.com/alpine/v3.20/main" > /etc/apk/repositories && \
echo "https://mirrors.aliyun.com/alpine/v3.20/community" >> /etc/apk/repositories && \
apk update
# ========== 增加 Node.js 堆内存限制 ==========
ENV NODE_OPTIONS="--max-old-space-size=4096"
# ========== 配置 npm 镜像源 ==========
RUN npm config set registry https://registry.npmmirror.com && \
npm config set fetch-timeout 120000 && \
npm config set fetch-retries 5 && \
npm config set fetch-retry-mintimeout 20000 && \
npm config set fetch-retry-maxtimeout 120000 && \
npm config set maxsockets 5
# ========== 配置二进制包镜像 ==========
ENV ELECTRON_MIRROR=https://npmmirror.com/mirrors/electron/ \
SASS_BINARY_SITE=https://npmmirror.com/mirrors/node-sass/ \
PHANTOMJS_CDNURL=https://nppmirror.com/mirrors/phantomjs/ \
CHROMEDRIVER_CDNURL=https://npmmirror.com/mirrors/chromedriver/ \
OPERADRIVER_CDNURL=https://npmmirror.com/mirrors/operadriver/ \
PYTHON_MIRROR=https://npmmirror.com/mirrors/python/
# ========== 配置代理(可选)==========
ARG HTTP_PROXY
ARG HTTPS_PROXY
ENV HTTP_PROXY=${HTTP_PROXY}
ENV HTTPS_PROXY=${HTTPS_PROXY}
ENV NO_PROXY=localhost,127.0.0.1,mirrors.aliyun.com,registry.nppmirror.com,nppmirror.com
# ========== 安装必要工具 ==========
RUN apk add --no-cache git python3 make g++ && \
if [ -n "$HTTP_PROXY" ]; then \
git config --global http.proxy ${HTTP_PROXY} && \
git config --global https.proxy ${HTTPS_PROXY} && \
git config --global http.sslVerify false; \
fi
# Set Node.js options (heap limit Allocation failed - JavaScript heap out of memory)
# ENV NODE_OPTIONS="--max-old-space-size=4096"
WORKDIR /app
# ========== 安装依赖(不使用 --ignore-scripts==========
# to store git revision in build
RUN apk add --no-cache git
COPY package.json package-lock.json ./
RUN npm ci --force
RUN echo "==================================" && \
echo "Starting npm install" && \
echo "Time: $(date)" && \
echo "==================================" && \
npm cache clean --force && \
npm install --legacy-peer-deps --no-audit --no-fund || \
(echo "First attempt failed, retrying..." && \
rm -rf node_modules package-lock.json && \
npm install --legacy-peer-deps --no-audit --no-fund) && \
echo "==================================" && \
echo "npm install completed" && \
echo "Time: $(date)" && \
echo "=================================="
# ========== 构建前端 ==========
COPY . .
ENV APP_BUILD_HASH=${BUILD_HASH}
RUN echo "==================================" && \
echo "Starting frontend build" && \
echo "Time: $(date)" && \
echo "==================================" && \
npm run build && \
echo "==================================" && \
echo "Build completed" && \
echo "Time: $(date)" && \
echo "=================================="
RUN npm run build
######## WebUI backend ########
FROM python:3.11-slim-bookworm AS base
@ -105,6 +58,7 @@ ARG GID
## Basis ##
ENV ENV=prod \
PORT=8080 \
# pass build args to the build
USE_OLLAMA_DOCKER=${USE_OLLAMA} \
USE_CUDA_DOCKER=${USE_CUDA} \
USE_SLIM_DOCKER=${USE_SLIM} \
@ -124,23 +78,31 @@ ENV OPENAI_API_KEY="" \
ANONYMIZED_TELEMETRY=false
#### Other models #########################################################
## whisper TTS model settings ##
ENV WHISPER_MODEL="base" \
WHISPER_MODEL_DIR="/app/backend/data/cache/whisper/models" \
RAG_EMBEDDING_MODEL="$USE_EMBEDDING_MODEL_DOCKER" \
RAG_RERANKING_MODEL="$USE_RERANKING_MODEL_DOCKER" \
SENTENCE_TRANSFORMERS_HOME="/app/backend/data/cache/embedding/models" \
TIKTOKEN_ENCODING_NAME="cl100k_base" \
TIKTOKEN_CACHE_DIR="/app/backend/data/cache/tiktoken" \
HF_HOME="/app/backend/data/cache/embedding/models"
WHISPER_MODEL_DIR="/app/backend/data/cache/whisper/models"
# ========== 配置 Hugging Face 镜像 ==========
ENV HF_ENDPOINT=https://hf-mirror.com
## RAG Embedding model settings ##
ENV RAG_EMBEDDING_MODEL="$USE_EMBEDDING_MODEL_DOCKER" \
RAG_RERANKING_MODEL="$USE_RERANKING_MODEL_DOCKER" \
SENTENCE_TRANSFORMERS_HOME="/app/backend/data/cache/embedding/models"
## Tiktoken model settings ##
ENV TIKTOKEN_ENCODING_NAME="cl100k_base" \
TIKTOKEN_CACHE_DIR="/app/backend/data/cache/tiktoken"
## Hugging Face download cache ##
ENV HF_HOME="/app/backend/data/cache/embedding/models"
## Torch Extensions ##
# ENV TORCH_EXTENSIONS_DIR="/.cache/torch_extensions"
#### Other models ##########################################################
WORKDIR /app/backend
ENV HOME=/root
# ========== 创建用户和组 ==========
# Create user and group if not root
RUN if [ $UID -ne 0 ]; then \
if [ $GID -ne 0 ]; then \
addgroup --gid $GID app; \
@ -148,15 +110,13 @@ RUN if [ $UID -ne 0 ]; then \
adduser --uid $UID --gid $GID --home $HOME --disabled-password --no-create-home app; \
fi
RUN mkdir -p $HOME/.cache/chroma && \
echo -n 00000000-0000-0000-0000-000000000000 > $HOME/.cache/chroma/telemetry_user_id && \
chown -R $UID:$GID /app $HOME
RUN mkdir -p $HOME/.cache/chroma
RUN echo -n 00000000-0000-0000-0000-000000000000 > $HOME/.cache/chroma/telemetry_user_id
# ========== 配置 Debian 镜像源 ==========
RUN sed -i 's@deb.debian.org@mirrors.aliyun.com@g' /etc/apt/sources.list.d/debian.sources && \
sed -i 's@security.debian.org@mirrors.aliyun.com@g' /etc/apt/sources.list.d/debian.sources
# Make sure the user has access to the app and root directory
RUN chown -R $UID:$GID /app $HOME
# ========== 安装系统依赖 ==========
# Install common system dependencies
RUN apt-get update && \
apt-get install -y --no-install-recommends \
git build-essential pandoc gcc netcat-openbsd curl jq \
@ -164,100 +124,56 @@ RUN apt-get update && \
ffmpeg libsm6 libxext6 \
&& rm -rf /var/lib/apt/lists/*
# ========== 配置 pip 镜像源 ==========
RUN pip3 config set global.index-url https://mirrors.aliyun.com/pypi/simple/ && \
pip3 config set install.trusted-host mirrors.aliyun.com && \
pip3 config set global.timeout 600
# ========== 配置 uv 使用镜像源 ==========
ENV UV_INDEX_URL=https://mirrors.aliyun.com/pypi/simple/ \
UV_EXTRA_INDEX_URL="" \
UV_NO_CACHE=0
# ========== 安装 Python 依赖 ==========
# install python dependencies
COPY --chown=$UID:$GID ./backend/requirements.txt ./requirements.txt
RUN echo "==================================" && \
echo "Installing Python dependencies" && \
echo "Time: $(date)" && \
echo "==================================" && \
pip3 install uv && \
RUN pip3 install --no-cache-dir uv && \
if [ "$USE_CUDA" = "true" ]; then \
echo "Installing PyTorch with CUDA support..." && \
pip3 install torch torchvision torchaudio \
--index-url https://mirrors.aliyun.com/pypi/simple/ \
--trusted-host mirrors.aliyun.com || \
(echo "Aliyun failed, trying Tsinghua mirror..." && \
pip3 install torch torchvision torchaudio \
--index-url https://pypi.tuna.tsinghua.edu.cn/simple/ \
--trusted-host pypi.tuna.tsinghua.edu.cn) || \
(echo "Mirrors failed, trying official PyTorch repo..." && \
pip3 install torch torchvision torchaudio \
--index-url https://download.pytorch.org/whl/$USE_CUDA_DOCKER_VER) && \
echo "Installing other requirements with uv..." && \
uv pip install --system -r requirements.txt \
--index-url https://mirrors.aliyun.com/pypi/simple/ && \
if [ "$USE_SLIM" != "true" ]; then \
echo "Downloading models..." && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])" && \
python -c "import os; import tiktoken; tiktoken.get_encoding(os.environ['TIKTOKEN_ENCODING_NAME'])"; \
fi; \
# If you use CUDA the whisper and embedding model will be downloaded on first use
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/$USE_CUDA_DOCKER_VER --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
python -c "import os; import tiktoken; tiktoken.get_encoding(os.environ['TIKTOKEN_ENCODING_NAME'])"; \
else \
echo "Installing PyTorch CPU version..." && \
pip3 install torch torchvision torchaudio \
--index-url https://mirrors.aliyun.com/pypi/simple/ \
--trusted-host mirrors.aliyun.com || \
(echo "Aliyun failed, trying Tsinghua mirror..." && \
pip3 install torch torchvision torchaudio \
--index-url https://pypi.tuna.tsinghua.edu.cn/simple/ \
--trusted-host pypi.tuna.tsinghua.edu.cn) || \
(echo "Tsinghua failed, trying USTC mirror..." && \
pip3 install torch torchvision torchaudio \
--index-url https://mirrors.ustc.edu.cn/pypi/web/simple/ \
--trusted-host mirrors.ustc.edu.cn) || \
(echo "All mirrors failed, trying official PyTorch CPU repo..." && \
pip3 install torch torchvision torchaudio \
--index-url https://download.pytorch.org/whl/cpu) && \
echo "Installing other requirements with uv..." && \
uv pip install --system -r requirements.txt \
--index-url https://mirrors.aliyun.com/pypi/simple/ && \
if [ "$USE_SLIM" != "true" ]; then \
echo "Downloading models..." && \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])" && \
python -c "import os; import tiktoken; tiktoken.get_encoding(os.environ['TIKTOKEN_ENCODING_NAME'])"; \
fi; \
fi && \
pip3 install torch torchvision torchaudio --index-url https://download.pytorch.org/whl/cpu --no-cache-dir && \
uv pip install --system -r requirements.txt --no-cache-dir && \
if [ "$USE_SLIM" != "true" ]; then \
python -c "import os; from sentence_transformers import SentenceTransformer; SentenceTransformer(os.environ['RAG_EMBEDDING_MODEL'], device='cpu')" && \
python -c "import os; from faster_whisper import WhisperModel; WhisperModel(os.environ['WHISPER_MODEL'], device='cpu', compute_type='int8', download_root=os.environ['WHISPER_MODEL_DIR'])"; \
python -c "import os; import tiktoken; tiktoken.get_encoding(os.environ['TIKTOKEN_ENCODING_NAME'])"; \
fi; \
fi; \
mkdir -p /app/backend/data && chown -R $UID:$GID /app/backend/data/ && \
echo "==================================" && \
echo "Python dependencies installed" && \
echo "Time: $(date)" && \
echo "=================================="
rm -rf /var/lib/apt/lists/*;
# ========== 安装 Ollama ==========
# Install Ollama if requested
RUN if [ "$USE_OLLAMA" = "true" ]; then \
date +%s > /tmp/ollama_build_hash && \
echo "Installing Ollama..." && \
export HF_ENDPOINT=https://hf-mirror.com && \
curl -fsSL https://ollama.com/install.sh | sh || \
(echo "Ollama installation failed, trying with proxy..." && \
export http_proxy=http://host.docker.internal:7897 && \
export https_proxy=http://host.docker.internal:7897 && \
curl -fsSL https://ollama.com/install.sh | sh); \
echo "Cache broken at timestamp: `cat /tmp/ollama_build_hash`" && \
curl -fsSL https://ollama.com/install.sh | sh && \
rm -rf /var/lib/apt/lists/*; \
fi
# ========== 复制构建文件 ==========
# copy embedding weight from build
# RUN mkdir -p /root/.cache/chroma/onnx_models/all-MiniLM-L6-v2
# COPY --from=build /app/onnx /root/.cache/chroma/onnx_models/all-MiniLM-L6-v2/onnx
# copy built frontend files
COPY --chown=$UID:$GID --from=build /app/build /app/build
COPY --chown=$UID:$GID --from=build /app/CHANGELOG.md /app/CHANGELOG.md
COPY --chown=$UID:$GID --from=build /app/package.json /app/package.json
# copy backend files
COPY --chown=$UID:$GID ./backend .
EXPOSE 8080
HEALTHCHECK CMD curl --silent --fail http://localhost:${PORT:-8080}/health | jq -ne 'input.status == true' || exit 1
# ========== 权限加固 ==========
# Minimal, atomic permission hardening for OpenShift (arbitrary UID):
# - Group 0 owns /app and /root
# - Directories are group-writable and have SGID so new files inherit GID 0
RUN if [ "$USE_PERMISSION_HARDENING" = "true" ]; then \
set -eux; \
chgrp -R 0 /app /root || true; \
@ -272,4 +188,4 @@ ARG BUILD_HASH
ENV WEBUI_BUILD_VERSION=${BUILD_HASH}
ENV DOCKER=true
CMD [ "bash", "start.sh"]
CMD [ "bash", "start.sh"]

168
Jenkinsfile vendored
View file

@ -1,168 +0,0 @@
pipeline {
agent any
environment {
REPO_URL = 'git@github.com:ai-friend-coming/open-webui-next.git'
IMAGE_NAME = 'open-webui-custom'
IMAGE_TAG = "${BUILD_NUMBER}"
OUTPUT_DIR = '/var/docker-images'
DOCKER_FILE_PATH = 'Dockerfile'
}
options {
buildDiscarder(logRotator(numToKeepStr: '10'))
timeout(time: 1, unit: 'HOURS')
timestamps()
}
stages {
stage('准备工作') {
steps {
script {
echo "========================================="
echo "开始构建 Build #${BUILD_NUMBER}"
echo "仓库: ${REPO_URL}"
echo "镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
echo "========================================="
// 检查Docker是否可用
sh 'docker --version'
sh 'docker info'
}
}
}
stage('检出代码') {
steps {
script {
echo "从 ${REPO_URL} 检出代码..."
}
// 使用更简单的checkout方式
checkout([
$class: 'GitSCM',
branches: [[name: '*/main']],
userRemoteConfigs: [[
url: "${REPO_URL}",
credentialsId: 'github-ssh' // 改成你实际创建的凭据ID
]]
])
script {
echo "代码检出完成"
sh 'ls -la'
sh 'git log --oneline -1 || echo "无法获取git日志"'
}
}
}
stage('验证 Dockerfile') {
steps {
script {
echo "检查 Dockerfile..."
sh """
if [ ! -f "${DOCKER_FILE_PATH}" ]; then
echo "错误: 找不到 Dockerfile: ${DOCKER_FILE_PATH}"
echo "当前目录内容:"
ls -la
exit 1
fi
echo "Dockerfile 存在"
echo "--- Dockerfile 内容 (前20行) ---"
head -20 "${DOCKER_FILE_PATH}"
"""
}
}
}
stage('创建输出目录') {
steps {
script {
echo "创建输出目录: ${OUTPUT_DIR}"
sh """
sudo mkdir -p ${OUTPUT_DIR}
sudo chmod 777 ${OUTPUT_DIR}
ls -ld ${OUTPUT_DIR}
"""
}
}
}
stage('构建 Docker 镜像') {
steps {
script {
echo "开始构建镜像: ${IMAGE_NAME}:${IMAGE_TAG}"
sh """
docker build \
-t ${IMAGE_NAME}:${IMAGE_TAG} \
-t ${IMAGE_NAME}:latest \
-f ${DOCKER_FILE_PATH} \
.
echo "镜像构建完成"
docker images | grep ${IMAGE_NAME} || echo "未找到镜像"
"""
}
}
}
stage('导出镜像') {
steps {
script {
echo "导出镜像到 ${OUTPUT_DIR}"
sh """
echo "导出 ${IMAGE_NAME}:${IMAGE_TAG}..."
docker save ${IMAGE_NAME}:${IMAGE_TAG} | gzip > ${OUTPUT_DIR}/${IMAGE_NAME}-${IMAGE_TAG}.tar.gz
echo "导出 ${IMAGE_NAME}:latest..."
docker save ${IMAGE_NAME}:latest | gzip > ${OUTPUT_DIR}/${IMAGE_NAME}-latest.tar.gz
echo "导出完成"
ls -lh ${OUTPUT_DIR}/${IMAGE_NAME}*.tar.gz
"""
}
}
}
stage('清理旧镜像') {
steps {
script {
echo "清理本地镜像..."
sh """
docker rmi ${IMAGE_NAME}:${IMAGE_TAG} 2>/dev/null || echo "镜像已删除或不存在"
# 保留latest标签方便下次使用
# docker rmi ${IMAGE_NAME}:latest 2>/dev/null || true
# 清理悬空镜像
docker image prune -f --filter "dangling=true" || true
echo "清理完成"
"""
}
}
}
}
post {
success {
script {
echo "========================================="
echo "✅ 构建成功!"
echo "镜像文件位置: ${OUTPUT_DIR}"
sh "ls -lh ${OUTPUT_DIR}/${IMAGE_NAME}*.tar.gz || true"
echo "========================================="
}
}
failure {
echo "❌ 构建失败,请检查上方日志"
}
always {
script {
echo "流水线执行完成"
// 可选:清理工作空间(注释掉以便调试)
// cleanWs()
}
}
}
}

View file

@ -1,291 +0,0 @@
# Open WebUI 本地开发环境搭建指南
本指南提供 Open WebUI 项目的本地开发环境配置和运行步骤。
## 系统要求
- **Node.js**: v20.19.5 或更高版本
- **Python**: 3.12.x (推荐使用 pyenv 管理)
- **npm**: 10.8.2 或更高版本
- **操作系统**: macOS / Linux / Windows
## 技术栈
### 前端
- **框架**: SvelteKit 4 + TypeScript
- **构建工具**: Vite 5
- **样式**: Tailwind CSS 4
### 后端
- **语言**: Python 3.12
- **框架**: FastAPI
- **数据库**: SQLite (开发环境) / PostgreSQL (生产环境)
- **ORM**: SQLAlchemy + Peewee
## 环境准备
### 1. 安装 pyenv (如果系统 Python 版本不是 3.12)
```bash
# macOS (使用 Homebrew)
brew install pyenv
# 配置 shell 环境变量 (添加到 ~/.zshrc 或 ~/.bash_profile)
export PATH="$HOME/.pyenv/bin:$PATH"
eval "$(pyenv init -)"
```
### 2. 安装 Python 3.12
```bash
# 使用 pyenv 安装 Python 3.12
pyenv install 3.12
# 验证安装
pyenv versions
```
## 安装依赖
### 前端依赖
```bash
# 在项目根目录执行
npm install --legacy-peer-deps
```
**注意**: 需要使用 `--legacy-peer-deps` 标志来解决 @tiptap 包的版本冲突问题。
### 后端依赖
```bash
# 进入后端目录
cd backend
# 创建 Python 3.12 虚拟环境
/Users/你的用户名/.pyenv/versions/3.12.12/bin/python3 -m venv venv
# 或者,如果系统 Python 已是 3.12
python3 -m venv venv
# 激活虚拟环境
source venv/bin/activate # macOS/Linux
# 或
venv\Scripts\activate # Windows
# 升级 pip
pip install --upgrade pip
# 安装依赖
pip install -r requirements.txt
```
## 运行开发服务器
### 启动后端服务 (端口 8080)
```bash
# 在 backend 目录下,激活虚拟环境后
cd backend
source venv/bin/activate
python -m uvicorn open_webui.main:app --reload --port 8080 --host 0.0.0.0
```
后端服务将运行在: **http://localhost:8080**
后端启动时会自动:
- 运行数据库迁移 (Alembic)
- 初始化 SQLite 数据库
- 配置向量数据库 (ChromaDB)
### 启动前端服务 (端口 5050)
```bash
# 在项目根目录
npm run dev:5050
```
前端服务将运行在: **http://localhost:5050**
首次启动时会自动:
- 下载 Pyodide 包 (浏览器内 Python 运行时)
- 预加载常用 Python 包 (numpy, pandas, matplotlib 等)
## 访问应用
打开浏览器访问: **http://localhost:5050**
前端会通过 Vite 代理将 API 请求转发到后端 (8080 端口)。
## 开发工作流
### 目录结构
```
open-webui-next/
├── src/ # 前端源码
│ ├── routes/ # SvelteKit 路由
│ ├── lib/
│ │ ├── apis/ # API 客户端
│ │ ├── components/ # Svelte 组件
│ │ ├── stores/ # 全局状态管理
│ │ └── i18n/ # 国际化
├── backend/ # 后端源码
│ ├── open_webui/
│ │ ├── main.py # FastAPI 入口
│ │ ├── routers/ # API 路由
│ │ ├── models/ # 数据模型
│ │ ├── utils/ # 工具函数
│ │ └── migrations/ # 数据库迁移
│ ├── requirements.txt
│ └── venv/ # Python 虚拟环境
└── package.json
```
### 常用开发命令
#### 前端
```bash
npm run dev # 启动开发服务器 (默认端口 5173)
npm run dev:5050 # 启动开发服务器 (端口 5050)
npm run build # 构建生产版本
npm run lint # 代码检查
npm run format # 代码格式化
npm run test:frontend # 运行单元测试
npm run i18n:parse # 解析并更新翻译文件
```
#### 后端
```bash
# 在 backend 目录下,激活虚拟环境后
# 启动开发服务器 (自动重载)
python -m uvicorn open_webui.main:app --reload --port 8080
# 代码格式化
black .
# 数据库迁移
cd backend
alembic revision --autogenerate -m "描述" # 生成迁移脚本
alembic upgrade head # 执行迁移
```
### 热重载
- **前端**: Vite 自动检测文件变化并热重载
- **后端**: uvicorn 的 `--reload` 参数自动检测 Python 代码变化并重启
## 常见问题
### 1. npm install 失败
**问题**: 依赖版本冲突
**解决方案**:
```bash
npm install --legacy-peer-deps
```
### 2. 后端 Python 版本不兼容
**问题**: `unstructured` 包不支持 Python 3.13+
**解决方案**: 使用 Python 3.12:
```bash
pyenv install 3.12
cd backend
rm -rf venv
/Users/你的用户名/.pyenv/versions/3.12.12/bin/python3 -m venv venv
source venv/bin/activate
pip install -r requirements.txt
```
### 3. 端口被占用
**问题**: 8080 或 5050 端口已被使用
**解决方案**:
```bash
# 查找占用端口的进程
lsof -i :8080
lsof -i :5050
# 终止进程
kill -9 <PID>
# 或者使用不同端口
# 前端:
npm run dev -- --port 3000
# 后端:
python -m uvicorn open_webui.main:app --reload --port 8000
```
### 4. 前端 Pyodide 下载慢
**问题**: 首次启动下载 Pyodide 包较慢
**解决方案**: 耐心等待,包会缓存在 `node_modules` 中,后续启动会很快。
### 5. 数据库迁移错误
**问题**: Alembic 迁移失败
**解决方案**:
```bash
# 删除数据库重新初始化 (仅开发环境)
rm backend/data/webui.db
python -m uvicorn open_webui.main:app --reload --port 8080
```
## 环境变量配置
后端可通过环境变量配置,创建 `backend/.env` 文件:
```bash
# 数据库
DATABASE_URL=sqlite:///data/webui.db
# 向量数据库
VECTOR_DB=chroma
EMBEDDING_MODEL=sentence-transformers/all-MiniLM-L6-v2
# CORS (开发环境)
CORS_ALLOW_ORIGIN=*
# 日志级别
LOG_LEVEL=INFO
```
## 生产部署
生产环境使用 Docker 部署,详见项目根目录的 `Dockerfile``docker-compose.yaml`
```bash
# 构建镜像
docker build -t open-webui .
# 运行容器
docker run -d -p 8080:8080 -v open-webui:/app/backend/data open-webui
```
## 更多资源
- **项目文档**: [CLAUDE.md](./CLAUDE.md)
- **API 文档**: http://localhost:8080/docs (启动后端后访问)
- **官方仓库**: https://github.com/open-webui/open-webui
## 贡献指南
1. Fork 项目
2. 创建功能分支 (`git checkout -b feature/AmazingFeature`)
3. 提交更改 (`git commit -m 'Add some AmazingFeature'`)
4. 推送到分支 (`git push origin feature/AmazingFeature`)
5. 创建 Pull Request
---
**最后更新**: 2025-11-08

View file

@ -1,88 +1,36 @@
# 本地开发故障排除
# Open WebUI Troubleshooting Guide
## 问题: "Open WebUI 需要后端服务" 错误
## Understanding the Open WebUI Architecture
### 🔧 快速解决方案
The Open WebUI system is designed to streamline interactions between the client (your browser) and the Ollama API. At the heart of this design is a backend reverse proxy, enhancing security and resolving CORS issues.
**请在浏览器中进行硬刷新:**
- **How it Works**: The Open WebUI is designed to interact with the Ollama API through a specific route. When a request is made from the WebUI to Ollama, it is not directly sent to the Ollama API. Initially, the request is sent to the Open WebUI backend via `/ollama` route. From there, the backend is responsible for forwarding the request to the Ollama API. This forwarding is accomplished by using the route specified in the `OLLAMA_BASE_URL` environment variable. Therefore, a request made to `/ollama` in the WebUI is effectively the same as making a request to `OLLAMA_BASE_URL` in the backend. For instance, a request to `/ollama/api/tags` in the WebUI is equivalent to `OLLAMA_BASE_URL/api/tags` in the backend.
- **macOS**: `Cmd + Shift + R`
- **Windows/Linux**: `Ctrl + Shift + R`
- **Security Benefits**: This design prevents direct exposure of the Ollama API to the frontend, safeguarding against potential CORS (Cross-Origin Resource Sharing) issues and unauthorized access. Requiring authentication to access the Ollama API further enhances this security layer.
然后检查是否解决问题。
## Open WebUI: Server Connection Error
### 📋 详细排查步骤
If you're experiencing connection issues, its often due to the WebUI docker container not being able to reach the Ollama server at 127.0.0.1:11434 (host.docker.internal:11434) inside the container . Use the `--network=host` flag in your docker command to resolve this. Note that the port changes from 3000 to 8080, resulting in the link: `http://localhost:8080`.
#### 1. 打开浏览器开发者工具
- **macOS**: `Cmd + Option + I`
- **Windows/Linux**: `F12`
#### 2. 检查 Console (控制台)
查找是否有错误消息,特别是:
- 红色的错误信息
- 网络请求失败
- CORS 相关错误
#### 3. 检查 Network (网络) 标签
1. 切换到 Network 标签
2. 刷新页面
3. 查找对 `http://localhost:8080/api/config` 的请求
4. 如果找到,点击查看:
- **Status** 应该是 `200`
- **Response** 应该包含 JSON 配置
#### 4. 清除本地存储
1. 在开发者工具中,转到 **Application** 标签
2. 左侧找到 **Local Storage**
3. 展开并点击 `http://localhost:5050`
4. 点击右键 → **Clear**
5. 刷新页面
### ✅ 验证服务状态
在终端运行:
**Example Docker Command**:
```bash
# 测试后端 API
curl http://localhost:8080/api/config
# 检查端口占用
lsof -i :8080 -i :5050 | grep LISTEN
docker run -d --network=host -v open-webui:/app/backend/data -e OLLAMA_BASE_URL=http://127.0.0.1:11434 --name open-webui --restart always ghcr.io/open-webui/open-webui:main
```
如果 curl 命令返回 JSON 配置,说明后端正常运行。
### Error on Slow Responses for Ollama
### 🔄 重启服务 (如果需要)
Open WebUI has a default timeout of 5 minutes for Ollama to finish generating the response. If needed, this can be adjusted via the environment variable AIOHTTP_CLIENT_TIMEOUT, which sets the timeout in seconds.
如果上述方法无效,停止当前服务 (`Ctrl + C`) 并重新启动:
### General Connection Errors
**后端:**
```bash
cd backend
source venv/bin/activate
python -m uvicorn open_webui.main:app --reload --port 8080 --host 0.0.0.0
```
**Ensure Ollama Version is Up-to-Date**: Always start by checking that you have the latest version of Ollama. Visit [Ollama's official site](https://ollama.com/) for the latest updates.
**前端:**
```bash
npm run dev:5050
```
**Troubleshooting Steps**:
### 🌐 尝试不同端口
1. **Verify Ollama URL Format**:
- When running the Web UI container, ensure the `OLLAMA_BASE_URL` is correctly set. (e.g., `http://192.168.1.1:11434` for different host setups).
- In the Open WebUI, navigate to "Settings" > "General".
- Confirm that the Ollama Server URL is correctly set to `[OLLAMA URL]` (e.g., `http://localhost:11434`).
如果端口冲突,可以使用不同端口:
**前端:**
```bash
npm run dev -- --port 3000
```
然后访问 `http://localhost:3000`
---
**还有问题?** 查看 `/Users/sylar/my_ws/open-webui-next/LOCAL_SETUP.md` 获取完整设置指南。
By following these enhanced troubleshooting steps, connection issues should be effectively resolved. For further assistance or queries, feel free to reach out to us on our community Discord.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

View file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

@ -0,0 +1,21 @@
{
"name": "Open WebUI",
"short_name": "WebUI",
"icons": [
{
"src": "/static/web-app-manifest-192x192.png",
"sizes": "192x192",
"type": "image/png",
"purpose": "maskable"
},
{
"src": "/static/web-app-manifest-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "maskable"
}
],
"theme_color": "#ffffff",
"background_color": "#ffffff",
"display": "standalone"
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.1 KiB

View file

@ -0,0 +1 @@
Name,Email,Password,Role
1 Name Email Password Role

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

646
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -141,7 +141,6 @@
"vega-lite": "^6.4.1",
"vite-plugin-static-copy": "^2.2.0",
"y-prosemirror": "^1.3.7",
"y-protocols": "^1.0.6",
"yaml": "^2.7.1",
"yjs": "^13.6.27"
},