# doc_stamp **Repository Path**: maju-blogs/doc_stamp ## Basic Information - **Project Name**: doc_stamp - **Description**: 盖章合成工具 - **Primary Language**: Unknown - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2026-09-03 - **Last Updated**: 2026-09-03 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # doc-stamp [在线体验](https://sign.ydfm.cc/) 基于 FastAPI 的 doc-stamp 后端服务骨架,内置「盖章合成」工具: 上传文档(图片或 Word .doc/.docx)与多张指纹 / 手写签名素材,自动抠图、识别签名区、把截图文档转成打印/扫描效果,再合成导出。 Word 文档由服务端自动转成逐页图片,默认取最后一页,多页时可在页面上选择。 ## 技术栈 - Python 3.13 + FastAPI(conda 管理环境) - OpenCV + Pillow + NumPy(图像处理) - Pydantic v2 + pydantic-settings(配置管理) - React + Vite + antd + Konva(前端) - pytest + httpx(接口测试) - ruff(代码质量) ## 快速开始 ### 1. 创建并激活 conda 环境 ```bash conda env create -f environment.yml conda activate doc_stamp ``` ### 2. 准备本地配置(可选) ```bash cp .env.example .env ``` ### 3. 启动开发服务 ```bash python -m app.main ``` 等效于 `uvicorn app.main:app --reload --host 127.0.0.1 --port 8000`; 绑定地址与端口由 `.env` 中的 `HOST` / `PORT` 控制,开发模式(`APP_ENV=dev`)自动开启热重载。 访问地址: - 指纹盖章工具页面: - API 文档(Swagger UI): - 健康检查: ### 4. 前端开发(修改 web/ 时使用) ```bash cd web npm install npm run dev # http://127.0.0.1:5173 ,/api 自动代理到 8000 npm run build # 产物输出到 web/dist,由 FastAPI 直接托管 ``` ### 5. 运行测试 ```bash pytest ``` ### 6. 代码检查 ```bash ruff check . ruff format --check . ``` ## Docker 镜像构建与运行 仓库内置多阶段构建配置(`Dockerfile` + `docker-compose.yml`): - 阶段 1(web-builder):使用 Node 编译 React/Vite 前端,产物输出到 `web/dist`; - 阶段 2(runtime):基于 `python:3.13-slim` 安装 Python 依赖并托管前端产物与 API。 镜像默认安装 LibreOffice,用于 Word(.doc/.docx)转 PDF;不需要该能力时可在构建阶段关闭以显著缩小镜像体积。 ### 1. 构建镜像 常规构建(包含 LibreOffice,默认): ```bash docker build -t doc-stamp:0.1.0 . ``` 关闭 LibreOffice(不提供 Word 转换,镜像更小): ```bash docker build --build-arg WITH_OFFICE=false -t doc-stamp:0.1.0 . ``` 更换 Python 依赖下载源(例如使用国内镜像加速构建): ```bash docker build --build-arg PIP_INDEX_URL=https://pypi.tuna.tsinghua.edu.cn/simple -t doc-stamp:0.1.0 . ``` ### 2. 使用 docker compose 构建并启动 ```bash docker compose up -d --build ``` 常用命令: ```bash docker compose logs -f app # 跟踪应用日志 docker compose ps # 查看服务状态 docker compose down # 停止服务(保留会话数据卷) docker compose down -v # 停止并删除数据卷(会清空 /data/stamp-sessions 下的会话文件) ``` ### 3. 直接使用 docker run ```bash docker run -d \ --name doc-stamp \ -p 8000:8000 \ -v doc-stamp-data:/data/stamp-sessions \ doc-stamp:0.1.0 ``` ### 4. 验证与注意事项 容器启动后访问: - 指纹盖章工具页面: - API 文档(Swagger UI): - 健康检查:`curl http://127.0.0.1:8000/api/v1/health` 注意事项: - 容器内服务绑定 `0.0.0.0:8000`,会话文件保存在 `/data/stamp-sessions`(默认 30 分钟自动清理),建议挂载命名卷持久化; - 浏览器跨域访问时需按实际前端地址设置 `CORS_ORIGINS`,例如 `CORS_ORIGINS='["http://your-host:8000"]'`; - 使用 `WITH_OFFICE=false` 构建的镜像不包含 LibreOffice,Word 转换接口会返回明确错误提示; - `docker compose down -v` 会删除会话数据卷,请先确认无需保留的会话文件。 ### 5. 推送到镜像仓库(含常见报错) 构建成功后按需推送镜像(`/` 替换为实际仓库地址): ```bash docker tag doc-stamp:0.1.0 //doc-stamp:0.1.0 docker push //doc-stamp:0.1.0 ``` #### 常见报错:unknown manifest class for application/vnd.oci.empty.v1+json 推送中断在 manifest 提交阶段,报错示例: ```text 6c0f2568ec38: Pushed error from registry: unknown manifest class for application/vnd.oci.empty.v1+json ``` 含义:镜像层(如上例的 `6c0f2568ec38`,这是层 digest 前缀,不是 git 提交)已全部上传成功,但最后写入 manifest / manifest index 时被仓库拒绝,因此仓库中不会出现可用镜像。 原因:BuildKit v0.32+(`docker buildx` 的默认构建后端)构建时默认生成 provenance / SBOM attestations,且 attestation manifest 按 OCI artifact 格式输出——其 config 描述符使用 OCI 1.1 新增的空配置类型 `application/vnd.oci.empty.v1+json`。Docker Hub 等仓库已支持该格式,而部分镜像仓库(如阿里云 ACR、GitLab Container Registry 等)尚未支持,会返回 `unknown manifest class` 拒绝整个 index。 确认方法:若同一 tag 在支持该格式的仓库(如 Docker Hub)上有成功推送,可执行以下命令查看 manifest 是否含平台为 `unknown/unknown` 的 attestation 条目: ```bash docker buildx imagetools inspect //doc-stamp:0.1.0 ``` 解决方案(任选其一): 1. 构建并推送时关闭默认 attestation(推荐,产物为普通单架构镜像,不含 attestation index): ```bash docker buildx build --platform linux/amd64 --push \ --provenance=false --sbom=false \ -t //doc-stamp:0.1.0 . ``` 2. 不便修改构建命令时,用环境变量全局关闭(适合 CI/CD): ```bash export BUILDX_NO_DEFAULT_ATTESTATIONS=1 docker buildx build --push -t //doc-stamp:0.1.0 . ``` GitHub Actions 使用 `docker/build-push-action` 时,可在 job 中设置环境变量 `BUILDX_NO_DEFAULT_ATTESTATIONS: "1"`,或在 `with` 中显式传 `provenance: false`、`sbom: false`。 3. 希望保留 attestation、仅关闭新的 OCI artifact 输出格式(buildx v0.36+): ```bash export BUILDX_NO_DEFAULT_OCI_ARTIFACT=1 docker buildx build --push -t //doc-stamp:0.1.0 . ``` 修复后重新推送,成功时输出会以 `digest: sha256:...` 结尾,不再出现 `unknown manifest class`。 ## 目录结构 ```text doc-stamp/ ├── app/ # 应用主目录 │ ├── main.py # 应用入口(应用工厂 + 中间件 + 路由注册) │ ├── core/ # 核心配置 │ │ └── config.py # Settings(环境变量 / .env 覆盖) │ ├── api/ # 接口层 │ │ └── v1/ │ │ ├── router.py # v1 路由聚合入口 │ │ └── endpoints/ # 具体接口(health.py、stamp.py 等) │ ├── schemas/ # Pydantic 请求/响应模型 │ ├── services/ # 业务逻辑层(stamp_processing.py 图像处理) │ └── models/ # 数据模型层(ORM 模型等) ├── web/ # React + Vite 前端 │ ├── src/ # 页面、画布编辑、API 封装 │ └── dist/ # 构建产物(.gitignore,FastAPI 托管) ├── tests/ # 测试 │ └── test_health.py ├── .env.example # 配置模板 ├── .dockerignore # Docker 构建忽略规则 ├── Dockerfile # 多阶段镜像构建(前端编译 + Python 运行时) ├── docker-compose.yml # 一键构建/启动编排(含命名卷与健康检查) ├── environment.yml # conda 环境与依赖清单 └── README.md ``` ## 新增业务模块约定 1. 在 `app/api/v1/endpoints/` 新建 `xxx.py`,内部定义 `router = APIRouter()`。 2. 在 `app/api/v1/router.py` 中挂载该 router(带前缀与 tags)。 3. 请求/响应模型放入 `app/schemas/`,业务逻辑放入 `app/services/`。 4. 在 `tests/` 下补充对应接口测试。 ## 指纹盖章 API - `POST /api/v1/stamp/sessions`:上传文档与素材(`fingerprints[]` / `signatures[]` 可多张) - `POST /api/v1/stamp/word/import`:Word(.doc/.docx)转逐页 PNG,返回页面列表(默认末页);页面资源见 `GET /word/imports/{id}/preview|page/{n}` - `POST /api/v1/stamp/sessions/{id}/process-document`:截图转打印(`screenshot` / `scan_texture`)、透视校正(auto/manual)、签名区识别 - `POST /api/v1/stamp/sessions/{id}/process-materials`:对所有素材抠图(`sensitivity` 灵敏度) - `POST/DELETE /api/v1/stamp/sessions/{id}/materials`:会话内增删素材 - `GET /api/v1/stamp/sessions/{id}/assets/document/{raw|clean|corrected}`、`assets/cutout/{material_id}`:访问中间图像 - `POST /api/v1/stamp/sessions/{id}/export/pdf`:合成 PNG 转 PDF 会话文件存放于系统临时目录(默认 30 分钟自动清理),不落库。 > Word 转换依赖本机已安装 Microsoft Word、WPS Office 或 LibreOffice 中的任意一种(自动探测:LibreOffice 命令行 → Word COM → WPS COM);未安装时会给出明确提示。