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
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