Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| from typing import Dict, List | |
| from utils.recommendations import calculate_total_impact | |
| def display_results(analysis_results: Dict, product_name: str): | |
| """Display analysis results in a formatted way""" | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| # Overall score | |
| score = analysis_results.get('overall_score', 5) | |
| if score >= 8: | |
| score_color = "🟢" | |
| score_text = "Excellent" | |
| elif score >= 6: | |
| score_color = "🟡" | |
| score_text = "Good" | |
| else: | |
| score_color = "🔴" | |
| score_text = "Needs Improvement" | |
| st.metric( | |
| label="Overall Score", | |
| value=f"{score}/10", | |
| delta=score_text, | |
| help="Overall assessment of product placement" | |
| ) | |
| with col2: | |
| # Confidence | |
| confidence = analysis_results.get('confidence', 0.5) | |
| confidence_pct = int(confidence * 100) | |
| st.metric( | |
| label="AI Confidence", | |
| value=f"{confidence_pct}%", | |
| help="How confident the AI is in this analysis" | |
| ) | |
| with col3: | |
| # Product found status | |
| found = analysis_results.get('product_found', False) | |
| status = "✅ Found" if found else "❌ Not Found" | |
| st.metric( | |
| label="Product Status", | |
| value=status, | |
| help="Whether the product was detected on the shelf" | |
| ) | |
| st.markdown("---") | |
| # Detailed information | |
| col1, col2 = st.columns(2) | |
| with col1: | |
| st.markdown("### 📊 Product Details") | |
| # Facing count | |
| facing_count = analysis_results.get('facing_count', 0) | |
| st.info(f"**Facings:** {facing_count} visible units") | |
| # Shelf position | |
| position = analysis_results.get('shelf_position', 'Unknown') | |
| position_emoji = { | |
| 'top': '⬆️', | |
| 'middle': '➡️', | |
| 'bottom': '⬇️', | |
| 'górna': '⬆️', | |
| 'środkowa': '➡️', | |
| 'dolna': '⬇️' | |
| }.get(position.lower(), '❓') | |
| st.info(f"**Position:** {position_emoji} {position.title()}") | |
| # Price visibility | |
| price_visible = analysis_results.get('price_visible', False) | |
| price_status = "✅ Visible" if price_visible else "❌ Not visible" | |
| st.info(f"**Price:** {price_status}") | |
| with col2: | |
| st.markdown("### 🔍 Quality Assessment") | |
| # Product condition | |
| condition = analysis_results.get('product_condition', 'Unknown') | |
| condition_emoji = { | |
| 'good': '✅', | |
| 'dusty': '🧹', | |
| 'damaged': '⚠️', | |
| 'dobry': '✅', | |
| 'zakurzony': '🧹', | |
| 'uszkodzony': '⚠️' | |
| }.get(condition.lower(), '❓') | |
| st.info(f"**Condition:** {condition_emoji} {condition.title()}") | |
| # Shelf share | |
| shelf_share = analysis_results.get('shelf_share', 0) | |
| if shelf_share > 0: | |
| st.info(f"**Shelf Share:** {shelf_share}% of shelf space") | |
| # Competitors | |
| competitors = analysis_results.get('competitors_nearby', []) | |
| if competitors: | |
| st.info(f"**Nearby Competitors:** {len(competitors)} products") | |
| # Description | |
| description = analysis_results.get('description', '') | |
| if description: | |
| st.markdown("### 📝 Analysis Details") | |
| st.markdown(f"> {description}") | |
| def display_recommendations(recommendations: List[Dict]): | |
| """Display recommendations in a formatted way""" | |
| if not recommendations: | |
| st.info("No specific recommendations generated.") | |
| return | |
| # Calculate total impact | |
| impact_summary = calculate_total_impact(recommendations) | |
| # Display summary metrics | |
| col1, col2, col3, col4 = st.columns(4) | |
| with col1: | |
| st.metric( | |
| "Total Recommendations", | |
| impact_summary['total_recommendations'], | |
| help="Number of actionable recommendations" | |
| ) | |
| with col2: | |
| st.metric( | |
| "High Priority", | |
| impact_summary['high_priority_count'], | |
| help="Critical issues requiring immediate attention" | |
| ) | |
| with col3: | |
| st.metric( | |
| "Estimated Time", | |
| f"{impact_summary['total_time_minutes']} min", | |
| help="Total time needed to implement all changes" | |
| ) | |
| with col4: | |
| # Calculate difficulty distribution | |
| difficulties = [r.get('difficulty', 'Unknown') for r in recommendations] | |
| easy_count = difficulties.count('Bardzo łatwe') + difficulties.count('Łatwe') | |
| difficulty_text = f"{easy_count}/{len(recommendations)} Easy" | |
| st.metric( | |
| "Difficulty", | |
| difficulty_text, | |
| help="How many recommendations are easy to implement" | |
| ) | |
| st.markdown("---") | |
| # Group recommendations by priority | |
| high_priority = [r for r in recommendations if r.get('priority', 5) <= 2] | |
| medium_priority = [r for r in recommendations if r.get('priority', 5) == 3] | |
| low_priority = [r for r in recommendations if r.get('priority', 5) >= 4] | |
| # Display high priority recommendations | |
| if high_priority: | |
| st.markdown("### 🚨 High Priority (Do First)") | |
| for rec in high_priority: | |
| display_recommendation_card(rec) | |
| # Display medium priority recommendations | |
| if medium_priority: | |
| st.markdown("### ⚡ Medium Priority") | |
| for rec in medium_priority: | |
| display_recommendation_card(rec) | |
| # Display low priority recommendations | |
| if low_priority: | |
| st.markdown("### 💡 Additional Improvements") | |
| for rec in low_priority: | |
| display_recommendation_card(rec) | |
| def display_recommendation_card(recommendation: Dict): | |
| """Display a single recommendation as a card""" | |
| # Priority styling | |
| priority = recommendation.get('priority', 5) | |
| if priority <= 2: | |
| border_color = "#ff4b4b" # Red | |
| elif priority == 3: | |
| border_color = "#ffa500" # Orange | |
| else: | |
| border_color = "#1f77b4" # Blue | |
| # Card styling | |
| st.markdown(f""" | |
| <div style=" | |
| border: 2px solid {border_color}; | |
| border-radius: 10px; | |
| padding: 15px; | |
| margin: 10px 0; | |
| background-color: white; | |
| "> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| with st.container(): | |
| col1, col2 = st.columns([3, 1]) | |
| with col1: | |
| # Title and description | |
| title = recommendation.get('title', 'Recommendation') | |
| st.markdown(f"**{title}**") | |
| description = recommendation.get('description', '') | |
| if description: | |
| st.markdown(f"*{description}*") | |
| # Action | |
| action = recommendation.get('action', '') | |
| if action: | |
| st.markdown(f"**Action:** {action}") | |
| with col2: | |
| # Metrics | |
| impact = recommendation.get('estimated_impact', '') | |
| if impact: | |
| st.markdown(f"📈 **{impact}**") | |
| time_to_fix = recommendation.get('time_to_fix', '') | |
| if time_to_fix: | |
| st.markdown(f"⏱️ {time_to_fix}") | |
| difficulty = recommendation.get('difficulty', '') | |
| if difficulty: | |
| difficulty_emoji = { | |
| 'Bardzo łatwe': '🟢', | |
| 'Łatwe': '🟡', | |
| 'Średnie': '🟠', | |
| 'Trudne': '🔴' | |
| }.get(difficulty, '⚪') | |
| st.markdown(f"{difficulty_emoji} {difficulty}") | |
| def display_analysis_history(history: List[Dict]): | |
| """Display analysis history""" | |
| if not history: | |
| st.info("No analysis history available.") | |
| return | |
| for i, analysis in enumerate(reversed(history[-10:])): # Show last 10 | |
| with st.expander( | |
| f"{analysis.get('product_name', 'Unknown')} - {analysis.get('analysis_date', 'Unknown')}" | |
| ): | |
| results = analysis.get('results', {}) | |
| col1, col2, col3 = st.columns(3) | |
| with col1: | |
| score = results.get('overall_score', 'N/A') | |
| st.metric("Score", f"{score}/10") | |
| with col2: | |
| found = results.get('product_found', False) | |
| status = "Found" if found else "Not Found" | |
| st.metric("Status", status) | |
| with col3: | |
| facings = results.get('facing_count', 0) | |
| st.metric("Facings", facings) | |
| description = results.get('description', '') | |
| if description: | |
| st.markdown(f"**Description:** {description[:200]}...") | |
| def create_export_summary(analysis_results: Dict, recommendations: List[Dict], product_name: str) -> str: | |
| """Create a summary for export purposes""" | |
| summary = f""" | |
| # Shelf Analysis Report - {product_name} | |
| ## Analysis Results | |
| - **Overall Score:** {analysis_results.get('overall_score', 'N/A')}/10 | |
| - **Product Found:** {'Yes' if analysis_results.get('product_found') else 'No'} | |
| - **Facing Count:** {analysis_results.get('facing_count', 0)} | |
| - **Shelf Position:** {analysis_results.get('shelf_position', 'Unknown')} | |
| - **Price Visible:** {'Yes' if analysis_results.get('price_visible') else 'No'} | |
| - **Product Condition:** {analysis_results.get('product_condition', 'Unknown')} | |
| - **AI Confidence:** {int(analysis_results.get('confidence', 0.5) * 100)}% | |
| ## Recommendations ({len(recommendations)}) | |
| """ | |
| for i, rec in enumerate(recommendations, 1): | |
| summary += f""" | |
| ### {i}. {rec.get('title', 'Recommendation')} | |
| - **Priority:** {rec.get('priority', 'N/A')} | |
| - **Description:** {rec.get('description', '')} | |
| - **Action:** {rec.get('action', '')} | |
| - **Estimated Impact:** {rec.get('estimated_impact', '')} | |
| - **Time to Fix:** {rec.get('time_to_fix', '')} | |
| - **Difficulty:** {rec.get('difficulty', '')} | |
| """ | |
| return summary |