mirror of
https://github.com/narrrl/holy-flavor-rater.git
synced 2026-11-03 16:41:27 +01:00
added anon metrics to recommendations
This commit is contained in:
1 parent
daeda71eca
commit
3757b784de
23 files changed
+1544
-66
No files matched your search
@@ -59,8 +59,10 @@ export interface Recommendation {
|
||||
predicted_score: number;
|
||||
/** "N tasters like you" count (cf) or rating count (popular). */
|
||||
contributing_neighbours: number;
|
||||
/** "cf" | "popular" — frontend picks the reason copy. */
|
||||
reason: 'cf' | 'popular';
|
||||
/** Anonymous shop reviews (reviews.io) backing this flavor; 0 if none. */
|
||||
external_reviews: number;
|
||||
/** "cf" | "popular" | "shop" (no community ratings yet — shop reviews only). */
|
||||
reason: 'cf' | 'popular' | 'shop';
|
||||
}
|
||||
|
||||
export interface DashboardData {
|
||||
@@ -81,8 +83,10 @@ export interface SimilarFlavor {
|
||||
average_rating: number | null;
|
||||
is_legacy: boolean;
|
||||
is_available: boolean;
|
||||
/** Adjusted-cosine similarity to the target flavor, in (0, 1]. */
|
||||
/** Blended, confidence-discounted similarity. Ranking only — not a "% match". */
|
||||
similarity: number;
|
||||
/** Users who rated both this flavor and the target. */
|
||||
co_raters: number;
|
||||
/** Anonymous shop reviewers who liked both this flavor and the target. */
|
||||
external_co_reviewers: number;
|
||||
}
|
||||
@@ -40,6 +40,7 @@ const resources = {
|
||||
recHeading: 'Tasters like you loved',
|
||||
recReasonCf: '{{count}} tasters like you',
|
||||
recReasonPopular: 'Popular pick',
|
||||
recReasonShop: '{{count}} shop buyers',
|
||||
predictedForYou: 'Predicted for you',
|
||||
myRatings: 'My Ratings',
|
||||
missing: 'Missing',
|
||||
@@ -179,6 +180,9 @@ const resources = {
|
||||
similarHeading: 'People who liked this also liked',
|
||||
similarCoRaters: '{{count}} rated both',
|
||||
similarTooltip: 'Tasters who rated both this flavor and the one above',
|
||||
similarShopCoReviewers: '{{count}} shop buyers liked both',
|
||||
similarShopTooltip:
|
||||
'Nobody here has rated both yet — this pairing comes from anonymous shop reviews',
|
||||
rateThisFlavor: 'Rate this flavor',
|
||||
scoreLabel: 'Your score, 1 to 10',
|
||||
submitReview: 'Submit Review',
|
||||
@@ -603,6 +607,7 @@ const resources = {
|
||||
recHeading: 'Tester wie du mochten',
|
||||
recReasonCf: '{{count}} Tester wie du',
|
||||
recReasonPopular: 'Beliebte Wahl',
|
||||
recReasonShop: '{{count}} Shop-Käufer',
|
||||
predictedForYou: 'Für dich vorhergesagt',
|
||||
myRatings: 'Meine Bewertungen',
|
||||
missing: 'Fehlend',
|
||||
@@ -742,6 +747,9 @@ const resources = {
|
||||
similarHeading: 'Wer das mochte, mochte auch',
|
||||
similarCoRaters: '{{count}} bewerteten beide',
|
||||
similarTooltip: 'Tester, die diese Sorte und die obige bewertet haben',
|
||||
similarShopCoReviewers: '{{count}} Shop-Käufer mochten beide',
|
||||
similarShopTooltip:
|
||||
'Hier hat noch niemand beide bewertet — diese Paarung stammt aus anonymen Shop-Bewertungen',
|
||||
rateThisFlavor: 'Diese Sorte bewerten',
|
||||
scoreLabel: 'Deine Bewertung, 1 bis 10',
|
||||
submitReview: 'Bewertung abschicken',
|
||||
|
||||
@@ -15,7 +15,9 @@ export interface RecommendationCardProps {
|
||||
|
||||
/**
|
||||
* A single recommended flavor. The reason chip is **count-only** (no neighbour
|
||||
* names, per product decision): CF → "N tasters like you", popularity → "Popular".
|
||||
* names, per product decision): CF → "N tasters like you", popularity →
|
||||
* "Popular", shop → "N shop buyers" for flavors nobody here has rated yet, whose
|
||||
* score comes from the anonymous reviews.io feed alone.
|
||||
*/
|
||||
const RecommendationCard: React.FC<RecommendationCardProps> = ({ rec }) => {
|
||||
const { t } = useTranslation();
|
||||
@@ -23,7 +25,9 @@ const RecommendationCard: React.FC<RecommendationCardProps> = ({ rec }) => {
|
||||
const reasonLabel =
|
||||
rec.reason === 'cf'
|
||||
? t('dashboard.recReasonCf', { count: rec.contributing_neighbours })
|
||||
: t('dashboard.recReasonPopular');
|
||||
: rec.reason === 'shop'
|
||||
? t('dashboard.recReasonShop', { count: rec.external_reviews })
|
||||
: t('dashboard.recReasonPopular');
|
||||
|
||||
return (
|
||||
<GlassCard
|
||||
|
||||
@@ -81,12 +81,26 @@ const SimilarCard: React.FC<{ item: SimilarFlavor }> = ({ item }) => {
|
||||
<Typography variant="caption" color="text.secondary" display="block" sx={{ mb: 1 }}>
|
||||
{t(`categories.${item.category_slug}`, { defaultValue: item.category_name })}
|
||||
</Typography>
|
||||
<Tooltip title={t('flavorDetail.similarTooltip')}>
|
||||
{/* Pairs the community hasn't co-rated yet can still surface, backed by
|
||||
anonymous shop reviewers — don't claim "0 rated both" for those. */}
|
||||
<Tooltip
|
||||
title={t(
|
||||
item.co_raters > 0
|
||||
? 'flavorDetail.similarTooltip'
|
||||
: 'flavorDetail.similarShopTooltip',
|
||||
)}
|
||||
>
|
||||
<Chip
|
||||
size="small"
|
||||
icon={<GroupsIcon />}
|
||||
label={t('flavorDetail.similarCoRaters', { count: item.co_raters })}
|
||||
color="primary"
|
||||
label={
|
||||
item.co_raters > 0
|
||||
? t('flavorDetail.similarCoRaters', { count: item.co_raters })
|
||||
: t('flavorDetail.similarShopCoReviewers', {
|
||||
count: item.external_co_reviewers,
|
||||
})
|
||||
}
|
||||
color={item.co_raters > 0 ? 'primary' : 'default'}
|
||||
variant="outlined"
|
||||
sx={{ fontWeight: 700, maxWidth: '100%' }}
|
||||
/>
|
||||
|
||||
Reference in new issue
Block a user