Linux(centos7)安裝 docker + ollama+ deepseek-r1:7b + Open WebUI(內含一鍵安裝腳本)

windows版本的 ollama :https://blog.csdn.net/YXWik/article/details/143871588
環境:centos7
在這里插入圖片描述

文中各個腳本
1.docker安裝 或者 需要重新安裝: install_docker.sh
2.docker已安裝只需要安裝 ollama+ deepseek-r1:7b + Open WebUI : install_ollama.sh
3.空環境需要安裝docker + ollama+ deepseek-r1:7b + Open WebUI :
install_docker.sh install_ollama.sh (這兩個腳本放同一目錄下運行install_ollama.sh 即可)
4. Python版安裝Open WebUI(此腳本半成品,需自行修復,與centos7這個環境兼容太差了):install_open_webui.sh腳本

ollama

ollama是一個簡明易用的本地大模型運行框架,只需一條命令即可在本地跑大模型。開源項目,專注于開發和部署先進的大型語言模型(LLM)
官網: https://ollama.com/ 下載地址:https://ollama.com/download/linux
在這里插入圖片描述
不著急執行,繼續閱讀文章,后面一鍵安裝腳本

curl -fsSL https://ollama.com/install.sh | sh

在這里插入圖片描述
在這里插入圖片描述

ollama --version

在這里插入圖片描述
Ollama 的官方二進制文件是使用較新的 glibcGCC 編譯的,它要求:

glibc >= 2.27
libstdc++ >= 4.8.5(最好 GCC 9+)
系統 glibclibstdc++ 版本太舊,需要更新
系統又安裝一些其他程序無法升級,只升級這兩個依賴又害怕搞出兼容性的問題
更新半天費勁巴拉的放棄了,采用docker安裝得了
以下是一個完整的 Bash 腳本,用于在 CentOS 7 系統上:

  1. 檢測是否安裝 Docker

    未安裝:自動安裝并啟動 Docker

  2. 檢查 Docker 是否運行

    未運行:啟動 Docker 服務

  3. 檢查是否已有 Ollama 容器

    有:嘗試啟動它(如果未運行)
    無:拉取并運行 Ollama 容器

注: 此腳本會更改服務器的下載源/etc/yum.repos.d 配置 會更改dockerdaemon.json 配置
腳本中 /home/ollama 掛載到容器內的 /root/.ollama,是用于持久化模型數據,如有需要自行更改路徑
ollama的腳本處理完后我就想著deepseek模型(想下載其他模型的也只需要更換腳本下載模型處的 deepseek-r1:7b 即可)和Open WebUI也放到腳本中自動安裝啟動,這之后就整理個一鍵安裝腳本得了,以下腳本為一鍵安裝腳本(經過多次優化已驗證無誤,安裝open webui巨慢,不想等或者不需要的可以裝完模型就結束)

install_ollama.sh

#!/bin/bashset -e# 日志函數
log_info() {echo -e "\033[1;32m[INFO] $1\033[0m"
}log_error() {echo -e "\033[1;31m[ERROR] $1\033[0m"
}# 檢查是否為 root
if [ "$EUID" -ne 0 ]; thenlog_error "請以 root 權限運行此腳本"exit 1
fi# 安裝依賴
if ! command -v curl &> /dev/null; thenlog_info "📥 安裝 curl..."yum install -y curl || apt-get update && apt-get install -y curl
fi# 設置 Docker 鏡像加速器
log_info "?? 配置 Docker 鏡像加速器..."
cat > /etc/docker/daemon.json << 'EOF'
{"registry-mirrors": ["https://docker.m.daocloud.io","https://dockerproxy.com","https://docker.mirrors.ustc.edu.cn","https://docker.nju.edu.cn"]
}
EOF# 檢查 Docker 是否已安裝
if ! command -v docker &> /dev/null; thenlog_info "🔍 Docker 未安裝,正在調用 install_docker.sh 安裝..."if [ -f "./install_docker.sh" ]; thenchmod +x ./install_docker.sh./install_docker.shelselog_error "? 未找到 install_docker.sh 腳本,正在安裝采用其他方式安裝 Docker"curl -fsSL https://get.docker.com | shsystemctl enable docker --nowexit 1fi
elselog_info "? Docker 已安裝"
fi# 確保 Docker 正在運行
if ! systemctl is-active --quiet docker; thenlog_info "🔄 Docker 未運行,正在啟動..."systemctl start docker
fi# 創建 Ollama 數據目錄
DATA_DIR="/home/ollama"
if [ ! -d "$DATA_DIR" ]; thenlog_info "📁 創建 Ollama 數據目錄:$DATA_DIR"mkdir -p "$DATA_DIR"
fi# 檢查是否已存在 ollama 容器
if docker inspect ollama > /dev/null 2>&1; thenlog_info "🔄 檢測到已存在的 ollama 容器,正在停止并刪除..."docker stop ollama > /dev/nulldocker rm ollama > /dev/null
fi# 啟動 Ollama 容器
log_info "📦 啟動 Ollama 容器..."
docker run -d \--name ollama \-v "$DATA_DIR":/root/.ollama \-p 11434:11434 \-e OLLAMA_HOST=0.0.0.0 \--add-host=host.docker.internal:host-gateway \--restart always \ollama/ollama# 等待服務就緒
log_info "? 等待 Ollama 服務啟動..."
sleep 5# 檢查 API 是否可用
if curl -s http://localhost:11434/api/tags > /dev/null; thenlog_info "? Ollama 服務啟動成功"
elselog_error "? Ollama 服務啟動失敗,請檢查日志:docker logs ollama"exit 1
fi# 下載模型(可修改為你需要的模型)
MODEL_NAME="deepseek-r1:7b"
log_info "🧠 正在下載模型:$MODEL_NAME"
docker exec -it ollama ollama run $MODEL_NAME# 部署 Open WebUI(可選)
log_info "🌐 正在部署 Open WebUI..."
docker run -d \--name open-webui \-p 3000:8080 \--network=host \-e OLLAMA_API_URL=http://192.168.0.180:11434 \--add-host=host.docker.internal:host-gateway \-v open-webui:/app/backend/data \--restart always \ghcr.io/open-webui/open-webui:main# 提示完成
log_info "🎉 所有任務已完成!"
log_info "👉 Ollama 地址:http://<你的服務器IP>:11434"
log_info "👉 Open WebUI 地址:http://<你的服務器IP>:3000"
log_info "🧠 模型已下載完成:$MODEL_NAME"
log_info "📁 模型保存路徑:$DATA_DIR/models"

新建 install_ollama.sh 文件 將腳本內容保存,然后給文件賦予權限
在這里插入圖片描述
還需要一個安裝docker的腳本 install_docker.sh ,依舊是需要賦權,這個腳本單獨出來是為了避免服務器已經有docker,運行此腳本會進行重裝,只有服務器無docker才需要運行,如果服務器有docker但是無法安裝ollama的,也可以單獨運行此腳本進行重裝或者將腳本中的 Docker 源配置一下

install_docker.sh

#!/bin/bash# 刪除所有舊的 Docker 源文件
echo "正在刪除舊的 Docker 源文件..."
rm -f /etc/yum.repos.d/docker-*.repo# 清理 yum 緩存
yum clean all# 創建新的阿里云 Docker 源文件
echo "正在添加阿里云 Docker 源..."
cat > /etc/yum.repos.d/docker-ce.repo << 'EOF'
[docker-ce-stable]
name=Docker CE Stable - $basearch
baseurl=https://mirrors.aliyun.com/docker-ce/linux/centos/7/$basearch/stable
enabled=1
gpgcheck=1
gpgkey=https://mirrors.aliyun.com/docker-ce/linux/centos/gpg
EOF# 更新 yum 緩存
yum makecache# 安裝必要軟件包
echo "正在安裝依賴..."
yum install -y yum-utils device-mapper-persistent-data lvm2# 安裝 Docker CE
echo "正在安裝 Docker CE..."
yum install -y docker-ce docker-ce-cli containerd.io# 啟動 Docker 服務并設置開機自啟
echo "啟動 Docker 服務..."
systemctl start docker
systemctl enable docker# 驗證 Docker 是否安裝成功
docker --version
systemctl status dockerecho "Docker 安裝完成!"

兩個腳本準備好久可以進行一鍵安裝了
在這里插入圖片描述

啟動安裝ollama腳本

./install_ollama.sh

如果自己有docker但是運行腳本報錯如下:
在這里插入圖片描述
刪除所有 Docker 源文件,重新安裝docker 或者更改docker源(腳本中有)
運行 install_docker.sh
在這里插入圖片描述
在這里插入圖片描述

在這里插入圖片描述
docker處理完成后重新運行安裝ollama的腳本

./install_ollama.sh

如果報錯 :docker: Error response from daemon: Get "https://registry-1.docker.io/v2/": dial tcp 103.42.176.244:443: connect: connection refused.

仍然無法訪問 Docker Hub
在這里插入圖片描述
解決方案:重啟docker,因為我們的腳本中配置了docker下載源,但是需要重啟才可以生效

systemctl daemon-reload
systemctl restart docker

在這里插入圖片描述
再次運行 ./install_ollama.sh
在這里插入圖片描述
這里 ctrl+d 退出輸入(這里就可以進行對話聊天了,deepseek已經部署好了)

如果不需要Open WebUI的這里就已經私有化deepseek完成了

安裝Open WebUI

OLLAMA_BASE_URL更改為Ollama服務器的URL在進行啟動:

docker run -d   -p 3000:8080   -e OLLAMA_BASE_URL=http://192.168.0.180:11434   -v open-webui:/app/backend/data   --name open-webui   --restart always   ghcr.nju.edu.cn/open-webui/open-webui:main

要使用Nvidia GPU支持運行Open WebUI,請使用以下命令:

docker run -d -p 3000:8080 --gpus all --add-host=host.docker.internal:host-gateway --network=host -v open-webui:/app/backend/data --name open-webui --restart always  ghcr.nju.edu.cn/open-webui/open-webui:cuda

在這里插入圖片描述
這個也太慢太慢了,五個小時了都沒有裝完,這個網速被限制了嗎,還是外網下載的呢,還是就這么慢,官方給的這 docker下載地址太磨嘰了,我之前在windows上用Python裝過:https://blog.csdn.net/YXWik/article/details/143871588,也可以換這種方式進行安裝
在這里插入圖片描述
不想等了,終止了,搞一個基于python進行安裝Open WebUI的腳本(這個腳本更難搞,搞了好幾天,但是最終還是采用docker安裝好的)

install_open_webui.sh

記得給文件授權
在這里插入圖片描述
最終還是需要升級gcc版本
腳本:Python 3.11 + Open WebUI+自動檢測和修復 _ssl模塊 (腳本內含centos7的gcc版本等依賴的升級,生產環境慎重使用
腳本中安裝的openssl是3.4.1版本
腳本會替換CentOS 7鏡像源,生產環境需要注意
腳本中將啟動的端口該為了9000,需要變更的自行更改下
gcc鏡像地址:http://gnu.mirror.constant.com/gcc/
如果 ollama不在本機裝的,需要更改腳本中OLLAMA_API_URL的值

install_open_webui.sh (這個腳本是未完成版,修復腳本中途采用docker安裝成功了,如果無法使用docker的可以在此腳本基礎上進行修復調整)

#!/bin/bash
set -e# 日志函數
log_info() {echo -e "\033[1;32m[INFO] $1\033[0m" >&2
}log_error() {echo -e "\033[1;31m[ERROR] $1\033[0m" >&2
}log_warn() {echo -e "\033[1;33m[WARN] $1\033[0m" >&2
}# 帶重試的命令執行函數
retry_command() {local max_retries=$1shiftlocal command=("$@")local retry_delay=5for ((retry=1; retry<=max_retries; retry++)); doif "${command[@]}"; thenreturn 0fiif [ $retry -lt $max_retries ]; thenlog_info "命令執行失敗,$retry_delay 秒后重試(第 $retry/$max_retries 次)..."sleep $retry_delayretry_delay=$((retry_delay + 5))fidonelog_error "命令執行失敗,已達到最大重試次數"return 1
}# 帶重試的pip安裝函數
pip_install_with_retry() {local full_package=$1local max_retries=3local retry_delay=10local extra_args=${@:2}# 提取包名(去掉版本號部分)local package=$(echo "$full_package" | sed -E 's/[=<>~].*//')for ((retry=1; retry<=max_retries; retry++)); dolog_info "嘗試安裝 $full_package(第 $retry/$max_retries 次)"if $PIP_BIN install $extra_args $full_package; thenlog_info "$full_package 安裝成功"return 0fiif [ $retry -lt $max_retries ]; thenlog_info "安裝失敗,$retry_delay 秒后重試..."sleep $retry_delayretry_delay=$((retry_delay + 5))fidonelog_error "$full_package 安裝失敗,已達到最大重試次數"return 1
}# 版本比較函數(判斷版本1是否>=版本2)
version_ge() {[ "$(printf '%s\n' "$1" "$2" | sort -V | head -n1)" = "$2" ]
}# 檢測系統類型和包管理器
detect_system() {log_info "🔍 檢測系統類型..."if [ -f /etc/os-release ]; then. /etc/os-releaseOS=$NAMEVERSION=$VERSION_IDif [[ "$OS" == "CentOS Linux" ]]; thenOS="CentOS"fielif type lsb_release >/dev/null 2>&1; thenOS=$(lsb_release -si)VERSION=$(lsb_release -sr)elif [ -f /etc/lsb-release ]; then. /etc/lsb-releaseOS=$DISTRIB_IDVERSION=$DISTRIB_RELEASEelif [ -f /etc/debian_version ]; thenOS=DebianVERSION=$(cat /etc/debian_version)elif [ -f /etc/redhat-release ]; thenOS=$(cat /etc/redhat-release | cut -d' ' -f1)VERSION=$(cat /etc/redhat-release | grep -oE '[0-9]+\.[0-9]+' | head -1)elseOS=$(uname -s)VERSION=$(uname -r)fi# 檢測包管理器if command -v yum >/dev/null 2>&1; thenPACKAGE_MANAGER="yum"elif command -v dnf >/dev/null 2>&1; thenPACKAGE_MANAGER="dnf"elif command -v apt-get >/dev/null 2>&1; thenPACKAGE_MANAGER="apt-get"elif command -v zypper >/dev/null 2>&1; thenPACKAGE_MANAGER="zypper"elsePACKAGE_MANAGER="unknown"filog_info "檢測到系統: $OS $VERSION,包管理器: $PACKAGE_MANAGER"
}# 檢測OpenSSL版本
check_openssl_version() {log_info "🔍 檢測OpenSSL版本(要求>=3.0.0)..."# 檢查OpenSSL是否安裝if ! command -v openssl &>/dev/null; thenlog_info "未安裝OpenSSL,需要安裝3.0.0及以上版本"return 1fi# 獲取完整版本號(如3.1.4)local openssl_version=$(openssl version | awk '{print $2}')if [ -z "$openssl_version" ]; thenlog_warn "無法解析OpenSSL版本,視為不兼容"return 1fi# 提取主版本號local major_version=$(echo "$openssl_version" | cut -d'.' -f1)# 提取次版本號local minor_version=$(echo "$openssl_version" | cut -d'.' -f2)log_info "當前OpenSSL版本: $openssl_version(主版本: $major_version,次版本: $minor_version)"# 檢查是否>=3.0.0if [ "$major_version" -ge 3 ] && [ "$minor_version" -ge 0 ]; thenlog_info "? OpenSSL版本兼容(>=3.0.0)"return 0elselog_warn "? OpenSSL版本過低($openssl_version < 3.0.0),需要升級"return 1fi
}# 校驗FFmpeg版本是否兼容(必須>=3.1)
check_ffmpeg_compatibility() {log_info "🔍 校驗FFmpeg版本兼容性(要求>=3.1)..."# 檢查FFmpeg是否安裝if ! command -v ffmpeg &>/dev/null; thenlog_info "未安裝FFmpeg,需要安裝兼容版本"return 1fi# 獲取主版本號(如5.1.3 -> 5)local ffmpeg_version=$(/usr/bin/ffmpeg -version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | cut -d'.' -f1)if [ -z "$ffmpeg_version" ]; thenlog_warn "無法解析FFmpeg版本,視為不兼容"return 1filog_info "當前FFmpeg主版本號: $ffmpeg_version"# 檢查是否>=3if [ "$ffmpeg_version" -ge 3 ]; thenlog_info "? FFmpeg版本兼容(>=3.1)"return 0elselog_warn "? FFmpeg版本過低($ffmpeg_version < 3),需要升級"return 1fi
}# 檢測CMake版本(新增函數)
check_cmake_version() {local required_version="3.25"log_info "🔍 檢測CMake版本(要求>=${required_version})..."# 檢查CMake是否安裝if ! command -v cmake &>/dev/null; thenlog_info "未安裝CMake,需要安裝${required_version}及以上版本"return 1fi# 獲取完整版本號local cmake_version=$(cmake --version | head -n1 | awk '{print $3}')if [ -z "$cmake_version" ]; thenlog_warn "無法解析CMake版本,視為不兼容"return 1filog_info "當前CMake版本: $cmake_version"# 檢查是否>=required_versionif version_ge "$cmake_version" "$required_version"; thenlog_info "? CMake版本兼容(>=${required_version})"return 0elselog_warn "? CMake版本過低($cmake_version < ${required_version}),需要升級"return 1fi
}# 卸載舊版FFmpeg(清理環境)
uninstall_old_ffmpeg() {log_info "🧹 卸載舊版FFmpeg..."# 根據包管理器卸載if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER remove -y ffmpeg ffmpeg-devel >/dev/null 2>&1 || trueelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get remove -y ffmpeg libavcodec-dev libavformat-dev >/dev/null 2>&1 || trueelif [ "$PACKAGE_MANAGER" = "zypper" ]; thenzypper remove -y ffmpeg ffmpeg-devel >/dev/null 2>&1 || truefi# 清理殘留文件(關鍵步驟)rm -rf /usr/bin/ffmpeg /usr/lib64/libav* /usr/include/libav* \/usr/local/bin/ffmpeg /usr/local/lib/libav* /usr/local/include/libav*# 刷新動態鏈接庫緩存ldconfig 2>/dev/nulllog_info "舊版FFmpeg清理完成"
}# 升級CMake(新增函數)
upgrade_cmake() {local required_version="3.25"local install_version="3.26.4"log_info "🔧 開始安裝CMake ${install_version}(要求>=${required_version})..."# 卸載舊版本if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER remove -y cmake >/dev/null 2>&1 || trueelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get remove -y cmake >/dev/null 2>&1 || trueelif [ "$PACKAGE_MANAGER" = "zypper" ]; thenzypper remove -y cmake >/dev/null 2>&1 || truefi# 安裝編譯依賴log_info "安裝CMake編譯依賴..."if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER install -y gcc-c++ make openssl-develelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get install -y g++ make libssl-develif [ "$PACKAGE_MANAGER" = "zypper" ]; thenzypper install -y gcc-c++ make libopenssl-develfi# 檢測系統架構local arch=$(uname -m)case $arch inx86_64) local cmake_arch="x86_64" ;;aarch64) local cmake_arch="aarch64" ;;*) log_error "不支持的架構: $arch"exit 1;;esac# 下載并安裝新版本local temp_dir=$(mktemp -d)cd "$temp_dir" || {log_error "無法進入臨時目錄"exit 1}local cmake_tar="cmake-3.26.4.tar.gz"local cmake_url="https://cmake.org/files/v3.26/cmake-3.26.4.tar.gz"local backup_url="https://github.com/Kitware/CMake/releases/download/v3.26.4/cmake-3.26.4.tar.gz"log_info "下載CMake ${install_version}..."if ! retry_command 2 wget --no-check-certificate "$cmake_url"; thenlog_warn "主鏈接下載失敗,嘗試備用鏈接..."if ! retry_command 2 wget --no-check-certificate "$backup_url"; thenlog_error "所有鏈接下載CMake失敗"cd .. && rm -rf "$temp_dir"exit 1fifi# 驗證文件是否存在if [ ! -f "$cmake_tar" ]; thenlog_error "CMake安裝包下載失敗,文件不存在"cd .. && rm -rf "$temp_dir"exit 1fi# 解壓源碼包log_info "解壓CMake安裝包..."if ! tar xzf "$cmake_tar"; thenlog_error "CMake安裝包解壓失敗"cd .. && rm -rf "$temp_dir"exit 1fi# 進入源碼目錄cd "cmake-3.26.4" || {log_error "找不到CMake源碼目錄"cd .. && rm -rf "$temp_dir"exit 1}# 配置編譯選項log_info "配置CMake編譯選項..."./bootstrap --prefix=/opt/cmake || {log_error "CMake配置失敗"cd ../.. && rm -rf "$temp_dir"exit 1}# 編譯(根據CPU核心數調整線程數)local cpu_cores=$(nproc)local make_jobs=$(( cpu_cores > 4 ? 4 : cpu_cores ))log_info "使用 $make_jobs 線程編譯CMake..."make -j$make_jobs || {log_error "CMake編譯失敗"cd ../.. && rm -rf "$temp_dir"exit 1}# 安裝log_info "安裝CMake..."make install || {log_error "CMake安裝失敗"cd ../.. && rm -rf "$temp_dir"exit 1}# 配置鏈接rm -f /usr/bin/cmake /usr/local/bin/cmakeln -sf /opt/cmake/bin/cmake /usr/bin/cmakeln -sf /opt/cmake/bin/cmake /usr/local/bin/cmake# 清理臨時文件cd ../.. && rm -rf "$temp_dir"# 驗證安裝if ! command -v cmake &> /dev/null; thenlog_error "CMake安裝失敗,無法找到可執行文件"exit 1fi# 再次檢查版本if check_cmake_version; thenlog_info "? CMake升級成功"return 0elselog_error "CMake升級后仍不滿足版本要求"exit 1fi
}# FFmpeg安裝函數(修復OpenSSL識別問題)
install_compatible_ffmpeg() {log_info "🔧 安裝兼容版本FFmpeg 5.1.3(與av包兼容)..."# 檢測OpenSSL是lib還是lib64目錄if [ -d "$OPENSSL_DIR/lib64" ]; thenOPENSSL_LIB_DIR="$OPENSSL_DIR/lib64"elseOPENSSL_LIB_DIR="$OPENSSL_DIR/lib"fi# 預檢查OpenSSL是否被正確識別log_info "預檢查OpenSSL配置..."if ! pkg-config --exists openssl; thenlog_error "pkg-config仍然無法檢測到OpenSSL"log_error "請檢查$OPENSSL_LIB_DIR/pkgconfig/openssl.pc是否存在"exit 1filocal openssl_version=$(pkg-config --modversion openssl)log_info "pkg-config報告的OpenSSL版本: $openssl_version"# 檢查主版本是否>=3local major_version=$(echo "$openssl_version" | cut -d'.' -f1)if [ "$major_version" -lt 3 ]; thenlog_error "pkg-config報告的OpenSSL版本仍然低于3.0.0"exit 1filocal ffmpeg_version="5.1.3"local ffmpeg_tar="ffmpeg-${ffmpeg_version}.tar.bz2"local install_prefix="/usr/local/ffmpeg"# 安裝編譯依賴log_info "安裝FFmpeg編譯依賴..."if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER install -y yasm nasm make cmake zlib-devel wget# 徹底卸載系統默認的openssl相關包$PACKAGE_MANAGER remove -y openssl openssl-develelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get install -y yasm nasm make cmake zlib1g-dev wgetapt-get remove -y openssl libssl-develif [ "$PACKAGE_MANAGER" = "zypper" ]; thenzypper install -y yasm nasm make cmake zlib-devel wgetzypper remove -y openssl openssl-develfi# 創建臨時編譯目錄local build_dir="/tmp/ffmpeg-build"rm -rf "$build_dir"mkdir -p "$build_dir"cd "$build_dir"# 下載源碼(多鏡像重試)local mirrors=("https://ffmpeg.org/releases/${ffmpeg_tar}""https://mirror.klaus-uwe.me/ffmpeg/releases/${ffmpeg_tar}""https://ftp.vim.org/ftp/ffmpeg/releases/${ffmpeg_tar}")local download_success=0for mirror in "${mirrors[@]}"; dolog_info "嘗試從鏡像下載FFmpeg ${ffmpeg_version}$mirror"if retry_command 2 wget --no-check-certificate "$mirror"; thenlog_info "? 從鏡像下載成功"download_success=1breakfidoneif [ $download_success -eq 0 ]; thenlog_error "所有鏡像下載FFmpeg失敗"exit 1fi# 解壓源碼log_info "解壓FFmpeg源碼..."if ! tar xjf "$ffmpeg_tar"; thenlog_error "源碼解壓失敗,文件可能損壞"exit 1ficd "ffmpeg-${ffmpeg_version}"# 清理之前的配置緩存make distclean 2>/dev/null || true# 配置編譯選項log_info "配置FFmpeg編譯選項,強制使用OpenSSL $OPENSSL_DIR..."# 顯式設置所有必要的環境變量,使用正確的lib目錄export PKG_CONFIG_PATH="$OPENSSL_LIB_DIR/pkgconfig"export CFLAGS="-I$OPENSSL_DIR/include"export CPPFLAGS="-I$OPENSSL_DIR/include"export LDFLAGS="-L$OPENSSL_LIB_DIR -Wl,-rpath,$OPENSSL_LIB_DIR"export LIBS="-ldl"./configure \--prefix="$install_prefix" \--enable-shared \--enable-gpl \--enable-version3 \--enable-openssl \--disable-static \--enable-pic \--extra-cflags="-I$OPENSSL_DIR/include" \--extra-ldflags="-L$OPENSSL_LIB_DIR -Wl,-rpath,$OPENSSL_LIB_DIR" \--extra-libs="-ldl"# 編譯(根據CPU核心數調整線程數)local cpu_cores=$(nproc)local make_jobs=$(( cpu_cores > 4 ? 4 : cpu_cores ))log_info "使用 $make_jobs 線程編譯FFmpeg(耗時較長,請耐心等待)..."if ! make -j$make_jobs; thenlog_error "多線程編譯失敗,嘗試單線程編譯..."if ! make -j1; thenlog_error "FFmpeg編譯徹底失敗"exit 1fifi# 安裝log_info "安裝FFmpeg..."make install# 配置系統識別新FFmpeglog_info "配置FFmpeg環境變量..."# 1. 添加動態鏈接庫路徑echo "$install_prefix/lib" > /etc/ld.so.conf.d/ffmpeg.confldconfig  # 刷新緩存# 2. 創建軟鏈接到系統路徑(確保能被找到)ln -sf "$install_prefix/bin/ffmpeg" /usr/bin/ffmpegln -sf "$install_prefix/bin/ffprobe" /usr/bin/ffprobe# 3. 配置pkg-config路徑(av包編譯需要)ln -sf "$install_prefix/lib/pkgconfig"/* /usr/lib64/pkgconfig/ 2>/dev/nullln -sf "$install_prefix/lib/pkgconfig"/* /usr/lib/pkgconfig/ 2>/dev/null# 驗證安裝結果local installed_version=$(ffmpeg -version | head -n1 | grep -oE '[0-9]+\.[0-9]+\.[0-9]+')if [ "$installed_version" = "$ffmpeg_version" ]; thenlog_info "? FFmpeg $ffmpeg_version 安裝成功"elselog_error "FFmpeg安裝版本不符(實際: $installed_version,預期: $ffmpeg_version)"exit 1fi
}# 安裝并驗證FFmpeg(整合校驗、卸載舊版、安裝新版)
setup_compatible_ffmpeg() {log_info "🎥 開始FFmpeg環境配置..."# 先校驗是否兼容if check_ffmpeg_compatibility; thenreturn 0fi# 不兼容則卸載舊版uninstall_old_ffmpeg# 安裝兼容版本install_compatible_ffmpeg# 再次驗證check_ffmpeg_compatibility || {log_error "FFmpeg配置后仍不兼容,無法繼續安裝"exit 1}
}# 搜索可能的GCC路徑(優先高版本)
search_gcc_paths() {log_info "🔍 搜索可能的GCC路徑..."local possible_paths=("/usr/local/gcc-"*"/bin/gcc""/opt/rh/devtoolset-*/root/usr/bin/gcc""/usr/bin/gcc-"*"/usr/local/bin/gcc""/usr/bin/gcc""/usr/lib/gcc/"*"/"*"/bin/gcc""$HOME/.local/bin/gcc")for path in "${possible_paths[@]}"; doif [[ $path == *"*"* ]]; thenfor matched_path in $(echo $path 2>/dev/null | sort -Vr); doif [ -x "$matched_path" ]; thenlog_info "發現可執行的GCC: $matched_path"echo "$matched_path"return 0fidoneelseif [ -x "$path" ]; thenlog_info "發現可執行的GCC: $path"echo "$path"return 0fifidoneif command -v gcc >/dev/null 2>&1; thenlocal gcc_path=$(command -v gcc)log_info "通過環境變量發現GCC: $gcc_path"echo "$gcc_path"return 0filog_info "未發現GCC可執行文件"echo ""return 1
}# 解析GCC版本號
parse_gcc_version() {local gcc_path=$1if [ -z "$gcc_path" ] || [ ! -x "$gcc_path" ]; thenlog_error "無效的GCC路徑: $gcc_path"echo "0"return 1filog_info "解析GCC版本: $gcc_path"local version_output=$("$gcc_path" --version 2>/dev/null | head -n1)local version=$(echo "$version_output" | grep -oE '[0-9]+\.[0-9]+\.[0-9]+' | head -n1 | cut -d'.' -f1)if [ -z "$version" ] || ! [[ "$version" =~ ^[0-9]+$ ]]; thenlog_error "無法解析GCC版本,輸出: $version_output"echo "0"return 1filog_info "解析到GCC主版本號: $version"echo "$version"return 0
}# 檢查GCC版本并升級
check_and_upgrade_gcc() {local required_version=${1:-9}log_info "🔍 檢查GCC版本(要求: $required_version 及以上)..."export PATH=/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:$PATHlog_info "當前環境變量PATH: $PATH"local gcc_path=$(search_gcc_paths)local gcc_version=0if [ -n "$gcc_path" ]; thengcc_version=$(parse_gcc_version "$gcc_path")if ! [[ "$gcc_version" =~ ^[0-9]+$ ]]; thenlog_error "獲取的GCC版本不是有效整數: $gcc_version"gcc_version=0fifiif [ "$gcc_version" -ge "$required_version" ]; thenlog_info "? GCC版本滿足要求 ($gcc_version >= $required_version)"echo "$gcc_version" > /tmp/gcc_version.txtreturn 0elif [ "$gcc_version" -gt 0 ]; thenlog_info "? GCC版本過低 ($gcc_version < $required_version),需要升級"elselog_info "? 未安裝有效GCC,將進行安裝"fiinstall_gcc "$required_version"return $?
}# 安裝高版本GCC
install_gcc() {local required_version=$1log_info "🔧 開始安裝GCC $required_version 或更高版本..."case $OS in"CentOS"|"Red Hat"|"Oracle Linux")if install_gcc_rhel "$required_version"; thenreturn 0fi;;"Ubuntu"|"Debian")if install_gcc_debian "$required_version"; thenreturn 0fi;;"SUSE Linux"|"openSUSE")if install_gcc_suse "$required_version"; thenreturn 0fi;;*)log_warn "未識別的系統: $OS,嘗試通用安裝方法";;esacif install_gcc_from_source "$required_version"; thenreturn 0elselog_error "所有GCC安裝方式均失敗"return 1fi
}# RHEL系系統安裝GCC
install_gcc_rhel() {local required_version=$1log_info "嘗試在RHEL系系統安裝GCC $required_version..."if [ "$PACKAGE_MANAGER" = "yum" ]; thenyum remove -y gcc gcc-c++ >/dev/null 2>&1 || trueelsednf remove -y gcc gcc-c++ >/dev/null 2>&1 || truefiif [ "$required_version" -le 10 ]; thenlog_info "嘗試通過Software Collections安裝GCC $required_version..."if ! $PACKAGE_MANAGER install -y centos-release-scl-rh 2>/dev/null; thenlog_info "嘗試備選SCL倉庫..."if ! $PACKAGE_MANAGER install -y centos-release-scl 2>/dev/null; thenlog_warn "SCL倉庫安裝失敗,嘗試其他方法"elselocal scl_package="devtoolset-$required_version-gcc"if ! $PACKAGE_MANAGER install -y "$scl_package" "$scl_package-c++" "devtoolset-$required_version-binutils"; thenlog_warn "安裝devtoolset-$required_version失敗,嘗試更高版本"elsesource /opt/rh/devtoolset-$required_version/enableln -sf /opt/rh/devtoolset-$required_version/root/usr/bin/gcc /usr/local/bin/gccln -sf /opt/rh/devtoolset-$required_version/root/usr/bin/g++ /usr/local/bin/g++log_info "? 成功安裝GCC $required_version (SCL方式)"echo "$required_version" > /tmp/gcc_version.txtreturn 0fifififilog_info "嘗試通過默認倉庫安裝GCC..."if $PACKAGE_MANAGER install -y gcc gcc-c++; thenlocal new_version=$(parse_gcc_version "$(command -v gcc)")if [ -n "$new_version" ] && [ "$new_version" -ge "$required_version" ]; thenlog_info "? 成功安裝GCC $new_version (默認倉庫)"echo "$new_version" > /tmp/gcc_version.txtreturn 0elselog_warn "默認倉庫安裝的GCC版本不足,需要從源碼編譯"fielselog_warn "默認倉庫安裝GCC失敗"fireturn 1
}# Debian/Ubuntu系系統安裝GCC
install_gcc_debian() {local required_version=$1log_info "嘗試在Debian/Ubuntu系系統安裝GCC $required_version..."retry_command 3 apt-get update -yapt-get remove -y gcc gcc-c++ >/dev/null 2>&1 || truelocal gcc_package="gcc-$required_version"local gpp_package="g++-$required_version"if apt-get install -y "$gcc_package" "$gpp_package"; thenupdate-alternatives --install /usr/bin/gcc gcc /usr/bin/"$gcc_package" 100update-alternatives --install /usr/bin/g++ g++ /usr/bin/"$gpp_package" 100local new_version=$(parse_gcc_version "$(command -v gcc)")if [ -n "$new_version" ] && [ "$new_version" -ge "$required_version" ]; thenlog_info "? 成功安裝GCC $new_version (apt方式)"echo "$new_version" > /tmp/gcc_version.txtreturn 0fielselog_warn "安裝GCC $required_version 失敗,嘗試安裝默認版本"if apt-get install -y gcc g++; thenlocal new_version=$(parse_gcc_version "$(command -v gcc)")if [ -n "$new_version" ] && [ "$new_version" -ge "$required_version" ]; thenlog_info "? 成功安裝GCC $new_version (apt方式)"echo "$new_version" > /tmp/gcc_version.txtreturn 0elselog_warn "默認倉庫安裝的GCC版本不足,需要從源碼編譯"fielselog_warn "apt安裝GCC失敗"fifireturn 1
}# SUSE系系統安裝GCC
install_gcc_suse() {local required_version=$1log_info "嘗試在SUSE系系統安裝GCC $required_version..."if zypper install -y gcc-$required_version gcc-c++-$required_version; thenlocal new_version=$(parse_gcc_version "$(command -v gcc)")if [ -n "$new_version" ] && [ "$new_version" -ge "$required_version" ]; thenlog_info "? 成功安裝GCC $new_version (zypper方式)"echo "$new_version" > /tmp/gcc_version.txtreturn 0fielselog_warn "安裝GCC $required_version 失敗,嘗試安裝默認版本"if zypper install -y gcc gcc-c++; thenlocal new_version=$(parse_gcc_version "$(command -v gcc)")if [ -n "$new_version" ] && [ "$new_version" -ge "$required_version" ]; thenlog_info "? 成功安裝GCC $new_version (zypper方式)"echo "$new_version" > /tmp/gcc_version.txtreturn 0elselog_warn "默認倉庫安裝的GCC版本不足,需要從源碼編譯"fielselog_warn "zypper安裝GCC失敗"fifireturn 1
}# 從源碼編譯安裝GCC
install_gcc_from_source() {local required_version=$1local install_version="9.4.0"if [ "$required_version" -gt 9 ]; theninstall_version="10.5.0"fiif [ "$required_version" -gt 10 ]; theninstall_version="11.4.0"fiif [ "$required_version" -gt 11 ]; theninstall_version="12.3.0"filog_info "嘗試從源碼編譯安裝GCC ${install_version}..."log_info "安裝GCC編譯依賴..."case $OS in"CentOS"|"Red Hat"|"Oracle Linux")$PACKAGE_MANAGER install -y gmp-devel mpfr-devel libmpc-devel wget make lbzip2 bzip2 patch;;"Ubuntu"|"Debian")apt-get install -y libgmp-dev libmpfr-dev libmpc-dev wget make lbzip2 bzip2 patch;;"SUSE Linux"|"openSUSE")zypper install -y gmp-devel mpfr-devel libmpc-devel wget make lbzip2 bzip2 patch;;*)log_warn "未識別系統,嘗試安裝常見依賴"if command -v apt-get >/dev/null 2>&1; thenapt-get install -y libgmp-dev libmpfr-dev libmpc-dev wget make lbzip2 bzip2 patchelif command -v yum >/dev/null 2>&1; thenyum install -y gmp-devel mpfr-devel libmpc-devel wget make lbzip2 bzip2 patchfi;;esaclocal gcc_workdir="/tmp/gcc-build"local gcc_tar="gcc-${install_version}.tar.gz"local gcc_major_version=$(echo "$install_version" | cut -d'.' -f1)rm -rf "$gcc_workdir"mkdir -p "$gcc_workdir"cd "$gcc_workdir"# 下載GCC源碼local mirrors=("http://gnu.mirror.constant.com/gcc/gcc-${install_version}/${gcc_tar}""https://mirror.lzu.edu.cn/gnu/gcc/gcc-${install_version}/${gcc_tar}""https://mirrors.ustc.edu.cn/gnu/gcc/gcc-${install_version}/${gcc_tar}""https://ftp.gnu.org/gnu/gcc/gcc-${install_version}/${gcc_tar}")local download_success=0for mirror in "${mirrors[@]}"; dolog_info "嘗試從鏡像下載GCC ${install_version}$mirror"if retry_command 2 wget --no-check-certificate "$mirror"; thenlog_info "? 從鏡像下載成功"download_success=1breakfidoneif [ $download_success -eq 0 ]; thenlog_error "所有鏡像下載失敗"return 1filog_info "解壓GCC源碼..."tar xzf "$gcc_tar" || {log_error "源碼解壓失敗,文件可能損壞"return 1}cd "gcc-${install_version}"log_info "準備GCC依賴項..."if ! ./contrib/download_prerequisites; thenlog_error "自動下載依賴失敗,嘗試手動下載..."wget ftp://gcc.gnu.org/pub/gcc/infrastructure/gmp-6.1.0.tar.bz2 && tar xjf gmp-6.1.0.tar.bz2 && ln -sf gmp-6.1.0 gmpwget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpfr-3.1.4.tar.bz2 && tar xjf mpfr-3.1.4.tar.bz2 && ln -sf mpfr-3.1.4 mpfrwget ftp://gcc.gnu.org/pub/gcc/infrastructure/mpc-1.0.3.tar.gz && tar xzf mpc-1.0.3.tar.gz && ln -sf mpc-1.0.3 mpcwget ftp://gcc.gnu.org/pub/gcc/infrastructure/isl-0.18.tar.bz2 && tar xjf isl-0.18.tar.bz2 && ln -sf isl-0.18 islfimkdir -p buildcd buildlog_info "配置GCC編譯選項..."../configure --prefix=/usr/local/gcc-${install_version} \--enable-bootstrap \--enable-shared \--enable-threads=posix \--enable-checking=release \--with-system-zlib \--enable-__cxa_atexit \--disable-libunwind-exceptions \--enable-gnu-unique-object \--enable-linker-build-id \--with-gcc-major-version-only \--enable-libstdcxx-dual-abi \--enable-languages=c,c++ \--disable-multiliblog_info "開始編譯GCC(這可能需要1-2小時)..."local cpu_cores=$(nproc)local make_jobs=$(( cpu_cores > 4 ? 4 : cpu_cores ))log_info "使用 $make_jobs 線程進行編譯"if ! make -j$make_jobs; thenlog_error "多線程編譯失敗,嘗試單線程編譯..."make -j1filog_info "安裝GCC..."make install || {log_error "GCC安裝失敗"return 1}log_info "配置系統使用新GCC..."ln -sf /usr/local/gcc-${install_version}/bin/gcc /usr/local/bin/gccln -sf /usr/local/gcc-${install_version}/bin/g++ /usr/local/bin/g++ln -sf /usr/local/gcc-${install_version}/bin/gcc /usr/local/bin/ccln -sf /usr/local/gcc-${install_version}/bin/g++ /usr/local/bin/c++echo "/usr/local/gcc-${install_version}/lib64" > /etc/ld.so.conf.d/gcc-${install_version}.confldconfig 2>/dev/nulllog_info "? GCC源碼編譯安裝成功,版本: $gcc_major_version"echo "$gcc_major_version" > /tmp/gcc_version.txtreturn 0
}# 檢查是否為 root
if [ "$EUID" -ne 0 ]; thenlog_error "請以 root 權限運行此腳本"exit 1
fi# 設置變量
WORK_DIR="/root/open-webui"
VENV_DIR="${WORK_DIR}/venv"  # 虛擬環境目錄
PYTHON_DIR="/usr/local/python3.11"
SYSTEM_PYTHON_BIN="${PYTHON_DIR}/bin/python3.11"
PYTHON_BIN="${VENV_DIR}/bin/python"  # 使用虛擬環境的python
PIP_BIN="${VENV_DIR}/bin/pip"        # 使用虛擬環境的pip
OPENSSL_DIR="/usr/local/openssl-3.1.4"
OPENSSL_TGZ="openssl-3.1.4.tar.gz"
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
LOCAL_OPENSSL_TGZ="${SCRIPT_DIR}/${OPENSSL_TGZ}"
WEBUI_PORT=9000
PIP_MIRROR="https://pypi.tuna.tsinghua.edu.cn/simple"
PIP_TIMEOUT=120# 禁用失效倉庫
disable_broken_repos() {log_info "🚫 禁用失效的倉庫..."if command -v yum-config-manager >/dev/null 2>&1; thenyum-config-manager --disable centos-sclo-rh || trueyum-config-manager --disable centos-sclo-sclo || trueyum-config-manager --disable docker-ce-stable || trueyum-config-manager --disable yarn || trueyum-config-manager --save --setopt=*.skip_if_unavailable=true || truefi
}# 替換鏡像源為 CentOS Vault
setup_centos_vault() {if [[ "$OS" == "CentOS" && "$VERSION" == "7"* ]]; thenlog_info "🔧 替換CentOS 7鏡像源為 Vault..."cd /etc/yum.repos.dmv CentOS-Base.repo CentOS-Base.repo.bak 2>/dev/null || truecat > CentOS-Base.repo << 'EOL'
[base]
name=CentOS-7.9.2009 - Base
baseurl=https://vault.centos.org/7.9.2009/os/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1[updates]
name=CentOS-7.9.2009 - Updates
baseurl=https://vault.centos.org/7.9.2009/updates/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1[extras]
name=CentOS-7.9.2009 - Extras
baseurl=https://vault.centos.org/7.9.2009/extras/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=1[centosplus]
name=CentOS-7.9.2009 - Plus
baseurl=https://vault.centos.org/7.9.2009/centosplus/x86_64/
gpgcheck=1
gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7
enabled=0
EOLyum clean allyum makecachefi
}# 安裝系統依賴(新增Perl模塊)
install_system_dependencies() {log_info "🧰 安裝系統依賴..."case $OS in"CentOS"|"Red Hat"|"Oracle Linux")$PACKAGE_MANAGER install -y epel-release gcc make perl perl-IPC-Cmd perl-Error zlib-devel bzip2-devel \readline-devel sqlite-devel libffi-devel xz-devel wget curl;;"Ubuntu"|"Debian")apt-get install -y build-essential libssl-dev zlib1g-dev libbz2-dev \libreadline-dev libsqlite3-dev wget curl llvm libncurses5-dev libncursesw5-dev \xz-utils tk-dev libffi-dev liblzma-dev perl libipc-cmd-perl;;"SUSE Linux"|"openSUSE")zypper install -y gcc make zlib-devel bzip2-devel readline-devel sqlite3-devel \libffi-devel xz-devel wget curl perl perl-IPC-Cmd;;*)log_warn "未識別系統,嘗試安裝常見依賴";;esac
}# 創建Python虛擬環境
create_venv() {log_info "🔧 創建Python虛擬環境..."# 如果虛擬環境已存在,先刪除if [ -d "$VENV_DIR" ]; thenlog_info "虛擬環境已存在,重新創建..."rm -rf "$VENV_DIR"fi# 使用系統Python創建虛擬環境if ! $SYSTEM_PYTHON_BIN -m venv "$VENV_DIR"; thenlog_error "創建虛擬環境失敗,嘗試安裝venv模塊..."# 安裝venv所需包if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER install -y python3-venvelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get install -y python3-venvfi# 再次嘗試創建if ! $SYSTEM_PYTHON_BIN -m venv "$VENV_DIR"; thenlog_error "創建虛擬環境失敗,無法繼續安裝"exit 1fifilog_info "? 虛擬環境創建成功: $VENV_DIR"
}# 準備 OpenSSL 安裝包
prepare_openssl_package() {cd "$WORK_DIR"local expected_md5="653ad58812c751b887e8ec37e02bba70"if [ -f "$LOCAL_OPENSSL_TGZ" ]; thenlog_info "📂 發現腳本同級目錄存在OpenSSL安裝包:$LOCAL_OPENSSL_TGZ"local actual_md5=$(md5sum "$LOCAL_OPENSSL_TGZ" | awk '{print $1}')log_info "本地包MD5: $actual_md5,預期MD5: $expected_md5"if [ "$actual_md5" = "$expected_md5" ]; thenlog_info "? MD5校驗通過,直接使用本地包"cp "$LOCAL_OPENSSL_TGZ" "$WORK_DIR/"return 0elselog_warn "? MD5校驗不匹配,忽略本地包"rm -f "$WORK_DIR/$OPENSSL_TGZ"fielselog_info "?? 腳本同級目錄未找到OpenSSL安裝包"fiif [ -f "$WORK_DIR/$OPENSSL_TGZ" ]; thenlog_info "📂 發現工作目錄存在OpenSSL安裝包"local actual_md5=$(md5sum "$WORK_DIR/$OPENSSL_TGZ" | awk '{print $1}')if [ "$actual_md5" = "$expected_md5" ]; thenlog_info "? MD5校驗通過,使用工作目錄包"return 0elselog_warn "? 工作目錄包損壞,重新下載"rm -f "$WORK_DIR/$OPENSSL_TGZ"fifilog_info "📥 開始在線下載OpenSSL安裝包..."download_openssl
}# 下載 OpenSSL
download_openssl() {cd "$WORK_DIR"local openssl_url="https://github.com/openssl/openssl/releases/download/openssl-3.1.4/openssl-3.1.4.tar.gz"if [ -f "$OPENSSL_TGZ" ]; thenrm -f "$OPENSSL_TGZ"fiMAX_RETRY=5RETRY_DELAY=10for i in $(seq 1 $MAX_RETRY); dolog_info "嘗試從官方地址下載(第 $i/$MAX_RETRY 次): $openssl_url"if wget --no-check-certificate -q --show-progress "$openssl_url"; thenlog_info "? 下載成功"return 0elselog_error "? 第 $i 次下載失敗,$RETRY_DELAY 秒后重試..."sleep $RETRY_DELAYRETRY_DELAY=$((RETRY_DELAY + 5))fidonelog_error "? 達到最大重試次數,下載失敗"log_error "請手動下載 openssl-3.1.4.tar.gz 并放在腳本同級目錄后重試"exit 1
}# OpenSSL安裝函數(修復lib64目錄識別問題)
install_openssl() {log_info "🔐 開始安裝 OpenSSL 3.1.4..."if [ -d "$OPENSSL_DIR" ]; thenrm -rf "$OPENSSL_DIR"ficd "$WORK_DIR"prepare_openssl_package# 清理之前可能存在的解壓目錄rm -rf openssl-3.1.4tar xzf "$OPENSSL_TGZ" || {log_error "? 安裝包解壓失敗"exit 1}cd openssl-3.1.4# 確保Perl模塊可用log_info "檢查Perl模塊IPC::Cmd是否可用..."if ! perl -e "use IPC::Cmd;"; thenlog_error "Perl模塊IPC::Cmd仍然缺失,嘗試手動安裝..."# 針對不同系統嘗試手動安裝缺失的Perl模塊if [ "$PACKAGE_MANAGER" = "yum" ] || [ "$PACKAGE_MANAGER" = "dnf" ]; then$PACKAGE_MANAGER install -y perl-IPC-Cmdelif [ "$PACKAGE_MANAGER" = "apt-get" ]; thenapt-get install -y libipc-cmd-perlelif [ "$PACKAGE_MANAGER" = "zypper" ]; thenzypper install -y perl-IPC-Cmdelse# 嘗試CPAN安裝作為最后的手段log_info "嘗試通過CPAN安裝IPC::Cmd..."perl -MCPAN -e 'install IPC::Cmd'fi# 再次檢查if ! perl -e "use IPC::Cmd;"; thenlog_error "? 無法安裝Perl模塊IPC::Cmd,無法繼續"exit 1fifi./Configure linux-x86_64 --prefix="$OPENSSL_DIR" --openssldir="$OPENSSL_DIR/etc" shared zlibmake -j$(nproc)make install_swlog_info "🔗 配置 OpenSSL 環境變量和pkg-config..."# 檢測是lib還是lib64目錄if [ -d "$OPENSSL_DIR/lib64" ]; thenOPENSSL_LIB_DIR="$OPENSSL_DIR/lib64"log_info "檢測到OpenSSL使用lib64目錄結構"elseOPENSSL_LIB_DIR="$OPENSSL_DIR/lib"log_info "檢測到OpenSSL使用lib目錄結構"fi# 配置pkg-config以優先使用我們安裝的OpenSSLif [ -d /usr/lib64/pkgconfig ]; then# 備份并移除系統默認的openssl.pcmv /usr/lib64/pkgconfig/openssl.pc /usr/lib64/pkgconfig/openssl.pc.bak 2>/dev/null || true# 創建指向我們安裝的openssl.pc的軟鏈接ln -sf "$OPENSSL_LIB_DIR/pkgconfig/openssl.pc" /usr/lib64/pkgconfig/openssl.pcfiif [ -d /usr/lib/pkgconfig ]; then# 備份并移除系統默認的openssl.pcmv /usr/lib/pkgconfig/openssl.pc /usr/lib/pkgconfig/openssl.pc.bak 2>/dev/null || true# 創建指向我們安裝的openssl.pc的軟鏈接ln -sf "$OPENSSL_LIB_DIR/pkgconfig/openssl.pc" /usr/lib/pkgconfig/openssl.pcfi# 配置環境變量,使用正確的lib目錄export PKG_CONFIG_PATH="$OPENSSL_LIB_DIR/pkgconfig:$PKG_CONFIG_PATH"export LD_LIBRARY_PATH="$OPENSSL_LIB_DIR:$LD_LIBRARY_PATH"export PATH="$OPENSSL_DIR/bin:$PATH"echo "$OPENSSL_LIB_DIR" > /etc/ld.so.conf.d/openssl.confldconfig# 替換系統默認的opensslrm -f /usr/bin/opensslln -sf "$OPENSSL_DIR/bin/openssl" /usr/bin/openssl# 驗證OpenSSL版本和pkg-config配置log_info "當前系統默認OpenSSL版本: $(openssl version | awk '{print $2}')"# 檢查openssl.pc是否存在if [ -f "$OPENSSL_LIB_DIR/pkgconfig/openssl.pc" ]; thenlog_info "openssl.pc文件存在: $OPENSSL_LIB_DIR/pkgconfig/openssl.pc"log_info "pkg-config檢測到的OpenSSL版本: $(pkg-config --modversion openssl 2>/dev/null || echo "未檢測到")"elselog_error "openssl.pc文件不存在于預期位置: $OPENSSL_LIB_DIR/pkgconfig/openssl.pc"log_error "OpenSSL安裝可能不完整"exit 1fi
}# OpenSSL安裝主函數
setup_compatible_openssl() {log_info "🔒 開始OpenSSL環境配置..."# 先校驗是否兼容if check_openssl_version; thenreturn 0fi# 不兼容或未安裝則安裝新版install_openssl# 再次驗證check_openssl_version || {log_error "OpenSSL配置后仍不兼容,無法繼續安裝"exit 1}
}# 檢查 Python SSL 支持
check_python_ssl() {log_info "🔍 檢查 Python SSL 支持..."if $PYTHON_BIN -c "import ssl; print('SSL 支持正常:', ssl.OPENSSL_VERSION)" 2>/dev/null; thenlog_info "? Python SSL 支持正常"return 0elselog_error "? Python SSL 支持異常"return 1fi
}# 安裝 Python 3.11
install_python() {if [ -x "$SYSTEM_PYTHON_BIN" ]; thenlog_info "? Python 3.11 已安裝"# 創建虛擬環境create_venv# 檢查虛擬環境中的Python SSL支持if check_python_ssl; thenreturn 0elselog_error "虛擬環境中Python SSL支持異常,嘗試重新安裝Python"fifilog_info "📥 安裝 Python 3.11..."cd "$WORK_DIR"PYTHON_TGZ="Python-3.11.0.tgz"local expected_py_size=26006345if [ ! -f "$PYTHON_TGZ" ]; thenlog_info "未發現本地Python源碼包,開始下載..."if ! retry_command 3 curl -LO --retry 3 --connect-timeout 10 https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tgz; thenlog_error "? Python 源碼包下載失敗"exit 1fielselocal actual_py_size=$(stat -c%s "$PYTHON_TGZ" 2>/dev/null || echo 0)if [ "$actual_py_size" -ne "$expected_py_size" ]; thenlog_info "本地Python源碼包不完整,重新下載..."rm -f "$PYTHON_TGZ"if ! retry_command 3 curl -LO --retry 3 --connect-timeout 10 https://www.python.org/ftp/python/3.11.0/Python-3.11.0.tgz; thenlog_error "? Python 源碼包下載失敗"exit 1fielselog_info "本地Python源碼包完整,直接使用"fifiif [ ! -d "Python-3.11.0" ]; thenlog_info "解壓Python源碼..."tar xzf "$PYTHON_TGZ"elselog_info "Python源碼已解壓,跳過解壓步驟"fichown -R root:root "Python-3.11.0"cd Python-3.11.0# 檢測OpenSSL庫目錄if [ -d "$OPENSSL_DIR/lib64" ]; thenOPENSSL_LIB_DIR="$OPENSSL_DIR/lib64"elseOPENSSL_LIB_DIR="$OPENSSL_DIR/lib"fiCPPFLAGS="-I$OPENSSL_DIR/include" \LDFLAGS="-L$OPENSSL_LIB_DIR -Wl,-rpath,$OPENSSL_LIB_DIR -Wl,--enable-new-dtags" \./configure --prefix="$PYTHON_DIR" \--enable-optimizations \--with-ssl="$OPENSSL_DIR" \--enable-ipv6 \--with-ensurepip=installmake -j$(nproc)make installlog_info "🔗 創建 Python 軟鏈接..."ln -sf "$PYTHON_DIR/bin/python3.11" /usr/local/bin/python3ln -sf "$PYTHON_DIR/bin/pip3.11" /usr/local/bin/pip3chown -R root:root "$PYTHON_DIR"# 創建虛擬環境create_venvcheck_python_ssl || {log_error "? Python SSL 支持修復失敗"exit 1}
}# 檢查 Python 版本
check_python_version() {log_info "🔍 驗證 Python 版本..."if ! command -v "$PYTHON_BIN" &>/dev/null; thenlog_error "未找到 Python3"exit 1fiPYTHON_VERSION=$($PYTHON_BIN -c 'import sys; print(".".join(map(str, sys.version_info[:2])))')log_info "當前 Python 版本: $PYTHON_VERSION"if [ "$(echo "$PYTHON_VERSION >= 3.11" | bc)" -ne 1 ]; thenlog_error "需要 Python 3.11 或更高版本"exit 1fi
}# 配置pip鏡像源
configure_pip_mirror() {log_info "🔧 配置 pip 鏡像源為 $PIP_MIRROR..."mkdir -p /root/.pipcat > /root/.pip/pip.conf << EOF
[global]
index-url = $PIP_MIRROR
trusted-host = $(echo $PIP_MIRROR | awk -F/ '{print $3}')
timeout = $PIP_TIMEOUT
EOF# 同時在虛擬環境中配置pipmkdir -p "${VENV_DIR}/pip"cat > "${VENV_DIR}/pip/pip.conf" << EOF
[global]
index-url = $PIP_MIRROR
trusted-host = $(echo $PIP_MIRROR | awk -F/ '{print $3}')
timeout = $PIP_TIMEOUT
EOF
}
# 在install_open_webui函數前新增安裝Apache Arrow的函數
install_apache_arrow() {log_info "📦 安裝Apache Arrow及Dataset組件(pyarrow需要)..."case $OS in"CentOS"|"Red Hat"|"Oracle Linux")# 安裝EPEL倉庫(忽略已安裝提示)yum install -y epel-release || true# 安裝Arrow倉庫配置(忽略已安裝提示)curl -fsSL https://apache.jfrog.io/artifactory/arrow/centos/$(rpm -E %rhel)/apache-arrow-release-latest.rpm -o apache-arrow-release.rpmyum install -y ./apache-arrow-release.rpm || truerm -f apache-arrow-release.rpm# 強制刷新倉庫緩存yum clean allyum makecache fast# 關鍵:安裝所有必需的開發包,包括Dataset組件log_info "安裝Arrow核心庫和Dataset組件..."yum install -y arrow-devel arrow-glib-devel arrow-dataset-devel;;# 保持其他系統的安裝邏輯不變"Ubuntu"|"Debian")# ... 原有代碼 ...;;"SUSE Linux"|"openSUSE")# ... 原有代碼 ...;;esac# 驗證ArrowDataset是否安裝成功if pkg-config --exists arrow-dataset; thenlog_info "? Apache Arrow及Dataset組件安裝成功"return 0elselog_error "? Apache Arrow Dataset組件安裝失敗"# 嘗試手動安裝作為最后的手段log_info "嘗試手動編譯安裝Apache Arrow..."install_arrow_from_sourcereturn $?fi
}# 新增:從源碼安裝Apache Arrow的函數(當包管理器安裝失敗時)
install_arrow_from_source() {local arrow_version="14.0.1"log_info "從源碼安裝Apache Arrow $arrow_version..."# 安裝編譯依賴yum install -y cmake gcc-c++ git python3-devel boost-devel rapidjson-devel# 創建臨時目錄local temp_dir=$(mktemp -d)cd "$temp_dir" || {log_error "無法進入臨時目錄"return 1}# 克隆源碼git clone --branch apache-arrow-$arrow_version https://github.com/apache/arrow.gitcd arrow/cpp || {log_error "找不到Arrow源碼目錄"return 1}# 創建編譯目錄mkdir build && cd build# 配置編譯選項cmake .. \-DCMAKE_INSTALL_PREFIX=/usr/local \-DARROW_DATASET=ON \-DARROW_PYTHON=ON \-DARROW_WITH_BZ2=ON \-DARROW_WITH_ZLIB=ON \-DARROW_WITH_ZSTD=ON \-DCMAKE_BUILD_TYPE=Release# 編譯并安裝make -j$(nproc)make install# 刷新動態鏈接庫ldconfig# 清理臨時文件cd ../../../../ && rm -rf "$temp_dir"# 驗證安裝if pkg-config --exists arrow-dataset; thenlog_info "? 源碼安裝Apache Arrow成功"return 0elselog_error "? 源碼安裝Apache Arrow失敗"return 1fi
}# 安裝 Open WebUI(強制使用新FFmpeg)
install_open_webui() {configure_pip_mirrorlog_info "📦 通過 pip 安裝 Open WebUI..."pip_install_with_retry "pip" "--upgrade"log_info "📦 安裝兼容版本的numpy..."pip_install_with_retry "numpy==1.26.4" "--no-cache-dir"# 安裝Apache Arrow系統依賴install_apache_arrow# 安裝av包log_info "📦 安裝av包(強制關聯新FFmpeg)..." export PKG_CONFIG_PATH="/usr/local/ffmpeg/lib/pkgconfig:$PKG_CONFIG_PATH"export CFLAGS="-I/usr/local/ffmpeg/include"export LDFLAGS="-L/usr/local/ffmpeg/lib -Wl,-rpath=/usr/local/ffmpeg/lib"pip_install_with_retry "av==10.0.0" "--no-cache-dir"# 使用預編譯的pyarrow wheel包log_info "📦 安裝pyarrow(優先使用預編譯包)..."export CMAKE_PREFIX_PATH="/usr/local:/usr"# 嘗試直接安裝預編譯wheelif ! pip_install_with_retry "pyarrow" "--no-cache-dir"; thenlog_warn "預編譯包安裝失敗,嘗試指定較低版本..."# 若失敗,嘗試已知兼容的版本pip_install_with_retry "pyarrow==14.0.1" "--no-cache-dir"fi# 安裝open-webuipip_install_with_retry "open-webui" "--no-cache-dir"
}# 配置系統服務(修復端口配置錯誤)
configure_service() {log_info "?? 配置 systemd 服務(端口: $WEBUI_PORT)..."OPEN_WEBUI_BIN="${VENV_DIR}/bin/open-webui"GCC_VERSION=$(cat /tmp/gcc_version.txt 2>/dev/null || echo "9")# 檢測OpenSSL庫目錄if [ -d "$OPENSSL_DIR/lib64" ]; thenOPENSSL_LIB_DIR="$OPENSSL_DIR/lib64"elseOPENSSL_LIB_DIR="$OPENSSL_DIR/lib"ficat > /etc/systemd/system/open-webui.service << EOF
[Unit]
Description=Open WebUI Service
After=network.target[Service]
User=root
Environment="PATH=/usr/local/bin:/usr/bin:${PYTHON_DIR}/bin:${VENV_DIR}/bin"
Environment="LD_LIBRARY_PATH=${OPENSSL_LIB_DIR}:/usr/local/gcc-${GCC_VERSION}.4.0/lib64:/usr/local/ffmpeg/lib"
Environment="PKG_CONFIG_PATH=/usr/local/ffmpeg/lib/pkgconfig:${OPENSSL_LIB_DIR}/pkgconfig"
ExecStart=${OPEN_WEBUI_BIN} serve --port $WEBUI_PORT
Restart=always
RestartSec=5[Install]
WantedBy=multi-user.target
EOFlog_info "🚀 啟動 Open WebUI 服務(端口: $WEBUI_PORT)..."systemctl daemon-reloadsystemctl enable open-webui --nowif systemctl is-active --quiet open-webui; thenlog_info "? Open WebUI 服務已啟動"elselog_error "? Open WebUI 服務啟動失敗"log_error "查看日志: journalctl -u open-webui -n 50"exit 1fi
}# 顯示安裝信息
show_info() {log_info "🎉 安裝完成!"log_info "🌐 訪問地址: http://<你的服務器IP>:$WEBUI_PORT"log_info "📄 服務狀態: systemctl status open-webui"log_info "📜 日志查看: journalctl -u open-webui -f"log_info "🔄 重啟服務: systemctl restart open-webui"log_info "📈 升級服務: ${PIP_BIN} install --upgrade open-webui"log_info "🔍 虛擬環境位置: ${VENV_DIR}"
}# 主函數(新增依賴檢測步驟)
main() {log_info "🔧 開始安裝 Open WebUI(將使用 $WEBUI_PORT 端口)..."detect_systemmkdir -p "$WORK_DIR"cd "$WORK_DIR"# 1. 檢查并升級GCCcheck_and_upgrade_gcc 9 || {log_error "GCC版本檢查和升級失敗,無法繼續安裝"exit 1}# 2. 檢查并升級CMake(新增步驟)log_info "開始CMake環境配置..."if ! check_cmake_version; thenupgrade_cmake || {log_error "CMake版本檢查和升級失敗,無法繼續安裝"exit 1}fi# 3. 檢查并安裝OpenSSLsetup_compatible_openssl || {log_error "OpenSSL版本檢查和安裝失敗,無法繼續安裝"exit 1}# 4. 其他系統配置disable_broken_repossetup_centos_vaultinstall_system_dependencies# 5. 配置FFmpegsetup_compatible_ffmpeg# 6. 安裝并配置Pythoninstall_pythoncheck_python_version# 7. 安裝Open WebUI及依賴install_open_webui# 8. 配置服務并啟動configure_serviceshow_info
}main

安裝

./install_open_webui.sh

如果openssl-3.1.4.tar.gz 文件下載特別慢可以將 openssl-3.1.4.tar.gz 文件手動下載上傳到腳本同級目錄,腳本已支持離線安裝

安裝中發現磁盤空間不夠滿了(清除了一遍發現空間還是有點少),中途進行了一次Linux磁盤的擴容:https://blog.csdn.net/YXWik/article/details/149566023

驗證openssl的MD5

md5sum openssl-3.1.4.tar.gz

如果MD5值與腳本中配置的不一致,需要手動將查出來的md值寫到腳本
在這里插入圖片描述

因為我的服務器環境什么都沒有,所以腳本更適用于什么都沒有的空環境,雖然已經適配了各個軟件存在的情況,但是沒有經過充分的驗證,會存在一些意想不到的問題

以下問題是出在安裝包時的一個特殊要求:它強制要求在虛擬環境中安裝,而當前腳本是在系統全局環境中運行的。要解決這個問題,我們需要修改安裝邏輯,為 Open WebUI 創建一個專用的 Python 虛擬環境。問題已在腳本中處理,在此記錄一下,安裝Open WebUI需要給它虛擬環境
在這里插入圖片描述

FFmpeg 啟用 GPL 許可功能時,要求 OpenSSL 版本≥3.0.0,但當前安裝的是 OpenSSL 1.1.1w(低于 3.0.0),導致兼容性沖突,我這里將 FFmpegGPL 許可功能禁用掉了,結果禁用了出現一大堆問題,沒辦法,只能升級openssl的版本
在這里插入圖片描述

在腳本運行安裝的途中,我決定再次使用docker安裝嘗試一下

在這里插入圖片描述

docker run -d -p 3000:8080  -e OLLAMA_BASE_URL=http://host.docker.internal:11434 -v open-webui:/app/backend/data --name open-webui --restart always ghcr.nju.edu.cn/open-webui/open-webui:main

結果很意外,很快很快就成功了,上次可能網絡不佳(折騰好幾天)
在這里插入圖片描述
查看日志,等如下圖啟動成功就可以訪問了(需要等一段時間才能啟動成功)

docker logs -f open-webui

在這里插入圖片描述
如果訪問不到開放下端口

iptables -I INPUT -p tcp --dport 3000 -j  ACCEPT

自行注冊一下賬號
在這里插入圖片描述
啟動成功了,但是我發現我的open-webui 容器中是訪問不到ollama的
在這里插入圖片描述
但是ollama在瀏覽器這種外部環境是可以訪問的
在這里插入圖片描述
這種情況是因為ollama proxy 網絡代理問題
卸載重裝ollama

docker stop ollama
docker rm ollama
docker run -d   --name ollama   -v /home/ollama:/root/.ollama   -p 11434:11434   -e OLLAMA_HOST=0.0.0.0   --add-host=host.docker.internal:host-gateway   --restart always   ollama/ollama
# 驗證
docker exec -it ollama env | grep OLLAMA_HOST
docker exec -it ollama ollama run deepseek-r1:7b

在這里插入圖片描述
然后再重裝 open-webui (我這里重裝是因為我之前的 open-webui 安裝時指定的OLLAMA_BASE_URL 是http://localhost:11434 ,要更改為 ollama的IP+端口)

docker stop open-webui
docker rm open-webui
docker run -d   -p 3000:8080   -e OLLAMA_BASE_URL=http://192.168.0.180:11434   -v open-webui:/app/backend/data   --name open-webui   --restart always   ghcr.nju.edu.cn/open-webui/open-webui:main
# 驗證docker exec -it open-webui curl http://192.168.0.180:11434/api/tags

在這里插入圖片描述
這里就正常完成啦
在這里插入圖片描述

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/90517.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/90517.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/90517.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

深度解析:在Odoo 18中基于原生Owl框架為PWA定制功能豐富的底部導航欄

本文旨在提供一個從架構設計、核心功能實現到高級用戶體驗優化的全面指南&#xff0c;詳細闡述如何在Odoo 18中&#xff0c;完全利用其原生的Owl前端框架&#xff0c;為漸進式網絡應用&#xff08;PWA&#xff09;從零開始開發一個功能完備、數據驅動且高度可定制的底部導航欄。…

Java泛型初始化ArrayList<String>()和ArrayList<>()的區別

文章目錄前言Java 泛型初始化&#xff1a;ArrayList<String>() vs ArrayList<>() 的區別1. 語法差異1.1 顯式泛型初始化 (ArrayList<String>())1.2 鉆石操作符初始化 (ArrayList<>())2. 編譯與運行時的區別3. 使用場景對比3.1 顯式泛型初始化的適用情況…

ubuntu25.04+4070+cuda+docker安裝

目錄 1.4070nvidia驅動安裝 2.CUDA安裝 3.docker安裝 4.docker的GPU支持 1.4070nvidia驅動安裝 首先從軟件源獲取最新的軟件包信息&#xff0c;然后升級一下安裝好的軟件包 #從軟件源獲取最新的軟件包信息 apt update -y #將已安裝的軟件包升級到最新版本 apt upgrade -y 然…

Mac m系列 VMware Fusion虛擬機安裝ARM contos

一、下載虛擬機 VMware Fusion和 CentOS 安裝 VMware Fusion下載地址下載好鏡像文件CentOS-Stream-9-20230516.0-aarch64-boot.iso下載地址 二、打開VMware Fusion新建虛擬機 選擇從光盤或映像中安裝點擊繼 選擇剛才下載的鏡像&#xff0c;點擊繼續選擇 Linux > 其他Linu…

MYSQL中NOT IN和NOT EXISTS

NOT IN 和 NOT EXISTS 是 MySQL 中用于排除某些數據的兩種常見查詢方式。它們的功能相似&#xff0c;都用于返回不滿足某一條件的結果&#xff0c;但是它們在內部的實現方式以及某些特定場景下的行為有所不同。1. NOT INNOT IN 是用來排除在指定值集合中存在的值。通常用來與子…

數據庫關系運算之連接

在數據庫理論中&#xff0c;關系連接&#xff08;Join&#xff09; 是將兩個或多個關系&#xff08;表&#xff09;中的元組&#xff08;行&#xff09;根據一定條件組合成新關系的操作&#xff0c;是關系型數據庫中核心且高頻使用的操作。其本質是通過共享的屬性&#xff08;列…

npm全局安裝后,依然不是內部或外部命令,也不是可運行的程序或批處理文件

雖然通過 npm install -g yarn 安裝了 Yarn&#xff0c;但系統無法識別 yarn 命令。這通常是因為 npm 的全局安裝目錄沒有添加到系統的 PATH 環境變量中C:\Users\Administrator>npm install -g yarnadded 1 package in 518msC:\Users\Administrator>yarn yarn 不是內部或…

C++ Proactor 與 Reactor 網絡編程模式

&#x1f9e0; C Proactor 與 Reactor 網絡編程模式&#x1f4cc; 核心區別概述特性Reactor 模式Proactor 模式事件驅動核心監聽 I/O 就緒事件 (可讀/可寫)監聽 I/O 完成事件 (讀完成/寫完成)I/O 執行者用戶線程 主動執行 I/O 操作操作系統 異步執行 I/O 操作控制流同步非阻塞 …

從手動操作到自動化:火語言 RPA 在多系統協作中的實踐

在企業日常運營中&#xff0c;很多業務流程需要在多個系統間來回切換&#xff1a;從 A 系統導出數據&#xff0c;到 B 系統校驗格式&#xff0c;再到 C 系統錄入信息…… 這些跨系統操作步驟繁瑣、邏輯固定&#xff0c;卻往往依賴人工完成&#xff0c;不僅效率低下&#xff0c;…

Spring Security 實踐之登錄

前言Spring Security是一個功能強大且高度且可定制的身份驗證和訪問控制框架&#xff0c;包含標準的身份認證和授權。 本文主要介紹SpringBoot中如何配置使用 Spring Security 安全認證框架并簡述相關原理和步驟。核心認證流程解析請求過濾 用戶提交登錄表單AbstractAuthentica…

華為云開發者空間 × DeepSeek-R1 智能融合測評:云端開發與AI客服的協同進化

前言&#xff1a; 華為開發者空間&#xff0c;是為全球開發者打造的專屬開發者空間&#xff0c;致力于為每位開發者提供一臺云主機、一套開發工具和云上存儲空間&#xff0c;當普惠云資源遇見推理大模型&#xff0c;企業服務與開發效能的范式革命正在加速。華為云開發者空間&am…

二分查找----4.搜索旋轉排序數組

題目鏈接 /** 升序數組在某個位置被分割為前后兩部分,前后兩部分整體互換;在被改變后的數組中找到目標值 O(log n)---> 二分查找 特點: 旋轉后的數組被分割為兩個獨立的遞增區間 左半區的最小值,大于右半區的最大值(mid所在區間的判斷依據) 二分策略: 首先判斷mid落在左區間…

地球表面附近兩點之間距離、高低角和方位角的計算方法,VC++代碼實操!

書接上文&#xff0c;這篇文章介紹具體的VC編程實現&#xff0c;代碼實操。任何一個算法&#xff0c;你必須將其編寫為代碼&#xff0c;運行結果正確&#xff0c;才算真正掌握了&#xff0c;否則都是似懂非懂&#xff0c;一知半解&#xff0c;下面先給出仿真結果的截圖&#xf…

uniapp各大平臺導航組件

最近有個需求要點擊導航然后跳出各家導航軟件話不多出直接貼出代碼&#xff1a;這個可以作為組件引入<template><view><view class"nav" :style"{color: customColor}" click.stop"openMap">{{title}}</view><!-- 彈…

Access開發一鍵刪除Excel指定工作表

Hi&#xff0c;大家好&#xff01;又到了每周給大家更新的時間了&#xff0c;這周給大家講講excel的處理操作吧。在開始前&#xff0c;先給大家匯報一下我們框架的進度&#xff0c;最近兩周沒有直播&#xff0c;所以大家不太清楚目前的進度&#xff0c;框架目前就差權限了&…

無廣告終端安全產品推薦:打造純凈辦公環境的安全之選

在數字化辦公時代&#xff0c;終端安全防護是企業和個人不可忽視的重要環節。然而&#xff0c;許多傳統安全軟件往往伴隨著頻繁的廣告彈窗和推廣信息&#xff0c;不僅干擾正常工作&#xff0c;還可能成為潛在的安全隱患。本文將為您介紹幾款「無廣告、無捆綁」的終端產品&#…

使用UE5自帶節點InteriorCubemap制作假室內效果

Interior Mapping&#xff08;室內映射&#xff09;是一種用著色器方法模擬室內結構紋理的方式&#xff0c;避免了真實對室內場景建模造成的模型面數渲染開銷&#xff0c;在《蜘蛛俠》《城市天際線》等游戲中都采用了該技術。 UE自帶了節點InteriorCubemap&#xff08;Unity S…

基于單片機睡眠質量/睡眠枕頭設計

傳送門 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目速選一覽表 &#x1f449;&#x1f449;&#x1f449;&#x1f449;其他作品題目功能速覽 概述 隨著現代社會生活節奏的加快&#xff0c;睡眠質量問題日益受到人們的關注。本研究設計了一種基于…

Ajax第一天

AJAX概念&#xff1a;AJAX 是瀏覽器與服務器進行數據通信的技術&#xff08;把數據變活&#xff09;語法&#xff1a;1.引入 axios.js&#xff1a;https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js2.使用 axios 函數? 傳入配置對象? 再用 .then 回調函數接收結果&#…

AI大模型各類概念掃盲

以下內容整理自AI&#xff0c;進行一個概念掃盲&#xff1a;Prompt&#xff08;提示詞&#xff09; Prompt是用戶提供給AI模型的指令或問題&#xff0c;用于引導模型生成特定輸出。良好的Prompt設計能顯著提升模型的任務理解能力和響應質量&#xff0c;例如通過結構化提示&…