Skip to main content

Gender Affinity System

Location: app/api/chat/services/gender-affinity.ts
Last Updated: December 2025
Status: Production


Overview

The Gender Affinity System provides gender-aware scoring for gift recommendations, improving relevance by adjusting category and product type rankings based on the recipient's gender.

Key Capabilities

  • Gender detection - Identifies recipient gender from Estonian and English keywords
  • Category affinity scoring - 0-100 scores for male/female appropriateness per category
  • Product type affinity scoring - Similar scoring at the product type level
  • Boost multiplier calculation - Converts affinity scores to ranking multipliers (0.5×-1.8×)
  • Hint enhancement - Automatically suggests gender-appropriate categories

Design Philosophy

Soft Boosting > Hard Filtering

Unlike age-based cultural filtering (which hard-rejects inappropriate products), gender affinity uses soft scoring boosts. Products are never excluded based on gender—they're simply ranked higher or lower based on statistical appropriateness.


Architecture

System Flow

Integration Point

Gender affinity scoring is applied in the Search Orchestrator (Phase 4.5), after Stage B funnel filtering and after LLM reranking:


Affinity Score System

Score Ranges

Affinity scores range from 0-100, representing how appropriate a category/product type is for each gender:

Category Gender Affinity

Categories are scored based on typical Estonian gift-giving patterns and cultural norms:

Strong Female Affinity (85-100)

CategoryMale ScoreFemale ScoreReasoning
Ehted (Jewelry)1595Jewelry typically female
Kosmeetika ja kehahooldus2092Cosmetics strongly female
Ilutarvikud (Beauty items)1893Beauty items strongly female
Komeetikakotid (Makeup bags)1095Highly female
Käekellad (Watches)4588Moderate to high female
Muud kotid (Bags)3085Female leaning

Moderate Female Affinity (70-85)

CategoryMale ScoreFemale ScoreReasoning
Aksessuaarid4575Accessories moderate female
Küünlad ja lõhnastajad4078Candles/fragrances female leaning
Kodutekstiil4572Home textiles moderate female
Psühholoogia/psühhiaatria4872Psychology female leaning
Eneseabi (Self-help)3878Self-help female leaning

Strong Male Affinity (85-100)

CategoryMale ScoreFemale ScoreReasoning
Autod, lennukid, laevad9220Vehicles strongly male
Ehitus, remont ja puutöö9025Construction/DIY strongly male
Muu sport ja tegevused8845Sports items strongly male
Kalandus, jahindus, matkamine8825Outdoor/survival strongly male
Tehnika8535Tech items strongly male
Arvutid ja programmeerimine8530Programming strongly male
Merendus ja veesport8240Water sports strongly male

Moderate Male Affinity (70-85)

CategoryMale ScoreFemale ScoreReasoning
Mänguautod (Toy cars)8035Toy cars strongly male
Grillimistarvikud7842Grilling moderate male
Ulme (Sci-fi)7545Sci-fi male leaning
Konstruktorid7545Construction toys male leaning
Aiandus ja talupidamine7250Gardening moderate male

Neutral/Unisex (50-70)

CategoryMale ScoreFemale ScoreReasoning
Kinkekaart (Gift cards)5555Perfectly unisex
Lastekirjandus5555Children books unisex
Lastemängud5555Children toys unisex
Raamat (Books)6065Slight female lean
Film6263Unisex
Muusika5860Unisex
Mängud (Games)6555Slight male lean
Kingitused (Gifts)5560Slight female lean

Product Type Gender Affinity

Higher-level product type scoring:

Product TypeMale ScoreFemale Score
Ilu ja stiil2092
Tehnika8535
Raamat5865
Mängud6555
Kodu ja aed5068
Kingitused4868
Film6060
Muusika5860
Kontorikaup5558
Kinkekaart5555

Boost Multiplier Calculation

The calculateGenderBoostMultiplier() function converts affinity scores to ranking multipliers:

Multiplier Formula

function calculateGenderBoostMultiplier(affinityScore: number): number {
if (affinityScore < 30) {
return 0.5; // Strong opposite gender
} else if (affinityScore < 50) {
return 0.7 + ((affinityScore - 30) / 20) * 0.3; // 0.7 to 1.0
} else if (affinityScore < 70) {
return 1.0; // Neutral
} else if (affinityScore < 85) {
return 1.0 + ((affinityScore - 70) / 15) * 0.3; // 1.0 to 1.3
} else {
return 1.3 + ((affinityScore - 85) / 15) * 0.5; // 1.3 to 1.8
}
}

Example Calculations

CategoryGenderAffinity ScoreMultiplierEffect
Ehted (Jewelry)female951.8×Strong boost
Ehted (Jewelry)male150.5×Strong reduce
Tehnika (Tech)male851.3×Moderate boost
Raamat (Books)female651.0×Neutral
Kinkekaarteither551.0×Neutral

Gender Detection

Detection Flow

Supported Patterns

Male Indicators (Estonian)

PatternMeaning
mees, meheleman, to a man
poiss, poisileboy, to a boy
isa, isalefather, to father
vend, vennalebrother, to brother
poeg, pojaleson, to son
vanaisagrandfather
onuuncle

Male Indicators (English)

PatternMeaning
man, boymale recipients
father, dadfather figures
brother, sonmale family
grandfather, uncleextended family
husband, boyfriend, bfpartners

Female Indicators (Estonian)

PatternMeaning
naine, naiselewoman, to a woman
tüdruk, tüdrukulegirl, to a girl
ema, emalemother, to mother
õde, õelesister, to sister
tütar, tütreledaughter, to daughter
vanaemagrandmother
tädiaunt
sõbrannafemale friend

Female Indicators (English)

PatternMeaning
woman, girlfemale recipients
mother, mommother figures
sister, daughterfemale family
grandmother, auntextended family
wife, girlfriend, gfpartners

Unisex Indicators

PatternMeaning
laps, lapselechild (gender neutral)
sõber, sõbralefriend (gender neutral in Estonian)
kolleeg, kolleegilecolleague

Hint Enhancement Functions

enhanceCategoryHintsWithGender()

Adds gender-appropriate categories to existing hints:

Example Usage

// Female recipient with no existing hints
enhanceCategoryHintsWithGender([], 'female', 10);
// Returns: ['Ehted', 'Ilutarvikud', 'Kosmeetika ja kehahooldus',
// 'Komeetikakotid', 'Käekellad', 'Muud kotid', ...]

// Male recipient with existing hints
enhanceCategoryHintsWithGender(['Raamat'], 'male', 5);
// Returns: ['Raamat', 'Autod, lennukid, laevad', 'Ehitus, remont ja puutöö',
// 'Muu sport ja tegevused', 'Kalandus, jahindus, matkamine']

API Reference

Types

type RecipientGender = 'male' | 'female' | 'unisex' | 'unknown';

interface CategoryAffinity {
category: string;
maleAffinity: number; // 0-100
femaleAffinity: number; // 0-100
reasoning?: string;
}

interface ProductTypeAffinity {
productType: string;
maleAffinity: number; // 0-100
femaleAffinity: number; // 0-100
reasoning?: string;
}

Functions

detectGenderFromRecipient(recipient: string): RecipientGender

Detects gender from recipient keywords.

detectGenderFromRecipient('mehele');      // 'male'
detectGenderFromRecipient('emale'); // 'female'
detectGenderFromRecipient('sõbrale'); // 'unisex'
detectGenderFromRecipient(''); // 'unisex'

getCategoryGenderAffinity(category: string, gender: RecipientGender): number

Returns affinity score (0-100) for a category.

getCategoryGenderAffinity('Ehted', 'female');  // 95
getCategoryGenderAffinity('Ehted', 'male'); // 15
getCategoryGenderAffinity('Ehted', 'unisex'); // 60 (neutral)

getProductTypeGenderAffinity(productType: string, gender: RecipientGender): number

Returns affinity score (0-100) for a product type.

getProductTypeGenderAffinity('Tehnika', 'male');    // 85
getProductTypeGenderAffinity('Ilu ja stiil', 'female'); // 92

calculateGenderBoostMultiplier(affinityScore: number): number

Converts affinity score to ranking multiplier.

calculateGenderBoostMultiplier(95);  // 1.8
calculateGenderBoostMultiplier(15); // 0.5
calculateGenderBoostMultiplier(60); // 1.0

getSuggestedCategoriesForGender(gender: RecipientGender, limit?: number): string[]

Returns top categories for a gender (score >= 70).

getSuggestedCategoriesForGender('female', 5);
// ['Ehted', 'Ilutarvikud', 'Kosmeetika ja kehahooldus', ...]

getSuggestedCategoriesForGender('male', 5);
// ['Autod, lennukid, laevad', 'Ehitus, remont ja puutöö', ...]

enhanceCategoryHintsWithGender(existingHints: string[], gender: RecipientGender, maxTotal?: number): string[]

Enhances hint list with gender-appropriate suggestions.

enhanceProductTypeHintsWithGender(existingHints: string[], gender: RecipientGender, maxTotal?: number): string[]

Enhances product type hints with gender-appropriate suggestions.


Integration Examples

Context Orchestrator Integration

// In extract-context.ts
import { detectGenderFromRecipient } from '../services/gender-affinity';

// During context extraction
const recipientGender = detectGenderFromRecipient(context.recipient);
context.recipientGender = recipientGender;

Search Orchestrator Integration

// In search-orchestrator.ts
import {
getCategoryGenderAffinity,
calculateGenderBoostMultiplier
} from '../services/gender-affinity';

// Phase 4.5: Apply gender boost
if (giftContext.recipientGender && giftContext.recipientGender !== 'unisex') {
for (const product of products) {
const affinity = getCategoryGenderAffinity(
product.csv_category,
giftContext.recipientGender
);
const multiplier = calculateGenderBoostMultiplier(affinity);
product.score *= multiplier;
}
}

Design Rationale

Why Soft Boosting (not Hard Filtering)?

ApproachProsCons
Hard FilteringGuarantees gender-appropriate resultsMay exclude valid gifts; too restrictive
Soft BoostingPreserves all options; allows exceptionsMay surface some less-typical gifts

Decision: Soft boosting is preferred because:

  1. Gift preferences are statistical, not absolute - some men like jewelry, some women like tech
  2. Discovery - Users may want non-typical gifts
  3. Edge cases - "Gift for my wife who loves fishing" should still show fishing gear

Why 0-100 Scale?

  • Intuitive - Easy to understand (percentage-like)
  • Granular - Allows fine-tuning without redesign
  • Mappable - Converts cleanly to multipliers

Why Estonian-First Design?

The affinity scores are based on Estonian gift-giving patterns, which may differ from other markets:

  • Estonian culture has distinct gender expectations for certain categories
  • Local category names (in Estonian) are used directly
  • Supports both Estonian and English recipient keywords


Appendix: Full Category Affinity Table

CategoryMaleFemaleType
Ehted1595Strong F
Kosmeetika ja kehahooldus2092Strong F
Ilutarvikud1893Strong F
Käekellad4588Strong F
Muud kotid3085Strong F
Komeetikakotid1095Strong F
Aksessuaarid4575Moderate F
Küünlad ja lõhnastajad4078Moderate F
Kodutekstiil4572Moderate F
Värviraamatud täiskasvanutele3570Moderate F
Autod, lennukid, laevad, mootorrattad9220Strong M
Ehitus, remont ja puutöö9025Strong M
Muu sport ja tegevused8845Strong M
Kalandus, jahindus, matkamine ja ellujäämine8825Strong M
Tehnika8535Strong M
Arvutid ja programmeerimine8530Strong M
Merendus ja veesport8240Strong M
Mänguautod8035Moderate M
Grillimistarvikud7842Moderate M
Ulme7545Moderate M
Konstruktorid7545Moderate M
Aiandus ja talupidamine7250Moderate M
Raamat6065Neutral
Film6263Neutral
Muusika5860Neutral
Mängud6555Neutral
Kinkekaart5555Neutral
Kingitused5560Neutral
Lastekirjandus5555Neutral
Lastemängud5555Neutral
Nukud2585Strong F
Kaasaegne romantika2090Strong F
Psühholoogia/psühhiaatria4872Moderate F
Eneseabi3878Moderate F
Eneseareng4275Moderate F
Krimi ja põnevus6862Neutral
Fantaasia6560Neutral
Ajaloolised isikud ja elulood6558Neutral

Document Version: 1.0
Last Reviewed: December 3, 2025
Owner: Search & Relevance Team