package com.engine.recruit.service.impl; import com.alibaba.fastjson.JSONArray; import com.alibaba.fastjson.JSONObject; import com.engine.core.exception.ECException; import com.engine.core.impl.Service; import com.engine.recruit.exception.CustomizeRunTimeException; import com.engine.recruit.service.ResumeRecognitionService; import com.engine.resumestorage.util.HttpUtils; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; import org.apache.commons.lang3.StringUtils; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.ContentType; import org.apache.http.entity.mime.MultipartEntityBuilder; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.util.EntityUtils; import weaver.file.ImageFileManager; import weaver.formmode.recruit.modeexpand.util.RecruitModeUtil; import weaver.general.BaseBean; import weaver.general.Util; import java.io.File; import java.math.BigInteger; import java.security.MessageDigest; import java.security.NoSuchAlgorithmException; import java.text.DateFormat; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; /** * @author:dxfeng * @createTime: 2023/12/12 * @version: 1.0 */ public class ResumeRecognitionServiceImpl extends Service implements ResumeRecognitionService { /** * 简历识别类型 */ private static final String OCR_TYPE = RecruitModeUtil.getRecruitPropValue("OCR_TYPE"); @Override public Map resumeUpload(Map param) { Map returnMap = new HashMap<>(); returnMap.put("isOcr", true); if (StringUtils.isBlank(OCR_TYPE)) { returnMap.put("isOcr", false); return returnMap; } String resumeId = Util.null2String(param.get("resumeId")); if (StringUtils.isBlank(resumeId)) { throw new CustomizeRunTimeException("原始简历文件获取失败"); } // 调用千里聆服务 if ("1".equals(OCR_TYPE)) { qllResumeUpload(Integer.parseInt(resumeId), returnMap); } // 调用阿里云服务 if ("2".equals(OCR_TYPE)) { alyResumeUpload(Integer.parseInt(resumeId), returnMap); } return returnMap; } /** * @param resumeId 简历ID * @param returnMap 响应集合 */ private void qllResumeUpload(int resumeId, Map returnMap) { String response = doQllPost(resumeId); if (StringUtils.isBlank(response)) { throw new CustomizeRunTimeException("千里聆接口调用失败,响应结果为空"); } JSONObject all = JSONObject.parseObject(response); if (!all.getBoolean("isSuccess")) { throw new CustomizeRunTimeException("千里聆接口调用失败,接口不通"); } JSONObject resultall = all.getJSONObject("data"); String status = resultall.getString("state"); if ("fail".equals(status)) { throw new CustomizeRunTimeException("调用千里聆接口失败,失败原因:" + resultall.getString("info")); } JSONObject result = resultall.getJSONObject("result"); Map dataMap = parseQllJsonToMap(result); returnMap.put("data", dataMap); } /** * @param resumeId 简历ID * @param returnMap 响应集合 */ private void alyResumeUpload(int resumeId, Map returnMap) { String response = doAlyPost(resumeId); JSONObject all = JSONObject.parseObject(response); String error_msg = all.getString("error_msg"); if (!"成功".equals(error_msg)) { throw new CustomizeRunTimeException("阿里云简历识别失败"); } Map saveResume = new HashMap<>(); JSONObject cv_parse = all.getJSONObject("data").getJSONObject("cv_parse"); saveResume.putAll(buildBasicInfo(cv_parse.getJSONObject("basic_info"))); saveResume.putAll(buildEducations(this.getJsonArrayFirstIfPresent(cv_parse.getJSONArray("educations")))); saveResume.putAll(buildContact(cv_parse.getJSONObject("contact"))); saveResume.putAll(buildJobObjective(cv_parse.getJSONObject("job_objective"))); saveResume.putAll(buildOccupations(this.getJsonArrayFirstIfPresent(cv_parse.getJSONArray("occupations")))); returnMap.put("data", saveResume); } private Map parseQllJsonToMap(JSONObject obj) { Map dataMap = new HashMap<>(); // 姓名 String xm = parseArray(obj.getJSONArray("姓名")); dataMap.put("xm", parseInputObject(xm)); // 电子邮箱 String dzyx = parseArray(obj.getJSONArray("电子邮箱")); dataMap.put("dzyx", parseInputObject(dzyx)); // 手机号码 String sjhm = parseArray(obj.getJSONArray("手机号")); dataMap.put("sjhm", parseInputObject(sjhm)); // 年龄 String nl = parseArray(obj.getJSONArray("年龄")); dataMap.put("nl", parseInputObject(nl)); // 出生日期 String csrq = parseArray(obj.getJSONArray("出生日期")); dataMap.put("csrq", parseDateObject(csrq)); // 民族 // 性别 String xb = "男".equals(parseArray(obj.getJSONArray("性别"))) ? "0" : "1"; dataMap.put("xb", parseValueObject(xb)); // 体重(KG) // 身高(CM) // 籍贯 dataMap.put("jg", parseArray(obj.getJSONArray("籍贯"))); // 婚姻状况 // 当前所在地 dataMap.put("jzd", parseArray(obj.getJSONArray("现居住地"))); // 政治面貌 // 在职状态 // 工作经验 dataMap.put("gzjy", parseArray(obj.getJSONArray("工作经验"))); // 最高学位 dataMap.put("zgxw", parseArray(obj.getJSONArray("最高学位"))); // 最高学历 dataMap.put("zgxlwb", parseArray(obj.getJSONArray("最高学历"))); // 专业 String zy = parseArray(obj.getJSONArray("专业")); dataMap.put("zy", parseInputObject(zy)); // 毕业院校 String byyx = parseArray(obj.getJSONArray("毕业院校")); dataMap.put("byyx", parseInputObject(byyx)); // 期望税前月薪(K) String qwxz = parseArray(obj.getJSONArray("期望薪资")); dataMap.put("qwxz", parseInputObject(qwxz)); // 现税前月薪(K) // 自我评价 String zwpj = parseArray(obj.getJSONArray("个人评价")); dataMap.put("zwpj", parseInputObject(zwpj)); // 明细表数据 // 教育经历 // 工作经历 // 项目经验 // 语言能力 // TODO // 当前所在地 // TODO dataMap.put("mz", parseArray(obj.getJSONArray("民族"))); dataMap.put("wx", parseArray(obj.getJSONArray("微信"))); dataMap.put("qq", parseArray(obj.getJSONArray("QQ"))); dataMap.put("ah", parseArray(obj.getJSONArray("爱好"))); dataMap.put("bysj", parseArray(obj.getJSONArray("毕业时间"))); dataMap.put("zyjn", parseArray(obj.getJSONArray("专业技能"))); dataMap.put("sxjl", parseArray(obj.getJSONArray("实习经历"))); dataMap.put("yysp", parseArray(obj.getJSONArray("英语水平"))); dataMap.put("jnzs", parseArray(obj.getJSONArray("技能证书"))); dataMap.put("xyjl", parseArray(obj.getJSONArray("校园经历"))); dataMap.put("gzxg", parseArray(obj.getJSONArray("工作信息"))); dataMap.put("qwcsgw", parseArray(obj.getJSONArray("期望从事岗位"))); dataMap.put("qwgzdd", parseArray(obj.getJSONArray("期望工作地点"))); dataMap.put("xmjl", parseArray(obj.getJSONArray("项目经历"))); dataMap.put("xyxg", parseArray(obj.getJSONArray("学业信息"))); return dataMap; } private Map buildBasicInfo(JSONObject basicInfo) { Map basic = new HashMap(); if (basicInfo.containsKey("name")) { String jzd; basic.put("xm", Util.null2String(basicInfo.getString("name"))); basic.put("nl", Util.null2String(basicInfo.getInteger("age"))); if ("男".equals(Util.null2String(basicInfo.getString("gender")))) { basic.put("xb", "0"); } else if ("女".equals(Util.null2String(basicInfo.getString("gender")))) { basic.put("xb", "1"); } jzd = basicInfo.getJSONObject("location").getString("province") + basicInfo.getJSONObject("location").getString("city"); basic.put("jzd", Util.null2String(jzd)); } return basic; } private Map buildEducations(JSONObject educations) { Map major = new HashMap<>(); if (educations != null) { if (educations.containsKey("major")) { major.put("sxzy", Util.null2String(educations.getString("major"))); } } return major; } private Map buildContact(JSONObject contact) { Map mobile = new HashMap(); if (contact.containsKey("mobile")) { mobile.put("wx", Util.null2String(contact.getString("mobile"))); mobile.put("sjhm", Util.null2String(contact.getString("mobile"))); mobile.put("qq", Util.null2String(contact.getString("qq"))); mobile.put("email", Util.null2String(contact.getString("email"))); } return mobile; } private Map buildJobObjective(JSONObject job_objective) { Map expect_salary = new HashMap(); if (job_objective != null) { if (job_objective.containsKey("expect_salary")) { expect_salary.put("qwxz", Util.null2String(job_objective.getString("expect_salary"))); } } return expect_salary; } private Map buildOccupations(JSONObject occupations) { Map company = new HashMap(); if (occupations != null) { if (occupations.containsKey("company")) { company.put("gs", Util.null2String(occupations.getString("expect_salary"))); } } return company; } private JSONObject getJsonArrayFirstIfPresent(JSONArray jsonArray) { return jsonArray.size() > 0 ? jsonArray.getJSONObject(0) : null; } /** * @param resumeId * @return */ private String doQllPost(int resumeId) { BaseBean bean = new BaseBean(); String url = bean.getPropValue("resume_qianliling", "qianlilingurl"); String appId = bean.getPropValue("resume_qianliling", "appId"); String appSecret = bean.getPropValue("resume_qianliling", "appSecret"); long currentTime = System.currentTimeMillis(); ImageFileManager manager = new ImageFileManager(); manager.getImageFileInfoById(resumeId); HttpPost postRequest = new HttpPost(url); postRequest.addHeader("sign", getSign(appId, appSecret, currentTime)); postRequest.addHeader("appId", appId); postRequest.addHeader("timestamp", String.valueOf(currentTime)); MultipartEntityBuilder builder = MultipartEntityBuilder.create(); // TODO builder.addTextBody("type", "pdf"); builder.addBinaryBody("resume", manager.getInputStream(), ContentType.APPLICATION_OCTET_STREAM, manager.getImageFileName()); HttpEntity entity = builder.build(); postRequest.setEntity(entity); try { CloseableHttpClient httpClient = HttpClients.createDefault(); CloseableHttpResponse response = httpClient.execute(postRequest); HttpEntity responseEntity = response.getEntity(); return EntityUtils.toString(responseEntity); } catch (Exception e) { throw new RuntimeException(e); } } /** * @param resumeId * @return */ private String doAlyPost(int resumeId) { try { BaseBean bean = new BaseBean(); String PARSE_HOST = bean.getPropValue("youyun", "host"); String PATH = bean.getPropValue("youyun", "path"); String METHOD = bean.getPropValue("youyun", "method"); String APPCODE = bean.getPropValue("youyun", "appcode"); ImageFileManager manager = new ImageFileManager(); manager.getImageFileInfoById(resumeId); String filePath = manager.getFileRealPath(); File file = new File(filePath); Map headers = new HashMap<>(); headers.put("Authorization", "APPCODE " + APPCODE); headers.put("Content-Type", "application/x-www-form-urlencoded; charset=UTF-8"); Map queryMap = new HashMap<>(); Map bodyMap = new HashMap<>(); byte[] bytes = FileUtils.readFileToByteArray(file); String base64 = Base64.encodeBase64String(bytes); bodyMap.put("content", base64); bodyMap.put("ext", "doc"); HttpResponse response = HttpUtils.doPost(PARSE_HOST, PATH, METHOD, headers, queryMap, bodyMap); return EntityUtils.toString(response.getEntity()); } catch (Exception var10) { throw new ECException("简历解析失败!详情:" + var10.getMessage()); } } /** * 千里聆签名 * * @param appId 开发者AppId * @param appSecret 开发者appSecret * @param timestamp 当前时间戳(毫秒数) * @return */ private static String getSign(String appId, String appSecret, long timestamp) { if (appId != null && appId.length() != 0) { if (appSecret != null && appSecret.length() != 0) { try { MessageDigest md5 = MessageDigest.getInstance("MD5"); md5.update(appId.getBytes()); md5.update((timestamp + "").getBytes()); md5.update(appSecret.getBytes()); byte[] bytes = md5.digest(); return (new BigInteger(1, bytes)).toString(16); } catch (NoSuchAlgorithmException var8) { throw new CustomizeRunTimeException("不支持的加密算法", var8); } } else { throw new CustomizeRunTimeException("appSecret不能为空"); } } else { throw new CustomizeRunTimeException("appId不能为空"); } } /** * 文本转换 * * @param ar * @return */ private String parseArray(JSONArray ar) { StringBuilder rs = new StringBuilder(); if (ar != null && ar.size() > 0) { for (int i = 0; i < ar.size(); ++i) { if (i == ar.size() - 1) { rs.append(ar.get(i)); } else { rs.append(ar.get(i)).append(","); } } } return rs.toString(); } /** * 转换文本对象 * * @param value * @return */ private String parseInputObject(String value) { return value; // return "{value: \"" + value + "\",showhtml: \"" + value + "\"}"; } private String parseValueObject(String value) { return value; // return "{value: \"" + value + "\"}"; } /** * 转换日期对象 * * @param value * @return */ private String parseDateObject(String value) { DateFormat sdf = new SimpleDateFormat("yyyy-MM-dd"); sdf.setLenient(false); try { sdf.parse(value); } catch (ParseException e) { value = ""; } return parseInputObject(value); } }