| import streamlit as st |
| import pandas as pd |
| import numpy as np |
| import plotly.express as px |
| import plotly.graph_objects as go |
| from datetime import datetime, timedelta |
| import time |
|
|
| |
| st.set_page_config( |
| page_title="Calcium Supplement Sales Dashboard", |
| page_icon="🐄", |
| layout="wide", |
| initial_sidebar_state="expanded" |
| ) |
|
|
| |
| @st.cache_data |
| def load_data(): |
| |
| sales_data = pd.DataFrame({ |
| 'Date': ['2025-06-01', '2025-06-01', '2025-06-10', '2025-06-11', '2025-06-12', |
| '2025-07-30', '2025-07-30', '2025-07-31', '2025-07-31', '2025-07-31'], |
| 'Customer': ['Gopalbhai', 'Ramprasad Khatik', 'Vikramsinh', 'Prahladbhai -Mantry', 'V S Stud Farm', |
| 'Hemendrabhai Parmar', 'Sundarbhai', 'Kamleshbhai Vasava -Mantry', 'Kiranbhai -Mantry', 'Kiritbhai'], |
| 'Village': ['Shilly', 'Rajasthan', 'Mithapura', 'Bhalod Dairy', 'Waghodia', |
| 'Panchdevla', 'Siyali', 'Moran', 'Talodara', 'Sindhrot'], |
| 'Total_L': [35.0, 400.0, 30.0, 7.0, 400.0, 50.0, 13.0, 1.0, 1.0, 30.0] |
| }) |
| |
| |
| mantri_data = pd.DataFrame({ |
| 'DATE': ['2024-03-08', '2025-06-03', '2025-02-23', '2025-05-28', '2025-05-02', |
| '2024-09-21', '2024-10-26', '2024-03-19', '2025-01-30', '2025-07-18'], |
| 'VILLAGE': ['JILOD', 'MANJIPURA', 'GOTHADA', 'UNTKHARI', 'VEMAR', |
| 'KANODA', 'KOTAMBI', 'RASNOL', 'JITPURA', 'BHATPURA'], |
| 'MANTRY_NAME': ['AJAYBHAI PATEL', 'AJAYBHAI PATEL', 'AJGAR KHAN', 'AMBALAL CHAUHAN', 'AMBALAL GOHIL', |
| 'VINUBHAI SOLANKI', 'VISHNUBHAI', 'VITHTHALBHAI', 'YOGESHBHAI', 'YUVRAJSINH'], |
| 'MOBILE_NO': [7984136988, 9737910554, 9724831903, 9313860902, 9978081739, |
| 9998756469, 9909550170, 9924590017, 7990383811, 6353209447], |
| 'sabhasad': [38, 21, 3, 0, 2, 0, 14, 1183, 8, 6], |
| 'contact_in_group': [38.0, 16.0, 2.0, 0.0, 0.0, 0.0, 14.0, 268.0, 5.0, 4.0], |
| 'TOTAL_L': [99.0, 120.0, 19.0, 87.0, 32.0, 60.0, 54.0, 82.0, 25.0, 11.0] |
| }) |
| |
| |
| sales_data['Date'] = pd.to_datetime(sales_data['Date']) |
| mantri_data['DATE'] = pd.to_datetime(mantri_data['DATE'], errors='coerce') |
| |
| return sales_data, mantri_data |
|
|
| |
| def analyze_mantri_performance(mantri_data, sales_data): |
| mantri_data = mantri_data.copy() |
| |
| |
| mantri_data['Conversion_Rate'] = (mantri_data['contact_in_group'] / mantri_data['sabhasad'] * 100).round(2) |
| mantri_data['Conversion_Rate'] = mantri_data['Conversion_Rate'].replace([np.inf, -np.inf], 0).fillna(0) |
| mantri_data['Untapped_Potential'] = mantri_data['sabhasad'] - mantri_data['contact_in_group'] |
| mantri_data['Sales_Efficiency'] = (mantri_data['TOTAL_L'] / mantri_data['contact_in_group']).round(2) |
| mantri_data['Sales_Efficiency'] = mantri_data['Sales_Efficiency'].replace([np.inf, -np.inf], 0).fillna(0) |
| |
| |
| mantri_data['Priority_Score'] = ( |
| (mantri_data['Untapped_Potential'] / mantri_data['Untapped_Potential'].max() * 50) + |
| ((100 - mantri_data['Conversion_Rate']) / 100 * 50) |
| ).round(2) |
| |
| |
| recent_sales = sales_data.groupby('Village').agg({ |
| 'Total_L': 'sum', |
| 'Customer': 'count' |
| }).reset_index() |
| recent_sales.columns = ['VILLAGE', 'Recent_Sales', 'Recent_Customers'] |
| |
| mantri_data = mantri_data.merge(recent_sales, on='VILLAGE', how='left') |
| mantri_data['Recent_Sales'] = mantri_data['Recent_Sales'].fillna(0) |
| mantri_data['Recent_Customers'] = mantri_data['Recent_Customers'].fillna(0) |
| |
| return mantri_data |
|
|
| def analyze_village_performance(sales_data, mantri_data): |
| |
| village_sales = sales_data.groupby('Village').agg({ |
| 'Total_L': 'sum', |
| 'Customer': 'count', |
| 'Date': 'max' |
| }).reset_index() |
| village_sales.columns = ['Village', 'Total_Sales', 'Customer_Count', 'Last_Sale_Date'] |
| |
| |
| village_sales['Days_Since_Last_Sale'] = (datetime.now() - village_sales['Last_Sale_Date']).dt.days |
| |
| |
| mantri_summary = mantri_data[['VILLAGE', 'MANTRY_NAME', 'MOBILE_NO', 'sabhasad', 'contact_in_group']] |
| mantri_summary.columns = ['Village', 'Mantri_Name', 'Mantri_Mobile', 'Sabhasad', 'Contacts'] |
| |
| village_performance = village_sales.merge(mantri_summary, on='Village', how='left') |
| |
| |
| village_performance['Conversion_Rate'] = (village_performance['Contacts'] / village_performance['Sabhasad'] * 100).round(2) |
| village_performance['Conversion_Rate'] = village_performance['Conversion_Rate'].replace([np.inf, -np.inf], 0).fillna(0) |
| village_performance['Untapped_Potential'] = village_performance['Sabhasad'] - village_performance['Contacts'] |
| |
| return village_performance |
|
|
| |
| def get_mantri_message_template(mantri_name, village, reason, performance_data): |
| templates = { |
| 'Low Conversion': f""" |
| Namaste {mantri_name} Ji! |
| |
| Aapke kshetra {village} mein humare calcium supplement ki conversion rate kam hai ({performance_data['Conversion_Rate']}%). |
| Humari marketing team aapke yaha demo dene aayegi. |
| Kripya taiyaari rakhein aur sabhi dudh utpadakon ko soochit karein. |
| |
| Aapke paas abhi bhi {int(performance_data['Untapped_Potential'])} aise farmers hain jo product nahi use kar rahe hain. |
| |
| Dhanyavaad, |
| Calcium Supplement Team |
| """, |
| 'High Potential': f""" |
| Namaste {mantri_name} Ji! |
| |
| Aapke kshetra {village} mein {int(performance_data['Untapped_Potential'])} aise farmers hain jo abhi tak humare product se anabhijit hain. |
| Kripya unse sampark karein aur unhe product ke fayde batayein. |
| Aapke liye special commission offer hai agle 10 naye customers ke liye. |
| |
| Dhanyavaad, |
| Calcium Supplement Team |
| """, |
| 'Good Performance': f""" |
| Namaste {mantri_name} Ji! |
| |
| Aapke kshetra {village} mein humare product ki demand badh rahi hai. |
| Aapki conversion rate {performance_data['Conversion_Rate']}% hai jo bahut achchi hai. |
| |
| Kripya farmers ko yaad dilaein ki pregnancy ke 3-9 mahine aur delivery ke baad calcium supplement zaroori hai. |
| |
| Dhanyavaad, |
| Calcium Supplement Team |
| """ |
| } |
| |
| return templates.get(reason, "Custom message based on analysis") |
|
|
| |
| sales_data, mantri_data = load_data() |
| mantri_performance = analyze_mantri_performance(mantri_data, sales_data) |
| village_performance = analyze_village_performance(sales_data, mantri_data) |
|
|
| |
| st.title("🐄 Calcium Supplement Sales Automation Dashboard") |
| st.markdown("---") |
|
|
| |
| st.sidebar.header("Navigation") |
| section = st.sidebar.radio("Go to", ["Dashboard", "Mantri Performance", "Village Analysis", "Message Center", "Team Dispatch"]) |
|
|
| |
| if section == "Dashboard": |
| st.header("Sales Performance Overview") |
| |
| col1, col2, col3, col4 = st.columns(4) |
| |
| with col1: |
| st.metric("Total Villages Covered", len(mantri_performance)) |
| with col2: |
| st.metric("Total Mantris", len(mantri_performance['MANTRY_NAME'].unique())) |
| with col3: |
| st.metric("Total Sales (Liters)", mantri_performance['TOTAL_L'].sum()) |
| with col4: |
| avg_conversion = mantri_performance['Conversion_Rate'].mean() |
| st.metric("Avg Conversion Rate", f"{avg_conversion:.2f}%") |
| |
| st.subheader("Top Priority Mantris") |
| priority_mantris = mantri_performance.nlargest(5, 'Priority_Score')[['MANTRY_NAME', 'VILLAGE', 'Conversion_Rate', 'Untapped_Potential', 'Priority_Score']] |
| st.dataframe(priority_mantris) |
| |
| st.subheader("Sales Distribution by Village") |
| fig = px.bar(mantri_performance, x='VILLAGE', y='TOTAL_L', title='Total Sales by Village') |
| st.plotly_chart(fig, use_container_width=True) |
| |
| st.subheader("Conversion Rate vs Untapped Potential") |
| fig = px.scatter(mantri_performance, x='Conversion_Rate', y='Untapped_Potential', |
| size='TOTAL_L', color='VILLAGE', hover_name='MANTRY_NAME', |
| title='Mantri Performance Analysis') |
| st.plotly_chart(fig, use_container_width=True) |
|
|
| |
| elif section == "Mantri Performance": |
| st.header("Mantri Performance Analysis") |
| |
| selected_mantri = st.selectbox("Select Mantri", mantri_performance['MANTRY_NAME'].unique()) |
| mantri_data = mantri_performance[mantri_performance['MANTRY_NAME'] == selected_mantri].iloc[0] |
| |
| col1, col2, col3, col4 = st.columns(4) |
| |
| with col1: |
| st.metric("Mantri", mantri_data['MANTRY_NAME']) |
| with col2: |
| st.metric("Village", mantri_data['VILLAGE']) |
| with col3: |
| st.metric("Conversion Rate", f"{mantri_data['Conversion_Rate']}%") |
| with col4: |
| st.metric("Untapped Potential", int(mantri_data['Untapped_Potential'])) |
| |
| st.subheader("Mantri Details") |
| st.dataframe(mantri_data) |
| |
| st.subheader("Action Recommendations") |
| if mantri_data['Conversion_Rate'] < 20: |
| st.error(f"**Send Marketing Team**: Conversion rate is low ({mantri_data['Conversion_Rate']}%). Need demos and awareness campaigns.") |
| if mantri_data['Untapped_Potential'] > 10: |
| st.warning(f"**Call Mantri**: {int(mantri_data['Untapped_Potential'])} farmers still not converted. Push Mantri to contact them.") |
| if mantri_data['Conversion_Rate'] > 50: |
| st.success(f"**Expand Success**: This mantri is performing well. Consider replicating their strategies.") |
|
|
| |
| elif section == "Village Analysis": |
| st.header("Village Performance Analysis") |
| |
| selected_village = st.selectbox("Select Village", village_performance['Village'].unique()) |
| village_data = village_performance[village_performance['Village'] == selected_village].iloc[0] |
| |
| col1, col2, col3, col4 = st.columns(4) |
| |
| with col1: |
| st.metric("Village", village_data['Village']) |
| with col2: |
| st.metric("Mantri", village_data['Mantri_Name']) |
| with col3: |
| st.metric("Total Sales (L)", village_data['Total_Sales']) |
| with col4: |
| st.metric("Days Since Last Sale", village_data['Days_Since_Last_Sale']) |
| |
| st.subheader("Village Details") |
| st.dataframe(village_data) |
| |
| st.subheader("Action Recommendations") |
| if village_data['Days_Since_Last_Sale'] > 30: |
| st.error(f"**Send Marketing Team**: No sales in {village_data['Days_Since_Last_Sale']} days. Need immediate attention.") |
| if village_data['Conversion_Rate'] < 25: |
| st.warning(f"**Low Conversion**: Only {village_data['Conversion_Rate']}% of potential customers are converted.") |
| if village_data['Total_Sales'] > 100: |
| st.success(f"**High Performer**: This village has high sales volume. Consider expanding product range.") |
|
|
| |
| elif section == "Message Center": |
| st.header("Message Center") |
| |
| st.subheader("Mantri Communication") |
| selected_mantri = st.selectbox("Select Mantri", mantri_performance['MANTRY_NAME'].unique()) |
| mantri_data = mantri_performance[mantri_performance['MANTRY_NAME'] == selected_mantri].iloc[0] |
| |
| st.write(f"**Village:** {mantri_data['VILLAGE']}") |
| st.write(f"**Conversion Rate:** {mantri_data['Conversion_Rate']}%") |
| st.write(f"**Untapped Potential:** {int(mantri_data['Untapped_Potential'])} farmers") |
| |
| if mantri_data['Conversion_Rate'] < 20: |
| reason = "Low Conversion" |
| elif mantri_data['Untapped_Potential'] > 10: |
| reason = "High Potential" |
| else: |
| reason = "Good Performance" |
| |
| message = get_mantri_message_template( |
| mantri_data['MANTRY_NAME'], |
| mantri_data['VILLAGE'], |
| reason, |
| mantri_data |
| ) |
| |
| st.text_area("Generated Message", message, height=200) |
| |
| if st.button("Send to Mantri"): |
| st.success(f"Message sent to {mantri_data['MANTRY_NAME']} at {mantri_data['MOBILE_NO']}") |
| |
| |
| st.subheader("Bulk Message Sender") |
| st.write("Send messages to multiple mantris at once") |
| |
| options = st.multiselect("Select Mantris", mantri_performance['MANTRY_NAME'].unique()) |
| message_template = st.text_area("Message Template", height=100) |
| |
| if st.button("Send to Selected Mantris"): |
| progress_bar = st.progress(0) |
| for i, mantri in enumerate(options): |
| |
| time.sleep(0.5) |
| progress_bar.progress((i + 1) / len(options)) |
| st.success(f"Messages sent to {len(options)} mantris") |
|
|
| |
| elif section == "Team Dispatch": |
| st.header("Marketing Team Dispatch Planner") |
| |
| st.subheader("Villages Needing Immediate Attention") |
| |
| |
| high_priority = village_performance[ |
| (village_performance['Days_Since_Last_Sale'] > 30) | |
| (village_performance['Conversion_Rate'] < 20) |
| ] |
| |
| if not high_priority.empty: |
| for _, village in high_priority.iterrows(): |
| with st.expander(f"{village['Village']} (Last sale: {village['Days_Since_Last_Sale']} days ago)"): |
| st.write(f"**Mantri:** {village['Mantri_Name']} ({village['Mantri_Mobile']})") |
| st.write(f"**Conversion Rate:** {village['Conversion_Rate']}%") |
| st.write(f"**Recommended Action:** Conduct demo sessions and awareness campaign") |
| |
| if st.button(f"Dispatch Team to {village['Village']}", key=f"dispatch_{village['Village']}"): |
| st.success(f"Team dispatched to {village['Village']}. Mantri {village['Mantri_Name']} has been notified.") |
| else: |
| st.info("No villages currently require immediate team dispatch.") |
| |
| st.subheader("Create New Dispatch Plan") |
| |
| col1, col2 = st.columns(2) |
| |
| with col1: |
| selected_village = st.selectbox("Select Village for Dispatch", village_performance['Village'].unique()) |
| village_data = village_performance[village_performance['Village'] == selected_village].iloc[0] |
| |
| st.write(f"**Mantri:** {village_data['Mantri_Name']}") |
| st.write(f"**Last Sale:** {village_data['Days_Since_Last_Sale']} days ago") |
| st.write(f"**Conversion Rate:** {village_data['Conversion_Rate']}%") |
| |
| with col2: |
| dispatch_date = st.date_input("Dispatch Date", datetime.now() + timedelta(days=1)) |
| team_size = st.slider("Team Size", 1, 5, 2) |
| duration = st.selectbox("Duration", ["1 day", "2 days", "3 days", "1 week"]) |
| |
| objectives = st.text_area("Objectives", "Conduct demo sessions, educate farmers about benefits, collect feedback") |
| |
| if st.button("Schedule Dispatch"): |
| st.success(f"Dispatch to {selected_village} scheduled for {dispatch_date}") |
| st.json({ |
| "village": selected_village, |
| "mantri": village_data['Mantri_Name'], |
| "date": str(dispatch_date), |
| "team_size": team_size, |
| "duration": duration, |
| "objectives": objectives |
| }) |
|
|
| |
| st.markdown("---") |
| st.markdown("**Calcium Supplement Sales Automation System** | For internal use only") |