From fd8ec3a04e94492d889b9612d3975efa87e96c1a Mon Sep 17 00:00:00 2001 From: phact Date: Tue, 26 Aug 2025 23:50:47 -0400 Subject: [PATCH] arm wip --- .github/workflows/build-multiarch.yml | 120 ++++++++++++++++++++++++++ Dockerfile | 17 ++-- Dockerfile.backend | 29 ++++++- docker-compose.yml | 1 - documents/warmup_ocr.pdf | Bin 0 -> 9612 bytes pyproject.toml | 5 +- warm_up_docling.py | 4 +- 7 files changed, 162 insertions(+), 14 deletions(-) create mode 100644 .github/workflows/build-multiarch.yml create mode 100644 documents/warmup_ocr.pdf diff --git a/.github/workflows/build-multiarch.yml b/.github/workflows/build-multiarch.yml new file mode 100644 index 00000000..31471517 --- /dev/null +++ b/.github/workflows/build-multiarch.yml @@ -0,0 +1,120 @@ +name: Build Multi-Architecture Docker Images + +on: + workflow_dispatch: + +jobs: + build: + strategy: + matrix: + include: + - platform: linux/amd64 + runs-on: ubuntu-latest + arch-suffix: amd64 + - platform: linux/arm64 + runs-on: ubuntu-24.04-arm + arch-suffix: arm64 + + runs-on: ${{ matrix.runs-on }} + + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract version from pyproject.toml + id: version + run: | + VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2) + echo "version=$VERSION" >> $GITHUB_OUTPUT + echo "Version: $VERSION" + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@v3 + + - name: Login to Docker Hub + if: github.event_name != 'pull_request' + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Build and push backend + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.backend + platforms: ${{ matrix.platform }} + push: ${{ github.event_name != 'pull_request' }} + tags: phact/openrag-backend:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build and push frontend + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile.frontend + platforms: ${{ matrix.platform }} + push: ${{ github.event_name != 'pull_request' }} + tags: phact/openrag-frontend:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }} + cache-from: type=gha + cache-to: type=gha,mode=max + + - name: Build and push OpenSearch + uses: docker/build-push-action@v5 + with: + context: . + file: ./Dockerfile + platforms: ${{ matrix.platform }} + push: ${{ github.event_name != 'pull_request' }} + tags: phact/openrag-opensearch:${{ steps.version.outputs.version }}-${{ matrix.arch-suffix }} + cache-from: type=gha + cache-to: type=gha,mode=max + + manifest: + needs: build + runs-on: ubuntu-latest + if: github.event_name != 'pull_request' + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Extract version from pyproject.toml + id: version + run: | + VERSION=$(grep '^version = ' pyproject.toml | cut -d '"' -f 2) + echo "version=$VERSION" >> $GITHUB_OUTPUT + + - name: Login to Docker Hub + uses: docker/login-action@v3 + with: + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + + - name: Create and push multi-arch manifests + run: | + VERSION=${{ steps.version.outputs.version }} + + # Backend manifest + docker buildx imagetools create -t phact/openrag-backend:$VERSION \ + phact/openrag-backend:$VERSION-amd64 \ + phact/openrag-backend:$VERSION-arm64 + docker buildx imagetools create -t phact/openrag-backend:latest \ + phact/openrag-backend:$VERSION-amd64 \ + phact/openrag-backend:$VERSION-arm64 + + # Frontend manifest + docker buildx imagetools create -t phact/openrag-frontend:$VERSION \ + phact/openrag-frontend:$VERSION-amd64 \ + phact/openrag-frontend:$VERSION-arm64 + docker buildx imagetools create -t phact/openrag-frontend:latest \ + phact/openrag-frontend:$VERSION-amd64 \ + phact/openrag-frontend:$VERSION-arm64 + + # OpenSearch manifest + docker buildx imagetools create -t phact/openrag-opensearch:$VERSION \ + phact/openrag-opensearch:$VERSION-amd64 \ + phact/openrag-opensearch:$VERSION-arm64 + docker buildx imagetools create -t phact/openrag-opensearch:latest \ + phact/openrag-opensearch:$VERSION-amd64 \ + phact/openrag-opensearch:$VERSION-arm64 \ No newline at end of file diff --git a/Dockerfile b/Dockerfile index ed7a9aba..77e7651e 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,12 +11,19 @@ RUN usermod -aG wheel opensearch # Change the sudoers file to allow passwordless sudo RUN echo "opensearch ALL=(ALL) NOPASSWD:ALL" >> /etc/sudoers -# FIXME handle the machine arch better, somehow -ARG ASYNC_PROFILER_URL=https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-x64.tar.gz +# Handle different architectures for async-profiler +ARG TARGETARCH +RUN if [ "$TARGETARCH" = "amd64" ]; then \ + export ASYNC_PROFILER_URL=https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-x64.tar.gz; \ + elif [ "$TARGETARCH" = "arm64" ]; then \ + export ASYNC_PROFILER_URL=https://github.com/async-profiler/async-profiler/releases/download/v4.0/async-profiler-4.0-linux-arm64.tar.gz; \ + else \ + echo "Unsupported architecture: $TARGETARCH" && exit 1; \ + fi && \ + mkdir /opt/async-profiler && \ + curl -s -L $ASYNC_PROFILER_URL | tar zxvf - --strip-components=1 -C /opt/async-profiler && \ + chown -R opensearch:opensearch /opt/async-profiler -RUN mkdir /opt/async-profiler -RUN curl -s -L $ASYNC_PROFILER_URL | tar zxvf - --strip-components=1 -C /opt/async-profiler -RUN chown -R opensearch:opensearch /opt/async-profiler RUN echo "#!/bin/bash" > /usr/share/opensearch/profile.sh RUN echo "export PATH=\$PATH:/opt/async-profiler/bin" >> /usr/share/opensearch/profile.sh diff --git a/Dockerfile.backend b/Dockerfile.backend index f257d4c2..bd88ae1b 100644 --- a/Dockerfile.backend +++ b/Dockerfile.backend @@ -1,7 +1,13 @@ FROM python:3.13-slim # Install curl for uv installation and openssl for RSA key generation -RUN apt-get update && apt-get install -y curl openssl && rm -rf /var/lib/apt/lists/* +# Also install git for potential dependencies and build-essential for native compilations +RUN apt-get update && apt-get install -y \ + curl \ + openssl \ + git \ + build-essential \ + && rm -rf /var/lib/apt/lists/* # Install uv RUN curl -LsSf https://astral.sh/uv/install.sh | sh @@ -15,9 +21,24 @@ COPY pyproject.toml uv.lock ./ RUN uv sync # Copy sample document and warmup script for docling -COPY documents/2506.08231v1.pdf ./ +COPY documents/warmup_ocr.pdf ./ COPY warm_up_docling.py ./ -RUN uv run python warm_up_docling.py && rm warm_up_docling.py 2506.08231v1.pdf +RUN uv run docling-tools models download +RUN uv run python - <<'PY' +import pathlib, easyocr +cache = pathlib.Path("/root/.EasyOCR/model") +cache.mkdir(parents=True, exist_ok=True) +# Prewarm the detector + recog for Docling’s default langs +easyocr.Reader(['fr','de','es','en'], + download_enabled=True, + model_storage_directory=str(cache)) +print("EasyOCR cache ready at", cache) +PY + +RUN uv run python warm_up_docling.py && rm warm_up_docling.py warmup_ocr.pdf + + +#ENV EASYOCR_MODULE_PATH=~/.cache/docling/models/EasyOcr/ # Copy Python source COPY src/ ./src/ @@ -26,4 +47,4 @@ COPY src/ ./src/ EXPOSE 8000 # Start backend in foreground -CMD ["uv", "run", "python", "src/main.py"] \ No newline at end of file +CMD ["uv", "run", "python", "src/main.py"] diff --git a/docker-compose.yml b/docker-compose.yml index 342cd4ba..ebb6e691 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -67,7 +67,6 @@ services: - ./documents:/app/documents:Z - ./keys:/app/keys:Z gpus: all - platform: linux/amd64 openrag-frontend: image: phact/openrag-frontend:latest diff --git a/documents/warmup_ocr.pdf b/documents/warmup_ocr.pdf new file mode 100644 index 0000000000000000000000000000000000000000..8b17f8b24a6612e40a589b4a7a039c82bf2e308d GIT binary patch literal 9612 zcmeHN3pi9;`(HCd7|K1Dbc`b8GGh=^G;)nDt|vukFf=hUH8ZYphB{P2rGq$ft4^te zP>Li(RHTs5agR94C6~hN{~r0iPR{fFpYQ)Y=jrQt{?>TsvETh$d%f@4^RD&2d;gSd zOwBd4GY0y`MX4eq>83JR%zFNbzLt$85mi(AceHiuZmNMw|P; zImMSnW?-uKPb>Lx}NoL8=rZ)x6W{mP)| ze!fD{>o*leV=Ze>TPscsM}Y~nT0I21#HNoyz>Ek1m6Z_av6x-sCIW$h%Mj>8cFgWa zJyXen&;7iuTYgRg0<-DP5Qvc}A@I@YHUwnBhb5Di zW@+iSv=njw)pe|HCH_08mFpQelGPM5>6Ys(`IYjCUsjN@W+SGv9c(FmO|>k6k>mGNJ(}FW2>H8 z8U8@EaCwofY;xhem15qma;gS+F?26j2;&)nwpJhzBHlFR4I+F0hA?5AHSx5Y1&mr1CxJJ_p zpUk)*g5oArOE)+19GgiyAsZVJ)Lk>-q8AdZcnkT4pPpbEOQ;ew4*A)O<`B<3S|?-l zAkOXNNLxfCRd!2|&)yfRvWi!BTv}~atE*XR{fSa2 zpinbTj2J_D^X&7+pxRY(R*hmS=_{uX4C=eiR7iDOG)nnJTpX8vTCk=3(aOCS;#x?L zqC+arqy%4zn5fF=8loDj1@bmM%-oq9deMON3dK8aBjTvMs!=Z1NC%N&7PN7eb~`~0 z0&3X^ zKx9RC)YxGNL5hTUaBVGeSXnS$}NMUR6q`KByl$W z{qg%#LJ)ZF&)r|YQY^r(7ZaE7-xzwY>0ZK#-`ckL|ElQ`*(B<TBriB+oLH6mqgL2YUcD>&n=h1(q(x3_s=;DsiI-enTgHrAljUMtfKZ-{ zJ`gT1x-Sy4J=ywL;_n(GB?%EaZAYnoKA|+ShVr=+5pk-<9>T?pL?QlOrgQTB<9;#N zZsIW=mr4BFa<){|O*$dW%YtA^fwCeX*+G--p?HIm4R z;-jQeSMxsmqwT2Htm%_w!PdtM-m1&bp_?h5sa+ZxR0xEsMax*mty{C*yMM2qa_YHL z74jk<+*Tg2_PBhhm2lgqI3O8!jft#nkP+uOt#bib1Ukv3LvO&S6P+LNzu4Qzgq(*LBVzwXUYT1lu+TGOoc zbxMcmEFnEKwvv*Z)5>PQDSi@i#bmC1{pBZzn#PF5d;DEBMyapgAJ0~}*>I!oJnbP( zBYK$k-XkU_x>EJCc(Sv=&7 znaPME(TZ=^tP&f^<8?5tKCF#3YD;`(pn4qwHXO80Gy^G)J=-rST%^KCvg0}Dr@&vc`q;4$OYd&y zOlUxjs}Yfprt;j6JIK@c8=n{SJ!cgk=DAaRN94DT&F}n^ z_XyiP8Lm;}pwapF0B4syKoarIP-wBf^xSp$I>+rXxD~-W$S!R^R;RL`Yn=_e`k!pIg$C6 z!Slb3wG>!Of%R=FfqxZb|E~k~hU+js`MC)Bk!!@k(9wF%3gQeJ z-f~dfms`8ojWa!IvvTZ733fT0GiOaz6Q}jzM@?$amMmGClcnFuQtbSv>xsokYW<9b zbxFynW7LFju1j^0kX~z80#R#)L%iyQ+`i6KA9#)7CW*q(D>O`PSs;WgkX*Rrl?9TE z9hph@V|c(s7%oG`hC%nRC$nIF3zkcv!Ok;QOkkP|c7e?@kD_pSEEq1~g-e{_{$Y2J zJt-t(dLY~r2Y+C43(UfSX)W+K+}VUqW5M(lCPsU{&jJyL%dFwDa2Q->%OV;M7r0>I z0<%R&?+dTx(B}bg+%`Yn{77F8J*XJ$XCqDN7+dsTCt$;u%R5k5zGRFF2Lb_r1Q>t{ z{J=rr2I#;8FjQgNxfCM`on{IXjW8;v8}T^2E>0h>hr{CuS_CH;v4igUFHioHR}{z~ zd!ca{J@mYlpH1DMtE;^MZ|hTAZ-f9MD}JZ$SCotD1-VjT{r^A{WrM}Vhs zQD40NpL8q+iQ)@$q`0@P?=zD{VzB1@AZQcx L&`L^X*5>~Md=&2= literal 0 HcmV?d00001 diff --git a/pyproject.toml b/pyproject.toml index 89b70864..d46ca3eb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -27,10 +27,11 @@ dependencies = [ [tool.uv.sources] #agentd = { path = "/home/tato/Desktop/agentd" } torch = [ - { index = "pytorch-cu128" }, + { index = "pytorch-cu128", marker = "sys_platform == 'linux' and platform_machine == 'x86_64'" }, + # macOS & other platforms use PyPI (no index entry needed) ] torchvision = [ - { index = "pytorch-cu128" }, + { index = "pytorch-cu128", marker = "sys_platform == 'linux' and platform_machine == 'x86_64'" }, ] [[tool.uv.index]] diff --git a/warm_up_docling.py b/warm_up_docling.py index 30c7489f..50fe7c6b 100644 --- a/warm_up_docling.py +++ b/warm_up_docling.py @@ -4,10 +4,10 @@ print('Warming up docling models...') try: # Use the sample document to warm up docling - test_file = "/app/2506.08231v1.pdf" + test_file = "/app/warmup_ocr.pdf" print(f'Using {test_file} to warm up docling...') DocumentConverter().convert(test_file) print('Docling models warmed up successfully') except Exception as e: print(f'Docling warm-up completed with: {e}') - # This is expected - we just want to trigger the model downloads \ No newline at end of file + # This is expected - we just want to trigger the model downloads