def _make_strategy( project: scoring.ScoringProject, module: strategy_pb2.StrategyModule, advice_scores: dict[str, float]) -> Optional[strategy_pb2.Strategy]: if module.is_for_alpha and not project.features_enabled.alpha: return None score = project.score(module.trigger_scoring_model) if not score: return None score = min(score * 100 / 3, 100 - project.details.diagnostic.overall_score) pieces_of_advice = [] for advice in module.pieces_of_advice: user_advice_id = next((a for a in advice_scores if a.startswith(advice.advice_id)), None) if not user_advice_id: if advice.is_required: # A necessary advice is missing, we drop everything. return None continue pieces_of_advice.append(strategy_pb2.StrategyAdvice( advice_id=user_advice_id, teaser=project.populate_template(project.translate_string(advice.teaser_template)), why=project.populate_template(project.translate_string(advice.why_template)))) if _SPECIFIC_TO_JOB_ADVICE_ID in advice_scores: specific_to_job_config = project.specific_to_job_advice_config() if specific_to_job_config and module.strategy_id in specific_to_job_config.strategy_ids: pieces_of_advice.append(strategy_pb2.StrategyAdvice( advice_id=_SPECIFIC_TO_JOB_ADVICE_ID)) if not pieces_of_advice and not module.external_url_template: # Don't want to show a strategy without any advice modules. return None strategy = project.details.strategies.add( description=project.populate_template(project.translate_airtable_string( 'strategyModules', module.strategy_id, 'description_template', hint=module.description_template)), score=int(score), is_secondary=score <= 10, title=project.translate_airtable_string( 'strategyModules', module.strategy_id, 'title', hint=module.title), header=project.populate_template(project.translate_airtable_string( 'strategyModules', module.strategy_id, 'header_template', hint=module.header_template)), strategy_id=module.strategy_id, external_url=project.populate_template(module.external_url_template), infinitive_title=project.translate_airtable_string( 'strategyModules', module.strategy_id, 'infinitive_title', hint=module.infinitive_title), action_ids=module.action_ids, description_speech=project.populate_template(project.translate_airtable_string( 'strategyModules', module.strategy_id, 'description_speech', hint=module.description_speech, is_genderized=True)), ) if strategy.external_url and pieces_of_advice: logging.error( 'Strategy %s has both an external URL and some pieces of advice:\n%s', strategy.strategy_id, ', '.join(a.advice_id for a in pieces_of_advice)) # Sort found pieces of advice by descending score. pieces_of_advice.sort(key=lambda a: advice_scores[a.advice_id], reverse=True) strategy.pieces_of_advice.extend(pieces_of_advice) return strategy
def _compute_diagnostic_topic_score( topic: 'diagnostic_pb2.DiagnosticTopic', scorers: Iterable[diagnostic_pb2.DiagnosticSubmetricScorer], scoring_project: scoring.ScoringProject) \ -> Optional[diagnostic_pb2.SubDiagnostic]: """Create the score for a given diagnostic submetric on a given project. Args: topic: the diagnostic topic we wish to evaluate scorers: a list of scorers for the given topic, with a weight on each. scoring_project: the project we want to score Returns: the populated subdiagnostic protobuf. """ topic_score = 0. topic_weight = 0. sub_diagnostic = diagnostic_pb2.SubDiagnostic(topic=topic) for scorer in scorers: try: score = scoring_project.score(scorer.trigger_scoring_model) except scoring.NotEnoughDataException: continue # Use default weight of 1 weight = scorer.weight or 1 weighted_score = score * weight topic_score += weighted_score topic_weight += weight if not topic_weight: return None sub_diagnostic.score = round(topic_score / topic_weight * 100 / 3) return sub_diagnostic
def _make_strategy( project: scoring.ScoringProject, module: strategy_pb2.StrategyModule, advice_scores: Dict[str, float]) -> Optional[strategy_pb2.Strategy]: score = project.score(module.trigger_scoring_model) if not score: return None score = min(score * 100 / 3, 100 - project.details.diagnostic.overall_score) pieces_of_advice = [] for advice in module.pieces_of_advice: user_advice_id = next( (a for a in advice_scores if a.startswith(advice.advice_id)), None) if not user_advice_id: if advice.is_required: # A necessary advice is missing, we drop everything. return None continue pieces_of_advice.append( strategy_pb2.StrategyAdvice( advice_id=user_advice_id, teaser=project.populate_template( project.translate_string(advice.teaser_template)), header=project.populate_template( project.translate_string(advice.header_template)))) if _SPECIFIC_TO_JOB_ADVICE_ID in advice_scores: specific_to_job_config = project.specific_to_job_advice_config() if specific_to_job_config and module.strategy_id in specific_to_job_config.strategy_ids: pieces_of_advice.append( strategy_pb2.StrategyAdvice( advice_id=_SPECIFIC_TO_JOB_ADVICE_ID)) if not pieces_of_advice: # Don't want to show a strategy without any advice modules. return None strategy = project.details.strategies.add( description=project.populate_template( project.translate_string(module.description_template)), score=int(score), is_secondary=score <= 10, title=project.translate_string(module.title), header=project.populate_template( project.translate_string(module.header_template)), strategy_id=module.strategy_id) # Sort found pieces of advice by descending score. pieces_of_advice.sort(key=lambda a: advice_scores[a.advice_id], reverse=True) strategy.pieces_of_advice.extend(pieces_of_advice) return strategy
def _get_relevance_from_its_model( main_challenge: diagnostic_pb2.DiagnosticMainChallenge, project: scoring.ScoringProject, has_missing_fields: bool, relevant_should_be_neutral: bool) \ -> 'diagnostic_pb2.MainChallengeRelevance.V': if main_challenge.relevance_scoring_model: relevance_score = project.score(main_challenge.relevance_scoring_model) if relevance_score <= 0: return diagnostic_pb2.NOT_RELEVANT if relevance_score >= 3 and not relevant_should_be_neutral: return diagnostic_pb2.RELEVANT_AND_GOOD return diagnostic_pb2.NEUTRAL_RELEVANCE if has_missing_fields: return diagnostic_pb2.NEUTRAL_RELEVANCE return diagnostic_pb2.NEUTRAL_RELEVANCE if relevant_should_be_neutral else \ diagnostic_pb2.RELEVANT_AND_GOOD
def _get_relevance_from_its_model( category: diagnostic_pb2.DiagnosticCategory, project: scoring.ScoringProject, has_missing_fields: bool) \ -> diagnostic_pb2.CategoryRelevance: if category.relevance_scoring_model: relevance_score = project.score(category.relevance_scoring_model) if relevance_score <= 0: return diagnostic_pb2.NOT_RELEVANT if relevance_score >= 3: return diagnostic_pb2.RELEVANT_AND_GOOD return diagnostic_pb2.NEUTRAL_RELEVANCE try: return _CATEGORIES_RELEVANCE_GETTERS[category.category_id](project) except KeyError: if has_missing_fields: return diagnostic_pb2.NEUTRAL_RELEVANCE return diagnostic_pb2.RELEVANT_AND_GOOD