Spaces:
Sleeping
Sleeping
| class Explainer: | |
| def __init__(self, products_df, users_df): | |
| self.products = products_df | |
| self.users = users_df | |
| self._product_cache = {} | |
| self._user_cache = {} | |
| for _, row in products_df.iterrows(): | |
| self._product_cache[row["product_id"]] = row | |
| for _, row in users_df.iterrows(): | |
| self._user_cache[row["user_id"]] = row | |
| def _get_product(self, product_id): | |
| return self._product_cache.get(product_id, {}) | |
| def _get_user(self, user_id): | |
| return self._user_cache.get(user_id, {}) | |
| def _fmt_score(self, score): | |
| if score >= 0.9: | |
| return "Excellent match" | |
| elif score >= 0.7: | |
| return "Strong match" | |
| elif score >= 0.5: | |
| return "Good match" | |
| elif score >= 0.3: | |
| return "Moderate match" | |
| else: | |
| return "Partial match" | |
| def _pref_list(self, user, key): | |
| raw = user.get(key, "") | |
| if raw is None or isinstance(raw, float): | |
| return [] | |
| if isinstance(raw, str): | |
| return [p.strip() for p in raw.split(",") if p.strip()][:2] | |
| return list(raw)[:2] if raw else [] | |
| def explain_cf(self, method, user_id, product_id, details=None): | |
| product = self._get_product(product_id) | |
| user = self._get_user(user_id) | |
| pname = product.get("name", f"Item #{product_id}") | |
| cat = product.get("category", "") | |
| brand = product.get("brand", "") | |
| price = product.get("price", 0) | |
| details = details or {} | |
| sim = min(details.get('sim_score', 0), 1.0) | |
| pref_cats = self._pref_list(user, "preferred_categories") | |
| templates = { | |
| "user_based": f"Users with {cat} taste also liked {pname}", | |
| "item_based": f"Matches your {cat} preferences — similar to items you've rated highly", | |
| "svd": f"Fits your profile: {brand}'s {cat} — top latent factor match" if brand and cat else f"Fits your profile: {cat} — top latent factor match", | |
| "knn": f"Popular among peers who also like {cat}" if cat else f"Popular among users with similar taste", | |
| "slope_one": f"Frequently chosen by users who liked the same {cat} products" if cat else f"Frequently chosen by users with your taste", | |
| } | |
| return templates.get(method, f"Recommended based on collaborative filtering") | |
| def explain_content(self, method, user_id, product_id, details=None): | |
| product = self._get_product(product_id) | |
| user = self._get_user(user_id) | |
| pname = product.get("name", f"Item #{product_id}") | |
| cat = product.get("category", "") | |
| brand = product.get("brand", "") | |
| sub = product.get("subcategory", "") | |
| details = details or {} | |
| score = min(details.get('score', 0), 1.0) | |
| pref_cats = self._pref_list(user, "preferred_categories") | |
| templates = { | |
| "tfidf": f"Content matches: {cat} / {sub} — strongly aligns with your past likes" if sub else f"Content matches your preferred {cat} items", | |
| "feature_match": f"Matches your preferences: {cat}, {brand}" if brand else f"Matches your preferred category: {cat}", | |
| } | |
| return templates.get(method, f"Recommended based on item features") | |
| def explain_knowledge(self, method, user_id, product_id, details=None): | |
| product = self._get_product(product_id) | |
| user = self._get_user(user_id) | |
| details = details or {} | |
| pname = product.get("name", f"Item #{product_id}") | |
| cat = product.get("category", "") | |
| brand = product.get("brand", "") | |
| price = product.get("price", 0) | |
| budget_max = details.get("budget_max", 0) | |
| templates = { | |
| "constraint": f"Fits your criteria: ${price:.0f} within budget · {cat} · {brand}" if brand else f"Fits your criteria: ${price:.0f} within budget · {cat}", | |
| "rule": f"{cat} buyers commonly add {pname} — cross-sell match" if cat else f"Customers also purchased {pname}", | |
| "utility": f"Top utility score: {cat} × {brand} matches your preference weights" if brand else f"Top utility score: {cat} matches your preference weights", | |
| } | |
| return templates.get(method, f"Recommended based on your requirements") | |
| def get_explanation(self, approach, method, user_id, product_id, details=None): | |
| if approach == "cf": | |
| return self.explain_cf(method, user_id, product_id, details) | |
| elif approach == "content": | |
| return self.explain_content(method, user_id, product_id, details) | |
| elif approach == "knowledge": | |
| return self.explain_knowledge(method, user_id, product_id, details) | |
| return "" | |