commit 7d9fff2c344f704990fc12ec1f80a1abc8a8a06b Author: seekee Date: Wed Jan 7 17:11:36 2026 +0800 first commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..de58fac --- /dev/null +++ b/README.md @@ -0,0 +1,136 @@ +# FunMD 文档转换服务 + +FunMD 是一个基于 FastAPI 的文档转换与资源重写服务,支持: +- DOC/DOCX/PDF/HTML → Markdown/HTML/JSON +- Markdown/HTML → DOCX/PDF(支持封面、Logo、页眉页脚、目录) +- 批量上传与处理,自动将本地相对资源上传至 MinIO 并重写为可访问链接 +- 运行时 MinIO 配置,支持私有桶返回签名下载链接 + +前端测试页面内置并由后端提供,便于在内网环境下直接联调。 + +## 目录结构 +- `docling/app/server.py`:FastAPI 应用入口,接口路由与 MinIO 集成 +- `docling/app/services/unified_converter.py`:统一转换逻辑,封装 Docling 与 word2markdown +- `docling/app/services/word2markdown.py`:DOC/DOCX 自定义转换与图片处理 +- `docling/app/services/minio_utils.py`:MinIO 客户端与运行时配置工具 +- `frontend/`:前端(Vite)源码,构建后由后端挂载到 `/ui` +- `Dockerfile`:镜像构建,包含 LibreOffice 与运行依赖 +- `api.md`:接口与测试说明(详细列举) + +## 快速开始(源代码) +1) 启动后端 +``` +cd docling +PYTHONPATH=. python -m uvicorn app.server:app --host 0.0.0.0 --port 8000 +``` +2) 访问前端测试页 +``` +http://<你的服务器IP>:8000/ui/ +``` +3) 前端 API 基址(可选) +- 若需显式指定后端地址,可在浏览器控制台设置: +``` +localStorage.setItem('app.api.base','http://<你的服务器IP>:8000') +``` +否则前端使用相对路径与同源后端。 + +## 快速开始(Docker 镜像) +镜像已包含 LibreOffice(提供 `soffice --headless`,用于 `.doc`→`.docx`)与模型缓存。 +1) 加载镜像 +``` +docker load -i FunMD_Convert_Image.tar +``` +2) 运行容器(示例映射到 8001,避免端口冲突) +``` +docker run --rm -p 8001:8000 --name funmd funmd-convert:latest +``` +3) 访问前端测试页 +``` +http://<你的服务器IP>:8001/ui/ +``` + +## MinIO 配置 +服务支持运行时配置 MinIO,避免写死环境变量;同时内置规范化与安全校验: +- 禁止使用控制台端口 `:9001` 或带 `/browser`、`/minio` 的控制台地址 +- `public` 用于生成返回链接的主机与协议;`secure` 仅影响后端连接 MinIO API 的协议 + +推荐流程: +``` +# 测试并必要时自动建桶、应用公开读策略 +curl -X POST 'http://<服务器IP>:8000/config/minio/test' \ + -F 'endpoint=10.9.35.31:9000' \ + -F 'public=https://docs-test.dameng.com' \ + -F 'access=minioadmin' \ + -F 'secret=minioadmin' \ + -F 'bucket=file-cms' \ + -F 'secure=false' \ + -F 'create_if_missing=true' \ + -F 'public_read=true' + +# 应用运行时配置(返回链接以 public 为准) +curl -X POST 'http://<服务器IP>:8000/config/minio' \ + -F 'endpoint=10.9.35.31:9000' \ + -F 'public=https://docs-test.dameng.com' \ + -F 'access=minioadmin' \ + -F 'secret=minioadmin' \ + -F 'bucket=file-cms' \ + -F 'secure=false' \ + -F 'public_read=true' +``` +私有桶场景下,前端应优先使用返回的 `minio_presigned_url` 进行下载;直链可能 403。 + +## 核心接口 +- 健康检查:`GET /health` +- 统一转换:`POST /api/convert` + - 字段:`file` 或 `source_url` 二选一;`export=markdown|html|json|doctags`;可选 `engine=word2markdown|docling`;`save=true|false`;`filename` + - 行为: + - `save=false`:返回文本内容与 `media_type`;若 MinIO 已配置,Markdown/HTML 中的资源(含 `data:` 图片)会上传并重写为可访问链接 + - `save=true`:Markdown/HTML/JSON 结果保存到 MinIO,返回 `minio_url` 与 `minio_presigned_url` +- Markdown→文档:`POST /md/convert`(DOCX/PDF;支持封面/Logo/页眉页脚/目录/样式) +- 批量重写并上传:`POST /md/convert-folder` +- 上传压缩包批量处理:`POST /api/upload-archive` +- 分阶段归档处理: + - 暂存上传:`POST /api/archive/stage` + - 批量处理:`POST /api/archive/process` + - 说明:HTML 文件采用两阶段策略(重写资源→转换为 Markdown→再次重写) +- MinIO 管理: + - 设置:`POST /config/minio` + - 测试:`POST /config/minio/test` + - 创建桶:`POST /config/minio/create-bucket` + - 配置快照与 Profile:`GET /config`、`/config/profile/list`、`/config/profile/activate` + +示例:DOCX→Markdown 不保存 +``` +curl -X POST 'http://<服务器IP>:8000/api/convert' \ + -F 'file=@/path/to/sample.docx' \ + -F 'export=markdown' \ + -F 'save=false' +``` + +示例:DOCX→Markdown 保存到 MinIO +``` +curl -X POST 'http://<服务器IP>:8000/api/convert' \ + -F 'file=@/path/to/sample.docx' \ + -F 'export=markdown' \ + -F 'save=true' \ + -F 'filename=sample' +``` + +## 引擎与图片处理 +- DOC/DOCX:默认走 `word2markdown`,将段落与表格转为 Markdown;内嵌的图片初始为 `data:image/*;base64,...` +- PDF/HTML:走 Docling 管线,生成 Markdown/HTML/JSON;PDF 可抽取图片作为额外资源上传 +- 资源重写:后端在返回前会解析 Markdown/HTML 内的相对路径与 `data:` 图片,上传到 MinIO 并替换为可访问链接 + +## 常见问题 +- 端口占用:若宿主已有服务使用 8000,请以 `-p 8001:8000` 映射对外端口 +- `.doc` 转换:非 macOS 环境需要 LibreOffice 提供 `soffice --headless`;镜像已内置,无需额外安装 +- 私有桶访问:使用 `minio_presigned_url`;直链可能 403 + +## 开发流程与建议 +- 前端 API 基址:优先读取 `localStorage('app.api.base')`,其次 `VITE_API_BASE_URL`;不再强制回退本地端口 +- 分支与 PR:遵循 “feature 分支 + PR” 的流程进行变更 +- 防御式设计:三层防线(菜单过滤、路由守卫、后端授权);后端始终需要硬授权 + +## 版权与许可 +本项目面向企业内部使用。如需开源或外部发布,请根据公司规范补充许可与版权说明。 +