Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

2024 07 04 ai and form fields #211

Merged
merged 34 commits into from
Jul 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
edf4aed
turns out getting the assistants API to work is a little bit of a lar…
Ches-ctrl Jul 4, 2024
fefdd88
ca marche!
Ches-ctrl Jul 4, 2024
024d58e
updates to outputs
Ches-ctrl Jul 4, 2024
4c425f3
update sidekiq
Ches-ctrl Jul 6, 2024
f6f26e3
update seeds
Ches-ctrl Jul 6, 2024
ba89b4b
puts & pretty_generate
Ches-ctrl Jul 6, 2024
ba6269c
we're getting somewhere
Ches-ctrl Jul 6, 2024
35f6852
getting there
Ches-ctrl Jul 6, 2024
2c2f05d
old file for now
Ches-ctrl Jul 6, 2024
ed0c5f0
better
Ches-ctrl Jul 7, 2024
dfb4bd1
updates and deletions
Ches-ctrl Jul 7, 2024
f4885be
comparing against old code
Ches-ctrl Jul 7, 2024
4d7c121
handle additional field sets
Ches-ctrl Jul 7, 2024
eac7d94
updating
Ches-ctrl Jul 7, 2024
f228418
delete capybara scrape
Ches-ctrl Jul 7, 2024
8acc5ca
add pretty generate
Ches-ctrl Jul 7, 2024
fb77e74
getting the fields from the API is ridiculously easier
Ches-ctrl Jul 7, 2024
9741f92
add old method in case
Ches-ctrl Jul 7, 2024
a3f5153
add testing rake task
Ches-ctrl Jul 7, 2024
fa05929
call service class for fields
Ches-ctrl Jul 7, 2024
dc6f051
update api comments
Ches-ctrl Jul 7, 2024
0447c21
pass job variable to gff
Ches-ctrl Jul 7, 2024
83b2c75
Setup testing
Ches-ctrl Jul 7, 2024
4c24552
setup for testing and add missing fields
Ches-ctrl Jul 7, 2024
95da870
add iframe for original link to job posting
Ches-ctrl Jul 7, 2024
1fafec8
remove iframe for now
Ches-ctrl Jul 7, 2024
e10cdc2
slight format update
Ches-ctrl Jul 7, 2024
bf9af52
add temporary link to original posting
Ches-ctrl Jul 7, 2024
3e24014
Add GetApiFieldsJob & fix seed
patanj101 Jul 9, 2024
47e0e81
get rid of getformfields
Ches-ctrl Jul 15, 2024
cba13af
call getapifields
Ches-ctrl Jul 15, 2024
8f7389d
create classs to inherit from
Ches-ctrl Jul 15, 2024
13ec639
Merge branch '2024-07-04-ai-and-form-fields' of github.com:Ches-ctrl/…
Ches-ctrl Jul 15, 2024
136c938
update empty file
Ches-ctrl Jul 15, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/assets/builds/tailwind.css

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions app/jobs/importer/get_api_fields_job.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
module Importer
class GetApiFieldsJob < ApplicationJob
include Sidekiq::Status::Worker

queue_as :importers
sidekiq_options retry: false

def perform(job)
Importer::GetApiFields.call(job)
end
end
end
259 changes: 1 addition & 258 deletions app/models/concerns/ats/greenhouse/application_fields.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,265 +2,8 @@ module Ats
module Greenhouse
module ApplicationFields
def get_application_criteria(job, _data)
job.application_criteria = CORE_FIELDS
# GetForm.perform
job.application_criteria = Importer::GetApiFields.call
end

CORE_FIELDS = {
first_name: {
interaction: :input,
locators: 'first_name',
required: true,
label: 'First Name',
core_field: true
},
last_name: {
interaction: :input,
locators: 'last_name',
required: true,
label: 'Last Name',
core_field: true
},
email: {
interaction: :input,
locators: 'email',
required: true,
label: 'Email',
core_field: true
},
phone_number: {
interaction: :input,
locators: 'phone',
required: true,
label: 'Phone',
core_field: true
},
city: {
interaction: :input,
locators: 'location',
required: false,
label: 'Location (City)',
core_field: true
},
resume: {
interaction: :upload,
locators: 'button[aria-describedby="resume-allowable-file-types"',
required: true,
label: 'Resume/CV',
core_field: true
},
cover_letter_: {
interaction: :upload,
locators: 'button[aria-describedby="cover_letter-allowable-file-types"]',
required: true,
label: 'Cover Letter',
core_field: true
}
}

ADDITIONAL_FIELDS = {
school: {
interaction: :select,
locators: 's2id_education_school_name_0',
required: true,
placeholder: 'Select a School',
data_url: 'https://boards-api.greenhouse.io/v1/boards/phonepe/education/schools',
label: 'School',
core_field: false
},
degree: {
interaction: :select,
locators: 's2id_education_degree_0',
required: false,
label: 'Degree',
core_field: false
},
discipline: {
interaction: :select,
locators: 's2id_education_discipline_0',
required: false,
label: 'Discipline',
core_field: false
},
ed_start_date_year: {
interaction: :input,
locators: 'job_application[educations][][start_date][year]',
required: true,
label: 'Education Start Date Year',
core_field: false
},
ed_end_date_year: {
interaction: :input,
locators: 'job_application[educations][][end_date][year]',
required: true,
label: 'Education End Date Year',
core_field: false
},
company_name: {
interaction: :input,
locators: 'job_application[employments][][company_name]',
required: true,
label: 'Company Name',
core_field: false
},
title: {
interaction: :input,
locators: 'job_application[employments][][title]',
required: true,
label: 'Title',
core_field: false
},
emp_start_date_month: {
interaction: :input,
locators: 'job_application[employments][][start_date][month]',
required: true,
label: 'Employment Start Date Month',
core_field: false
},
emp_start_date_year: {
interaction: :input,
locators: 'job_application[employments][][start_date][year]',
required: true,
label: 'Employment Start Date Year',
core_field: false
},
emp_end_date_month: {
interaction: :input,
locators: 'job_application[employments][][end_date][month]',
required: true,
label: 'Employment End Date Month',
core_field: false
},
emp_end_date_year: {
interaction: :input,
locators: 'job_application[employments][][end_date][year]',
required: true,
label: 'Employment End Date Year',
core_field: false
},
linkedin_profile: {
interaction: :input,
locators: 'input[autocomplete="custom-question-linkedin-profile"]',
required: false,
label: 'LinkedIn Profile',
core_field: false
},
personal_website: {
interaction: :input,
locators: 'input[autocomplete="custom-question-website"], input[autocomplete="custom-question-portfolio-linkwebsite"]',
required: false,
label: 'Personal Website',
core_field: false
},
gender: {
interaction: :input,
locators: 'input[autocomplete="custom-question-website"], input[autocomplete="custom-question-portfolio-linkwebsite"]',
required: false,
label: 'Gender',
core_field: false
}
# location_click: {
# interaction: :listbox,
# locators: 'ul#location_autocomplete-items-popup'
# },

# heard_from: {
# interaction: :input,
# locators: 'input[autocomplete="custom-question-how-did-you-hear-about-this-job"]'
# },
# require_visa?: {
# interaction: :input,
# locators: 'textarea[autocomplete="custom-question-would-you-need-sponsorship-to-work-in-the-uk-"]'
# },
}

DEGREE_OPTIONS = [
"High School",
"Associate's Degree",
"Bachelor's Degree",
"Master's Degree",
"Master of Business Administration (M.B.A.)",
"Juris Doctor (J.D.)",
"Doctor of Medicine (M.D.)",
"Doctor of Philosophy (Ph.D.)",
"Engineer's Degree",
"Other"
]

DISCIPLINE_OPTIONS = [
"Accounting",
"African Studies",
"Agriculture",
"Anthropology",
"Applied Health Services",
"Architecture",
"Art",
"Asian Studies",
"Biology",
"Business",
"Business Administration",
"Chemistry",
"Classical Languages",
"Communications &amp; Film",
"Computer Science",
"Dentistry",
"Developing Nations",
"Discipline Unknown",
"Earth Sciences",
"Economics",
"Education",
"Electronics",
"Engineering",
"English Studies",
"Environmental Studies",
"European Studies",
"Fashion",
"Finance",
"Fine Arts",
"General Studies",
"Health Services",
"History",
"Human Resources Management",
"Humanities",
"Industrial Arts &amp; Carpentry",
"Information Systems",
"International Relations",
"Journalism",
"Languages",
"Latin American Studies",
"Law",
"Linguistics",
"Manufacturing &amp; Mechanics",
"Mathematics",
"Medicine",
"Middle Eastern Studies",
"Naval Science",
"North American Studies",
"Nuclear Technics",
"Operations Research &amp; Strategy",
"Organizational Theory",
"Philosophy",
"Physical Education",
"Physical Sciences",
"Physics",
"Political Science",
"Psychology",
"Public Policy",
"Public Service",
"Religious Studies",
"Russian &amp; Soviet Studies",
"Scandinavian Studies",
"Science",
"Slavic Studies",
"Social Science",
"Social Sciences",
"Sociology",
"Speech",
"Statistics &amp; Decision Theory",
"Urban Studies",
"Veterinary Medicine",
"Other"
]
end
end
end
4 changes: 4 additions & 0 deletions app/services/faraday_helpers.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,4 +51,8 @@ def stream_xml_data(body)
def log_error(message)
Rails.logger.error(message)
end

def pretty_generate(json)
JSON.pretty_generate(json)
end
end
56 changes: 56 additions & 0 deletions app/services/importer/get_api_fields.rb
Copy link
Collaborator

@daniel-sussman daniel-sussman Jul 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JB suggested I take a look and offer suggestions. Here are a few thoughts I had:

  • could we call this alternatively with job_data rather than with a url? That avoids calling the API a second time to get the application_criteria after first calling it to get the job_details, which is unnecessary if they're both part of the same json response (as with GH). Other ATSs will require a new API call to get the application_questions anyway.
  • I would put the logic that builds @fields in a separate method, so it can be easily swapped out for different ATSs
  • likewise, fetch_json should go in a separate method. It's sometimes going to be more complicated than with GH. With ashby, for example, this request is a GraphQL query via a POST request with specific info in the request body and headers.
  • just fyi, running FormFiller with GH jobs is a bit trickier if you're getting the questions via API, because mostly the API doesn't give you any useful locators other than the text of the question itself. I did some experimenting and verified that it's possible to get FormFiller to work using the text of the questions as locators, although it runs somewhat more slowly than if we get the element IDs via GetFormFields.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is helpful context thanks Dan - noted on the updates to the Faraday helper and also calling with job_data instead - ideally we do this as you note (we'll need to build the URL carefully for Greenhouse in this case as perhaps we'll sometimes want to pass the additional params and sometimes not? Keen to discuss / hear thoughts)

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also a note on this - we can add further customisation into how Faraday makes the connection than what we're doing at the moment - think we might want to bring this in in future so just noting (e.g. custom user agent, proxy etc.)

Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
module Importer
# Core class for getting form fields directly from the API
# Splits based on category of fields - main, custom, demographic, eeoc
# Known Issues - Building the checkbox logic for the data_compliance section
# Allowable file types (Greenhouse): (File types: pdf, doc, docx, txt, rtf)
# NB. Must include all params to get additional fields from the API
class GetApiFields < ApplicationTask
include FaradayHelpers

def initialize
# @job = job
# @url = @job.api_url
@url = "https://boards-api.greenhouse.io/v1/boards/cleoai/jobs/4628944002"
# @url = "https://boards-api.greenhouse.io/v1/boards/cleoai/jobs/7301308002"
# @url = "https://boards-api.greenhouse.io/v1/boards/monzo/jobs/6076740"
# @url = "https://boards-api.greenhouse.io/v1/boards/axios/jobs/6009256"
# @url = "https://boards-api.greenhouse.io/v1/boards/11fs/jobs/4060453101"
# @url = "https://boards-api.greenhouse.io/v1/boards/forter/jobs/7259821002"
# @url = "https://boards-api.greenhouse.io/v1/boards/cleoai/jobs/4628944002"
@url += "?questions=true&location_questions=true&demographic_questions=true&&compliance=true&pay_transparency=true"
# @ats_sections = %w[main_fields custom_fields demographic_questions eeoc_fields data_compliance security_code_fields]
@fields = {}
@errors = false
end

def call
return unless processable

process
rescue StandardError => e
Rails.logger.error "Error running GetFormFields: #{e.message}"
nil
end

private

def processable
@url # && @job
end

def process
p "Hello from GetApiFields!"

json = fetch_json(@url)
return unless json

@fields['main_fields'] = json['questions']
@fields['demographic_questions'] = json['demographic_questions']
@fields['location_questions'] = json['location_questions']
@fields['data_compliance'] = json['data_compliance']

puts pretty_generate(@fields)
@fields
end
end
end
Loading
Loading