moved to gradio
Browse files- README.md +3 -3
- app.py +84 -30
- inference.py +17 -15
README.md
CHANGED
@@ -3,12 +3,12 @@ title: Recommendation Engine
|
|
3 |
emoji: π
|
4 |
colorFrom: green
|
5 |
colorTo: blue
|
6 |
-
sdk:
|
7 |
-
sdk_version:
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: apache-2.0
|
11 |
-
tags: ["
|
12 |
---
|
13 |
|
14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
3 |
emoji: π
|
4 |
colorFrom: green
|
5 |
colorTo: blue
|
6 |
+
sdk: gradio
|
7 |
+
sdk_version: 5.7.1
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
license: apache-2.0
|
11 |
+
tags: ["recommendation system", "tensorflow", "deep learning"]
|
12 |
---
|
13 |
|
14 |
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
CHANGED
@@ -1,14 +1,12 @@
|
|
1 |
-
import streamlit as st
|
2 |
import pandas as pd
|
|
|
3 |
from datetime import datetime
|
4 |
-
from inference import
|
|
|
5 |
|
6 |
|
7 |
class QueryInputForm:
|
8 |
def __init__(self):
|
9 |
-
# Title of the Streamlit form
|
10 |
-
st.title("E-Commerce Recommendation Engine Demo")
|
11 |
-
|
12 |
# Predefined options for channel and device type
|
13 |
self.channel_options = [
|
14 |
'Paid Social', 'Paid Search - Brand', 'Organic', 'Email - Transactional',
|
@@ -26,38 +24,94 @@ class QueryInputForm:
|
|
26 |
self.default_query_text = "pizza"
|
27 |
|
28 |
# Initialize the recommender engine
|
29 |
-
self.recommender_engine =
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
self.channel = st.selectbox("Channel", options=self.channel_options)
|
34 |
-
self.device_type = st.selectbox("Device Type", options=self.device_type_options)
|
35 |
-
self.query_text = st.text_input("Query Text", value=self.default_query_text)
|
36 |
-
|
37 |
-
# Submit button
|
38 |
-
if st.button("Submit"):
|
39 |
-
self.submit()
|
40 |
-
|
41 |
-
def submit(self):
|
42 |
# Pass the query information to the recommender engine
|
43 |
raw_query = {
|
44 |
-
'user_id': "new_user",
|
45 |
-
'channel':
|
46 |
-
'device_type':
|
47 |
-
'query_text':
|
48 |
-
'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"),
|
49 |
}
|
50 |
|
51 |
# Get recommendations
|
52 |
self.recommender_engine.get_recommendations(raw_query)
|
53 |
-
self.
|
|
|
|
|
|
|
|
|
54 |
|
55 |
-
|
56 |
-
|
57 |
-
|
58 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
59 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
60 |
|
61 |
if __name__ == "__main__":
|
62 |
-
|
63 |
-
form.display_form()
|
|
|
|
|
1 |
import pandas as pd
|
2 |
+
import gradio as gr
|
3 |
from datetime import datetime
|
4 |
+
from inference import RecommendationEngine
|
5 |
+
import spaces
|
6 |
|
7 |
|
8 |
class QueryInputForm:
|
9 |
def __init__(self):
|
|
|
|
|
|
|
10 |
# Predefined options for channel and device type
|
11 |
self.channel_options = [
|
12 |
'Paid Social', 'Paid Search - Brand', 'Organic', 'Email - Transactional',
|
|
|
24 |
self.default_query_text = "pizza"
|
25 |
|
26 |
# Initialize the recommender engine
|
27 |
+
self.recommender_engine = RecommendationEngine()
|
28 |
+
|
29 |
+
@spaces.GPU
|
30 |
+
def get_recommendations(self, channel, device_type, query_text):
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
31 |
# Pass the query information to the recommender engine
|
32 |
raw_query = {
|
33 |
+
'user_id': "new_user", # any user will be considered as a new user
|
34 |
+
'channel': channel,
|
35 |
+
'device_type': device_type,
|
36 |
+
'query_text': query_text,
|
37 |
+
'time': datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f"), # query time
|
38 |
}
|
39 |
|
40 |
# Get recommendations
|
41 |
self.recommender_engine.get_recommendations(raw_query)
|
42 |
+
recommendations_df = pd.DataFrame(self.recommender_engine.recommendations)
|
43 |
+
recommendations_df = recommendations_df.style.format({'Score': '{:.2f}'})
|
44 |
+
# Return the recommendations as a dataframe
|
45 |
+
return gr.update(value=recommendations_df)
|
46 |
+
|
47 |
|
48 |
+
# Instantiate the form
|
49 |
+
form = QueryInputForm()
|
50 |
+
|
51 |
+
# Gradio interface
|
52 |
+
def recommendation_interface(channel, device_type, query_text):
|
53 |
+
return form.get_recommendations(channel, device_type, query_text)
|
54 |
+
|
55 |
+
|
56 |
+
with gr.Blocks() as interface:
|
57 |
+
gr.Markdown("<h1 class='title'>E-Commerce Recommendation Engine Demo</h1>")
|
58 |
+
|
59 |
+
with gr.Row(): # Use Row to place components side by side
|
60 |
+
with gr.Column():
|
61 |
+
channel_dropdown = gr.Dropdown(choices=form.channel_options, label="Channel")
|
62 |
+
device_dropdown = gr.Dropdown(choices=form.device_type_options, label="Device Type")
|
63 |
+
query_input = gr.Textbox(value=form.default_query_text, label="Query Text")
|
64 |
+
submit_button = gr.Button("Submit", elem_id="submit-button")
|
65 |
+
|
66 |
+
with gr.Column(scale=3):
|
67 |
+
gr.Markdown("<h2>Top Recommendations:</h2>")
|
68 |
+
recommendation_output = gr.Dataframe(
|
69 |
+
show_label=False,
|
70 |
+
headers = [
|
71 |
+
'Score', 'Product Name', 'Category', 'Price (in cents)', 'Reviews',
|
72 |
+
'Merchant', 'City', 'State', 'Region',
|
73 |
+
'Free Shipping', 'Sold Out', 'Editor\'s Pick', 'On Sale',
|
74 |
+
],
|
75 |
+
interactive=False,
|
76 |
+
elem_id="recommendation-table",
|
77 |
+
max_height=400,
|
78 |
+
column_widths=["90px", "350px", "250px", "90px", "90px", "200px", "150px", "150px", "150px", "90px", "90px", "90px", "90px"]
|
79 |
+
)
|
80 |
+
|
81 |
+
submit_button.click(
|
82 |
+
recommendation_interface,
|
83 |
+
inputs=[channel_dropdown, device_dropdown, query_input],
|
84 |
+
outputs=recommendation_output,
|
85 |
+
)
|
86 |
|
87 |
+
# Add custom CSS for styling
|
88 |
+
interface.css = """
|
89 |
+
.title {
|
90 |
+
color: #E76E00;
|
91 |
+
text-align: center;
|
92 |
+
margin: 40px;
|
93 |
+
margin-bottom: 30px !important;
|
94 |
+
font-size: 36px;
|
95 |
+
font-weight: bold;
|
96 |
+
}
|
97 |
+
#submit-button {
|
98 |
+
background-color: #E76E00;
|
99 |
+
color: white;
|
100 |
+
border: none;
|
101 |
+
padding: 10px 20px;
|
102 |
+
font-size: 16px;
|
103 |
+
border-radius: 5px;
|
104 |
+
cursor: pointer;
|
105 |
+
}
|
106 |
+
#submit-button:hover {
|
107 |
+
background-color: #FF8C00;
|
108 |
+
}
|
109 |
+
#recommendation-table .gradio-header {
|
110 |
+
background-color: #FF8C00; /* Orange header */
|
111 |
+
color: white; /* White text */
|
112 |
+
font-weight: bold; /* Optional: Bold text */
|
113 |
+
}
|
114 |
+
"""
|
115 |
|
116 |
if __name__ == "__main__":
|
117 |
+
interface.launch()
|
|
inference.py
CHANGED
@@ -2,7 +2,7 @@ import tensorflow as tf
|
|
2 |
import os
|
3 |
|
4 |
|
5 |
-
class
|
6 |
def __init__(self):
|
7 |
self.product_features = [
|
8 |
'product_id', 'product_name', 'category_name',
|
@@ -60,30 +60,32 @@ class Inference():
|
|
60 |
|
61 |
def desired_output(self, item):
|
62 |
return {
|
63 |
-
'
|
64 |
-
'
|
65 |
-
'
|
66 |
-
'
|
67 |
-
'
|
68 |
-
'
|
69 |
-
'
|
70 |
-
'
|
71 |
-
'
|
72 |
-
'
|
73 |
-
'
|
74 |
-
'
|
|
|
75 |
}
|
76 |
|
|
|
77 |
def order_by_score(self, recs):
|
78 |
rec_list = list(recs.as_numpy_iterator())
|
79 |
|
80 |
# Descending order by score
|
81 |
-
return sorted(rec_list, key=lambda x: x['
|
82 |
|
83 |
def decode_values(self, item):
|
84 |
for key, value in item.items():
|
85 |
if isinstance(value, bytes):
|
86 |
item[key] = value.decode('utf-8')
|
87 |
-
if key == '
|
88 |
item[key] = value[0]
|
89 |
return item
|
|
|
2 |
import os
|
3 |
|
4 |
|
5 |
+
class RecommendationEngine():
|
6 |
def __init__(self):
|
7 |
self.product_features = [
|
8 |
'product_id', 'product_name', 'category_name',
|
|
|
60 |
|
61 |
def desired_output(self, item):
|
62 |
return {
|
63 |
+
'Score': item['score'],
|
64 |
+
'Product Name': item['product_name'],
|
65 |
+
'Category': item['category_name'],
|
66 |
+
'Price (in cents)': item['price_in_cents'],
|
67 |
+
'Reviews': item['reviews'],
|
68 |
+
'Merchant': item['merchant_name'],
|
69 |
+
'City': item['merchant_city'],
|
70 |
+
'State': item['merchant_state'],
|
71 |
+
'Region': item['merchant_region'],
|
72 |
+
'Free Shipping': item['free_shipping'],
|
73 |
+
'Sold Out': item['is_sold_out'],
|
74 |
+
'Editor\'s Pick': item['editor_pick'],
|
75 |
+
'On Sale': item['on_sale']
|
76 |
}
|
77 |
|
78 |
+
|
79 |
def order_by_score(self, recs):
|
80 |
rec_list = list(recs.as_numpy_iterator())
|
81 |
|
82 |
# Descending order by score
|
83 |
+
return sorted(rec_list, key=lambda x: x['Score'], reverse=True)
|
84 |
|
85 |
def decode_values(self, item):
|
86 |
for key, value in item.items():
|
87 |
if isinstance(value, bytes):
|
88 |
item[key] = value.decode('utf-8')
|
89 |
+
if key == 'Score':
|
90 |
item[key] = value[0]
|
91 |
return item
|