| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- const fs = require('fs')
- const cosineSimilarity = require('compute-cosine-similarity')
- const mockOutputPath = './db/_generated.js'
-
- // Insert here how many users you would like to generate:
- const total = 10
- let extraProfilesToGenerate = 0
-
- // Amount of responses for a complete survey
- const questions = 13
-
- // Seekers per 100 profiles
- const percentageOfSeekers = 90
-
- // Values for responses
- const possibleResponses = {
- not_important: '120',
- some_what_important: '140',
- important: '160',
- very_important: '180',
- extremely_important: '200',
- mandatory: '400',
- }
-
- const possibleZipcodes = [
- '90065', // Glassel
- '90012', // Chinatown
- '90240', // Downey
- '91030', // South Pasadena
- '91201', // Glendale
- '91399', // Woodland Hills
- '91401', // Van Nuys
- '90840', // Long Beach
- '91001', // Altadena
- '91011', // La Canada Flintridge
- '97075', // Beaverton
- ]
-
- // Helper functions
- const randomNumber = max => {
- return Math.floor(Math.random() * max) < 1
- ? 1
- : Math.floor(Math.random() * max)
- }
-
- const randomValFrom = arr => arr[randomNumber(arr.length)]
- const randomEmail = (length = 5) => {
- let chars =
- 'abcdefghijklmnopqrstuvwxyz-_abcdefghijklmnopqrstuvwxyz0123456789'
- let str = ''
- for (let i = 0; i < length + randomNumber(9); i++) {
- str += chars.charAt(Math.floor(Math.random() * chars.length))
- }
- const suffixs = [
- '@gmail.com',
- '@aol.com',
- '@yahoo.com',
- '@apple.com',
- '@hotmail.com',
- '@rocket-mail.com',
- '@mail.com',
- ]
- return str + randomValFrom(suffixs)
- }
- const randomName = (length = 4) => {
- let chars = 'aeiouaeiouabcdefghijklmnoprstuvwyabcdefghijklmnopqrstuvwxyz'
- let str = ''
- for (let i = 0; i < length + randomNumber(9); i++) {
- str += chars.charAt(Math.floor(Math.random() * chars.length))
- }
- return str
- }
-
- const generate = (classObj, amount, meta) => {
- const instances = []
- for (let i = 0; i < amount; i++) {
- instances.push(new classObj(i + 1, meta))
- }
- return instances
- }
-
- class User {
- constructor(id) {
- this.user_id = id
- this.user_name = ''
- this.user_email = ''
- this.is_admin = false
- this.is_poster = false
- }
- }
- class Profile {
- constructor(id, override) {
- this.user_id = override ? override.user_id : id
- this.profile_id = override ? override.profile_id + id : id
- }
- }
- class Response {
- constructor(id) {
- this.response_id = id
- this.profile_id = null
- this.response_key_id = null
- this.val = null
- }
- }
-
- const users = generate(User, total)
- users.forEach(user => {
- user.is_poster = randomNumber(100) > percentageOfSeekers ? 1 : 0
- if (user.is_poster) {
- extraProfilesToGenerate = extraProfilesToGenerate + randomNumber(2)
- }
- user.user_name = randomName() + ' ' + randomName()
- user.user_email = randomEmail()
- })
- let jobPosterIds = users
- .filter(user => user.is_poster > 0)
- .map(user => user.user_id)
-
- // Guarentee ONE job poster
- if (!jobPosterIds.length) {
- randomValFrom(users).is_poster = 1
- jobPosterIds = users
- .filter(user => user.is_poster > 0)
- .map(user => user.user_id)
- }
-
- const profiles = generate(Profile, total)
-
- // Generate extra job posting profiles
- // attributed to random user.is_poster === true
- // TODO: Clean this up. Hard to read...
- if (extraProfilesToGenerate > 0) {
- let extras = []
- for (let l = 0; l < extraProfilesToGenerate; l++) {
- const generatedExtraProfiles = generate(Profile, 1, {
- user_id:
- jobPosterIds.length > 1
- ? randomValFrom(jobPosterIds)
- : jobPosterIds[0],
- profile_id: profiles.length + l,
- })
- extras = [...extras, ...generatedExtraProfiles]
- }
- extras.forEach(profile => profiles.push(profile))
- }
-
- // Generate responses, then fill in details
- const responses = generate(
- Response,
- (total + extraProfilesToGenerate) * questions,
- )
- profiles.forEach((profile, i) => {
- const startingIndex = i * questions
- for (let k = 0; k < questions; k++) {
- const resToEdit = responses[startingIndex + k]
- resToEdit.response_key_id = k + 1
- resToEdit.profile_id = profile.profile_id
- resToEdit.val =
- k + 1 == questions
- ? randomValFrom(possibleZipcodes)
- : randomValFrom(Object.values(possibleResponses))
- }
- })
-
- /**
- * Score all the profiles!
- */
- const scoreResponses = (seeker, potentialMatch) => {
- const seekerResponses = responses
- .filter(response => response.profile_id == seeker.profile_id)
- .filter(response => response.val.length < 4)
-
- const potentialMatchResponses = responses
- .filter(response => response.profile_id == potentialMatch.profile_id)
- .filter(response => response.val.length < 4)
-
- const checkValCb = res => {
- const val = parseInt(res.val)
- return isNaN(val) ? 0 : val
- }
- return Math.floor(
- cosineSimilarity(
- seekerResponses.map(checkValCb),
- potentialMatchResponses.map(checkValCb),
- ) * 1000,
- )
- }
- const scoreProfile = (profile, potentialMatchList) => {
- const scored = potentialMatchList.map(profileToCompare => {
- return {
- match_queue_id: null,
- profile_id: profile.profile_id,
- target_id: profileToCompare.profile_id,
- is_deleted: false,
- score: scoreResponses(profile, profileToCompare),
- }
- })
- return scored.sort((a, b) => a.score - b.score)
- }
- const scoreAll = () => {
- let scores = []
- const posterProfiles = profiles.filter(profile =>
- jobPosterIds.includes(profile.user_id),
- )
- const seekerProfiles = profiles.filter(
- profile => !jobPosterIds.includes(profile.user_id),
- )
- seekerProfiles.forEach(seeker => {
- const scored = scoreProfile(seeker, posterProfiles)
- scores = [...scored, ...scores]
- })
- posterProfiles.forEach(poster => {
- const scored = scoreProfile(poster, seekerProfiles)
- scores = [...scored, ...scores]
- })
- return scores.reverse()
- }
- const match_queues = scoreAll().map((score, i) => {
- score.match_queue_id = i + 1
- // Comment out to see the score
- delete score.score
- return score
- })
-
- /**
- * Our output format
- */
- const outputDataObject = { users, profiles, responses, match_queues }
-
- const jobPostings = profiles.filter(profile =>
- jobPosterIds.includes(profile.user_id),
- ).length
- const jobPosters = users.filter(user => user.is_poster > 0).length
- const header = `/**
- * GENERATED MOCK SIIMEE DATA
- * Generated at: ${Date.now()}
- * ---
- * ${jobPostings} positions listed by ${jobPosters} job posters
- * ${total + extraProfilesToGenerate - jobPostings} candidate profiles by ${
- total + extraProfilesToGenerate - jobPostings
- } job seekers
- * ---
- * ${total + extraProfilesToGenerate} Profiles
- * ${total} Users
- */
- `
- const write = async () => {
- await fs.writeFile(mockOutputPath, '', () => {})
- fs.appendFile(
- mockOutputPath,
- header + 'module.exports = ' + JSON.stringify(outputDataObject),
- err => {
- if (err) {
- console.error(err)
- return
- }
- },
- )
- }
- write()
|