# Dockerfile.huggingface - HF Spaces single container # LiteLLM v1.81.14 with external PostgreSQL via DATABASE_URL # # Required HF Space secrets: # DATABASE_URL postgresql://user:pass@host:5432/db # LITELLM_SALT_KEY random string, encrypts API keys in DB (never change after first use) # LITELLM_MASTER_KEY admin key # JWT_SECRET session secret # # Bug fixes: # [Bug2] build-essential for better-sqlite3 node-gyp fallback # [Bug3] npm install --omit=dev (--only=production deprecated in npm v10) # [Bug5] ARG LITELLM_VERSION for single-source versioning # [BugP] prisma generate — LiteLLM v1.61+ 在 database_url 存在时会在 FastAPI # lifespan 启动阶段初始化 Prisma 客户端,需要 query-engine 二进制文件 # 预先存在。否则容器立即崩溃: # ModuleNotFoundError: No module named 'prisma' # Exception: Unable to find Prisma binaries. # Please run 'prisma generate' first. # # 根因分析(三层): # 1. litellm[proxy]==1.81.14 的依赖树里 **没有** prisma 包, # 必须显式 pip install prisma。 # 2. prisma generate 产生的 query-engine 二进制默认写入 # ~/.cache/prisma-binaries/(即 root 的 /root/.cache/), # 但容器运行时是 uid=1000(user),查找路径是 # /home/user/.cache/ → 完全不同的目录 → 找不到。 # 3. 修复:设 PRISMA_BINARY_CACHE_DIR=/app/.prisma(在 /app 下, # 后续 chown -R user:user /app 会覆盖到这里),build 阶段和 # 运行时都读同一个环境变量,路径始终一致。 FROM node:20-alpine AS frontend-builder WORKDIR /build ARG VITE_API_BASE=/api ARG VITE_APP_NAME="AI Gateway Hub" ENV VITE_API_BASE=$VITE_API_BASE VITE_APP_NAME=$VITE_APP_NAME COPY frontend/package*.json ./ RUN npm install COPY frontend/ . RUN npm run build FROM python:3.11-slim ARG LITELLM_VERSION=1.81.14 # 把 prisma 二进制缓存目录固定到 /app/.prisma, # 使 build 阶段(root)和运行时(uid=1000)使用同一路径。 ENV PRISMA_BINARY_CACHE_DIR=/app/.prisma RUN apt-get update && apt-get install -y --no-install-recommends \ curl gnupg ca-certificates nginx supervisor build-essential \ && curl -fsSL https://deb.nodesource.com/setup_20.x | bash - \ && apt-get install -y --no-install-recommends nodejs \ && apt-get purge -y gnupg && apt-get autoremove -y \ && rm -rf /var/lib/apt/lists/* # [BugP 修复] # litellm[proxy]==1.81.14 的依赖里不含 prisma,需要单独安装。 # 安装后立即执行 prisma generate,将 query-engine 写入 # $PRISMA_BINARY_CACHE_DIR(/app/.prisma),后续 chown 会一并处理权限。 RUN pip install --no-cache-dir "litellm[proxy]==${LITELLM_VERSION}" prisma \ && mkdir -p "${PRISMA_BINARY_CACHE_DIR}" \ && SCHEMA_PATH=$(python3 -c \ "import litellm, os; \ print(os.path.join(os.path.dirname(litellm.__file__), 'proxy', 'schema.prisma'))") \ && echo "Running: prisma generate --schema ${SCHEMA_PATH}" \ && prisma generate --schema "${SCHEMA_PATH}" RUN useradd -m -u 1000 -s /bin/bash user RUN mkdir -p \ /app/frontend/dist /app/backend/src /app/litellm \ /app/huggingface /app/data \ /var/log/supervisor \ /tmp/nginx/client_body /tmp/nginx/proxy \ /tmp/nginx/fastcgi /tmp/nginx/uwsgi /tmp/nginx/scgi \ && chown -R user:user \ /app /var/log/supervisor \ /var/log/nginx /var/lib/nginx /tmp/nginx COPY --from=frontend-builder --chown=user:user /build/dist /app/frontend/dist COPY --chown=user:user backend/package*.json /app/backend/ RUN cd /app/backend && npm install --omit=dev \ && chown -R user:user /app/backend/node_modules COPY --chown=user:user backend/src/ /app/backend/src/ COPY --chown=user:user litellm/config.yaml /app/litellm/config.yaml COPY --chown=user:user huggingface/nginx.conf /app/huggingface/nginx.conf COPY --chown=user:user huggingface/supervisord.conf /app/huggingface/supervisord.conf COPY --chown=user:user huggingface/entrypoint.sh /app/huggingface/entrypoint.sh RUN chmod +x /app/huggingface/entrypoint.sh USER user WORKDIR /app EXPOSE 7860 ENTRYPOINT ["/app/huggingface/entrypoint.sh"]