Exemplo n.º 1
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        product = get_product(insight.barcode, ["code"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        image_id = get_image_id(insight.source_image or "")

        if not image_id:
            return AnnotationResult(
                status="error_invalid_image",
                description="the image is invalid",
            )
        image_key = "nutrition_{}".format(insight.value_tag)
        select_rotate_image(
            barcode=insight.barcode,
            image_id=image_id,
            image_key=image_key,
            rotate=insight.data.get("rotation"),
            server_domain=insight.server_domain,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 2
0
def is_automatically_processable(barcode: str, source_image: Optional[str],
                                 max_timedelta: datetime.timedelta) -> bool:
    if not source_image:
        return False

    image_path = pathlib.Path(source_image)
    image_id = image_path.stem

    if not image_id.isdigit():
        return False

    product = get_product(barcode, projection=["images"])

    if product is None:
        logger.debug("Missing product: {}".format(barcode))
        raise InvalidInsight()

    if "images" not in product:
        logger.debug("No images for product {}".format(barcode))
        raise InvalidInsight()

    product_images = product["images"]

    if image_id not in product_images:
        logger.debug("Missing image for product {}, ID: {}".format(
            barcode, image_id))
        raise InvalidInsight()

    if is_recent_image(product_images, image_id, max_timedelta):
        return True

    if is_selected_image(product_images, image_id):
        return True

    return False
Exemplo n.º 3
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        product = get_product(insight.barcode, ["quantity"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        quantity: Optional[str] = product.get("quantity") or None

        if quantity is not None:
            return ALREADY_ANNOTATED_RESULT

        update_quantity(
            insight.barcode,
            insight.value,
            insight_id=insight.id,
            server_domain=insight.server_domain,
            auth=auth,
        )

        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 4
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        packaging_tag: str = insight.value_tag

        product = get_product(insight.barcode, ["packaging_tags"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        packaging_tags: List[str] = product.get("packaging_tags") or []

        if packaging_tag in packaging_tags:
            return ALREADY_ANNOTATED_RESULT

        add_packaging(
            insight.barcode,
            insight.value,
            insight_id=insight.id,
            server_domain=insight.server_domain,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 5
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        barcode = insight.barcode
        lang = insight.data["lang"]
        field_name = "ingredients_text_{}".format(lang)
        product = get_product(barcode, [field_name])

        if product is None:
            return MISSING_PRODUCT_RESULT

        original_ingredients = insight.data["text"]
        corrected = insight.data["corrected"]
        expected_ingredients = product.get(field_name)

        if expected_ingredients != original_ingredients:
            logger.warning("ingredients have changed since spellcheck insight "
                           "creation (product {})".format(barcode))
            return AnnotationResult(
                status=AnnotationStatus.error_updated_product.name,
                description=
                "the ingredient list has been updated since spellcheck",
            )

        save_ingredients(
            barcode,
            corrected,
            lang=lang,
            insight_id=insight.id,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 6
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        emb_code: str = insight.value

        product = get_product(insight.barcode, ["emb_codes"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        emb_codes_str: str = product.get("emb_codes", "")

        emb_codes: List[str] = []
        if emb_codes_str:
            emb_codes = emb_codes_str.split(",")

        if self.already_exists(emb_code, emb_codes):
            return ALREADY_ANNOTATED_RESULT

        emb_codes.append(emb_code)
        update_emb_codes(
            insight.barcode,
            emb_codes,
            server_domain=insight.server_domain,
            insight_id=insight.id,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 7
0
def categorize(
    barcode: str,
    deepest_only: bool = False,
) -> None:
    """Categorise predicts product categories based on the neural category classifier.

    deepest_only: controls whether the returned predictions should only contain the deepmost
    categories for a predicted taxonomy chain.
    For example, if we predict 'fresh vegetables' -> 'legumes' -> 'beans' for a product,
    setting deepest_only=True will return 'beans'."""
    from robotoff.prediction.category.neural.category_classifier import (
        CategoryClassifier, )
    from robotoff.products import get_product
    from robotoff.taxonomy import TaxonomyType, get_taxonomy

    product = get_product(barcode)
    if product is None:
        print(f"Product {barcode} not found")
        return

    predictions = CategoryClassifier(get_taxonomy(
        TaxonomyType.category.name)).predict(product, deepest_only)

    if predictions:
        for prediction in predictions:
            print(f"{prediction.value_tag}: {prediction.data['confidence']}")
    else:
        print(f"Nothing predicted for product {barcode}")
Exemplo n.º 8
0
def update_insights(barcode: str, server_domain: str):
    # Sleep 10s to let the OFF update request that triggered the webhook call
    # to finish
    time.sleep(10)
    product_dict = get_product(barcode)

    if product_dict is None:
        logger.warn("Updated product does not exist: {}".format(barcode))
        return

    updated = updated_product_predict_insights(barcode, product_dict, server_domain)

    if updated:
        logger.info("Product {} updated".format(barcode))

    update_ingredients(barcode, product_dict, server_domain)

    product = Product(product_dict)
    validators: Dict[str, Optional[InsightValidator]] = {}

    for insight in (
        ProductInsight.select()
        .where(
            ProductInsight.annotation.is_null(),
            ProductInsight.barcode == barcode,
            ProductInsight.server_domain == server_domain,
        )
        .iterator()
    ):
        if insight.type not in validators:
            validators[insight.type] = InsightValidatorFactory.create(
                insight.type, None
            )

        validator = validators[insight.type]

        if validator is not None:
            result = validate_insight(insight, validator=validator, product=product)
            if result == InsightValidationResult.deleted:
                logger.info(
                    "Insight {} deleted (type: {})".format(insight.id, insight.type)
                )
            elif result == InsightValidationResult.updated:
                logger.info(
                    "Insight {} converted to latent (type: {})".format(
                        insight.id, insight.type
                    )
                )
Exemplo n.º 9
0
def update_insights(barcode: str, server_domain: str):
    # Sleep 10s to let the OFF update request that triggered the webhook call
    # to finish
    logger.info(
        f"Running `update_insights` for product {barcode} ({server_domain})")

    product_dict = get_product(barcode)

    if product_dict is None:
        logger.warning("Updated product does not exist: %s", barcode)
        return

    updated_product_predict_insights(barcode, product_dict, server_domain)
    logger.info("Refreshing insights...")
    imported = refresh_insights(barcode, server_domain, automatic=True)
    logger.info(f"{imported} insights created after refresh")
Exemplo n.º 10
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        product = get_product(insight.barcode, ["brands_tags"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        add_brand(
            insight.barcode,
            insight.value,
            insight_id=insight.id,
            server_domain=insight.server_domain,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT
Exemplo n.º 11
0
    def process_annotation(
        self,
        insight: ProductInsight,
        data: Optional[Dict] = None,
        auth: Optional[OFFAuthentication] = None,
    ) -> AnnotationResult:
        product = get_product(insight.barcode, ["expiration_date"])

        if product is None:
            return MISSING_PRODUCT_RESULT

        current_expiration_date = product.get("expiration_date") or None

        if current_expiration_date:
            return ALREADY_ANNOTATED_RESULT

        update_expiration_date(
            insight.barcode,
            insight.value,
            insight_id=insight.id,
            server_domain=insight.server_domain,
            auth=auth,
        )
        return UPDATED_ANNOTATION_RESULT