使用GPT-3和Node.js将CV转换为结构化数据
#教程 #node #gpt3 #resume

大型语言模型(例如GPT-3)对于简化常规任务很有用。例如,我们可以使用非结构化的数据,例如PDF中的工作申请人的简历,并将其转换为结构化数据,并将其填充到我们的申请人跟踪系统(ATS)(例如Greenhouse)或可行。

在本文中,我将向您展示一个node.js应用程序。但是,尽管GPT-3简化了常规数据输入作业,但作为开发人员,我们仍然需要连接所有相应的API以下载申请人的简历,从PDF获取文本,然后将数据放在ATS上。幸运的是,Superface使我们摆脱了这种常规的API接线。我们在许多API提供商中提供统一的界面。例如,从可行的人HR切换为一行更改。

让我们检查一下此应用程序执行的步骤:

  1. 加载了从申请人跟踪系统(ATS)(例如可行或温室)申请给定工作的候选人的简历。
  2. 将简历转换为文本并将文本解析为可读的数据。
  3. 使用从CV获得的数据更新ATS中的候选人。

您可以在CV Analyzer repository中找到完整的应用程序。它使用以下软件包:

  • @superfaceai/one-sdk -Superface OnesDK用于与ATS,OpenAI和CloudMersive SaaS提供商集成。
  • node-fetch -nodefetch用于获取简历文档。
  • dotenv -dotenv用于加载环境变量。
  • inquirer-询问器.js用于构建交互式用户界面。

我们还依靠Superface Catalog的这些用例:

在此演示中,我们使用Workable作为ATS,Cloudmersive将候选人的简历转换为纯文本,而OpenAI提供商将CV转换为结构化数据。但是您不仅限于这三个提供商。对于ATS用例,您还可以使用Breezy HR,Greenhouse和many others

设置应用程序

  1. 克隆应用程序存储库并输入其目录。
   git clone git@github.com:superfaceai/cv-analyzer.git
   cd cv-analyzer
  1. 安装依赖项。
   npm install
  1. 为提供者创建帐户(如果您还没有):
  1. 复制示例.env文件。
   cp .env.example .env
  1. 设置.env文件中提供商的凭据和集成参数。
  1. 创建一个工作位置并在可行的ATS中添加新候选人。

  2. 启动应用程序。

   npm start

应用程序启动后,它将向您显示候选人列表。当您选择一个时,它将通过从其CV中解析的数据更新候选人的条目。

A screenshot of a running application with selection of job position and a list of candidates for the position.

应用程序如何工作

该应用程序的主要流在src/index.js文件中,该文件调用src/use_cases.js文件中定义的用例。

选择候选人并获得其简历

首先,我们列出所选职位的开放职位和候选人。这是用List Jobs用例来处理的;一旦用户选择职位职位,我们将使用List Candidates用例与工作位置的各个ID:

exports.listCandidates = async (sdk, providerOptions, jobId) => {
  const listCandidatesProfile = await sdk.getProfile(
    'recruitment/list-candidates@1.0.0'
  );
  const listCandidatesResult = await listCandidatesProfile
    .getUseCase('ListCandidates')
    .perform(
      {
        jobId,
      },
      providerOptions
    );
  return listCandidatesResult.unwrap().candidates;
};

我们使用选定候选人的ID,并使用Get CV用例使用候选人的简历获取文档的URL(通常是PDF,但ATS也可以接受其他格式):

exports.getCVUrl = async (sdk, providerOptions, candidateId) => {
  const getCVProfile = await sdk.getProfile('recruitment/get-cv@1.0.0');
  const getCVResult = await getCVProfile.getUseCase('GetCV').perform(
    {
      candidateId,
    },
    providerOptions
  );
  return getCVResult.unwrap().cv.documentUrl;
};

将简历转换为文本

现在,我们知道候选人的简历可以下载哪里,但是我们需要以某种方式从中提取文本。我们使用Convert Document to Text用例来获取文档并将其上传到转换提供商(在此示例中cloudMersive)并获取纯文本以返回。

exports.convertCVToText = async (sdk, providerOptions, cvDocumentUrl) => {
  const docToTextProfile = await sdk.getProfile(
    'file-conversion/doc-to-text@1.0.0'
  );

  const fetchDocumentResponse = await fetch(cvDocumentUrl);

  if (!fetchDocumentResponse.body) {
    console.error('Failed to fetch CV document.');
    return;
  }

  const result = await docToTextProfile
    .getUseCase('ConvertDocumentToText')
    .perform(
      {
        fileName: 'cv.pdf',
        content: BinaryData.fromStream(fetchDocumentResponse.body),
      },
      providerOptions
    );

  return result.unwrap().text;
};

提取结构化数据

现在是时候采用AI魔术了!我们通过Text Completion用例使用OpenAI的GPT-3模型。我们为模型提供了一个提示,解释了我们需要返回的特定数据作为JSON:

exports.analyzeCV = async (sdk, providerOptions, cvText) => {
  try {
    const generateTextProfile = await sdk.getProfile('ai/generate-text@1.0.0');

    const promptCommand = `Parse following job applicant resume and return json object with properties 
    { 
      "firstName", "lastName", "address", "phone", 
      "education":
      [{"school", "fieldOfStudy", "studiedFrom_ISO8601":"YYYY-MM-DD", "studiedTill_ISO8601":"YYYY-MM-DD"}],
    "workHistory":
      [{"company", "position", "summary", "workedFrom_ISO8601:"YYYY-MM-DD"", "workedTill_ISO8601":"YYYY-MM-DD"}]
    }. `;

    const result = await generateTextProfile.getUseCase('CompleteText').perform(
      {
        prompt: promptCommand + cvText,
        creativity: 0.8,
        approxMaxWords: 1000,
        model: 'large',
      },
      providerOptions
    );

    analyzeCVOutcome = result.unwrap();
  } catch (error) {
    console.error('Failed to analyze CV.', error);
  }
  // ...
};

如果分析顺利进行,并且模型完成了我们的提示,我们将返回的完成将其转换为JSON:

const parsedCV = JSON.parse(analyzeCVOutcome.completions[0]);
const mappedCV = {
  ...parsedCV,
  education: parsedCV.education?.map(school => {
    return {
      school: school.school,
      degree: school.degree,
      fieldOfStudy: school.fieldOfStudy,
      startedAt: school.studiedFrom_ISO8601,
      endedAt: school.studiedTill_ISO8601,
    };
  }),
  workHistory: parsedCV.workHistory?.map(work => {
    // ...
  }),
};

return mappedCV;

更新候选数据

现在,我们有一个带有从简历中提取结构化数据的JSON,我们可以使用Update Candidate用例将数据发送回ATS,以更新候选人的数据:

exports.updateCandidate = async (sdk, providerOptions, candidate) => {
  const profile = await sdk.getProfile('recruitment/update-candidate@1.0.0');

  const result = await profile
    .getUseCase('UpdateCandidate')
    .perform(candidate, providerOptions);

  result.unwrap();

  return true;
};

使用另一个ATS?

如果您查看代码,则不会提及可行,云代理或OpenAI。那是因为用例以提供商中立的方式设计。对于ATS,我们使用unified terminology,因此,如果您需要使用其他ATS,则无需重写整个应用程序。相反,您可以在src/index.js文件中更改atsProviderOptions

// Options for Workable
const atsProviderOptions = {
  provider: 'workable',
  parameters: {
    SUBDOMAIN: process.env.WORKABLE_SUBDOMAIN,
  },
  security: {
    bearer_token: {
      token: process.env.WORKABLE_TOKEN,
    },
  },
};

,如果您想使用,例如Br​​eezy HR,请将atsProviderOptions设置为这样:

// Options for Breezy HR
const atsProviderOptions = {
  provider: 'breezy-hr',
  parameters: {
    COMPANY_ID: process.env.BREEZY_HR_COMPANY_ID,
    ACCESS_TOKEN: process.env.BREEZY_HR_ACCESS_TOKEN,
  },
};

下一步

在此演示应用程序中,我们使用了来自3个不同API提供商的6种不同API用例,而从未查看API文档。这是超级表面的优点。

您是否需要集成申请人跟踪系统,例如可行,杠杆或SAP SuccessFactors?查看我们的Applicant Tracking Systems integrations。而且不要错过Superface catalog中的其他集成。