Merge pull request #1111 from mengdehong/fix/openai-compatible-empty-… #163
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Test and Release | |
| on: | |
| push: | |
| branches: | |
| - main | |
| - master | |
| concurrency: | |
| group: ${{ github.workflow }}-${{ github.ref }} | |
| cancel-in-progress: false | |
| permissions: | |
| id-token: write | |
| contents: write | |
| pull-requests: write | |
| env: | |
| REGISTRY: ghcr.io | |
| REPO_LOWER: ${{ github.repository_owner }}/${{ github.event.repository.name }} | |
| GHCR_REPO: ghcr.io/${{ github.repository }} | |
| DOCKERHUB_REPO: byaidu/pdf2zh | |
| WIN_EXE_PYTHON_VERSION: "3.12.9" | |
| jobs: | |
| check-repository: | |
| name: Check if running in main repository | |
| runs-on: ubuntu-latest | |
| outputs: | |
| # debug purpose | |
| is_main_repo: ${{ github.repository == 'Byaidu/PDFMathTranslate' }} | |
| is_doc_only: ${{ steps.check-doc.outputs.is_doc_only }} | |
| steps: | |
| - run: echo "Running repository check" | |
| - name: Check if commit is doc-only | |
| id: check-doc | |
| run: | | |
| MSG=$(echo "${{ github.event.head_commit.message }}" | head -n 1) | |
| if [[ "$MSG" == doc:* ]] || [[ "$MSG" == "doc("* ]]; then | |
| echo "is_doc_only=true" >> $GITHUB_OUTPUT | |
| else | |
| echo "is_doc_only=false" >> $GITHUB_OUTPUT | |
| fi | |
| test: | |
| needs: check-repository | |
| uses: ./.github/workflows/python-test.yml | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| build: | |
| name: Build distribution 📦 | |
| needs: [test, check-repository] | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| outputs: | |
| is_release: ${{ steps.check-version.outputs.tag }} | |
| version: ${{ steps.check-version.outputs.tag && steps.get-release-version.outputs.version || steps.get-dev-version.outputs.version }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: true | |
| fetch-depth: 2 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Setup uv with Python 3.12 | |
| uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Check if there is a parent commit | |
| id: check-parent-commit | |
| run: | | |
| echo "sha=$(git rev-parse --verify --quiet HEAD^)" >> $GITHUB_OUTPUT | |
| - name: Detect and tag new version | |
| id: check-version | |
| if: steps.check-parent-commit.outputs.sha | |
| uses: salsify/action-detect-and-tag-new-version@b1778166f13188a9d478e2d1198f993011ba9864 # v2.0.3 | |
| with: | |
| version-command: | | |
| cat pyproject.toml | grep "version = " | head -n 1 | awk -F'"' '{print $2}' | |
| tag-template: 'v{VERSION}' | |
| - name: Install Dependencies | |
| run: | | |
| uv sync | |
| - name: Bump version for developmental release | |
| if: "!steps.check-version.outputs.tag" | |
| id: get-dev-version | |
| run: | | |
| version=$(bumpver update --patch --tag=final --dry 2>&1 | grep "New Version" | awk '{print $NF}') | |
| echo "version=$version.dev$(date +%s)" >> $GITHUB_OUTPUT | |
| bumpver update --set-version $version.dev$(date +%s) | |
| - name: Get release version | |
| if: steps.check-version.outputs.tag | |
| id: get-release-version | |
| run: | | |
| version=$(cat pyproject.toml | grep "version = " | head -n 1 | awk -F'"' '{print $2}') | |
| echo "version=$version" >> $GITHUB_OUTPUT | |
| - name: Build package | |
| run: "uv build" | |
| - name: Store the distribution packages | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 | |
| with: | |
| name: python-package-distributions | |
| path: dist/ | |
| publish-to-pypi: | |
| name: Publish Python 🐍 distribution 📦 to PyPI | |
| if: needs.build.outputs.is_release != '' | |
| needs: | |
| - check-repository | |
| - build | |
| - test-win64-exe | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: pypi | |
| url: https://pypi.org/p/pdf2zh | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download all the dists | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: python-package-distributions | |
| path: dist/ | |
| - name: Publish distribution 📦 to PyPI | |
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 | |
| publish-to-testpypi: | |
| name: Publish Python 🐍 distribution 📦 to TestPyPI | |
| if: needs.build.outputs.is_release == '' | |
| needs: | |
| - check-repository | |
| - build | |
| - test-win64-exe | |
| runs-on: ubuntu-latest | |
| environment: | |
| name: testpypi | |
| url: https://test.pypi.org/p/pdf2zh | |
| permissions: | |
| id-token: write | |
| steps: | |
| - name: Download all the dists | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: python-package-distributions | |
| path: dist/ | |
| - name: Publish distribution 📦 to TestPyPI | |
| uses: pypa/gh-action-pypi-publish@ed0c53931b1dc9bd32cbe73a98c7f6766f8a527e # v1.13.0 | |
| with: | |
| repository-url: https://test.pypi.org/legacy/ | |
| build-docker-image: | |
| strategy: | |
| fail-fast: false | |
| matrix: | |
| include: | |
| - platform: linux/amd64 | |
| runner: ubuntu-latest | |
| - platform: linux/arm64 | |
| runner: ubuntu-24.04-arm | |
| runs-on: ${{ matrix.runner }} | |
| timeout-minutes: 30 | |
| needs: | |
| - build | |
| - check-repository | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| environment: | |
| name: ${{ needs.build.outputs.is_release != '' && 'pypi' || 'testpypi' }} | |
| url: ${{ needs.build.outputs.is_release != '' && 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=latest' || 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=dev' }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Convert to lowercase | |
| run: | | |
| echo "GHCR_REPO_LOWER=$(echo ${{ env.GHCR_REPO }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
| - name: Prepare | |
| run: | | |
| platform=${{ matrix.platform }} | |
| echo "PLATFORM_PAIR=${platform//\//-}" >> $GITHUB_ENV | |
| - name: Checkout repository | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup uv with Python 3.12 | |
| uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 | |
| with: | |
| python-version: "3.12" | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Set version from build job | |
| if: needs.build.outputs.is_release == '' | |
| run: | | |
| uv tool install bumpver | |
| echo "Using version: ${{ needs.build.outputs.version }}" | |
| bumpver update --set-version ${{ needs.build.outputs.version }} | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6 | |
| with: | |
| images: | | |
| ${{ env.DOCKERHUB_REPO }} | |
| ${{ env.GHCR_REPO_LOWER }} | |
| tags: | | |
| type=raw,value=dev | |
| type=raw,value=${{ needs.build.outputs.version }},enable=${{ needs.build.outputs.is_release != '' }} | |
| type=raw,value=latest,enable=${{ needs.build.outputs.is_release != '' }} | |
| - name: Login to Docker.io | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: docker.io | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Login to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Build and push by digest | |
| id: build | |
| uses: docker/build-push-action@10e90e3645eae34f1e60eeb005ba3a3d33f178e8 # v6 | |
| with: | |
| platforms: ${{ matrix.platform }} | |
| labels: ${{ steps.meta.outputs.labels }} | |
| outputs: type=image,"name=${{ env.DOCKERHUB_REPO }},${{ env.GHCR_REPO_LOWER }}",push-by-digest=true,name-canonical=true,push=true | |
| cache-from: type=gha,scope=${{ matrix.platform }} | |
| cache-to: type=gha,mode=max,scope=${{ matrix.platform }} | |
| - name: Export digest | |
| run: | | |
| mkdir -p ${{ runner.temp }}/digests | |
| digest="${{ steps.build.outputs.digest }}" | |
| touch "${{ runner.temp }}/digests/${digest#sha256:}" | |
| - name: Upload digest | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 | |
| with: | |
| name: digests-${{ env.PLATFORM_PAIR }} | |
| path: ${{ runner.temp }}/digests/* | |
| if-no-files-found: error | |
| retention-days: 1 | |
| merge-docker-image: | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| needs: | |
| - build | |
| - build-docker-image | |
| - check-repository | |
| - test-win64-exe | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| environment: | |
| name: ${{ needs.build.outputs.is_release != '' && 'pypi' || 'testpypi' }} | |
| url: ${{ needs.build.outputs.is_release != '' && 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=latest' || 'https://hub.docker.com/r/byaidu/pdf2zh/tags?name=dev' }} | |
| permissions: | |
| contents: read | |
| packages: write | |
| steps: | |
| - name: Convert to lowercase | |
| run: | | |
| echo "GHCR_REPO_LOWER=$(echo ${{ env.GHCR_REPO }} | tr '[:upper:]' '[:lower:]')" >> $GITHUB_ENV | |
| - name: Download digests | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| path: ${{ runner.temp }}/digests | |
| pattern: digests-* | |
| merge-multiple: true | |
| - name: Set up Docker Buildx | |
| uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4 | |
| - name: Docker meta | |
| id: meta | |
| uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6 | |
| with: | |
| images: | | |
| ${{ env.DOCKERHUB_REPO }} | |
| ${{ env.GHCR_REPO_LOWER }} | |
| tags: | | |
| type=raw,value=dev | |
| type=raw,value=${{ needs.build.outputs.version }},enable=${{ needs.build.outputs.is_release != '' && 'true' || 'false' }} | |
| type=raw,value=latest,enable=${{ needs.build.outputs.is_release != '' && 'true' || 'false' }} | |
| - name: Login to Docker.io | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: docker.io | |
| username: ${{ secrets.DOCKER_USERNAME }} | |
| password: ${{ secrets.DOCKER_PASSWORD }} | |
| - name: Login to GHCR | |
| uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4 | |
| with: | |
| registry: ghcr.io | |
| username: ${{ github.repository_owner }} | |
| password: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Create manifest list and push | |
| working-directory: ${{ runner.temp }}/digests | |
| run: | | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.DOCKERHUB_REPO }}@sha256:%s ' *) | |
| docker buildx imagetools create $(jq -cr '.tags | map("-t " + .) | join(" ")' <<< "$DOCKER_METADATA_OUTPUT_JSON") \ | |
| $(printf '${{ env.GHCR_REPO_LOWER }}@sha256:%s ' *) | |
| - name: Inspect image | |
| run: | | |
| docker buildx imagetools inspect ${{ env.DOCKERHUB_REPO }}:${{ steps.meta.outputs.version }} | |
| docker buildx imagetools inspect ${{ env.GHCR_REPO_LOWER }}:${{ steps.meta.outputs.version }} | |
| build-win64-exe: | |
| runs-on: windows-latest | |
| timeout-minutes: 30 | |
| needs: | |
| - check-repository | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| steps: | |
| - name: checkout babeldoc metadata | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| repository: funstory-ai/BabelDOC | |
| path: babeldoctemp1234567 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| sparse-checkout: babeldoc/assets/embedding_assets_metadata.py | |
| - name: Cached Assets | |
| id: cache-assets | |
| uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5.0.4 | |
| with: | |
| path: ~/.cache/babeldoc | |
| key: test-1-babeldoc-assets-${{ hashFiles('babeldoctemp1234567/babeldoc/assets/embedding_assets_metadata.py') }} | |
| - name: 检出代码 | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Setup uv with Python ${{ env.WIN_EXE_PYTHON_VERSION }} | |
| uses: astral-sh/setup-uv@85856786d1ce8acfbcc2f13a5f3fbd6b938f9f41 # v7.1.2 | |
| with: | |
| python-version: ${{ env.WIN_EXE_PYTHON_VERSION }} | |
| enable-cache: true | |
| cache-dependency-glob: "pyproject.toml" | |
| - name: Build Windows executable | |
| shell: pwsh | |
| run: | | |
| ./script/build-win64.ps1 ` | |
| -PythonVersion "${{ env.WIN_EXE_PYTHON_VERSION }}" ` | |
| -CleanBabelDoc ` | |
| -DownloadVCRedist ` | |
| -GenerateOfflineAssets | |
| - name: Upload build with offline assets artifact | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 | |
| with: | |
| name: win64-exe-with-assets | |
| path: ./build | |
| if-no-files-found: error | |
| compression-level: 1 | |
| include-hidden-files: true | |
| test-win64-exe: | |
| needs: | |
| - build-win64-exe | |
| - check-repository | |
| if: needs.check-repository.outputs.is_main_repo == 'true' && needs.check-repository.outputs.is_doc_only != 'true' | |
| runs-on: windows-latest | |
| timeout-minutes: 20 | |
| steps: | |
| - name: 检出代码 | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Download build artifact | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: win64-exe-with-assets | |
| path: ./build | |
| - name: Test show version | |
| run: | | |
| ./build/pdf2zh.exe --version | |
| - name: Test - Translate a PDF file with plain text only | |
| run: | | |
| ./build/pdf2zh.exe ./test/file/translate.cli.plain.text.pdf -o ./test/file | |
| - name: Test - Translate a PDF file figure | |
| run: | | |
| ./build/pdf2zh.exe ./test/file/translate.cli.text.with.figure.pdf -o ./test/file | |
| - name: Delete offline assets and cache | |
| shell: pwsh | |
| run: | | |
| $offlineAssetsPath = Get-ChildItem -Path "./build" -Filter "offline_assets_*.zip" -Recurse | Select-Object -First 1 -ExpandProperty FullName | |
| if ($offlineAssetsPath) { | |
| Remove-Item -Path $offlineAssetsPath -Force | |
| } | |
| $cachePath = "$env:USERPROFILE/.cache/babeldoc" | |
| if (Test-Path $cachePath) { | |
| Remove-Item -Path $cachePath -Recurse -Force | |
| } | |
| - name: Test - Translate without offline assets | |
| run: | | |
| New-Item -Path "./test/file/offline_result" -ItemType Directory -Force | |
| ./build/pdf2zh.exe ./test/file/translate.cli.plain.text.pdf -o ./test/file/offline_result | |
| - name: Upload test results | |
| uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7 | |
| with: | |
| name: test-results | |
| path: ./test/file/ | |
| retention-days: 7 | |
| release-draft: | |
| name: Release Draft Tasks | |
| needs: | |
| - check-repository | |
| - build | |
| - publish-to-pypi | |
| - publish-to-testpypi | |
| - merge-docker-image | |
| - test-win64-exe | |
| if: | | |
| always() && needs.check-repository.outputs.is_main_repo == 'true' && | |
| needs.check-repository.outputs.is_doc_only != 'true' && | |
| (needs.publish-to-pypi.result == 'success' || needs.publish-to-testpypi.result == 'success') && | |
| needs.merge-docker-image.result == 'success' && | |
| needs.test-win64-exe.result == 'success' | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| permissions: | |
| contents: write | |
| pull-requests: write | |
| outputs: | |
| tag_name: ${{ steps.release-drafter.outputs.tag_name }} | |
| steps: | |
| - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| with: | |
| persist-credentials: true | |
| fetch-depth: 2 | |
| token: ${{ secrets.GITHUB_TOKEN }} | |
| - name: Publish the release notes | |
| id: release-drafter | |
| uses: release-drafter/release-drafter@139054aeaa9adc52ab36ddf67437541f039b88e2 # v7.1.1 | |
| with: | |
| publish: ${{ needs.build.outputs.is_release != '' }} | |
| tag: ${{ needs.build.outputs.is_release }} | |
| env: | |
| GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| upload-release: | |
| needs: [release-draft, check-repository] | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| if: always() && needs.check-repository.outputs.is_main_repo == 'true' && | |
| needs.check-repository.outputs.is_doc_only != 'true' && | |
| needs.release-draft.result == 'success' | |
| steps: | |
| - name: 检出代码 | |
| uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 | |
| - name: Download build artifact | |
| uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8 | |
| with: | |
| name: win64-exe-with-assets | |
| path: ./build | |
| - name: Create release zip | |
| run: | | |
| mv ./build ./pdf2zh | |
| zip -9qr "pdf2zh-${{ needs.release-draft.outputs.tag_name }}-with-assets-win64.zip" ./pdf2zh/* | |
| # Find and delete offline asset files | |
| find ./pdf2zh -name "offline_assets_*.zip" -type f -print -delete | |
| echo "Remaining offline assets files (should be empty):" | |
| find ./pdf2zh -name "offline_assets_*.zip" -type f | |
| zip -9qr "pdf2zh-${{ needs.release-draft.outputs.tag_name }}-win64.zip" ./pdf2zh/* | |
| - name: Upload to latest release | |
| env: | |
| GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} | |
| run: | | |
| LATEST_RELEASE=${{ needs.release-draft.outputs.tag_name }} | |
| echo "Latest release tag: $LATEST_RELEASE" | |
| gh release upload "$LATEST_RELEASE" "pdf2zh-${{ needs.release-draft.outputs.tag_name }}-win64.zip" --clobber |