diff --git a/Dockerfile b/Dockerfile index af06dda..18bcac5 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,8 @@ # ====== Backend: FastAPI ====== -FROM python:3.12-slim +# digest 固定:buildkit 每次都会联网解析 tag 元数据,国内网络下常被掐断导致 +# 构建卡死;digest 引用可直接命中本地镜像,无需联网。升级基础镜像时更新 digest +# (docker images --digests python)。 +FROM python:3.12-slim@sha256:09f7da3bc104798d0afb40bc08d23ab2da20a76130cec1f2ef170848f5d85217 LABEL app="mind-base-backend" @@ -33,10 +36,11 @@ RUN curl -fsSL --retry 5 --retry-all-errors --retry-delay 3 --connect-timeout 30 WORKDIR /app # Install Python dependencies -# Tip: for faster downloads in China, uncomment the mirror line below -# --index-url https://pypi.tuna.tsinghua.edu.cn/simple +# --default-timeout/--retries:清华源偶尔读超时(大包下载中断导致整层失败), +# 放宽单请求超时到 120s 并自动重试,与 ffmpeg 下载的 --retry 策略保持一致。 COPY requirements.txt . -RUN pip install --no-cache-dir -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt +RUN pip install --no-cache-dir --timeout 120 --retries 5 \ + -i https://pypi.tuna.tsinghua.edu.cn/simple -r requirements.txt # Copy application code COPY app/ ./app/ diff --git a/app/infra/minio.py b/app/infra/minio.py index 6f1287b..ba6977a 100644 --- a/app/infra/minio.py +++ b/app/infra/minio.py @@ -300,13 +300,24 @@ async def abort_multipart_upload(self, object_key: str, upload_id: str) -> None: # ── object access ───────────────────────────────────────── - async def presigned_get(self, object_key: str) -> str: + async def presigned_get( + self, object_key: str, response_headers: Optional[dict] = None + ) -> str: + """Presigned GET URL. + + ``response_headers`` (e.g. ``{"response-content-type": "application/pdf"}``) + is signed into the query string, so the object is served with the given + Content-Type regardless of how it was stored — needed when uploads + persisted a generic ``application/octet-stream`` and the browser must + render the file inline (PDF / video / image). + """ self._ensure_client() url = await _run_async( self._client.presigned_get_object, self.bucket, object_key, expires=timedelta(seconds=config.minio.presign_expire), + response_headers=response_headers, ) return self._public_url(url) diff --git a/app/routers/cloud.py b/app/routers/cloud.py index cd09f7a..c1b1ba0 100644 --- a/app/routers/cloud.py +++ b/app/routers/cloud.py @@ -804,7 +804,15 @@ async def get_video_raw( view_mode = _classify_view_mode(file.mime_type) # Presigned GET URL - works for download and as