ShelfPhotoAnalyzer / utils /recommendations.py
Marek4321's picture
Upload 9 files
af2bcb1 verified
from typing import Dict, List
from config import RECOMMENDATIONS_RULES
def generate_recommendations(analysis_results: Dict) -> List[Dict]:
"""
Generate actionable recommendations based on analysis results
Args:
analysis_results: Dictionary with analysis results from AI
Returns:
List of recommendation dictionaries
"""
recommendations = []
if not analysis_results:
return recommendations
# Product not found recommendations
if not analysis_results.get('product_found', False):
recommendations.append({
'type': 'critical',
'priority': 1,
'title': '🚨 Produkt nie znaleziony',
'description': 'Produkt nie jest widoczny na półce lub jest niedostępny.',
'action': 'Uzupełnij asortyment lub sprawdź lokalizację produktu',
'estimated_impact': '+100% dostępności',
'time_to_fix': '5-15 minut',
'difficulty': 'Łatwe'
})
return recommendations
# Position recommendations
shelf_position = analysis_results.get('shelf_position', '').lower()
if shelf_position in ['bottom', 'dół', 'dolna']:
recommendations.append({
'type': 'position',
'priority': 2,
'title': '📈 Przenieś na poziom oczu',
'description': 'Produkt znajduje się na dolnej półce, co znacznie zmniejsza widoczność.',
'action': 'Przenieś produkty na poziom oczu (120-160cm)',
'estimated_impact': '+30% sprzedaży',
'time_to_fix': '2-3 minuty',
'difficulty': 'Łatwe'
})
elif shelf_position in ['top', 'góra', 'górna']:
recommendations.append({
'type': 'position',
'priority': 3,
'title': '👁️ Popraw widoczność',
'description': 'Produkt na górnej półce - rozważ przeniesienie lub dodatkowe oznakowanie.',
'action': 'Przenieś na środkową półkę lub dodaj shelf talker',
'estimated_impact': '+20% widoczności',
'time_to_fix': '2-3 minuty',
'difficulty': 'Łatwe'
})
# Facing count recommendations
facing_count = analysis_results.get('facing_count', 0)
if facing_count == 1:
recommendations.append({
'type': 'quantity',
'priority': 3,
'title': '➕ Zwiększ liczbę facings',
'description': 'Tylko jeden facing - zwiększenie do 2-3 poprawia widoczność.',
'action': 'Dodaj 1-2 dodatkowe facings',
'estimated_impact': '+15% widoczności',
'time_to_fix': '1-2 minuty',
'difficulty': 'Bardzo łatwe'
})
elif facing_count == 0:
recommendations.append({
'type': 'quantity',
'priority': 1,
'title': '🔄 Uzupełnij produkty',
'description': 'Brak produktów na półce.',
'action': 'Uzupełnij asortyment z magazynu',
'estimated_impact': '+100% dostępności',
'time_to_fix': '5-10 minut',
'difficulty': 'Łatwe'
})
# Price visibility recommendations
if not analysis_results.get('price_visible', False):
recommendations.append({
'type': 'pricing',
'priority': 2,
'title': '💰 Dodaj widoczną cenę',
'description': 'Brak widocznej ceny może zniechęcać klientów.',
'action': 'Dodaj lub popraw czytelność cenówki',
'estimated_impact': '+10% konwersji',
'time_to_fix': '1-2 minuty',
'difficulty': 'Bardzo łatwe'
})
# Product condition recommendations
condition = analysis_results.get('product_condition', '').lower()
if condition in ['dusty', 'zakurzony']:
recommendations.append({
'type': 'condition',
'priority': 4,
'title': '🧹 Wyczyść produkty',
'description': 'Produkty wyglądają na zakurzone, co wpływa na postrzeganie jakości.',
'action': 'Wyczyść produkty i opakowania',
'estimated_impact': '+5% percepcji jakości',
'time_to_fix': '2-3 minuty',
'difficulty': 'Bardzo łatwe'
})
elif condition in ['damaged', 'uszkodzony']:
recommendations.append({
'type': 'condition',
'priority': 1,
'title': '⚠️ Wymień uszkodzone produkty',
'description': 'Uszkodzone produkty negatywnie wpływają na wizerunek marki.',
'action': 'Usuń uszkodzone produkty i zastąp nowymi',
'estimated_impact': '+15% percepcji marki',
'time_to_fix': '3-5 minut',
'difficulty': 'Łatwe'
})
# Competition recommendations
competitors = analysis_results.get('competitors_nearby', [])
if len(competitors) > 3:
recommendations.append({
'type': 'competition',
'priority': 3,
'title': '🎯 Zwiększ wyróżnienie',
'description': f'Silna konkurencja w pobliżu ({len(competitors)} produktów konkurencyjnych).',
'action': 'Dodaj materiały POS lub zwiększ liczbę facings',
'estimated_impact': '+20% uwagi klientów',
'time_to_fix': '5-10 minut',
'difficulty': 'Średnie'
})
# Shelf share recommendations
shelf_share = analysis_results.get('shelf_share', 0)
if shelf_share < 10:
recommendations.append({
'type': 'share',
'priority': 2,
'title': '📊 Zwiększ udział w półce',
'description': f'Niski udział w półce ({shelf_share}%). Rozważ negocjacje z menedżerem kategorii.',
'action': 'Zwiększ liczbę facings lub wynegocjuj lepszą przestrzeń',
'estimated_impact': '+25% widoczności',
'time_to_fix': '10-30 minut',
'difficulty': 'Trudne'
})
# Overall score recommendations
overall_score = analysis_results.get('overall_score', 5)
if overall_score < 4:
recommendations.append({
'type': 'general',
'priority': 1,
'title': '🚀 Kompleksowa poprawa',
'description': 'Niska ogólna ocena ekspozycji wymaga kompleksowej poprawy.',
'action': 'Zastosuj wszystkie powyższe rekomendacje w kolejności priorytetów',
'estimated_impact': '+50% ogólnej efektywności',
'time_to_fix': '15-30 minut',
'difficulty': 'Średnie'
})
# Sort recommendations by priority
recommendations.sort(key=lambda x: x['priority'])
return recommendations
def calculate_total_impact(recommendations: List[Dict]) -> Dict:
"""
Calculate estimated total impact of all recommendations
Args:
recommendations: List of recommendation dictionaries
Returns:
Dictionary with total impact estimates
"""
total_time = 0
impact_categories = {
'sprzedaż': [],
'widoczność': [],
'dostępność': [],
'jakość': []
}
for rec in recommendations:
# Extract time (assuming format like "2-3 minuty")
time_str = rec.get('time_to_fix', '0')
try:
# Extract first number from time string
time_parts = time_str.split('-')
if time_parts:
total_time += int(''.join(filter(str.isdigit, time_parts[0])))
except:
total_time += 5 # Default 5 minutes
# Categorize impact
impact = rec.get('estimated_impact', '')
if 'sprzedaż' in impact.lower():
impact_categories['sprzedaż'].append(impact)
elif 'widoczność' in impact.lower():
impact_categories['widoczność'].append(impact)
elif 'dostępność' in impact.lower():
impact_categories['dostępność'].append(impact)
elif any(word in impact.lower() for word in ['jakość', 'percepcj']):
impact_categories['jakość'].append(impact)
return {
'total_time_minutes': total_time,
'impact_categories': impact_categories,
'total_recommendations': len(recommendations),
'high_priority_count': len([r for r in recommendations if r['priority'] <= 2])
}