Files
prop-ai-hr/docs/API_INTEGRATION.md
T

21 KiB
Raw Blame History

后端 API 对接指南

前端四条演示流和演示预检已经稳定。后端 API 按页面逐刀接入,避免一次性铺满四个页面。

第一阶段范围

页面 后端接口 处理
AI面试 /recruit/interview POST /api/recruit/interview/start、/answer、/finish 已接入真实模型优先链路:配置 chat 模型后 /start 动态生成面试题,/finish 按前端提交的真实回答做结构化评分;未配置模型时使用本地 Rubric 估分,不返回固定候选人分数
三角色对练 /train/practice POST /api/train/practice/start、/turn、/finish 已接入编排 API;数据库启用 chat 模型后,/turn 客户回复按人设走真 LLM 生成(seed 剧本作剧情锚点),/finish 走单次 temperature=0 结构化评分(4 维分+导师改写+点评);模型未配置或调用失败自动回退 seed,契约不变
对练语音 POST /api/ai/asr(multipart 字段 file,≤5MB)、POST /api/ai/tts(JSON {text≤300字, voice},返回 {audioUrl} base64 dataURL) 走 OpenAI-compatible audio 接口(如硅基流动 SenseVoice/CosyVoice2);模型管理需启用 category=asr/tts 配置;移动端优先用浏览器录音,getUserMedia/MediaRecorder 不可用或麦克风权限失败时,用 audio/* file input 选择/录制音频后继续调同一 ASR 接口;ASR/TTS 未配置或失败返回 fail,前端降级文本
案例沉淀 /knowledge/cases POST /api/knowledge/case/upload、/organize、/curate /upload 改为 multipart 真实语音上传并走 ASR;/organize 用真实转写调 chat 模型整理案例,未配置模型时按真实 transcript 本地结构化;不再用固定样例转写冒充成功
SOP知识库 /knowledge/sop POST /api/knowledge/search、POST /api/knowledge/doc/upload 已接入 MySQL Fulltext + Qdrant 混合召回、OSS-first 文档上传、txt/md/PDF/Word/Excel/PPT 解析和 embedding 写入,失败回退 seed
资料处理 /knowledge/processing GET /api/knowledge/processing/overview、POST /api/knowledge/doc/upload-async、GET /api/knowledge/doc/upload-items、POST /api/knowledge/doc/upload-items/{id}/retry、POST /api/knowledge/doc/import-local-task、GET /api/knowledge/doc/import-tasks、POST /api/knowledge/doc/import-tasks/{id}/cancel 已接入解析任务状态聚合;批量上传走异步队列:接口只暂存+入队即秒回,后台 worker(并发 2)逐条解析/归类/向量化,页面按批次轮询进度、失败可单文件重试;服务端目录导入、进度轮询和任务取消保留,失败回退 seed
组织人员同步 POST /api/aihr/org/sync 从开放组织同步系统的 /open/v1/sync/snapshot 拉取 company/department/employee 快照,映射并刷新 aihr_org_snapshot;默认 replaceExisting=true 覆盖本租户快照,先用 {"dryRun":true} 预检;外部接口未配置时保留 SQL seed
移动端手机号登录 GET /resource/sms/code、POST /auth/mobile/sms-login 已复用 sms4j 阿里云配置 config1 和 RuoYi sms 授权策略;短信发送成功后才写 Redis 验证码;手机号不存在时自动注册 app_user;aihr.sms.dev-fixed-code 非空时不真发短信、验证码固定(dev 默认 123456,prod profile 代码级强制失效)
移动端三端首页 /h5/user、/h5/candidate、/h5/supervisor GET /api/aihr/mobile/home/{role} 已接入员工、候选人、主管首页公开只读 API;移动端本地 fallback 保演示
移动端员工训练闭环 复用 POST /api/train/practice/start、/turn、/finish;查询 GET /api/aihr/mobile/practice/history、/practice/reviews、/practice/reviews/{id}、/profile;标记 POST /api/aihr/mobile/practice/reviews/{id}/reviewed 员工端登录后带 Authorization 与 clientid 调用;mode=mobile 完成后写入 aihr_practice_session,主管端首页完训率、待复盘列表、复盘详情、员工训练历史和能力画像同步变化;复盘标记可带 incentivePoint 写入 incentive_point,用于贡献度和试点 CSV
移动端候选人闭环 面试复用 POST /api/recruit/interview/start、/answer、/finish;资料 POST /api/aihr/mobile/candidate/materials、GET /api/aihr/mobile/candidate/materials;HR 审核 GET /api/aihr/hr/candidate/materials、POST /api/aihr/hr/candidate/materials/{id}/review 候选人端登录后带 Authorization 与 clientid 调用;面试拉题/评分走真实模型优先;资料上传写 sys_oss/MinIO 和 aihr_candidate_material,HR 在 AI 面试页标记 已通过/已驳回,候选人端列表同步状态

后端落点

  • 业务模块:backend/ruoyi-modules/ruoyi-aihr
  • 注册模块:backend/ruoyi-modules/pom.xml
  • 接入启动包:backend/ruoyi-admin/pom.xml
  • 包名建议:org.dromara.aihr
  • Controller 返回统一用 org.dromara.common.core.domain.R

当前管理端 AI 面试和案例沉淀已改为真实模型/ASR 优先;移动端首页和部分演示态数据仍保留 fallback。知识库、模型能力、文档解析、RAG、chat 按 ruoyi-ai 能力分片迁移计划 逐片引入;知识库 DDL 与住宅类 SOP seed 在 backend/script/sql/aihr_knowledge_mysql8.sql,模型 DDL 在 backend/script/sql/aihr_model_mysql8.sql,训练记录 DDL 在 backend/script/sql/aihr_practice_mysql8.sql,AI 面试结果 DDL 在 backend/script/sql/aihr_interview_result_mysql8.sql,候选人资料 DDL 在 backend/script/sql/aihr_candidate_material_mysql8.sql,组织人员快照表在 backend/script/sql/aihr_org_snapshot_mysql8.sql,本地 reset 带 2 个住宅项目 22 人 seed;配置开放组织同步系统后用 POST /api/aihr/org/sync 覆盖为外部快照。

直接打后端 /api/** 通常需要登录后的 Authorization: Bearer <access_token>;浏览器内通过已登录前端和 /dev-api 代理访问。移动端登录接口为 POST /auth/mobile/sms-login,请求 { phonenumber, smsCode, tenantId },内部固定使用 app 客户端 428a8310cd442757ae699df5d894f051 和 sms grant;验证码通过后若手机号不存在,会创建 app_user,用户名为手机号,备注为“移动端短信自动注册”。移动端 MVP 首页接口 GET /api/aihr/mobile/home/{role} 目前仍是 @SaIgnore 的公开只读 seed 接口,避免 H5 首屏被后台管理登录态阻断;后续接小程序登录后再收紧为移动端 token。

阿里云短信复用 RuoYi 的 sms.blends.config1。本地开发把真实短信参数放根目录 .env.local 或外部环境变量,scripts/dev-backend.sh 会自动加载;application-dev.yml / application-prod.yml 只保留占位,不写真实密钥。

AIHR_SMS_LOGIN_TEMPLATE_ID=SMS_xxxxxx
ALIYUN_SMS_ACCESS_KEY_ID=xxx
ALIYUN_SMS_ACCESS_KEY_SECRET=xxx
ALIYUN_SMS_SIGN_NAME=物业AI助手

候选人资料上传最小后端边界:

能力 后端接口 处理
候选资料上传 POST /api/aihr/mobile/candidate/materials multipart/form-data 字段 file,参数 candidateId/candidateName/materialType;需移动端登录返回的 Authorization 与 clientid;文件用 ISysOssService 写 sys_oss/MinIO,关系写 aihr_candidate_material,状态默认 待审核,单文件 20MB
候选资料列表 GET /api/aihr/mobile/candidate/materials?candidateId= 返回前 20 条 {id, ossId, fileName, materialType, fileSize, status, time},供 /h5/candidate 的“已提交资料”展示
HR 资料审核 GET /api/aihr/hr/candidate/materials?status=、POST /api/aihr/hr/candidate/materials/{id}/review 管理端 /recruit/interview 展示前 50 条,可按状态筛选;审核请求体 {status},只接受 待审核/已通过/已驳回

SOP 文档上传第三片已经落最小后端边界:

能力 后端接口 处理
文档上传解析 POST /api/knowledge/doc/upload multipart/form-data,字段 file 和 category;支持 .txt/.md/.markdown/.pdf/.doc/.docx/.xls/.xlsx/.ppt/.pptx 及图片 .jpg/.jpeg/.png/.gif/.webp/.bmp、100MB 内;先写 sys_oss,再绑定 aihr_knowledge_attach.oss_id 并切分写入 aihr_knowledge_fragment;管理端该接口 timeout 为 180s,避免 PDF 同步解析/归类/向量化接近默认 50s 时被客户端断开
图片视觉 OCR 同一上传/导入链路 上传图片时,若启用了 aihr_model_config.category='vision'(无则回退 category='chat')的模型,会把图片编码为 base64 data URL 调用该供应商 OpenAI-compatible /chat/completions 提取文字,识别结果按普通正文切分写入 fragment;无可用视觉模型或 OCR 无结果时按「待处理」落库(attach status=0、0 片段),不算失败,启用视觉模型后重新上传同名文件即可解析。不依赖 Tesseract,识别质量由所配置视觉模型决定
智能归类与标签 同一上传/导入链路 category=__auto__ 时,解析正文后优先调用已启用的 aihr_model_config.category='chat' 模型生成分类、摘要、标签和归类理由,温度固定为 0;无模型或调用失败时按文件名/正文关键词兜底。最终分类写入 aihr_knowledge_info/attach,摘要和标签写入 sys_oss.ext1
重复资料处理 同一上传/导入链路 上传时计算原始文件 aihrFileSha256、解析文本 aihrTextSha256 和 md5 写入 sys_oss.ext1;重复判断优先按文件 SHA-256,其次按文本 SHA-256,最后用同名同大小兼容旧数据。命中重复时复用原附件并迁移到最新分类,删除其他重复附件和旧 fragment
归类稳定性 同一上传/导入链路 命中重复资料时优先复用已有 sys_oss.ext1 里的分类、摘要和标签;只有旧资料没有存过模型结果时才重新分析,避免同文件因重复上传或更换模型导致标签漂移
文档替换 同一 category + fileName 再上传 复用原 doc_id,删除旧 fragment 后重写新 fragment,避免重复文档堆积
片段向量化 同一上传接口内机会性执行 若 aihr_model_config.category='vector' 且启用,会优先调用配置供应商的 OpenAI-compatible /embeddings,把返回向量写入 aihr_knowledge_fragment.embedding_json;配置缺失或外部接口失败时使用本地确定性 local-hash-v1 兜底,保证 MVP 链路仍有真实向量数据
缺失向量补跑 POST /api/knowledge/doc/vectorize-missing 扫描缺少 embedding_json 的片段,复用同一向量化与 Qdrant 入库链路,适合模型配置变更后或历史资料补齐向量
向量库状态与重建 GET /api/knowledge/doc/vector-index-status、POST /api/knowledge/doc/rebuild-vector-index 模型配置页展示当前 vector 模型维度、Qdrant collection 维度、点数和片段向量数;维度不一致时可一键清空旧 embedding、删除 collection 并按当前模型重建
Qdrant 向量索引 同一上传接口内机会性执行 embedding 写入 MySQL 后尽力 upsert 到 Qdrant;同名文档替换会尽力删除旧 points;Qdrant 不可用不影响上传和 MySQL 检索;外部 embedding 成功但 collection 维度不一致时不静默降级为 local-hash-v1,通过状态接口和重建入口处理
混合检索 POST /api/knowledge/search 先跑中文关键词 LIKE 打分和 MySQL Fulltext,再生成 query embedding 走 Qdrant,RRF 融合后交给 category='rerank' 模型(如硅基流动 bge-reranker-v2-m3)按语义相关性重排;rerank 未配置或失败保持 RRF 顺序,Qdrant 或外部向量接口不可用时保留关键词/全文检索。命中后若 chat 模型可用,自动生成结构化轻概要写入响应 answer/keyPoints/cautions(≤60字直答+3-6要点+0-3注意;temperature=0,15s 超时,硬约束不得编造、答不了明示无依据);概要失败回退片段原文拼接,检索不报错
检索总结卡 POST /api/knowledge/summary-card(JSON {queryText, category}) 按需生成信息图式总结卡 {title, steps[], objections[], scripts[], reminders[]}:复用检索命中片段(最多5条)调 chat 模型,temperature=0、30s 超时;无命中/无 chat 模型/生成失败均抛明确错误供前端重试,不兜假数据。移动端查SOP结果页「生成总结卡」按钮触发,底部弹层展示并可 TTS 朗读
解析状态聚合 GET /api/knowledge/processing/overview 聚合 aihr_knowledge_attach.status、fragment 数、embedding 数、sys_oss.ext1.fileSize,生成资料处理页指标、分类、任务、链路和事件列表
服务端目录导入 POST /api/knowledge/doc/import-local JSON { directory, category, limit };directory 只能是 AIHR_IMPORT_ROOT / aihr.import.root 下的相对目录,默认根目录为 ./.data/import;逐文件复用上传解析链路,同步执行,保留给小批量/调试
服务端导入任务 POST /api/knowledge/doc/import-local-task、GET /api/knowledge/doc/import-tasks、POST /api/knowledge/doc/import-tasks/{id}/cancel 启动后台目录导入并返回任务;任务写入 aihr_knowledge_import_task,页面轮询查看总数、成功数、失败数、当前文件和进度;运行中任务可取消;重试当前按同目录重新启动一轮
批量异步上传 POST /api/knowledge/doc/upload-async(multipart file+category+batchId)、GET /api/knowledge/doc/upload-items?batchId=、POST /api/knowledge/doc/upload-items/{id}/retry 上传只做暂存(aihr.upload.staging,默认 ./.data/staging)+ 写入 aihr_knowledge_upload_item(0待处理/1处理中/2完成/3失败)即返回;后台 worker 并发 2 复用同一解析/归类/向量化链路,同名文件串行防撞唯一键;完成/失败状态 CAS 写入,卡住 30 分钟(视频 120 分钟)由清扫重置,失败暂存文件保留 72h 供重试;同步接口 POST /api/knowledge/doc/upload 保留给 SOP 页单文件即时预览
视频解析 走批量异步上传,支持 .mp4/.mov/.avi/.mkv/.webm/.m4v,单文件 ≤500MB、时长 ≤60 分钟 依赖服务器 ffmpeg/ffprobe;抽音轨按 5 分钟分段调 asr 模型转写([mm:ss] 时间戳),按 30s 间隔(≤40 帧)抽关键帧调 vision 模型提取画面文字(相邻重复画面去重);两类文本合并后走归类/切片/向量化;无 asr 且无 vision 结果时按「待处理」落库不报错;视频同时只加工 1 个

模型能力第二片已经落最小后端边界:

能力 后端接口 处理
模型供应商 GET /api/aihr/model/providers、POST /api/aihr/model/providers、PUT /api/aihr/model/providers/{providerCode}、PATCH /api/aihr/model/providers/{providerCode}/status 优先返回 aihr_model_provider,支持新增、编辑、启停;缺表或空表时返回 seed 清单
模型配置 GET /api/aihr/model/configs、POST /api/aihr/model/configs、PUT /api/aihr/model/configs/{id}、PATCH /api/aihr/model/configs/{id}/enabled 优先返回 aihr_model_config,支持新增、编辑、启停,并计算是否已具备 URL/Key;category 支持 chat/vector/rerank/asr/tts/vision
模型探针 POST /api/aihr/model/chat 数据库配置后走 OpenAI-compatible /chat/completions,否则 seed fallback;请求携带的模型名在库中不存在时(如前端 seed 占位行 gpt-4o-mini),自动回退到默认已启用的 chat 配置

本阶段不修改 .env,也不自动执行模型 SQL。API Key 通过模型配置页面写入数据库:api_key 可放在 aihr_model_provider 作为供应商默认值,也可放在 aihr_model_config 覆盖单个模型;接口响应只返回 configured/apiKeyConfigured,不返回密钥明文。

Qdrant 本地默认值可不配;需要覆盖时用 JVM property 或环境变量:

配置 默认值 用途
AIHR_QDRANT_URL / -Daihr.qdrant.url http://127.0.0.1:6333 Qdrant REST 地址
AIHR_QDRANT_COLLECTION / -Daihr.qdrant.collection aihr_knowledge 知识库向量 collection
AIHR_QDRANT_API_KEY / -Daihr.qdrant.apiKey 空 远端 Qdrant API Key,本地不用
AIHR_IMPORT_ROOT / -Daihr.import.root ./.data/import 服务端资料目录导入根目录

组织人员同步配置:

配置 默认值 用途
AIHR_ORG_SYNC_BASE_URL / -Daihr.org-sync.base-url 空 外部开放平台 /open/v1 前缀,例如 https://hr.example.com/open/v1
AIHR_ORG_SYNC_ACCESS_TOKEN / -Daihr.org-sync.access-token 空 已有 Bearer token;为空时尝试用 client credentials 换 token
AIHR_ORG_SYNC_CLIENT_ID / -Daihr.org-sync.client-id 空 开放平台应用 client_id,也用于签名头 X-Client-Id
AIHR_ORG_SYNC_CLIENT_SECRET / -Daihr.org-sync.client-secret 空 POST /auth/token 换取访问令牌
AIHR_ORG_SYNC_SIGNING_SECRET / -Daihr.org-sync.signing-secret 空 可选 HMAC-SHA256 签名密钥;配置后请求带 X-Timestamp/X-Nonce/X-Signature
TOKEN=<登录后 access_token>
curl -fsS http://127.0.0.1:8080/api/aihr/org/sync \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"dryRun":true}'

curl -fsS http://127.0.0.1:8080/api/aihr/org/sync \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"replaceExisting":true}'

前端落点

  • 管理端前端:frontend/,只承载后台管理、配置、审核、查看结果等页面。
  • AI 面试 API 文件:frontend/src/api/aihr/interview.ts
  • AI 面试页面:frontend/src/views/recruit/interview.vue
  • 三角色对练 API 文件:frontend/src/api/aihr/practice.ts
  • 三角色对练页面:frontend/src/views/train/practice.vue
  • 案例沉淀 API 文件:frontend/src/api/aihr/case.ts
  • 案例沉淀页面:frontend/src/views/knowledge/cases.vue
  • SOP 知识库 API 文件:frontend/src/api/aihr/sop.ts
  • SOP 知识库页面:frontend/src/views/knowledge/sop.vue
  • 资料处理 API 文件:frontend/src/api/aihr/processing.ts
  • 资料处理页面:frontend/src/views/knowledge/processing.vue
  • 模型配置 API 文件:frontend/src/api/aihr/model.ts
  • 模型配置页面:frontend/src/views/system/model/index.vue
  • 移动端独立工程:mobile/src/App.vue,路由 /h5/user、/h5/candidate、/h5/supervisor;员工端子路由为 /h5/user/training(训练列表)和 /h5/user/practice(对练页)。当前三端首页已按高保真原型实现,未登录先走手机号短信登录,登录后 API 优先请求 /api/aihr/mobile/home/{role},不复用后台页面路由。语音输入不要新增移动端专用接口,浏览器录音和文件选择兜底都复用 /api/ai/asr。
  • 员工端训练:底部“练”进入 /h5/user/training,首屏展示场景模拟、开始练习和最近练过,每日三题后置;点“开始练习”切换到 /h5/user/practice,复用管理端三角色对练 API,完成两轮后展示评分和导师改写;记录写入 aihr_practice_session,员工端展示训练历史和能力画像,主管端展示待复盘列表,点进单条可看评分、话术、导师改写,并可标记“已复盘”。
  • 候选人端:/h5/candidate 的“开始面试/面试练习”复用 AI 面试 API;“补充资料”走候选资料上传接口,成功后展示 OSS ID、资料类型和审核状态。管理端 /recruit/interview 底部展示“候选资料审核”,支持通过/驳回。
  • 演示 fallback 只作为未配置模型或外部接口异常时的降级,不作为真实测试通过证据。

验收

./scripts/demo-check.sh
npm --prefix mobile run build
curl -fsS http://127.0.0.1:8080/api/aihr/mobile/home/user
npm --prefix frontend run lint:eslint -- src/api/aihr/interview.ts src/views/recruit/interview.vue src/api/aihr/practice.ts src/views/train/practice.vue src/api/aihr/case.ts src/views/knowledge/cases.vue src/api/aihr/sop.ts src/views/knowledge/sop.vue
mvn -f backend/pom.xml -pl ruoyi-admin -am -DskipTests package

模型能力可单独 smoke:

TOKEN=<登录后 access_token>
curl -fsS http://127.0.0.1:8080/api/aihr/model/providers -H "Authorization: Bearer $TOKEN"
curl -fsS http://127.0.0.1:8080/api/aihr/model/configs -H "Authorization: Bearer $TOKEN"
curl -fsS -X POST http://127.0.0.1:8080/api/aihr/model/chat \
  -H "Authorization: Bearer $TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"prompt":"物业管家处理漏水投诉第一步是什么?"}'

Qdrant 和向量索引可单独 smoke;重建接口会清空旧 embedding 并重建 collection,只用于本地验证或确认维度不一致后的修复:

TOKEN=<登录后 access_token>
curl -fsS http://127.0.0.1:6333/
curl -fsS http://127.0.0.1:8080/api/knowledge/doc/vector-index-status -H "Authorization: Bearer $TOKEN"
curl -fsS -X POST http://127.0.0.1:8080/api/knowledge/doc/rebuild-vector-index -H "Authorization: Bearer $TOKEN"

浏览器验收仍按 DEMO_ACCEPTANCE.md 的四条关键路径执行。