From fe00782db1805c29b224d9ee3c355872704d98ec Mon Sep 17 00:00:00 2001 From: MyeonghoeLee Date: Wed, 25 Mar 2026 21:36:28 +0900 Subject: [PATCH] =?UTF-8?q?Qwen3.5=20+=20Open=20WebUI=20=EB=A1=9C=EC=BB=AC?= =?UTF-8?q?=20=EC=84=9C=EB=B9=99=20=ED=99=98=EA=B2=BD=20=EC=85=8B=EC=97=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Ollama 방식과 vllm-mlx(MLX) 방식 두 가지 셋업 스크립트 및 가이드 포함. transformers fast image processor 호환성 패치 자동 적용. Co-Authored-By: Claude Opus 4.6 (1M context) --- SETUP_MLX.md | 390 +++++++++++++++++++++++++++++++++++++++++ SETUP_OLLAMA.md | 127 ++++++++++++++ docker-compose.mlx.yml | 18 ++ docker-compose.yml | 16 ++ setup-mlx.sh | 219 +++++++++++++++++++++++ setup-ollama.sh | 117 +++++++++++++ stop-mlx.sh | 37 ++++ stop-ollama.sh | 33 ++++ 8 files changed, 957 insertions(+) create mode 100644 SETUP_MLX.md create mode 100644 SETUP_OLLAMA.md create mode 100644 docker-compose.mlx.yml create mode 100644 docker-compose.yml create mode 100755 setup-mlx.sh create mode 100755 setup-ollama.sh create mode 100755 stop-mlx.sh create mode 100755 stop-ollama.sh diff --git a/SETUP_MLX.md b/SETUP_MLX.md new file mode 100644 index 0000000..aaf2be0 --- /dev/null +++ b/SETUP_MLX.md @@ -0,0 +1,390 @@ +# Qwen3.5 + Open WebUI — vllm-mlx (Mac 최적화) + +> 환경: MacBook Pro M4 Pro 48GB / Docker Desktop / Python 3.10+ + +--- + +# 목차 + +1. [환경 준비](#1-환경-준비) +2. [서버 시작](#2-서버-시작) +3. [Open WebUI 연결](#3-open-webui-연결) +4. [종료 / 재시작](#4-종료--재시작) +5. [파라미터 레퍼런스](#5-파라미터-레퍼런스) +6. [트러블슈팅](#6-트러블슈팅) + +--- + +# 1. 환경 준비 + +> ⚠️ conda 환경에서 실행하면 MPICH와 MLX가 충돌합니다. 반드시 별도 venv에서 실행하세요. + +```bash +conda deactivate + +python3 -m venv ~/mlx-env +source ~/mlx-env/bin/activate + +pip install git+https://github.com/waybarrios/vllm-mlx.git +``` + +--- + +# 2. 서버 시작 + +모델은 첫 시작 시 HuggingFace에서 자동 다운로드됩니다. + +## 텍스트 전용 + +```bash +source ~/mlx-env/bin/activate + +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 \ + --max-tokens 8192 \ + --default-temperature 0.7 \ + --default-top-p 0.9 +``` + +## 텍스트 + 이미지 (멀티모달) + +```bash +source ~/mlx-env/bin/activate + +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 \ + --max-tokens 8192 \ + --default-temperature 0.7 \ + --default-top-p 0.9 \ + --mllm +``` + +> `--mllm` 플래그 하나로 이미지 입력이 활성화됩니다. +> +> 포그라운드로 실행됩니다. **새 터미널 탭**을 열어서 다음 단계를 진행하세요. + +## 용도별 추천 설정 + +```bash +# 문서 생성 (보수적) +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 --max-tokens 8192 \ + --default-temperature 0.2 --default-top-p 0.95 --mllm + +# 대화 / 창의적 응답 +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 --max-tokens 8192 \ + --default-temperature 1.0 --default-top-p 0.8 --mllm + +# 동시 요청 최적화 (여러 사용자) +# ⚠️ --continuous-batching은 단일 사용자일 때 오히려 느려질 수 있음 +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 --max-tokens 8192 \ + --default-temperature 0.7 --mllm --continuous-batching +``` + +--- + +# 3. Open WebUI 연결 + +### 3-1. 서버 동작 확인 + +```bash +curl http://localhost:8090/v1/models + +curl http://localhost:8090/v1/chat/completions \ + -H "Content-Type: application/json" \ + -d '{ + "model": "mlx-community/Qwen3.5-35B-A3B-4bit", + "max_tokens": 8192, + "messages": [{"role": "user", "content": "안녕하세요"}] + }' +``` + +### 3-2. Open WebUI 실행 + +```bash +cd ~/PyCharmMiscProject/openwebui +docker compose -f docker-compose.mlx.yml up -d +``` + +> `docker-compose.mlx.yml`이 없으면 [부록](#부록-docker-composemlxyml-생성)을 참고하세요. + +### 3-3. 브라우저 접속 + +``` +http://localhost:3000 +``` + +1. 첫 접속 시 회원가입 (로컬 전용, 첫 계정 = admin) +2. **설정 → Connections** → OpenAI API 연결 확인 + - URL: `http://host.docker.internal:8090/v1` + - API Key: `none` +3. 상단 모델 선택 후 채팅 시작 + +--- + +# 4. 종료 / 재시작 + +### 종료 + +```bash +# vllm-mlx 서버: Ctrl+C + +# Open WebUI +cd ~/PyCharmMiscProject/openwebui +docker compose -f docker-compose.mlx.yml down +``` + +### 재시작 + +```bash +# 터미널 1: 서버 +source ~/mlx-env/bin/activate +vllm-mlx serve mlx-community/Qwen3.5-35B-A3B-4bit \ + --port 8090 --max-tokens 8192 \ + --default-temperature 0.7 --default-top-p 0.9 --mllm + +# 터미널 2: Open WebUI +cd ~/PyCharmMiscProject/openwebui +docker compose -f docker-compose.mlx.yml up -d +``` + +--- + +# 5. 파라미터 레퍼런스 + +## 서버 시작 플래그 + +### 생성 파라미터 + +| 플래그 | 기본값 | 설명 | +|--------|--------|------| +| `--max-tokens` | 32768 | 최대 생성 토큰 수 (thinking + 응답 합산) | +| `--default-temperature` | 모델 기본값 | Temperature (0.0~2.0) | +| `--default-top-p` | 모델 기본값 | Nucleus Sampling | +| `--reasoning-parser qwen3` | off | thinking 내용을 별도 필드로 추출 | + +### 모달리티 + +| 플래그 | 기본값 | 설명 | +|--------|--------|------| +| `--mllm` | off | 멀티모달 (이미지 입력) 활성화 | + +### 성능 + +| 플래그 | 기본값 | 설명 | +|--------|--------|------| +| `--continuous-batching` | off | 동시 요청 배칭 (단일 사용자 시 오히려 느림) | +| `--prefill-step-size` | 2048 | 프리필 처리 단위 | +| `--stream-interval` | 1 | 스트리밍 배치 토큰 수 (1=부드러움, 클수록 처리량↑) | + +### 메모리 + +| 플래그 | 기본값 | 설명 | +|--------|--------|------| +| `--kv-cache-quantization` | off | KV 캐시 양자화 활성화 (메모리 절약) | +| `--kv-cache-quantization-bits` | 8 | KV 캐시 양자화 비트 (4 또는 8) | +| `--cache-memory-percent` | 0.20 | RAM의 몇 %를 캐시에 할당 | + +### 서버 + +| 플래그 | 기본값 | 설명 | +|--------|--------|------| +| `--port` | - | 서버 포트 | +| `--host` | - | 서버 호스트 | +| `--api-key` | - | API 키 (미설정 시 인증 없음) | +| `--rate-limit` | 0 | 분당 요청 제한 (0 = 무제한) | +| `--timeout` | 300 | 요청 타임아웃 (초) | + +## 각 파라미터가 하는 일 + +### `--default-temperature` (Temperature) + +모델의 출력 랜덤성을 조절합니다. + +``` +0.0 ←──────────────────────────→ 2.0 +결정적 랜덤 +(같은 질문 = 같은 답) (창의적, 횡설수설 가능) +``` + +- `0.0` → 항상 가장 확률 높은 토큰 선택 +- `0.7` → 일반 대화에 적합 +- `1.0+` → 창의적 글쓰기 + +### `--default-top-p` (Nucleus Sampling) + +누적 확률 상위 p%에 드는 토큰만 후보로 남깁니다. + +``` +예: top-p = 0.9 + [토큰A: 50%] [토큰B: 30%] [토큰C: 10%] | [토큰D: 5%] [토큰E: 3%] ... + ─────────── 상위 90% (후보) ────────── ──── 제외 ──── +``` + +- `0.9` → 희귀한 토큰 배제, 안정적 +- `1.0` → 필터 없음 + +### `--max-tokens` + +한 요청에서 생성할 최대 토큰 수입니다. + +- Qwen3.5는 **thinking 토큰 + 응답 토큰이 합산**됩니다 +- 너무 크면 thinking이 끝없이 돌 수 있음 +- **8192 권장** + +### `--mllm` + +멀티모달 모드를 활성화합니다. 이 플래그가 없으면 텍스트만 처리합니다. + +### `--continuous-batching` + +여러 요청을 동시에 처리합니다. **단일 사용자일 때는 오히려 느려지므로**, 동시 사용자가 있을 때만 사용하세요. + +### `--reasoning-parser qwen3` + +Qwen3.5의 `...` thinking 내용을 별도 `reasoning_content` 필드로 추출합니다. Open WebUI에서 thinking 과정을 보고 싶을 때 유용합니다. + +--- + +# 6. 트러블슈팅 + +## 빠른 참조 + +| 증상 | 원인 | 해결 | +|------|------|------| +| thinking만 하고 응답 없음 | `--max-tokens`가 너무 큼 | 8192로 설정 후 서버 재시작 | +| conda에서 abort / MPI 에러 | MPICH 충돌 | `conda deactivate` 후 venv에서 실행 | +| 이미지 입력 안 됨 | `--mllm` 미설정 | 서버 시작 시 `--mllm` 추가 | +| 모델이 안 보임 | 서버 미실행 | `curl http://localhost:8090/v1/models` 확인 | +| 컨테이너 안 뜸 | Docker 문제 | `docker logs open-webui-mlx` 확인 | +| 포트 충돌 | 이미 사용 중 | `lsof -i :3000` / `lsof -i :8090` | +| 요청 타임아웃 | 기본 300초 초과 | `--timeout 600` 으로 늘리기 | +| 이미지 입력 시 PyTorch 텐서 에러 | transformers fast image processor 호환성 문제 | 아래 **[이미지 프로세서 호환성 문제](#이미지-프로세서-호환성-문제-transformers--mlx_vlm)** 참고 | +| 서버가 Ctrl+C로 안 꺼짐 | 프로세스가 응답 중 | `lsof -ti :8090 \| xargs kill -9` | + +--- + +## 이미지 프로세서 호환성 문제 (transformers + mlx_vlm) + +### 증상 + +`--mllm` 모드에서 이미지를 입력하면 아래 에러가 발생합니다: + +``` +ValueError: Failed to process inputs with error: Only returning PyTorch tensors is currently supported. +``` + +또는 Open WebUI에서: + +``` +Response payload is not completed: +``` + +### 원인 + +`vllm-mlx`는 내부적으로 `mlx_vlm`을 사용하여 이미지를 처리합니다. +`mlx_vlm`은 `transformers` 라이브러리의 이미지 프로세서를 호출하는데, +`transformers >= 5.x`에서는 **Fast Image Processor**가 기본으로 로드됩니다. + +``` +요청 흐름: + Open WebUI → vllm-mlx → mlx_vlm → transformers (이미지 프로세서) → 에러 +``` + +문제의 핵심: + +| | Fast 버전 | Slow 버전 | +|---|---|---| +| 파일 | `image_processing_qwen2_vl_fast.py` | `image_processing_qwen2_vl.py` | +| 반환 형식 | **PyTorch 텐서만** 지원 | numpy 등 다양한 형식 지원 | +| mlx_vlm 호환 | ❌ | ✅ | + +`transformers`는 자동으로 fast 버전을 우선 로드하지만, +`mlx_vlm`은 PyTorch 텐서가 아닌 numpy/MLX 배열을 기대하므로 충돌이 발생합니다. + +### 해결 방법 + +fast 파일을 slow 클래스로 리다이렉트합니다. + +**1. fast 파일 위치 확인:** + +```bash +# venv 경로에 따라 다를 수 있음 +FAST_FILE="$(python -c "import transformers; import os; print(os.path.join(os.path.dirname(transformers.__file__), 'models/qwen2_vl/image_processing_qwen2_vl_fast.py'))")" +echo "$FAST_FILE" +``` + +**2. 원본 백업:** + +```bash +cp "$FAST_FILE" "${FAST_FILE}.bak" +``` + +**3. fast 파일을 slow 버전으로 리다이렉트:** + +```bash +cat > "$FAST_FILE" << 'EOF' +""" +Fast Image processor class for Qwen2-VL. +Patched: mlx_vlm 호환을 위해 slow 버전으로 폴백합니다. +원본: image_processing_qwen2_vl_fast.py.bak +""" + +from .image_processing_qwen2_vl import Qwen2VLImageProcessor as Qwen2VLImageProcessorFast + +__all__ = ["Qwen2VLImageProcessorFast"] +EOF +``` + +**4. 서버 재시작 후 이미지 테스트** + +### 복원 방법 + +패치를 되돌리려면: + +```bash +FAST_FILE="$(python -c "import transformers; import os; print(os.path.join(os.path.dirname(transformers.__file__), 'models/qwen2_vl/image_processing_qwen2_vl_fast.py'))")" +cp "${FAST_FILE}.bak" "$FAST_FILE" +``` + +### 언제 이 패치가 필요 없어지나 + +- `mlx_vlm`이 fast image processor를 지원하게 업데이트되면 +- `transformers`가 PyTorch 외의 텐서 반환을 지원하면 +- `vllm-mlx`가 자체 이미지 프로세싱을 구현하면 + +`pip install --upgrade mlx-vlm` 후 이미지 테스트가 정상이면 패치를 복원해도 됩니다. + +--- + +# 부록: docker-compose.mlx.yml 생성 + +> `~/PyCharmMiscProject/openwebui/docker-compose.mlx.yml`이 없을 때만 실행하세요. + +```bash +mkdir -p ~/PyCharmMiscProject/openwebui +cd ~/PyCharmMiscProject/openwebui + +cat > docker-compose.mlx.yml << 'EOF' +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui-mlx + ports: + - "3000:8080" + environment: + - OPENAI_API_BASE_URL=http://host.docker.internal:8090/v1 + - OPENAI_API_KEY=none + - OLLAMA_BASE_URL= + volumes: + - open-webui-mlx-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-mlx-data: +EOF +``` diff --git a/SETUP_OLLAMA.md b/SETUP_OLLAMA.md new file mode 100644 index 0000000..6556456 --- /dev/null +++ b/SETUP_OLLAMA.md @@ -0,0 +1,127 @@ +# Qwen3.5 + Open WebUI — Ollama 방식 (간편) + +> 환경: MacBook Pro M4 Pro 48GB / Docker Desktop / Homebrew + +--- + +## 0. 사전 요구사항 + +- Docker Desktop이 설치되어 있고 실행 중이어야 합니다 +- Homebrew가 설치되어 있어야 합니다 + +```bash +docker --version +brew --version +``` + +## 1. Ollama 설치 및 시작 + +```bash +brew install ollama +brew services start ollama +``` + +## 2. Qwen3.5 모델 다운로드 + +```bash +ollama pull qwen3.5:35b +``` + +## 3. 모델 확인 및 테스트 + +```bash +ollama list +ollama run qwen3.5:35b "안녕하세요, 자기소개 해주세요" +``` + +> 나가려면 `/bye` 입력 + +## 4. 프로젝트 디렉터리 생성 + +```bash +mkdir -p ~/PyCharmMiscProject/openwebui +cd ~/PyCharmMiscProject/openwebui +``` + +## 5. docker-compose.yml 생성 + +```bash +cat > docker-compose.yml << 'EOF' +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui + ports: + - "3000:8080" + environment: + - OLLAMA_BASE_URL=http://host.docker.internal:11434 + volumes: + - open-webui-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-data: +EOF +``` + +## 6. Open WebUI 실행 + +```bash +docker compose up -d +``` + +## 7. 확인 + +```bash +docker ps +curl http://localhost:11434/api/tags +``` + +## 8. 브라우저 접속 + +``` +http://localhost:3000 +``` + +1. 첫 접속 시 회원가입 (로컬 전용, 첫 계정 = admin) +2. 상단 모델 선택에서 **qwen3.5:35b** 선택 +3. 채팅 시작 + +--- + +## 종료 + +```bash +cd ~/PyCharmMiscProject/openwebui && docker compose down +brew services stop ollama +``` + +## 재시작 + +```bash +brew services start ollama +cd ~/PyCharmMiscProject/openwebui && docker compose up -d +``` + +## 트러블슈팅 + +### 모델이 안 보일 때 + +```bash +brew services list | grep ollama +curl http://localhost:11434/api/tags +``` + +### 컨테이너가 안 뜰 때 + +```bash +docker logs open-webui +``` + +### 포트 충돌 시 + +```bash +lsof -i :3000 +``` diff --git a/docker-compose.mlx.yml b/docker-compose.mlx.yml new file mode 100644 index 0000000..a668c2d --- /dev/null +++ b/docker-compose.mlx.yml @@ -0,0 +1,18 @@ +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui-mlx + ports: + - "3000:8080" + environment: + - OPENAI_API_BASE_URL=http://host.docker.internal:8090/v1 + - OPENAI_API_KEY=none + - OLLAMA_BASE_URL= + volumes: + - open-webui-mlx-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-mlx-data: diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..be520d6 --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,16 @@ +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui + ports: + - "3000:8080" + environment: + - OLLAMA_BASE_URL=http://host.docker.internal:11434 + volumes: + - open-webui-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-data: diff --git a/setup-mlx.sh b/setup-mlx.sh new file mode 100755 index 0000000..2278950 --- /dev/null +++ b/setup-mlx.sh @@ -0,0 +1,219 @@ +#!/bin/bash +set -e + +#==================================================================== +# Qwen3.5 + Open WebUI (vllm-mlx) 원클릭 셋업 +# 환경: Apple Silicon Mac (M1/M2/M3/M4) / Docker Desktop / Python 3.10+ +#==================================================================== + +VENV_DIR="$HOME/mlx-env" +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODEL="mlx-community/Qwen3.5-35B-A3B-4bit" +PORT=8090 +WEBUI_PORT=3000 + +echo "============================================" +echo " Qwen3.5 + Open WebUI (vllm-mlx) 셋업" +echo "============================================" +echo "" + +#-------------------------------------------------------------------- +# 1. 사전 요구사항 확인 +#-------------------------------------------------------------------- +echo "[1/6] 사전 요구사항 확인..." + +# Python +if ! command -v python3 &>/dev/null; then + echo "❌ python3가 설치되어 있지 않습니다." + exit 1 +fi +PYTHON_VERSION=$(python3 -c "import sys; print(f'{sys.version_info.major}.{sys.version_info.minor}')") +PYTHON_MAJOR=$(echo "$PYTHON_VERSION" | cut -d. -f1) +PYTHON_MINOR=$(echo "$PYTHON_VERSION" | cut -d. -f2) +if [ "$PYTHON_MAJOR" -lt 3 ] || { [ "$PYTHON_MAJOR" -eq 3 ] && [ "$PYTHON_MINOR" -lt 10 ]; }; then + echo "❌ Python 3.10 이상이 필요합니다. (현재: $PYTHON_VERSION)" + exit 1 +fi +echo " ✓ Python $PYTHON_VERSION" + +# Docker +if ! command -v docker &>/dev/null; then + echo "❌ Docker가 설치되어 있지 않습니다." + exit 1 +fi +if ! docker info &>/dev/null; then + echo "❌ Docker Desktop이 실행 중이 아닙니다." + exit 1 +fi +echo " ✓ Docker" + +# Apple Silicon +if ! sysctl -n machdep.cpu.brand_string 2>/dev/null | grep -q "Apple"; then + echo "❌ Apple Silicon이 아닙니다. MLX는 Apple Silicon에서만 동작합니다." + exit 1 +fi +echo " ✓ Apple Silicon" + +# RAM +TOTAL_RAM_GB=$(sysctl -n hw.memsize | awk '{printf "%.0f", $1/1024/1024/1024}') +echo " ✓ RAM: ${TOTAL_RAM_GB}GB" +if [ "$TOTAL_RAM_GB" -lt 32 ]; then + echo " ⚠️ RAM이 32GB 미만입니다. 4bit 모델(~20GB)도 빡빡할 수 있습니다." +fi + +echo "" + +#-------------------------------------------------------------------- +# 2. 가상환경 생성 및 패키지 설치 +#-------------------------------------------------------------------- +echo "[2/6] 가상환경 및 패키지 설치..." + +# conda 감지 경고 +if [ -n "$CONDA_DEFAULT_ENV" ]; then + echo " ⚠️ conda 환경 감지 ($CONDA_DEFAULT_ENV)." + echo " MPICH 충돌 방지를 위해 별도 venv를 사용합니다." +fi + +if [ ! -d "$VENV_DIR" ]; then + python3 -m venv "$VENV_DIR" + echo " ✓ 가상환경 생성: $VENV_DIR" +else + echo " ✓ 기존 가상환경 사용: $VENV_DIR" +fi + +source "$VENV_DIR/bin/activate" + +# vllm-mlx +if ! pip show vllm-mlx &>/dev/null; then + echo " vllm-mlx 설치 중... (시간이 걸릴 수 있습니다)" + pip install -q git+https://github.com/waybarrios/vllm-mlx.git + echo " ✓ vllm-mlx 설치 완료" +else + echo " ✓ vllm-mlx 이미 설치됨" +fi + +# torch, torchvision +if ! pip show torch &>/dev/null; then + echo " torch, torchvision 설치 중..." + pip install -q torch torchvision + echo " ✓ torch 설치 완료" +else + echo " ✓ torch 이미 설치됨" +fi + +echo "" + +#-------------------------------------------------------------------- +# 3. transformers fast image processor 패치 +# 원인: transformers >= 5.x의 fast image processor가 PyTorch 텐서만 +# 반환하지만, mlx_vlm은 numpy/MLX 배열을 기대하여 충돌 발생. +# 해결: fast 클래스를 slow 클래스로 리다이렉트. +#-------------------------------------------------------------------- +echo "[3/6] 이미지 프로세서 호환성 패치..." + +FAST_FILE=$("$VENV_DIR/bin/python3" -c " +import transformers, os +print(os.path.join(os.path.dirname(transformers.__file__), + 'models/qwen2_vl/image_processing_qwen2_vl_fast.py')) +") + +if grep -q "mlx_vlm 호환" "$FAST_FILE" 2>/dev/null; then + echo " ✓ 이미 패치 적용됨" +else + cp "$FAST_FILE" "${FAST_FILE}.bak" + + cat > "$FAST_FILE" << 'PATCH' +""" +Fast Image processor class for Qwen2-VL. +Patched: mlx_vlm 호환을 위해 slow 버전으로 폴백합니다. +원본: image_processing_qwen2_vl_fast.py.bak + +배경: + transformers >= 5.x는 Fast Image Processor를 기본 로드합니다. + Fast 버전은 PyTorch 텐서만 반환하지만, mlx_vlm은 numpy/MLX 배열을 기대합니다. + 이 패치는 fast 클래스를 slow 클래스로 대체하여 호환성을 확보합니다. + +복원: + cp image_processing_qwen2_vl_fast.py.bak image_processing_qwen2_vl_fast.py +""" + +from .image_processing_qwen2_vl import Qwen2VLImageProcessor as Qwen2VLImageProcessorFast + +__all__ = ["Qwen2VLImageProcessorFast"] +PATCH + + echo " ✓ 패치 적용 완료 (원본 백업됨)" +fi + +echo "" + +#-------------------------------------------------------------------- +# 4. Docker Compose 설정 +#-------------------------------------------------------------------- +echo "[4/6] Docker Compose 설정..." + +if [ ! -f "$PROJECT_DIR/docker-compose.mlx.yml" ]; then + cat > "$PROJECT_DIR/docker-compose.mlx.yml" << EOF +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui-mlx + ports: + - "${WEBUI_PORT}:8080" + environment: + - OPENAI_API_BASE_URL=http://host.docker.internal:${PORT}/v1 + - OPENAI_API_KEY=none + - OLLAMA_BASE_URL= + volumes: + - open-webui-mlx-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-mlx-data: +EOF + echo " ✓ docker-compose.mlx.yml 생성" +else + echo " ✓ docker-compose.mlx.yml 이미 존재" +fi + +echo "" + +#-------------------------------------------------------------------- +# 5. Open WebUI 실행 +#-------------------------------------------------------------------- +echo "[5/6] Open WebUI 실행..." + +cd "$PROJECT_DIR" +docker compose -f docker-compose.mlx.yml up -d 2>&1 | grep -v "^$" +echo " ✓ Open WebUI 실행 중 (http://localhost:${WEBUI_PORT})" + +echo "" + +#-------------------------------------------------------------------- +# 6. 완료 +#-------------------------------------------------------------------- +echo "[6/6] 셋업 완료!" +echo "" +echo "============================================" +echo " 다음 단계: 서버를 시작하세요" +echo "============================================" +echo "" +echo " # 텍스트 전용:" +echo " source $VENV_DIR/bin/activate" +echo " vllm-mlx serve $MODEL \\" +echo " --port $PORT --max-tokens 8192 \\" +echo " --default-temperature 0.7 --default-top-p 0.9" +echo "" +echo " # 텍스트 + 이미지 (멀티모달):" +echo " source $VENV_DIR/bin/activate" +echo " vllm-mlx serve $MODEL \\" +echo " --port $PORT --max-tokens 8192 \\" +echo " --default-temperature 0.7 --default-top-p 0.9 --mllm" +echo "" +echo " 서버 시작 후 브라우저에서 http://localhost:${WEBUI_PORT} 접속" +echo " (첫 접속 시 회원가입 → 첫 계정이 admin)" +echo "" +echo " 종료하려면: ./stop-mlx.sh" +echo "============================================" diff --git a/setup-ollama.sh b/setup-ollama.sh new file mode 100755 index 0000000..9043ded --- /dev/null +++ b/setup-ollama.sh @@ -0,0 +1,117 @@ +#!/bin/bash +set -e + +#==================================================================== +# Qwen3.5 + Open WebUI (Ollama) 원클릭 셋업 +# 환경: Mac / Docker Desktop / Homebrew +#==================================================================== + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +MODEL="qwen3.5:35b" +WEBUI_PORT=3000 + +echo "============================================" +echo " Qwen3.5 + Open WebUI (Ollama) 셋업" +echo "============================================" +echo "" + +#-------------------------------------------------------------------- +# 1. 사전 요구사항 확인 +#-------------------------------------------------------------------- +echo "[1/5] 사전 요구사항 확인..." + +if ! command -v brew &>/dev/null; then + echo "❌ Homebrew가 설치되어 있지 않습니다." + echo " /bin/bash -c \"\$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"" + exit 1 +fi +echo " ✓ Homebrew" + +if ! command -v docker &>/dev/null; then + echo "❌ Docker가 설치되어 있지 않습니다." + exit 1 +fi +if ! docker info &>/dev/null; then + echo "❌ Docker Desktop이 실행 중이 아닙니다." + exit 1 +fi +echo " ✓ Docker" + +echo "" + +#-------------------------------------------------------------------- +# 2. Ollama 설치 및 시작 +#-------------------------------------------------------------------- +echo "[2/5] Ollama 설치..." + +if ! command -v ollama &>/dev/null; then + brew install ollama + echo " ✓ Ollama 설치 완료" +else + echo " ✓ Ollama 이미 설치됨" +fi + +if ! brew services list | grep ollama | grep -q started; then + brew services start ollama + sleep 3 + echo " ✓ Ollama 서비스 시작" +else + echo " ✓ Ollama 서비스 실행 중" +fi + +echo "" + +#-------------------------------------------------------------------- +# 3. 모델 다운로드 +#-------------------------------------------------------------------- +echo "[3/5] 모델 다운로드 ($MODEL)..." +echo " (네트워크 속도에 따라 시간이 걸릴 수 있습니다)" + +ollama pull "$MODEL" +echo " ✓ 모델 다운로드 완료" + +echo "" + +#-------------------------------------------------------------------- +# 4. Docker Compose 설정 및 실행 +#-------------------------------------------------------------------- +echo "[4/5] Open WebUI 실행..." + +if [ ! -f "$PROJECT_DIR/docker-compose.yml" ]; then + cat > "$PROJECT_DIR/docker-compose.yml" << EOF +services: + open-webui: + image: ghcr.io/open-webui/open-webui:main + container_name: open-webui + ports: + - "${WEBUI_PORT}:8080" + environment: + - OLLAMA_BASE_URL=http://host.docker.internal:11434 + volumes: + - open-webui-data:/app/backend/data + extra_hosts: + - "host.docker.internal:host-gateway" + restart: unless-stopped + +volumes: + open-webui-data: +EOF + echo " ✓ docker-compose.yml 생성" +fi + +cd "$PROJECT_DIR" +docker compose up -d 2>&1 | grep -v "^$" +echo " ✓ Open WebUI 실행 중" + +echo "" + +#-------------------------------------------------------------------- +# 5. 완료 +#-------------------------------------------------------------------- +echo "[5/5] 셋업 완료!" +echo "" +echo "============================================" +echo " 브라우저에서 http://localhost:${WEBUI_PORT} 접속" +echo " (첫 접속 시 회원가입 → 첫 계정이 admin)" +echo " 모델 선택: $MODEL" +echo "============================================" diff --git a/stop-mlx.sh b/stop-mlx.sh new file mode 100755 index 0000000..3dac1c6 --- /dev/null +++ b/stop-mlx.sh @@ -0,0 +1,37 @@ +#!/bin/bash + +#==================================================================== +# vllm-mlx + Open WebUI 종료 +#==================================================================== + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" +PORT=8090 + +echo "============================================" +echo " vllm-mlx + Open WebUI 종료" +echo "============================================" +echo "" + +# Open WebUI 컨테이너 종료 +if docker ps -q --filter name=open-webui-mlx | grep -q .; then + cd "$PROJECT_DIR" + docker compose -f docker-compose.mlx.yml down 2>&1 | grep -v "^$" + echo " ✓ Open WebUI 종료" +else + echo " - Open WebUI 컨테이너 없음 (이미 종료됨)" +fi + +# vllm-mlx 서버 종료 +PIDS=$(lsof -ti :$PORT 2>/dev/null || true) +if [ -n "$PIDS" ]; then + echo "$PIDS" | xargs kill -9 2>/dev/null || true + echo " ✓ vllm-mlx 서버 종료 (포트 $PORT)" +else + echo " - vllm-mlx 서버 없음 (이미 종료됨)" +fi + +echo "" +echo " 완료. 재시작하려면:" +echo " 1. ./setup-mlx.sh" +echo " 2. 서버 시작 (setup 완료 시 안내되는 명령어 참고)" +echo "" diff --git a/stop-ollama.sh b/stop-ollama.sh new file mode 100755 index 0000000..a6fa10d --- /dev/null +++ b/stop-ollama.sh @@ -0,0 +1,33 @@ +#!/bin/bash + +#==================================================================== +# Ollama + Open WebUI 종료 +#==================================================================== + +PROJECT_DIR="$(cd "$(dirname "$0")" && pwd)" + +echo "============================================" +echo " Ollama + Open WebUI 종료" +echo "============================================" +echo "" + +# Open WebUI 컨테이너 종료 +if docker ps -q --filter name=open-webui | grep -q .; then + cd "$PROJECT_DIR" + docker compose down 2>&1 | grep -v "^$" + echo " ✓ Open WebUI 종료" +else + echo " - Open WebUI 컨테이너 없음 (이미 종료됨)" +fi + +# Ollama 서비스 종료 +if brew services list 2>/dev/null | grep ollama | grep -q started; then + brew services stop ollama + echo " ✓ Ollama 서비스 종료" +else + echo " - Ollama 이미 종료됨" +fi + +echo "" +echo " 완료. 재시작하려면: ./setup-ollama.sh" +echo ""