sagravela commited on
Commit
788b9b3
·
1 Parent(s): 573a0f4

first commit

Browse files
.gitattributes CHANGED
@@ -33,3 +33,5 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ *.data-00000-of-00001 filter=lfs diff=lfs merge=lfs -text
37
+ *.snapshot filter=lfs diff=lfs merge=lfs -text
.gitignore ADDED
@@ -0,0 +1 @@
 
 
1
+ __pycache__
README.md CHANGED
@@ -1,8 +1,8 @@
1
  ---
2
- title: Demo Recs Engine
3
- emoji: 👀
4
- colorFrom: yellow
5
- colorTo: gray
6
  sdk: streamlit
7
  sdk_version: 1.38.0
8
  app_file: app.py
 
1
  ---
2
+ title: Recommender Engine
3
+ emoji: 🤗
4
+ colorFrom: pink
5
+ colorTo: green
6
  sdk: streamlit
7
  sdk_version: 1.38.0
8
  app_file: app.py
app.py ADDED
@@ -0,0 +1,65 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import streamlit as st
2
+ import pandas as pd
3
+ from datetime import datetime
4
+ from inference import Inference
5
+
6
+
7
+ class QueryInputForm:
8
+ def __init__(self):
9
+ # Title of the Streamlit form
10
+ st.title("Query Input Form")
11
+
12
+ # Predefined options for channel and device type
13
+ self.channel_options = [
14
+ 'Paid Social', 'Paid Search - Brand', 'Organic', 'Email - Transactional',
15
+ 'Affiliate', 'Paid Search', 'Direct', 'Referral', 'Email - Marketing',
16
+ 'Paid Search - Brand Reactivation', 'SMS - Marketing', 'Email - Trigger',
17
+ 'Referral - Whitelabel', 'Referral - Merchant', 'Social', 'SMS - Trigger',
18
+ ]
19
+
20
+ self.device_type_options = [
21
+ 'Mobile', 'Desktop', 'Phablet', 'Tablet', '', 'TV',
22
+ 'Portable Media Player', 'Wearable',
23
+ ]
24
+
25
+ # Default values for the form
26
+ self.default_user_id = "b7485193f4e7f5b8ac3c94f71f4456a9"
27
+ self.default_query_text = "pizza"
28
+
29
+ # Initialize the recommender engine
30
+ self.recommender_engine = Inference()
31
+
32
+ def display_form(self):
33
+ # Input fields for user ID, channel, device type, and query text
34
+ self.user_id = st.text_input("User ID", value=self.default_user_id)
35
+ self.channel = st.selectbox("Channel", options=self.channel_options)
36
+ self.device_type = st.selectbox("Device Type", options=self.device_type_options)
37
+ self.query_text = st.text_input("Query Text", value=self.default_query_text)
38
+
39
+ # Submit button
40
+ if st.button("Submit"):
41
+ self.submit()
42
+
43
+ def submit(self):
44
+ # Pass the query information to the recommender engine
45
+ raw_query = {
46
+ 'user_id': self.user_id,
47
+ 'channel': self.channel,
48
+ 'device_type': self.device_type,
49
+ 'query_text': self.query_text,
50
+ 'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
51
+ }
52
+
53
+ # Get recommendations
54
+ self.recommender_engine.get_recommendations(raw_query)
55
+ self.display_recommendations()
56
+
57
+ def display_recommendations(self):
58
+ # Output the recommendations from the inference engine
59
+ st.write("Top recommendations:")
60
+ st.dataframe(self.recommender_engine.recommendations, hide_index=True)
61
+
62
+
63
+ if __name__ == "__main__":
64
+ form = QueryInputForm()
65
+ form.display_form()
inference.py ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import tensorflow as tf
2
+ import os
3
+
4
+
5
+ class Inference():
6
+ def __init__(self):
7
+
8
+ index_path = os.path.join("recommender_model", "index")
9
+ model_path = os.path.join("recommender_model", "model")
10
+ self.index = tf.keras.models.load_model(index_path)
11
+ self.model = tf.keras.models.load_model(model_path)
12
+
13
+ products_path = os.path.join("products")
14
+ self.products = tf.data.Dataset.load(products_path)
15
+
16
+ self.model_product_features = [
17
+ 'product_id', 'category_name', 'merchant_name', 'merchant_city', 'merchant_state', 'merchant_region',
18
+ 'free_shipping', 'is_sold_out', 'editor_pick', 'on_sale', 'product_name', 'price_in_cents', 'reviews'
19
+ ]
20
+
21
+ def get_recommendations(self, raw_query: dict):
22
+ self.query_input = {
23
+ 'user_id': tf.convert_to_tensor(raw_query['user_id'], dtype=tf.string),
24
+ 'channel': tf.convert_to_tensor(raw_query['channel'], dtype=tf.string),
25
+ 'device_type': tf.convert_to_tensor(raw_query['device_type'], dtype=tf.string),
26
+ 'query_text': tf.convert_to_tensor(raw_query['query_text'], dtype=tf.string),
27
+ 'time': tf.convert_to_tensor(raw_query['time'], dtype=tf.string),
28
+ }
29
+
30
+ # Get recommendations. Note that I am expanding the dimension to match the batch size expected by the model
31
+ _, self.top_rec = self.index({k: [v] for k, v in self.query_input.items()})
32
+
33
+ # Filter by product id
34
+ filtered_recs = self.products.filter(self.filter_by_id)
35
+ # Add query input
36
+ query_added_recs = filtered_recs.map(lambda x: {**self.query_input, **x})
37
+ # Get score
38
+ score_added_recs = query_added_recs.batch(8).map(self.get_score).unbatch()
39
+
40
+ # Drop unwanted columns
41
+ recs = score_added_recs.map(self.desired_output)
42
+
43
+ # Order by score
44
+ ordered_recs = self.order_by_score(recs)
45
+
46
+ # Decode values
47
+ self.recommendations = list(map(self.decode_values, ordered_recs))
48
+
49
+ def filter_by_id(self, item):
50
+ return tf.reduce_any(tf.equal(item['product_id'], self.top_rec[0]))
51
+
52
+ def get_score(self, item):
53
+ input_data = {k: v for k, v in item.items() if k in self.model_product_features + list(self.query_input.keys())}
54
+ _, _, score = self.model(input_data)
55
+ item['score'] = score
56
+ return item
57
+
58
+ def desired_output(self, item):
59
+ return {
60
+ 'product_name': item['product_name'],
61
+ 'category_name': item['category_name'],
62
+ 'price_in_cents': item['price_in_cents'],
63
+ 'reviews': item['reviews'],
64
+ 'merchant_name': item['merchant_name'],
65
+ 'merchant_city': item['merchant_city'],
66
+ 'merchant_state': item['merchant_state'],
67
+ 'merchant_region': item['merchant_region'],
68
+ 'free_shipping': item['free_shipping'],
69
+ 'is_sold_out': item['is_sold_out'],
70
+ 'editor_pick': item['editor_pick'],
71
+ 'on_sale': item['on_sale'],
72
+ 'score': item['score']
73
+ }
74
+
75
+ def order_by_score(self, recs):
76
+ rec_list = list(recs.as_numpy_iterator())
77
+
78
+ # Descending order by score
79
+ return sorted(rec_list, key=lambda x: x['score'], reverse=True)
80
+
81
+ def decode_values(self, item):
82
+ for key, value in item.items():
83
+ if isinstance(value, bytes):
84
+ item[key] = value.decode('utf-8')
85
+ if key == 'score':
86
+ item[key] = value[0]
87
+ return item
products/4470620803936518297/00000000.shard/00000000.snapshot ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6b7c352940d95107a6bfc9035e75d6797ad9f18449205e1f718ec3757835065
3
+ size 5133290
products/7776351335182402423/00000000.shard/00000000.snapshot ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6b7c352940d95107a6bfc9035e75d6797ad9f18449205e1f718ec3757835065
3
+ size 5133290
products/dataset_spec.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a6e96cdf4683d9d39dfc6f9479faacaf67e96d9e82abf87731908391a2b1b55d
3
+ size 411
products/snapshot.metadata ADDED
@@ -0,0 +1 @@
 
 
1
+ 4470620803936518297�ޘ��� *  0�H�>
recommender_model/index/fingerprint.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:5fa78657cc3dc078663289fc7e2e2269269e30855679fa8dd8fe6ecc1cc784e3
3
+ size 56
recommender_model/index/keras_metadata.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:feef2be744045e53d44c33c63dd223c3d14a1fe0d57db1044a5d8c3506bf8fb4
3
+ size 43956
recommender_model/index/saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:54aa27f06f6c7bc92493e16f14fdc4c0d5a4418e68f5a7be3900a986167cd345
3
+ size 1340342
recommender_model/index/variables/variables.data-00000-of-00001 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:a8c214a6184250fe8cd49e17760e466ae3aafd7d952cd92338d754183dca2fea
3
+ size 21942235
recommender_model/index/variables/variables.index ADDED
Binary file (1.02 kB). View file
 
recommender_model/model/fingerprint.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:73dd5eb15d19b0f7ba30b2974616716ad220ab358f4f5a0ccb63f4a1abb91441
3
+ size 56
recommender_model/model/keras_metadata.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:0f5a6e2a033359beeaa8ea2aaa03b19a37affcc7b0ee9be7383acf6d487bec32
3
+ size 114938
recommender_model/model/saved_model.pb ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:9ac62f41927afd25da1c115920addf4834d98db64c5a11dbfcb48307e3b5edd5
3
+ size 2888902
recommender_model/model/variables/variables.data-00000-of-00001 ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:469452fc885fbaa976c2fc4867844c1b77258c1f4265a75699fc2a29316091fe
3
+ size 37821029
recommender_model/model/variables/variables.index ADDED
Binary file (2.75 kB). View file
 
requirements.txt ADDED
@@ -0,0 +1,2 @@
 
 
 
1
+ pandas
2
+ tensorflow==2.15.1