Example #1
0
def get_products(feature,
                 user_id,
                 current_item_id,
                 num_results,
                 campaign_arn_param_name,
                 user_reqd_for_campaign=False,
                 fully_qualify_image_urls=False):
    """ Returns products given a UI feature, user, item/product.

    If a feature name is provided and there is an active experiment for the 
    feature, the experiment will be used to retrieve products. Otherwise, 
    the default behavior will be used which will look to see if an Amazon Personalize 
    campaign is available. If not, the Product service will be called to get products 
    from the same category as the current product.
    """

    # Check environment for host and port first in case we're running in a local Docker container (dev mode)
    products_service_host = os.environ.get('PRODUCT_SERVICE_HOST')
    products_service_port = os.environ.get('PRODUCT_SERVICE_PORT', 80)

    if not products_service_host:
        # Get product service instance. We'll need it rehydrate product info for recommendations.
        response = servicediscovery.discover_instances(
            NamespaceName='retaildemostore.local',
            ServiceName='products',
            MaxResults=1,
            HealthStatus='HEALTHY')

        products_service_host = response['Instances'][0]['Attributes'][
            'AWS_INSTANCE_IPV4']

    items = []
    resp_headers = {}
    experiment = None
    exp_manager = None

    # Get active experiment if one is setup for feature and we have a user.
    if feature and user_id:
        exp_manager = ExperimentManager()
        experiment = exp_manager.get_active(feature)

    if experiment:
        # Get items from experiment.
        tracker = exp_manager.default_tracker()

        items = experiment.get_items(user_id=user_id,
                                     current_item_id=current_item_id,
                                     num_results=num_results,
                                     tracker=tracker)

        resp_headers['X-Experiment-Name'] = experiment.name
        resp_headers['X-Experiment-Type'] = experiment.type
        resp_headers['X-Experiment-Id'] = experiment.id
    else:
        # Fallback to default behavior of checking for campaign ARN parameter and
        # then the default product resolver.
        values = get_parameter_values(
            [campaign_arn_param_name, filter_purchased_param_name])

        campaign_arn = values[0]
        filter_arn = values[1]

        if campaign_arn and (user_id or not user_reqd_for_campaign):
            resolver = PersonalizeRecommendationsResolver(
                campaign_arn=campaign_arn, filter_arn=filter_arn)

            items = resolver.get_items(user_id=user_id,
                                       product_id=current_item_id,
                                       num_results=num_results)

            resp_headers['X-Personalize-Recipe'] = get_recipe(campaign_arn)
        else:
            resolver = DefaultProductResolver(
                products_service_host=products_service_host,
                products_service_port=products_service_port)

            items = resolver.get_items(product_id=current_item_id,
                                       num_results=num_results)

    for item in items:
        itemId = item['itemId']
        url = f'http://{products_service_host}:{products_service_port}/products/id/{itemId}?fullyQualifyImageUrls={fully_qualify_image_urls}'
        app.logger.debug(f"Asking for product info from {url}")
        response = requests.get(url)
        app.logger.debug(f"Got product info: {response}")

        if response.ok:
            product = response.json()

            if 'experiment' in item and 'url' in product:
                # Append the experiment correlation ID to the product URL so it gets tracked if used by client.
                product_url = product.get('url')
                if '?' in product_url:
                    product_url += '&'
                else:
                    product_url += '?'

                product_url += 'exp=' + item['experiment']['correlationId']

                product['url'] = product_url

            item.update({'product': product})

        item.pop('itemId')

    resp = Response(json.dumps(items, cls=CompatEncoder),
                    content_type='application/json',
                    headers=resp_headers)
    return resp
Example #2
0
def get_products(feature, user_id, current_item_id, num_results, default_inference_arn_param_name,
                 default_filter_arn_param_name, filter_values=None, user_reqd_for_inference=False, fully_qualify_image_urls=False,
                 ):
    """ Returns products given a UI feature, user, item/product.

    If a feature name is provided and there is an active experiment for the
    feature, the experiment will be used to retrieve products. Otherwise,
    the default behavior will be used which will look to see if an Amazon Personalize
    campaign/recommender is available. If not, the Product service will be called to get products
    from the same category as the current product.
    Args:
        feature: Used to track different experiments - different experiments pertain to different features
        user_id: If supplied we are looking at user personalization
        current_item_id: Or maybe we are looking at related items
        num_results: Num to return
        default_inference_arn_param_name: If no experiment active, use this SSM parameters to get recommender Arn
        default_filter_arn_param_name: If no experiment active, use this SSM parameter to get filter Arn, if exists
        filter_values: Values to pass at inference for the filter
        user_reqd_for_inference: Require a user ID to use Personalze - otherwise default
        fully_qualify_image_urls: Fully qualify image URLs n here
    Returns:
        A prepared HTTP response object.
    """

    items = []
    resp_headers = {}
    experiment = None
    exp_manager = None

    # Get active experiment if one is setup for feature and we have a user.
    if feature and user_id:
        exp_manager = ExperimentManager()
        experiment = exp_manager.get_active(feature, user_id)

    if experiment:
        # Get items from experiment.
        tracker = exp_manager.default_tracker()

        items = experiment.get_items(
            user_id = user_id,
            current_item_id = current_item_id,
            num_results = num_results,
            tracker = tracker,
            filter_values = filter_values,
            timestamp = get_timestamp_from_request()
        )

        resp_headers['X-Experiment-Name'] = experiment.name
        resp_headers['X-Experiment-Type'] = experiment.type
        resp_headers['X-Experiment-Id'] = experiment.id
    else:
        # Fallback to default behavior of checking for campaign/recommender ARN parameter and
        # then the default product resolver.
        values = get_parameter_values([default_inference_arn_param_name, default_filter_arn_param_name])

        inference_arn = values[0]
        filter_arn = values[1]

        if inference_arn and (user_id or not user_reqd_for_inference):

            logger.info(f"get_products: Supplied campaign/recommender: {inference_arn} (from {default_inference_arn_param_name}) Supplied filter: {filter_arn} (from {default_filter_arn_param_name}) Supplied user: {user_id}")

            resolver = PersonalizeRecommendationsResolver(inference_arn = inference_arn, filter_arn = filter_arn)

            items = resolver.get_items(
                user_id = user_id,
                product_id = current_item_id,
                num_results = num_results,
                filter_values = filter_values
            )

            resp_headers['X-Personalize-Recipe'] = get_recipe(inference_arn)
        else:
            products_service_host, products_service_port = get_products_service_host_and_port()
            resolver = DefaultProductResolver(products_service_host = products_service_host, products_service_port = products_service_port)

            items = resolver.get_items(product_id = current_item_id, num_results = num_results)

    item_ids = [item['itemId'] for item in items]

    products = fetch_product_details(item_ids, fully_qualify_image_urls)
    for item in items:
        item_id = item['itemId']

        product = next((p for p in products if p['id'] == item_id), None)
        if product is not None and 'experiment' in item and 'url' in product:
            # Append the experiment correlation ID to the product URL so it gets tracked if used by client.
            product_url = product.get('url')
            if '?' in product_url:
                product_url += '&'
            else:
                product_url += '?'

            product_url += 'exp=' + item['experiment']['correlationId']

            product['url'] = product_url

        item.update({
            'product': product
        })

        item.pop('itemId')

    resp = Response(json.dumps(items, cls=CompatEncoder), content_type = 'application/json', headers = resp_headers)
    return resp