diff --git a/.github/workflows/deploy-dmg.yml b/.github/workflows/deploy-dmg.yml index 3e79d7b7..807ff4ca 100644 --- a/.github/workflows/deploy-dmg.yml +++ b/.github/workflows/deploy-dmg.yml @@ -1,28 +1,59 @@ -name: Build macOS .dmg +name: Deploy macOS .dmg + on: workflow_call: workflow_dispatch: + pull_request: + jobs: build-macos-dmg: runs-on: macos-latest steps: - uses: actions/checkout@v4 + - name: Set up Python uses: actions/setup-python@v5 with: - python-version: '3.12' - - name: Install py2app - run: pip install py2app + python-version: '3.10' + + - name: Install tomli for version extraction + run: python -m pip install tomli + + - name: Extract version from pyproject.toml + id: get_version + run: | + VERSION=$(python -c "import tomli; print(tomli.load(open('pyproject.toml', 'rb'))['project']['version'])") + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Building version: $VERSION" + + - name: Create virtual environment + run: python -m venv .venv + + - name: Install dependencies and package + run: | + source .venv/bin/activate + pip install -U pip wheel setuptools + pip install py2app + # Install PyTorch CPU version (lighter for macOS) + pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu + # Install other dependencies + pip install clip-anytorch numpy scikit-learn pillow + # Install your package + pip install . + - name: Build .app bundle run: | + source .venv/bin/activate cd macos python setup.py py2app - - name: Create .dmg + + - name: Create .dmg with version run: | - hdiutil create -volname "PhotoMapAI" -srcfolder macos/dist/PhotoMapAI.app -ov -format UDZO PhotoMapAI.dmg + DMG_NAME="PhotoMapAI-v${{ steps.get_version.outputs.version }}.dmg" + hdiutil create -volname "PhotoMapAI" -srcfolder macos/dist/PhotoMapAI.app -ov -format UDZO "$DMG_NAME" + - name: Upload .dmg uses: actions/upload-artifact@v4 with: - name: PhotoMapAI.dmg - path: PhotoMapAI.dmg - \ No newline at end of file + name: PhotoMapAI-v${{ steps.get_version.outputs.version }} + path: PhotoMapAI-v${{ steps.get_version.outputs.version }}.dmg diff --git a/.github/workflows/deploy-pyinstaller.yml b/.github/workflows/deploy-pyinstaller.yml index b476be49..5f5756e7 100644 --- a/.github/workflows/deploy-pyinstaller.yml +++ b/.github/workflows/deploy-pyinstaller.yml @@ -3,13 +3,14 @@ name: Deploy PyInstaller Executables on: workflow_call: workflow_dispatch: + pull_request: jobs: build: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - torch_variant: [cpu, cu128] + torch_variant: [cpu, cu129] include: - os: ubuntu-latest platform: linux-x64 @@ -25,7 +26,7 @@ jobs: executable_ext: ".exe" exclude: - os: macos-latest - torch_variant: cu128 + torch_variant: cu129 runs-on: ${{ matrix.os }} steps: @@ -37,6 +38,25 @@ jobs: with: python-version: '3.12' + - name: Free up disk space (Linux/macOS) + if: matrix.torch_variant != 'cpu' && runner.os != 'Windows' + run: | + sudo rm -rf /usr/share/dotnet + sudo rm -rf /opt/ghc + sudo rm -rf /usr/local/share/boost + sudo rm -rf "$AGENT_TOOLSDIRECTORY" + df -h + shell: bash + + - name: Free up disk space (Windows) + if: matrix.torch_variant != 'cpu' && runner.os == 'Windows' + run: | + Get-PSDrive C + Remove-Item -Recurse -Force $env:TEMP\* -ErrorAction SilentlyContinue + pip cache purge + Get-PSDrive C + shell: pwsh + - name: Install tomli for version extraction (Linux/macOS) if: runner.os != 'Windows' run: python -m pip install tomli @@ -77,6 +97,7 @@ jobs: if: runner.os != 'Windows' run: | source .venv/bin/activate + chmod +x ${{ matrix.build_script }} ${{ matrix.build_script }} ${{ matrix.torch_variant }} shell: bash @@ -87,35 +108,36 @@ jobs: & ${{ matrix.build_script }} ${{ matrix.torch_variant }} shell: pwsh - - name: Rename executable - run: | - mv dist/photomap${{ matrix.executable_ext }} dist/photomap-${{ matrix.torch_variant }}${{ matrix.executable_ext }} - shell: bash - if: runner.os != 'Windows' - - - name: Rename executable (Windows) - run: | - Rename-Item -Path dist\photomap${{ matrix.executable_ext }} -NewName photomap-${{ matrix.torch_variant }}${{ matrix.executable_ext }} - shell: pwsh - if: runner.os == 'Windows' - - - name: Create zip archive with version (Linux/macOS) + - name: Rename and zip executable or directory (Linux/macOS) if: runner.os != 'Windows' run: | cd dist - ARCHIVE_NAME="photomap-${{ matrix.platform }}-${{ matrix.torch_variant }}-v${{ steps.get_version_unix.outputs.version || steps.get_version_win.outputs.version }}.zip" - zip -j "$ARCHIVE_NAME" "photomap-${{ matrix.torch_variant }}${{ matrix.executable_ext }}" + BASE="photomap-${{ matrix.torch_variant }}" + EXT="${{ matrix.executable_ext }}" + VERSION="${{ steps.get_version_unix.outputs.version || steps.get_version_win.outputs.version }}" + ARCHIVE_NAME="photomap-${{ matrix.platform }}-${{ matrix.torch_variant }}-v$VERSION.zip" + if [ -f "photomap$EXT" ]; then + mv "photomap$EXT" "$BASE$EXT" + zip "$ARCHIVE_NAME" "$BASE$EXT" + elif [ -d "photomap" ]; then + mv "photomap" "$BASE" + zip -r "$ARCHIVE_NAME" "$BASE" + else + echo "Neither photomap$EXT nor photomap directory found!" + exit 1 + fi ls -la *.zip shell: bash - - name: Create zip archive with version (Windows) - if: runner.os == 'Windows' - run: | - cd dist - $archiveName = "photomap-${{ matrix.platform }}-${{ matrix.torch_variant }}-v${{ steps.get_version_unix.outputs.version || steps.get_version_win.outputs.version }}.zip" - Compress-Archive -Path "photomap-${{ matrix.torch_variant }}${{ matrix.executable_ext }}" -DestinationPath $archiveName - Get-ChildItem *.zip + - name: Debug - List dist contents + run: ls -la dist/ + shell: bash + if: runner.os != 'Windows' + + - name: Debug - List dist contents (Windows) + run: Get-ChildItem dist/ shell: pwsh + if: runner.os == 'Windows' - name: Upload artifact uses: actions/upload-artifact@v4 diff --git a/.github/workflows/deploy.yml b/.github/workflows/deploy.yml index 21988178..6a618f2d 100644 --- a/.github/workflows/deploy.yml +++ b/.github/workflows/deploy.yml @@ -50,12 +50,8 @@ jobs: needs: deploy-dockerhub uses: ./.github/workflows/deploy-pyinstaller.yml - deploy-make-dmg: - needs: deploy-pyinstaller - uses: ./.github/workflows/deploy-dmg.yml - upload-release: - needs: [deploy-pypi, deploy-dockerhub, deploy-pyinstaller, deploy-make-dmg] + needs: [deploy-pypi, deploy-dockerhub, deploy-pyinstaller] runs-on: ubuntu-latest steps: - name: Download all artifacts diff --git a/.github/workflows/run_tests.yml b/.github/workflows/run_tests.yml index 941d7caa..17f78ccc 100644 --- a/.github/workflows/run_tests.yml +++ b/.github/workflows/run_tests.yml @@ -1,8 +1,6 @@ name: Run Pytest on: - push: - branches: [ master, main ] pull_request: branches: [ master, main ] diff --git a/INSTALL/pyinstaller/make_pyinstaller_image.ps1 b/INSTALL/pyinstaller/make_pyinstaller_image.ps1 index f3856725..2259dbba 100644 --- a/INSTALL/pyinstaller/make_pyinstaller_image.ps1 +++ b/INSTALL/pyinstaller/make_pyinstaller_image.ps1 @@ -58,6 +58,13 @@ if ($IsWindows) { $sep = ":" } +# After installing PyTorch +pip cache purge + +# Before running PyInstaller +Write-Host "Disk space before PyInstaller:" +Get-PSDrive C + # Run PyInstaller pyinstaller ` --hidden-import clip ` @@ -90,4 +97,7 @@ pyinstaller ` $pyinstallerMode ` --name photomap ` -y ` - photomap/backend/photomap_server.py \ No newline at end of file + photomap/backend/photomap_server.py + +# After PyInstaller +Remove-Item -Recurse -Force build/ -ErrorAction SilentlyContinue \ No newline at end of file diff --git a/INSTALL/pyinstaller/make_pyinstaller_image.sh b/INSTALL/pyinstaller/make_pyinstaller_image.sh index f0dcf9e4..8d2461f2 100755 --- a/INSTALL/pyinstaller/make_pyinstaller_image.sh +++ b/INSTALL/pyinstaller/make_pyinstaller_image.sh @@ -36,6 +36,10 @@ case "$TORCH_VARIANT" in ;; esac +# After installing PyTorch +pip cache purge +python -c "import torch; print(f'PyTorch cache cleared')" + # Make sure build tools and hooks are up to date python -m pip install -U pip wheel setuptools python -m pip install -U pyinstaller pyinstaller-hooks-contrib @@ -82,4 +86,11 @@ pyinstaller \ --argv-emulation \ --name photomap \ -y \ - photomap/backend/photomap_server.py \ No newline at end of file + photomap/backend/photomap_server.py + +# Before running PyInstaller +echo "Disk space before PyInstaller:" +df -h + +# After PyInstaller +rm -rf build/ # Remove PyInstaller temp files \ No newline at end of file diff --git a/macos/setup.py b/macos/setup.py index 15c42532..796155b2 100644 --- a/macos/setup.py +++ b/macos/setup.py @@ -1,32 +1,32 @@ from setuptools import find_packages, setup -APP = ["../photomap/backend/photomap_outer_loop.py"] +APP = ["./main.py"] DATA_FILES = [] OPTIONS = { - "argv_emulation": True, - "packages": ["photomap"], + # "argv_emulation": True, + # "packages": ["photomap"], "includes": [ - "fastapi", - "uvicorn", - "jinja2", - "numpy", - "pandas", - "networkx", - "pillow_heif", - "platformdirs", - "pydantic", - "python_multipart", - "PyYAML", - "requests", - "scikit_learn", - "torch", - "tqdm", - "umap_learn", - "psutil", - "packaging", - "dash", - "clip_anytorch", - "colorama", + # "fastapi", + # "uvicorn", + # "jinja2", + # "numpy", + # "pandas", + # "networkx", + # "pillow_heif", + # "platformdirs", + # "pydantic", + # "python_multipart", + # "PyYAML", + # "requests", + # "scikit_learn", + # "torch", + # "tqdm", + # "umap_learn", + # "psutil", + # "packaging", + # "dash", + # "clip_anytorch", + # "colorama", ], "iconfile": "../photomap/frontend/static/icons/icon.icns", } diff --git a/photomap/backend/embeddings.py b/photomap/backend/embeddings.py index 5af8ba55..83c07c87 100644 --- a/photomap/backend/embeddings.py +++ b/photomap/backend/embeddings.py @@ -236,7 +236,7 @@ def _process_images_batch( progress_callback: Optional callback function(index, total, message) for progress updates """ device = "cuda" if torch.cuda.is_available() else "cpu" - model, preprocess = clip.load("ViT-B/32", device=device, download_root=self._clip_root()) + model, preprocess = clip.load("ViT-B/32", device=device, download_root=self._clip_root()) # type: ignore embeddings = [] filenames = [] diff --git a/pyproject.toml b/pyproject.toml index 3e58defa..353c64f1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "photomapai" -version = "0.9.3" +version = "0.9.4" description = "AI-based image clustering and exploration tool" authors = [ { name = "Lincoln Stein", email = "lincoln.stein@gmail.com" }