Spaces:
Sleeping
Sleeping
| # syntax=docker.io/docker/dockerfile:1 | |
| # Force cache invalidation for HuggingFace Spaces | |
| ARG CACHEBUST=1 | |
| FROM node:slim AS base | |
| # Install Python and build tools for native dependencies | |
| # Install Chromium and dependencies for Puppeteer | |
| RUN apt-get update && apt-get install -y \ | |
| python3 make g++ \ | |
| chromium \ | |
| fonts-noto-cjk \ | |
| fonts-liberation \ | |
| fonts-freefont-ttf \ | |
| ca-certificates \ | |
| libnss3 \ | |
| libatk-bridge2.0-0 \ | |
| libdrm2 \ | |
| libxcomposite1 \ | |
| libxdamage1 \ | |
| libxfixes3 \ | |
| libxrandr2 \ | |
| libgbm1 \ | |
| libxkbcommon0 \ | |
| libasound2 \ | |
| libatspi2.0-0 \ | |
| libgtk-3-0 \ | |
| libglib2.0-0 \ | |
| libxss1 \ | |
| libgconf-2-4 \ | |
| && rm -rf /var/lib/apt/lists/* | |
| # Set Puppeteer to use installed Chromium | |
| ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true | |
| ENV PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium | |
| # Install dependencies only when needed | |
| FROM base AS deps | |
| WORKDIR /app | |
| # Install dependencies based on the preferred package manager | |
| COPY package.json yarn.lock* package-lock.json* pnpm-lock.yaml* .npmrc* ./ | |
| RUN \ | |
| if [ -f yarn.lock ]; then yarn --frozen-lockfile; \ | |
| elif [ -f package-lock.json ]; then npm ci --include=optional; \ | |
| elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm i --frozen-lockfile; \ | |
| else echo "Lockfile not found." && exit 1; \ | |
| fi | |
| # Install the correct platform-specific packages based on architecture | |
| RUN if [ "$(uname -m)" = "x86_64" ]; then \ | |
| npm install lightningcss-linux-x64-gnu@1.29.1 --no-save; \ | |
| elif [ "$(uname -m)" = "aarch64" ]; then \ | |
| npm install lightningcss-linux-arm64-gnu@1.29.1 --no-save; \ | |
| fi && \ | |
| npm rebuild @tailwindcss/oxide --update-binary | |
| # Rebuild the source code only when needed | |
| FROM base AS builder | |
| WORKDIR /app | |
| # Clear all cache to avoid build issues | |
| RUN rm -rf .next node_modules/.cache | |
| COPY --from=deps /app/node_modules ./node_modules | |
| COPY . . | |
| # Rebuild native dependencies for the builder stage | |
| # Rebuild sharp and other native modules for the platform | |
| RUN if [ "$(uname -m)" = "x86_64" ]; then \ | |
| npm install lightningcss-linux-x64-gnu@1.29.1 --no-save; \ | |
| elif [ "$(uname -m)" = "aarch64" ]; then \ | |
| npm install lightningcss-linux-arm64-gnu@1.29.1 --no-save; \ | |
| fi && \ | |
| npm rebuild sharp && \ | |
| npm rebuild @tailwindcss/oxide --update-binary | |
| # Clean up build artifacts | |
| RUN rm -rf .next/cache node_modules/.cache | |
| # Build arguments for API keys (passed from HuggingFace Spaces environment) | |
| ARG OPENAI_TEMPLATE_AI_DEV | |
| ARG OPENAI_GENERATE_FV_AI | |
| ARG CLAUDE_TEMPLATE_AI_DEV | |
| ARG ANTHROPIC_API_KEY | |
| ARG GOOGLE_API_KEY | |
| ARG NEXT_PUBLIC_APP_ENV | |
| ARG OKTA_OAUTH2_ISSUER | |
| ARG OKTA_OAUTH2_CLIENT_ID | |
| ARG OKTA_OAUTH2_CLIENT_SECRET | |
| ARG SECRET | |
| # Set environment variables for build time | |
| ENV NEXT_TELEMETRY_DISABLED=1 | |
| ENV NEXT_PUBLIC_APP_ENV=$NEXT_PUBLIC_APP_ENV | |
| ENV OPENAI_TEMPLATE_AI_DEV=$OPENAI_TEMPLATE_AI_DEV | |
| ENV OPENAI_GENERATE_FV_AI=$OPENAI_GENERATE_FV_AI | |
| ENV CLAUDE_TEMPLATE_AI_DEV=$CLAUDE_TEMPLATE_AI_DEV | |
| ENV ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY | |
| ENV GOOGLE_API_KEY=$GOOGLE_API_KEY | |
| ENV OKTA_OAUTH2_ISSUER=$OKTA_OAUTH2_ISSUER | |
| ENV OKTA_OAUTH2_CLIENT_ID=$OKTA_OAUTH2_CLIENT_ID | |
| ENV OKTA_OAUTH2_CLIENT_SECRET=$OKTA_OAUTH2_CLIENT_SECRET | |
| ENV SECRET=$SECRET | |
| # Set memory limit for build process | |
| ENV NODE_OPTIONS="--max-old-space-size=2048" | |
| RUN \ | |
| if [ -f yarn.lock ]; then yarn run build; \ | |
| elif [ -f package-lock.json ]; then npm run build; \ | |
| elif [ -f pnpm-lock.yaml ]; then corepack enable pnpm && pnpm run build; \ | |
| else echo "Lockfile not found." && exit 1; \ | |
| fi | |
| # Remove build cache to reduce image size (keep only necessary runtime files) | |
| RUN rm -rf .next/cache/webpack .next/cache/swc node_modules/.cache | |
| # Production image, copy all the files and run next | |
| FROM base AS runner | |
| WORKDIR /app | |
| ENV NODE_ENV=production | |
| # Disable Next.js telemetry and set cache to writable location | |
| ENV NEXT_TELEMETRY_DISABLED=1 | |
| ENV TMPDIR=/tmp | |
| # Runtime environment variables for API keys | |
| ARG OPENAI_TEMPLATE_AI_DEV | |
| ARG OPENAI_GENERATE_FV_AI | |
| ARG CLAUDE_TEMPLATE_AI_DEV | |
| ARG ANTHROPIC_API_KEY | |
| ARG GOOGLE_API_KEY | |
| ARG NEXT_PUBLIC_APP_ENV | |
| ARG OKTA_OAUTH2_ISSUER | |
| ARG OKTA_OAUTH2_CLIENT_ID | |
| ARG OKTA_OAUTH2_CLIENT_SECRET | |
| ARG SECRET | |
| ENV NEXT_PUBLIC_APP_ENV=$NEXT_PUBLIC_APP_ENV | |
| ENV OPENAI_TEMPLATE_AI_DEV=$OPENAI_TEMPLATE_AI_DEV | |
| ENV OPENAI_GENERATE_FV_AI=$OPENAI_GENERATE_FV_AI | |
| ENV CLAUDE_TEMPLATE_AI_DEV=$CLAUDE_TEMPLATE_AI_DEV | |
| ENV ANTHROPIC_API_KEY=$ANTHROPIC_API_KEY | |
| ENV GOOGLE_API_KEY=$GOOGLE_API_KEY | |
| ENV OKTA_OAUTH2_ISSUER=$OKTA_OAUTH2_ISSUER | |
| ENV OKTA_OAUTH2_CLIENT_ID=$OKTA_OAUTH2_CLIENT_ID | |
| ENV OKTA_OAUTH2_CLIENT_SECRET=$OKTA_OAUTH2_CLIENT_SECRET | |
| ENV SECRET=$SECRET | |
| RUN addgroup --system --gid 1001 nodejs | |
| RUN adduser --system --uid 1001 nextjs --home /home/nextjs | |
| # Copy node_modules for runtime (including Puppeteer) | |
| COPY --from=builder /app/node_modules ./node_modules | |
| RUN chown -R nextjs:nodejs ./node_modules | |
| # Ensure nextjs user has access to home directory | |
| RUN chown -R nextjs:nodejs /home/nextjs | |
| COPY --from=builder /app/public ./public | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./ | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static | |
| # Copy .next directory but exclude cache to avoid permission issues | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/server ./.next/server | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/required-server-files.json ./.next/required-server-files.json | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/routes-manifest.json ./.next/routes-manifest.json | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/build-manifest.json ./.next/build-manifest.json | |
| COPY --from=builder --chown=nextjs:nodejs /app/.next/package.json ./.next/package.json | |
| # Copy optional manifest files (may not exist in all builds) | |
| RUN --mount=type=bind,from=builder,source=/app/.next,target=/tmp/source \ | |
| if [ -f /tmp/source/prerender-manifest.json ]; then cp /tmp/source/prerender-manifest.json ./.next/; fi && \ | |
| if [ -f /tmp/source/react-loadable-manifest.json ]; then cp /tmp/source/react-loadable-manifest.json ./.next/; fi && \ | |
| chown -R nextjs:nodejs ./.next/ | |
| # Create cache directories and ensure full permissions (combining both approaches) | |
| RUN mkdir -p /tmp/.next/cache/images && \ | |
| mkdir -p /app/.next/cache/images && \ | |
| chmod -R 777 /tmp && \ | |
| chmod -R 755 /app/.next && \ | |
| chmod -R 777 /app/.next/cache/images && \ | |
| chown -R nextjs:nodejs /tmp/.next && \ | |
| chown -R nextjs:nodejs /app/.next | |
| USER nextjs | |
| EXPOSE 7860 | |
| ENV PORT=7860 | |
| ENV HOSTNAME="0.0.0.0" | |
| # Optimize for HuggingFace free tier | |
| ENV NODE_OPTIONS="--max-old-space-size=1024" | |
| CMD ["node", "server.js"] |