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)
| Category | Male Score | Female Score | Reasoning |
|---|---|---|---|
Ehted (Jewelry) | 15 | 95 | Jewelry typically female |
Kosmeetika ja kehahooldus | 20 | 92 | Cosmetics strongly female |
Ilutarvikud (Beauty items) | 18 | 93 | Beauty items strongly female |
Komeetikakotid (Makeup bags) | 10 | 95 | Highly female |
Käekellad (Watches) | 45 | 88 | Moderate to high female |
Muud kotid (Bags) | 30 | 85 | Female leaning |
Moderate Female Affinity (70-85)
| Category | Male Score | Female Score | Reasoning |
|---|---|---|---|
Aksessuaarid | 45 | 75 | Accessories moderate female |
Küünlad ja lõhnastajad | 40 | 78 | Candles/fragrances female leaning |
Kodutekstiil | 45 | 72 | Home textiles moderate female |
Psühholoogia/psühhiaatria | 48 | 72 | Psychology female leaning |
Eneseabi (Self-help) | 38 | 78 | Self-help female leaning |
Strong Male Affinity (85-100)
| Category | Male Score | Female Score | Reasoning |
|---|---|---|---|
Autod, lennukid, laevad | 92 | 20 | Vehicles strongly male |
Ehitus, remont ja puutöö | 90 | 25 | Construction/DIY strongly male |
Muu sport ja tegevused | 88 | 45 | Sports items strongly male |
Kalandus, jahindus, matkamine | 88 | 25 | Outdoor/survival strongly male |
Tehnika | 85 | 35 | Tech items strongly male |
Arvutid ja programmeerimine | 85 | 30 | Programming strongly male |
Merendus ja veesport | 82 | 40 | Water sports strongly male |
Moderate Male Affinity (70-85)
| Category | Male Score | Female Score | Reasoning |
|---|---|---|---|
Mänguautod (Toy cars) | 80 | 35 | Toy cars strongly male |
Grillimistarvikud | 78 | 42 | Grilling moderate male |
Ulme (Sci-fi) | 75 | 45 | Sci-fi male leaning |
Konstruktorid | 75 | 45 | Construction toys male leaning |
Aiandus ja talupidamine | 72 | 50 | Gardening moderate male |
Neutral/Unisex (50-70)
| Category | Male Score | Female Score | Reasoning |
|---|---|---|---|
Kinkekaart (Gift cards) | 55 | 55 | Perfectly unisex |
Lastekirjandus | 55 | 55 | Children books unisex |
Lastemängud | 55 | 55 | Children toys unisex |
Raamat (Books) | 60 | 65 | Slight female lean |
Film | 62 | 63 | Unisex |
Muusika | 58 | 60 | Unisex |
Mängud (Games) | 65 | 55 | Slight male lean |
Kingitused (Gifts) | 55 | 60 | Slight female lean |
Product Type Gender Affinity
Higher-level product type scoring:
| Product Type | Male Score | Female Score |
|---|---|---|
Ilu ja stiil | 20 | 92 |
Tehnika | 85 | 35 |
Raamat | 58 | 65 |
Mängud | 65 | 55 |
Kodu ja aed | 50 | 68 |
Kingitused | 48 | 68 |
Film | 60 | 60 |
Muusika | 58 | 60 |
Kontorikaup | 55 | 58 |
Kinkekaart | 55 | 55 |
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
| Category | Gender | Affinity Score | Multiplier | Effect |
|---|---|---|---|---|
Ehted (Jewelry) | female | 95 | 1.8× | Strong boost |
Ehted (Jewelry) | male | 15 | 0.5× | Strong reduce |
Tehnika (Tech) | male | 85 | 1.3× | Moderate boost |
Raamat (Books) | female | 65 | 1.0× | Neutral |
Kinkekaart | either | 55 | 1.0× | Neutral |
Gender Detection
Detection Flow
Supported Patterns
Male Indicators (Estonian)
| Pattern | Meaning |
|---|---|
mees, mehele | man, to a man |
poiss, poisile | boy, to a boy |
isa, isale | father, to father |
vend, vennale | brother, to brother |
poeg, pojale | son, to son |
vanaisa | grandfather |
onu | uncle |
Male Indicators (English)
| Pattern | Meaning |
|---|---|
man, boy | male recipients |
father, dad | father figures |
brother, son | male family |
grandfather, uncle | extended family |
husband, boyfriend, bf | partners |
Female Indicators (Estonian)
| Pattern | Meaning |
|---|---|
naine, naisele | woman, to a woman |
tüdruk, tüdrukule | girl, to a girl |
ema, emale | mother, to mother |
õde, õele | sister, to sister |
tütar, tütrele | daughter, to daughter |
vanaema | grandmother |
tädi | aunt |
sõbranna | female friend |
Female Indicators (English)
| Pattern | Meaning |
|---|---|
woman, girl | female recipients |
mother, mom | mother figures |
sister, daughter | female family |
grandmother, aunt | extended family |
wife, girlfriend, gf | partners |
Unisex Indicators
| Pattern | Meaning |
|---|---|
laps, lapsele | child (gender neutral) |
sõber, sõbrale | friend (gender neutral in Estonian) |
kolleeg, kolleegile | colleague |
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)?
| Approach | Pros | Cons |
|---|---|---|
| Hard Filtering | Guarantees gender-appropriate results | May exclude valid gifts; too restrictive |
| Soft Boosting ✓ | Preserves all options; allows exceptions | May surface some less-typical gifts |
Decision: Soft boosting is preferred because:
- Gift preferences are statistical, not absolute - some men like jewelry, some women like tech
- Discovery - Users may want non-typical gifts
- 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
Related Documentation
- Cultural Relevance System - Estonian cultural intelligence including gender section
- Deterministic Demographics - Regex-based gender/age extraction
- Gift Category Prioritization - Category ordering system
- Context Extraction - LLM-based context extraction
Appendix: Full Category Affinity Table
| Category | Male | Female | Type |
|---|---|---|---|
| Ehted | 15 | 95 | Strong F |
| Kosmeetika ja kehahooldus | 20 | 92 | Strong F |
| Ilutarvikud | 18 | 93 | Strong F |
| Käekellad | 45 | 88 | Strong F |
| Muud kotid | 30 | 85 | Strong F |
| Komeetikakotid | 10 | 95 | Strong F |
| Aksessuaarid | 45 | 75 | Moderate F |
| Küünlad ja lõhnastajad | 40 | 78 | Moderate F |
| Kodutekstiil | 45 | 72 | Moderate F |
| Värviraamatud täiskasvanutele | 35 | 70 | Moderate F |
| Autod, lennukid, laevad, mootorrattad | 92 | 20 | Strong M |
| Ehitus, remont ja puutöö | 90 | 25 | Strong M |
| Muu sport ja tegevused | 88 | 45 | Strong M |
| Kalandus, jahindus, matkamine ja ellujäämine | 88 | 25 | Strong M |
| Tehnika | 85 | 35 | Strong M |
| Arvutid ja programmeerimine | 85 | 30 | Strong M |
| Merendus ja veesport | 82 | 40 | Strong M |
| Mänguautod | 80 | 35 | Moderate M |
| Grillimistarvikud | 78 | 42 | Moderate M |
| Ulme | 75 | 45 | Moderate M |
| Konstruktorid | 75 | 45 | Moderate M |
| Aiandus ja talupidamine | 72 | 50 | Moderate M |
| Raamat | 60 | 65 | Neutral |
| Film | 62 | 63 | Neutral |
| Muusika | 58 | 60 | Neutral |
| Mängud | 65 | 55 | Neutral |
| Kinkekaart | 55 | 55 | Neutral |
| Kingitused | 55 | 60 | Neutral |
| Lastekirjandus | 55 | 55 | Neutral |
| Lastemängud | 55 | 55 | Neutral |
| Nukud | 25 | 85 | Strong F |
| Kaasaegne romantika | 20 | 90 | Strong F |
| Psühholoogia/psühhiaatria | 48 | 72 | Moderate F |
| Eneseabi | 38 | 78 | Moderate F |
| Eneseareng | 42 | 75 | Moderate F |
| Krimi ja põnevus | 68 | 62 | Neutral |
| Fantaasia | 65 | 60 | Neutral |
| Ajaloolised isikud ja elulood | 65 | 58 | Neutral |
Document Version: 1.0
Last Reviewed: December 3, 2025
Owner: Search & Relevance Team