# Resume Parse API 一个简单的 Node.js/Express 接口:上传简历文档(支持 `.docx` / `.pdf`),提取文本后返回结构化信息和面试评估内容。 ## 运行 1. 安装依赖 - `npm install` 2. 启动开发模式 - `npm run dev` 3. 服务启动后默认地址 - `http://localhost:3000` ## 健康检查 - `GET /health` 返回示例:`{ "ok": true, "mysql": { "ok": true, "skipped": false, "database": "Resume" } }` - 未配置 `MYSQL_HOST` 时:`mysql.skipped === true` - 连接失败时:`mysql.ok === false` 且带 `mysql.error` ## MySQL(远程库 Resume) 在 `.env` 中配置(勿提交到 Git,仓库已忽略 `.env`): - `MYSQL_HOST`:服务器 IP 或域名(必填) - `MYSQL_PORT`:默认 `3306` - `MYSQL_USER`:默认 `root`(按你服务器实际账号修改) - `MYSQL_PASSWORD` - `MYSQL_DATABASE`:默认 `Resume` 启动时会在控制台打印 `[mysql] 已连接` 或 `[mysql] 连接失败`。代码里通过 `require("./mysql").getMysqlPool()` 获取连接池。 ### 入库说明 - 连接成功后会自动维护表 **`resume_submissions`**。 - **列结构**:与解析结果对齐,**姓名、城市、年龄、期望薪资、教育经历、学历、能力、工作经历、项目经历、技术栈**各占一列(便于查询、统计、以后查重);**不再写入**整段 `extracted_text`。 - **JSON 列**:`interview_report`(AI 面试题与整块评估)、`pdf_meta`(PDF/OCR 元信息)、`warnings_json`(解析告警列表)。 - 若检测到**旧版表**(曾含 `extracted_text` 列),启动时会 **DROP 后重建**,旧数据会清空,请注意备份。 - 接口响应里仍有 **`db`**:`{ "saved": true, "id": 1 }` 等含义不变。 ## 解析接口 ### 推荐流程(前端默认) 1. **`POST /api/resume/step1`**(`multipart/form-data`,字段 `file`) - 抽取文本、计算 `file_sha256`、与库比对是否重复(同哈希且已有 `interview_report`)。 - **不调 AI**。返回 `parsedPreview`(规则)、`text`、`fileSha256`、`uploadId`(非重复时用于第二步)、`isDuplicate` 等。 2. **`POST /api/resume/consult-ai`**(`application/json`) - Body:`{ "fileSha256": "...", "uploadId": "..." }`(重复时可省略 `uploadId`)。 - 若重复:直接返回库内 `interview_report` 与列字段还原的 `parsed`,**不请求模型**。 - 若不重复:用 `uploadId` 取内存会话,调用 AI,写入 `resume_submissions`,并清除会话。 ### 兼容接口 - `POST /api/parse-word`:一步完成「抽取 + AI + 入库」(脚本或旧客户端可用)。 - 请求类型:`multipart/form-data` - 文件字段名:`file` ### curl 示例 ```bash curl -X POST "http://localhost:3000/api/parse-word" ^ -F "file=@D:\test\demo.docx" ``` ```bash curl -X POST "http://localhost:3000/api/parse-word" ^ -F "file=@D:\test\demo.pdf" ``` ### 返回 ```json { "filename": "demo.pdf", "mimeType": "application/pdf", "sourceType": "pdf", "text": "解析出的内容(纯文本)", "parsed": { "姓名": "张三" }, "interviewReport": { "interviewQuestions": [] }, "warnings": [] } ``` ## 说明 - 当前使用 `mammoth` 解析 `.docx`,使用 `pdf-parse` 解析 `.pdf`。 - **扫描版 PDF(几乎无文本层)**:当文本层有效字符数低于阈值时,可启用 OCR:使用 `pdfjs-dist` + `@napi-rs/canvas` 将页面渲染为图片,再用 `tesseract.js` 识别文字。 - **`PDF_OCR_ENABLED=1` 才会执行 OCR**(默认不开启,避免首次下载模型时请求长时间无响应)。 - `PDF_OCR_MIN_CHARS`:低于该有效字符数才尝试 OCR,默认 `80` - `PDF_OCR_MAX_PAGES`:最多 OCR 的页数,默认 `5` - `PDF_OCR_SCALE`:渲染缩放(越大越清晰但更慢),默认 `2` - `PDF_OCR_DISABLED`:设为 `1` 可强制关闭 OCR(优先级高于 `PDF_OCR_ENABLED`) - `PDF_OCR_LANG`:Tesseract 语言,默认 `chi_sim`。可设为 `eng` 或 `chi_sim+eng` 等 - `PDF_OCR_INIT_TIMEOUT_MS`:初始化 Tesseract(含首次下载)超时,默认 `120000` - `PDF_OCR_PAGE_TIMEOUT_MS`:单页识别超时,默认 `120000` - 项目将 `pdfjs-dist` 固定为 `5.4.296`,与 `pdf-parse` 内置版本一致,避免 Worker 与 API 版本不一致。 - 如果你需要支持 `.doc`(旧版 Word),告诉我你的文档来源/格式,我可以再加转换或抽取方案。