Spaces:
Running
Running
import logging | |
from flask import Flask, render_template, request | |
from model import Model | |
import plotly.graph_objects as go | |
model = Model() | |
app = Flask(__name__) | |
logging.basicConfig(level=logging.DEBUG) | |
PRED_CACHE = dict() | |
def index(): | |
return render_template('index.html') | |
def test_users(): | |
model.run_predictions_on_full_test() | |
model.prepare_user_details() | |
# Options for the dropdown menu | |
user_details = model.user_details['top_books'].to_dict() | |
return render_template('test_users.html', user_details=user_details) | |
def process(chosen_user): | |
# Get book recommendations | |
if chosen_user in PRED_CACHE: | |
preds_df = PRED_CACHE[chosen_user] | |
else: | |
preds_df = model.get_user_predictions(chosen_user) | |
PRED_CACHE[chosen_user] = preds_df | |
if preds_df is None: | |
return "No predictions hit!" | |
# Get Pandas series of recommended books | |
recommended_books = preds_df.set_index('book_id')[['title_without_series', 'target', 'final_score']] | |
recommended_books['is_recommended'] = recommended_books['final_score'] >= 0.45 | |
# Use Bootstrap's List to make a list of recommended books and a button for each book, routing to '/explain/book_id' | |
# Render the page with recommended books | |
return render_template( | |
'recommended_books.html', | |
chosen_user=chosen_user, | |
recommended_books=recommended_books | |
) | |
def explain(chosen_user, chosen_book): | |
# Get book recommendations | |
# This should be a cache hit since we're coming from `process`, but we include the else path just in case | |
if chosen_user in PRED_CACHE: | |
preds_df = PRED_CACHE[chosen_user] | |
else: | |
preds_df = model.get_user_predictions(chosen_user) | |
PRED_CACHE[chosen_user] = preds_df | |
# Get Pandas series of recommended books | |
recommended_books = preds_df.set_index('book_id')[['title_without_series', 'target', 'final_score']] | |
recommended_books['is_recommended'] = recommended_books['final_score'] >= 0.45 | |
# book_details = model.all_books[model.all_books['book_id'] == book_id] | |
logging.info(f"Generating explanation for user:{chosen_user}, book:{chosen_book}") | |
book_df = preds_df.set_index('book_id').loc[chosen_book] | |
waterfall_cols = [ | |
'intercept', | |
'clus_score', | |
'gen_score', | |
'desc_score', | |
'rev_score', | |
'user_score', | |
'tit_score', | |
'final_score' | |
] | |
waterfall_display_cols = [ | |
'Intercept', | |
'Book Clustering Similarity', | |
'Genre Similarity', | |
'Description Topic Similarity', | |
'Review Vector Similarity', | |
'User Clustering Similarity', | |
'Title Vector Similarity', | |
'Sum of Sub-Model Scores' | |
] | |
waterfall_data = book_df[waterfall_cols].tolist() | |
fig = go.Figure( | |
go.Waterfall( | |
name='Recommendation explanation', | |
orientation='h', | |
measure=['relative', 'relative', 'relative', 'relative', 'relative', 'relative', 'relative', 'total'], | |
y=waterfall_display_cols, | |
x=waterfall_data | |
) | |
) | |
fig_html = fig.to_html(full_html=False) | |
top_model_idx = waterfall_cols.index(book_df[waterfall_cols[:-1]].astype(float).idxmax()) | |
top_model = waterfall_display_cols[top_model_idx] | |
explanation_str = f"The highest contributing model was {top_model}. " | |
if book_df['final_score'] >= 0.45: | |
reasons = [ | |
'-', # intercept | |
'it is similar to books you enjoyed in terms of book statistics like popularity and page count.', | |
'it is similar to books you enjoyed in terms of overlapping genres.', | |
'it is similar to books you enjoyed in terms of description similarity.', | |
'it is similar to books you enjoyed in terms of review similarity.', | |
'other users similar to you in taste enjoyed this book.', | |
'it is similar to books you enjoyed in terms of title similarity.', | |
] | |
explanation_str += "This means that this book was recommended since " | |
explanation_str += reasons[top_model_idx] | |
else: | |
explanation_str += "However, the confidence score is below the threshold of 0.45, so it is not recommended." | |
score_sum = f"{sum(waterfall_data[:-1]):.5f}" | |
final_score = f"{book_df['final_score']:.5f}" | |
return render_template( | |
'recommended_books.html', | |
chosen_user=chosen_user, | |
recommended_books=recommended_books, | |
render_explanation='true', | |
fig=fig_html, | |
score_sum=score_sum, | |
final_score=final_score, | |
explanation_str=explanation_str | |
) | |
if __name__ == '__main__': | |
app.run(debug=True) | |