E-commerce Fashion - Conversational Search Implementation
Complete implementation guide for fashion e-commerce conversational search.
Overview
This example demonstrates how to implement conversational search for a fashion e-commerce platform, focusing on style-aware search, size intelligence, and progressive refinement.
Business Context
Fashion E-commerce Challenges
- Style Complexity: Multiple ways to describe the same item
- Size Variations: Different sizing across brands and countries
- Color Nuances: Subtle color differences and seasonal variations
- Occasion Matching: Finding items for specific events or purposes
- Trend Awareness: Keeping up with fashion trends and seasons
Customer Journey
Customer Intent → Style Discovery → Size Selection → Color Choice → Purchase Decision
Implementation
Step 1: Fashion-Specific Configuration
Create config/fashion_api_mapping.yaml:
# Fashion E-commerce API Configuration
base_url: "https://api.fashionstore.com"
timeout: 30.0
# API Endpoints
api_endpoints:
search: "/api/products/search"
filters: "/api/products/filters"
recommendations: "/api/products/recommendations"
inventory: "/api/products/inventory"
# Fashion-Specific Request Mapping
request_mapping:
# Style and Occasion
style:
api_param: "style"
values: ["casual", "formal", "business", "party", "beach", "workout", "evening"]
occasion:
api_param: "occasion"
values: ["wedding", "interview", "date", "vacation", "office", "gym", "party"]
# Size and Fit
size:
api_param: "size"
values: ["XS", "S", "M", "L", "XL", "XXL", "XXXL"]
fit:
api_param: "fit"
values: ["loose", "tight", "slim", "relaxed", "fitted", "oversized"]
# Color and Pattern
color:
api_param: "color"
values: ["red", "blue", "green", "black", "white", "navy", "beige", "pink"]
pattern:
api_param: "pattern"
values: ["solid", "striped", "polka_dot", "floral", "geometric", "abstract"]
# Price and Brand
price_max:
api_param: "max_price"
price_min:
api_param: "min_price"
brand:
api_param: "brand"
values: ["nike", "adidas", "zara", "h&m", "uniqlo", "levis", "calvin_klein"]
# Response Mapping
response_mapping:
products: "items"
total: "total_count"
filters: "available_filters"
recommendations: "suggested_items"
Step 2: Fashion-Specific NLU Engine
Create fashion_nlu_engine.py:
from recoagent.packages.conversational_search import ContextAwareNLUEngine
import re
class FashionNLUEngine(ContextAwareNLUEngine):
"""Fashion-specific NLU engine with style and size intelligence"""
def __init__(self):
super().__init__()
# Fashion-specific entity patterns
self.fashion_patterns = {
"style": [
r'\b(casual|formal|business|party|beach|workout|evening|sporty|elegant|chic)\b',
r'\b(relaxed|fitted|loose|tight|slim|oversized|comfortable)\b'
],
"occasion": [
r'\b(wedding|interview|date|vacation|office|gym|party|dinner|meeting)\b',
r'\b(work|school|travel|exercise|special event)\b'
],
"size": [
r'\b(xs|small|s|medium|m|large|l|xl|xxl|xxxl)\b',
r'\b(extra small|extra large|petite|plus size|regular)\b'
],
"color": [
r'\b(red|blue|green|black|white|navy|beige|pink|purple|yellow|orange)\b',
r'\b(maroon|burgundy|teal|mint|cream|ivory|charcoal|gray|grey)\b',
r'\b(light blue|dark blue|bright red|deep green|soft pink)\b'
],
"brand": [
r'\b(nike|adidas|zara|h&m|uniqlo|levis|calvin klein|tommy hilfiger)\b',
r'\b(gucci|prada|versace|armani|chanel|dior|louis vuitton)\b'
],
"price": [
r'\$(\d+(?:\.\d{2})?)',
r'(\d+(?:\.\d{2})?)\s*dollars?',
r'under\s*\$?(\d+)',
r'below\s*\$?(\d+)',
r'less\s*than\s*\$?(\d+)',
r'max\s*\$?(\d+)',
r'up\s*to\s*\$?(\d+)',
r'around\s*\$?(\d+)',
r'about\s*\$?(\d+)'
]
}
# Size conversion mapping
self.size_conversions = {
"xs": "XS", "extra small": "XS", "petite": "XS",
"s": "S", "small": "S",
"m": "M", "medium": "M", "regular": "M",
"l": "L", "large": "L",
"xl": "XL", "extra large": "XL",
"xxl": "XXL", "xxxl": "XXXL", "plus size": "XXL"
}
# Style synonyms
self.style_synonyms = {
"casual": ["relaxed", "comfortable", "everyday", "informal"],
"formal": ["elegant", "dressy", "sophisticated", "classy"],
"business": ["professional", "office", "work", "corporate"],
"party": ["evening", "night out", "celebration", "festive"],
"beach": ["summer", "vacation", "resort", "tropical"],
"workout": ["sporty", "athletic", "gym", "exercise"]
}
def extract_fashion_entities(self, text: str, conversation_history: list = None):
"""Extract fashion-specific entities with context awareness"""
# Get base entities
entities = self.extract_entities_with_context(text, conversation_history)
# Enhance with fashion-specific extraction
fashion_entities = self._extract_fashion_specific(text)
entities.update(fashion_entities)
# Resolve style synonyms
entities = self._resolve_style_synonyms(entities)
# Normalize sizes
entities = self._normalize_sizes(entities)
return entities
def _extract_fashion_specific(self, text: str):
"""Extract fashion-specific entities"""
entities = {}
text_lower = text.lower()
# Extract using fashion patterns
for entity_type, patterns in self.fashion_patterns.items():
for pattern in patterns:
matches = re.findall(pattern, text_lower, re.IGNORECASE)
if matches:
if entity_type == "price":
try:
price = float(matches[0])
entities["price_max"] = price
except ValueError:
pass
else:
entities[entity_type] = matches[0].title()
break
return entities
def _resolve_style_synonyms(self, entities):
"""Resolve style synonyms to standard values"""
if "style" in entities:
style = entities["style"].lower()
for standard_style, synonyms in self.style_synonyms.items():
if style in synonyms or style == standard_style:
entities["style"] = standard_style
break
return entities
def _normalize_sizes(self, entities):
"""Normalize size values"""
if "size" in entities:
size = entities["size"].lower()
entities["size"] = self.size_conversions.get(size, size.upper())
return entities
Step 3: Fashion-Specific Response Generator
Create fashion_response_generator.py:
from recoagent.packages.conversational_search import SimpleAPIMappingEngine
class FashionResponseGenerator(SimpleAPIMappingEngine):
"""Fashion-specific response generator with style intelligence"""
def __init__(self, config):
super().__init__(config)
# Fashion-specific response templates
self.response_templates = {
"no_results": [
"I couldn't find any {item_type} matching your criteria. Let me suggest some alternatives:",
"No {item_type} found with those specifications. Here are some similar options:",
"I don't have {item_type} in that exact style. Would you like to see these alternatives?"
],
"too_many_results": [
"I found {count} {item_type} options. Let me help you narrow it down:",
"There are {count} {item_type} available. What's most important to you?",
"I have {count} {item_type} to choose from. Let's refine your search:"
],
"perfect_match": [
"Perfect! I found {count} {item_type} that match your style:",
"Great choice! Here are {count} {item_type} I think you'll love:",
"Excellent! I found {count} {item_type} that fit your criteria:"
]
}
# Fashion-specific suggestions
self.fashion_suggestions = {
"size_help": [
"Check our size guide for the perfect fit",
"Try our virtual fitting room",
"Read customer reviews for sizing advice"
],
"style_help": [
"Browse our style guide for inspiration",
"Check out our trending styles",
"See how other customers styled this item"
],
"color_help": [
"Try different color variations",
"Check out our seasonal color palette",
"See this item in other colors"
]
}
def map_response_to_nl_fashion(self, api_response, original_query, user_context):
"""Generate fashion-specific natural language responses"""
result_count = self._extract_result_count(api_response)
results = self._extract_results(api_response)
# Determine response template
if result_count == 0:
response_template = self._get_template("no_results")
suggestions = self._get_fashion_suggestions("no_results", original_query)
elif result_count > 20:
response_template = self._get_template("too_many_results")
suggestions = self._get_fashion_suggestions("too_many_results", original_query)
else:
response_template = self._get_template("perfect_match")
suggestions = self._get_fashion_suggestions("perfect_match", original_query)
# Generate response text
item_type = self._extract_item_type(original_query)
response_text = response_template.format(
count=result_count,
item_type=item_type
)
# Add style-specific details
if results:
response_text += self._add_style_details(results, original_query)
return {
"text": response_text,
"result_count": result_count,
"products": results[:5],
"suggestions": suggestions,
"filters_applied": self._extract_applied_filters(api_response),
"style_insights": self._generate_style_insights(results, original_query)
}
def _get_template(self, template_type):
"""Get random template for variety"""
import random
templates = self.response_templates[template_type]
return random.choice(templates)
def _get_fashion_suggestions(self, suggestion_type, query):
"""Get fashion-specific suggestions"""
suggestions = []
if "size" in query.lower():
suggestions.extend(self.fashion_suggestions["size_help"])
elif "color" in query.lower():
suggestions.extend(self.fashion_suggestions["color_help"])
else:
suggestions.extend(self.fashion_suggestions["style_help"])
return suggestions[:3]
def _extract_item_type(self, query):
"""Extract item type from query"""
query_lower = query.lower()
if "dress" in query_lower:
return "dresses"
elif "shirt" in query_lower or "top" in query_lower:
return "tops"
elif "pant" in query_lower or "jean" in query_lower:
return "pants"
elif "shoe" in query_lower:
return "shoes"
elif "bag" in query_lower or "purse" in query_lower:
return "bags"
else:
return "items"
def _add_style_details(self, results, query):
"""Add style-specific details to response"""
if not results:
return ""
# Extract common style elements
styles = set()
colors = set()
brands = set()
for result in results[:3]:
if "style" in result:
styles.add(result["style"])
if "color" in result:
colors.add(result["color"])
if "brand" in result:
brands.add(result["brand"])
details = []
if styles:
details.append(f"Styles: {', '.join(styles)}")
if colors:
details.append(f"Colors: {', '.join(colors)}")
if brands:
details.append(f"Brands: {', '.join(brands)}")
if details:
return f"\n\nKey features: {' | '.join(details)}"
return ""
def _generate_style_insights(self, results, query):
"""Generate style insights for fashion items"""
if not results:
return {}
insights = {}
# Price range insight
prices = [r.get("price", 0) for r in results if "price" in r]
if prices:
insights["price_range"] = {
"min": min(prices),
"max": max(prices),
"average": sum(prices) / len(prices)
}
# Style trend insight
styles = [r.get("style", "") for r in results if "style" in r]
if styles:
from collections import Counter
style_counts = Counter(styles)
insights["trending_styles"] = style_counts.most_common(3)
return insights
Step 4: Complete Fashion Implementation
Create fashion_conversational_search.py:
import asyncio
from recoagent.packages.conversational_search import (
ConversationalSearchEngine,
SimpleMemoryManager,
load_api_mapping_config
)
from fashion_nlu_engine import FashionNLUEngine
from fashion_response_generator import FashionResponseGenerator
class FashionConversationalSearch:
"""Complete fashion e-commerce conversational search implementation"""
def __init__(self, config_path="config/fashion_api_mapping.yaml"):
# Load configuration
self.config = load_api_mapping_config(config_path)
# Initialize fashion-specific components
self.nlu_engine = FashionNLUEngine()
self.memory_manager = SimpleMemoryManager()
self.response_generator = FashionResponseGenerator(self.config)
# Create enhanced engine
self.engine = ConversationalSearchEngine(
api_config=self.config,
nlu_engine=self.nlu_engine,
memory_manager=self.memory_manager,
api_mapping_engine=self.response_generator,
enable_caching=True,
enable_resilience=True
)
# Preload fashion-specific common queries
self._preload_fashion_queries()
# Add fashion-specific fallback responses
self._setup_fashion_fallbacks()
def _preload_fashion_queries(self):
"""Preload common fashion queries for better performance"""
common_queries = [
("red dresses", {"color": "red", "item_type": "dress"}, {
"text": "I found 15 beautiful red dresses for you!",
"result_count": 15,
"products": [
{"name": "Red Summer Dress", "price": 49.99, "brand": "Zara"},
{"name": "Red Evening Gown", "price": 129.99, "brand": "H&M"}
],
"suggestions": ["Try different sizes", "Check out similar colors"]
}),
("casual tops", {"style": "casual", "item_type": "top"}, {
"text": "I found 25 casual tops perfect for everyday wear!",
"result_count": 25,
"products": [
{"name": "Casual Cotton Tee", "price": 19.99, "brand": "Uniqlo"},
{"name": "Relaxed Blouse", "price": 39.99, "brand": "H&M"}
],
"suggestions": ["Filter by color", "Check different brands"]
}),
("black shoes", {"color": "black", "item_type": "shoe"}, {
"text": "I found 20 black shoes for every occasion!",
"result_count": 20,
"products": [
{"name": "Black Leather Loafers", "price": 89.99, "brand": "Nike"},
{"name": "Black Ankle Boots", "price": 79.99, "brand": "Adidas"}
],
"suggestions": ["Filter by style", "Check size availability"]
})
]
self.engine.preload_common_queries(common_queries)
def _setup_fashion_fallbacks(self):
"""Setup fashion-specific fallback responses"""
fallbacks = {
"size help": {
"text": "I can help with sizing! What type of item are you looking for?",
"suggestions": ["Check our size guide", "Try virtual fitting", "Read size reviews"]
},
"style help": {
"text": "I can help you find the perfect style! What's the occasion?",
"suggestions": ["Browse style guide", "Check trending styles", "Get style advice"]
},
"color help": {
"text": "I can help with colors! What's your favorite color palette?",
"suggestions": ["Try different colors", "Check seasonal palette", "See color variations"]
}
}
for pattern, response in fallbacks.items():
self.engine.add_fallback_response(pattern, response)
async def search(self, query, session_id, user_id=None):
"""Process fashion search query"""
# Use fashion-specific entity extraction
nlu_result = self.nlu_engine.extract_fashion_entities(query)
# Process with enhanced engine
response = await self.engine.process_message(query, session_id, user_id)
# Add fashion-specific enhancements
response["fashion_insights"] = self._generate_fashion_insights(response, query)
return response
def _generate_fashion_insights(self, response, query):
"""Generate fashion-specific insights"""
insights = {}
if response.get("products"):
products = response["products"]
# Style analysis
styles = [p.get("style", "") for p in products if "style" in p]
if styles:
from collections import Counter
insights["popular_styles"] = Counter(styles).most_common(3)
# Price analysis
prices = [p.get("price", 0) for p in products if "price" in p]
if prices:
insights["price_analysis"] = {
"range": f"${min(prices):.0f} - ${max(prices):.0f}",
"average": f"${sum(prices)/len(prices):.0f}"
}
# Brand analysis
brands = [p.get("brand", "") for p in products if "brand" in p]
if brands:
from collections import Counter
insights["featured_brands"] = Counter(brands).most_common(3)
return insights
# Example usage
async def main():
fashion_search = FashionConversationalSearch()
# Test fashion-specific queries
test_queries = [
"I need a red dress for a wedding",
"Show me casual tops under $50",
"I want black shoes for work",
"Help me find something for a date night"
]
session_id = "fashion_test_session"
for query in test_queries:
print(f"\nUser: {query}")
response = await fashion_search.search(query, session_id)
print(f"Bot: {response['text']}")
print(f"Products: {len(response['products'])}")
print(f"Fashion Insights: {response.get('fashion_insights', {})}")
if __name__ == "__main__":
asyncio.run(main())
Testing & Validation
Fashion-Specific Test Cases
Create test_fashion_search.py:
import pytest
import asyncio
from fashion_conversational_search import FashionConversationalSearch
@pytest.mark.asyncio
async def test_style_extraction():
"""Test fashion style extraction"""
fashion_search = FashionConversationalSearch()
# Test style recognition
response = await fashion_search.search("casual summer dress", "test_session")
assert "casual" in response["filters_applied"].get("style", "").lower()
# Test occasion recognition
response = await fashion_search.search("wedding guest dress", "test_session")
assert "wedding" in response["filters_applied"].get("occasion", "").lower()
@pytest.mark.asyncio
async def test_size_intelligence():
"""Test size normalization and conversion"""
fashion_search = FashionConversationalSearch()
# Test size normalization
response = await fashion_search.search("medium size dress", "test_session")
assert response["filters_applied"].get("size") == "M"
# Test size synonyms
response = await fashion_search.search("large size shirt", "test_session")
assert response["filters_applied"].get("size") == "L"
@pytest.mark.asyncio
async def test_color_understanding():
"""Test color extraction and variations"""
fashion_search = FashionConversationalSearch()
# Test basic colors
response = await fashion_search.search("red dress", "test_session")
assert "red" in response["filters_applied"].get("color", "").lower()
# Test color variations
response = await fashion_search.search("navy blue top", "test_session")
assert "navy" in response["filters_applied"].get("color", "").lower()
@pytest.mark.asyncio
async def test_progressive_refinement():
"""Test progressive refinement in fashion context"""
fashion_search = FashionConversationalSearch()
# First query
response1 = await fashion_search.search("I need a dress", "test_session")
# Second query with context
response2 = await fashion_search.search("something red", "test_session")
# Should maintain context
assert "red" in response2["filters_applied"].get("color", "").lower()
assert "dress" in response2["text"].lower()
@pytest.mark.asyncio
async def test_fashion_insights():
"""Test fashion-specific insights generation"""
fashion_search = FashionConversationalSearch()
response = await fashion_search.search("casual summer dresses", "test_session")
# Should have fashion insights
assert "fashion_insights" in response
insights = response["fashion_insights"]
# Should have style analysis if products found
if response["products"]:
assert "popular_styles" in insights or "price_analysis" in insights
Deployment
Docker Configuration
Create Dockerfile.fashion:
FROM python:3.9-slim
WORKDIR /app
# Install dependencies
COPY requirements.txt .
RUN pip install -r requirements.txt
# Copy fashion-specific files
COPY fashion_nlu_engine.py .
COPY fashion_response_generator.py .
COPY fashion_conversational_search.py .
COPY config/ ./config/
# Expose port
EXPOSE 8000
# Run fashion search service
CMD ["python", "fashion_conversational_search.py"]
Environment Configuration
Create .env.fashion:
# Fashion-specific configuration
FASHION_API_BASE_URL=https://api.fashionstore.com
FASHION_API_KEY=your_api_key_here
# Redis configuration
REDIS_URL=redis://localhost:6379
# Fashion-specific settings
FASHION_CACHE_TTL=7200
FASHION_MAX_CACHE_SIZE=2000
FASHION_STYLE_SYNONYMS_ENABLED=true
FASHION_SIZE_CONVERSION_ENABLED=true
Performance Metrics
Expected Results
- Search completion rate: 85%+ (vs 60% with traditional search)
- Conversion rate: 3.5%+ (vs 2.1% with traditional search)
- Average response time: <150ms (with caching)
- Cache hit rate: 70%+ (for common fashion queries)
- User satisfaction: 4.5/5+ (vs 3.2/5 with traditional search)
Key Performance Indicators
- Style accuracy: 90%+ correct style classification
- Size conversion: 95%+ accurate size normalization
- Color recognition: 85%+ accurate color extraction
- Context retention: 80%+ context maintained across turns
Next Steps
- Marketplace Example → - Multi-vendor implementation
- Implementation Guide → - General setup guide
- Case Studies → - Real-world success stories