Spaces:
Sleeping
Sleeping
Update app.py
Browse files
app.py
CHANGED
@@ -825,6 +825,98 @@ def predict_and_store_freight(state, *args):
|
|
825 |
state.freight_predictions.append(result)
|
826 |
return result
|
827 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
828 |
def create_interface():
|
829 |
"""Create Gradio interface with enhanced UI"""
|
830 |
state = SupplyChainState()
|
@@ -841,167 +933,102 @@ def create_interface():
|
|
841 |
# Main Content Tabs
|
842 |
with gr.Tabs() as tabs:
|
843 |
# Data Upload Tab
|
844 |
-
|
845 |
-
|
846 |
-
|
847 |
-
|
848 |
-
|
849 |
-
|
850 |
-
|
851 |
-
|
852 |
-
|
853 |
|
854 |
-
|
855 |
-
|
856 |
-
|
857 |
-
|
858 |
-
|
859 |
-
|
860 |
-
|
861 |
-
|
862 |
-
with gr.Row():
|
863 |
-
text_input_area = gr.Textbox(
|
864 |
-
label="π Additional Context",
|
865 |
-
placeholder="Add market updates, news, or other relevant information...",
|
866 |
-
lines=5
|
867 |
-
)
|
868 |
-
|
869 |
-
with gr.Row():
|
870 |
-
upload_status = gr.Textbox(
|
871 |
-
label="Status",
|
872 |
-
elem_classes="status-box"
|
873 |
-
)
|
874 |
-
upload_button = gr.Button(
|
875 |
-
"π Process Data",
|
876 |
-
variant="primary",
|
877 |
-
elem_classes="action-button"
|
878 |
-
)
|
879 |
-
|
880 |
-
# Add file format instructions
|
881 |
-
with gr.Row():
|
882 |
-
gr.Markdown("""
|
883 |
-
π‘ **Supported File Formats**:
|
884 |
-
- Excel files (.xlsx, .xls)
|
885 |
-
- CSV files (.csv)
|
886 |
|
887 |
-
|
888 |
-
|
889 |
-
|
890 |
-
|
891 |
-
|
892 |
-
with gr.Row():
|
893 |
-
gr.Markdown("### Select Analysis Types")
|
894 |
-
|
895 |
-
with gr.Row():
|
896 |
-
analysis_options = gr.CheckboxGroup(
|
897 |
-
choices=[
|
898 |
-
"π Demand Forecasting",
|
899 |
-
"β οΈ Risk Assessment",
|
900 |
-
"π¦ Inventory Optimization",
|
901 |
-
"π€ Supplier Performance",
|
902 |
-
"πΏ Sustainability Analysis"
|
903 |
-
],
|
904 |
-
label="Choose analyses to perform",
|
905 |
-
value=[] # Initialize with empty selection
|
906 |
-
)
|
907 |
-
|
908 |
-
|
909 |
-
analyze_button = gr.Button(
|
910 |
-
"π Run Analysis",
|
911 |
-
variant="primary",
|
912 |
-
elem_classes="action-button"
|
913 |
-
)
|
914 |
-
|
915 |
-
with gr.Row():
|
916 |
-
with gr.Column(scale=2):
|
917 |
-
analysis_output = gr.Textbox(
|
918 |
-
label="Analysis Results",
|
919 |
-
elem_classes="result-box"
|
920 |
-
)
|
921 |
-
with gr.Column(scale=3):
|
922 |
-
plot_output = gr.Plot(
|
923 |
-
label="Visualization",
|
924 |
-
elem_classes="chart-container"
|
925 |
)
|
926 |
-
|
927 |
-
|
928 |
-
|
929 |
-
|
930 |
-
|
931 |
-
|
932 |
-
# Freight Cost Prediction Tab
|
933 |
-
with gr.Tab("π° Cost Prediction", elem_classes="tab-content"):
|
934 |
-
with gr.Row():
|
935 |
-
shipment_mode = gr.Dropdown(
|
936 |
-
choices=["βοΈ Air", "π’ Ocean", "π Truck"],
|
937 |
-
label="Transport Mode",
|
938 |
-
value="βοΈ Air"
|
939 |
-
)
|
940 |
-
|
941 |
-
with gr.Row():
|
942 |
-
with gr.Column():
|
943 |
-
weight = gr.Slider(
|
944 |
-
label="π¦ Weight (kg)",
|
945 |
-
minimum=1,
|
946 |
-
maximum=10000,
|
947 |
-
step=1,
|
948 |
-
value=1000
|
949 |
)
|
950 |
-
|
951 |
-
|
952 |
-
|
953 |
-
|
954 |
-
maximum=1000000,
|
955 |
-
step=1,
|
956 |
-
value=10000
|
957 |
)
|
958 |
-
|
959 |
-
|
960 |
-
|
961 |
-
|
962 |
-
|
963 |
-
|
964 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
965 |
)
|
966 |
|
967 |
-
|
968 |
-
|
969 |
-
|
970 |
-
|
971 |
-
minimum=0,
|
972 |
-
maximum=10000
|
973 |
-
)
|
974 |
-
air_charter_value = gr.Slider(
|
975 |
-
label="Air Charter Value",
|
976 |
-
minimum=0,
|
977 |
-
maximum=1000000
|
978 |
-
)
|
979 |
-
|
980 |
-
with gr.Row(visible=False) as ocean_inputs:
|
981 |
-
ocean_weight = gr.Slider(
|
982 |
-
label="Ocean Weight",
|
983 |
-
minimum=0,
|
984 |
-
maximum=10000
|
985 |
-
)
|
986 |
-
ocean_value = gr.Slider(
|
987 |
-
label="Ocean Value",
|
988 |
-
minimum=0,
|
989 |
-
maximum=1000000
|
990 |
-
)
|
991 |
-
|
992 |
-
with gr.Row(visible=False) as truck_inputs:
|
993 |
-
truck_weight = gr.Slider(
|
994 |
-
label="Truck Weight",
|
995 |
-
minimum=0,
|
996 |
-
maximum=10000
|
997 |
-
)
|
998 |
-
truck_value = gr.Slider(
|
999 |
-
label="Truck Value",
|
1000 |
-
minimum=0,
|
1001 |
-
maximum=1000000
|
1002 |
)
|
1003 |
-
|
1004 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1005 |
predict_button = gr.Button(
|
1006 |
"π Calculate Cost",
|
1007 |
variant="primary",
|
@@ -1011,14 +1038,13 @@ def create_interface():
|
|
1011 |
label="Predicted Cost (USD)",
|
1012 |
elem_classes="result-box"
|
1013 |
)
|
1014 |
-
|
1015 |
# Chat Tab
|
1016 |
with gr.Tab("π¬ Chat", elem_classes="tab-content"):
|
1017 |
chatbot = gr.Chatbot(
|
1018 |
label="Chat History",
|
1019 |
elem_classes="chat-container",
|
1020 |
-
height=400
|
1021 |
-
type="messages"
|
1022 |
)
|
1023 |
with gr.Row():
|
1024 |
msg = gr.Textbox(
|
@@ -1032,7 +1058,7 @@ def create_interface():
|
|
1032 |
scale=1,
|
1033 |
elem_classes="action-button"
|
1034 |
)
|
1035 |
-
|
1036 |
# Report Tab
|
1037 |
with gr.Tab("π Report", elem_classes="tab-content"):
|
1038 |
report_button = gr.Button(
|
@@ -1043,11 +1069,7 @@ def create_interface():
|
|
1043 |
report_download = gr.File(
|
1044 |
label="Download Report"
|
1045 |
)
|
1046 |
-
|
1047 |
-
# Footer
|
1048 |
-
with gr.Row(elem_classes="footer"):
|
1049 |
-
gr.Markdown("Designed and Developed by Aditya Ratan Β© 2025")
|
1050 |
-
|
1051 |
# Event Handlers
|
1052 |
def update_mode_inputs(mode):
|
1053 |
return {
|
@@ -1062,27 +1084,15 @@ def create_interface():
|
|
1062 |
outputs=[upload_status]
|
1063 |
)
|
1064 |
|
1065 |
-
# Update the analyze button click handler
|
1066 |
analyze_button.click(
|
1067 |
fn=lambda choices, sales, supplier, text: run_analyses(state, choices, sales, supplier, text),
|
1068 |
inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
|
1069 |
outputs=[analysis_output, plot_output, raw_output]
|
1070 |
)
|
1071 |
|
1072 |
-
|
1073 |
-
shipment_mode.change(
|
1074 |
-
fn=update_mode_inputs,
|
1075 |
-
inputs=[shipment_mode],
|
1076 |
-
outputs=[air_inputs, ocean_inputs, truck_inputs]
|
1077 |
-
)
|
1078 |
-
|
1079 |
predict_button.click(
|
1080 |
-
fn=lambda *args:
|
1081 |
-
inputs=[
|
1082 |
-
weight, line_item_value, cost_per_kg,
|
1083 |
-
shipment_mode, air_charter_weight, ocean_weight, truck_weight,
|
1084 |
-
air_charter_value, ocean_value, truck_value
|
1085 |
-
],
|
1086 |
outputs=[freight_result]
|
1087 |
)
|
1088 |
|
@@ -1090,19 +1100,14 @@ def create_interface():
|
|
1090 |
fn=lambda message: chat_with_navigator(state, message),
|
1091 |
inputs=[msg],
|
1092 |
outputs=[chatbot]
|
1093 |
-
).then(
|
1094 |
-
fn=lambda: "",
|
1095 |
-
outputs=[msg]
|
1096 |
)
|
1097 |
|
1098 |
report_button.click(
|
1099 |
-
fn=lambda
|
1100 |
-
inputs=[analysis_options],
|
1101 |
outputs=[report_download]
|
1102 |
)
|
1103 |
-
|
1104 |
-
return demo
|
1105 |
|
|
|
1106 |
|
1107 |
# Update the launch parameters in __main__:
|
1108 |
if __name__ == "__main__":
|
|
|
825 |
state.freight_predictions.append(result)
|
826 |
return result
|
827 |
|
828 |
+
|
829 |
+
CUSTOM_CSS = """
|
830 |
+
/* Horizontal tabs layout */
|
831 |
+
.tabs {
|
832 |
+
display: flex !important;
|
833 |
+
flex-direction: column !important;
|
834 |
+
gap: 1rem !important;
|
835 |
+
}
|
836 |
+
|
837 |
+
.tabs > .tab-nav {
|
838 |
+
display: flex !important;
|
839 |
+
flex-direction: row !important;
|
840 |
+
gap: 0.5rem !important;
|
841 |
+
padding: 0.5rem !important;
|
842 |
+
background: #f8f9fa !important;
|
843 |
+
border-radius: 8px !important;
|
844 |
+
border-bottom: 2px solid #e9ecef !important;
|
845 |
+
}
|
846 |
+
|
847 |
+
.tabs > .tab-nav > button {
|
848 |
+
flex: 1 !important;
|
849 |
+
padding: 0.75rem 1rem !important;
|
850 |
+
border-radius: 6px !important;
|
851 |
+
border: none !important;
|
852 |
+
background: transparent !important;
|
853 |
+
color: #495057 !important;
|
854 |
+
font-weight: 500 !important;
|
855 |
+
transition: all 0.2s ease !important;
|
856 |
+
}
|
857 |
+
|
858 |
+
.tabs > .tab-nav > button.selected {
|
859 |
+
background: white !important;
|
860 |
+
color: #228be6 !important;
|
861 |
+
box-shadow: 0 2px 4px rgba(0,0,0,0.1) !important;
|
862 |
+
}
|
863 |
+
|
864 |
+
.tab-content {
|
865 |
+
padding: 1.5rem !important;
|
866 |
+
background: white !important;
|
867 |
+
border-radius: 8px !important;
|
868 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important;
|
869 |
+
}
|
870 |
+
|
871 |
+
/* Additional styling */
|
872 |
+
.main-header {
|
873 |
+
background: linear-gradient(135deg, #0061a8 0%, #003459 100%);
|
874 |
+
padding: 2rem;
|
875 |
+
color: white;
|
876 |
+
border-radius: 8px;
|
877 |
+
margin-bottom: 2rem;
|
878 |
+
}
|
879 |
+
|
880 |
+
.app-title {
|
881 |
+
font-size: 2.5rem !important;
|
882 |
+
margin-bottom: 0.5rem !important;
|
883 |
+
}
|
884 |
+
|
885 |
+
.app-subtitle {
|
886 |
+
opacity: 0.9;
|
887 |
+
margin-bottom: 1rem !important;
|
888 |
+
}
|
889 |
+
|
890 |
+
.action-button {
|
891 |
+
background: #228be6 !important;
|
892 |
+
border-radius: 6px !important;
|
893 |
+
transition: all 0.2s ease !important;
|
894 |
+
}
|
895 |
+
|
896 |
+
.action-button:hover {
|
897 |
+
transform: translateY(-2px) !important;
|
898 |
+
box-shadow: 0 4px 8px rgba(34, 139, 230, 0.2) !important;
|
899 |
+
}
|
900 |
+
|
901 |
+
.file-upload {
|
902 |
+
border: 2px dashed #e9ecef !important;
|
903 |
+
border-radius: 8px !important;
|
904 |
+
padding: 1rem !important;
|
905 |
+
}
|
906 |
+
|
907 |
+
.result-box {
|
908 |
+
background: #f8f9fa !important;
|
909 |
+
border-radius: 6px !important;
|
910 |
+
padding: 1rem !important;
|
911 |
+
}
|
912 |
+
|
913 |
+
.chart-container {
|
914 |
+
background: white !important;
|
915 |
+
border-radius: 8px !important;
|
916 |
+
box-shadow: 0 2px 8px rgba(0,0,0,0.05) !important;
|
917 |
+
}
|
918 |
+
"""
|
919 |
+
|
920 |
def create_interface():
|
921 |
"""Create Gradio interface with enhanced UI"""
|
922 |
state = SupplyChainState()
|
|
|
933 |
# Main Content Tabs
|
934 |
with gr.Tabs() as tabs:
|
935 |
# Data Upload Tab
|
936 |
+
with gr.Tab("π Data Upload", elem_classes="tab-content"):
|
937 |
+
with gr.Row():
|
938 |
+
with gr.Column(scale=1):
|
939 |
+
sales_data_upload = gr.File(
|
940 |
+
file_types=[".xlsx", ".xls", ".csv"],
|
941 |
+
label="π Sales Data (Excel or CSV)",
|
942 |
+
elem_classes="file-upload"
|
943 |
+
)
|
944 |
+
gr.Markdown("*Upload sales data in Excel (.xlsx, .xls) or CSV format*", elem_classes="file-instructions")
|
945 |
|
946 |
+
with gr.Column(scale=1):
|
947 |
+
supplier_data_upload = gr.File(
|
948 |
+
file_types=[".xlsx", ".xls", ".csv"],
|
949 |
+
label="π Supplier Data (Excel or CSV)",
|
950 |
+
elem_classes="file-upload"
|
951 |
+
)
|
952 |
+
gr.Markdown("*Upload supplier data in Excel (.xlsx, .xls) or CSV format*", elem_classes="file-instructions")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
953 |
|
954 |
+
with gr.Row():
|
955 |
+
text_input_area = gr.Textbox(
|
956 |
+
label="π Additional Context",
|
957 |
+
placeholder="Add market updates, news, or other relevant information...",
|
958 |
+
lines=5
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
959 |
)
|
960 |
+
|
961 |
+
with gr.Row():
|
962 |
+
upload_status = gr.Textbox(
|
963 |
+
label="Status",
|
964 |
+
elem_classes="status-box"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
965 |
)
|
966 |
+
upload_button = gr.Button(
|
967 |
+
"π Process Data",
|
968 |
+
variant="primary",
|
969 |
+
elem_classes="action-button"
|
|
|
|
|
|
|
970 |
)
|
971 |
+
|
972 |
+
# Analysis Tab
|
973 |
+
with gr.Tab("π Analysis", elem_classes="tab-content"):
|
974 |
+
with gr.Row():
|
975 |
+
analysis_options = gr.CheckboxGroup(
|
976 |
+
choices=[
|
977 |
+
"π Demand Forecasting",
|
978 |
+
"β οΈ Risk Assessment",
|
979 |
+
"π¦ Inventory Optimization",
|
980 |
+
"π€ Supplier Performance",
|
981 |
+
"πΏ Sustainability Analysis"
|
982 |
+
],
|
983 |
+
label="Choose analyses to perform",
|
984 |
+
value=[]
|
985 |
)
|
986 |
|
987 |
+
analyze_button = gr.Button(
|
988 |
+
"π Run Analysis",
|
989 |
+
variant="primary",
|
990 |
+
elem_classes="action-button"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
991 |
)
|
992 |
+
|
993 |
+
with gr.Row():
|
994 |
+
with gr.Column(scale=2):
|
995 |
+
analysis_output = gr.Textbox(
|
996 |
+
label="Analysis Results",
|
997 |
+
elem_classes="result-box"
|
998 |
+
)
|
999 |
+
with gr.Column(scale=3):
|
1000 |
+
plot_output = gr.Plot(
|
1001 |
+
label="Visualization",
|
1002 |
+
elem_classes="chart-container"
|
1003 |
+
)
|
1004 |
+
|
1005 |
+
# Cost Prediction Tab
|
1006 |
+
with gr.Tab("π° Cost Prediction", elem_classes="tab-content"):
|
1007 |
+
with gr.Row():
|
1008 |
+
shipment_mode = gr.Dropdown(
|
1009 |
+
choices=["βοΈ Air", "π’ Ocean", "π Truck"],
|
1010 |
+
label="Transport Mode",
|
1011 |
+
value="βοΈ Air"
|
1012 |
+
)
|
1013 |
+
|
1014 |
+
with gr.Row():
|
1015 |
+
with gr.Column():
|
1016 |
+
weight = gr.Slider(
|
1017 |
+
label="π¦ Weight (kg)",
|
1018 |
+
minimum=1,
|
1019 |
+
maximum=10000,
|
1020 |
+
step=1,
|
1021 |
+
value=1000
|
1022 |
+
)
|
1023 |
+
with gr.Column():
|
1024 |
+
line_item_value = gr.Slider(
|
1025 |
+
label="π΅ Item Value (USD)",
|
1026 |
+
minimum=1,
|
1027 |
+
maximum=1000000,
|
1028 |
+
step=1,
|
1029 |
+
value=10000
|
1030 |
+
)
|
1031 |
+
|
1032 |
predict_button = gr.Button(
|
1033 |
"π Calculate Cost",
|
1034 |
variant="primary",
|
|
|
1038 |
label="Predicted Cost (USD)",
|
1039 |
elem_classes="result-box"
|
1040 |
)
|
1041 |
+
|
1042 |
# Chat Tab
|
1043 |
with gr.Tab("π¬ Chat", elem_classes="tab-content"):
|
1044 |
chatbot = gr.Chatbot(
|
1045 |
label="Chat History",
|
1046 |
elem_classes="chat-container",
|
1047 |
+
height=400
|
|
|
1048 |
)
|
1049 |
with gr.Row():
|
1050 |
msg = gr.Textbox(
|
|
|
1058 |
scale=1,
|
1059 |
elem_classes="action-button"
|
1060 |
)
|
1061 |
+
|
1062 |
# Report Tab
|
1063 |
with gr.Tab("π Report", elem_classes="tab-content"):
|
1064 |
report_button = gr.Button(
|
|
|
1069 |
report_download = gr.File(
|
1070 |
label="Download Report"
|
1071 |
)
|
1072 |
+
|
|
|
|
|
|
|
|
|
1073 |
# Event Handlers
|
1074 |
def update_mode_inputs(mode):
|
1075 |
return {
|
|
|
1084 |
outputs=[upload_status]
|
1085 |
)
|
1086 |
|
|
|
1087 |
analyze_button.click(
|
1088 |
fn=lambda choices, sales, supplier, text: run_analyses(state, choices, sales, supplier, text),
|
1089 |
inputs=[analysis_options, sales_data_upload, supplier_data_upload, text_input_area],
|
1090 |
outputs=[analysis_output, plot_output, raw_output]
|
1091 |
)
|
1092 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1093 |
predict_button.click(
|
1094 |
+
fn=lambda *args: predict_freight_cost(state, *args),
|
1095 |
+
inputs=[weight, line_item_value, shipment_mode],
|
|
|
|
|
|
|
|
|
1096 |
outputs=[freight_result]
|
1097 |
)
|
1098 |
|
|
|
1100 |
fn=lambda message: chat_with_navigator(state, message),
|
1101 |
inputs=[msg],
|
1102 |
outputs=[chatbot]
|
|
|
|
|
|
|
1103 |
)
|
1104 |
|
1105 |
report_button.click(
|
1106 |
+
fn=lambda: generate_report(state),
|
|
|
1107 |
outputs=[report_download]
|
1108 |
)
|
|
|
|
|
1109 |
|
1110 |
+
return demo
|
1111 |
|
1112 |
# Update the launch parameters in __main__:
|
1113 |
if __name__ == "__main__":
|