project.details.job_search_length_months or 1) if num_monthly_interviews > self._max_monthly_interviews(project): return 3 # Whatever the number of month of search, trigger 3 if the user did more than 5 interviews: if num_interviews >= self._NUM_INTERVIEWS[project_pb2.A_LOT] and \ project.details.job_search_length_months <= 6: return 3 return 0 def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" interview_tips = project.list_application_tips() sorted_tips = sorted(interview_tips, key=lambda t: (-len(t.filters), random.random())) tips_proto = application_pb2.InterviewTips( qualities=[ t for t in sorted_tips if t.type == application_pb2.QUALITY ], preparations=[ t for t in sorted_tips if t.type == application_pb2.INTERVIEW_PREPARATION ]) for tip in itertools.chain(tips_proto.qualities, tips_proto.preparations): tip.ClearField('type') return tips_proto scoring.register_model('advice-improve-interview', _AdviceImproveInterview()) scoring.register_model('advice-improve-resume', _AdviceImproveResume())
try: geo.get_departement_name(own_departement) except KeyError: logging.warning( 'We cannot find the name of the French département "%s"', own_departement) # We only advice departements that are better than own departement. min_offers = departement_to_offers.get(own_departement, 0) if not min_offers: return [] # Compute the score for each departement. sorted_departements = sorted(departement_to_offers.items(), key=lambda x: x[1], reverse=True) # Get only departements that are strictly better than own departement. top_departements = [ project_pb2.DepartementScore(name=geo.get_departement_name(dep[0]), offer_ratio=dep[1] / min_offers) for dep in sorted_departements if dep[1] > min_offers ] # Return at most 10 departements. return top_departements[:10] scoring.register_model('advice-relocate', _AdviceRelocateScoringModel())
@scoring.ScoringProject.cached('events') def list_events(self, project): """List all events close to the project's target.""" today = project.now.strftime('%Y-%m-%d') all_events = [ e for e in self._db.get_collection(project.database) if e.start_date >= today ] return list( scoring.filter_using_score(all_events, lambda e: e.filters, project)) def compute_extra_data(self, project): """Compute extra data for this module to render a card in the client.""" all_events = self.list_events(project) if not all_events: return None return project_pb2.EventsData(event_name=all_events[0].title) def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" events = self.list_events(project) sorted_events = sorted( events, key=lambda j: (j.start_date, -len(j.filters), random.random())) return event_pb2.Events(events=sorted_events) scoring.register_model('advice-event', _AdviceEventScoringModel())
"""Compute departements that propose seasonal jobs.""" top_departements = seasonal_jobbing_pb2.MonthlySeasonalJobbingStats() # TODO(guillaume): Cache this to increase speed. proto.parse_from_mongo( project.database.seasonal_jobbing.find_one( {'_id': project.now.month}), top_departements) for departement in top_departements.departement_stats: # TODO(guillaume): If we don't use deeper jobgroups by october 1st 2017, trim the db. del departement.job_groups[6:] try: departement.departement_in_name = geo.get_in_a_departement_text( departement.departement_id) except KeyError: logging.exception( 'Prefix or name not found for departement: %s', departement.departement_id) continue for i, departement in enumerate( top_departements.departement_stats[::-1]): if not departement.departement_in_name: del top_departements.departement_stats[i] return top_departements or [] scoring.register_model('advice-seasonal-relocate', _AdviceSeasonalRelocate())
"""Compute extra data for this module to render a card in the client.""" association_names = [ m.association_name for m in self.volunteering_missions(project).missions ] # Deduplicate association names. seen = set() association_names = [ n for n in association_names if not (n in seen or seen.add(n)) ] return project_pb2.VolunteerData( association_names=association_names[:3]) def score(self, project): """Compute a score for the given ScoringProject.""" missions = self.volunteering_missions(project).missions if not missions: return 0 if project.details.job_search_length_months < 9: return 1 return 2 def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" return self.volunteering_missions(project) scoring.register_model('advice-volunteer', _AdviceVolunteer())
def compute_extra_data(self, project): """Compute extra data for this module to render a card in the client.""" jobboards = [ j for j in self.list_jobboards(project) if not j.is_well_known ] if not jobboards: return None sorted_jobboards = sorted(jobboards, key=lambda j: (-len(j.filters), random.random())) best_job_board = sorted_jobboards[0] return project_pb2.JobBoardsData( job_board_title=best_job_board.title, is_specific_to_job_group=any( f.startswith('for-job') for f in best_job_board.filters), is_specific_to_region=any( f.startswith('for-departement') for f in best_job_board.filters), ) def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" jobboards = self.list_jobboards(project) sorted_jobboards = sorted(jobboards, key=lambda j: (-len(j.filters), random.random())) return jobboard_pb2.JobBoards(job_boards=sorted_jobboards) scoring.register_model('advice-job-boards', _AdviceJobBoards())
if user_pb2.MOTIVATION in project.user_profile.frustrations: return 3 if len(associations ) >= 3 and project.details.job_search_length_months >= 6: return 3 if project.details.job_search_length_months >= 12: return 3 return 2 def compute_extra_data(self, project): """Compute extra data for this module to render a card in the client.""" associations = self.list_associations(project) if not associations: return None sorted_associations = sorted(associations, key=lambda j: (-len(j.filters), random.random())) return project_pb2.AssociationsData( association_name=sorted_associations[0].name) def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" associations = self.list_associations(project) sorted_associations = sorted(associations, key=lambda j: (-len(j.filters), random.random())) return association_pb2.Associations(associations=sorted_associations) scoring.register_model('advice-association-help', _AdviceAssociationHelp())
if distance >= _MAX_CITY_DISTANCE: continue try: relative_offers = (hiring_city.offers / hiring_city.city.population) / ref except ZeroDivisionError: relative_offers = 0 yield commute_pb2.CommutingCity( name=hiring_city.city.name, relative_offers_per_inhabitant=relative_offers, distance_km=distance) def _compute_square_distance(city_a, city_b): """Compute the approximative distance between two cities. Since we only look at short distances, we can approximate that: - 1° latitude = 111km - 1° longitude = 111km * cos(lat) """ delta_y = (city_a.latitude - city_b.latitude) * 111 mean_latitude = (city_a.latitude + city_b.latitude) / 2 delta_x = (city_a.longitude - city_b.longitude) * 111 * math.cos( math.radians(mean_latitude)) return delta_x * delta_x + delta_y * delta_y scoring.register_model('advice-commute', _AdviceCommuteScoringModel())
specific_jobs = project.requirements().specific_jobs if not specific_jobs: return None extra_data = project_pb2.BetterJobInGroupData() try: extra_data.num_better_jobs = next( i for i, job in enumerate(specific_jobs) if job.code_ogr == project.details.target_job.code_ogr) except StopIteration: # Target job is not mentionned in the specific jobs, do not mention # the number of better jobs. pass all_jobs = project.job_group_info().jobs try: best_job = next( job for job in all_jobs if job.code_ogr == specific_jobs[0].code_ogr) extra_data.better_job.CopyFrom(best_job) except StopIteration: logging.warning( 'Better job "%s" is not listed in the group "%s"', specific_jobs[0].code_ogr, project.job_group_info().rome_id) return extra_data scoring.register_model('advice-better-job-in-group', _AdviceBetterJobInGroup())
card_content = project.populate_template(best_lead.card_content) return project_pb2.Advice(card_text=card_content) def get_expanded_card_data(self, project): """Retrieve data for the expanded card.""" contact_leads = self._list_contact_leads(project) sorted_leads = sorted(contact_leads, key=lambda l: (-len(l.filters), random.random())) return network_pb2.ContactLeads(leads=[ network_pb2.ContactLead( name=project.populate_template(template.name), email_example=project.populate_template( template.email_template), contact_tip=template.contact_tip) for template in sorted_leads ]) @scoring.ScoringProject.cached('contact-leads') def _list_contact_leads(self, project): return scoring.filter_using_score( self._db.get_collection(project.database), lambda l: l.filters, project) scoring.register_model('advice-better-network', _ImproveYourNetworkScoringModel(2)) scoring.register_model('advice-improve-network', _ImproveYourNetworkScoringModel(1)) scoring.register_model('advice-use-good-network', _ImproveYourNetworkScoringModel(3))