feat: complete release preparation, 10+ ad mediation, CI/CD, and docker deployment
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
Some checks failed
CI Pipeline / Code Quality & Typecheck (push) Waiting to run
CI Pipeline / Test Suite (macos-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (ubuntu-latest) (push) Blocked by required conditions
CI Pipeline / Test Suite (windows-latest) (push) Blocked by required conditions
CI Pipeline / Build Validation (admin) (push) Blocked by required conditions
CI Pipeline / Build Validation (desktop) (push) Blocked by required conditions
Deploy Landing Page / deploy (push) Blocked by required conditions
Deploy Landing Page / build (push) Waiting to run
Release & Packaging Pipeline / Build & Publish Admin Docker Image (push) Failing after 8s
Release & Code Signing CA Pipeline / build-and-sign-windows (push) Failing after 1m51s
Build macOS / Build & Package (macOS) (push) Failing after 4s
Build macOS / Build & Package (macOS)-1 (push) Failing after 5s
Release & Code Signing CA Pipeline / build-and-sign-macos (push) Failing after 3s
Release & Packaging Pipeline / Package macOS Desktop App (push) Failing after 4s
Release & Packaging Pipeline / Package Windows Desktop App (push) Failing after 2m28s
Release & Packaging Pipeline / Publish Official GitHub Release (push) Has been skipped
This commit is contained in:
parent
5cd1de6859
commit
708e20f747
406 changed files with 42464 additions and 6199 deletions
|
|
@ -1,138 +0,0 @@
|
|||
"""
|
||||
scripts/build-sidecar.py
|
||||
faster-whisper sidecar를 PyInstaller로 빌드한다. (크로스 플랫폼)
|
||||
|
||||
사용법:
|
||||
pip install pyinstaller
|
||||
pip install -r sidecar/requirements.txt
|
||||
python scripts/build-sidecar.py
|
||||
|
||||
출력:
|
||||
sidecar-dist/sidecar/sidecar(.exe) (onedir 모드)
|
||||
|
||||
플랫폼:
|
||||
Windows → --noconsole (콘솔 창 숨김)
|
||||
macOS → --windowed (.app 번들 형식은 여기서는 미사용, onedir만)
|
||||
Linux → 콘솔 옵션 없음
|
||||
"""
|
||||
|
||||
import platform
|
||||
import subprocess
|
||||
import sys
|
||||
import shutil
|
||||
from pathlib import Path
|
||||
|
||||
PROJECT_ROOT = Path(__file__).parent.parent
|
||||
SIDECAR_DIR = PROJECT_ROOT / "sidecar"
|
||||
MAIN_PY = SIDECAR_DIR / "main.py"
|
||||
OUTPUT_DIR = PROJECT_ROOT / "sidecar-dist"
|
||||
|
||||
IS_WINDOWS = platform.system() == "Windows"
|
||||
IS_MACOS = platform.system() == "Darwin"
|
||||
EXE_SUFFIX = ".exe" if IS_WINDOWS else ""
|
||||
|
||||
|
||||
def check_prerequisites():
|
||||
"""필수 도구가 설치되어 있는지 확인한다."""
|
||||
try:
|
||||
import PyInstaller # noqa: F401
|
||||
except ImportError:
|
||||
print("PyInstaller가 설치되어 있지 않습니다.")
|
||||
print("실행: pip install pyinstaller")
|
||||
sys.exit(1)
|
||||
|
||||
try:
|
||||
import faster_whisper # noqa: F401
|
||||
except ImportError:
|
||||
print("faster-whisper가 설치되어 있지 않습니다.")
|
||||
print("실행: pip install -r sidecar/requirements.txt")
|
||||
sys.exit(1)
|
||||
|
||||
if not MAIN_PY.exists():
|
||||
print(f"sidecar 소스를 찾을 수 없습니다: {MAIN_PY}")
|
||||
sys.exit(1)
|
||||
|
||||
|
||||
def build():
|
||||
"""PyInstaller로 sidecar를 빌드한다."""
|
||||
print("=" * 60)
|
||||
print(f"D3RO-VOICE Sidecar 빌드 시작 ({platform.system()} {platform.machine()})")
|
||||
print("=" * 60)
|
||||
|
||||
# 기존 빌드 정리
|
||||
if OUTPUT_DIR.exists():
|
||||
shutil.rmtree(OUTPUT_DIR)
|
||||
|
||||
cmd = [
|
||||
sys.executable, "-m", "PyInstaller",
|
||||
"--name", "sidecar",
|
||||
"--distpath", str(OUTPUT_DIR),
|
||||
"--workpath", str(PROJECT_ROOT / "build" / "sidecar-build"),
|
||||
"--specpath", str(PROJECT_ROOT / "build"),
|
||||
"--noconfirm",
|
||||
"--clean",
|
||||
# hidden imports
|
||||
"--hidden-import", "faster_whisper",
|
||||
"--hidden-import", "ctranslate2",
|
||||
"--hidden-import", "huggingface_hub",
|
||||
"--hidden-import", "tokenizers",
|
||||
"--hidden-import", "uvicorn.logging",
|
||||
"--hidden-import", "uvicorn.protocols.http",
|
||||
"--hidden-import", "uvicorn.protocols.http.auto",
|
||||
"--hidden-import", "uvicorn.protocols.http.h11_impl",
|
||||
"--hidden-import", "uvicorn.protocols.websockets",
|
||||
"--hidden-import", "uvicorn.protocols.websockets.auto",
|
||||
"--hidden-import", "uvicorn.lifespan",
|
||||
"--hidden-import", "uvicorn.lifespan.on",
|
||||
"--hidden-import", "uvicorn.lifespan.off",
|
||||
]
|
||||
|
||||
# 플랫폼별 콘솔 옵션
|
||||
if IS_WINDOWS:
|
||||
cmd.append("--noconsole")
|
||||
elif IS_MACOS:
|
||||
# macOS에서 --windowed는 .app 번들 생성을 의미.
|
||||
# onedir 모드로도 .app이 만들어질 수 있어서 명시적으로는 쓰지 않음.
|
||||
# electron-builder가 extraResources로 Binary만 포함하므로 기본 콘솔 형태 유지.
|
||||
pass
|
||||
# Linux: 옵션 없음
|
||||
|
||||
cmd.append(str(MAIN_PY))
|
||||
|
||||
print(f"\n실행 명령:\n {' '.join(cmd)}\n")
|
||||
|
||||
result = subprocess.run(cmd, cwd=str(PROJECT_ROOT))
|
||||
|
||||
if result.returncode != 0:
|
||||
print(f"\nPyInstaller 빌드 실패 (exit code: {result.returncode})")
|
||||
sys.exit(1)
|
||||
|
||||
# 빌드 결과 확인
|
||||
exe_path = OUTPUT_DIR / "sidecar" / f"sidecar{EXE_SUFFIX}"
|
||||
if exe_path.exists():
|
||||
size_mb = exe_path.stat().st_size / (1024 * 1024)
|
||||
print(f"\n빌드 성공!")
|
||||
print(f" 경로: {exe_path}")
|
||||
print(f" 크기: {size_mb:.1f} MB")
|
||||
|
||||
total_size = sum(
|
||||
f.stat().st_size for f in (OUTPUT_DIR / "sidecar").rglob("*") if f.is_file()
|
||||
)
|
||||
total_mb = total_size / (1024 * 1024)
|
||||
print(f" 전체 디렉토리: {total_mb:.1f} MB")
|
||||
else:
|
||||
print(f"\n빌드 출력을 찾을 수 없습니다: {exe_path}")
|
||||
# onedir 모드에서는 디렉토리 내부에 바이너리가 있음
|
||||
pattern = "*.exe" if IS_WINDOWS else "sidecar"
|
||||
for item in OUTPUT_DIR.rglob(pattern):
|
||||
print(f" 발견: {item}")
|
||||
|
||||
print("\n빌드 완료!")
|
||||
print("electron-builder에서 이 경로를 extraResources로 지정하세요:")
|
||||
print(" from: sidecar-dist/sidecar/")
|
||||
print(" to: sidecar/")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_prerequisites()
|
||||
build()
|
||||
|
|
@ -1,103 +0,0 @@
|
|||
# scripts/download-ollama.ps1
|
||||
# Downloads the portable Ollama Windows binary into resources/ollama/.
|
||||
# Usage: powershell -ExecutionPolicy Bypass -File scripts/download-ollama.ps1
|
||||
#
|
||||
# Note: Ollama only ships an NSIS installer officially. We use the
|
||||
# ollama-windows-amd64.zip release asset on GitHub instead.
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$OLLAMA_VERSION = if ($env:OLLAMA_VERSION) { $env:OLLAMA_VERSION } else { "v0.32.1" }
|
||||
$OLLAMA_URL = "https://github.com/ollama/ollama/releases/download/$OLLAMA_VERSION/ollama-windows-amd64.zip"
|
||||
$DEST_DIR = Join-Path $PSScriptRoot "..\resources\ollama"
|
||||
$TEMP_ZIP = Join-Path $env:TEMP "ollama-$OLLAMA_VERSION-windows-amd64.zip"
|
||||
$TEMP_DIR = Join-Path $env:TEMP "ollama-extract"
|
||||
$VERSION_STAMP = Join-Path $DEST_DIR ".ollama-version"
|
||||
|
||||
Write-Host "=== Ollama $OLLAMA_VERSION (Windows amd64) ===" -ForegroundColor Cyan
|
||||
|
||||
# Version-aware cache: CI runner reuses the checkout dir, so an old bundle can
|
||||
# linger. Re-download whenever the stamped version differs from the wanted one.
|
||||
if (Test-Path (Join-Path $DEST_DIR "ollama.exe")) {
|
||||
$stamped = if (Test-Path $VERSION_STAMP) { (Get-Content $VERSION_STAMP -Raw).Trim() } else { "" }
|
||||
if ($stamped -eq $OLLAMA_VERSION) {
|
||||
Write-Host "Ollama $OLLAMA_VERSION already present: $DEST_DIR\ollama.exe" -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
Write-Host "Cached Ollama version '$stamped' != '$OLLAMA_VERSION' - re-downloading" -ForegroundColor Yellow
|
||||
Remove-Item -Recurse -Force $DEST_DIR
|
||||
}
|
||||
|
||||
if (Test-Path $TEMP_ZIP) { Remove-Item -Force $TEMP_ZIP }
|
||||
|
||||
Write-Host "Downloading: $OLLAMA_URL"
|
||||
# curl.exe (Win10+ native) handles GitHub redirects, progress output, large files
|
||||
# better than Invoke-WebRequest. -L follow redirects, --fail error on HTTP >=400,
|
||||
# --retry 3, --max-time 1800 (30min), --progress-bar human readable.
|
||||
$curlExe = "$env:SystemRoot\System32\curl.exe"
|
||||
if (-not (Test-Path $curlExe)) { $curlExe = "curl.exe" }
|
||||
& $curlExe -L --fail --retry 3 --max-time 1800 --progress-bar `
|
||||
-o $TEMP_ZIP $OLLAMA_URL
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "curl download failed with exit code $LASTEXITCODE" -ForegroundColor Red
|
||||
Write-Host ""
|
||||
Write-Host "=== Manual install ===" -ForegroundColor Yellow
|
||||
Write-Host "Download ollama-windows-amd64.zip from:"
|
||||
Write-Host " https://github.com/ollama/ollama/releases"
|
||||
Write-Host "and extract its contents into:"
|
||||
Write-Host " $DEST_DIR"
|
||||
exit 1
|
||||
}
|
||||
|
||||
$fileSize = (Get-Item $TEMP_ZIP).Length
|
||||
if ($fileSize -lt 1000000) {
|
||||
Write-Host ("Downloaded file too small ({0} bytes)." -f $fileSize) -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$sizeMB = [math]::Round($fileSize / 1MB, 1)
|
||||
Write-Host ("Download complete ({0} MB)" -f $sizeMB)
|
||||
Write-Host "Extracting..."
|
||||
|
||||
if (Test-Path $TEMP_DIR) { Remove-Item -Recurse -Force $TEMP_DIR }
|
||||
Expand-Archive -Path $TEMP_ZIP -DestinationPath $TEMP_DIR -Force
|
||||
|
||||
New-Item -ItemType Directory -Force -Path $DEST_DIR | Out-Null
|
||||
|
||||
# zip layout: ollama.exe + lib/ (runners + DLLs).
|
||||
# Prune GPU runners (CUDA v11/v12, ROCm) to keep installer under NSIS 2GB limit.
|
||||
# CPU runners (cpu_avx2, cpu_avx) are sufficient for initial bundle; users needing GPU
|
||||
# can install Ollama separately or via future builds.
|
||||
Get-ChildItem -Path $TEMP_DIR -Force | ForEach-Object {
|
||||
Copy-Item $_.FullName -Destination $DEST_DIR -Recurse -Force
|
||||
Write-Host (" copied: {0}" -f $_.Name) -ForegroundColor Green
|
||||
}
|
||||
|
||||
# Remove heavy GPU runtimes to stay below NSIS size limits.
|
||||
# Layout differs across versions (old: lib\ollama\runners\cuda*, new: lib\ollama\cuda_v12 etc.)
|
||||
# so prune ANY cuda*/rocm* directory recursively - version-agnostic.
|
||||
Get-ChildItem -Path $DEST_DIR -Directory -Recurse |
|
||||
Where-Object { $_.Name -like "cuda*" -or $_.Name -like "rocm*" } |
|
||||
ForEach-Object {
|
||||
if (Test-Path $_.FullName) {
|
||||
Remove-Item -Recurse -Force $_.FullName
|
||||
Write-Host (" pruned GPU runtime: {0}" -f $_.FullName.Substring($DEST_DIR.Length)) -ForegroundColor Yellow
|
||||
}
|
||||
}
|
||||
|
||||
Remove-Item -Recurse -Force $TEMP_DIR -ErrorAction SilentlyContinue
|
||||
Remove-Item -Force $TEMP_ZIP -ErrorAction SilentlyContinue
|
||||
|
||||
if (Test-Path (Join-Path $DEST_DIR "ollama.exe")) {
|
||||
Set-Content -Path $VERSION_STAMP -Value $OLLAMA_VERSION
|
||||
$totalSize = (Get-ChildItem $DEST_DIR -Recurse -File | Measure-Object -Property Length -Sum).Sum
|
||||
$totalMB = [math]::Round($totalSize / 1MB, 0)
|
||||
Write-Host ""
|
||||
Write-Host ("Ollama $OLLAMA_VERSION installed: {0} (pruned total {1} MB)" -f $DEST_DIR, $totalMB) -ForegroundColor Green
|
||||
if ($totalSize -gt 1500MB) {
|
||||
Write-Host "WARNING: pruned bundle exceeds 1.5GB - NSIS 2GB installer limit at risk" -ForegroundColor Red
|
||||
}
|
||||
} else {
|
||||
Write-Host "ollama.exe not found after extraction. Inspect the zip layout." -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
|
@ -1,85 +0,0 @@
|
|||
#!/usr/bin/env bash
|
||||
# scripts/download-ollama.sh
|
||||
# Ollama 포터블 바이너리를 resources/ollama/에 배치한다. (macOS/Linux)
|
||||
# 실행: bash scripts/download-ollama.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
OLLAMA_VERSION="${OLLAMA_VERSION:-v0.32.1}"
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
DEST_DIR="$SCRIPT_DIR/../resources/ollama"
|
||||
VERSION_STAMP="$DEST_DIR/.ollama-version"
|
||||
|
||||
OS="$(uname -s)"
|
||||
ARCH="$(uname -m)"
|
||||
|
||||
case "$OS" in
|
||||
Darwin)
|
||||
# v0.6+ 기준 tgz 제공 (metal 포함, ~145MB). v0.5.x는 단일 바이너리였음.
|
||||
ASSET="ollama-darwin.tgz"
|
||||
;;
|
||||
Linux)
|
||||
if [ "$ARCH" = "aarch64" ] || [ "$ARCH" = "arm64" ]; then
|
||||
ASSET="ollama-linux-arm64.tgz"
|
||||
else
|
||||
ASSET="ollama-linux-amd64.tgz"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "지원하지 않는 OS: $OS" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
URL="https://github.com/ollama/ollama/releases/download/${OLLAMA_VERSION}/${ASSET}"
|
||||
TMP="$(mktemp -d)"
|
||||
trap 'rm -rf "$TMP"' EXIT
|
||||
|
||||
# 버전 스탬프 캐시 무효화 — runner가 checkout 디렉토리를 재사용하므로
|
||||
# 구버전 번들이 남아있으면 갈아엎는다.
|
||||
if [ -f "$DEST_DIR/ollama" ]; then
|
||||
STAMPED="$(cat "$VERSION_STAMP" 2>/dev/null || echo '')"
|
||||
if [ "$STAMPED" = "$OLLAMA_VERSION" ]; then
|
||||
echo "Ollama ${OLLAMA_VERSION}가 이미 존재합니다: $DEST_DIR/ollama"
|
||||
exit 0
|
||||
fi
|
||||
echo "캐시된 Ollama 버전('$STAMPED') != '$OLLAMA_VERSION' — 재다운로드"
|
||||
rm -rf "$DEST_DIR"
|
||||
fi
|
||||
|
||||
mkdir -p "$DEST_DIR"
|
||||
|
||||
echo "=== Ollama ${OLLAMA_VERSION} ${OS} ${ARCH} 다운로드 ==="
|
||||
echo "URL: $URL"
|
||||
|
||||
curl -L --fail --retry 3 -o "$TMP/$ASSET" "$URL"
|
||||
|
||||
case "$ASSET" in
|
||||
*.tgz)
|
||||
tar -xzf "$TMP/$ASSET" -C "$TMP"
|
||||
# tgz 구조는 버전에 따라 bin/ollama 또는 루트 ollama — 둘 다 지원
|
||||
if [ -f "$TMP/bin/ollama" ]; then
|
||||
cp "$TMP/bin/ollama" "$DEST_DIR/ollama"
|
||||
elif [ -f "$TMP/ollama" ]; then
|
||||
cp "$TMP/ollama" "$DEST_DIR/ollama"
|
||||
else
|
||||
echo "ERROR: tgz 안에서 ollama 바이너리를 찾지 못했습니다" >&2
|
||||
find "$TMP" -maxdepth 2 -type f | head -20 >&2
|
||||
exit 1
|
||||
fi
|
||||
chmod +x "$DEST_DIR/ollama"
|
||||
# 라이브러리 동봉 (linux: CUDA/ROCm은 용량 문제로 제외, darwin: metal 등 유지)
|
||||
if [ -d "$TMP/lib" ]; then
|
||||
cp -R "$TMP/lib" "$DEST_DIR/"
|
||||
find "$DEST_DIR/lib" -maxdepth 3 -type d \( -name "cuda*" -o -name "rocm*" \) -exec rm -rf {} + 2>/dev/null || true
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
# 단일 실행 바이너리 asset
|
||||
cp "$TMP/$ASSET" "$DEST_DIR/ollama"
|
||||
chmod +x "$DEST_DIR/ollama"
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "$OLLAMA_VERSION" > "$VERSION_STAMP"
|
||||
echo "Ollama ${OLLAMA_VERSION} 설치 완료: $DEST_DIR ($(du -sh "$DEST_DIR" | cut -f1))"
|
||||
Loading…
Add table
Add a link
Reference in a new issue