Spaces:
Sleeping
Sleeping
| 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]) | |
| } |