diff --git a/.github/workflows/publish-npm.yml b/.github/workflows/publish-npm.yml new file mode 100644 index 0000000..2eb9238 --- /dev/null +++ b/.github/workflows/publish-npm.yml @@ -0,0 +1,26 @@ +name: Publish Package to npmjs + +on: + workflow_dispatch: + +jobs: + build: + runs-on: ubuntu-24.04 + permissions: + id-token: write + contents: read + steps: + - uses: actions/checkout@v4 + - uses: pnpm/action-setup@v3 + with: + version: 9.15.9 + - uses: actions/setup-node@v4 + with: + node-version: '20.x' + registry-url: 'https://registry.npmjs.org' + - run: | + pnpm i + cd packages/pdf2md && pnpm build && pnpm publish + cd ../mcp && pnpm build && pnpm publish + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} diff --git a/.gitignore b/.gitignore index 995b14b..4e5a7d7 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,5 @@ -/node_modules -/test/samples -/test/output -/test/results -/test/imahes -/test/tt.js -/test/mm.js \ No newline at end of file +**/node_modules +**/dist +.vscode/mcp.json +samples +packages/mcp/output diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..51fb693 --- /dev/null +++ b/.prettierrc @@ -0,0 +1,5 @@ +{ + "printWidth": 160, + "singleQuote": true, + "endOfLine": "lf" +} diff --git a/README.md b/README.md index 36a52cb..a364a57 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # PDF2MD Node.js

- Node.js Version + Node.js Version License

@@ -20,17 +20,15 @@ A powerful Node.js tool for converting PDF documents to Markdown format using ad ## 🚀 Installation ```bash -# Clone the repository -git clone https://github.com/yourusername/pdf2md.git -cd pdf2md/pdf2md-node - # Install dependencies -npm install +pnpm add pdf2md-js +# or +npm add pdf2md-js ``` ## 📋 Requirements -- Node.js 16.0.0 or higher +- Node.js 20.0.0 or higher - API key for at least one of the supported vision models ## 🔧 Usage @@ -38,7 +36,7 @@ npm install ### Basic Usage ```javascript -import { parsePdf } from './src/index.js'; +import { parsePdf } from 'pdf2md-js'; const result = await parsePdf('path/to/your.pdf', { apiKey: 'your-api-key', @@ -107,19 +105,19 @@ The project includes several test scripts to verify functionality: ```bash # Test the full PDF to Markdown conversion process -node test/testFullProcess.js +pnpm vite-node test/testFullProcess.js # Test only the PDF to image conversion -node test/testFullPageImages.js +pnpm vite-node test/testFullPageImages.js # Test specific vision models -node test/testModel.js +pnpm vite-node test/testModel.js ``` ## 📁 Project Structure ``` -pdf2md-node/ +pdf2md-js/ ├── src/ │ ├── index.js # Main entry point │ ├── pdfParser.js # PDF parsing module diff --git a/README.zh-CN.md b/README.zh-CN.md index f70b117..703c65e 100644 --- a/README.zh-CN.md +++ b/README.zh-CN.md @@ -1,7 +1,7 @@ # PDF2MD Node.js

- Node.js 版本 + Node.js 版本 许可证

@@ -18,17 +18,15 @@ ## 🚀 安装 ```bash -# 克隆仓库 -git clone https://github.com/yourusername/pdf2md.git -cd pdf2md/pdf2md-node - -# 安装依赖 -npm install +# Install dependencies +pnpm add pdf2md-js +# or +npm add pdf2md-js ``` ## 📋 系统要求 -- Node.js 16.0.0 或更高版本 +- Node.js 20.0.0 或更高版本 - 至少一个支持的视觉模型的API密钥 ## 🔧 使用方法 @@ -36,7 +34,7 @@ npm install ### 基本用法 ```javascript -import { parsePdf } from './src/index.js'; +import { parsePdf } from 'pdf2md-js'; const result = await parsePdf('path/to/your.pdf', { apiKey: 'your-api-key', @@ -106,19 +104,19 @@ const result = await parsePdf('path/to/your.pdf', options); ```bash # 测试完整的PDF到Markdown转换流程 -node test/testFullProcess.js +pnpm vite-node test/testFullProcess.js # 仅测试PDF到图像的转换 -node test/testFullPageImages.js +pnpm vite-node test/testFullPageImages.js # 测试特定视觉模型 -node test/testModel.js +pnpm vite-node test/testModel.js ``` ## 📁 项目结构 ``` -pdf2md-node/ +pdf2md-js/ ├── src/ │ ├── index.js # 主入口点 │ ├── pdfParser.js # PDF解析模块 diff --git a/package-lock.json b/package-lock.json deleted file mode 100644 index 5a6a7d3..0000000 --- a/package-lock.json +++ /dev/null @@ -1,3563 +0,0 @@ -{ - "name": "pdf2md-node", - "version": "1.0.0", - "lockfileVersion": 3, - "requires": true, - "packages": { - "": { - "name": "pdf2md-node", - "version": "1.0.0", - "license": "MIT", - "dependencies": { - "@turf/turf": "^6.5.0", - "canvas": "^2.11.2", - "fs-extra": "^11.1.1", - "openai": "^4.28.0", - "pdf-lib": "^1.17.1", - "pdf-parse": "^1.1.1", - "pdf.js-extract": "^0.2.1", - "pdfjs-dist": "^3.11.174", - "sharp": "^0.33.1" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/@emnapi/runtime/-/runtime-1.4.0.tgz", - "integrity": "sha512-64WYIf4UYcdLnbKn/umDlNjQDSS8AgZrI/R9+x5ilkUVFxXcA1Ebl+gQLc/6mERA4407Xof0R7wEyEuj091CVw==", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime/node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "optional": true - }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" - } - }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" - } - }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" - }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" - } - }, - "node_modules/@pdf-lib/standard-fonts": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/@pdf-lib/standard-fonts/-/standard-fonts-1.0.0.tgz", - "integrity": "sha512-hU30BK9IUN/su0Mn9VdlVKsWBS6GyhVfqjwl1FjZN4TxP6cCw0jP2w7V3Hf5uX7M0AZJ16vey9yE0ny7Sa59ZA==", - "dependencies": { - "pako": "^1.0.6" - } - }, - "node_modules/@pdf-lib/upng": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/@pdf-lib/upng/-/upng-1.0.1.tgz", - "integrity": "sha512-dQK2FUMQtowVP00mtIksrlZhdFXQZPC+taih1q4CvPZ5vqdxR/LKBaFg0oAfzd1GlHZXXSPdQfzQnt+ViGvEIQ==", - "dependencies": { - "pako": "^1.0.10" - } - }, - "node_modules/@turf/along": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/along/-/along-6.5.0.tgz", - "integrity": "sha512-LLyWQ0AARqJCmMcIEAXF4GEu8usmd4Kbz3qk1Oy5HoRNpZX47+i5exQtmIWKdqJ1MMhW26fCTXgpsEs5zgJ5gw==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/angle": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/angle/-/angle-6.5.0.tgz", - "integrity": "sha512-4pXMbWhFofJJAOvTMCns6N4C8CMd5Ih4O2jSAG9b3dDHakj3O4yN1+Zbm+NUei+eVEZ9gFeVp9svE3aMDenIkw==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/area": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/area/-/area-6.5.0.tgz", - "integrity": "sha512-xCZdiuojokLbQ+29qR6qoMD89hv+JAgWjLrwSEWL+3JV8IXKeNFl6XkEJz9HGkVpnXvQKJoRz4/liT+8ZZ5Jyg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bbox": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/bbox/-/bbox-6.5.0.tgz", - "integrity": "sha512-RBbLaao5hXTYyyg577iuMtDB8ehxMlUqHEJiMs8jT1GHkFhr6sYre3lmLsPeYEi/ZKj5TP5tt7fkzNdJ4GIVyw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bbox-clip": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/bbox-clip/-/bbox-clip-6.5.0.tgz", - "integrity": "sha512-F6PaIRF8WMp8EmgU/Ke5B1Y6/pia14UAYB5TiBC668w5rVVjy5L8rTm/m2lEkkDMHlzoP9vNY4pxpNthE7rLcQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bbox-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/bbox-polygon/-/bbox-polygon-6.5.0.tgz", - "integrity": "sha512-+/r0NyL1lOG3zKZmmf6L8ommU07HliP4dgYToMoTxqzsWzyLjaj/OzgQ8rBmv703WJX+aS6yCmLuIhYqyufyuw==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bearing": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/bearing/-/bearing-6.5.0.tgz", - "integrity": "sha512-dxINYhIEMzgDOztyMZc20I7ssYVNEpSv04VbMo5YPQsqa80KO3TFvbuCahMsCAW5z8Tncc8dwBlEFrmRjJG33A==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/bezier-spline": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/bezier-spline/-/bezier-spline-6.5.0.tgz", - "integrity": "sha512-vokPaurTd4PF96rRgGVm6zYYC5r1u98ZsG+wZEv9y3kJTuJRX/O3xIY2QnTGTdbVmAJN1ouOsD0RoZYaVoXORQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-clockwise": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-clockwise/-/boolean-clockwise-6.5.0.tgz", - "integrity": "sha512-45+C7LC5RMbRWrxh3Z0Eihsc8db1VGBO5d9BLTOAwU4jR6SgsunTfRWR16X7JUwIDYlCVEmnjcXJNi/kIU3VIw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-contains": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-contains/-/boolean-contains-6.5.0.tgz", - "integrity": "sha512-4m8cJpbw+YQcKVGi8y0cHhBUnYT+QRfx6wzM4GI1IdtYH3p4oh/DOBJKrepQyiDzFDaNIjxuWXBh0ai1zVwOQQ==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/boolean-point-on-line": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-crosses": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-crosses/-/boolean-crosses-6.5.0.tgz", - "integrity": "sha512-gvshbTPhAHporTlQwBJqyfW+2yV8q/mOTxG6PzRVl6ARsqNoqYQWkd4MLug7OmAqVyBzLK3201uAeBjxbGw0Ng==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/polygon-to-line": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-disjoint": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-disjoint/-/boolean-disjoint-6.5.0.tgz", - "integrity": "sha512-rZ2ozlrRLIAGo2bjQ/ZUu4oZ/+ZjGvLkN5CKXSKBcu6xFO6k2bgqeM8a1836tAW+Pqp/ZFsTA5fZHsJZvP2D5g==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/polygon-to-line": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-equal": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-equal/-/boolean-equal-6.5.0.tgz", - "integrity": "sha512-cY0M3yoLC26mhAnjv1gyYNQjn7wxIXmL2hBmI/qs8g5uKuC2hRWi13ydufE3k4x0aNRjFGlg41fjoYLwaVF+9Q==", - "dependencies": { - "@turf/clean-coords": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "geojson-equality": "0.1.6" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-intersects": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-intersects/-/boolean-intersects-6.5.0.tgz", - "integrity": "sha512-nIxkizjRdjKCYFQMnml6cjPsDOBCThrt+nkqtSEcxkKMhAQj5OO7o2CecioNTaX8EayqwMGVKcsz27oP4mKPTw==", - "dependencies": { - "@turf/boolean-disjoint": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-overlap": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-overlap/-/boolean-overlap-6.5.0.tgz", - "integrity": "sha512-8btMIdnbXVWUa1M7D4shyaSGxLRw6NjMcqKBcsTXcZdnaixl22k7ar7BvIzkaRYN3SFECk9VGXfLncNS3ckQUw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/line-overlap": "^6.5.0", - "@turf/meta": "^6.5.0", - "geojson-equality": "0.1.6" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-parallel": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-parallel/-/boolean-parallel-6.5.0.tgz", - "integrity": "sha512-aSHJsr1nq9e5TthZGZ9CZYeXklJyRgR5kCLm5X4urz7+MotMOp/LsGOsvKvK9NeUl9+8OUmfMn8EFTT8LkcvIQ==", - "dependencies": { - "@turf/clean-coords": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-point-in-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-point-in-polygon/-/boolean-point-in-polygon-6.5.0.tgz", - "integrity": "sha512-DtSuVFB26SI+hj0SjrvXowGTUCHlgevPAIsukssW6BG5MlNSBQAo70wpICBNJL6RjukXg8d2eXaAWuD/CqL00A==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-point-on-line": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-point-on-line/-/boolean-point-on-line-6.5.0.tgz", - "integrity": "sha512-A1BbuQ0LceLHvq7F/P7w3QvfpmZqbmViIUPHdNLvZimFNLo4e6IQunmzbe+8aSStH9QRZm3VOflyvNeXvvpZEQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/boolean-within": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/boolean-within/-/boolean-within-6.5.0.tgz", - "integrity": "sha512-YQB3oU18Inx35C/LU930D36RAVe7LDXk1kWsQ8mLmuqYn9YdPsDQTMTkLJMhoQ8EbN7QTdy333xRQ4MYgToteQ==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/boolean-point-on-line": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/buffer": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/buffer/-/buffer-6.5.0.tgz", - "integrity": "sha512-qeX4N6+PPWbKqp1AVkBVWFerGjMYMUyencwfnkCesoznU6qvfugFHNAngNqIBVnJjZ5n8IFyOf+akcxnrt9sNg==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/center": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/projection": "^6.5.0", - "d3-geo": "1.7.1", - "turf-jsts": "*" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/center": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/center/-/center-6.5.0.tgz", - "integrity": "sha512-T8KtMTfSATWcAX088rEDKjyvQCBkUsLnK/Txb6/8WUXIeOZyHu42G7MkdkHRoHtwieLdduDdmPLFyTdG5/e7ZQ==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/center-mean": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/center-mean/-/center-mean-6.5.0.tgz", - "integrity": "sha512-AAX6f4bVn12pTVrMUiB9KrnV94BgeBKpyg3YpfnEbBpkN/znfVhL8dG8IxMAxAoSZ61Zt9WLY34HfENveuOZ7Q==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/center-median": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/center-median/-/center-median-6.5.0.tgz", - "integrity": "sha512-dT8Ndu5CiZkPrj15PBvslpuf01ky41DEYEPxS01LOxp5HOUHXp1oJxsPxvc+i/wK4BwccPNzU1vzJ0S4emd1KQ==", - "dependencies": { - "@turf/center-mean": "^6.5.0", - "@turf/centroid": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/center-of-mass": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/center-of-mass/-/center-of-mass-6.5.0.tgz", - "integrity": "sha512-EWrriU6LraOfPN7m1jZi+1NLTKNkuIsGLZc2+Y8zbGruvUW+QV7K0nhf7iZWutlxHXTBqEXHbKue/o79IumAsQ==", - "dependencies": { - "@turf/centroid": "^6.5.0", - "@turf/convex": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/centroid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/centroid/-/centroid-6.5.0.tgz", - "integrity": "sha512-MwE1oq5E3isewPprEClbfU5pXljIK/GUOMbn22UM3IFPDJX0KeoyLNwghszkdmFp/qMGL/M13MMWvU+GNLXP/A==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/circle": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/circle/-/circle-6.5.0.tgz", - "integrity": "sha512-oU1+Kq9DgRnoSbWFHKnnUdTmtcRUMmHoV9DjTXu9vOLNV5OWtAAh1VZ+mzsioGGzoDNT/V5igbFOkMfBQc0B6A==", - "dependencies": { - "@turf/destination": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/clean-coords": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/clean-coords/-/clean-coords-6.5.0.tgz", - "integrity": "sha512-EMX7gyZz0WTH/ET7xV8MyrExywfm9qUi0/MY89yNffzGIEHuFfqwhcCqZ8O00rZIPZHUTxpmsxQSTfzJJA1CPw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/clone": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/clone/-/clone-6.5.0.tgz", - "integrity": "sha512-mzVtTFj/QycXOn6ig+annKrM6ZlimreKYz6f/GSERytOpgzodbQyOgkfwru100O1KQhhjSudKK4DsQ0oyi9cTw==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/clusters": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/clusters/-/clusters-6.5.0.tgz", - "integrity": "sha512-Y6gfnTJzQ1hdLfCsyd5zApNbfLIxYEpmDibHUqR5z03Lpe02pa78JtgrgUNt1seeO/aJ4TG1NLN8V5gOrHk04g==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/clusters-dbscan": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/clusters-dbscan/-/clusters-dbscan-6.5.0.tgz", - "integrity": "sha512-SxZEE4kADU9DqLRiT53QZBBhu8EP9skviSyl+FGj08Y01xfICM/RR9ACUdM0aEQimhpu+ZpRVcUK+2jtiCGrYQ==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0", - "density-clustering": "1.3.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/clusters-kmeans": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/clusters-kmeans/-/clusters-kmeans-6.5.0.tgz", - "integrity": "sha512-DwacD5+YO8kwDPKaXwT9DV46tMBVNsbi1IzdajZu1JDSWoN7yc7N9Qt88oi+p30583O0UPVkAK+A10WAQv4mUw==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "skmeans": "0.9.7" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/collect": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/collect/-/collect-6.5.0.tgz", - "integrity": "sha512-4dN/T6LNnRg099m97BJeOcTA5fSI8cu87Ydgfibewd2KQwBexO69AnjEFqfPX3Wj+Zvisj1uAVIZbPmSSrZkjg==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "rbush": "2.x" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/combine": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/combine/-/combine-6.5.0.tgz", - "integrity": "sha512-Q8EIC4OtAcHiJB3C4R+FpB4LANiT90t17uOd851qkM2/o6m39bfN5Mv0PWqMZIHWrrosZqRqoY9dJnzz/rJxYQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/concave": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/concave/-/concave-6.5.0.tgz", - "integrity": "sha512-I/sUmUC8TC5h/E2vPwxVht+nRt+TnXIPRoztDFvS8/Y0+cBDple9inLSo9nnPXMXidrBlGXZ9vQx/BjZUJgsRQ==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/tin": "^6.5.0", - "topojson-client": "3.x", - "topojson-server": "3.x" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/convex": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/convex/-/convex-6.5.0.tgz", - "integrity": "sha512-x7ZwC5z7PJB0SBwNh7JCeCNx7Iu+QSrH7fYgK0RhhNop13TqUlvHMirMLRgf2db1DqUetrAO2qHJeIuasquUWg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0", - "concaveman": "*" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/destination": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/destination/-/destination-6.5.0.tgz", - "integrity": "sha512-4cnWQlNC8d1tItOz9B4pmJdWpXqS0vEvv65bI/Pj/genJnsL7evI0/Xw42RvEGROS481MPiU80xzvwxEvhQiMQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/difference": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/difference/-/difference-6.5.0.tgz", - "integrity": "sha512-l8iR5uJqvI+5Fs6leNbhPY5t/a3vipUF/3AeVLpwPQcgmedNXyheYuy07PcMGH5Jdpi5gItOiTqwiU/bUH4b3A==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "polygon-clipping": "^0.15.3" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/dissolve": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/dissolve/-/dissolve-6.5.0.tgz", - "integrity": "sha512-WBVbpm9zLTp0Bl9CE35NomTaOL1c4TQCtEoO43YaAhNEWJOOIhZMFJyr8mbvYruKl817KinT3x7aYjjCMjTAsQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "polygon-clipping": "^0.15.3" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/distance": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/distance/-/distance-6.5.0.tgz", - "integrity": "sha512-xzykSLfoURec5qvQJcfifw/1mJa+5UwByZZ5TZ8iaqjGYN0vomhV9aiSLeYdUGtYRESZ+DYC/OzY+4RclZYgMg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/distance-weight": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/distance-weight/-/distance-weight-6.5.0.tgz", - "integrity": "sha512-a8qBKkgVNvPKBfZfEJZnC3DV7dfIsC3UIdpRci/iap/wZLH41EmS90nM+BokAJflUHYy8PqE44wySGWHN1FXrQ==", - "dependencies": { - "@turf/centroid": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/ellipse": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/ellipse/-/ellipse-6.5.0.tgz", - "integrity": "sha512-kuXtwFviw/JqnyJXF1mrR/cb496zDTSbGKtSiolWMNImYzGGkbsAsFTjwJYgD7+4FixHjp0uQPzo70KDf3AIBw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/rhumb-destination": "^6.5.0", - "@turf/transform-rotate": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/envelope": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/envelope/-/envelope-6.5.0.tgz", - "integrity": "sha512-9Z+FnBWvOGOU4X+fMZxYFs1HjFlkKqsddLuMknRaqcJd6t+NIv5DWvPtDL8ATD2GEExYDiFLwMdckfr1yqJgHA==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/bbox-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/explode": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/explode/-/explode-6.5.0.tgz", - "integrity": "sha512-6cSvMrnHm2qAsace6pw9cDmK2buAlw8+tjeJVXMfMyY+w7ZUi1rprWMsY92J7s2Dar63Bv09n56/1V7+tcj52Q==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/flatten": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/flatten/-/flatten-6.5.0.tgz", - "integrity": "sha512-IBZVwoNLVNT6U/bcUUllubgElzpMsNoCw8tLqBw6dfYg9ObGmpEjf9BIYLr7a2Yn5ZR4l7YIj2T7kD5uJjZADQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/flip": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/flip/-/flip-6.5.0.tgz", - "integrity": "sha512-oyikJFNjt2LmIXQqgOGLvt70RgE2lyzPMloYWM7OR5oIFGRiBvqVD2hA6MNw6JewIm30fWZ8DQJw1NHXJTJPbg==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/great-circle": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/great-circle/-/great-circle-6.5.0.tgz", - "integrity": "sha512-7ovyi3HaKOXdFyN7yy1yOMa8IyOvV46RC1QOQTT+RYUN8ke10eyqExwBpL9RFUPvlpoTzoYbM/+lWPogQlFncg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/helpers": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/helpers/-/helpers-6.5.0.tgz", - "integrity": "sha512-VbI1dV5bLFzohYYdgqwikdMVpe7pJ9X3E+dlr425wa2/sMJqYDhTO++ec38/pcPvPE6oD9WEEeU3Xu3gza+VPw==", - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/hex-grid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/hex-grid/-/hex-grid-6.5.0.tgz", - "integrity": "sha512-Ln3tc2tgZT8etDOldgc6e741Smg1CsMKAz1/Mlel+MEL5Ynv2mhx3m0q4J9IB1F3a4MNjDeVvm8drAaf9SF33g==", - "dependencies": { - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/intersect": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/interpolate": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/interpolate/-/interpolate-6.5.0.tgz", - "integrity": "sha512-LSH5fMeiGyuDZ4WrDJNgh81d2DnNDUVJtuFryJFup8PV8jbs46lQGfI3r1DJ2p1IlEJIz3pmAZYeTfMMoeeohw==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/centroid": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/hex-grid": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/point-grid": "^6.5.0", - "@turf/square-grid": "^6.5.0", - "@turf/triangle-grid": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/intersect": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/intersect/-/intersect-6.5.0.tgz", - "integrity": "sha512-2legGJeKrfFkzntcd4GouPugoqPUjexPZnOvfez+3SfIMrHvulw8qV8u7pfVyn2Yqs53yoVCEjS5sEpvQ5YRQg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "polygon-clipping": "^0.15.3" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/invariant": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/invariant/-/invariant-6.5.0.tgz", - "integrity": "sha512-Wv8PRNCtPD31UVbdJE/KVAWKe7l6US+lJItRR/HOEW3eh+U/JwRCSUl/KZ7bmjM/C+zLNoreM2TU6OoLACs4eg==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/isobands": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/isobands/-/isobands-6.5.0.tgz", - "integrity": "sha512-4h6sjBPhRwMVuFaVBv70YB7eGz+iw0bhPRnp+8JBdX1UPJSXhoi/ZF2rACemRUr0HkdVB/a1r9gC32vn5IAEkw==", - "dependencies": { - "@turf/area": "^6.5.0", - "@turf/bbox": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/explode": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "object-assign": "*" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/isolines": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/isolines/-/isolines-6.5.0.tgz", - "integrity": "sha512-6ElhiLCopxWlv4tPoxiCzASWt/jMRvmp6mRYrpzOm3EUl75OhHKa/Pu6Y9nWtCMmVC/RcWtiiweUocbPLZLm0A==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "object-assign": "*" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/kinks": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/kinks/-/kinks-6.5.0.tgz", - "integrity": "sha512-ViCngdPt1eEL7hYUHR2eHR662GvCgTc35ZJFaNR6kRtr6D8plLaDju0FILeFFWSc+o8e3fwxZEJKmFj9IzPiIQ==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/length": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/length/-/length-6.5.0.tgz", - "integrity": "sha512-5pL5/pnw52fck3oRsHDcSGrj9HibvtlrZ0QNy2OcW8qBFDNgZ4jtl6U7eATVoyWPKBHszW3dWETW+iLV7UARig==", - "dependencies": { - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-arc": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-arc/-/line-arc-6.5.0.tgz", - "integrity": "sha512-I6c+V6mIyEwbtg9P9zSFF89T7QPe1DPTG3MJJ6Cm1MrAY0MdejwQKOpsvNl8LDU2ekHOlz2kHpPVR7VJsoMllA==", - "dependencies": { - "@turf/circle": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-chunk": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-chunk/-/line-chunk-6.5.0.tgz", - "integrity": "sha512-i1FGE6YJaaYa+IJesTfyRRQZP31QouS+wh/pa6O3CC0q4T7LtHigyBSYjrbjSLfn2EVPYGlPCMFEqNWCOkC6zg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/length": "^6.5.0", - "@turf/line-slice-along": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-intersect": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-intersect/-/line-intersect-6.5.0.tgz", - "integrity": "sha512-CS6R1tZvVQD390G9Ea4pmpM6mJGPWoL82jD46y0q1KSor9s6HupMIo1kY4Ny+AEYQl9jd21V3Scz20eldpbTVA==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/meta": "^6.5.0", - "geojson-rbush": "3.x" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-offset": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-offset/-/line-offset-6.5.0.tgz", - "integrity": "sha512-CEXZbKgyz8r72qRvPchK0dxqsq8IQBdH275FE6o4MrBkzMcoZsfSjghtXzKaz9vvro+HfIXal0sTk2mqV1lQTw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-overlap": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-overlap/-/line-overlap-6.5.0.tgz", - "integrity": "sha512-xHOaWLd0hkaC/1OLcStCpfq55lPHpPNadZySDXYiYjEz5HXr1oKmtMYpn0wGizsLwrOixRdEp+j7bL8dPt4ojQ==", - "dependencies": { - "@turf/boolean-point-on-line": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/nearest-point-on-line": "^6.5.0", - "deep-equal": "1.x", - "geojson-rbush": "3.x" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-segment": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-segment/-/line-segment-6.5.0.tgz", - "integrity": "sha512-jI625Ho4jSuJESNq66Mmi290ZJ5pPZiQZruPVpmHkUw257Pew0alMmb6YrqYNnLUuiVVONxAAKXUVeeUGtycfw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-slice": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-slice/-/line-slice-6.5.0.tgz", - "integrity": "sha512-vDqJxve9tBHhOaVVFXqVjF5qDzGtKWviyjbyi2QnSnxyFAmLlLnBfMX8TLQCAf2GxHibB95RO5FBE6I2KVPRuw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/nearest-point-on-line": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-slice-along": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-slice-along/-/line-slice-along-6.5.0.tgz", - "integrity": "sha512-KHJRU6KpHrAj+BTgTNqby6VCTnDzG6a1sJx/I3hNvqMBLvWVA2IrkR9L9DtsQsVY63IBwVdQDqiwCuZLDQh4Ng==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-split": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-split/-/line-split-6.5.0.tgz", - "integrity": "sha512-/rwUMVr9OI2ccJjw7/6eTN53URtGThNSD5I0GgxyFXMtxWiloRJ9MTff8jBbtPWrRka/Sh2GkwucVRAEakx9Sw==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/nearest-point-on-line": "^6.5.0", - "@turf/square": "^6.5.0", - "@turf/truncate": "^6.5.0", - "geojson-rbush": "3.x" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/line-to-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/line-to-polygon/-/line-to-polygon-6.5.0.tgz", - "integrity": "sha512-qYBuRCJJL8Gx27OwCD1TMijM/9XjRgXH/m/TyuND4OXedBpIWlK5VbTIO2gJ8OCfznBBddpjiObLBrkuxTpN4Q==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/mask": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/mask/-/mask-6.5.0.tgz", - "integrity": "sha512-RQha4aU8LpBrmrkH8CPaaoAfk0Egj5OuXtv6HuCQnHeGNOQt3TQVibTA3Sh4iduq4EPxnZfDjgsOeKtrCA19lg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "polygon-clipping": "^0.15.3" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/meta": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/meta/-/meta-6.5.0.tgz", - "integrity": "sha512-RrArvtsV0vdsCBegoBtOalgdSOfkBrTJ07VkpiCnq/491W67hnMWmDu7e6Ztw0C3WldRYTXkg3SumfdzZxLBHA==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/midpoint": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/midpoint/-/midpoint-6.5.0.tgz", - "integrity": "sha512-MyTzV44IwmVI6ec9fB2OgZ53JGNlgOpaYl9ArKoF49rXpL84F9rNATndbe0+MQIhdkw8IlzA6xVP4lZzfMNVCw==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/moran-index": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/moran-index/-/moran-index-6.5.0.tgz", - "integrity": "sha512-ItsnhrU2XYtTtTudrM8so4afBCYWNaB0Mfy28NZwLjB5jWuAsvyV+YW+J88+neK/ougKMTawkmjQqodNJaBeLQ==", - "dependencies": { - "@turf/distance-weight": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/nearest-point": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/nearest-point/-/nearest-point-6.5.0.tgz", - "integrity": "sha512-fguV09QxilZv/p94s8SMsXILIAMiaXI5PATq9d7YWijLxWUj6Q/r43kxyoi78Zmwwh1Zfqz9w+bCYUAxZ5+euA==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/nearest-point-on-line": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/nearest-point-on-line/-/nearest-point-on-line-6.5.0.tgz", - "integrity": "sha512-WthrvddddvmymnC+Vf7BrkHGbDOUu6Z3/6bFYUGv1kxw8tiZ6n83/VG6kHz4poHOfS0RaNflzXSkmCi64fLBlg==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/nearest-point-to-line": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/nearest-point-to-line/-/nearest-point-to-line-6.5.0.tgz", - "integrity": "sha512-PXV7cN0BVzUZdjj6oeb/ESnzXSfWmEMrsfZSDRgqyZ9ytdiIj/eRsnOXLR13LkTdXVOJYDBuf7xt1mLhM4p6+Q==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/point-to-line-distance": "^6.5.0", - "object-assign": "*" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/planepoint": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/planepoint/-/planepoint-6.5.0.tgz", - "integrity": "sha512-R3AahA6DUvtFbka1kcJHqZ7DMHmPXDEQpbU5WaglNn7NaCQg9HB0XM0ZfqWcd5u92YXV+Gg8QhC8x5XojfcM4Q==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/point-grid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/point-grid/-/point-grid-6.5.0.tgz", - "integrity": "sha512-Iq38lFokNNtQJnOj/RBKmyt6dlof0yhaHEDELaWHuECm1lIZLY3ZbVMwbs+nXkwTAHjKfS/OtMheUBkw+ee49w==", - "dependencies": { - "@turf/boolean-within": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/point-on-feature": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/point-on-feature/-/point-on-feature-6.5.0.tgz", - "integrity": "sha512-bDpuIlvugJhfcF/0awAQ+QI6Om1Y1FFYE8Y/YdxGRongivix850dTeXCo0mDylFdWFPGDo7Mmh9Vo4VxNwW/TA==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/center": "^6.5.0", - "@turf/explode": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/nearest-point": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/point-to-line-distance": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/point-to-line-distance/-/point-to-line-distance-6.5.0.tgz", - "integrity": "sha512-opHVQ4vjUhNBly1bob6RWy+F+hsZDH9SA0UW36pIRzfpu27qipU18xup0XXEePfY6+wvhF6yL/WgCO2IbrLqEA==", - "dependencies": { - "@turf/bearing": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/projection": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0", - "@turf/rhumb-distance": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/points-within-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/points-within-polygon/-/points-within-polygon-6.5.0.tgz", - "integrity": "sha512-YyuheKqjliDsBDt3Ho73QVZk1VXX1+zIA2gwWvuz8bR1HXOkcuwk/1J76HuFMOQI3WK78wyAi+xbkx268PkQzQ==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/polygon-smooth": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/polygon-smooth/-/polygon-smooth-6.5.0.tgz", - "integrity": "sha512-LO/X/5hfh/Rk4EfkDBpLlVwt3i6IXdtQccDT9rMjXEP32tRgy0VMFmdkNaXoGlSSKf/1mGqLl4y4wHd86DqKbg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/polygon-tangents": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/polygon-tangents/-/polygon-tangents-6.5.0.tgz", - "integrity": "sha512-sB4/IUqJMYRQH9jVBwqS/XDitkEfbyqRy+EH/cMRJURTg78eHunvJ708x5r6umXsbiUyQU4eqgPzEylWEQiunw==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/boolean-within": "^6.5.0", - "@turf/explode": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/nearest-point": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/polygon-to-line": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/polygon-to-line/-/polygon-to-line-6.5.0.tgz", - "integrity": "sha512-5p4n/ij97EIttAq+ewSnKt0ruvuM+LIDzuczSzuHTpq4oS7Oq8yqg5TQ4nzMVuK41r/tALCk7nAoBuw3Su4Gcw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/polygonize": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/polygonize/-/polygonize-6.5.0.tgz", - "integrity": "sha512-a/3GzHRaCyzg7tVYHo43QUChCspa99oK4yPqooVIwTC61npFzdrmnywMv0S+WZjHZwK37BrFJGFrZGf6ocmY5w==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/envelope": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/projection": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/projection/-/projection-6.5.0.tgz", - "integrity": "sha512-/Pgh9mDvQWWu8HRxqpM+tKz8OzgauV+DiOcr3FCjD6ubDnrrmMJlsf6fFJmggw93mtVPrZRL6yyi9aYCQBOIvg==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/random": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/random/-/random-6.5.0.tgz", - "integrity": "sha512-8Q25gQ/XbA7HJAe+eXp4UhcXM9aOOJFaxZ02+XSNwMvY8gtWSCBLVqRcW4OhqilgZ8PeuQDWgBxeo+BIqqFWFQ==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/rectangle-grid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/rectangle-grid/-/rectangle-grid-6.5.0.tgz", - "integrity": "sha512-yQZ/1vbW68O2KsSB3OZYK+72aWz/Adnf7m2CMKcC+aq6TwjxZjAvlbCOsNUnMAuldRUVN1ph6RXMG4e9KEvKvg==", - "dependencies": { - "@turf/boolean-intersects": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/rewind": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/rewind/-/rewind-6.5.0.tgz", - "integrity": "sha512-IoUAMcHWotBWYwSYuYypw/LlqZmO+wcBpn8ysrBNbazkFNkLf3btSDZMkKJO/bvOzl55imr/Xj4fi3DdsLsbzQ==", - "dependencies": { - "@turf/boolean-clockwise": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/rhumb-bearing": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/rhumb-bearing/-/rhumb-bearing-6.5.0.tgz", - "integrity": "sha512-jMyqiMRK4hzREjQmnLXmkJ+VTNTx1ii8vuqRwJPcTlKbNWfjDz/5JqJlb5NaFDcdMpftWovkW5GevfnuzHnOYA==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/rhumb-destination": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/rhumb-destination/-/rhumb-destination-6.5.0.tgz", - "integrity": "sha512-RHNP1Oy+7xTTdRrTt375jOZeHceFbjwohPHlr9Hf68VdHHPMAWgAKqiX2YgSWDcvECVmiGaBKWus1Df+N7eE4Q==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/rhumb-distance": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/rhumb-distance/-/rhumb-distance-6.5.0.tgz", - "integrity": "sha512-oKp8KFE8E4huC2Z1a1KNcFwjVOqa99isxNOwfo4g3SUABQ6NezjKDDrnvC4yI5YZ3/huDjULLBvhed45xdCrzg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/sample": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/sample/-/sample-6.5.0.tgz", - "integrity": "sha512-kSdCwY7el15xQjnXYW520heKUrHwRvnzx8ka4eYxX9NFeOxaFITLW2G7UtXb6LJK8mmPXI8Aexv23F2ERqzGFg==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/sector": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/sector/-/sector-6.5.0.tgz", - "integrity": "sha512-cYUOkgCTWqa23SOJBqxoFAc/yGCUsPRdn/ovbRTn1zNTm/Spmk6hVB84LCKOgHqvSF25i0d2kWqpZDzLDdAPbw==", - "dependencies": { - "@turf/circle": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/line-arc": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/shortest-path": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/shortest-path/-/shortest-path-6.5.0.tgz", - "integrity": "sha512-4de5+G7+P4hgSoPwn+SO9QSi9HY5NEV/xRJ+cmoFVRwv2CDsuOPDheHKeuIAhKyeKDvPvPt04XYWbac4insJMg==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/bbox-polygon": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/clean-coords": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/transform-scale": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/simplify": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/simplify/-/simplify-6.5.0.tgz", - "integrity": "sha512-USas3QqffPHUY184dwQdP8qsvcVH/PWBYdXY5am7YTBACaQOMAlf6AKJs9FT8jiO6fQpxfgxuEtwmox+pBtlOg==", - "dependencies": { - "@turf/clean-coords": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/square": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/square/-/square-6.5.0.tgz", - "integrity": "sha512-BM2UyWDmiuHCadVhHXKIx5CQQbNCpOxB6S/aCNOCLbhCeypKX5Q0Aosc5YcmCJgkwO5BERCC6Ee7NMbNB2vHmQ==", - "dependencies": { - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/square-grid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/square-grid/-/square-grid-6.5.0.tgz", - "integrity": "sha512-mlR0ayUdA+L4c9h7p4k3pX6gPWHNGuZkt2c5II1TJRmhLkW2557d6b/Vjfd1z9OVaajb1HinIs1FMSAPXuuUrA==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/rectangle-grid": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/standard-deviational-ellipse": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/standard-deviational-ellipse/-/standard-deviational-ellipse-6.5.0.tgz", - "integrity": "sha512-02CAlz8POvGPFK2BKK8uHGUk/LXb0MK459JVjKxLC2yJYieOBTqEbjP0qaWhiBhGzIxSMaqe8WxZ0KvqdnstHA==", - "dependencies": { - "@turf/center-mean": "^6.5.0", - "@turf/ellipse": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/points-within-polygon": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/tag": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/tag/-/tag-6.5.0.tgz", - "integrity": "sha512-XwlBvrOV38CQsrNfrxvBaAPBQgXMljeU0DV8ExOyGM7/hvuGHJw3y8kKnQ4lmEQcmcrycjDQhP7JqoRv8vFssg==", - "dependencies": { - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/tesselate": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/tesselate/-/tesselate-6.5.0.tgz", - "integrity": "sha512-M1HXuyZFCfEIIKkglh/r5L9H3c5QTEsnMBoZOFQiRnGPGmJWcaBissGb7mTFX2+DKE7FNWXh4TDnZlaLABB0dQ==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "earcut": "^2.0.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/tin": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/tin/-/tin-6.5.0.tgz", - "integrity": "sha512-YLYikRzKisfwj7+F+Tmyy/LE3d2H7D4kajajIfc9mlik2+esG7IolsX/+oUz1biguDYsG0DUA8kVYXDkobukfg==", - "dependencies": { - "@turf/helpers": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/transform-rotate": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/transform-rotate/-/transform-rotate-6.5.0.tgz", - "integrity": "sha512-A2Ip1v4246ZmpssxpcL0hhiVBEf4L8lGnSPWTgSv5bWBEoya2fa/0SnFX9xJgP40rMP+ZzRaCN37vLHbv1Guag==", - "dependencies": { - "@turf/centroid": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0", - "@turf/rhumb-destination": "^6.5.0", - "@turf/rhumb-distance": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/transform-scale": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/transform-scale/-/transform-scale-6.5.0.tgz", - "integrity": "sha512-VsATGXC9rYM8qTjbQJ/P7BswKWXHdnSJ35JlV4OsZyHBMxJQHftvmZJsFbOqVtQnIQIzf2OAly6rfzVV9QLr7g==", - "dependencies": { - "@turf/bbox": "^6.5.0", - "@turf/center": "^6.5.0", - "@turf/centroid": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0", - "@turf/rhumb-destination": "^6.5.0", - "@turf/rhumb-distance": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/transform-translate": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/transform-translate/-/transform-translate-6.5.0.tgz", - "integrity": "sha512-NABLw5VdtJt/9vSstChp93pc6oel4qXEos56RBMsPlYB8hzNTEKYtC146XJvyF4twJeeYS8RVe1u7KhoFwEM5w==", - "dependencies": { - "@turf/clone": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/rhumb-destination": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/triangle-grid": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/triangle-grid/-/triangle-grid-6.5.0.tgz", - "integrity": "sha512-2jToUSAS1R1htq4TyLQYPTIsoy6wg3e3BQXjm2rANzw4wPQCXGOxrur1Fy9RtzwqwljlC7DF4tg0OnWr8RjmfA==", - "dependencies": { - "@turf/distance": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/intersect": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/truncate": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/truncate/-/truncate-6.5.0.tgz", - "integrity": "sha512-pFxg71pLk+eJj134Z9yUoRhIi8vqnnKvCYwdT4x/DQl/19RVdq1tV3yqOT3gcTQNfniteylL5qV1uTBDV5sgrg==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/turf": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/turf/-/turf-6.5.0.tgz", - "integrity": "sha512-ipMCPnhu59bh92MNt8+pr1VZQhHVuTMHklciQURo54heoxRzt1neNYZOBR6jdL+hNsbDGAECMuIpAutX+a3Y+w==", - "dependencies": { - "@turf/along": "^6.5.0", - "@turf/angle": "^6.5.0", - "@turf/area": "^6.5.0", - "@turf/bbox": "^6.5.0", - "@turf/bbox-clip": "^6.5.0", - "@turf/bbox-polygon": "^6.5.0", - "@turf/bearing": "^6.5.0", - "@turf/bezier-spline": "^6.5.0", - "@turf/boolean-clockwise": "^6.5.0", - "@turf/boolean-contains": "^6.5.0", - "@turf/boolean-crosses": "^6.5.0", - "@turf/boolean-disjoint": "^6.5.0", - "@turf/boolean-equal": "^6.5.0", - "@turf/boolean-intersects": "^6.5.0", - "@turf/boolean-overlap": "^6.5.0", - "@turf/boolean-parallel": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/boolean-point-on-line": "^6.5.0", - "@turf/boolean-within": "^6.5.0", - "@turf/buffer": "^6.5.0", - "@turf/center": "^6.5.0", - "@turf/center-mean": "^6.5.0", - "@turf/center-median": "^6.5.0", - "@turf/center-of-mass": "^6.5.0", - "@turf/centroid": "^6.5.0", - "@turf/circle": "^6.5.0", - "@turf/clean-coords": "^6.5.0", - "@turf/clone": "^6.5.0", - "@turf/clusters": "^6.5.0", - "@turf/clusters-dbscan": "^6.5.0", - "@turf/clusters-kmeans": "^6.5.0", - "@turf/collect": "^6.5.0", - "@turf/combine": "^6.5.0", - "@turf/concave": "^6.5.0", - "@turf/convex": "^6.5.0", - "@turf/destination": "^6.5.0", - "@turf/difference": "^6.5.0", - "@turf/dissolve": "^6.5.0", - "@turf/distance": "^6.5.0", - "@turf/distance-weight": "^6.5.0", - "@turf/ellipse": "^6.5.0", - "@turf/envelope": "^6.5.0", - "@turf/explode": "^6.5.0", - "@turf/flatten": "^6.5.0", - "@turf/flip": "^6.5.0", - "@turf/great-circle": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/hex-grid": "^6.5.0", - "@turf/interpolate": "^6.5.0", - "@turf/intersect": "^6.5.0", - "@turf/invariant": "^6.5.0", - "@turf/isobands": "^6.5.0", - "@turf/isolines": "^6.5.0", - "@turf/kinks": "^6.5.0", - "@turf/length": "^6.5.0", - "@turf/line-arc": "^6.5.0", - "@turf/line-chunk": "^6.5.0", - "@turf/line-intersect": "^6.5.0", - "@turf/line-offset": "^6.5.0", - "@turf/line-overlap": "^6.5.0", - "@turf/line-segment": "^6.5.0", - "@turf/line-slice": "^6.5.0", - "@turf/line-slice-along": "^6.5.0", - "@turf/line-split": "^6.5.0", - "@turf/line-to-polygon": "^6.5.0", - "@turf/mask": "^6.5.0", - "@turf/meta": "^6.5.0", - "@turf/midpoint": "^6.5.0", - "@turf/moran-index": "^6.5.0", - "@turf/nearest-point": "^6.5.0", - "@turf/nearest-point-on-line": "^6.5.0", - "@turf/nearest-point-to-line": "^6.5.0", - "@turf/planepoint": "^6.5.0", - "@turf/point-grid": "^6.5.0", - "@turf/point-on-feature": "^6.5.0", - "@turf/point-to-line-distance": "^6.5.0", - "@turf/points-within-polygon": "^6.5.0", - "@turf/polygon-smooth": "^6.5.0", - "@turf/polygon-tangents": "^6.5.0", - "@turf/polygon-to-line": "^6.5.0", - "@turf/polygonize": "^6.5.0", - "@turf/projection": "^6.5.0", - "@turf/random": "^6.5.0", - "@turf/rewind": "^6.5.0", - "@turf/rhumb-bearing": "^6.5.0", - "@turf/rhumb-destination": "^6.5.0", - "@turf/rhumb-distance": "^6.5.0", - "@turf/sample": "^6.5.0", - "@turf/sector": "^6.5.0", - "@turf/shortest-path": "^6.5.0", - "@turf/simplify": "^6.5.0", - "@turf/square": "^6.5.0", - "@turf/square-grid": "^6.5.0", - "@turf/standard-deviational-ellipse": "^6.5.0", - "@turf/tag": "^6.5.0", - "@turf/tesselate": "^6.5.0", - "@turf/tin": "^6.5.0", - "@turf/transform-rotate": "^6.5.0", - "@turf/transform-scale": "^6.5.0", - "@turf/transform-translate": "^6.5.0", - "@turf/triangle-grid": "^6.5.0", - "@turf/truncate": "^6.5.0", - "@turf/union": "^6.5.0", - "@turf/unkink-polygon": "^6.5.0", - "@turf/voronoi": "^6.5.0" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/union": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/union/-/union-6.5.0.tgz", - "integrity": "sha512-igYWCwP/f0RFHIlC2c0SKDuM/ObBaqSljI3IdV/x71805QbIvY/BYGcJdyNcgEA6cylIGl/0VSlIbpJHZ9ldhw==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "polygon-clipping": "^0.15.3" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/unkink-polygon": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/unkink-polygon/-/unkink-polygon-6.5.0.tgz", - "integrity": "sha512-8QswkzC0UqKmN1DT6HpA9upfa1HdAA5n6bbuzHy8NJOX8oVizVAqfEPY0wqqTgboDjmBR4yyImsdPGUl3gZ8JQ==", - "dependencies": { - "@turf/area": "^6.5.0", - "@turf/boolean-point-in-polygon": "^6.5.0", - "@turf/helpers": "^6.5.0", - "@turf/meta": "^6.5.0", - "rbush": "^2.0.1" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@turf/voronoi": { - "version": "6.5.0", - "resolved": "https://registry.npmmirror.com/@turf/voronoi/-/voronoi-6.5.0.tgz", - "integrity": "sha512-C/xUsywYX+7h1UyNqnydHXiun4UPjK88VDghtoRypR9cLlb7qozkiLRphQxxsCM0KxyxpVPHBVQXdAL3+Yurow==", - "dependencies": { - "@turf/helpers": "^6.5.0", - "@turf/invariant": "^6.5.0", - "d3-voronoi": "1.1.2" - }, - "funding": { - "url": "https://opencollective.com/turf" - } - }, - "node_modules/@types/geojson": { - "version": "7946.0.8", - "resolved": "https://registry.npmmirror.com/@types/geojson/-/geojson-7946.0.8.tgz", - "integrity": "sha512-1rkryxURpr6aWP7R786/UQOkJ3PcpQiWkAXBmdWc7ryFWqN6a4xfK7BtjXvFBKO9LjQ+MWQSWxYeZX1OApnArA==" - }, - "node_modules/@types/node": { - "version": "18.19.84", - "resolved": "https://registry.npmmirror.com/@types/node/-/node-18.19.84.tgz", - "integrity": "sha512-ACYy2HGcZPHxEeWTqowTF7dhXN+JU1o7Gr4b41klnn6pj2LD6rsiGqSZojMdk1Jh2ys3m76ap+ae1vvE4+5+vg==", - "dependencies": { - "undici-types": "~5.26.4" - } - }, - "node_modules/@types/node-fetch": { - "version": "2.6.12", - "resolved": "https://registry.npmmirror.com/@types/node-fetch/-/node-fetch-2.6.12.tgz", - "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", - "dependencies": { - "@types/node": "*", - "form-data": "^4.0.0" - } - }, - "node_modules/abbrev": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/abbrev/-/abbrev-1.1.1.tgz", - "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==" - }, - "node_modules/abort-controller": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/abort-controller/-/abort-controller-3.0.0.tgz", - "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", - "dependencies": { - "event-target-shim": "^5.0.0" - }, - "engines": { - "node": ">=6.5" - } - }, - "node_modules/agent-base": { - "version": "6.0.2", - "resolved": "https://registry.npmmirror.com/agent-base/-/agent-base-6.0.2.tgz", - "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", - "dependencies": { - "debug": "4" - }, - "engines": { - "node": ">= 6.0.0" - } - }, - "node_modules/agent-base/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/agentkeepalive": { - "version": "4.6.0", - "resolved": "https://registry.npmmirror.com/agentkeepalive/-/agentkeepalive-4.6.0.tgz", - "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", - "dependencies": { - "humanize-ms": "^1.2.1" - }, - "engines": { - "node": ">= 8.0.0" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/aproba": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/aproba/-/aproba-2.0.0.tgz", - "integrity": "sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==" - }, - "node_modules/are-we-there-yet": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/are-we-there-yet/-/are-we-there-yet-2.0.0.tgz", - "integrity": "sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==", - "deprecated": "This package is no longer supported.", - "dependencies": { - "delegates": "^1.0.0", - "readable-stream": "^3.6.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/asynckit": { - "version": "0.4.0", - "resolved": "https://registry.npmmirror.com/asynckit/-/asynckit-0.4.0.tgz", - "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" - }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==" - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmmirror.com/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/call-bind": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/call-bind/-/call-bind-1.0.8.tgz", - "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.0", - "es-define-property": "^1.0.0", - "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/call-bind-apply-helpers": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", - "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dependencies": { - "es-errors": "^1.3.0", - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/call-bound": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/call-bound/-/call-bound-1.0.4.tgz", - "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "get-intrinsic": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/canvas": { - "version": "2.11.2", - "resolved": "https://registry.npmmirror.com/canvas/-/canvas-2.11.2.tgz", - "integrity": "sha512-ItanGBMrmRV7Py2Z+Xhs7cT+FNt5K0vPL4p9EZ/UX/Mu7hFbkxSjKF2KVtPwX7UYWp7dRKnrTvReflgrItJbdw==", - "hasInstallScript": true, - "dependencies": { - "@mapbox/node-pre-gyp": "^1.0.0", - "nan": "^2.17.0", - "simple-get": "^3.0.3" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/chownr": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/chownr/-/chownr-2.0.0.tgz", - "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", - "engines": { - "node": ">=10" - } - }, - "node_modules/color": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/color/-/color-4.2.3.tgz", - "integrity": "sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==", - "dependencies": { - "color-convert": "^2.0.1", - "color-string": "^1.9.0" - }, - "engines": { - "node": ">=12.5.0" - } - }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/color-string": { - "version": "1.9.1", - "resolved": "https://registry.npmmirror.com/color-string/-/color-string-1.9.1.tgz", - "integrity": "sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==", - "dependencies": { - "color-name": "^1.0.0", - "simple-swizzle": "^0.2.2" - } - }, - "node_modules/color-support": { - "version": "1.1.3", - "resolved": "https://registry.npmmirror.com/color-support/-/color-support-1.1.3.tgz", - "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", - "bin": { - "color-support": "bin.js" - } - }, - "node_modules/combined-stream": { - "version": "1.0.8", - "resolved": "https://registry.npmmirror.com/combined-stream/-/combined-stream-1.0.8.tgz", - "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", - "dependencies": { - "delayed-stream": "~1.0.0" - }, - "engines": { - "node": ">= 0.8" - } - }, - "node_modules/commander": { - "version": "2.20.3", - "resolved": "https://registry.npmmirror.com/commander/-/commander-2.20.3.tgz", - "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmmirror.com/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==" - }, - "node_modules/concaveman": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/concaveman/-/concaveman-1.2.1.tgz", - "integrity": "sha512-PwZYKaM/ckQSa8peP5JpVr7IMJ4Nn/MHIaWUjP4be+KoZ7Botgs8seAZGpmaOM+UZXawcdYRao/px9ycrCihHw==", - "dependencies": { - "point-in-polygon": "^1.1.0", - "rbush": "^3.0.1", - "robust-predicates": "^2.0.4", - "tinyqueue": "^2.0.3" - } - }, - "node_modules/concaveman/node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" - }, - "node_modules/concaveman/node_modules/rbush": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", - "dependencies": { - "quickselect": "^2.0.0" - } - }, - "node_modules/console-control-strings": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/console-control-strings/-/console-control-strings-1.1.0.tgz", - "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==" - }, - "node_modules/d3-array": { - "version": "1.2.4", - "resolved": "https://registry.npmmirror.com/d3-array/-/d3-array-1.2.4.tgz", - "integrity": "sha512-KHW6M86R+FUPYGb3R5XiYjXPq7VzwxZ22buHhAEVG5ztoEcZZMLov530mmccaqA1GghZArjQV46fuc8kUqhhHw==" - }, - "node_modules/d3-geo": { - "version": "1.7.1", - "resolved": "https://registry.npmmirror.com/d3-geo/-/d3-geo-1.7.1.tgz", - "integrity": "sha512-O4AempWAr+P5qbk2bC2FuN/sDW4z+dN2wDf9QV3bxQt4M5HfOEeXLgJ/UKQW0+o1Dj8BE+L5kiDbdWUMjsmQpw==", - "dependencies": { - "d3-array": "1" - } - }, - "node_modules/d3-voronoi": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/d3-voronoi/-/d3-voronoi-1.1.2.tgz", - "integrity": "sha512-RhGS1u2vavcO7ay7ZNAPo4xeDh/VYeGof3x5ZLJBQgYhLegxr3s5IykvWmJ94FTU6mcbtp4sloqZ54mP6R4Utw==" - }, - "node_modules/debug": { - "version": "3.2.7", - "resolved": "https://registry.npmmirror.com/debug/-/debug-3.2.7.tgz", - "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", - "dependencies": { - "ms": "^2.1.1" - } - }, - "node_modules/decompress-response": { - "version": "4.2.1", - "resolved": "https://registry.npmmirror.com/decompress-response/-/decompress-response-4.2.1.tgz", - "integrity": "sha512-jOSne2qbyE+/r8G1VU+G/82LBs2Fs4LAsTiLSHOCOMZQl2OKZ6i8i4IyHemTe+/yIXOtTcRQMzPcgyhoFlqPkw==", - "dependencies": { - "mimic-response": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/deep-equal": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/deep-equal/-/deep-equal-1.1.2.tgz", - "integrity": "sha512-5tdhKF6DbU7iIzrIOa1AOUt39ZRm13cmL1cGEh//aqR8x9+tNfbywRf0n5FD/18OKMdo7DNEtrX2t22ZAkI+eg==", - "dependencies": { - "is-arguments": "^1.1.1", - "is-date-object": "^1.0.5", - "is-regex": "^1.1.4", - "object-is": "^1.1.5", - "object-keys": "^1.1.1", - "regexp.prototype.flags": "^1.5.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmmirror.com/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/delayed-stream": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delayed-stream/-/delayed-stream-1.0.0.tgz", - "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", - "engines": { - "node": ">=0.4.0" - } - }, - "node_modules/delegates": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/delegates/-/delegates-1.0.0.tgz", - "integrity": "sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==" - }, - "node_modules/density-clustering": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/density-clustering/-/density-clustering-1.3.0.tgz", - "integrity": "sha512-icpmBubVTwLnsaor9qH/4tG5+7+f61VcqMN3V3pm9sxxSCt2Jcs0zWOgwZW9ARJYaKD3FumIgHiMOcIMRRAzFQ==" - }, - "node_modules/detect-libc": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/detect-libc/-/detect-libc-2.0.3.tgz", - "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", - "engines": { - "node": ">=8" - } - }, - "node_modules/dommatrix": { - "version": "0.0.24", - "resolved": "https://registry.npmmirror.com/dommatrix/-/dommatrix-0.0.24.tgz", - "integrity": "sha512-PatEhAW5pIHr28MvFQGV5iiHNloqvecQZlxs7/8s/eulLqZI3uVqPkrO7YDuqsebovr/9mmcWDSWzVG4amEZgQ==" - }, - "node_modules/dunder-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/dunder-proto/-/dunder-proto-1.0.1.tgz", - "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.1", - "es-errors": "^1.3.0", - "gopd": "^1.2.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/earcut": { - "version": "2.2.4", - "resolved": "https://registry.npmmirror.com/earcut/-/earcut-2.2.4.tgz", - "integrity": "sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==" - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmmirror.com/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/es-define-property": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/es-define-property/-/es-define-property-1.0.1.tgz", - "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-errors": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/es-errors/-/es-errors-1.3.0.tgz", - "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-object-atoms": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/es-object-atoms/-/es-object-atoms-1.1.1.tgz", - "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dependencies": { - "es-errors": "^1.3.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-set-tostringtag": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", - "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dependencies": { - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/event-target-shim": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/event-target-shim/-/event-target-shim-5.0.1.tgz", - "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", - "engines": { - "node": ">=6" - } - }, - "node_modules/form-data": { - "version": "4.0.2", - "resolved": "https://registry.npmmirror.com/form-data/-/form-data-4.0.2.tgz", - "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", - "dependencies": { - "asynckit": "^0.4.0", - "combined-stream": "^1.0.8", - "es-set-tostringtag": "^2.1.0", - "mime-types": "^2.1.12" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/form-data-encoder": { - "version": "1.7.2", - "resolved": "https://registry.npmmirror.com/form-data-encoder/-/form-data-encoder-1.7.2.tgz", - "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==" - }, - "node_modules/formdata-node": { - "version": "4.4.1", - "resolved": "https://registry.npmmirror.com/formdata-node/-/formdata-node-4.4.1.tgz", - "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", - "dependencies": { - "node-domexception": "1.0.0", - "web-streams-polyfill": "4.0.0-beta.3" - }, - "engines": { - "node": ">= 12.20" - } - }, - "node_modules/fs-extra": { - "version": "11.3.0", - "resolved": "https://registry.npmmirror.com/fs-extra/-/fs-extra-11.3.0.tgz", - "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^6.0.1", - "universalify": "^2.0.0" - }, - "engines": { - "node": ">=14.14" - } - }, - "node_modules/fs-minipass": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/fs-minipass/-/fs-minipass-2.1.0.tgz", - "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", - "dependencies": { - "minipass": "^3.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/fs-minipass/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/fs.realpath": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/fs.realpath/-/fs.realpath-1.0.0.tgz", - "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==" - }, - "node_modules/function-bind": { - "version": "1.1.2", - "resolved": "https://registry.npmmirror.com/function-bind/-/function-bind-1.1.2.tgz", - "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/gauge": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/gauge/-/gauge-3.0.2.tgz", - "integrity": "sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==", - "deprecated": "This package is no longer supported.", - "dependencies": { - "aproba": "^1.0.3 || ^2.0.0", - "color-support": "^1.1.2", - "console-control-strings": "^1.0.0", - "has-unicode": "^2.0.1", - "object-assign": "^4.1.1", - "signal-exit": "^3.0.0", - "string-width": "^4.2.3", - "strip-ansi": "^6.0.1", - "wide-align": "^1.1.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/geojson-equality": { - "version": "0.1.6", - "resolved": "https://registry.npmmirror.com/geojson-equality/-/geojson-equality-0.1.6.tgz", - "integrity": "sha512-TqG8YbqizP3EfwP5Uw4aLu6pKkg6JQK9uq/XZ1lXQntvTHD1BBKJWhNpJ2M0ax6TuWMP3oyx6Oq7FCIfznrgpQ==", - "dependencies": { - "deep-equal": "^1.0.0" - } - }, - "node_modules/geojson-rbush": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/geojson-rbush/-/geojson-rbush-3.2.0.tgz", - "integrity": "sha512-oVltQTXolxvsz1sZnutlSuLDEcQAKYC/uXt9zDzJJ6bu0W+baTI8LZBaTup5afzibEH4N3jlq2p+a152wlBJ7w==", - "dependencies": { - "@turf/bbox": "*", - "@turf/helpers": "6.x", - "@turf/meta": "6.x", - "@types/geojson": "7946.0.8", - "rbush": "^3.0.1" - } - }, - "node_modules/geojson-rbush/node_modules/quickselect": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/quickselect/-/quickselect-2.0.0.tgz", - "integrity": "sha512-RKJ22hX8mHe3Y6wH/N3wCM6BWtjaxIyyUIkpHOvfFnxdI4yD4tBXEBKSbriGujF6jnSVkJrffuo6vxACiSSxIw==" - }, - "node_modules/geojson-rbush/node_modules/rbush": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/rbush/-/rbush-3.0.1.tgz", - "integrity": "sha512-XRaVO0YecOpEuIvbhbpTrZgoiI6xBlz6hnlr6EHhd+0x9ase6EmeN+hdwwUaJvLcsFFQ8iWVF1GAK1yB0BWi0w==", - "dependencies": { - "quickselect": "^2.0.0" - } - }, - "node_modules/get-intrinsic": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz", - "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "function-bind": "^1.1.2", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/get-proto": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/get-proto/-/get-proto-1.0.1.tgz", - "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/glob": { - "version": "7.2.3", - "resolved": "https://registry.npmmirror.com/glob/-/glob-7.2.3.tgz", - "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", - "deprecated": "Glob versions prior to v9 are no longer supported", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/gopd": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/gopd/-/gopd-1.2.0.tgz", - "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmmirror.com/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==" - }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-symbols": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/has-symbols/-/has-symbols-1.1.0.tgz", - "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-tostringtag": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/has-tostringtag/-/has-tostringtag-1.0.2.tgz", - "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dependencies": { - "has-symbols": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-unicode": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/has-unicode/-/has-unicode-2.0.1.tgz", - "integrity": "sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==" - }, - "node_modules/hasown": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/hasown/-/hasown-2.0.2.tgz", - "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dependencies": { - "function-bind": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/https-proxy-agent": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz", - "integrity": "sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==", - "dependencies": { - "agent-base": "6", - "debug": "4" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/https-proxy-agent/node_modules/debug": { - "version": "4.4.0", - "resolved": "https://registry.npmmirror.com/debug/-/debug-4.4.0.tgz", - "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/humanize-ms": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/humanize-ms/-/humanize-ms-1.2.1.tgz", - "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", - "dependencies": { - "ms": "^2.0.0" - } - }, - "node_modules/inflight": { - "version": "1.0.6", - "resolved": "https://registry.npmmirror.com/inflight/-/inflight-1.0.6.tgz", - "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", - "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", - "dependencies": { - "once": "^1.3.0", - "wrappy": "1" - } - }, - "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" - }, - "node_modules/is-arguments": { - "version": "1.2.0", - "resolved": "https://registry.npmmirror.com/is-arguments/-/is-arguments-1.2.0.tgz", - "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.3.2", - "resolved": "https://registry.npmmirror.com/is-arrayish/-/is-arrayish-0.3.2.tgz", - "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==" - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmmirror.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmmirror.com/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/jsonfile": { - "version": "6.1.0", - "resolved": "https://registry.npmmirror.com/jsonfile/-/jsonfile-6.1.0.tgz", - "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", - "dependencies": { - "universalify": "^2.0.0" - }, - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/mime-db": { - "version": "1.52.0", - "resolved": "https://registry.npmmirror.com/mime-db/-/mime-db-1.52.0.tgz", - "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mime-types": { - "version": "2.1.35", - "resolved": "https://registry.npmmirror.com/mime-types/-/mime-types-2.1.35.tgz", - "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", - "dependencies": { - "mime-db": "1.52.0" - }, - "engines": { - "node": ">= 0.6" - } - }, - "node_modules/mimic-response": { - "version": "2.1.0", - "resolved": "https://registry.npmmirror.com/mimic-response/-/mimic-response-2.1.0.tgz", - "integrity": "sha512-wXqjST+SLt7R009ySCglWBCFpjUygmCIfD790/kVbiGmUgfYGuB14PiTd5DwVxSV4NcYHjzMkoj5LjQZwTQLEA==", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "node_modules/minipass": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-5.0.0.tgz", - "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", - "engines": { - "node": ">=8" - } - }, - "node_modules/minizlib": { - "version": "2.1.2", - "resolved": "https://registry.npmmirror.com/minizlib/-/minizlib-2.1.2.tgz", - "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", - "dependencies": { - "minipass": "^3.0.0", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/minizlib/node_modules/minipass": { - "version": "3.3.6", - "resolved": "https://registry.npmmirror.com/minipass/-/minipass-3.3.6.tgz", - "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", - "dependencies": { - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/mkdirp": { - "version": "1.0.4", - "resolved": "https://registry.npmmirror.com/mkdirp/-/mkdirp-1.0.4.tgz", - "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", - "bin": { - "mkdirp": "bin/cmd.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmmirror.com/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" - }, - "node_modules/nan": { - "version": "2.22.2", - "resolved": "https://registry.npmmirror.com/nan/-/nan-2.22.2.tgz", - "integrity": "sha512-DANghxFkS1plDdRsX0X9pm0Z6SJNN6gBdtXfanwoZ8hooC5gosGFSBGRYHUVPz1asKA/kMRqDRdHrluZ61SpBQ==" - }, - "node_modules/node-domexception": { - "version": "1.0.0", - "resolved": "https://registry.npmmirror.com/node-domexception/-/node-domexception-1.0.0.tgz", - "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/jimmywarting" - }, - { - "type": "github", - "url": "https://paypal.me/jimmywarting" - } - ], - "engines": { - "node": ">=10.5.0" - } - }, - "node_modules/node-ensure": { - "version": "0.0.0", - "resolved": "https://registry.npmmirror.com/node-ensure/-/node-ensure-0.0.0.tgz", - "integrity": "sha512-DRI60hzo2oKN1ma0ckc6nQWlHU69RH6xN0sjQTjMpChPfTYvKZdcQFfdYK2RWbJcKyUizSIy/l8OTGxMAM1QDw==" - }, - "node_modules/node-fetch": { - "version": "2.7.0", - "resolved": "https://registry.npmmirror.com/node-fetch/-/node-fetch-2.7.0.tgz", - "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", - "dependencies": { - "whatwg-url": "^5.0.0" - }, - "engines": { - "node": "4.x || >=6.0.0" - }, - "peerDependencies": { - "encoding": "^0.1.0" - }, - "peerDependenciesMeta": { - "encoding": { - "optional": true - } - } - }, - "node_modules/nopt": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/nopt/-/nopt-5.0.0.tgz", - "integrity": "sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==", - "dependencies": { - "abbrev": "1" - }, - "bin": { - "nopt": "bin/nopt.js" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/npmlog": { - "version": "5.0.1", - "resolved": "https://registry.npmmirror.com/npmlog/-/npmlog-5.0.1.tgz", - "integrity": "sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==", - "deprecated": "This package is no longer supported.", - "dependencies": { - "are-we-there-yet": "^2.0.0", - "console-control-strings": "^1.1.0", - "gauge": "^3.0.0", - "set-blocking": "^2.0.0" - } - }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmmirror.com/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/object-is": { - "version": "1.1.6", - "resolved": "https://registry.npmmirror.com/object-is/-/object-is-1.1.6.tgz", - "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmmirror.com/once/-/once-1.4.0.tgz", - "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/openai": { - "version": "4.90.0", - "resolved": "https://registry.npmmirror.com/openai/-/openai-4.90.0.tgz", - "integrity": "sha512-YCuHMMycqtCg1B8G9ezkOF0j8UnBWD3Al/zYaelpuXwU1yhCEv+Y4n9G20MnyGy6cH4GsFwOMrgstQ+bgG1PtA==", - "dependencies": { - "@types/node": "^18.11.18", - "@types/node-fetch": "^2.6.4", - "abort-controller": "^3.0.0", - "agentkeepalive": "^4.2.1", - "form-data-encoder": "1.7.2", - "formdata-node": "^4.3.2", - "node-fetch": "^2.6.7" - }, - "bin": { - "openai": "bin/cli" - }, - "peerDependencies": { - "ws": "^8.18.0", - "zod": "^3.23.8" - }, - "peerDependenciesMeta": { - "ws": { - "optional": true - }, - "zod": { - "optional": true - } - } - }, - "node_modules/pako": { - "version": "1.0.11", - "resolved": "https://registry.npmmirror.com/pako/-/pako-1.0.11.tgz", - "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" - }, - "node_modules/path-is-absolute": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz", - "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/path2d-polyfill": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/path2d-polyfill/-/path2d-polyfill-2.0.1.tgz", - "integrity": "sha512-ad/3bsalbbWhmBo0D6FZ4RNMwsLsPpL6gnvhuSaU5Vm7b06Kr5ubSltQQ0T7YKsiJQO+g22zJ4dJKNTXIyOXtA==", - "optional": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pdf-lib": { - "version": "1.17.1", - "resolved": "https://registry.npmmirror.com/pdf-lib/-/pdf-lib-1.17.1.tgz", - "integrity": "sha512-V/mpyJAoTsN4cnP31vc0wfNA1+p20evqqnap0KLoRUN0Yk/p3wN52DOEsL4oBFcLdb76hlpKPtzJIgo67j/XLw==", - "dependencies": { - "@pdf-lib/standard-fonts": "^1.0.0", - "@pdf-lib/upng": "^1.0.1", - "pako": "^1.0.11", - "tslib": "^1.11.1" - } - }, - "node_modules/pdf-parse": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/pdf-parse/-/pdf-parse-1.1.1.tgz", - "integrity": "sha512-v6ZJ/efsBpGrGGknjtq9J/oC8tZWq0KWL5vQrk2GlzLEQPUDB1ex+13Rmidl1neNN358Jn9EHZw5y07FFtaC7A==", - "dependencies": { - "debug": "^3.1.0", - "node-ensure": "^0.0.0" - }, - "engines": { - "node": ">=6.8.1" - } - }, - "node_modules/pdf.js-extract": { - "version": "0.2.1", - "resolved": "https://registry.npmmirror.com/pdf.js-extract/-/pdf.js-extract-0.2.1.tgz", - "integrity": "sha512-oUs5KaTVCelIyiBajCx3zAZKurkN9oVwRdqbSeDqeofddxNuwJRur86fCETvKZ/tX5nZJUSZWq3ie76PsArz7A==", - "dependencies": { - "dommatrix": "0.0.24", - "web-streams-polyfill": "3.2.0" - }, - "engines": { - "node": ">=12.0.0" - } - }, - "node_modules/pdf.js-extract/node_modules/web-streams-polyfill": { - "version": "3.2.0", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-3.2.0.tgz", - "integrity": "sha512-EqPmREeOzttaLRm5HS7io98goBgZ7IVz79aDvqjD0kYXLtFZTc0T/U6wHTPKyIjb+MdN7DFIIX6hgdBEpWmfPA==", - "engines": { - "node": ">= 8" - } - }, - "node_modules/pdfjs-dist": { - "version": "3.11.174", - "resolved": "https://registry.npmmirror.com/pdfjs-dist/-/pdfjs-dist-3.11.174.tgz", - "integrity": "sha512-TdTZPf1trZ8/UFu5Cx/GXB7GZM30LT+wWUNfsi6Bq8ePLnb+woNKtDymI2mxZYBpMbonNFqKmiz684DIfnd8dA==", - "engines": { - "node": ">=18" - }, - "optionalDependencies": { - "canvas": "^2.11.2", - "path2d-polyfill": "^2.0.1" - } - }, - "node_modules/point-in-polygon": { - "version": "1.1.0", - "resolved": "https://registry.npmmirror.com/point-in-polygon/-/point-in-polygon-1.1.0.tgz", - "integrity": "sha512-3ojrFwjnnw8Q9242TzgXuTD+eKiutbzyslcq1ydfu82Db2y+Ogbmyrkpv0Hgj31qwT3lbS9+QAAO/pIQM35XRw==" - }, - "node_modules/polygon-clipping": { - "version": "0.15.7", - "resolved": "https://registry.npmmirror.com/polygon-clipping/-/polygon-clipping-0.15.7.tgz", - "integrity": "sha512-nhfdr83ECBg6xtqOAJab1tbksbBAOMUltN60bU+llHVOL0e5Onm1WpAXXWXVB39L8AJFssoIhEVuy/S90MmotA==", - "dependencies": { - "robust-predicates": "^3.0.2", - "splaytree": "^3.1.0" - } - }, - "node_modules/polygon-clipping/node_modules/robust-predicates": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-3.0.2.tgz", - "integrity": "sha512-IXgzBWvWQwE6PrDI05OvmXUIruQTcoMDzRsOd5CDvHCVLcLHMTSYvOK5Cm46kWqlV3yAbuSpBZdJ5oP5OUoStg==" - }, - "node_modules/quickselect": { - "version": "1.1.1", - "resolved": "https://registry.npmmirror.com/quickselect/-/quickselect-1.1.1.tgz", - "integrity": "sha512-qN0Gqdw4c4KGPsBOQafj6yj/PA6c/L63f6CaZ/DCF/xF4Esu3jVmKLUDYxghFx8Kb/O7y9tI7x2RjTSXwdK1iQ==" - }, - "node_modules/rbush": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/rbush/-/rbush-2.0.2.tgz", - "integrity": "sha512-XBOuALcTm+O/H8G90b6pzu6nX6v2zCKiFG4BJho8a+bY6AER6t8uQUZdi5bomQc0AprCWhEGa7ncAbbRap0bRA==", - "dependencies": { - "quickselect": "^1.0.1" - } - }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmmirror.com/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmmirror.com/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/rimraf": { - "version": "3.0.2", - "resolved": "https://registry.npmmirror.com/rimraf/-/rimraf-3.0.2.tgz", - "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", - "deprecated": "Rimraf versions prior to v4 are no longer supported", - "dependencies": { - "glob": "^7.1.3" - }, - "bin": { - "rimraf": "bin.js" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/robust-predicates": { - "version": "2.0.4", - "resolved": "https://registry.npmmirror.com/robust-predicates/-/robust-predicates-2.0.4.tgz", - "integrity": "sha512-l4NwboJM74Ilm4VKfbAtFeGq7aEjWL+5kVFcmgFA2MrdnQWx9iE/tUGvxY5HyMI7o/WpSIUFLbC5fbeaHgSCYg==" - }, - "node_modules/safe-buffer": { - "version": "5.2.1", - "resolved": "https://registry.npmmirror.com/safe-buffer/-/safe-buffer-5.2.1.tgz", - "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/semver": { - "version": "7.7.1", - "resolved": "https://registry.npmmirror.com/semver/-/semver-7.7.1.tgz", - "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", - "bin": { - "semver": "bin/semver.js" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmmirror.com/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==" - }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmmirror.com/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmmirror.com/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmmirror.com/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", - "hasInstallScript": true, - "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" - } - }, - "node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmmirror.com/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" - }, - "node_modules/simple-concat": { - "version": "1.0.1", - "resolved": "https://registry.npmmirror.com/simple-concat/-/simple-concat-1.0.1.tgz", - "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ] - }, - "node_modules/simple-get": { - "version": "3.1.1", - "resolved": "https://registry.npmmirror.com/simple-get/-/simple-get-3.1.1.tgz", - "integrity": "sha512-CQ5LTKGfCpvE1K0n2us+kuMPbk/q0EKl82s4aheV9oXjFEz6W/Y7oQFVJuU6QG77hRT4Ghb5RURteF5vnWjupA==", - "dependencies": { - "decompress-response": "^4.2.0", - "once": "^1.3.1", - "simple-concat": "^1.0.0" - } - }, - "node_modules/simple-swizzle": { - "version": "0.2.2", - "resolved": "https://registry.npmmirror.com/simple-swizzle/-/simple-swizzle-0.2.2.tgz", - "integrity": "sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==", - "dependencies": { - "is-arrayish": "^0.3.1" - } - }, - "node_modules/skmeans": { - "version": "0.9.7", - "resolved": "https://registry.npmmirror.com/skmeans/-/skmeans-0.9.7.tgz", - "integrity": "sha512-hNj1/oZ7ygsfmPZ7ZfN5MUBRoGg1gtpnImuJBgLO0ljQ67DtJuiQaiYdS4lUA6s0KCwnPhGivtC/WRwIZLkHyg==" - }, - "node_modules/splaytree": { - "version": "3.1.2", - "resolved": "https://registry.npmmirror.com/splaytree/-/splaytree-3.1.2.tgz", - "integrity": "sha512-4OM2BJgC5UzrhVnnJA4BkHKGtjXNzzUfpQjCO8I05xYPsfS/VuQDwjCGGMi8rYQilHEV4j8NBqTFbls/PZEE7A==" - }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmmirror.com/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, - "node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmmirror.com/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmmirror.com/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/tar": { - "version": "6.2.1", - "resolved": "https://registry.npmmirror.com/tar/-/tar-6.2.1.tgz", - "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", - "dependencies": { - "chownr": "^2.0.0", - "fs-minipass": "^2.0.0", - "minipass": "^5.0.0", - "minizlib": "^2.1.1", - "mkdirp": "^1.0.3", - "yallist": "^4.0.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/tinyqueue": { - "version": "2.0.3", - "resolved": "https://registry.npmmirror.com/tinyqueue/-/tinyqueue-2.0.3.tgz", - "integrity": "sha512-ppJZNDuKGgxzkHihX8v9v9G5f+18gzaTfrukGrq6ueg0lmH4nqVnA2IPG0AEH3jKEk2GRJCUhDoqpoiw3PHLBA==" - }, - "node_modules/topojson-client": { - "version": "3.1.0", - "resolved": "https://registry.npmmirror.com/topojson-client/-/topojson-client-3.1.0.tgz", - "integrity": "sha512-605uxS6bcYxGXw9qi62XyrV6Q3xwbndjachmNxu8HWTtVPxZfEJN9fd/SZS1Q54Sn2y0TMyMxFj/cJINqGHrKw==", - "dependencies": { - "commander": "2" - }, - "bin": { - "topo2geo": "bin/topo2geo", - "topomerge": "bin/topomerge", - "topoquantize": "bin/topoquantize" - } - }, - "node_modules/topojson-server": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/topojson-server/-/topojson-server-3.0.1.tgz", - "integrity": "sha512-/VS9j/ffKr2XAOjlZ9CgyyeLmgJ9dMwq6Y0YEON8O7p/tGGk+dCWnrE03zEdu7i4L7YsFZLEPZPzCvcB7lEEXw==", - "dependencies": { - "commander": "2" - }, - "bin": { - "geo2topo": "bin/geo2topo" - } - }, - "node_modules/tr46": { - "version": "0.0.3", - "resolved": "https://registry.npmmirror.com/tr46/-/tr46-0.0.3.tgz", - "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==" - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmmirror.com/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==" - }, - "node_modules/turf-jsts": { - "version": "1.2.3", - "resolved": "https://registry.npmmirror.com/turf-jsts/-/turf-jsts-1.2.3.tgz", - "integrity": "sha512-Ja03QIJlPuHt4IQ2FfGex4F4JAr8m3jpaHbFbQrgwr7s7L6U8ocrHiF3J1+wf9jzhGKxvDeaCAnGDot8OjGFyA==" - }, - "node_modules/undici-types": { - "version": "5.26.5", - "resolved": "https://registry.npmmirror.com/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" - }, - "node_modules/universalify": { - "version": "2.0.1", - "resolved": "https://registry.npmmirror.com/universalify/-/universalify-2.0.1.tgz", - "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", - "engines": { - "node": ">= 10.0.0" - } - }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, - "node_modules/web-streams-polyfill": { - "version": "4.0.0-beta.3", - "resolved": "https://registry.npmmirror.com/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", - "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", - "engines": { - "node": ">= 14" - } - }, - "node_modules/webidl-conversions": { - "version": "3.0.1", - "resolved": "https://registry.npmmirror.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz", - "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==" - }, - "node_modules/whatwg-url": { - "version": "5.0.0", - "resolved": "https://registry.npmmirror.com/whatwg-url/-/whatwg-url-5.0.0.tgz", - "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", - "dependencies": { - "tr46": "~0.0.3", - "webidl-conversions": "^3.0.0" - } - }, - "node_modules/wide-align": { - "version": "1.1.5", - "resolved": "https://registry.npmmirror.com/wide-align/-/wide-align-1.1.5.tgz", - "integrity": "sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==", - "dependencies": { - "string-width": "^1.0.2 || 2 || 3 || 4" - } - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmmirror.com/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==" - }, - "node_modules/yallist": { - "version": "4.0.0", - "resolved": "https://registry.npmmirror.com/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" - } - } -} diff --git a/package.json b/package.json index ecd225b..f7bbd67 100644 --- a/package.json +++ b/package.json @@ -1,30 +1,13 @@ { - "name": "pdf2md-js", - "version": "1.0.2", - "description": "Convert PDF to Markdown using Node.js", - "main": "src/index.js", - "type": "module", "scripts": { - "start": "node src/index.js", "test": "echo \"Error: no test specified\" && exit 1" }, - "keywords": [ - "pdf", - "markdown", - "converter", - "ocr" - ], - "author": "", "license": "MIT", - "dependencies": { - "@turf/turf": "^6.5.0", - "canvas": "^2.11.2", - "fs-extra": "^11.1.1", - "openai": "^4.28.0", - "pdf-lib": "^1.17.1", - "pdf-parse": "^1.1.1", - "pdf.js-extract": "^0.2.1", - "pdfjs-dist": "^3.11.174", - "sharp": "^0.33.1" + "packageManager": "pnpm@9.15.9+sha512.68046141893c66fad01c079231128e9afb89ef87e2691d69e4d40eee228988295fd4682181bae55b58418c3a253bde65a505ec7c5f9403ece5cc3cd37dcf2531", + "devDependencies": { + "@rslib/core": "^0.6.4", + "@types/node": "^22.14.1", + "prettier": "^3.5.3", + "typescript": "^5.8.3" } -} \ No newline at end of file +} diff --git a/packages/mcp/package.json b/packages/mcp/package.json new file mode 100644 index 0000000..86f2ee3 --- /dev/null +++ b/packages/mcp/package.json @@ -0,0 +1,28 @@ +{ + "name": "@tiny-tool/pdf2md-mcp", + "version": "2.0.0", + "bin": "dist/index.js", + "repository": { + "url": "https://github.com/tiny-tool/pdf2md" + }, + "scripts": { + "build": "rslib build", + "build:watch": "rslib build --watch" + }, + "author": "muzea ", + "license": "MIT", + "dependencies": { + "@modelcontextprotocol/sdk": "^1.9.0", + "@tiny-tool/pdf2md": "workspace:*", + "express": "^5.1.0", + "zod": "^3.24.3", + "zod-to-json-schema": "^3.24.5" + }, + "devDependencies": { + "@types/express": "^5.0.1" + }, + "publishConfig": { + "access": "public", + "provenance": true + } +} diff --git a/packages/mcp/rslib.config.ts b/packages/mcp/rslib.config.ts new file mode 100644 index 0000000..0cc25e1 --- /dev/null +++ b/packages/mcp/rslib.config.ts @@ -0,0 +1,15 @@ +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + { + syntax: ['node 20'], + format: 'cjs', + }, + ], + source: { + entry: { + index: './src/index.ts', + }, + }, +}); diff --git a/packages/mcp/src/index.ts b/packages/mcp/src/index.ts new file mode 100644 index 0000000..d5b7251 --- /dev/null +++ b/packages/mcp/src/index.ts @@ -0,0 +1,153 @@ +#!/usr/bin/env node + +import { Server } from '@modelcontextprotocol/sdk/server/index.js'; +import { SSEServerTransport } from '@modelcontextprotocol/sdk/server/sse.js'; +import { CallToolRequestSchema, ListToolsRequestSchema, ToolSchema } from '@modelcontextprotocol/sdk/types.js'; +import { z } from 'zod'; +import { zodToJsonSchema } from 'zod-to-json-schema'; +import express from 'express'; +import fs from 'node:fs/promises'; +import { parsePdf } from '@tiny-tool/pdf2md'; + +/** + * Reads a file from the specified path. + * + * + * @TODO read file from various protocols, such as http, https, ftp, etc. + * @param filePath + * @returns The content of the file as a Buffer. + */ +async function readFile(filePath: string) { + try { + const data = await fs.readFile(filePath); + return data; + } catch (error) { + console.error(`Error reading file ${filePath}:`, error); + throw error; + } +} + +// Server setup +const server = new Server( + { + name: '@tiny-tool/pdf2md-mcp', + version: '2.0.0', + }, + { + capabilities: { + tools: {}, + }, + }, +); + +const ToolInputSchema = ToolSchema.shape.inputSchema; +type ToolInput = z.infer; + +const ConvertSchema = z.object({ + file_path: z.string(), +}); + +// Tool handlers +server.setRequestHandler(ListToolsRequestSchema, async () => { + return { + tools: [ + { + name: 'pdf2md', + description: 'Convert PDF files to Markdown format, extract text content from the document', + inputSchema: zodToJsonSchema(ConvertSchema) as ToolInput, + }, + ], + }; +}); + +server.setRequestHandler(CallToolRequestSchema, async (request) => { + try { + const { name, arguments: args } = request.params; + + switch (name) { + case 'pdf2md': { + const parsed = ConvertSchema.safeParse(args); + if (!parsed.success) { + throw new Error(`Invalid arguments for pdf2md: ${parsed.error}`); + } + + console.log('pdf2md called with args:', parsed.data); + + // const parsedResult = await parsePdf( + // parsed.data.file_path, + // { + // apiKey: '', + // baseURL: 'https://dashscope.aliyuncs.com/compatible-mode/v1/', + // model: 'qwen2.5-vl-72b-instruct', + // }, + // { scale: 2, concurrency: 1 }, + // ); + const parsedResult = await parsePdf( + parsed.data.file_path, + { + baseURL: 'http://localhost:11434/v1/', + model: 'gemma3:12b', + }, + { scale: 1, concurrency: 1 }, + ); + return { + content: [{ type: 'text', text: parsedResult.content }], + }; + } + + default: + throw new Error(`Unknown tool: ${name}`); + } + } catch (error) { + const errorMessage = error instanceof Error ? error.message : String(error); + return { + content: [{ type: 'text', text: `Error: ${errorMessage}` }], + isError: true, + }; + } +}); + +const connections = new Map(); + +const app = express(); +app.get('/sse', async (req, res) => { + const transport = new SSEServerTransport('/messages', res); + + const sessionId = transport.sessionId; + console.log(`[${new Date().toISOString()}] 新的SSE连接建立: ${sessionId}`); + connections.set(sessionId, transport); + + req.on('close', () => { + console.log(`[${new Date().toISOString()}] SSE连接关闭: ${sessionId}`); + connections.delete(sessionId); + }); + + // 将传输对象与MCP服务器连接 + await server.connect(transport); + console.log(`[${new Date().toISOString()}] MCP服务器连接成功: ${sessionId}`); +}); + +app.post('/messages', async (req, res) => { + try { + console.log(`[${new Date().toISOString()}] 收到客户端消息:`, req.query); + const sessionId = req.query.sessionId as string; + + // 查找对应的SSE连接并处理消息 + if (connections.size > 0) { + const transport: SSEServerTransport = connections.get(sessionId) as SSEServerTransport; + // 使用transport处理消息 + if (transport) { + await transport.handlePostMessage(req, res); + } else { + throw new Error('没有活跃的SSE连接'); + } + } else { + throw new Error('没有活跃的SSE连接'); + } + } catch (error: any) { + console.error(`[${new Date().toISOString()}] 处理客户端消息失败:`, error); + res.status(500).json({ error: '处理消息失败', message: error.message }); + } +}); + +app.listen(3002); diff --git a/packages/mcp/tsconfig.json b/packages/mcp/tsconfig.json new file mode 100644 index 0000000..276fda8 --- /dev/null +++ b/packages/mcp/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "NodeNext", + "strict": true, + "noEmit": true, + "moduleResolution": "nodenext", + "skipLibCheck": true, + "isolatedModules": true, + "useDefineForClassFields": true, + "allowImportingTsExtensions": true, + "allowSyntheticDefaultImports": true, + "allowJs": true + }, + "include": ["src"] +} diff --git a/packages/pdf2md/package.json b/packages/pdf2md/package.json new file mode 100644 index 0000000..4854a85 --- /dev/null +++ b/packages/pdf2md/package.json @@ -0,0 +1,50 @@ +{ + "name": "@tiny-tool/pdf2md", + "version": "2.0.0", + "repository": { + "url": "https://github.com/tiny-tool/pdf2md" + }, + "description": "Convert PDF to Markdown using Node.js", + "main": "./dist/index.js", + "module": "./dist/index.mjs", + "types": "./dist/index.d.ts", + "exports": { + ".": { + "require": "./dist/index.js", + "import": "./dist/index.mjs", + "types": "./dist/index.d.ts" + } + }, + "scripts": { + "build": "rslib build", + "build:watch": "rslib build --watch" + }, + "keywords": [ + "pdf", + "markdown", + "converter", + "ocr" + ], + "author": "muzea ", + "license": "MIT", + "dependencies": { + "@napi-rs/canvas": "^0.1.69", + "@xsai/generate-text": "0.2.0-beta.3", + "fs-extra": "^11.3.0", + "pdfjs-dist": "^5.1.91" + }, + "devDependencies": { + "@types/fs-extra": "^11.0.4", + "@xsai/shared-chat": "0.2.0-beta.3" + }, + "engines": { + "node": ">=20" + }, + "files": [ + "dist/*" + ], + "publishConfig": { + "access": "public", + "provenance": true + } +} diff --git a/packages/pdf2md/rslib.config.ts b/packages/pdf2md/rslib.config.ts new file mode 100644 index 0000000..88a4cfa --- /dev/null +++ b/packages/pdf2md/rslib.config.ts @@ -0,0 +1,20 @@ +import { defineConfig } from '@rslib/core'; + +export default defineConfig({ + lib: [ + { + syntax: ['node 20'], + format: 'cjs', + }, + { + syntax: ['node 20'], + format: 'esm', + dts: true, + }, + ], + source: { + entry: { + index: './src/index.ts', + }, + }, +}); diff --git a/packages/pdf2md/src/const.ts b/packages/pdf2md/src/const.ts new file mode 100644 index 0000000..3546aee --- /dev/null +++ b/packages/pdf2md/src/const.ts @@ -0,0 +1,59 @@ +export const DefaultPrompt = `使用markdown语法,将图片中识别到的文字转换为markdown格式输出。你必须做到: +1. 输出和使用识别到的图片的相同的语言,例如,识别到英语的字段,输出的内容必须是英语。 +2. 不要解释和输出无关的文字,直接输出图片中的内容。 +3. 内容不要包含在\`\`\`markdown \`\`\`中、段落公式使用 $$ $$ 的形式、行内公式使用 $ $ 的形式。 +4. 忽略掉页眉页脚里的内容 +5. 请不要对图片的标题进行markdown的格式化,直接以文本形式输出到内容中。 +6. 有可能每页都会出现期刊名称,论文名称,会议名称或者书籍名称,请忽略他们不要识别成标题 +7. 请精确分析当前PDF页面的文本结构和视觉布局,按以下要求处理: + 1. 识别所有标题文本,并判断其层级(根据字体大小、加粗、位置等视觉特征) + 2. 输出为带层级的Markdown格式,严格使用以下规则: + - 一级标题:字体最大/顶部居中,前面加 # + - 二级标题:字体较大/左对齐加粗,有可能是数字开头也有可能是罗马数组开头,前面加 ## + - 三级标题:字体稍大/左对齐加粗,前面加 ### + - 正文文本:直接转换为普通段落 + 3. 不确定层级的标题请标记[?] + 4. 如果是中文文献,但是有英文标题和摘要可以省略不输出 + + +示例输出: + +## 4研究方法 +### 4.1数据收集 +本文采用问卷调查... +`; + +export const DefaultTextPrompt = `你是一个专业的文本结构化处理助手,擅长根据前缀规则和标题语义分析并优化Markdown文档的标题层级结构。请根据以下要求处理我提供的Markdown标题: +## 任务描述 +请根据markdown文章标题的实际含义,以及标题的前缀特征调整各级标题的正确层级关系,具体要求如下: +1. 一般相同格式的前缀的标题是同级关系({title}代表实际的标题内容): + 例如: + 纯数字前缀开头\`1 {title}\`, \` 2 {title}\` ,\` 3 {title}\`,\` 4 {title}\`,\` 5 {title}\` ... 等 + 罗马数字前缀开头的\`I {title}\`,\`II {title}\` ,\`III {title}\`,\`IV {title}\`,\`V {title}\` ... 等 + 小数点分隔数组前缀开头 \`1.1 {title}\`, \`1.2 {title}\`, \`1.3 {title}\`.... \`2.1 {title}\`, \`2.2 {title}\` 等 +2. 将子标题正确嵌套到父标题下(如\`1.1 {title}\`应作为\`1 {title}\`的子标题) +3. 剔除与文章内容无关的标题 +4. 保持输出标题内容与输入完全一致 +5. 确保内容无缺失 +6. 如果是中文文献,但有英文的文章题目,可以省略 + +## 输入输出格式 +- 输入:包含错误层级关系的markdown标题结构 +- 输出:修正后的标准markdown标题层级结构 + +## 处理原则 +1. 严格根据标题语义确定所属关系 +2. 仅调整层级不修改原标题文本 +3. 无关标题直接移除不保留占位 +4. 相同前缀规则的标题必须是同一级别,不能出现 一部分是 n级标题,一部分是其他级别的标题 + +## 输出要求 +请将修正后的完整标题结构放在代码块中返回,格式示例如下: + +期望输出: + \`\`\`markdown + + \`\`\` + +请处理以下数据: +`; diff --git a/packages/pdf2md/src/image-generator.ts b/packages/pdf2md/src/image-generator.ts new file mode 100644 index 0000000..1662880 --- /dev/null +++ b/packages/pdf2md/src/image-generator.ts @@ -0,0 +1,71 @@ +/** + * 图像生成模块,负责将PDF区域转换为图像 + */ +import { getDocument } from 'pdfjs-dist/legacy/build/pdf.mjs'; +import type { PageViewport } from 'pdfjs-dist/types/src/display/display_utils.d.ts'; +import type { PDFPageProxy, PDFDocumentProxy } from 'pdfjs-dist/types/src/display/api.d.ts'; +import fs from 'fs-extra'; +import { createCanvas, Canvas } from '@napi-rs/canvas'; + +// 定义一些类型 +export type PageImage = { index: number; data: Buffer }; + +/** + * 直接生成PDF文档的所有页面图像,不依赖区域识别 + * @param pdfData PDF文件数据或路径 + * @param outputDir 输出目录 + * @param scale 缩放比例 + * @returns 生成的图像文件路径数组 + */ +export const generateFullPageImages = async (pdfData: Buffer | string, outputDir: string, scale: number = 3): Promise => { + // 确保输出目录存在 + await fs.ensureDir(outputDir); + + // 如果pdfData是字符串,则当作路径处理 + let data: Uint8Array; + if (typeof pdfData === 'string') { + data = new Uint8Array(await fs.readFile(pdfData)); + } else { + data = new Uint8Array(pdfData); + } + + // 加载PDF文档 + const pdfDocument: PDFDocumentProxy = await getDocument({ data }).promise; + const numPages = pdfDocument.numPages; + console.log(`PDF文档共 ${numPages} 页`); + + // 存储生成的图像路径 + const pageImages: PageImage[] = []; + + // 处理每一页 + for (let i = 0; i < numPages; i++) { + const pageIndex = i + 1; + console.log(`处理第 ${pageIndex} 页...`); + + // 获取页面 + const page: PDFPageProxy = await pdfDocument.getPage(pageIndex); + const viewport: PageViewport = page.getViewport({ scale }); + + // 创建canvas + const canvas: Canvas = createCanvas(viewport.width, viewport.height); + const context = canvas.getContext('2d') as any as CanvasRenderingContext2D; + + // 填充白色背景 + context.fillStyle = '#ffffff'; + context.fillRect(0, 0, viewport.width, viewport.height); + + // 渲染页面 + await page.render({ + canvasContext: context, + viewport: viewport, + }).promise; + + // 将canvas转换为图像并保存 + const buffer = canvas.toBuffer('image/png'); + + // 添加到结果数组 + pageImages.push({ index: pageIndex, data: buffer }); + } + + return pageImages; +}; diff --git a/packages/pdf2md/src/index.ts b/packages/pdf2md/src/index.ts new file mode 100644 index 0000000..50eab0e --- /dev/null +++ b/packages/pdf2md/src/index.ts @@ -0,0 +1,186 @@ +/** + * PDF2MD 主入口模块 + * 提供PDF转Markdown的完整功能 + */ +import fs from 'fs-extra'; +import path from 'path'; +import { generateFullPageImages, PageImage } from './image-generator'; +import { extractMdFromLLMOutput, adjustMarkdownHeadings, getOldMarkdownHeadings } from './utils'; +import ModelClient, { ModelConfig } from './model-client'; +import { DefaultPrompt, DefaultTextPrompt } from './const'; + +interface ParseOptions { + outputDir?: string; + prompt?: string; + textPrompt?: string; + verbose?: boolean; + scale?: number; + concurrency?: number; + onProgress?: (progress: ProgressInfo) => void; +} + +interface ProgressInfo { + current: number; + total: number; + taskStatus: 'starting' | 'running' | 'finished'; +} + +interface PageContent { + pageIndex: number; + content: string; +} + +interface ParseResult { + content: string; + mdFilePath: string; +} + +/** + * 将PDF文件解析为Markdown + */ +export const parsePdf = async (pdfPath: string, modelConfig: ModelConfig = {}, options: ParseOptions = {}): Promise => { + const { outputDir = './output', prompt = DefaultPrompt, textPrompt = DefaultTextPrompt, verbose = false, scale = 3, concurrency = 2, onProgress } = options; + + // 确保输出目录存在 + await fs.ensureDir(outputDir); + + console.log('开始解析PDF文件(全页模式):', pdfPath); + + try { + // 第一步:生成全页图像 + console.log('生成全页图像...'); + const imageOutputDir = path.join(outputDir, 'pages'); + await fs.ensureDir(imageOutputDir); + + const imageFiles = await generateFullPageImages(pdfPath, imageOutputDir, scale); + + //先把总页数传递回调用方法 + if (onProgress) { + onProgress({ + current: 0, + total: imageFiles.length, + taskStatus: 'starting', + }); + } + + // 第二步:使用视觉模型处理每个页面图像 + console.log('处理全页图像...'); + + // 创建模型客户端 + const modelClient = new ModelClient(modelConfig); + + const pageContents: PageContent[] = []; + const processImages = async (item: PageImage) => { + console.log(`处理页面 ${item.index}/${imageFiles.length}`); + try { + // 处理图像 - 确保传入有效的prompt + const defaultPrompt = '请将图像中的所有文本内容转换为Markdown格式,包括标题、段落、列表和表格等。'; + const pageContent = await modelClient.processImage(item.data, prompt || defaultPrompt); + + if (true) { + await fs.writeFile(`${imageOutputDir}/page_${item.index}.md`, pageContent, { encoding: 'utf8' }); + } + + // 添加页面内容 + pageContents.push({ + pageIndex: item.index, + content: pageContent, + }); + // 处理完成后,更新调用者的信息 + if (onProgress) { + onProgress({ + current: pageContents.length, + total: imageFiles.length, + taskStatus: 'running', + }); + } + return { success: true, item, data: pageContent }; + } catch (error) { + console.error('Markdown 转换失败:', error); + return { success: false, item, error: (error as Error).message }; + } + }; + + // 并行处理所有问题,最多同时处理concurrency个 + await processInParallel(imageFiles, processImages, concurrency); + + //并行处理生成结果是乱序的,根据pageIndex进行排序再输出Markdown + pageContents.sort((a, b) => a.pageIndex - b.pageIndex); + + // 第三步:生成Markdown文件 + console.log('生成Markdown文档...'); + + // 生成Markdown内容 + let content = ''; + for (const page of pageContents) { + content += page.content + '\n'; + } + + console.log('正在重新调整目录...'); + + // 提取转换后的标题 + const title = await getOldMarkdownHeadings(content); + + //使用大模型重新调整目录结构 + const defaultPrompt = '请将图像中的所有文本内容转换为Markdown格式,包括标题、段落、列表和表格等。'; + const convertedTitleLLMResult = await modelClient.processImage(null, textPrompt + JSON.stringify(title) || defaultPrompt); + const convertedTitle = await extractMdFromLLMOutput(convertedTitleLLMResult); + + //根据调整后的结果重新生成md文件 + const convertContent = await adjustMarkdownHeadings(content, convertedTitle || ''); + + console.log('目录调整完成...'); + + // 第四步:保存Markdown文件 + const mdFilePath = path.join(outputDir, path.basename(pdfPath, '.pdf') + '.md'); + await fs.writeFile(mdFilePath, convertContent); + console.log('Markdown文件已保存至:', mdFilePath); + + // 将任务执行结束传递回调用方法 + if (onProgress) { + onProgress({ + current: imageFiles.length, + total: imageFiles.length, + taskStatus: 'finished', + }); + } + + return { + content, + mdFilePath, + }; + } catch (error) { + console.error('PDF解析过程中发生错误:', error); + throw error; + } +}; + +// 定义并行处理的辅助函数类型 +type ProcessFunction = (item: T) => Promise; + +// 并行处理数组的辅助函数,限制并发数 +const processInParallel = async (items: T[], processFunction: ProcessFunction, concurrencyLimit: number): Promise => { + const results: Promise[] = []; + const inProgress = new Set>(); + const queue = [...items]; + + while (queue.length > 0 || inProgress.size > 0) { + // 如果有空闲槽位且队列中还有任务,启动新任务 + while (inProgress.size < concurrencyLimit && queue.length > 0) { + const item = queue.shift()!; + const promise = processFunction(item).then((result) => { + inProgress.delete(promise); + return result; + }); + inProgress.add(promise); + results.push(promise); + } + + // 等待其中一个任务完成 + if (inProgress.size > 0) { + await Promise.race(inProgress); + } + } + + return Promise.all(results); +}; diff --git a/packages/pdf2md/src/model-client.ts b/packages/pdf2md/src/model-client.ts new file mode 100644 index 0000000..b82c4ef --- /dev/null +++ b/packages/pdf2md/src/model-client.ts @@ -0,0 +1,105 @@ +/** + * 模型客户端模块,用于处理不同视觉模型的API调用 + */ +import { generateText } from '@xsai/generate-text'; +import type { UserMessagePart } from '@xsai/shared-chat'; + +// 默认角色提示词(中文版) +const DEFAULT_ROLE_PROMPT = `你是一个PDF文档解析器,使用markdown和latex语法输出图片的内容。`; + +/** + * 模型配置接口 + */ +export interface ModelConfig { + apiKey?: string; + baseURL?: string; + model?: string; +} + +/** + * 处理图像选项接口 + */ +interface ProcessImageOptions extends ModelConfig { + rolePrompt?: string; +} + +/** + * 模型客户端类,处理与不同视觉模型的交互 + */ +export class ModelClient { + private config: ModelConfig; + + /** + * 创建模型客户端实例 + */ + constructor(config: ModelConfig) { + this.config = { + baseURL: 'http://localhost:11434/v1/', + model: 'gemma3:12b', + ...config, + }; + } + + /** + * 处理图像并转换为Markdown文本 + */ + async processImage(imageData: Buffer | null, prompt: string, options: ProcessImageOptions = {}): Promise { + const { rolePrompt = DEFAULT_ROLE_PROMPT } = options; + + // 读取图像文件 + let base64Image: string | null = null; + if (imageData) { + base64Image = imageData.toString('base64'); + } + + const modelConfig: ModelConfig = { + apiKey: options.apiKey || this.config.apiKey, + baseURL: options.baseURL || this.config.baseURL, + model: options.model || this.config.model, + }; + + return this.callLLM(rolePrompt, prompt, base64Image, modelConfig); + } + + /** + * 通过API调用OpenAI视觉模型 + * @private + */ + private async callLLM(rolePrompt: string, prompt: string, base64Image: string | null, modelConfig: ModelConfig): Promise { + // 使用OpenAI API + const baseURL = modelConfig.baseURL || 'https://api.openai.com/v1/'; + + // 构建用户消息内容 + const userContent: Array = [{ type: 'text', text: prompt }]; + + // 如果有base64图片,添加图片内容 + if (base64Image) { + userContent.push({ + type: 'image_url', + image_url: { + url: `data:image/png;base64,${base64Image}`, + }, + }); + } + + const { text } = await generateText({ + apiKey: modelConfig.apiKey!, + baseURL: baseURL, + messages: [ + { + role: 'system', + content: rolePrompt, + }, + { + role: 'user', + content: userContent, + }, + ], + model: modelConfig.model!, + }); + + return text || ''; + } +} + +export default ModelClient; diff --git a/packages/pdf2md/src/utils.ts b/packages/pdf2md/src/utils.ts new file mode 100644 index 0000000..7d6f9d7 --- /dev/null +++ b/packages/pdf2md/src/utils.ts @@ -0,0 +1,85 @@ +/** + * 工具函数模块,提供常用的辅助功能 + */ +import fs from 'fs-extra'; + +/** + * 删除文件 + * @param filePath 文件路径 + */ +export const removeFile = async (filePath: string): Promise => { + try { + await fs.remove(filePath); + } catch (error: any) { + console.error(`删除文件 ${filePath} 失败:`, error); + } +}; + +// 从 LLM 输出中提取标题 +export const extractMdFromLLMOutput = (output: string): string | undefined => { + const mdStart = output.indexOf('```markdown'); + const mdEnd = output.lastIndexOf('```'); + if (mdStart !== -1 && mdEnd !== -1) { + const mdString = output.substring(mdStart + 12, mdEnd); + return mdString; + } else { + console.error('模型未按标准格式输出:', output); + return undefined; + } +}; + +//获取优化前的 markdwon 标题 +export const getOldMarkdownHeadings = (markdownText: string): string => { + const title: string[] = []; + const lines = markdownText.split('\n'); + lines.forEach((line) => { + // 匹配 # 开头,并捕获后面的内容 + const match = line.match(/^#+\s*(.*)/); + if (match) { + title.push(line); + } + }); + return title.join('\n'); +}; + +//根据新生成的标题结构,重新设置原文章中标题级别 +export const adjustMarkdownHeadings = (markdownText: string, newTitle: string): string => { + const map = createTitleLevelMap(newTitle); + const lines = markdownText.split('\n'); + const processedLines: string[] = []; + lines.forEach((line) => { + // 匹配 # 开头,并捕获后面的内容 + const match = line.match(/^#+\s*(.*)/); + if (!match) { + processedLines.push(line); + return; + } + const content = match ? match[1] : line; + // 检查 content 是否在 map 中存在 + let newLine = line; + if (map.has(content)) { + const level = map.get(content); + // 生成对应数量的 #(例如 level=2 -> "##") + const hashes = '#'.repeat(level!); + newLine = `${hashes} ${content}`; + console.log('转换前:' + line + '===>转换后' + newLine); + } + processedLines.push(newLine); + }); + return processedLines.join('\n'); +}; + +//根据标题#数量,建立内容和数量的map映射 +function createTitleLevelMap(data: string, map: Map = new Map()): Map { + const lines = data.split('\n'); + for (const line of lines) { + // 匹配以#开头的标题行 + const headerMatch = line.match(/^(#+)\s*(.+)/); + if (headerMatch) { + const level = headerMatch[1].length; // #号的数量 + const text = headerMatch[2].trim(); // #号后的文本内容 + map.set(text, level); + } + } + return map; +} diff --git a/packages/pdf2md/tsconfig.json b/packages/pdf2md/tsconfig.json new file mode 100644 index 0000000..276fda8 --- /dev/null +++ b/packages/pdf2md/tsconfig.json @@ -0,0 +1,17 @@ +{ + "compilerOptions": { + "target": "ES2020", + "lib": ["DOM", "ES2020"], + "module": "NodeNext", + "strict": true, + "noEmit": true, + "moduleResolution": "nodenext", + "skipLibCheck": true, + "isolatedModules": true, + "useDefineForClassFields": true, + "allowImportingTsExtensions": true, + "allowSyntheticDefaultImports": true, + "allowJs": true + }, + "include": ["src"] +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml new file mode 100644 index 0000000..64bf668 --- /dev/null +++ b/pnpm-lock.yaml @@ -0,0 +1,1438 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +importers: + + .: + devDependencies: + '@rslib/core': + specifier: ^0.6.4 + version: 0.6.4(typescript@5.8.3) + '@types/node': + specifier: ^22.14.1 + version: 22.14.1 + prettier: + specifier: ^3.5.3 + version: 3.5.3 + typescript: + specifier: ^5.8.3 + version: 5.8.3 + + packages/mcp: + dependencies: + '@modelcontextprotocol/sdk': + specifier: ^1.9.0 + version: 1.9.0 + '@tiny-tool/pdf2md': + specifier: workspace:* + version: link:../pdf2md + express: + specifier: ^5.1.0 + version: 5.1.0 + zod: + specifier: ^3.24.3 + version: 3.24.3 + zod-to-json-schema: + specifier: ^3.24.5 + version: 3.24.5(zod@3.24.3) + devDependencies: + '@types/express': + specifier: ^5.0.1 + version: 5.0.1 + + packages/pdf2md: + dependencies: + '@napi-rs/canvas': + specifier: ^0.1.69 + version: 0.1.69 + '@xsai/generate-text': + specifier: 0.2.0-beta.3 + version: 0.2.0-beta.3 + fs-extra: + specifier: ^11.3.0 + version: 11.3.0 + pdfjs-dist: + specifier: ^5.1.91 + version: 5.1.91 + devDependencies: + '@types/fs-extra': + specifier: ^11.0.4 + version: 11.0.4 + '@xsai/shared-chat': + specifier: 0.2.0-beta.3 + version: 0.2.0-beta.3 + +packages: + + '@ast-grep/napi-darwin-arm64@0.37.0': + resolution: {integrity: sha512-QAiIiaAbLvMEg/yBbyKn+p1gX2/FuaC0SMf7D7capm/oG4xGMzdeaQIcSosF4TCxxV+hIH4Bz9e4/u7w6Bnk3Q==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@ast-grep/napi-darwin-x64@0.37.0': + resolution: {integrity: sha512-zvcvdgekd4ySV3zUbUp8HF5nk5zqwiMXTuVzTUdl/w08O7JjM6XPOIVT+d2o/MqwM9rsXdzdergY5oY2RdhSPA==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@ast-grep/napi-linux-arm64-gnu@0.37.0': + resolution: {integrity: sha512-L7Sj0lXy8X+BqSMgr1LB8cCoWk0rericdeu+dC8/c8zpsav5Oo2IQKY1PmiZ7H8IHoFBbURLf8iklY9wsD+cyA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@ast-grep/napi-linux-arm64-musl@0.37.0': + resolution: {integrity: sha512-LF9sAvYy6es/OdyJDO3RwkX3I82Vkfsng1sqUBcoWC1jVb1wX5YVzHtpQox9JrEhGl+bNp7FYxB4Qba9OdA5GA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@ast-grep/napi-linux-x64-gnu@0.37.0': + resolution: {integrity: sha512-TViz5/klqre6aSmJzswEIjApnGjJzstG/SE8VDWsrftMBMYt2PTu3MeluZVwzSqDao8doT/P+6U11dU05UOgxw==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@ast-grep/napi-linux-x64-musl@0.37.0': + resolution: {integrity: sha512-/BcCH33S9E3ovOAEoxYngUNXgb+JLg991sdyiNP2bSoYd30a9RHrG7CYwW6fMgua3ijQ474eV6cq9yZO1bCpXg==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@ast-grep/napi-win32-arm64-msvc@0.37.0': + resolution: {integrity: sha512-TjQA4cFoIEW2bgjLkaL9yqT4XWuuLa5MCNd0VCDhGRDMNQ9+rhwi9eLOWRaap3xzT7g+nlbcEHL3AkVCD2+b3A==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [win32] + + '@ast-grep/napi-win32-ia32-msvc@0.37.0': + resolution: {integrity: sha512-uNmVka8fJCdYsyOlF9aZqQMLTatEYBynjChVTzUfFMDfmZ0bihs/YTqJVbkSm8TZM7CUX82apvn50z/dX5iWRA==} + engines: {node: '>= 10'} + cpu: [ia32] + os: [win32] + + '@ast-grep/napi-win32-x64-msvc@0.37.0': + resolution: {integrity: sha512-vCiFOT3hSCQuHHfZ933GAwnPzmL0G04JxQEsBRfqONywyT8bSdDc/ECpAfr3S9VcS4JZ9/F6tkePKW/Om2Dq2g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@ast-grep/napi@0.37.0': + resolution: {integrity: sha512-Hb4o6h1Pf6yRUAX07DR4JVY7dmQw+RVQMW5/m55GoiAT/VRoKCWBtIUPPOnqDVhbx1Cjfil9b6EDrgJsUAujEQ==} + engines: {node: '>= 10'} + + '@jridgewell/sourcemap-codec@1.5.0': + resolution: {integrity: sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==} + + '@modelcontextprotocol/sdk@1.9.0': + resolution: {integrity: sha512-Jq2EUCQpe0iyO5FGpzVYDNFR6oR53AIrwph9yWl7uSc7IWUMsrmpmSaTGra5hQNunXpM+9oit85p924jWuHzUA==} + engines: {node: '>=18'} + + '@module-federation/error-codes@0.11.2': + resolution: {integrity: sha512-ik1Qnn0I+WyEdprTck9WGlH41vGsVdUg8cfO+ZM02qOb2cZm5Vu3SlxGAobj6g7uAj0g8yINnd7h7Dci40BxQA==} + + '@module-federation/runtime-core@0.11.2': + resolution: {integrity: sha512-dia5kKybi6MFU0s5PgglJwN27k7n9Sf69Cy5xZ4BWaP0qlaXTsxHKO0PECHNt2Pt8jDdyU29sQ4DwAQfxpnXJQ==} + + '@module-federation/runtime-tools@0.11.2': + resolution: {integrity: sha512-4MJTGAxVq6vxQRkTtTlH7Mm9AVqgn0X9kdu+7RsL7T/qU+jeYsbrntN2CWG3GVVA8r5JddXyTI1iJ0VXQZLV1w==} + + '@module-federation/runtime@0.11.2': + resolution: {integrity: sha512-Ya9u/L6z2LvhgpqxuKCB7LcigIIRf1BbaxAZIH7mzbq/A7rZtTP7v+73E433jvgiAlbAfPSZkeoYGele6hfRwA==} + + '@module-federation/sdk@0.11.2': + resolution: {integrity: sha512-SBFe5xOamluT900J4AGBx+2/kCH/JbfqXoUwPSAC6PRzb8Y7LB0posnOGzmqYsLZXT37vp3d6AmJDsVoajDqxw==} + + '@module-federation/webpack-bundler-runtime@0.11.2': + resolution: {integrity: sha512-WdwIE6QF+MKs/PdVu0cKPETF743JB9PZ62/qf7Uo3gU4fjsUMc37RnbJZ/qB60EaHHfjwp1v6NnhZw1r4eVsnw==} + + '@napi-rs/canvas-android-arm64@0.1.69': + resolution: {integrity: sha512-4icWTByY8zPvM9SelfQKf3I6kwXw0aI5drBOVrwfER5kjwXJd78FPSDSZkxDHjvIo9Q86ljl18Yr963ehA4sHQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [android] + + '@napi-rs/canvas-darwin-arm64@0.1.69': + resolution: {integrity: sha512-HOanhhYlHdukA+unjelT4Dg3ta7e820x87/AG2dKUMsUzH19jaeZs9bcYjzEy2vYi/dFWKz7cSv2yaIOudB8Yg==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [darwin] + + '@napi-rs/canvas-darwin-x64@0.1.69': + resolution: {integrity: sha512-SIp7WfhxAPnSVK9bkFfJp+84rbATCIq9jMUzDwpCLhQ+v+OqtXe4pggX1oeV+62/HK6BT1t18qRmJfyqwJ9f3g==} + engines: {node: '>= 10'} + cpu: [x64] + os: [darwin] + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.69': + resolution: {integrity: sha512-Ls+KujCp6TGpkuMVFvrlx+CxtL+casdkrprFjqIuOAnB30Mct6bCEr+I83Tu29s3nNq4EzIGjdmA3fFAZG/Dtw==} + engines: {node: '>= 10'} + cpu: [arm] + os: [linux] + + '@napi-rs/canvas-linux-arm64-gnu@0.1.69': + resolution: {integrity: sha512-m8VcGmeSBNRbHZBd1srvdM1aq/ScS2y8KqGqmCCEgJlytYK4jdULzAo2K/BPKE1v3xvn8oUPZDLI/NBJbJkEoA==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/canvas-linux-arm64-musl@0.1.69': + resolution: {integrity: sha512-a3xjNRIeK2m2ZORGv2moBvv3vbkaFZG1QKMeiEv/BKij+rkztuEhTJGMar+buICFgS0fLgphXXsKNkUSJb7eRQ==} + engines: {node: '>= 10'} + cpu: [arm64] + os: [linux] + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.69': + resolution: {integrity: sha512-pClUoJF5wdC9AvD0mc15G9JffL1Q85nuH1rLSQPRkGmGmQOtRjw5E9xNbanz7oFUiPbjH7xcAXUjVAcf7tdgPQ==} + engines: {node: '>= 10'} + cpu: [riscv64] + os: [linux] + + '@napi-rs/canvas-linux-x64-gnu@0.1.69': + resolution: {integrity: sha512-96X3bFAmzemfw84Ts6Jg/omL86uuynvK06MWGR/mp3JYNumY9RXofA14eF/kJIYelbYFWXcwpbcBR71lJ6G/YQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/canvas-linux-x64-musl@0.1.69': + resolution: {integrity: sha512-2QTsEFO72Kwkj53W9hc5y1FAUvdGx0V+pjJB+9oQF6Ys9+y989GyPIl5wZDzeh8nIJW6koZZ1eFa8pD+pA5BFQ==} + engines: {node: '>= 10'} + cpu: [x64] + os: [linux] + + '@napi-rs/canvas-win32-x64-msvc@0.1.69': + resolution: {integrity: sha512-Q4YA8kVnKarApBVLu7F8icGlIfSll5Glswo5hY6gPS4Is2dCI8+ig9OeDM8RlwYevUIxKq8lZBypN8Q1iLAQ7w==} + engines: {node: '>= 10'} + cpu: [x64] + os: [win32] + + '@napi-rs/canvas@0.1.69': + resolution: {integrity: sha512-ydvNeJMRm+l3T14yCoUKqjYQiEdXDq1isznI93LEBGYssXKfSaLNLHOkeM4z9Fnw9Pkt2EKOCAtW9cS4b00Zcg==} + engines: {node: '>= 10'} + + '@rsbuild/core@1.3.8': + resolution: {integrity: sha512-J3WfY7XH5RRswfXFFUYizhrsEe/ueufALBSYfNyXpDnzTWgO/NGcjtB7iRgOsXs5z1WLRBMukiFUdDFf0iTcMQ==} + engines: {node: '>=16.10.0'} + hasBin: true + + '@rslib/core@0.6.4': + resolution: {integrity: sha512-7UDx1/Rm3YB/hPkp51GeGybrI9/7cEMVXOF47crXMDb1TRpa69aJxN/o/L6/GFSRQzQMhS1q17S/jyDE+x+SFA==} + engines: {node: '>=16.7.0'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7 + typescript: ^5 + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + typescript: + optional: true + + '@rspack/binding-darwin-arm64@1.3.5': + resolution: {integrity: sha512-bhqi9nZ0jrlQc/YgTklzD02y0E8Emdrov6HLcxt/Dzwq5SZryl4Ik8yc/8E1M0PWNkr09+TO8i1Zc51z0Gfu2g==} + cpu: [arm64] + os: [darwin] + + '@rspack/binding-darwin-x64@1.3.5': + resolution: {integrity: sha512-ysNn7bd/5NdVb0mTDBQl+D9GypCSS7FJoJJEeSpPcN01zFF8lRUsvdbOvzrG/CUBA2qbeWhwZvG2eKOy3p2NRA==} + cpu: [x64] + os: [darwin] + + '@rspack/binding-linux-arm64-gnu@1.3.5': + resolution: {integrity: sha512-oEfPjYx3RVsMeHG/kI9k96nLJUQhYfQS9HUKS37Ko3RWC84qTuzMAAdWIXE9ys8GHwpks7pL953AfYNK5PLhPw==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-arm64-musl@1.3.5': + resolution: {integrity: sha512-4cUoxd8nGsCCnqWBqortJRF+VKWzUm7ac9YRMQ+wpoL5i0abcQf8GqeilsNtRBRNqAlAh3mfgRlyeZgWvoS44g==} + cpu: [arm64] + os: [linux] + + '@rspack/binding-linux-x64-gnu@1.3.5': + resolution: {integrity: sha512-JehI/z61Y9wwkcTxbAdPtjUnAyyAUCJZOqP3FwQTAd2gBFG/8k7v1quGwrfOLsCLOcT3azbd8YFoHmkveGQayQ==} + cpu: [x64] + os: [linux] + + '@rspack/binding-linux-x64-musl@1.3.5': + resolution: {integrity: sha512-t8BqaOXrqIXZHTrz4ItX/m6BOvbBkeb7qTewlkN5mMHtPAF/Xg203rQ814VXx59kjgGF7i79PXIK2dQxHnCYDA==} + cpu: [x64] + os: [linux] + + '@rspack/binding-win32-arm64-msvc@1.3.5': + resolution: {integrity: sha512-k9vf/WgEwxtXzV4la1H6eL07GIlvNjdPdvo1AJZdu0Zcnm600Kv5NSBjySJCp3zUHIKkCE9A0+ibifqbliG0fw==} + cpu: [arm64] + os: [win32] + + '@rspack/binding-win32-ia32-msvc@1.3.5': + resolution: {integrity: sha512-dGfGJySHC/ktbNkK/FY2vEpFNK4UT+fgChhmUxIyQaHWjloFGVmEr6NttS0GtdtvblfF3tTzkTe9pGMIkdlegw==} + cpu: [ia32] + os: [win32] + + '@rspack/binding-win32-x64-msvc@1.3.5': + resolution: {integrity: sha512-GujYFTr043jse5gdvofsRvltkH/E8G5h3Yu9JG/+6EyQpFJebYm/NpRQrOyqZLIQP39+tbdViTfW4nOpUuurNA==} + cpu: [x64] + os: [win32] + + '@rspack/binding@1.3.5': + resolution: {integrity: sha512-2oluCT+iBnTg0w7XfR8AmfkvgMPSuqEndzhrlHY//qgyyI04CW1lCMgsh+9wcSOUWUKYSOMCiGiVlYFtae5Lcg==} + + '@rspack/core@1.3.5': + resolution: {integrity: sha512-PwIpzXj9wjHM0Ohq6geIKPoh3yNb5oSK74gqzs0plR7pTYLbhrjG/1DSV/JLFF4C5WCpLHHiDEX5E0IYm2Aqeg==} + engines: {node: '>=16.0.0'} + peerDependencies: + '@rspack/tracing': ^1.x + '@swc/helpers': '>=0.5.1' + peerDependenciesMeta: + '@rspack/tracing': + optional: true + '@swc/helpers': + optional: true + + '@rspack/lite-tapable@1.0.1': + resolution: {integrity: sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==} + engines: {node: '>=16.0.0'} + + '@swc/helpers@0.5.17': + resolution: {integrity: sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==} + + '@types/body-parser@1.19.5': + resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} + + '@types/connect@3.4.38': + resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} + + '@types/express-serve-static-core@5.0.6': + resolution: {integrity: sha512-3xhRnjJPkULekpSzgtoNYYcTWgEZkp4myc+Saevii5JPnHNvHMRlBSHDbs7Bh1iPPoVTERHEZXyhyLbMEsExsA==} + + '@types/express@5.0.1': + resolution: {integrity: sha512-UZUw8vjpWFXuDnjFTh7/5c2TWDlQqeXHi6hcN7F2XSVT5P+WmUnnbFS3KA6Jnc6IsEqI2qCVu2bK0R0J4A8ZQQ==} + + '@types/fs-extra@11.0.4': + resolution: {integrity: sha512-yTbItCNreRooED33qjunPthRcSjERP1r4MqCZc7wv0u2sUkzTFp45tgUfS5+r7FrZPdmCCNflLhVSP/o+SemsQ==} + + '@types/http-errors@2.0.4': + resolution: {integrity: sha512-D0CFMMtydbJAegzOyHjtiKPLlvnm3iTZyZRSZoLq2mRhDdmLfIWOCYPfQJ4cu2erKghU++QvjcUjp/5h7hESpA==} + + '@types/jsonfile@6.1.4': + resolution: {integrity: sha512-D5qGUYwjvnNNextdU59/+fI+spnwtTFmyQP0h+PfIOSkNfpU6AOICUOkm4i0OnSk+NyjdPJrxCDro0sJsWlRpQ==} + + '@types/mime@1.3.5': + resolution: {integrity: sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==} + + '@types/node@22.14.1': + resolution: {integrity: sha512-u0HuPQwe/dHrItgHHpmw3N2fYCR6x4ivMNbPHRkBVP4CvN+kiRrKHWk3i8tXiO/joPwXLMYvF9TTF0eqgHIuOw==} + + '@types/qs@6.9.18': + resolution: {integrity: sha512-kK7dgTYDyGqS+e2Q4aK9X3D7q234CIZ1Bv0q/7Z5IwRDoADNU81xXJK/YVyLbLTZCoIwUoDoffFeF+p/eIklAA==} + + '@types/range-parser@1.2.7': + resolution: {integrity: sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==} + + '@types/send@0.17.4': + resolution: {integrity: sha512-x2EM6TJOybec7c52BX0ZspPodMsQUd5L6PRwOunVyVUhXiBSKf3AezDL8Dgvgt5o0UfKNfuA0eMLr2wLT4AiBA==} + + '@types/serve-static@1.15.7': + resolution: {integrity: sha512-W8Ym+h8nhuRwaKPaDw34QUkwsGi6Rc4yYqvKFo5rm2FUEhCFbzVWrxXUxuKK8TASjWsysJY0nsmNCGhCOIsrOw==} + + '@xsai/generate-text@0.2.0-beta.3': + resolution: {integrity: sha512-dE01PDM3WDsI9FBzCxOyNQ8uqwae5/Y9hU16iO0DX/HAYSE44zgZ51Yaj3nEmf3idfZq66tswBAYh8eOHuA8Zg==} + + '@xsai/shared-chat@0.2.0-beta.3': + resolution: {integrity: sha512-mjgo+YaUwXXxY1Bfvnj2aW3Brhu2Q8gr5SLaIfiOjI0oXuOxN1Fq3GPnBlVBkAzOLEwIQZ82Q2p9zUlBAljm3g==} + + '@xsai/shared@0.2.0-beta.3': + resolution: {integrity: sha512-bpp848WfOCmmkuSePe7czB5Vy1lZxNqV1pSX/N0gZVXxfBQC6wVqkjoScl17v13hsThDbqB6dyrN4ca3mwVBog==} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + body-parser@2.2.0: + resolution: {integrity: sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg==} + engines: {node: '>=18'} + + bytes@3.1.2: + resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} + engines: {node: '>= 0.8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + caniuse-lite@1.0.30001714: + resolution: {integrity: sha512-mtgapdwDLSSBnCI3JokHM7oEQBLxiJKVRtg10AxM1AyeiKcM96f0Mkbqeq+1AbiCtvMcHRulAAEMu693JrSWqg==} + + content-disposition@1.0.0: + resolution: {integrity: sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg==} + engines: {node: '>= 0.6'} + + content-type@1.0.5: + resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} + engines: {node: '>= 0.6'} + + cookie-signature@1.2.2: + resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} + engines: {node: '>=6.6.0'} + + cookie@0.7.2: + resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} + engines: {node: '>= 0.6'} + + core-js@3.41.0: + resolution: {integrity: sha512-SJ4/EHwS36QMJd6h/Rg+GyR4A5xE0FSI3eZ+iBVpfqf1x0eTSg1smWLHrA+2jQThZSh97fmSgFSU8B61nxosxA==} + + cors@2.8.5: + resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + engines: {node: '>= 0.10'} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + debug@4.4.0: + resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.1: + resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + engines: {node: '>= 0.4'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + eventsource-parser@3.0.1: + resolution: {integrity: sha512-VARTJ9CYeuQYb0pZEPbzi740OWFgpHe7AYJ2WFZVnUDUQp5Dk2yJUgF36YsZ81cOyxT0QxmXD2EQpapAouzWVA==} + engines: {node: '>=18.0.0'} + + eventsource@3.0.6: + resolution: {integrity: sha512-l19WpE2m9hSuyP06+FbuUUf1G+R0SFLrtQfbRb9PRr+oimOfxQhgGCbVaXg5IvZyyTThJsxh6L/srkMiCeBPDA==} + engines: {node: '>=18.0.0'} + + express-rate-limit@7.5.0: + resolution: {integrity: sha512-eB5zbQh5h+VenMPM3fh+nw1YExi5nMr6HUCR62ELSP11huvxm/Uir1H1QEyTkk5QX6A58pX6NmaTMceKZ0Eodg==} + engines: {node: '>= 16'} + peerDependencies: + express: ^4.11 || 5 || ^5.0.0-beta.1 + + express@5.1.0: + resolution: {integrity: sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA==} + engines: {node: '>= 18'} + + fdir@6.4.3: + resolution: {integrity: sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==} + peerDependencies: + picomatch: ^3 || ^4 + peerDependenciesMeta: + picomatch: + optional: true + + finalhandler@2.1.0: + resolution: {integrity: sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q==} + engines: {node: '>= 0.8'} + + forwarded@0.2.0: + resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} + engines: {node: '>= 0.6'} + + fresh@2.0.0: + resolution: {integrity: sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A==} + engines: {node: '>= 0.8'} + + fs-extra@11.3.0: + resolution: {integrity: sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==} + engines: {node: '>=14.14'} + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.2: + resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} + engines: {node: '>= 0.4'} + + http-errors@2.0.0: + resolution: {integrity: sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==} + engines: {node: '>= 0.8'} + + iconv-lite@0.6.3: + resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} + engines: {node: '>=0.10.0'} + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + ipaddr.js@1.9.1: + resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} + engines: {node: '>= 0.10'} + + is-promise@4.0.0: + resolution: {integrity: sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + jiti@2.4.2: + resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} + hasBin: true + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonfile@6.1.0: + resolution: {integrity: sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==} + + magic-string@0.30.17: + resolution: {integrity: sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + media-typer@1.1.0: + resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + engines: {node: '>= 0.8'} + + merge-descriptors@2.0.0: + resolution: {integrity: sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==} + engines: {node: '>=18'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.1: + resolution: {integrity: sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA==} + engines: {node: '>= 0.6'} + + minimist@1.2.8: + resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-inspect@1.13.4: + resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} + engines: {node: '>= 0.4'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-to-regexp@8.2.0: + resolution: {integrity: sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==} + engines: {node: '>=16'} + + pdfjs-dist@5.1.91: + resolution: {integrity: sha512-qSIADdagooJB4wWCBnrBJjRvASevmxL0BwafvOuKJG5uTQdYoFBrhrRYnucKNiSc9qS6JIk0hC5y1yktFljXkA==} + engines: {node: '>=20'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + + pkce-challenge@5.0.0: + resolution: {integrity: sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ==} + engines: {node: '>=16.20.0'} + + prettier@3.5.3: + resolution: {integrity: sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==} + engines: {node: '>=14'} + hasBin: true + + proxy-addr@2.0.7: + resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + engines: {node: '>= 0.10'} + + qs@6.14.0: + resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} + engines: {node: '>=0.6'} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + raw-body@3.0.0: + resolution: {integrity: sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g==} + engines: {node: '>= 0.8'} + + router@2.2.0: + resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} + engines: {node: '>= 18'} + + rsbuild-plugin-dts@0.6.4: + resolution: {integrity: sha512-1sVfKuY2MQPoemFlpmlNjNw+Kx4jNj7ckD0GGNyRjdVqvTGAJJ8bFKoJEgaSmlgbYn2CXv3x1BriqQny23Z9EA==} + engines: {node: '>=16.7.0'} + peerDependencies: + '@microsoft/api-extractor': ^7 + '@rsbuild/core': 1.x + typescript: ^5 + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + typescript: + optional: true + + safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + + safer-buffer@2.1.2: + resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + + send@1.2.0: + resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + engines: {node: '>= 18'} + + serve-static@2.2.0: + resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + engines: {node: '>= 18'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + side-channel-list@1.0.0: + resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + engines: {node: '>= 0.4'} + + side-channel-map@1.0.1: + resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} + engines: {node: '>= 0.4'} + + side-channel-weakmap@1.0.2: + resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} + engines: {node: '>= 0.4'} + + side-channel@1.1.0: + resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + engines: {node: '>= 0.4'} + + statuses@2.0.1: + resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} + engines: {node: '>= 0.8'} + + strip-bom@3.0.0: + resolution: {integrity: sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==} + engines: {node: '>=4'} + + tinyglobby@0.2.12: + resolution: {integrity: sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==} + engines: {node: '>=12.0.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tsconfig-paths@4.2.0: + resolution: {integrity: sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==} + engines: {node: '>=6'} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-is@2.0.1: + resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} + engines: {node: '>= 0.6'} + + typescript@5.8.3: + resolution: {integrity: sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@6.21.0: + resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + + universalify@2.0.1: + resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} + engines: {node: '>= 10.0.0'} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + vary@1.1.2: + resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} + engines: {node: '>= 0.8'} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + zod-to-json-schema@3.24.5: + resolution: {integrity: sha512-/AuWwMP+YqiPbsJx5D6TfgRTc4kTLjsh5SOcd4bLsfUg2RcEXrFMJl1DGgdHy2aCfsIA/cr/1JM0xcB2GZji8g==} + peerDependencies: + zod: ^3.24.1 + + zod@3.24.3: + resolution: {integrity: sha512-HhY1oqzWCQWuUqvBFnsyrtZRhyPeR7SUGv+C4+MsisMuVfSPx8HpwWqH8tRahSlt6M3PiFAcoeFhZAqIXTxoSg==} + +snapshots: + + '@ast-grep/napi-darwin-arm64@0.37.0': + optional: true + + '@ast-grep/napi-darwin-x64@0.37.0': + optional: true + + '@ast-grep/napi-linux-arm64-gnu@0.37.0': + optional: true + + '@ast-grep/napi-linux-arm64-musl@0.37.0': + optional: true + + '@ast-grep/napi-linux-x64-gnu@0.37.0': + optional: true + + '@ast-grep/napi-linux-x64-musl@0.37.0': + optional: true + + '@ast-grep/napi-win32-arm64-msvc@0.37.0': + optional: true + + '@ast-grep/napi-win32-ia32-msvc@0.37.0': + optional: true + + '@ast-grep/napi-win32-x64-msvc@0.37.0': + optional: true + + '@ast-grep/napi@0.37.0': + optionalDependencies: + '@ast-grep/napi-darwin-arm64': 0.37.0 + '@ast-grep/napi-darwin-x64': 0.37.0 + '@ast-grep/napi-linux-arm64-gnu': 0.37.0 + '@ast-grep/napi-linux-arm64-musl': 0.37.0 + '@ast-grep/napi-linux-x64-gnu': 0.37.0 + '@ast-grep/napi-linux-x64-musl': 0.37.0 + '@ast-grep/napi-win32-arm64-msvc': 0.37.0 + '@ast-grep/napi-win32-ia32-msvc': 0.37.0 + '@ast-grep/napi-win32-x64-msvc': 0.37.0 + + '@jridgewell/sourcemap-codec@1.5.0': {} + + '@modelcontextprotocol/sdk@1.9.0': + dependencies: + content-type: 1.0.5 + cors: 2.8.5 + cross-spawn: 7.0.6 + eventsource: 3.0.6 + express: 5.1.0 + express-rate-limit: 7.5.0(express@5.1.0) + pkce-challenge: 5.0.0 + raw-body: 3.0.0 + zod: 3.24.3 + zod-to-json-schema: 3.24.5(zod@3.24.3) + transitivePeerDependencies: + - supports-color + + '@module-federation/error-codes@0.11.2': {} + + '@module-federation/runtime-core@0.11.2': + dependencies: + '@module-federation/error-codes': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@module-federation/runtime-tools@0.11.2': + dependencies: + '@module-federation/runtime': 0.11.2 + '@module-federation/webpack-bundler-runtime': 0.11.2 + + '@module-federation/runtime@0.11.2': + dependencies: + '@module-federation/error-codes': 0.11.2 + '@module-federation/runtime-core': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@module-federation/sdk@0.11.2': {} + + '@module-federation/webpack-bundler-runtime@0.11.2': + dependencies: + '@module-federation/runtime': 0.11.2 + '@module-federation/sdk': 0.11.2 + + '@napi-rs/canvas-android-arm64@0.1.69': + optional: true + + '@napi-rs/canvas-darwin-arm64@0.1.69': + optional: true + + '@napi-rs/canvas-darwin-x64@0.1.69': + optional: true + + '@napi-rs/canvas-linux-arm-gnueabihf@0.1.69': + optional: true + + '@napi-rs/canvas-linux-arm64-gnu@0.1.69': + optional: true + + '@napi-rs/canvas-linux-arm64-musl@0.1.69': + optional: true + + '@napi-rs/canvas-linux-riscv64-gnu@0.1.69': + optional: true + + '@napi-rs/canvas-linux-x64-gnu@0.1.69': + optional: true + + '@napi-rs/canvas-linux-x64-musl@0.1.69': + optional: true + + '@napi-rs/canvas-win32-x64-msvc@0.1.69': + optional: true + + '@napi-rs/canvas@0.1.69': + optionalDependencies: + '@napi-rs/canvas-android-arm64': 0.1.69 + '@napi-rs/canvas-darwin-arm64': 0.1.69 + '@napi-rs/canvas-darwin-x64': 0.1.69 + '@napi-rs/canvas-linux-arm-gnueabihf': 0.1.69 + '@napi-rs/canvas-linux-arm64-gnu': 0.1.69 + '@napi-rs/canvas-linux-arm64-musl': 0.1.69 + '@napi-rs/canvas-linux-riscv64-gnu': 0.1.69 + '@napi-rs/canvas-linux-x64-gnu': 0.1.69 + '@napi-rs/canvas-linux-x64-musl': 0.1.69 + '@napi-rs/canvas-win32-x64-msvc': 0.1.69 + + '@rsbuild/core@1.3.8': + dependencies: + '@rspack/core': 1.3.5(@swc/helpers@0.5.17) + '@rspack/lite-tapable': 1.0.1 + '@swc/helpers': 0.5.17 + core-js: 3.41.0 + jiti: 2.4.2 + transitivePeerDependencies: + - '@rspack/tracing' + + '@rslib/core@0.6.4(typescript@5.8.3)': + dependencies: + '@rsbuild/core': 1.3.8 + rsbuild-plugin-dts: 0.6.4(@rsbuild/core@1.3.8)(typescript@5.8.3) + tinyglobby: 0.2.12 + optionalDependencies: + typescript: 5.8.3 + transitivePeerDependencies: + - '@rspack/tracing' + + '@rspack/binding-darwin-arm64@1.3.5': + optional: true + + '@rspack/binding-darwin-x64@1.3.5': + optional: true + + '@rspack/binding-linux-arm64-gnu@1.3.5': + optional: true + + '@rspack/binding-linux-arm64-musl@1.3.5': + optional: true + + '@rspack/binding-linux-x64-gnu@1.3.5': + optional: true + + '@rspack/binding-linux-x64-musl@1.3.5': + optional: true + + '@rspack/binding-win32-arm64-msvc@1.3.5': + optional: true + + '@rspack/binding-win32-ia32-msvc@1.3.5': + optional: true + + '@rspack/binding-win32-x64-msvc@1.3.5': + optional: true + + '@rspack/binding@1.3.5': + optionalDependencies: + '@rspack/binding-darwin-arm64': 1.3.5 + '@rspack/binding-darwin-x64': 1.3.5 + '@rspack/binding-linux-arm64-gnu': 1.3.5 + '@rspack/binding-linux-arm64-musl': 1.3.5 + '@rspack/binding-linux-x64-gnu': 1.3.5 + '@rspack/binding-linux-x64-musl': 1.3.5 + '@rspack/binding-win32-arm64-msvc': 1.3.5 + '@rspack/binding-win32-ia32-msvc': 1.3.5 + '@rspack/binding-win32-x64-msvc': 1.3.5 + + '@rspack/core@1.3.5(@swc/helpers@0.5.17)': + dependencies: + '@module-federation/runtime-tools': 0.11.2 + '@rspack/binding': 1.3.5 + '@rspack/lite-tapable': 1.0.1 + caniuse-lite: 1.0.30001714 + optionalDependencies: + '@swc/helpers': 0.5.17 + + '@rspack/lite-tapable@1.0.1': {} + + '@swc/helpers@0.5.17': + dependencies: + tslib: 2.8.1 + + '@types/body-parser@1.19.5': + dependencies: + '@types/connect': 3.4.38 + '@types/node': 22.14.1 + + '@types/connect@3.4.38': + dependencies: + '@types/node': 22.14.1 + + '@types/express-serve-static-core@5.0.6': + dependencies: + '@types/node': 22.14.1 + '@types/qs': 6.9.18 + '@types/range-parser': 1.2.7 + '@types/send': 0.17.4 + + '@types/express@5.0.1': + dependencies: + '@types/body-parser': 1.19.5 + '@types/express-serve-static-core': 5.0.6 + '@types/serve-static': 1.15.7 + + '@types/fs-extra@11.0.4': + dependencies: + '@types/jsonfile': 6.1.4 + '@types/node': 22.14.1 + + '@types/http-errors@2.0.4': {} + + '@types/jsonfile@6.1.4': + dependencies: + '@types/node': 22.14.1 + + '@types/mime@1.3.5': {} + + '@types/node@22.14.1': + dependencies: + undici-types: 6.21.0 + + '@types/qs@6.9.18': {} + + '@types/range-parser@1.2.7': {} + + '@types/send@0.17.4': + dependencies: + '@types/mime': 1.3.5 + '@types/node': 22.14.1 + + '@types/serve-static@1.15.7': + dependencies: + '@types/http-errors': 2.0.4 + '@types/node': 22.14.1 + '@types/send': 0.17.4 + + '@xsai/generate-text@0.2.0-beta.3': + dependencies: + '@xsai/shared': 0.2.0-beta.3 + '@xsai/shared-chat': 0.2.0-beta.3 + + '@xsai/shared-chat@0.2.0-beta.3': + dependencies: + '@xsai/shared': 0.2.0-beta.3 + + '@xsai/shared@0.2.0-beta.3': {} + + accepts@2.0.0: + dependencies: + mime-types: 3.0.1 + negotiator: 1.0.0 + + body-parser@2.2.0: + dependencies: + bytes: 3.1.2 + content-type: 1.0.5 + debug: 4.4.0 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + on-finished: 2.4.1 + qs: 6.14.0 + raw-body: 3.0.0 + type-is: 2.0.1 + transitivePeerDependencies: + - supports-color + + bytes@3.1.2: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + caniuse-lite@1.0.30001714: {} + + content-disposition@1.0.0: + dependencies: + safe-buffer: 5.2.1 + + content-type@1.0.5: {} + + cookie-signature@1.2.2: {} + + cookie@0.7.2: {} + + core-js@3.41.0: {} + + cors@2.8.5: + dependencies: + object-assign: 4.1.1 + vary: 1.1.2 + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + debug@4.4.0: + dependencies: + ms: 2.1.3 + + depd@2.0.0: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + ee-first@1.1.1: {} + + encodeurl@2.0.0: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + escape-html@1.0.3: {} + + etag@1.8.1: {} + + eventsource-parser@3.0.1: {} + + eventsource@3.0.6: + dependencies: + eventsource-parser: 3.0.1 + + express-rate-limit@7.5.0(express@5.1.0): + dependencies: + express: 5.1.0 + + express@5.1.0: + dependencies: + accepts: 2.0.0 + body-parser: 2.2.0 + content-disposition: 1.0.0 + content-type: 1.0.5 + cookie: 0.7.2 + cookie-signature: 1.2.2 + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + finalhandler: 2.1.0 + fresh: 2.0.0 + http-errors: 2.0.0 + merge-descriptors: 2.0.0 + mime-types: 3.0.1 + on-finished: 2.4.1 + once: 1.4.0 + parseurl: 1.3.3 + proxy-addr: 2.0.7 + qs: 6.14.0 + range-parser: 1.2.1 + router: 2.2.0 + send: 1.2.0 + serve-static: 2.2.0 + statuses: 2.0.1 + type-is: 2.0.1 + vary: 1.1.2 + transitivePeerDependencies: + - supports-color + + fdir@6.4.3(picomatch@4.0.2): + optionalDependencies: + picomatch: 4.0.2 + + finalhandler@2.1.0: + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + on-finished: 2.4.1 + parseurl: 1.3.3 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + forwarded@0.2.0: {} + + fresh@2.0.0: {} + + fs-extra@11.3.0: + dependencies: + graceful-fs: 4.2.11 + jsonfile: 6.1.0 + universalify: 2.0.1 + + function-bind@1.1.2: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-symbols@1.1.0: {} + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + http-errors@2.0.0: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.1 + toidentifier: 1.0.1 + + iconv-lite@0.6.3: + dependencies: + safer-buffer: 2.1.2 + + inherits@2.0.4: {} + + ipaddr.js@1.9.1: {} + + is-promise@4.0.0: {} + + isexe@2.0.0: {} + + jiti@2.4.2: {} + + json5@2.2.3: {} + + jsonfile@6.1.0: + dependencies: + universalify: 2.0.1 + optionalDependencies: + graceful-fs: 4.2.11 + + magic-string@0.30.17: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.0 + + math-intrinsics@1.1.0: {} + + media-typer@1.1.0: {} + + merge-descriptors@2.0.0: {} + + mime-db@1.54.0: {} + + mime-types@3.0.1: + dependencies: + mime-db: 1.54.0 + + minimist@1.2.8: {} + + ms@2.1.3: {} + + negotiator@1.0.0: {} + + object-assign@4.1.1: {} + + object-inspect@1.13.4: {} + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + parseurl@1.3.3: {} + + path-key@3.1.1: {} + + path-to-regexp@8.2.0: {} + + pdfjs-dist@5.1.91: + optionalDependencies: + '@napi-rs/canvas': 0.1.69 + + picocolors@1.1.1: {} + + picomatch@4.0.2: {} + + pkce-challenge@5.0.0: {} + + prettier@3.5.3: {} + + proxy-addr@2.0.7: + dependencies: + forwarded: 0.2.0 + ipaddr.js: 1.9.1 + + qs@6.14.0: + dependencies: + side-channel: 1.1.0 + + range-parser@1.2.1: {} + + raw-body@3.0.0: + dependencies: + bytes: 3.1.2 + http-errors: 2.0.0 + iconv-lite: 0.6.3 + unpipe: 1.0.0 + + router@2.2.0: + dependencies: + debug: 4.4.0 + depd: 2.0.0 + is-promise: 4.0.0 + parseurl: 1.3.3 + path-to-regexp: 8.2.0 + transitivePeerDependencies: + - supports-color + + rsbuild-plugin-dts@0.6.4(@rsbuild/core@1.3.8)(typescript@5.8.3): + dependencies: + '@ast-grep/napi': 0.37.0 + '@rsbuild/core': 1.3.8 + magic-string: 0.30.17 + picocolors: 1.1.1 + tinyglobby: 0.2.12 + tsconfig-paths: 4.2.0 + optionalDependencies: + typescript: 5.8.3 + + safe-buffer@5.2.1: {} + + safer-buffer@2.1.2: {} + + send@1.2.0: + dependencies: + debug: 4.4.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 2.0.0 + http-errors: 2.0.0 + mime-types: 3.0.1 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.1 + transitivePeerDependencies: + - supports-color + + serve-static@2.2.0: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 1.2.0 + transitivePeerDependencies: + - supports-color + + setprototypeof@1.2.0: {} + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + side-channel-list@1.0.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + + side-channel-map@1.0.1: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + + side-channel-weakmap@1.0.2: + dependencies: + call-bound: 1.0.4 + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + object-inspect: 1.13.4 + side-channel-map: 1.0.1 + + side-channel@1.1.0: + dependencies: + es-errors: 1.3.0 + object-inspect: 1.13.4 + side-channel-list: 1.0.0 + side-channel-map: 1.0.1 + side-channel-weakmap: 1.0.2 + + statuses@2.0.1: {} + + strip-bom@3.0.0: {} + + tinyglobby@0.2.12: + dependencies: + fdir: 6.4.3(picomatch@4.0.2) + picomatch: 4.0.2 + + toidentifier@1.0.1: {} + + tsconfig-paths@4.2.0: + dependencies: + json5: 2.2.3 + minimist: 1.2.8 + strip-bom: 3.0.0 + + tslib@2.8.1: {} + + type-is@2.0.1: + dependencies: + content-type: 1.0.5 + media-typer: 1.1.0 + mime-types: 3.0.1 + + typescript@5.8.3: {} + + undici-types@6.21.0: {} + + universalify@2.0.1: {} + + unpipe@1.0.0: {} + + vary@1.1.2: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + wrappy@1.0.2: {} + + zod-to-json-schema@3.24.5(zod@3.24.3): + dependencies: + zod: 3.24.3 + + zod@3.24.3: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml new file mode 100644 index 0000000..833a27f --- /dev/null +++ b/pnpm-workspace.yaml @@ -0,0 +1,2 @@ +packages: + - 'packages/*' diff --git a/src/imageGenerator.js b/src/imageGenerator.js deleted file mode 100644 index ab2b7ab..0000000 --- a/src/imageGenerator.js +++ /dev/null @@ -1,253 +0,0 @@ -/** - * 图像生成模块,负责将PDF区域转换为图像 - */ -import pkg from 'pdfjs-dist/legacy/build/pdf.js'; -const { getDocument } = pkg; -import sharp from 'sharp'; -import path from 'path'; -import fs from 'fs-extra'; -import { generateRandomFileName } from './utils.js'; -import { createCanvas } from 'canvas'; - -// 设置PDF.js的worker路径 -try { - // 获取当前文件的目录 - const currentDir = path.dirname(new URL(import.meta.url).pathname); - // 构建 worker 的绝对路径 - const pdfjsWorker = path.join(currentDir, '..', 'node_modules/pdfjs-dist/legacy/build/pdf.worker.js'); - const pdfjsWorkerUrl = new URL(`file://${pdfjsWorker}`).href; - - // 全局设置worker路径 - globalThis.pdfjsWorkerSrc = pdfjsWorkerUrl; - - console.log('设置PDF.js worker路径:', pdfjsWorkerUrl); -} catch (error) { - console.warn('设置PDF.js worker路径时出错:', error.message); -} - -/** - * 将PDF页面的指定区域渲染为图像 - * @param {Object} page PDF.js页面对象 - * @param {Array} rect 区域坐标 [x0, y0, x1, y1] - * @param {number} scale 渲染缩放比例 - * @returns {Buffer} 图像缓冲区 - */ -export const renderRectToImage = async (page, rect, scale = 4) => { - const viewport = page.getViewport({ scale }); - - // 计算渲染区域 - 添加内边距确保文本不被截断 - const [x0, y0, x1, y1] = rect; - - // 添加内边距(单位:原始坐标系下的点) - const padding = 20 / scale; // 添加相当20像素的填充 - - // 确保填充后的坐标不超出页面范围 - const paddedX0 = Math.max(0, x0 - padding); - const paddedY0 = Math.max(0, y0 - padding); - const paddedX1 = Math.min(viewport.width / scale, x1 + padding); - const paddedY1 = Math.min(viewport.height / scale, y1 + padding); - - // 计算最终宽度和高度 - const width = (paddedX1 - paddedX0) * scale; - const height = (paddedY1 - paddedY0) * scale; - - // 创建canvas - 使用Node.js版的canvas - const canvas = createCanvas(width, height); - const context = canvas.getContext('2d'); - - // 填充背景色 - context.fillStyle = '#ffffff'; - context.fillRect(0, 0, width, height); - - // 设置渲染参数 - 使用填充后的坐标 - const renderContext = { - canvasContext: context, - viewport: viewport, - transform: [scale, 0, 0, scale, -paddedX0 * scale, -paddedY0 * scale] - }; - - // 渲染页面 - await page.render(renderContext).promise; - - // 获取图像数据 - 使用Node.js版的canvas - const pngData = canvas.toBuffer('image/png'); - - // 使用Sharp处理图像 - const buffer = await sharp(pngData).png().toBuffer(); - - return buffer; -}; - -/** - * 从PDF文件生成区域图像 - * @param {string} pdfPath PDF文件路径 - * @param {Array} pageRects 每个页面的区域信息 [{ pageIndex, rects }, ...] - * @param {string} outputDir 输出目录 - * @param {boolean} drawBoundingBoxes 是否绘制边界框 - * @returns {Array} 图像信息 [{ pageImage, rectImages }, ...] - */ -export const generateImagesFromPdf = async (pdfPath, pageRects, outputDir, drawBoundingBoxes = true) => { - // 确保输出目录存在 - await fs.ensureDir(outputDir); - - // 加载PDF文档 - const data = new Uint8Array(await fs.readFile(pdfPath)); - const pdfDocument = await getDocument({ data }).promise; - - const imageInfos = []; - - // 处理每一页 - for (const { pageIndex, rects } of pageRects) { - console.log(`生成页面 ${pageIndex + 1} 的图像`); - - // 获取页面 - const page = await pdfDocument.getPage(pageIndex + 1); - const viewport = page.getViewport({ scale: 1.0 }); - - // 用于存储区域图像文件名 - const rectImages = []; - - // 处理每个区域 - for (let i = 0; i < rects.length; i++) { - const rect = rects[i]; - // 生成区域图像 - const buffer = await renderRectToImage(page, rect); - - // 保存图像 - const imageName = `${pageIndex}_${i}.png`; - const imagePath = path.join(outputDir, imageName); - await fs.writeFile(imagePath, buffer); - - rectImages.push(imageName); - } - - // 如果需要绘制边界框,渲染整个页面并标记区域 - let pageImage = null; - if (drawBoundingBoxes) { - // 渲染整个页面 - 使用Node.js版的canvas - const scale = 3; - const canvas = createCanvas(viewport.width * scale, viewport.height * scale); - const context = canvas.getContext('2d'); - - // 填充白色背景 - context.fillStyle = '#ffffff'; - context.fillRect(0, 0, canvas.width, canvas.height); - - // 渲染页面 - await page.render({ - canvasContext: context, - viewport: page.getViewport({ scale }) - }).promise; - - // 绘制区域标记 - context.lineWidth = 1; - context.strokeStyle = 'red'; - context.fillStyle = 'white'; - - for (let i = 0; i < rects.length; i++) { - const [x0, y0, x1, y1] = rects[i]; - - // 绘制矩形 - context.strokeRect(x0 * scale, y0 * scale, (x1 - x0) * scale, (y1 - y0) * scale); - - // 绘制标签背景 - context.fillRect(x0 * scale + 2, y0 * scale + 2, 80, 12); - - // 绘制标签文本 - context.fillStyle = 'red'; - context.font = '10px Arial'; - context.fillText(`${pageIndex}_${i}`, x0 * scale + 5, y0 * scale + 12); - context.fillStyle = 'white'; - } - - // 保存页面图像 - const pageImageName = `${pageIndex}.png`; - const pageImagePath = path.join(outputDir, pageImageName); - - const pageBuffer = await sharp(canvas.toBuffer('image/png')).png().toBuffer(); - await fs.writeFile(pageImagePath, pageBuffer); - - pageImage = pageImageName; - } - - imageInfos.push({ - pageImage, - rectImages - }); - } - - return imageInfos; -}; - -/** - * 直接生成PDF文档的所有页面图像,不依赖区域识别 - * @param {Buffer|string} pdfData PDF文件数据或路径 - * @param {string} outputDir 输出目录 - * @param {number} scale 缩放比例 - * @returns {Promise>} 生成的图像文件路径数组 - */ -export const generateFullPageImages = async (pdfData, outputDir, scale = 3) => { - // 确保输出目录存在 - await fs.ensureDir(outputDir); - - // 如果pdfData是字符串,则当作路径处理 - let data; - if (typeof pdfData === 'string') { - data = new Uint8Array(await fs.readFile(pdfData)); - } else { - data = pdfData; - } - - // 加载PDF文档 - const pdfDocument = await getDocument({ data }).promise; - const numPages = pdfDocument.numPages; - console.log(`PDF文档共 ${numPages} 页`); - - // 存储生成的图像路径 - const pageImages = []; - - // 处理每一页 - for (let i = 0; i < numPages; i++) { - const pageIndex = i + 1; - console.log(`处理第 ${pageIndex} 页...`); - - // 获取页面 - const page = await pdfDocument.getPage(pageIndex); - const viewport = page.getViewport({ scale }); - - // 创建canvas - const canvas = createCanvas(viewport.width, viewport.height); - const context = canvas.getContext('2d'); - - // 填充白色背景 - context.fillStyle = '#ffffff'; - context.fillRect(0, 0, viewport.width, viewport.height); - - // 渲染页面 - await page.render({ - canvasContext: context, - viewport: viewport - }).promise; - - // 保存为图像 - const imageName = `page_${pageIndex}.png`; - const imagePath = path.join(outputDir, imageName); - - // 将canvas转换为图像并保存 - const buffer = await sharp(canvas.toBuffer('image/png')).png().toBuffer(); - await fs.writeFile(imagePath, buffer); - - // 添加到结果数组 - pageImages.push({"index":pageIndex,"path":imagePath}); - - console.log(`页面 ${pageIndex} 已保存到: ${imagePath}`); - } - - return pageImages; -}; - -export default { - renderRectToImage, - generateImagesFromPdf, - generateFullPageImages -}; diff --git a/src/index.js b/src/index.js deleted file mode 100644 index 57a197a..0000000 --- a/src/index.js +++ /dev/null @@ -1,265 +0,0 @@ -/** - * PDF2MD 主入口模块 - * 提供PDF转Markdown的完整功能 - */ -import fs from 'fs-extra'; -import path from 'path'; -import { parsePdfRects } from './pdfParser.js'; -import { generateImagesFromPdf, generateFullPageImages } from './imageGenerator.js'; -import { convertImagesToMarkdown } from './markdownConverter.js'; -import { ensureDir, removeFile, extractMdFromLLMOutput, adjustMarkdownHeadings, getOldMarkdownHeadings } from './utils.js'; -import ModelClient from './modelClient.js'; - -/** - * 将PDF文件解析为Markdown - * @param {string} pdfPath PDF文件路径 - * @param {Object} options 配置选项 - * @returns {Object} 处理结果 { content, imageFiles } - */ -/** - * 将PDF文件解析为Markdown,使用全页图像识别 - * @param {string} pdfPath PDF文件路径 - * @param {Object} options 配置选项 - * @returns {Object} 处理结果 { content, imageFiles, mdFilePath } - */ -export const parsePdfFullPage = async (pdfPath, options = {}) => { - const { - outputDir = './output', - apiKey, - baseUrl, - openAiApicompatible = false, - model = 'gpt-4-vision-preview', - prompt = `使用markdown语法,将图片中识别到的文字转换为markdown格式输出。你必须做到: - 1. 输出和使用识别到的图片的相同的语言,例如,识别到英语的字段,输出的内容必须是英语。 - 2. 不要解释和输出无关的文字,直接输出图片中的内容。 - 3. 内容不要包含在\`\`\`markdown \`\`\`中、段落公式使用 $$ $$ 的形式、行内公式使用 $ $ 的形式。 - 4. 忽略掉页眉页脚里的内容 - 5. 请不要对图片的标题进行markdown的格式化,直接以文本形式输出到内容中。 - 6. 有可能每页都会出现期刊名称,论文名称,会议名称或者书籍名称,请忽略他们不要识别成标题 - 7. 请精确分析当前PDF页面的文本结构和视觉布局,按以下要求处理: - 1. 识别所有标题文本,并判断其层级(根据字体大小、加粗、位置等视觉特征) - 2. 输出为带层级的Markdown格式,严格使用以下规则: - - 一级标题:字体最大/顶部居中,前面加 # - - 二级标题:字体较大/左对齐加粗,有可能是数字开头也有可能是罗马数组开头,前面加 ## - - 三级标题:字体稍大/左对齐加粗,前面加 ### - - 正文文本:直接转换为普通段落 - 3. 不确定层级的标题请标记[?] - 4. 如果是中文文献,但是有英文标题和摘要可以省略不输出 - 示例输出: - ## 4研究方法 - ### 4.1数据收集 - 本文采用问卷调查...`, - textPrompt = `你是一个专业的文本结构化处理助手,擅长根据前缀规则和标题语义分析并优化Markdown文档的标题层级结构。请根据以下要求处理我提供的Markdown标题: - ## 任务描述 - 请根据markdown文章标题的实际含义,以及标题的前缀特征调整各级标题的正确层级关系,具体要求如下: - 1. 一般相同格式的前缀的标题是同级关系({title}代表实际的标题内容): - 例如: - 纯数字前缀开头\`1 {title}\`, \` 2 {title}\` ,\` 3 {title}\`,\` 4 {title}\`,\` 5 {title}\` ... 等 - 罗马数字前缀开头的\`I {title}\`,\`II {title}\` ,\`III {title}\`,\`IV {title}\`,\`V {title}\` ... 等 - 小数点分隔数组前缀开头 \`1.1 {title}\`, \`1.2 {title}\`, \`1.3 {title}\`.... \`2.1 {title}\`, \`2.2 {title}\` 等 - 2. 将子标题正确嵌套到父标题下(如\`1.1 {title}\`应作为\`1 {title}\`的子标题) - 3. 剔除与文章内容无关的标题 - 4. 保持输出标题内容与输入完全一致 - 5. 确保内容无缺失 - 6. 如果是中文文献,但有英文的文章题目,可以省略 - - ## 输入输出格式 - - 输入:包含错误层级关系的markdown标题结构 - - 输出:修正后的标准markdown标题层级结构 - - ## 处理原则 - 1. 严格根据标题语义确定所属关系 - 2. 仅调整层级不修改原标题文本 - 3. 无关标题直接移除不保留占位 - 4. 相同前缀规则的标题必须是同一级别,不能出现 一部分是 n级标题,一部分是其他级别的标题 - - ## 输出要求 - 请将修正后的完整标题结构放在代码块中返回,格式示例如下: - - 期望输出: - \`\`\`markdown - - \`\`\` - - 请处理以下数据: - `, - verbose = false, - scale = 3, - concurrency = 2, - onProgress - } = options; - - // 确保输出目录存在 - await ensureDir(outputDir); - - console.log('开始解析PDF文件(全页模式):', pdfPath); - - try { - // 第一步:生成全页图像 - console.log('生成全页图像...'); - const imageOutputDir = path.join(outputDir, 'pages'); - await ensureDir(imageOutputDir); - - const imageFiles = await generateFullPageImages(pdfPath, imageOutputDir, scale); - - //先把总页数传递回调用方法 - if(onProgress){ - onProgress({ - current: 0, - total: imageFiles.length, - taskStatus: "starting" - }); - } - - // 第二步:使用视觉模型处理每个页面图像 - console.log('处理全页图像...'); - - // 创建模型客户端 - const modelClient = new ModelClient({ - apiKey, - baseUrl, - model, - openAiApicompatible - }); - - const pageContents = []; - const processImages = async item => { - console.log(`处理页面 ${item.index}/${imageFiles.length}: ${path.basename(item.path)}`); - try { - // 处理图像 - 确保传入有效的prompt - const defaultPrompt = '请将图像中的所有文本内容转换为Markdown格式,包括标题、段落、列表和表格等。'; - const pageContent = await modelClient.processImage(item.path, prompt || defaultPrompt); - // 添加页面内容 - pageContents.push({ - pageIndex: item.index, - content: pageContent - }); - // 处理完成后,更新调用者的信息 - if(onProgress){ - onProgress({ - current: pageContents.length, - total: imageFiles.length, - taskStatus: "running" - }); - } - return { success: true, item, data: pageContent }; - } catch (error) { - console.error('Markdown 转换失败:', error); - return { success: false, item, error: error.message }; - } - } - - // 并行处理所有问题,最多同时处理5个 - await processInParallel(imageFiles, processImages, concurrency); - - //并行处理生成结果是乱序的,根据pageIndex进行排序再输出Markdown - pageContents.sort((a, b) => a.pageIndex - b.pageIndex); - - // 第三步:生成Markdown文件 - console.log('生成Markdown文档...'); - - // 生成Markdown内容 - let content = ''; - for (const page of pageContents) { - content += page.content; - } - - console.log("正在重新调整目录..."); - - // 提取转换后的标题 - const title = await getOldMarkdownHeadings(content); - - //使用大模型重新调整目录结构 - const convertedTitleLLMResult = await modelClient.processImage(null, textPrompt + JSON.stringify(title) || defaultPrompt); - const convertedTitle = await extractMdFromLLMOutput(convertedTitleLLMResult); - - //根据调整后的结果重新生成md文件 - const convertContent = await adjustMarkdownHeadings(content, convertedTitle); - - console.log("目录调整完成..."); - - // 第四步:保存Markdown文件 - const mdFilePath = path.join(outputDir, path.basename(pdfPath, '.pdf') + '.md'); - await fs.writeFile(mdFilePath, convertContent); - console.log('Markdown文件已保存至:', mdFilePath); - - // 第五步:清理临时图像文件(如果不需要保留) - if (!verbose) { - console.log('清理临时文件...'); - for (const imagePath of imageFiles) { - await removeFile(imagePath.path); - } - } - - // 将任务执行结束传递回调用方法 - if(onProgress){ - onProgress({ - current: imageFiles.length, - total: imageFiles.length, - taskStatus:"finished" - }); - } - - return { - content, - mdFilePath, - imageFiles - }; - } catch (error) { - console.error('PDF解析过程中发生错误:', error); - throw error; - } -}; - -/** - * 将PDF文件解析为Markdown(使用区域识别) - * @param {string} pdfPath PDF文件路径 - * @param {Object} options 配置选项 - * @returns {Object} 处理结果 { content, imageFiles } - */ -/** - * 将PDF文件解析为Markdown - * @param {string} pdfPath PDF文件路径 - * @param {Object} options 配置选项 - * @returns {Object} 处理结果 { content, imageFiles, mdFilePath } - */ -export const parsePdf = async (pdfPath, options = {}) => { - // 直接使用全页图像处理,不再使用子图 - return parsePdfFullPage(pdfPath, options); -}; - -// 并行处理数组的辅助函数,限制并发数 -const processInParallel = async (items, processFunction, concurrencyLimit) => { - const results = []; - const inProgress = new Set(); - const queue = [...items]; - - while (queue.length > 0 || inProgress.size > 0) { - // 如果有空闲槽位且队列中还有任务,启动新任务 - while (inProgress.size < concurrencyLimit && queue.length > 0) { - const item = queue.shift(); - const promise = processFunction(item).then(result => { - inProgress.delete(promise); - return result; - }); - inProgress.add(promise); - results.push(promise); - } - - // 等待其中一个任务完成 - if (inProgress.size > 0) { - await Promise.race(inProgress); - } - } - - return Promise.all(results); -}; - - -/** - * PDF2MD模块导出 - */ -export default { - parsePdf, - parsePdfFullPage -}; diff --git a/src/markdownConverter.js b/src/markdownConverter.js deleted file mode 100644 index e1a8a0a..0000000 --- a/src/markdownConverter.js +++ /dev/null @@ -1,116 +0,0 @@ -/** - * Markdown转换模块,使用模型客户端将图像转换为Markdown - */ -import fs from 'fs-extra'; -import path from 'path'; -import ModelClient from './modelClient.js'; - -// 默认提示词(中文版) -const DEFAULT_PROMPT = `使用markdown语法,将图片中识别到的文字转换为markdown格式输出。你必须做到: -1. 输出和使用识别到的图片的相同的语言,例如,识别到英语的字段,输出的内容必须是英语。 -2. 不要解释和输出无关的文字,直接输出图片中的内容。例如,严禁输出 "以下是我根据图片内容生成的markdown文本:"这样的例子,而是应该直接输出markdown。 -3. 内容不要包含在\`\`\`markdown \`\`\`中、段落公式使用 $$ $$ 的形式、行内公式使用 $ $ 的形式、忽略掉长直线、忽略掉页码。 -再次强调,不要解释和输出无关的文字,直接输出图片中的内容。`; - -// 默认区域提示词(中文版) -const DEFAULT_RECT_PROMPT = `图片中用红色框和名称(%s)标注出了一些区域。如果区域是表格或者图片,使用 ![]() 的形式插入到输出内容中,否则直接输出文字内容。`; - -// 此处移除DEFAULT_ROLE_PROMPT,它已经被迁移到modelClient.js - -/** - * 处理单个图像并转换为Markdown - * @param {ModelClient} modelClient 模型客户端实例 - * @param {string} imagePath 图像文件路径 - * @param {string} prompt 提示词 - * @param {Object} options 模型选项 - * @returns {string} Markdown内容 - */ -export const processImageToMarkdown = async (modelClient, imagePath, prompt, options = {}) => { - return modelClient.processImage(imagePath, prompt, options); -}; - -/** - * 处理一组图像并合并成完整的Markdown - * @param {Array} imageInfos 图像信息数组 [{ pageImage, rectImages }, ...] - * @param {string} outputDir 输出目录 - * @param {Object} options 配置选项 - * @returns {string} 合并后的Markdown内容 - */ -export const convertImagesToMarkdown = async (imageInfos, outputDir, options) => { - const { - apiKey, - baseUrl, - model = 'gpt-4-vision-preview', - prompt: customPrompt, - rectPrompt: customRectPrompt, - verbose = false, - concurrency = 1, - modelConfig = {} - } = options; - - // 创建模型客户端 - const modelClient = new ModelClient({ - apiKey, - baseUrl, - model, - modelConfig - }); - - // 使用自定义提示词或默认提示词 - const prompt = customPrompt || DEFAULT_PROMPT; - const rectPrompt = customRectPrompt || DEFAULT_RECT_PROMPT; - - // 存储每个图像的Markdown内容 - const markdownParts = []; - - // 处理每个页面的图像 - for (let pageIndex = 0; pageIndex < imageInfos.length; pageIndex++) { - const { pageImage, rectImages } = imageInfos[pageIndex]; - console.log(`处理页面 ${pageIndex + 1} 的 ${rectImages.length} 个区域图像`); - - // 处理页面上的每个区域图像 - const tasks = rectImages.map(async (rectImage, rectIndex) => { - const imagePath = path.join(outputDir, rectImage); - const imageName = `${pageIndex}_${rectIndex}`; - - // 构建提示词 - const fullPrompt = prompt + '\n' + rectPrompt.replace('%s', imageName); - - try { - // 处理图像 - const markdown = await processImageToMarkdown(modelClient, imagePath, fullPrompt, { model }); - return { rectIndex, markdown }; - } catch (error) { - console.error(`处理图像 ${imageName} 失败:`, error); - return { rectIndex, markdown: `` }; - } - }); - - // 并行处理图像(根据并发度) - const results = []; - for (let i = 0; i < tasks.length; i += concurrency) { - const batch = tasks.slice(i, i + concurrency); - const batchResults = await Promise.all(batch); - results.push(...batchResults); - } - - // 按原始顺序整理结果 - const sortedResults = results.sort((a, b) => a.rectIndex - b.rectIndex); - const pageMarkdownParts = sortedResults.map(result => result.markdown); - - // 添加页面标记 - // markdownParts.push(`\n\n`); - markdownParts.push(...pageMarkdownParts); - // markdownParts.push(`\n\n\n\n`); - } - - // 合并所有Markdown内容 - return markdownParts.join('\n\n'); -}; - -export default { - processImageToMarkdown, - convertImagesToMarkdown, - DEFAULT_PROMPT, - DEFAULT_RECT_PROMPT -}; diff --git a/src/modelClient.js b/src/modelClient.js deleted file mode 100644 index d9fc696..0000000 --- a/src/modelClient.js +++ /dev/null @@ -1,370 +0,0 @@ -/** - * 模型客户端模块,用于处理不同视觉模型的API调用 - */ -import fs from 'fs-extra'; -import path from 'path'; -import https from 'https'; -import http from 'http'; -import { promisify } from 'util'; - -// 默认角色提示词(中文版) -const DEFAULT_ROLE_PROMPT = `你是一个PDF文档解析器,使用markdown和latex语法输出图片的内容。`; - -/** - * 模型客户端类,处理与不同视觉模型的交互 - */ -export class ModelClient { - /** - * 创建模型客户端实例 - * @param {Object} config 配置对象 - * @param {string} config.apiKey OpenAI API密钥 - * @param {string} [config.baseUrl] 自定义API基础URL - * @param {string} [config.model='gpt-4-vision-preview'] 默认使用的模型 - * @param {Object} [config.modelConfig={}] 模型特定配置 - */ - constructor(config) { - this.config = { - model: 'gpt-4-vision-preview', - modelConfig: {}, - ...config - }; - - // 初始化模型客户端 - this.initClient(); - } - - /** - * 初始化模型客户端 - * @private - */ - initClient() { - const { apiKey } = this.config; - - if (!apiKey) { - throw new Error('必须提供API密钥'); - } - - // 不再创建SDK实例,而是保存必要的配置信息用于API调用 - this.apiKey = apiKey; - } - - /** - * 处理图像并转换为Markdown文本 - * @param {string} imagePath 图像文件路径 - * @param {string} prompt 提示词 - * @param {Object} [options={}] 附加选项 - * @param {string} [options.model] 覆盖默认模型 - * @param {string} [options.rolePrompt] 覆盖默认角色提示词 - * @param {number} [options.maxTokens] 最大生成token数 - * @param {string} [options.endpoint] 自定义API端点 - * @returns {Promise} Markdown文本 - */ - async processImage(imagePath, prompt, options = {}) { - const { - model = this.config.model, - rolePrompt = DEFAULT_ROLE_PROMPT, - maxTokens = 4096, - endpoint = this.config.baseUrl - } = options; - - // 读取图像文件 - let base64Image = null; - if (imagePath) { - const imageBuffer = await fs.readFile(imagePath); - base64Image = imageBuffer.toString('base64'); - } - - - // 根据不同模型类型调用对应API - if (model.startsWith('gpt-4') || model.startsWith('gpt-3.5')) { - return this.callOpenAIAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint); - } else if (model.startsWith('claude') && !this.config.openAiApicompatible) { - return this.callClaudeAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint); - } else if (model.startsWith('gemini') && !this.config.openAiApicompatible) { - return this.callGeminiAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint); - } else if (model.startsWith('doubao') && !this.config.openAiApicompatible) { - return this.callDoubaoAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint); - } else { - // 默认使用OpenAI - return this.callOpenAIAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint); - } - } - - /** - * 通过API调用OpenAI视觉模型 - * @private - */ - async callOpenAIAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint) { - // 使用OpenAI API - const apiEndpoint = endpoint || 'https://api.openai.com/v1/chat/completions'; - - // 构建用户消息内容 - const userContent = [{ type: 'text', text: prompt }]; - - // 如果有base64图片,添加图片内容 - if (base64Image) { - userContent.push({ - type: 'image_url', - image_url: { - url: `data:image/png;base64,${base64Image}` - } - }); - } - - const requestData = { - model, - messages: [ - { - role: 'system', - content: rolePrompt - }, - { - role: 'user', - content: userContent - } - ], - max_tokens: maxTokens - }; - - const response = await this.makeHttpRequest(apiEndpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Authorization': `Bearer ${this.apiKey}` - }, - body: JSON.stringify(requestData) - }); - - if (response.error) { - throw new Error(`OpenAI API调用失败: ${response.error.message || JSON.stringify(response.error)}`); - } - - return response.choices[0].message.content; - } - - /** - * 通过API调用Claude视觉模型 - * @private - */ - async callClaudeAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint) { - // 使用Claude API - const apiEndpoint = endpoint || 'https://api.anthropic.com/v1/messages'; - - // 构建消息内容 - const messageContent = [{ type: 'text', text: prompt }]; - - // 如果有base64图片,添加图片内容 - if (base64Image) { - messageContent.push({ - type: 'image', - source: { - type: 'base64', - media_type: 'image/png', - data: base64Image - } - }); - } - - const requestData = { - model, - system: rolePrompt, - max_tokens: maxTokens, - messages: [ - { - role: 'user', - content: messageContent - } - ] - }; - - const response = await this.makeHttpRequest(apiEndpoint, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'x-api-key': this.apiKey, - 'anthropic-version': '2023-06-01' - }, - body: JSON.stringify(requestData) - }); - - if (response.error) { - throw new Error(`Claude API调用失败: ${response.error.message || JSON.stringify(response.error)}`); - } - - return response.content[0].text; - } - - /** - * 通过API调用Gemini视觉模型 - * @private - */ - async callGeminiAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint) { - // 使用Google Gemini API - const apiEndpoint = endpoint || `https://generativelanguage.googleapis.com/v1/models/${model}:generateContent`; - - // 构建消息部分 - const parts = [ - { text: `${rolePrompt}\n${prompt}` } // 合并系统提示和用户提示 - ]; - - // 如果有base64图片,添加图片内容 - if (base64Image) { - parts.push({ - inline_data: { - mime_type: 'image/png', // 可以根据实际情况调整MIME类型 - data: base64Image - } - }); - } - - const requestData = { - contents: [{ - parts: parts - }], - generation_config: { - max_output_tokens: maxTokens - } - }; - - // Gemini API使用URL参数传递API密钥 - const fullUrl = `${apiEndpoint}?key=${this.apiKey}`; - - const response = await this.makeHttpRequest(fullUrl, { - method: 'POST', - headers: { - 'Content-Type': 'application/json' - }, - body: JSON.stringify(requestData) - }); - - if (response.error) { - throw new Error(`Gemini API调用失败: ${response.error.message || JSON.stringify(response.error)}`); - } - - return response.candidates[0].content.parts[0].text; - } - - /** - * 通过API调用豆包视觉模型 - * @private - */ - async callDoubaoAPI(model, rolePrompt, prompt, base64Image, maxTokens, endpoint) { - // 使用豆包API - const apiEndpoint = endpoint || 'https://ark.cn-beijing.volces.com/api/v3'; - - // 构建用户消息内容 - const userContent = [{ type: 'text', text: prompt }]; - - // 如果有base64图片,添加图片内容 - if (base64Image) { - userContent.push({ - type: 'image_url', - image_url: { - url: `data:image/png;base64,${base64Image}` - } - }); - } - - const requestData = { - model, - messages: [ - { - role: 'system', - content: rolePrompt - }, - { - role: 'user', - content: userContent - } - ], - max_tokens: maxTokens // 添加max_tokens参数 - }; - - const response = await this.makeHttpRequest(endpoint.endsWith('/chat/completions') ? apiEndpoint : `${apiEndpoint}/chat/completions`, { - method: 'POST', - headers: { - 'Content-Type': 'application/json', - 'Content-Length': Buffer.byteLength(JSON.stringify(requestData)), - 'Authorization': `Bearer ${this.apiKey}` - }, - body: JSON.stringify(requestData) - }); - - if (response.error) { - throw new Error(`豆包API调用失败: ${response.error.message || JSON.stringify(response.error)}`); - } - - return response.choices[0].message.content; - } - - /** - * 通用HTTP请求方法 - * @param {string} url API端点URL - * @param {Object} options 请求选项 - * @returns {Promise} API响应对象 - * @private - */ - makeHttpRequest(url, options) { - return new Promise((resolve, reject) => { - const urlObj = new URL(url); - const client = urlObj.protocol === 'https:' ? https : http; - const requestOptions = { - method: options.method || 'GET', - headers: options.headers || {}, - hostname: urlObj.hostname, - port: urlObj.port || (urlObj.protocol === 'https:' ? 443 : 80), - path: urlObj.pathname + urlObj.search - }; - const req = client.request(requestOptions, (res) => { - let data = ''; - res.on('data', (chunk) => { - data += chunk; - }); - - res.on('end', () => { - try { - if (res.statusCode >= 200 && res.statusCode < 300) { - const parsedData = JSON.parse(data); - resolve(parsedData); - } else { - reject(new Error(`请求失败,状态码: ${res.statusCode}, 响应: ${data}`)); - } - } catch (e) { - reject(new Error(`API响应解析失败: ${e.message}, 原始响应: ${data}`)); - } - }); - }); - - req.on('error', (error) => { - reject(new Error(`请求失败: ${error.message}`)); - }); - - if (options.body) { - req.write(options.body); - } - - req.end(); - }); - } - - /** - * 获取支持的模型列表 - * @returns {Array} 支持的模型列表 - */ - getSupportedModels() { - return [ - // OpenAI视觉模型 - 'gpt-4-vision-preview', - 'gpt-4o', - // Claude视觉模型 - 'claude-3-opus-20240229', - 'claude-3-sonnet-20240229', - // Gemini模型 - 'gemini-pro-vision', - // 豆包模型 - 'doubao-1.5-vision-pro-32k-250115' - ]; - } -} - -export default ModelClient; diff --git a/src/pdfParser.js b/src/pdfParser.js deleted file mode 100644 index 5c5cf9b..0000000 --- a/src/pdfParser.js +++ /dev/null @@ -1,177 +0,0 @@ -/** - * PDF解析模块,负责从PDF文件中提取文本和图像信息 - */ -import pkg from 'pdfjs-dist/legacy/build/pdf.js'; -const { getDocument, OPS } = pkg; -import { createRect } from './utils.js'; -import { mergeRects, adsorbRectsToRects, filterSmallRects } from './rectProcessor.js'; -import fs from 'fs-extra'; -import path from 'path'; - -/** - * 解析PDF页面,识别区域 - * @param {Object} page PDF.js页面对象 - * @returns {Array} 识别出的区域坐标数组 [[x0, y0, x1, y1], ...] - */ -export const parseRects = async (page) => { - console.log('\n开始解析页面区域...'); - // 获取页面尺寸 - const viewport = page.getViewport({ scale: 1.0 }); - console.log(`页面尺寸: ${viewport.width} x ${viewport.height}`); - - // 提取文本内容 - const textContent = await page.getTextContent(); - - // 创建文本区域的矩形列表 - const textRects = textContent.items.map(item => { - const { str, transform } = item; - // 获取文本项的位置和尺寸 - const x = transform[4]; - const y = transform[5]; - const width = item.width || 0; - const height = item.height || 12; // 默认高度 - - // 创建文本区域矩形 - return { - rect: createRect([x, viewport.height - y - height, x + width, viewport.height - y]), - text: str, - isLarge: str.length / Math.max(1, str.split('\n').length) > 5 // 判断是否为大文本块 - }; - }); - - // 分离大文本和小文本区域 - const largeTextRects = textRects.filter(item => item.isLarge).map(item => item.rect); - const smallTextRects = textRects.filter(item => !item.isLarge).map(item => item.rect); - console.log(`创建了 ${textRects.length} 个文本区域,其中大文本 ${largeTextRects.length} 个,小文本 ${smallTextRects.length} 个`); - - // 获取操作列表,找出图像和绘图元素 - const operatorList = await page.getOperatorList(); - console.log(`提取到 ${operatorList.fnArray.length} 个操作`); - - // 提取图像和绘图元素 - const drawingRects = []; - const imageRects = []; - - for (let i = 0; i < operatorList.fnArray.length; i++) { - const fn = operatorList.fnArray[i]; - const args = operatorList.argsArray[i]; - - // 处理绘图操作 - if (fn === OPS.stroke || fn === OPS.fill) { - // 简化处理:假设前面有一个矩形路径定义 - if (i > 0 && operatorList.fnArray[i - 1] === OPS.constructPath) { - const pathArgs = operatorList.argsArray[i - 1]; - // 简化:仅处理第一个矩形 - if (pathArgs.length >= 2 && pathArgs[0].length >= 4) { - const coords = pathArgs[0].slice(0, 4); - // 创建矩形,简化处理 - const rect = createRect([ - coords[0], - viewport.height - coords[1], - coords[2], - viewport.height - coords[3] - ]); - - // 忽略小的水平线 - const bbox = rect.bbox; - const isShortLine = Math.abs(bbox[3] - bbox[1]) < 1 && Math.abs(bbox[2] - bbox[0]) < 30; - - if (!isShortLine) { - drawingRects.push(rect); - } - } - } - } - - // 处理图像操作 - if (fn === OPS.paintImageXObject) { - // 简化:假设前面有setTransform操作 - if (i > 0 && operatorList.fnArray[i - 1] === OPS.setTransform) { - const transform = operatorList.argsArray[i - 1]; - // 简化:根据变换矩阵创建近似的矩形 - const x = transform[4]; - const y = transform[5]; - const width = transform[0] * 100; // 简化估计 - const height = transform[3] * 100; // 简化估计 - - const rect = createRect([ - x, - viewport.height - y - height, - x + width, - viewport.height - y - ]); - - imageRects.push(rect); - } - } - } - - // 合并所有矩形 - let allRects = [...drawingRects, ...imageRects, ...largeTextRects, ...smallTextRects]; - console.log(`提取到 ${drawingRects.length} 个绘图区域、${imageRects.length} 个图像区域、${largeTextRects.length} 个大文本区域和 ${smallTextRects.length} 个小文本区域`); - - // 合并相近的矩形 - 增加合并阈值以确保文本不被截断 - let mergedRects = mergeRects(allRects, 25, 150); // 将距离阈值从10增加到25,高度阈值从100增加到150 - console.log(`合并后有 ${mergedRects.length} 个区域`); - - // 如果有绘图或图像区域,才进行吸附 - let updatedMergedRects = mergedRects; - if (drawingRects.length > 0 || imageRects.length > 0) { - // 将大文本区域吸附到合并后的矩形 - let [_, temp] = adsorbRectsToRects(largeTextRects, mergedRects, 0.1); - updatedMergedRects = temp; - - // 将小文本区域吸附到更新后的矩形 - [_, updatedMergedRects] = adsorbRectsToRects(smallTextRects, updatedMergedRects, 5); - } - - // 再次合并相近的矩形 - mergedRects = mergeRects(updatedMergedRects, 10); - - // 过滤掉太小的矩形 - 减小过滤阈值以保留更多区域 - mergedRects = filterSmallRects(mergedRects, 15, 10); // 降低尺寸阈值,从20x20高度改为15x10 - console.log(`过滤小矩形后剩下 ${mergedRects.length} 个区域`); - - // 将矩形转换为坐标数组 - const result = mergedRects.map(rect => { - const bbox = rect.bbox; - return [bbox[0], bbox[1], bbox[2], bbox[3]]; - }); - - console.log(`最终返回 ${result.length} 个区域`); - return result; -}; - -/** - * 从PDF文件解析出所有页面的区域 - * @param {string} pdfPath PDF文件路径 - * @returns {Array} 每个页面的区域信息 [{ pageIndex, rects: [[x0, y0, x1, y1], ...] }, ...] - */ -export const parsePdfRects = async (pdfPath) => { - // 加载PDF文档 - const data = new Uint8Array(await fs.readFile(pdfPath)); - const pdf = await getDocument({ data }).promise; - - const pageCount = pdf.numPages; - const results = []; - - // 处理每一页 - for (let i = 1; i <= pageCount; i++) { - const page = await pdf.getPage(i); - const rects = await parseRects(page); - - results.push({ - pageIndex: i - 1, - rects - }); - - console.log(`处理页面 ${i}/${pageCount},找到 ${rects.length} 个区域`); - } - - return results; -}; - -export default { - parseRects, - parsePdfRects -}; diff --git a/src/rectProcessor.js b/src/rectProcessor.js deleted file mode 100644 index c85600c..0000000 --- a/src/rectProcessor.js +++ /dev/null @@ -1,137 +0,0 @@ -/** - * 矩形区域处理模块,用于合并和处理PDF中的矩形区域 - */ -import * as turf from '@turf/turf'; -import { isNear, isHorizontalNear, unionRects, createRect, isValidRect } from './utils.js'; - -/** - * 合并矩形列表中相近的矩形 - * @param {Array} rectList 矩形列表 - * @param {number} distance 合并距离阈值 - * @param {number|null} horizontalDistance 水平合并距离阈值 - * @returns {Array} 合并后的矩形列表 - */ -export const mergeRects = (rectList, distance = 20, horizontalDistance = null) => { - try { - // 防止空列表 - if (!rectList || !Array.isArray(rectList) || rectList.length === 0) { - return []; - } - - // 预处理:过滤无效矩形 - let validRects = rectList.filter(rect => rect && isValidRect(rect)); - if (validRects.length === 0) { - return []; - } - - // 复制数组,避免修改原数组 - let workingRects = [...validRects]; - let merged = true; - - while (merged && workingRects.length > 0) { - merged = false; - const newRectList = []; - - while (workingRects.length > 0) { - let rect = workingRects.shift(); - if (!rect) continue; // 跳过空值 - - for (let i = 0; i < workingRects.length; i++) { - const otherRect = workingRects[i]; - if (!otherRect) continue; // 跳过空值 - - if (isNear(rect, otherRect, distance) || - (horizontalDistance && isHorizontalNear(rect, otherRect, horizontalDistance))) { - // 合并矩形 - const mergedRect = unionRects(rect, otherRect); - if (mergedRect) { - rect = mergedRect; - // 从列表中移除已合并的矩形 - workingRects.splice(i, 1); - i--; // 调整索引 - merged = true; - } - } - } - - if (rect) { - newRectList.push(rect); - } - } - - workingRects = newRectList; - } - - // 过滤无效的矩形 - return workingRects.filter(rect => rect && isValidRect(rect)); - } catch (error) { - console.error('合并矩形时出错:', error.message); - return []; - } -}; - -/** - * 将源矩形列表吸附到目标矩形列表 - * @param {Array} sourceRects 源矩形列表 - * @param {Array} targetRects 目标矩形列表 - * @param {number} distance 吸附距离阈值 - * @returns {Array} [未吸附的源矩形列表, 更新后的目标矩形列表] - */ -export const adsorbRectsToRects = (sourceRects, targetRects, distance = 10) => { - const newSourceRects = []; - const updatedTargetRects = [...targetRects]; - - for (const rect of sourceRects) { - let adsorbed = false; - - for (let i = 0; i < updatedTargetRects.length; i++) { - if (isNear(rect, updatedTargetRects[i], distance)) { - // 合并矩形 - updatedTargetRects[i] = unionRects(rect, updatedTargetRects[i]); - adsorbed = true; - break; - } - } - - if (!adsorbed) { - newSourceRects.push(rect); - } - } - - return [newSourceRects, updatedTargetRects]; -}; - -/** - * 将几何对象数组转换为矩形的坐标数组 - * @param {Array} rects 几何对象数组 - * @returns {Array} 矩形坐标数组 [[x0, y0, x1, y1], ...] - */ -export const rectsToCoordinates = (rects) => { - return rects.map(rect => { - const bbox = turf.bbox(rect); - return [bbox[0], bbox[1], bbox[2], bbox[3]]; - }); -}; - -/** - * 过滤掉太小的矩形 - * @param {Array} rects 矩形列表 - * @param {number} minWidth 最小宽度 - * @param {number} minHeight 最小高度 - * @returns {Array} 过滤后的矩形列表 - */ -export const filterSmallRects = (rects, minWidth = 20, minHeight = 20) => { - return rects.filter(rect => { - const bbox = turf.bbox(rect); - const width = bbox[2] - bbox[0]; - const height = bbox[3] - bbox[1]; - return width > minWidth && height > minHeight; - }); -}; - -export default { - mergeRects, - adsorbRectsToRects, - rectsToCoordinates, - filterSmallRects -}; diff --git a/src/utils.js b/src/utils.js deleted file mode 100644 index 745c72a..0000000 --- a/src/utils.js +++ /dev/null @@ -1,301 +0,0 @@ -/** - * 工具函数模块,提供常用的辅助功能 - */ -import fs from 'fs-extra'; -import path from 'path'; -import * as turf from '@turf/turf'; - -/** - * 确保目录存在,不存在则创建 - * @param {string} directory 目录路径 - */ -export const ensureDir = async (directory) => { - await fs.ensureDir(directory); -}; - -/** - * 创建矩形几何对象 - * @param {Array} bounds [x0, y0, x1, y1] 表示矩形的左上和右下坐标 - * @returns {Object} turf几何对象 - */ -export const createRect = (bounds) => { - const [x0, y0, x1, y1] = bounds; - // 创建一个矩形几何对象 - return turf.bboxPolygon([x0, y0, x1, y1]); -}; - -/** - * 计算两个矩形之间的距离 - * @param {Object} rect1 第一个矩形 - * @param {Object} rect2 第二个矩形 - * @param {number} buffer 缓冲区大小 - * @returns {number} 距离 - */ -export const getDistance = (rect1, rect2, buffer = 0.1) => { - // 直接使用几何计算来获取距离 - const bbox1 = turf.bbox(rect1); - const bbox2 = turf.bbox(rect2); - - // 计算矩形之间的距离 - // 如果矩形重叠,返回0 - if (bbox1[0] <= bbox2[2] && bbox2[0] <= bbox1[2] && bbox1[1] <= bbox2[3] && bbox2[1] <= bbox1[3]) { - return 0; - } - - // 计算水平和垂直方向的距离 - let dx = 0; - let dy = 0; - - if (bbox1[2] < bbox2[0]) { - dx = bbox2[0] - bbox1[2]; // rect1在rect2的左边 - } else if (bbox2[2] < bbox1[0]) { - dx = bbox1[0] - bbox2[2]; // rect1在rect2的右边 - } - - if (bbox1[3] < bbox2[1]) { - dy = bbox2[1] - bbox1[3]; // rect1在rect2的上边 - } else if (bbox2[3] < bbox1[1]) { - dy = bbox1[1] - bbox2[3]; // rect1在rect2的下边 - } - - // 计算欧几里得距离 - return Math.sqrt(dx * dx + dy * dy) - buffer * 2; -}; - -/** - * 检查两个矩形是否足够接近 - * @param {Object} rect1 第一个矩形 - * @param {Object} rect2 第二个矩形 - * @param {number} distance 距离阈值 - * @returns {boolean} 是否接近 - */ -export const isNear = (rect1, rect2, distance = 20) => { - try { - // 检查矩形是否有效 - if (!rect1 || !rect2) return false; - - // 计算距离 - const dist = getDistance(rect1, rect2); - - // 返回是否小于阈值 - return dist < distance; - } catch (error) { - console.error('检查矩形接近性时出错:', error.message); - return false; - } -}; - -/** - * 检查两个矩形是否在水平方向上接近 - * @param {Object} rect1 第一个矩形 - * @param {Object} rect2 第二个矩形 - * @param {number} distance 距离阈值 - * @returns {boolean} 是否水平接近 - */ -export const isHorizontalNear = (rect1, rect2, distance = 100) => { - try { - // 检查矩形是否有效 - if (!rect1 || !rect2) return false; - - const bbox1 = turf.bbox(rect1); - const bbox2 = turf.bbox(rect2); - - // 获取矩形的高度和宽度 - const height1 = bbox1[3] - bbox1[1]; - const height2 = bbox2[3] - bbox2[1]; - const width1 = bbox1[2] - bbox1[0]; - const width2 = bbox2[2] - bbox2[0]; - - // 判断是否为水平线(高度很小,宽度较大) - const isHorizontalLine1 = height1 < 2 && width1 > 10; - const isHorizontalLine2 = height2 < 2 && width2 > 10; - - // 如果两个矩形都是水平线 - if (isHorizontalLine1 && isHorizontalLine2) { - // 检查水平方向上是否重叠或接近 - const horizontalOverlap = ( - (bbox1[0] <= bbox2[2] && bbox2[0] <= bbox1[2]) || // x方向重叠 - Math.abs(bbox1[0] - bbox2[0]) < 5 || // 左边界接近 - Math.abs(bbox1[2] - bbox2[2]) < 5 // 右边界接近 - ); - - // 如果水平方向重叠或接近,检查垂直距离 - if (horizontalOverlap) { - const verticalDistance = Math.min( - Math.abs(bbox1[1] - bbox2[3]), - Math.abs(bbox1[3] - bbox2[1]) - ); - return verticalDistance < distance; - } - } - - return false; - } catch (error) { - console.error('检查水平接近性时出错:', error.message); - return false; - } -}; - -/** - * 合并两个矩形 - * @param {Object} rect1 第一个矩形 - * @param {Object} rect2 第二个矩形 - * @returns {Object} 合并后的矩形 - */ -export const unionRects = (rect1, rect2) => { - try { - // 检查矩形是否有效 - if (!rect1 && !rect2) return null; - if (!rect1) return rect2; - if (!rect2) return rect1; - - // 获取边界框 - const bbox1 = turf.bbox(rect1); - const bbox2 = turf.bbox(rect2); - - // 创建一个包含两个矩形的最小矩形 - const minX = Math.min(bbox1[0], bbox2[0]); - const minY = Math.min(bbox1[1], bbox2[1]); - const maxX = Math.max(bbox1[2], bbox2[2]); - const maxY = Math.max(bbox1[3], bbox2[3]); - - // 创建新的矩形 - return turf.bboxPolygon([minX, minY, maxX, maxY]); - } catch (error) { - console.error('合并矩形时出错:', error.message); - return null; - } -}; - -/** - * 生成随机文件名 - * @param {string} prefix 前缀 - * @param {string} extension 文件扩展名 - * @returns {string} 随机文件名 - */ -export const generateRandomFileName = (prefix = 'img', extension = 'png') => { - return `${prefix}_${Date.now()}_${Math.floor(Math.random() * 10000)}.${extension}`; -}; - -/** - * 删除文件 - * @param {string} filePath 文件路径 - */ -export const removeFile = async (filePath) => { - try { - await fs.remove(filePath); - } catch (error) { - console.error(`删除文件 ${filePath} 失败:`, error); - } -}; - -/** - * 判断矩形是否有效 - * @param {Object} rect 矩形对象 - * @returns {boolean} 是否有效 - */ -export const isValidRect = (rect) => { - try { - // 检查是否为空 - if (!rect) return false; - - // 检查是否有效的几何对象 - if (!rect.type || !rect.geometry) { - // 如果不是GeoJSON对象,尝试获取其边界框 - const bbox = turf.bbox(rect); - // 检查边界框是否有效 - return bbox && bbox.length === 4 && - bbox[0] <= bbox[2] && bbox[1] <= bbox[3] && // 确保坐标正确 - (bbox[2] - bbox[0]) > 0 && (bbox[3] - bbox[1]) > 0; // 确保矩形有面积 - } - - return true; - } catch (error) { - console.error('检查矩形有效性时出错:', error.message); - return false; - } -}; - -// 从 LLM 输出中提取标题 -export const extractMdFromLLMOutput = (output) => { - const mdStart = output.indexOf('```markdown'); - const mdEnd = output.lastIndexOf('```'); - if (mdStart !== -1 && mdEnd !== -1) { - const mdString = output.substring(mdStart + 12, mdEnd) - return mdString; - } else { - console.error('模型未按标准格式输出:', output); - return undefined; - } -} - -//获取优化前的 markdwon 标题 -export const getOldMarkdownHeadings = (markdownText) => { - const title = []; - const lines = markdownText.split('\n'); - lines.forEach((line) => { - // 匹配 # 开头,并捕获后面的内容 - const match = line.match(/^#+\s*(.*)/); - if (match) { - title.push(line); - } - }) - return title.join('\n');; -} - -//根据新生成的标题结构,重新设置原文章中标题级别 -export const adjustMarkdownHeadings = (markdownText, newTitle) => { - const map = createTitleLevelMap(newTitle); - const lines = markdownText.split('\n'); - const processedLines = []; - lines.forEach((line) => { - // 匹配 # 开头,并捕获后面的内容 - const match = line.match(/^#+\s*(.*)/); - if (!match) { - processedLines.push(line); - return; - } - const content = match ? match[1] : line; - // 检查 content 是否在 map 中存在 - let newLine = line; - if (map.has(content)) { - const level = map.get(content); - // 生成对应数量的 #(例如 level=2 -> "##") - const hashes = '#'.repeat(level); - newLine = `${hashes} ${content}`; - console.log("转换前:" + line + "===>转换后" + newLine); - } - processedLines.push(newLine); - }); - return processedLines.join('\n'); -} - -//根据标题#数量,建立内容和数量的map映射 -function createTitleLevelMap(data, map = new Map()) { - const lines = data.split('\n'); - for (const line of lines) { - // 匹配以#开头的标题行 - const headerMatch = line.match(/^(#+)\s*(.+)/); - if (headerMatch) { - const level = headerMatch[1].length; // #号的数量 - const text = headerMatch[2].trim(); // #号后的文本内容 - map.set(text, level); - } - } - return map; -} - -export default { - ensureDir, - createRect, - getDistance, - isNear, - isHorizontalNear, - unionRects, - generateRandomFileName, - removeFile, - isValidRect, - extractMdFromLLMOutput, - adjustMarkdownHeadings, - getOldMarkdownHeadings -}; diff --git a/test/README.md b/test/README.md deleted file mode 100644 index ac76fb1..0000000 --- a/test/README.md +++ /dev/null @@ -1,59 +0,0 @@ -# 模型测试工具使用说明 - -这个测试工具用于测试不同视觉模型的处理能力,方便您对比和选择最适合PDF转Markdown任务的模型。 - -## 准备工作 - -1. 创建测试图片目录: -```bash -mkdir -p test/images -``` - -2. 将测试图片放入 `test/images` 目录中(支持PNG、JPG格式) - -3. 设置环境变量(可选): -```bash -# OpenAI API密钥 -export OPENAI_API_KEY=sk-your-key - -# Claude API密钥 -export ANTHROPIC_API_KEY=sk-ant-your-key - -# Gemini API密钥 -export GEMINI_API_KEY=your-key - -# 豆包API密钥 -export DOUBAO_API_KEY=your-key -``` - -## 运行测试 - -```bash -node test/testModel.js -``` - -## 功能说明 - -1. **选择模型**:支持多种视觉模型,包括OpenAI、Claude、Gemini和豆包 -2. **选择测试图片**:从test/images目录中选择要测试的图片 -3. **选择提示词模板**:提供多种预设的提示词模板,也可以自定义提示词 -4. **保存结果**:可以将处理结果保存到test/results目录中,方便对比不同模型的效果 - -## 支持的模型 - -- GPT-4 Vision Preview (OpenAI) -- GPT-4o (OpenAI) -- Claude 3 Opus (Anthropic) -- Claude 3 Sonnet (Anthropic) -- Gemini Pro Vision (Google) -- 豆包 1.5 Vision Pro (ByteDance) - -## 提示词模板 - -- **default**: 默认的PDF转Markdown提示词 -- **simple**: 简单描述图片内容 -- **detailed**: 详细分析图片内容,包括文本、图表、公式等 - -## 结果对比 - -测试结果会保存在 `test/results` 目录中,文件名格式为 `{模型ID}_{时间戳}.md`,方便您对比不同模型的处理效果。 diff --git a/test/images/test.png b/test/images/test.png deleted file mode 100644 index 8ed3fdf..0000000 Binary files a/test/images/test.png and /dev/null differ diff --git a/test/results/doubao-1.5-vision-pro-32k-250115_2025-03-30T03-03-21-341Z.md b/test/results/doubao-1.5-vision-pro-32k-250115_2025-03-30T03-03-21-341Z.md deleted file mode 100644 index c015eff..0000000 --- a/test/results/doubao-1.5-vision-pro-32k-250115_2025-03-30T03-03-21-341Z.md +++ /dev/null @@ -1,9 +0,0 @@ -## 二、营销危机的解决方案——故事化营销 -### 1. 为什么是故事拯救营销? -最早的人类,通过自我意识、他者意识、记忆、智慧、想象力、洞察力、关联能力和自我表达能力,将发生的现实在头脑中转化成故事来总结并与他人分享经验。 - -人类从故事中就可以汲取生活经验用于现实生活,所以人本能地就喜欢故事,这也就是为什么说故事是最适合人类心智的学习工具的原因,因此故事可以作为一个切入口成为有效的营销工具。 - -### 2. 什么是故事? -#### (1)故事的定义 -所有的故事都是叙事,但并不是所有的叙事都是故事。零部件的堆砌不是故事、公司层级制度展示不是故事、大事记不是故事、被动的流水账也不是故事。 \ No newline at end of file diff --git a/test/testFullImageGeneration.js b/test/testFullImageGeneration.js deleted file mode 100644 index c8784f0..0000000 --- a/test/testFullImageGeneration.js +++ /dev/null @@ -1,145 +0,0 @@ -/** - * 完整PDF到图像转换测试 - * 用于测试将PDF文件及其识别出的区域转换为图像 - */ -import fs from 'fs-extra'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import pkg from 'pdfjs-dist/legacy/build/pdf.js'; -const { getDocument } = pkg; -import { renderRectToImage, generateImagesFromPdf } from '../src/imageGenerator.js'; -import { parsePdfRects } from '../src/pdfParser.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 设置PDF.js的worker路径 -try { - const pdfjsWorker = path.join(__dirname, '..', 'node_modules/pdfjs-dist/legacy/build/pdf.worker.js'); - const pdfjsWorkerUrl = new URL(`file://${pdfjsWorker}`).href; - - // 全局设置worker路径 - globalThis.pdfjsWorkerSrc = pdfjsWorkerUrl; - - console.log('设置PDF.js worker路径:', pdfjsWorkerUrl); -} catch (error) { - console.warn('设置PDF.js worker路径时出错:', error.message); -} - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', '2.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output', 'full_images'), - - // 是否绘制边界框 - drawBoundingBox: true, - - // 缩放比例 - scale: 2 -}; - -/** - * 测试完整的PDF到图像转换流程 - */ -async function testFullPdfToImage() { - console.log('=== 测试完整的PDF到图像转换流程 ==='); - - try { - // 确保输出目录存在 - await fs.ensureDir(CONFIG.outputDir); - - // 检查PDF文件是否存在 - if (!await fs.pathExists(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - console.log('请将测试PDF文件放在 test/samples 目录下,并更新 CONFIG.pdfPath'); - return; - } - - console.log(`加载PDF文件: ${CONFIG.pdfPath}`); - - // 第一步:解析PDF获取所有区域 - console.log('\n步骤1: 解析PDF获取所有区域...'); - const startParseTime = Date.now(); - const pageRects = await parsePdfRects(CONFIG.pdfPath); - const endParseTime = Date.now(); - - if (!pageRects || pageRects.length === 0) { - console.log('未找到有效区域,测试结束'); - return; - } - - console.log(`解析完成,耗时: ${(endParseTime - startParseTime) / 1000}秒`); - console.log(`共 ${pageRects.length} 页`); - - // 记录矩形数量 - let totalRects = 0; - for (const { pageIndex, rects } of pageRects) { - console.log(`页面 ${pageIndex + 1}: ${rects.length} 个矩形`); - totalRects += rects.length; - } - console.log(`总计 ${totalRects} 个矩形`); - - // 第二步:生成所有区域的图像 - console.log('\n步骤2: 生成所有区域的图像...'); - const startGenTime = Date.now(); - const imageInfos = await generateImagesFromPdf( - CONFIG.pdfPath, - pageRects, - CONFIG.outputDir, - CONFIG.drawBoundingBox, - CONFIG.scale - ); - const endGenTime = Date.now(); - - console.log(`图像生成完成,耗时: ${(endGenTime - startGenTime) / 1000}秒`); - - // 输出图像生成结果 - console.log(`\n生成了 ${imageInfos.length} 页的图像:`); - - let totalImages = 0; - for (let i = 0; i < imageInfos.length; i++) { - const { pageImage, rectImages } = imageInfos[i]; - console.log(`页面 ${i + 1}:`); - - // 输出页面图像路径 - console.log(` 页面图像: ${pageImage}`); - - // 输出区域图像路径 - console.log(` 区域图像 (${rectImages.length} 个):`); - for (let j = 0; j < rectImages.length; j++) { - console.log(` - ${rectImages[j]}`); - } - - totalImages += rectImages.length + 1; // +1 是页面图像 - } - - console.log(`\n总共生成了 ${totalImages} 张图像,包括 ${imageInfos.length} 张完整页面图像和 ${totalImages - imageInfos.length} 张区域图像`); - console.log(`所有图像已保存到: ${CONFIG.outputDir}`); - - } catch (error) { - console.error('测试过程中发生错误:', error); - } - - console.log(''); -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试完整的PDF到图像转换...\n'); - - // 测试完整流程 - await testFullPdfToImage(); - - console.log('PDF到图像转换测试完成'); -} - -// 运行测试 -main().catch(error => { - console.error('测试过程中发生错误:', error); -}); diff --git a/test/testFullPageImages.js b/test/testFullPageImages.js deleted file mode 100644 index e8d98f0..0000000 --- a/test/testFullPageImages.js +++ /dev/null @@ -1,88 +0,0 @@ -/** - * 测试直接生成整页PDF图像功能 - * 不使用区域识别,简化处理流程 - */ - -import fs from 'fs-extra'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { generateFullPageImages } from '../src/imageGenerator.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', '2.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output', 'full_pages'), - - // 缩放比例 - scale: 3 -}; - -/** - * 测试整页PDF图像生成 - */ -async function testFullPageImageGeneration() { - console.log('=== 测试整页PDF图像生成 ==='); - - try { - // 确保输出目录存在 - await fs.ensureDir(CONFIG.outputDir); - - // 检查PDF文件是否存在 - if (!await fs.pathExists(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - return; - } - - console.log(`加载PDF文件: ${CONFIG.pdfPath}`); - - // 开始时间 - const startTime = Date.now(); - - // 执行转换 - const imageFiles = await generateFullPageImages( - CONFIG.pdfPath, - CONFIG.outputDir, - CONFIG.scale - ); - - // 结束时间 - const endTime = Date.now(); - - // 输出结果 - console.log(`\n转换完成,耗时: ${(endTime - startTime) / 1000}秒`); - console.log(`生成了 ${imageFiles.length} 个页面图像:`); - - for (const file of imageFiles) { - console.log(`- ${file}`); - } - - console.log(`\n所有图像已保存到: ${CONFIG.outputDir}`); - - } catch (error) { - console.error('测试过程中发生错误:', error); - } -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试整页PDF图像生成...\n'); - - // 测试整页图像生成 - await testFullPageImageGeneration(); - - console.log('整页PDF图像生成测试完成'); -} - -// 执行测试 -main().catch(error => { - console.error('执行测试时发生错误:', error); -}); diff --git a/test/testFullProcess.js b/test/testFullProcess.js deleted file mode 100644 index 5e3dfae..0000000 --- a/test/testFullProcess.js +++ /dev/null @@ -1,132 +0,0 @@ -/** - * 完整流程测试 - * 用于测试PDF转Markdown的整个流程 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { parsePdf } from '../src/index.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 定义进度状态 -const progressState = { current: 0, total: 0, taskStatus: "pending" }; - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', '2.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output'), - - // API密钥 (从环境变量获取或手动设置) - apiKey: process.env.DOUBAO_API_KEY || '', - - // 模型配置 - model: 'doubao-1.5-vision-pro-32k-250115', - endpoint: 'https://ark.cn-beijing.volces.com/api/v3/', - - // 使用全页模式 - useFullPage: true, - - // 是否保留中间生成的图像文件 - verbose: true, - - // 并发处理数量 - concurrency: 5 -}; - -/** - * 测试完整的PDF转Markdown流程 - */ -async function testFullProcess() { - console.log('=== 测试完整的PDF转Markdown流程 ==='); - - try { - // 确保输出目录存在 - if (!fs.existsSync(CONFIG.outputDir)) { - fs.mkdirSync(CONFIG.outputDir, { recursive: true }); - } - - // 检查PDF文件是否存在 - if (!fs.existsSync(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - console.log('请将测试PDF文件放在 test/samples 目录下,并更新 CONFIG.pdfPath'); - return; - } - - console.log(`处理PDF文件: ${CONFIG.pdfPath}`); - console.log(`使用模型: ${CONFIG.model}`); - - // 开始处理 - const startTime = Date.now(); - - let parseResult = null; - - parsePdf(CONFIG.pdfPath, { - outputDir: CONFIG.outputDir, - apiKey: CONFIG.apiKey, - baseUrl: CONFIG.endpoint, - model: CONFIG.model, - verbose: CONFIG.verbose, - gptWorker: CONFIG.concurrency, - useFullPage: CONFIG.useFullPage, // 添加useFullPage参数 - concurrency: CONFIG.concurrency, - //增加处理进度结果回调 - onProgress: ({ current, total, taskStatus }) => { - progressState.current = current; - progressState.total = total; - progressState.taskStatus = taskStatus; - } - }).then(result => { - parseResult = result; - }); - - // 如果需要主动查询 - await new Promise((resolve) => { - const interval = setInterval(() => { - console.log(`[主动查询] 进度: ${progressState.current}/${progressState.total},${progressState.taskStatus}`); - if (progressState.taskStatus === "finished") { - clearInterval(interval); - resolve(); - } - }, 1000); - }); - - const endTime = Date.now(); - - console.log(`\n处理完成,耗时: ${(endTime - startTime) / 1000}秒`); - console.log(`生成的Markdown文件: ${parseResult.mdFilePath}`); - console.log(`生成的图像文件数量: ${parseResult.imageFiles.length}`); - - // 显示Markdown内容预览 - const mdContent = fs.readFileSync(parseResult.mdFilePath, 'utf-8'); - const previewLength = Math.min(500, mdContent.length); - - console.log('\nMarkdown内容预览:'); - console.log('-----------------------------------'); - console.log(mdContent.substring(0, previewLength) + (mdContent.length > previewLength ? '...' : '')); - console.log('-----------------------------------'); - - } catch (error) { - console.error('处理PDF时发生错误:', error); - } -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试完整流程...\n'); - - // 测试完整流程 - await testFullProcess(); - - console.log('\n完整流程测试完成'); -} - -// 运行测试 -main(); diff --git a/test/testImageGenerator.js b/test/testImageGenerator.js deleted file mode 100644 index b1bdfab..0000000 --- a/test/testImageGenerator.js +++ /dev/null @@ -1,103 +0,0 @@ -/** - * 图像生成模块测试 - * 用于测试PDF区域转图像功能 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { getDocument } from 'pdfjs-dist/legacy/build/pdf.js'; -import { renderRectToImage } from '../src/imageGenerator.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 设置PDF.js的worker路径 -try { - // 3.x 版本的设置方式 - const pdfjsWorker = path.join(__dirname, '..', 'node_modules/pdfjs-dist/legacy/build/pdf.worker.js'); - const pdfjsWorkerUrl = new URL(`file://${pdfjsWorker}`).href; - - // 全局设置worker路径 - globalThis.pdfjsWorkerSrc = pdfjsWorkerUrl; - - console.log('设置PDF.js worker路径:', pdfjsWorkerUrl); -} catch (error) { - console.warn('设置PDF.js worker路径时出错:', error.message); -} - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', 'sample.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output'), - - // 测试区域 [x0, y0, x1, y1] - testRect: [100, 100, 300, 200] -}; - -/** - * 测试渲染PDF区域为图像 - */ -async function testRenderRectToImage() { - console.log('=== 测试渲染PDF区域为图像 ==='); - - try { - // 确保输出目录存在 - if (!fs.existsSync(CONFIG.outputDir)) { - fs.mkdirSync(CONFIG.outputDir, { recursive: true }); - } - - // 检查PDF文件是否存在 - if (!fs.existsSync(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - console.log('请将测试PDF文件放在 test/samples 目录下,并更新 CONFIG.pdfPath'); - return; - } - - console.log(`加载PDF文件: ${CONFIG.pdfPath}`); - - // 加载PDF文档 - const data = new Uint8Array(fs.readFileSync(CONFIG.pdfPath)); - const pdfDocument = await getDocument({ data }).promise; - - console.log(`PDF加载成功,共 ${pdfDocument.numPages} 页`); - - // 获取第一页 - const page = await pdfDocument.getPage(1); - - console.log(`渲染区域: [${CONFIG.testRect.join(', ')}]`); - - // 渲染区域为图像 - const imageBuffer = await renderRectToImage(page, CONFIG.testRect, 2); - - // 保存图像 - const outputPath = path.join(CONFIG.outputDir, 'test_rect.png'); - fs.writeFileSync(outputPath, imageBuffer); - - console.log(`图像已保存到: ${outputPath}`); - console.log(`图像大小: ${(imageBuffer.length / 1024).toFixed(2)} KB`); - - } catch (error) { - console.error('渲染区域为图像时发生错误:', error); - } - - console.log(''); -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试图像生成模块...\n'); - - // 测试渲染区域为图像 - await testRenderRectToImage(); - - console.log('图像生成模块测试完成'); -} - -// 运行测试 -main(); diff --git a/test/testModel.js b/test/testModel.js deleted file mode 100644 index a53c5f8..0000000 --- a/test/testModel.js +++ /dev/null @@ -1,109 +0,0 @@ -/** - * 简化版模型测试工具 - * 用于测试不同视觉模型的处理能力 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import ModelClient from '../src/modelClient.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 测试配置 -const CONFIG = { - // 要测试的模型 - model: 'doubao-1.5-vision-pro-32k-250115', // 可选: gpt-4-vision-preview, gpt-4o, claude-3-opus-20240229, gemini-pro-vision - - // API密钥 (也可以从环境变量中获取) - apiKey: process.env.DOUBAO_API_KEY || '', - - // 自定义API端点 (可选) - endpoint: 'https://ark.cn-beijing.volces.com/api/v3/', - - // 测试图片路径 - imagePath: path.join(__dirname, 'images', 'test.png'), - - // 提示词 - prompt: `使用markdown语法,将图片中识别到的文字转换为markdown格式输出。你必须做到: -1. 输出和使用识别到的图片的相同的语言,例如,识别到英语的字段,输出的内容必须是英语。 -2. 不要解释和输出无关的文字,直接输出图片中的内容。 -3. 内容不要包含在\`\`\`markdown \`\`\`中、段落公式使用 $$ $$ 的形式、行内公式使用 $ $ 的形式。`, - - // 是否保存结果到文件 - saveResult: true, - - // 结果保存目录 - resultsDir: path.join(__dirname, 'results') -}; - -/** - * 保存结果到文件 - * @param {string} result 处理结果 - * @param {string} modelId 模型ID - */ -async function saveResult(result, modelId) { - // 确保结果目录存在 - if (!fs.existsSync(CONFIG.resultsDir)) { - fs.mkdirSync(CONFIG.resultsDir, { recursive: true }); - } - - const timestamp = new Date().toISOString().replace(/[:.]/g, '-'); - const filename = `${modelId}_${timestamp}.md`; - const filePath = path.join(CONFIG.resultsDir, filename); - - fs.writeFileSync(filePath, result); - console.log(`\n结果已保存到: ${filePath}`); -} - -/** - * 主函数 - */ -async function main() { - try { - console.log('=== 视觉模型测试工具 (简化版) ===\n'); - - // 确保测试图片存在 - if (!fs.existsSync(CONFIG.imagePath)) { - console.error(`错误: 测试图片不存在: ${CONFIG.imagePath}`); - console.log('请将测试图片放在 test/images 目录下,并更新 CONFIG.imagePath'); - return; - } - - console.log(`测试模型: ${CONFIG.model}`); - console.log(`测试图片: ${path.basename(CONFIG.imagePath)}`); - - // 创建模型客户端 - const modelClient = new ModelClient({ - apiKey: CONFIG.apiKey, - model: CONFIG.model, - endpoint: CONFIG.endpoint - }); - - console.log('\n开始处理图像...'); - - // 处理图像 - const startTime = Date.now(); - const result = await modelClient.processImage(CONFIG.imagePath, CONFIG.prompt, { - model: CONFIG.model, - endpoint: CONFIG.endpoint - }); - const endTime = Date.now(); - - console.log(`\n处理完成,耗时: ${(endTime - startTime) / 1000}秒`); - console.log('\n=== 处理结果 ===\n'); - console.log(result); - - // 保存结果 - if (CONFIG.saveResult) { - await saveResult(result, CONFIG.model); - } - - } catch (error) { - console.error('发生错误:', error); - } -} - -// 运行主函数 -main(); \ No newline at end of file diff --git a/test/testPdfParser.js b/test/testPdfParser.js deleted file mode 100644 index 729ebfd..0000000 --- a/test/testPdfParser.js +++ /dev/null @@ -1,113 +0,0 @@ -/** - * PDF解析模块测试 - * 用于测试PDF文件解析和区域识别功能 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import pkg from 'pdfjs-dist/legacy/build/pdf.js'; -const { getDocument } = pkg; -import { parseRects, parsePdfRects } from '../src/pdfParser.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 设置PDF.js的worker路径 -try { - const pdfjsWorker = path.join(__dirname, '..', 'node_modules/pdfjs-dist/legacy/build/pdf.worker.js'); - const pdfjsWorkerUrl = new URL(`file://${pdfjsWorker}`).href; - - // 全局设置worker路径 - globalThis.pdfjsWorkerSrc = pdfjsWorkerUrl; - - console.log('设置PDF.js worker路径:', pdfjsWorkerUrl); -} catch (error) { - console.warn('设置PDF.js worker路径时出错:', error.message); -} - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', '1.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output') -}; - -/** - * 测试PDF区域识别功能 - */ -async function testParseRects() { - console.log('=== 测试PDF区域识别功能 ==='); - - try { - // 确保输出目录存在 - if (!fs.existsSync(CONFIG.outputDir)) { - fs.mkdirSync(CONFIG.outputDir, { recursive: true }); - } - - // 检查PDF文件是否存在 - if (!fs.existsSync(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - console.log('请将测试PDF文件放在 test/samples 目录下,并更新 CONFIG.pdfPath'); - return; - } - - console.log(`加载PDF文件: ${CONFIG.pdfPath}`); - - // 加载PDF文档 - const data = new Uint8Array(fs.readFileSync(CONFIG.pdfPath)); - const pdf = await getDocument({ data }).promise; - - console.log(`PDF加载成功,共 ${pdf.numPages} 页`); - - // 处理每一页 - for (let i = 1; i <= Math.min(pdf.numPages, 3); i++) { - console.log(`\n处理第 ${i} 页...`); - - // 获取页面 - const page = await pdf.getPage(i); - - // 解析区域 - const startTime = Date.now(); - const rects = await parseRects(page); - const endTime = Date.now(); - - console.log(`识别出 ${rects.length} 个区域,耗时: ${(endTime - startTime) / 1000}秒`); - - // 输出前5个区域的坐标 - if (rects.length > 0) { - console.log('前5个区域的坐标:'); - rects.slice(0, 5).forEach((rect, index) => { - console.log(` 区域 ${index + 1}: [${rect.map(v => v.toFixed(2)).join(', ')}]`); - }); - } - - // 保存区域信息到JSON文件 - const outputPath = path.join(CONFIG.outputDir, `page_${i}_rects.json`); - fs.writeFileSync(outputPath, JSON.stringify(rects, null, 2)); - console.log(`区域信息已保存到: ${outputPath}`); - } - - } catch (error) { - console.error('解析PDF区域时发生错误:', error); - } - - console.log(''); -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试PDF解析模块...\n'); - - // 测试PDF区域识别 - await testParseRects(); - - console.log('PDF解析模块测试完成'); -} - -// 运行测试 -main(); diff --git a/test/testRectProcessor.js b/test/testRectProcessor.js deleted file mode 100644 index 34e893a..0000000 --- a/test/testRectProcessor.js +++ /dev/null @@ -1,119 +0,0 @@ -/** - * 矩形处理模块测试 - * 用于测试矩形合并、吸附等功能 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import * as turf from '@turf/turf'; -import { mergeRects, adsorbRectsToRects, filterSmallRects } from '../src/rectProcessor.js'; -import { createRect } from '../src/utils.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 测试数据 -const TEST_RECTS = [ - // 两个相近的矩形 - createRect([10, 10, 30, 20]), - createRect([32, 12, 50, 22]), - - // 两个远离的矩形 - createRect([100, 100, 120, 120]), - createRect([200, 200, 220, 220]), - - // 一个水平线 - createRect([10, 50, 100, 51]), - - // 一个小矩形 - createRect([300, 300, 305, 305]) -]; - -/** - * 测试矩形合并功能 - */ -function testMergeRects() { - console.log('=== 测试矩形合并功能 ==='); - - // 测试1: 合并相近的矩形 - const mergedRects1 = mergeRects(TEST_RECTS.slice(0, 2), 5); - console.log(`合并相近矩形 (距离=5): 期望合并成1个,实际合并成 ${mergedRects1.length} 个`); - - // 测试2: 不合并远离的矩形 - const mergedRects2 = mergeRects(TEST_RECTS.slice(2, 4), 5); - console.log(`合并远离矩形 (距离=5): 期望保持2个,实际合并成 ${mergedRects2.length} 个`); - - // 测试3: 水平线合并 - const horizontalTestRects = [ - createRect([10, 50, 100, 51]), - createRect([10, 80, 100, 81]) - ]; - const mergedRects3 = mergeRects(horizontalTestRects, 5, 50); - console.log(`水平线合并 (水平距离=50): 期望合并成1个,实际合并成 ${mergedRects3.length} 个`); - - console.log(''); -} - -/** - * 测试矩形吸附功能 - */ -function testAdsorbRects() { - console.log('=== 测试矩形吸附功能 ==='); - - // 源矩形 - const sourceRects = [ - createRect([15, 15, 25, 25]), - createRect([150, 150, 160, 160]) - ]; - - // 目标矩形 - const targetRects = [ - createRect([10, 10, 30, 30]), - createRect([200, 200, 220, 220]) - ]; - - // 测试吸附 - const [remainingSourceRects, updatedTargetRects] = adsorbRectsToRects(sourceRects, targetRects, 10); - - console.log(`吸附前: 源矩形=${sourceRects.length}个, 目标矩形=${targetRects.length}个`); - console.log(`吸附后: 未吸附源矩形=${remainingSourceRects.length}个, 更新后目标矩形=${updatedTargetRects.length}个`); - - console.log(''); -} - -/** - * 测试小矩形过滤功能 - */ -function testFilterSmallRects() { - console.log('=== 测试小矩形过滤功能 ==='); - - // 测试过滤 - const filteredRects = filterSmallRects(TEST_RECTS, 10, 10); - - console.log(`过滤前矩形数量: ${TEST_RECTS.length}`); - console.log(`过滤后矩形数量: ${filteredRects.length}`); - - console.log(''); -} - -/** - * 主函数 - */ -function main() { - console.log('开始测试矩形处理模块...\n'); - - // 测试矩形合并 - testMergeRects(); - - // 测试矩形吸附 - testAdsorbRects(); - - // 测试小矩形过滤 - testFilterSmallRects(); - - console.log('矩形处理模块测试完成'); -} - -// 运行测试 -main(); diff --git a/test/testSimpleFullProcess.js b/test/testSimpleFullProcess.js deleted file mode 100644 index acf8a4a..0000000 --- a/test/testSimpleFullProcess.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * 简化版完整流程测试 - * 使用整页图像功能,直接处理PDF页面 - */ -import fs from 'fs'; -import path from 'path'; -import { fileURLToPath } from 'url'; -import { generateFullPageImages } from '../src/imageGenerator.js'; -import { processImage } from '../src/modelClient.js'; -import { generateMarkdown } from '../src/markdownConverter.js'; - -// 获取当前文件的目录 -const __filename = fileURLToPath(import.meta.url); -const __dirname = path.dirname(__filename); - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', 'sample.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output'), - - // 图像输出目录 - imageOutputDir: path.join(__dirname, 'output', 'pages'), - - // API密钥 (从环境变量获取或手动设置) - apiKey: process.env.DOUBAO_API_KEY || 'your-api-key-here', - - // 模型配置 - model: 'doubao-1.5-vision-pro-32k-250115', - endpoint: 'https://ark.cn-beijing.volces.com/api/v3/', - - // 是否保留中间生成的图像文件 - verbose: true, - - // 缩放比例 - scale: 3 -}; - -/** - * 简化版PDF转Markdown流程 - */ -async function simpleFullProcess() { - console.log('=== 测试简化版PDF转Markdown流程 ==='); - - try { - // 确保输出目录存在 - if (!fs.existsSync(CONFIG.outputDir)) { - fs.mkdirSync(CONFIG.outputDir, { recursive: true }); - } - - if (!fs.existsSync(CONFIG.imageOutputDir)) { - fs.mkdirSync(CONFIG.imageOutputDir, { recursive: true }); - } - - // 检查PDF文件是否存在 - if (!fs.existsSync(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - console.log('请将测试PDF文件放在 test/samples 目录下,并更新 CONFIG.pdfPath'); - return; - } - - console.log(`处理PDF文件: ${CONFIG.pdfPath}`); - console.log(`使用模型: ${CONFIG.model}`); - - // 步骤1: 生成整页图像 - console.log('\n步骤1: 生成整页图像...'); - const startImageTime = Date.now(); - const imageFiles = await generateFullPageImages( - CONFIG.pdfPath, - CONFIG.imageOutputDir, - CONFIG.scale - ); - const endImageTime = Date.now(); - console.log(`生成整页图像完成,耗时: ${(endImageTime - startImageTime) / 1000}秒`); - console.log(`共生成 ${imageFiles.length} 张页面图像`); - - // 步骤2: 处理每个页面图像 - console.log('\n步骤2: 使用视觉模型处理图像...'); - const startProcessTime = Date.now(); - - const pageContents = []; - for (let i = 0; i < imageFiles.length; i++) { - const imagePath = imageFiles[i]; - console.log(`处理图像 ${i + 1}/${imageFiles.length}: ${path.basename(imagePath)}`); - - // 读取图像文件 - const imageData = fs.readFileSync(imagePath); - const base64Image = imageData.toString('base64'); - - // 调用模型处理图像 - const pageContent = await processImage( - base64Image, - CONFIG.model, - CONFIG.apiKey, - CONFIG.endpoint - ); - - // 添加页面内容 - pageContents.push({ - pageIndex: i, - content: pageContent - }); - } - - const endProcessTime = Date.now(); - console.log(`图像处理完成,耗时: ${(endProcessTime - startProcessTime) / 1000}秒`); - - // 步骤3: 生成Markdown文档 - console.log('\n步骤3: 生成Markdown文档...'); - const startMdTime = Date.now(); - - // 生成Markdown文件名 - const pdfBaseName = path.basename(CONFIG.pdfPath, '.pdf'); - const mdFilePath = path.join(CONFIG.outputDir, `${pdfBaseName}_simple.md`); - - // 生成Markdown内容 - const mdContent = generateMarkdown(pageContents); - - // 保存Markdown文件 - fs.writeFileSync(mdFilePath, mdContent, 'utf-8'); - - const endMdTime = Date.now(); - console.log(`Markdown生成完成,耗时: ${(endMdTime - startMdTime) / 1000}秒`); - - // 计算总耗时 - const totalTime = (endMdTime - startImageTime) / 1000; - - console.log(`\n处理完成,总耗时: ${totalTime}秒`); - console.log(`生成的Markdown文件: ${mdFilePath}`); - console.log(`生成的图像文件数量: ${imageFiles.length}`); - - // 显示Markdown内容预览 - const previewLength = Math.min(500, mdContent.length); - - console.log('\nMarkdown内容预览:'); - console.log('-----------------------------------'); - console.log(mdContent.substring(0, previewLength) + (mdContent.length > previewLength ? '...' : '')); - console.log('-----------------------------------'); - - return { - mdFilePath, - imageFiles - }; - - } catch (error) { - console.error('处理PDF时发生错误:', error); - } -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试简化版完整流程...\n'); - - // 测试简化版完整流程 - await simpleFullProcess(); - - console.log('\n简化版完整流程测试完成'); -} - -// 运行测试 -main(); diff --git a/test/testSimpleImageGeneration.js b/test/testSimpleImageGeneration.js deleted file mode 100644 index 44b135c..0000000 --- a/test/testSimpleImageGeneration.js +++ /dev/null @@ -1,156 +0,0 @@ -/** - * 简化版PDF到图像转换测试 - * 这个版本只生成完整页面图像,不再分割为子图 - */ - -const fs = require('fs-extra'); -const path = require('path'); -const { createCanvas } = require('canvas'); -const sharp = require('sharp'); -const pdfjsLib = require('pdfjs-dist/legacy/build/pdf.js'); - -// 设置PDF.js的worker路径 -try { - const pdfjsWorker = path.join(__dirname, '..', 'node_modules/pdfjs-dist/legacy/build/pdf.worker.js'); - const pdfjsWorkerUrl = new URL(`file://${pdfjsWorker}`).href; - - // 全局设置worker路径 - globalThis.pdfjsWorkerSrc = pdfjsWorkerUrl; - - console.log('设置PDF.js worker路径:', pdfjsWorkerUrl); -} catch (error) { - console.warn('设置PDF.js worker路径时出错:', error.message); -} - -// 测试配置 -const CONFIG = { - // 测试PDF文件路径 - pdfPath: path.join(__dirname, 'samples', '1.pdf'), - - // 输出目录 - outputDir: path.join(__dirname, 'output', 'simple_images'), - - // 缩放比例 - 可以调整以获得更高清晰度的图像 - scale: 3 -}; - -/** - * 简化版PDF到图像转换函数 - 每页生成一个完整图像 - * @param {Buffer} pdfData PDF文件数据 - * @param {string} outputDir 输出目录 - * @param {number} scale 缩放比例 - * @returns {Promise>} 生成的图像文件路径数组 - */ -async function generateImagesFromPdf(pdfData, outputDir, scale = 3) { - // 确保输出目录存在 - await fs.ensureDir(outputDir); - - // 加载PDF文档 - const pdfDocument = await pdfjsLib.getDocument({ data: pdfData }).promise; - const numPages = pdfDocument.numPages; - console.log(`PDF文档共 ${numPages} 页`); - - // 存储生成的图像路径 - const pageImages = []; - - // 处理每一页 - for (let i = 0; i < numPages; i++) { - const pageIndex = i + 1; - console.log(`处理第 ${pageIndex} 页...`); - - // 获取页面 - const page = await pdfDocument.getPage(pageIndex); - const viewport = page.getViewport({ scale }); - - // 创建canvas - const canvas = createCanvas(viewport.width, viewport.height); - const context = canvas.getContext('2d'); - - // 填充白色背景 - context.fillStyle = '#ffffff'; - context.fillRect(0, 0, viewport.width, viewport.height); - - // 渲染页面 - await page.render({ - canvasContext: context, - viewport: viewport - }).promise; - - // 保存为图像 - const imageName = `page_${pageIndex}.png`; - const imagePath = path.join(outputDir, imageName); - - // 将canvas转换为图像并保存 - const buffer = await sharp(canvas.toBuffer('image/png')).png().toBuffer(); - await fs.writeFile(imagePath, buffer); - - // 添加到结果数组 - pageImages.push(imagePath); - - console.log(`页面 ${pageIndex} 已保存到: ${imagePath}`); - } - - return pageImages; -} - -/** - * 测试简化版PDF到图像转换 - */ -async function testSimplePdfToImage() { - console.log('=== 测试简化版PDF到图像转换 ==='); - - try { - // 确保输出目录存在 - await fs.ensureDir(CONFIG.outputDir); - - // 检查PDF文件是否存在 - if (!await fs.pathExists(CONFIG.pdfPath)) { - console.error(`错误: 测试PDF文件不存在: ${CONFIG.pdfPath}`); - return; - } - - console.log(`加载PDF文件: ${CONFIG.pdfPath}`); - - // 读取PDF文件 - const pdfData = await fs.readFile(CONFIG.pdfPath); - - // 开始时间 - const startTime = Date.now(); - - // 执行转换 - const imageFiles = await generateImagesFromPdf(pdfData, CONFIG.outputDir, CONFIG.scale); - - // 结束时间 - const endTime = Date.now(); - - // 输出结果 - console.log(`\n转换完成,耗时: ${(endTime - startTime) / 1000}秒`); - console.log(`生成了 ${imageFiles.length} 个页面图像:`); - - for (const file of imageFiles) { - console.log(`- ${file}`); - } - - console.log(`\n所有图像已保存到: ${CONFIG.outputDir}`); - - } catch (error) { - console.error('测试过程中发生错误:', error); - } -} - -/** - * 主函数 - */ -async function main() { - console.log('开始测试简化版PDF到图像转换...\n'); - - // 测试简化流程 - await testSimplePdfToImage(); - - console.log('简化版PDF到图像转换测试完成'); -} - -// 执行测试 -main().catch(error => { - console.error('执行测试时发生错误:', error); -});