Some checks failed
Forgejo Android APK / Root app tests (push) Successful in 48s
Forgejo Docker Build / Root app tests (push) Successful in 59s
Forgejo Android APK / Build signed APK (push) Successful in 2m6s
Forgejo Docker Build / Build Docker image (push) Successful in 25s
Forgejo Docker Build / Deploy to the host (push) Failing after 0s
Pandoc's pptx writer was the ceiling on how good a generated deck could be, and the model on top made no difference to it. It maps markdown onto a handful of reference layouts with no per-slide layout, no positioning and no control over how large an image is drawn, which is why every deck came out as bullets on a template — and why autofit had to be injected into its emitted OOXML by hand afterwards, because LibreOffice ignores the autofit pandoc leaves off. scripts/render_pptx.py draws the deck and src/utils/slideSpec.js decides what each slide is. Markdown stays the stored artifact, so "change slide 4" is still a text edit and Word export is untouched — pandoc still writes docx, where its output is good. What that buys, all of it visible in a rendered deck rather than argued for: - 16:9, not pandoc's 4:3. - A pipe table becomes a real table with a header band and banded rows, not eight lines of text with pipes in them. - A list longer than seven items becomes two columns instead of a wall of text. - Text is measured and sized to fit before the file is written, so nothing depends on a renderer honouring autofit. - Wrapped lines hang under the text instead of running back to the margin, which is the clearest single tell that a deck was generated. - An image is drawn at its own aspect ratio, centred, with a caption. Figures now reach the deck at all, which they never did. They were queued and shown on the page, but nothing recorded that they belonged to the resource, so an export could not include them: user_resources.image_ids holds them, a modification adds to that list rather than replacing it, and export fetches the finished ones to a scratch directory. They are spread through the deck rather than appended, because ending on three unexplained pictures is worse than showing each near its material, and a References slide stays last. If the renderer fails for any reason, pandoc still produces a deck — a plainer deck beats a failed download. Verified end to end: a seven-slide request with three figures exported as a 13-page deck; the slides were rendered to PDF, rasterised and looked at. All three formats still download. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Dv6sqaY6Vq3ChZHMem3cnU
71 lines
3.7 KiB
Docker
71 lines
3.7 KiB
Docker
# ─── OpenBao CLI, copied from upstream image (multi-arch automatic) ───
|
|
# Update the tag here to adopt a newer OpenBao. Binary is statically linked,
|
|
# safe to drop into the Node alpine image as-is.
|
|
# Pinned by digest, not by tag: a tag is a moving pointer, so two builds of the
|
|
# same commit could otherwise produce different images. These are manifest-list
|
|
# digests, so buildx still selects the right per-architecture variant.
|
|
FROM openbao/openbao:2.5.3@sha256:fdc6da21ca6963560c32336fd7feb9cf2d5e52668f1a1647205a4b41171f0806 AS bao-src
|
|
|
|
FROM node:24-alpine@sha256:e67514e5d0f6c46656005e1b693b2ec9d52e80b641307de684d4a015ba7a4eaf
|
|
|
|
WORKDIR /app
|
|
|
|
# ffmpeg: audio conversion for AWS Transcribe (WebM → PCM)
|
|
# curl: HTTP helper used by the OpenBao entrypoint and health/debug tooling
|
|
# jq: JSON parsing for the entrypoint's OpenBao secret-fetch step
|
|
# pandoc: Markdown → PPTX for Learning resources. It is large (~230MB), and it
|
|
# is here rather than in a sidecar because a sidecar would add a
|
|
# cross-stack network dependency to an export that must not fail for
|
|
# reasons outside this container. It also measures images, which
|
|
# pptxgenjs cannot: that library emits the target box verbatim with
|
|
# <a:stretch/>, so every image in every generated deck was distorted.
|
|
RUN apk add --no-cache ffmpeg curl jq pandoc-cli
|
|
|
|
# python-pptx builds the slide decks. pandoc still writes Word, where its output
|
|
# is good, but its pptx writer can only map markdown onto a handful of reference
|
|
# layouts: no per-slide layout, no positioning, no control over where an image
|
|
# lands or how large it is. That ceiling is the renderer's, not the model's — a
|
|
# better-written deck still came out as bullets on a template, and slides
|
|
# overflowed until autofit was injected into the emitted OOXML by hand.
|
|
#
|
|
# py3-lxml and py3-pillow come from apk rather than pip because both are C
|
|
# extensions and Alpine has no wheels for them; installing from source here
|
|
# would mean carrying a compiler in the runtime image. Adds ~58MB.
|
|
RUN apk add --no-cache python3 py3-pip py3-lxml py3-pillow \
|
|
&& pip install --break-system-packages --no-cache-dir python-pptx==1.0.2 \
|
|
&& python3 -c 'import pptx'
|
|
|
|
# Pull the bao CLI out of the upstream image — matches host arch because
|
|
# buildx pulls the right manifest-list variant per build.
|
|
COPY --from=bao-src /bin/bao /usr/local/bin/bao
|
|
RUN /usr/local/bin/bao version
|
|
|
|
COPY package.json package-lock.json ./
|
|
# argon2 compiles native code via node-gyp — needs python3/make/g++ at build time
|
|
RUN apk add --no-cache --virtual .build-deps python3 make g++ \
|
|
&& npm ci --omit=dev \
|
|
&& apk del .build-deps
|
|
|
|
COPY . .
|
|
|
|
# One validated source revision for both runtime cache busting and OCI provenance.
|
|
# Direct development builds without an explicit revision remain visibly unversioned.
|
|
ARG GIT_REVISION=unknown
|
|
RUN node -e 'const r=process.argv[1]; if (r !== "unknown" && !require("./src/utils/buildId").isGitRevision(r)) throw new Error("GIT_REVISION must be a full lowercase Git SHA"); require("node:fs").writeFileSync("BUILD_ID", r + "\n");' -- "$GIT_REVISION"
|
|
LABEL org.opencontainers.image.revision=$GIT_REVISION
|
|
|
|
# Ensure the entrypoint is executable regardless of host file permissions
|
|
RUN chmod +x /app/docker-entrypoint.sh
|
|
|
|
RUN mkdir -p /app/data/logs
|
|
|
|
EXPOSE 3000
|
|
|
|
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s \
|
|
CMD wget --no-verbose --tries=1 --spider http://localhost:3000/api/health || exit 1
|
|
|
|
# Entrypoint wrapper handles optional OpenBao secret fetch before exec'ing CMD.
|
|
# See docker-entrypoint.sh for the logic — it is a no-op if OPENBAO_ADDR is
|
|
# unset, so legacy .env-only deployments continue to work unchanged.
|
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
|
CMD ["node", "server.js"]
|