Upload 7 files
Browse files- .gitattributes +1 -0
- Dockerfile +20 -0
- app.py +181 -0
- lgb_model_cropforecastinghyperparamters__33333.pkl +3 -0
- requirements.txt +7 -0
- static/img1.jpg +3 -0
- templates/index.html +378 -0
- templates/output.html +412 -0
.gitattributes
CHANGED
|
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
|
|
| 33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
| 34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
| 35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
| 36 |
+
static/img1.jpg filter=lfs diff=lfs merge=lfs -text
|
Dockerfile
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
# Use an official Python runtime as a parent image
|
| 2 |
+
FROM python:3.9-slim
|
| 3 |
+
|
| 4 |
+
# Set the working directory
|
| 5 |
+
WORKDIR /app
|
| 6 |
+
|
| 7 |
+
# Copy the application files to the container
|
| 8 |
+
COPY . /app
|
| 9 |
+
|
| 10 |
+
# Install Python dependencies
|
| 11 |
+
RUN pip install --no-cache-dir -r requirements.txt
|
| 12 |
+
|
| 13 |
+
RUN apt-get update && apt-get install -y libgomp1
|
| 14 |
+
|
| 15 |
+
|
| 16 |
+
# Expose the Flask port (Hugging Face Spaces uses port 7860 by default)
|
| 17 |
+
EXPOSE 7860
|
| 18 |
+
|
| 19 |
+
# Command to run the Flask app
|
| 20 |
+
CMD ["python", "app.py"]
|
app.py
ADDED
|
@@ -0,0 +1,181 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
from flask import Flask, render_template, request, jsonify
|
| 2 |
+
import pandas as pd
|
| 3 |
+
import plotly.express as px
|
| 4 |
+
import plotly.graph_objects as go
|
| 5 |
+
import plotly.io as pio
|
| 6 |
+
import joblib
|
| 7 |
+
import numpy as np
|
| 8 |
+
|
| 9 |
+
app = Flask(__name__)
|
| 10 |
+
|
| 11 |
+
url='https://drive.google.com/file/d/1_vd4HISZB2h2--CiXKezeWDXHHo2fY23/view?usp=sharing'
|
| 12 |
+
df = pd.read_csv('https://drive.usercontent.google.com/download?id={}&export=download&authuser=0&confirm=t'.format(url.split('/')[-2]))
|
| 13 |
+
|
| 14 |
+
for column in ['State', 'District', 'Crop', 'Season']:
|
| 15 |
+
df[column] = df[column].str.strip()
|
| 16 |
+
|
| 17 |
+
# Load the model for predictions
|
| 18 |
+
model_filename = 'lgb_model_cropforecastinghyperparamters__33333.pkl'
|
| 19 |
+
model = joblib.load(model_filename)
|
| 20 |
+
|
| 21 |
+
# Use a 2% sample for faster processing
|
| 22 |
+
sampled_df = df.sample(frac=0.02, random_state=42)
|
| 23 |
+
|
| 24 |
+
@app.route('/')
|
| 25 |
+
def index():
|
| 26 |
+
states = sampled_df['State'].unique()
|
| 27 |
+
crops = sampled_df['Crop'].unique()
|
| 28 |
+
seasons = sampled_df['Season'].unique()
|
| 29 |
+
return render_template('index.html', states=states, crops=crops, seasons=seasons)
|
| 30 |
+
|
| 31 |
+
@app.route('/filter_districts', methods=['POST'])
|
| 32 |
+
def filter_districts():
|
| 33 |
+
state = request.form['state']
|
| 34 |
+
districts = sampled_df[sampled_df['State'] == state]['District'].unique()
|
| 35 |
+
return jsonify({'districts': list(districts)})
|
| 36 |
+
|
| 37 |
+
@app.route('/predict', methods=['POST'])
|
| 38 |
+
def predict():
|
| 39 |
+
state = request.form['state']
|
| 40 |
+
district = request.form['district']
|
| 41 |
+
crop_year = int(request.form['crop_year'])
|
| 42 |
+
season = request.form['season']
|
| 43 |
+
crop = request.form['crop']
|
| 44 |
+
area = float(request.form['area'])
|
| 45 |
+
|
| 46 |
+
# Prepare input for prediction
|
| 47 |
+
input_data = pd.DataFrame({
|
| 48 |
+
'State': [state],
|
| 49 |
+
'District': [district],
|
| 50 |
+
'Crop_Year': [crop_year],
|
| 51 |
+
'Season': [season],
|
| 52 |
+
'Crop': [crop],
|
| 53 |
+
'Area': [area]
|
| 54 |
+
})
|
| 55 |
+
|
| 56 |
+
# Ensure consistent categories with the original DataFrame
|
| 57 |
+
input_data['State'] = input_data['State'].astype(pd.CategoricalDtype(categories=df['State'].unique()))
|
| 58 |
+
input_data['District'] = input_data['District'].astype(pd.CategoricalDtype(categories=df['District'].unique()))
|
| 59 |
+
input_data['Season'] = input_data['Season'].astype(pd.CategoricalDtype(categories=df['Season'].unique()))
|
| 60 |
+
input_data['Crop'] = input_data['Crop'].astype(pd.CategoricalDtype(categories=df['Crop'].unique()))
|
| 61 |
+
|
| 62 |
+
# Make prediction
|
| 63 |
+
prediction = model.predict(input_data)[0]
|
| 64 |
+
prediction_tons = max(0, round(prediction, 2)) # Ensure prediction is non-negative
|
| 65 |
+
|
| 66 |
+
# Calculate production/area ratio
|
| 67 |
+
nearest_area = find_nearest_area(state, district)
|
| 68 |
+
production_ratio = round((prediction_tons / nearest_area), 2)
|
| 69 |
+
ratio_category = categorize_production_ratio(production_ratio)
|
| 70 |
+
|
| 71 |
+
# Generate updated graphs based on the selected state and district
|
| 72 |
+
pie_chart = generate_pie_chart(state, district, crop)
|
| 73 |
+
area_vs_production = generate_area_vs_production(state, district)
|
| 74 |
+
season_vs_production = generate_season_vs_production(state, district)
|
| 75 |
+
top_states_by_production = generate_top_states_plot()
|
| 76 |
+
yearly_violin_plot = generate_yearly_violin_plot()
|
| 77 |
+
crop_year_vs_production = generate_crop_year_vs_production(state, district)
|
| 78 |
+
|
| 79 |
+
# Create gauge chart for the production ratio
|
| 80 |
+
gauge_chart = generate_gauge_chart(production_ratio, ratio_category)
|
| 81 |
+
|
| 82 |
+
# Hardcoded suggestions based on production ratio
|
| 83 |
+
suggestions = generate_suggestions(ratio_category, crop, district)
|
| 84 |
+
|
| 85 |
+
return render_template('output.html',
|
| 86 |
+
prediction=prediction_tons,
|
| 87 |
+
ratio=production_ratio,
|
| 88 |
+
pie_chart_html=pio.to_html(pie_chart, full_html=False),
|
| 89 |
+
season_vs_production_html=pio.to_html(season_vs_production, full_html=False),
|
| 90 |
+
area_vs_production_html=pio.to_html(area_vs_production, full_html=False),
|
| 91 |
+
top_states_html=pio.to_html(top_states_by_production, full_html=False),
|
| 92 |
+
yearly_violin_plot_html=pio.to_html(yearly_violin_plot, full_html=False),
|
| 93 |
+
crop_year_vs_production_html=pio.to_html(crop_year_vs_production, full_html=False),
|
| 94 |
+
gauge_chart_html=pio.to_html(gauge_chart, full_html=False),
|
| 95 |
+
suggestions=suggestions)
|
| 96 |
+
|
| 97 |
+
|
| 98 |
+
def find_nearest_area(state, district):
|
| 99 |
+
# Calculate the nearest similar area for the district using average
|
| 100 |
+
district_data = sampled_df[(sampled_df['State'] == state) & (sampled_df['District'] == district)]
|
| 101 |
+
return district_data['Area'].mean()
|
| 102 |
+
|
| 103 |
+
def categorize_production_ratio(ratio):
|
| 104 |
+
if ratio <= 2:
|
| 105 |
+
return 'Very Low'
|
| 106 |
+
elif ratio <= 4:
|
| 107 |
+
return 'Low'
|
| 108 |
+
elif ratio <= 6:
|
| 109 |
+
return 'Normal'
|
| 110 |
+
elif ratio <= 8:
|
| 111 |
+
return 'High'
|
| 112 |
+
else:
|
| 113 |
+
return 'Very High'
|
| 114 |
+
|
| 115 |
+
def generate_suggestions(category, crop, district):
|
| 116 |
+
suggestions = {
|
| 117 |
+
'Very Low': f"Increase soil nutrients and irrigation efficiency. Consider crop rotation strategies. {crop} is not suitable for {district} based on the given conditions and season. Try advanced farming methods or consider growing alternative crops that are better suited to this region.",
|
| 118 |
+
'Low': f"Optimize seed selection and planting techniques. {crop} is somewhat suitable for {district}, but production may be low. Monitor soil moisture regularly and apply precise farming techniques. Current strategies may need improvement for better yields.",
|
| 119 |
+
'Normal': f"Maintain current practices but focus on improving pest control and irrigation. {crop} is generally performing well in {district}. Production and profit depend heavily on farming practices and weather conditions, but there is potential for increased revenue.",
|
| 120 |
+
'High': f"Consider diversifying crops or expanding production. Explore more efficient harvesting methods to optimize yield and profitability. {crop} thrives in {district}, and with better mechanization or workforce management, you can further boost production and income potential.",
|
| 121 |
+
'Very High': f"{crop} is performing exceptionally well in {district}. Explore export opportunities to maximize profitability. Optimize production processes to sustain high yields while minimizing additional inputs. Consider expanding into new markets, and explore ways to reduce production costs, such as through precision farming or automation."
|
| 122 |
+
}
|
| 123 |
+
return suggestions.get(category, "No suggestions available.")
|
| 124 |
+
|
| 125 |
+
|
| 126 |
+
def generate_gauge_chart(ratio, category):
|
| 127 |
+
colors = ["#ff0000", "#ff6666", "#ffa500", "#ffff00", "#32cd32"]
|
| 128 |
+
fig = go.Figure(go.Indicator(
|
| 129 |
+
mode="gauge+number+delta",
|
| 130 |
+
value=ratio,
|
| 131 |
+
title={'text': "Production Ratio"},
|
| 132 |
+
delta={'reference': 5},
|
| 133 |
+
gauge={'axis': {'range': [None, 10]},
|
| 134 |
+
'bar': {'color': "darkblue"},
|
| 135 |
+
'steps': [{'range': [0, 2], 'color': colors[0]},
|
| 136 |
+
{'range': [2, 4], 'color': colors[1]},
|
| 137 |
+
{'range': [4, 6], 'color': colors[2]},
|
| 138 |
+
{'range': [6, 8], 'color': colors[3]},
|
| 139 |
+
{'range': [8, 10], 'color': colors[4]}]}))
|
| 140 |
+
return fig
|
| 141 |
+
|
| 142 |
+
def generate_pie_chart(state, district, crop):
|
| 143 |
+
filtered_data = sampled_df[(sampled_df['State'] == state) & (sampled_df['District'] == district)]
|
| 144 |
+
crop_data = filtered_data.groupby('Crop')['Production'].sum().reset_index()
|
| 145 |
+
crop_data['Percentage'] = (crop_data['Production'] / crop_data['Production'].sum()) * 100
|
| 146 |
+
crop_data = crop_data[crop_data['Percentage'] > 3]
|
| 147 |
+
fig = px.pie(crop_data, names='Crop', values='Production', title='Popular Crops in the Given Region')
|
| 148 |
+
return fig
|
| 149 |
+
|
| 150 |
+
def generate_season_vs_production(state, district):
|
| 151 |
+
filtered_data = sampled_df[(sampled_df['State'] == state) & (sampled_df['District'] == district)]
|
| 152 |
+
fig = px.bar(filtered_data, x='Season', y='Production', title='Season vs Production (Sum for All Crops)')
|
| 153 |
+
fig.update_traces(marker_color='darkblue')
|
| 154 |
+
return fig
|
| 155 |
+
|
| 156 |
+
def generate_area_vs_production(state, district):
|
| 157 |
+
filtered_data = sampled_df[(sampled_df['State'] == state) & (sampled_df['District'] == district)]
|
| 158 |
+
fig = px.density_heatmap(filtered_data, x='Area', y='Production', title='Area vs Production (Hexbin Plot)',
|
| 159 |
+
range_x=[0, 10000], nbinsx=5)
|
| 160 |
+
return fig
|
| 161 |
+
|
| 162 |
+
def generate_top_states_plot():
|
| 163 |
+
state_data = sampled_df.groupby('State')['Production'].sum().reset_index()
|
| 164 |
+
top_states = state_data.nlargest(10, 'Production')
|
| 165 |
+
fig = px.bar(top_states, x='State', y='Production', title='Top 10 States by Production (Overall)')
|
| 166 |
+
return fig
|
| 167 |
+
|
| 168 |
+
def generate_yearly_violin_plot():
|
| 169 |
+
filtered_data = sampled_df[sampled_df['Crop_Year'] >= 2014]
|
| 170 |
+
fig = px.violin(filtered_data, x='Crop_Year', y='Production', title='Violin Plot: Overall Production (2014-2023)')
|
| 171 |
+
return fig
|
| 172 |
+
|
| 173 |
+
def generate_crop_year_vs_production(state, district):
|
| 174 |
+
filtered_data = sampled_df[sampled_df['Crop_Year'] >= 2014]
|
| 175 |
+
fig = px.bar(filtered_data, x='Crop_Year', y='Production', title='Year vs Production Count (2014-2023)',
|
| 176 |
+
labels={'Crop_Year': 'Year', 'Production': 'Production Count'})
|
| 177 |
+
fig.update_traces(marker_color='darkblue')
|
| 178 |
+
return fig
|
| 179 |
+
|
| 180 |
+
if __name__ == '__main__':
|
| 181 |
+
app.run(port=7860,host='0.0.0.0')
|
lgb_model_cropforecastinghyperparamters__33333.pkl
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
version https://git-lfs.github.com/spec/v1
|
| 2 |
+
oid sha256:572294da95026ba0d4067408bd2cfcf2a5816a87be18c02e53597516feaa1bff
|
| 3 |
+
size 270332
|
requirements.txt
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
flask
|
| 2 |
+
pandas
|
| 3 |
+
plotly
|
| 4 |
+
numpy
|
| 5 |
+
joblib==1.4.2
|
| 6 |
+
scikit-learn==1.5.2
|
| 7 |
+
lightgbm
|
static/img1.jpg
ADDED
|
Git LFS Details
|
templates/index.html
ADDED
|
@@ -0,0 +1,378 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8">
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
+
<title>Crop Yield Prediction</title>
|
| 8 |
+
<!-- Fonts -->
|
| 9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<!-- Bootstrap -->
|
| 13 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 14 |
+
<!-- Icons -->
|
| 15 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
| 16 |
+
|
| 17 |
+
<style>
|
| 18 |
+
:root {
|
| 19 |
+
--primary-green: #1a5d3a;
|
| 20 |
+
--accent-green: #198754;
|
| 21 |
+
--darker-accent: #143d2e;
|
| 22 |
+
--light-bg: #f8f9fa;
|
| 23 |
+
--surface: #ffffff;
|
| 24 |
+
--text-dark: #212529;
|
| 25 |
+
--text-muted: #6c757d;
|
| 26 |
+
--border: #dee2e6;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
* {
|
| 30 |
+
box-sizing: border-box;
|
| 31 |
+
margin: 0;
|
| 32 |
+
padding: 0;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
body {
|
| 36 |
+
font-family: 'Outfit', sans-serif;
|
| 37 |
+
background-color: var(--light-bg);
|
| 38 |
+
color: var(--text-dark);
|
| 39 |
+
min-height: 100vh;
|
| 40 |
+
display: flex;
|
| 41 |
+
flex-direction: column;
|
| 42 |
+
}
|
| 43 |
+
|
| 44 |
+
/* --- Hero Header Section --- */
|
| 45 |
+
.hero-header {
|
| 46 |
+
background-color: var(--primary-green);
|
| 47 |
+
color: white;
|
| 48 |
+
padding: 4rem 1rem 7rem;
|
| 49 |
+
text-align: center;
|
| 50 |
+
border-bottom-left-radius: 60px;
|
| 51 |
+
border-bottom-right-radius: 60px;
|
| 52 |
+
position: relative;
|
| 53 |
+
}
|
| 54 |
+
|
| 55 |
+
.hero-icon {
|
| 56 |
+
font-size: 3rem;
|
| 57 |
+
margin-bottom: 1rem;
|
| 58 |
+
display: block;
|
| 59 |
+
}
|
| 60 |
+
|
| 61 |
+
.hero-title {
|
| 62 |
+
font-weight: 700;
|
| 63 |
+
font-size: 2.5rem;
|
| 64 |
+
margin-bottom: 0.5rem;
|
| 65 |
+
}
|
| 66 |
+
|
| 67 |
+
.hero-subtitle {
|
| 68 |
+
font-weight: 300;
|
| 69 |
+
opacity: 0.9;
|
| 70 |
+
font-size: 1.1rem;
|
| 71 |
+
}
|
| 72 |
+
|
| 73 |
+
/* --- Main Card --- */
|
| 74 |
+
.main-container {
|
| 75 |
+
margin-top: -5rem;
|
| 76 |
+
padding-bottom: 3rem;
|
| 77 |
+
display: flex;
|
| 78 |
+
justify-content: center;
|
| 79 |
+
padding-left: 15px;
|
| 80 |
+
padding-right: 15px;
|
| 81 |
+
}
|
| 82 |
+
|
| 83 |
+
.prediction-card {
|
| 84 |
+
background: var(--surface);
|
| 85 |
+
border-radius: 20px;
|
| 86 |
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08);
|
| 87 |
+
width: 100%;
|
| 88 |
+
max-width: 900px;
|
| 89 |
+
padding: 3rem;
|
| 90 |
+
position: relative;
|
| 91 |
+
}
|
| 92 |
+
|
| 93 |
+
/* --- 3-Step Process Icons --- */
|
| 94 |
+
.process-steps {
|
| 95 |
+
display: flex;
|
| 96 |
+
justify-content: center;
|
| 97 |
+
gap: 4rem;
|
| 98 |
+
margin-bottom: 3rem;
|
| 99 |
+
text-align: center;
|
| 100 |
+
}
|
| 101 |
+
|
| 102 |
+
.step-item {
|
| 103 |
+
display: flex;
|
| 104 |
+
flex-direction: column;
|
| 105 |
+
align-items: center;
|
| 106 |
+
color: var(--text-dark);
|
| 107 |
+
}
|
| 108 |
+
|
| 109 |
+
.step-icon {
|
| 110 |
+
width: 50px;
|
| 111 |
+
height: 50px;
|
| 112 |
+
border-radius: 50%;
|
| 113 |
+
border: 1px solid #e9ecef;
|
| 114 |
+
display: flex;
|
| 115 |
+
align-items: center;
|
| 116 |
+
justify-content: center;
|
| 117 |
+
font-size: 1.2rem;
|
| 118 |
+
color: var(--primary-green);
|
| 119 |
+
margin-bottom: 0.5rem;
|
| 120 |
+
background: #fff;
|
| 121 |
+
}
|
| 122 |
+
|
| 123 |
+
.step-title {
|
| 124 |
+
font-weight: 600;
|
| 125 |
+
font-size: 0.9rem;
|
| 126 |
+
margin-bottom: 0px;
|
| 127 |
+
}
|
| 128 |
+
|
| 129 |
+
.step-desc {
|
| 130 |
+
font-size: 0.75rem;
|
| 131 |
+
color: var(--text-muted);
|
| 132 |
+
}
|
| 133 |
+
|
| 134 |
+
/* --- Form Styles --- */
|
| 135 |
+
.form-label {
|
| 136 |
+
font-weight: 600;
|
| 137 |
+
font-size: 0.85rem;
|
| 138 |
+
margin-bottom: 0.5rem;
|
| 139 |
+
color: var(--text-dark);
|
| 140 |
+
text-transform: uppercase;
|
| 141 |
+
letter-spacing: 0.05em;
|
| 142 |
+
}
|
| 143 |
+
|
| 144 |
+
.form-control,
|
| 145 |
+
.form-select {
|
| 146 |
+
padding: 0.85rem 1rem;
|
| 147 |
+
border: 1px solid var(--border);
|
| 148 |
+
border-radius: 8px;
|
| 149 |
+
background-color: var(--light-bg);
|
| 150 |
+
font-family: 'Outfit', sans-serif;
|
| 151 |
+
font-size: 1rem;
|
| 152 |
+
color: var(--text-dark);
|
| 153 |
+
transition: all 0.2s ease;
|
| 154 |
+
}
|
| 155 |
+
|
| 156 |
+
.form-control:focus,
|
| 157 |
+
.form-select:focus {
|
| 158 |
+
border-color: var(--accent-green);
|
| 159 |
+
box-shadow: 0 0 0 4px rgba(25, 135, 84, 0.1);
|
| 160 |
+
background-color: white;
|
| 161 |
+
outline: none;
|
| 162 |
+
}
|
| 163 |
+
|
| 164 |
+
/* --- Predict Button --- */
|
| 165 |
+
.btn-predict {
|
| 166 |
+
width: 100%;
|
| 167 |
+
background-color: var(--primary-green);
|
| 168 |
+
color: white;
|
| 169 |
+
border: none;
|
| 170 |
+
padding: 1rem;
|
| 171 |
+
border-radius: 8px;
|
| 172 |
+
font-weight: 600;
|
| 173 |
+
font-size: 1.1rem;
|
| 174 |
+
margin-top: 2rem;
|
| 175 |
+
transition: background 0.3s;
|
| 176 |
+
display: flex;
|
| 177 |
+
align-items: center;
|
| 178 |
+
justify-content: center;
|
| 179 |
+
gap: 0.5rem;
|
| 180 |
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
| 181 |
+
}
|
| 182 |
+
|
| 183 |
+
.btn-predict:hover {
|
| 184 |
+
background-color: var(--darker-accent);
|
| 185 |
+
color: white;
|
| 186 |
+
transform: translateY(-2px);
|
| 187 |
+
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
| 188 |
+
}
|
| 189 |
+
|
| 190 |
+
/* --- Footer --- */
|
| 191 |
+
.footer {
|
| 192 |
+
margin-top: auto;
|
| 193 |
+
text-align: center;
|
| 194 |
+
padding: 2rem;
|
| 195 |
+
color: #adb5bd;
|
| 196 |
+
font-size: 0.8rem;
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
/* --- Loading Overlay --- */
|
| 200 |
+
#loadingOverlay {
|
| 201 |
+
display: none;
|
| 202 |
+
position: fixed;
|
| 203 |
+
top: 0;
|
| 204 |
+
left: 0;
|
| 205 |
+
width: 100%;
|
| 206 |
+
height: 100%;
|
| 207 |
+
background: rgba(255, 255, 255, 0.95);
|
| 208 |
+
z-index: 9999;
|
| 209 |
+
flex-direction: column;
|
| 210 |
+
align-items: center;
|
| 211 |
+
justify-content: center;
|
| 212 |
+
}
|
| 213 |
+
|
| 214 |
+
.spinner-border {
|
| 215 |
+
color: var(--primary-green);
|
| 216 |
+
width: 3rem;
|
| 217 |
+
height: 3rem;
|
| 218 |
+
}
|
| 219 |
+
|
| 220 |
+
/* --- Responsive --- */
|
| 221 |
+
@media (max-width: 768px) {
|
| 222 |
+
.hero-title {
|
| 223 |
+
font-size: 1.75rem;
|
| 224 |
+
}
|
| 225 |
+
|
| 226 |
+
.prediction-card {
|
| 227 |
+
padding: 1.5rem;
|
| 228 |
+
}
|
| 229 |
+
|
| 230 |
+
.process-steps {
|
| 231 |
+
gap: 2rem;
|
| 232 |
+
}
|
| 233 |
+
|
| 234 |
+
.step-icon {
|
| 235 |
+
width: 40px;
|
| 236 |
+
height: 40px;
|
| 237 |
+
font-size: 1rem;
|
| 238 |
+
}
|
| 239 |
+
|
| 240 |
+
.hero-header {
|
| 241 |
+
border-bottom-left-radius: 40px;
|
| 242 |
+
border-bottom-right-radius: 40px;
|
| 243 |
+
}
|
| 244 |
+
}
|
| 245 |
+
</style>
|
| 246 |
+
</head>
|
| 247 |
+
|
| 248 |
+
<body>
|
| 249 |
+
|
| 250 |
+
<!-- Hero Header -->
|
| 251 |
+
<div class="hero-header">
|
| 252 |
+
<i class="bi bi-graph-up-arrow hero-icon"></i>
|
| 253 |
+
<h1 class="hero-title">Crop Yield Prediction</h1>
|
| 254 |
+
<p class="hero-subtitle">AI-powered yield forecasting for smarter farming decisions</p>
|
| 255 |
+
</div>
|
| 256 |
+
|
| 257 |
+
<!-- Main Content -->
|
| 258 |
+
<div class="main-container">
|
| 259 |
+
<div class="prediction-card">
|
| 260 |
+
|
| 261 |
+
<!-- Steps -->
|
| 262 |
+
<div class="process-steps">
|
| 263 |
+
<div class="step-item">
|
| 264 |
+
<div class="step-icon"><i class="bi bi-geo-alt"></i></div>
|
| 265 |
+
<div class="step-title">1. Location</div>
|
| 266 |
+
<div class="step-desc">Select your region</div>
|
| 267 |
+
</div>
|
| 268 |
+
<div class="step-item">
|
| 269 |
+
<div class="step-icon"><i class="bi bi-flower1"></i></div>
|
| 270 |
+
<div class="step-title">2. Crop Info</div>
|
| 271 |
+
<div class="step-desc">Enter crop details</div>
|
| 272 |
+
</div>
|
| 273 |
+
<div class="step-item">
|
| 274 |
+
<div class="step-icon"><i class="bi bi-bar-chart-line"></i></div>
|
| 275 |
+
<div class="step-title">3. Predict</div>
|
| 276 |
+
<div class="step-desc">Get yield forecast</div>
|
| 277 |
+
</div>
|
| 278 |
+
</div>
|
| 279 |
+
|
| 280 |
+
<!-- Form -->
|
| 281 |
+
<form id="prediction-form" method="POST" action="/predict">
|
| 282 |
+
<div class="row g-4">
|
| 283 |
+
<div class="col-md-6">
|
| 284 |
+
<label for="state" class="form-label"><i class="bi bi-geo-alt me-1"></i>State</label>
|
| 285 |
+
<select id="state" name="state" class="form-select" required>
|
| 286 |
+
<option value="">Select State</option>
|
| 287 |
+
{% for state in states %}
|
| 288 |
+
<option value="{{ state }}">{{ state }}</option>
|
| 289 |
+
{% endfor %}
|
| 290 |
+
</select>
|
| 291 |
+
</div>
|
| 292 |
+
|
| 293 |
+
<div class="col-md-6">
|
| 294 |
+
<label for="district" class="form-label"><i class="bi bi-pin-map me-1"></i>District</label>
|
| 295 |
+
<select id="district" name="district" class="form-select" required>
|
| 296 |
+
<option value="">Select District</option>
|
| 297 |
+
</select>
|
| 298 |
+
</div>
|
| 299 |
+
|
| 300 |
+
<div class="col-md-6">
|
| 301 |
+
<label for="crop_year" class="form-label"><i class="bi bi-calendar3 me-1"></i>Crop Year (2024
|
| 302 |
+
onwards)</label>
|
| 303 |
+
<input type="number" id="crop_year" name="crop_year" class="form-control" min="2024"
|
| 304 |
+
placeholder="e.g., 2024" required>
|
| 305 |
+
</div>
|
| 306 |
+
|
| 307 |
+
<div class="col-md-6">
|
| 308 |
+
<label for="season" class="form-label"><i class="bi bi-cloud-sun me-1"></i>Season</label>
|
| 309 |
+
<select id="season" name="season" class="form-select" required>
|
| 310 |
+
{% for season in seasons %}
|
| 311 |
+
<option value="{{ season }}">{{ season }}</option>
|
| 312 |
+
{% endfor %}
|
| 313 |
+
</select>
|
| 314 |
+
</div>
|
| 315 |
+
|
| 316 |
+
<div class="col-md-6">
|
| 317 |
+
<label for="crop" class="form-label"><i class="bi bi-flower2 me-1"></i>Crop</label>
|
| 318 |
+
<select id="crop" name="crop" class="form-select" required>
|
| 319 |
+
{% for crop in crops %}
|
| 320 |
+
<option value="{{ crop }}">{{ crop }}</option>
|
| 321 |
+
{% endfor %}
|
| 322 |
+
</select>
|
| 323 |
+
</div>
|
| 324 |
+
|
| 325 |
+
<div class="col-md-6">
|
| 326 |
+
<label for="area" class="form-label"><i class="bi bi-rulers me-1"></i>Area (in Acres)</label>
|
| 327 |
+
<input type="number" id="area" name="area" class="form-control" step="0.01"
|
| 328 |
+
placeholder="e.g., 10.5" required>
|
| 329 |
+
</div>
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
<button type="submit" class="btn-predict">
|
| 333 |
+
<i class="bi bi-stars"></i> Predict Crop Yield
|
| 334 |
+
</button>
|
| 335 |
+
</form>
|
| 336 |
+
</div>
|
| 337 |
+
</div>
|
| 338 |
+
|
| 339 |
+
<!-- Footer -->
|
| 340 |
+
<div class="footer">
|
| 341 |
+
© 2025 Crop Yield Prediction | Powered by AI
|
| 342 |
+
</div>
|
| 343 |
+
|
| 344 |
+
<!-- Loading Overlay -->
|
| 345 |
+
<div id="loadingOverlay">
|
| 346 |
+
<div class="spinner-border" role="status"></div>
|
| 347 |
+
<p class="text-muted mt-3">Analyzing crop data...</p>
|
| 348 |
+
</div>
|
| 349 |
+
|
| 350 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
| 351 |
+
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
|
| 352 |
+
<script>
|
| 353 |
+
$(document).ready(function () {
|
| 354 |
+
// Dynamic district loading
|
| 355 |
+
$('#state').change(function () {
|
| 356 |
+
const state = $(this).val();
|
| 357 |
+
$.ajax({
|
| 358 |
+
url: '/filter_districts',
|
| 359 |
+
method: 'POST',
|
| 360 |
+
data: { state: state },
|
| 361 |
+
success: function (response) {
|
| 362 |
+
$('#district').empty().append('<option value="">Select District</option>');
|
| 363 |
+
response.districts.forEach(function (district) {
|
| 364 |
+
$('#district').append('<option value="' + district + '">' + district + '</option>');
|
| 365 |
+
});
|
| 366 |
+
}
|
| 367 |
+
});
|
| 368 |
+
});
|
| 369 |
+
|
| 370 |
+
// Show loading overlay on form submit
|
| 371 |
+
$('#prediction-form').on('submit', function () {
|
| 372 |
+
document.getElementById('loadingOverlay').style.display = 'flex';
|
| 373 |
+
});
|
| 374 |
+
});
|
| 375 |
+
</script>
|
| 376 |
+
</body>
|
| 377 |
+
|
| 378 |
+
</html>
|
templates/output.html
ADDED
|
@@ -0,0 +1,412 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
<!DOCTYPE html>
|
| 2 |
+
<html lang="en">
|
| 3 |
+
|
| 4 |
+
<head>
|
| 5 |
+
<meta charset="UTF-8">
|
| 6 |
+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| 7 |
+
<title>Prediction Results | Crop Yield</title>
|
| 8 |
+
<!-- Fonts -->
|
| 9 |
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
| 10 |
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
| 11 |
+
<link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
|
| 12 |
+
<!-- Bootstrap -->
|
| 13 |
+
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/css/bootstrap.min.css" rel="stylesheet">
|
| 14 |
+
<!-- Icons -->
|
| 15 |
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.1/font/bootstrap-icons.css">
|
| 16 |
+
|
| 17 |
+
<style>
|
| 18 |
+
:root {
|
| 19 |
+
--primary-green: #1a5d3a;
|
| 20 |
+
--accent-green: #198754;
|
| 21 |
+
--darker-accent: #143d2e;
|
| 22 |
+
--light-bg: #f8f9fa;
|
| 23 |
+
--surface: #ffffff;
|
| 24 |
+
--text-dark: #212529;
|
| 25 |
+
--text-muted: #6c757d;
|
| 26 |
+
--border: #dee2e6;
|
| 27 |
+
}
|
| 28 |
+
|
| 29 |
+
* {
|
| 30 |
+
box-sizing: border-box;
|
| 31 |
+
margin: 0;
|
| 32 |
+
padding: 0;
|
| 33 |
+
}
|
| 34 |
+
|
| 35 |
+
body {
|
| 36 |
+
font-family: 'Outfit', sans-serif;
|
| 37 |
+
background-color: var(--light-bg);
|
| 38 |
+
color: var(--text-dark);
|
| 39 |
+
min-height: 100vh;
|
| 40 |
+
}
|
| 41 |
+
|
| 42 |
+
/* --- Hero Header Section --- */
|
| 43 |
+
.hero-header {
|
| 44 |
+
background-color: var(--primary-green);
|
| 45 |
+
color: white;
|
| 46 |
+
padding: 3rem 1rem 7rem;
|
| 47 |
+
text-align: center;
|
| 48 |
+
border-bottom-left-radius: 60px;
|
| 49 |
+
border-bottom-right-radius: 60px;
|
| 50 |
+
position: relative;
|
| 51 |
+
}
|
| 52 |
+
|
| 53 |
+
.hero-icon {
|
| 54 |
+
font-size: 2.5rem;
|
| 55 |
+
margin-bottom: 0.75rem;
|
| 56 |
+
display: block;
|
| 57 |
+
}
|
| 58 |
+
|
| 59 |
+
.hero-title {
|
| 60 |
+
font-weight: 700;
|
| 61 |
+
font-size: 2rem;
|
| 62 |
+
margin-bottom: 0.5rem;
|
| 63 |
+
}
|
| 64 |
+
|
| 65 |
+
.hero-subtitle {
|
| 66 |
+
font-weight: 300;
|
| 67 |
+
opacity: 0.9;
|
| 68 |
+
font-size: 1rem;
|
| 69 |
+
}
|
| 70 |
+
|
| 71 |
+
/* --- Main Content --- */
|
| 72 |
+
.main-container {
|
| 73 |
+
margin-top: -5rem;
|
| 74 |
+
padding: 0 1rem 3rem;
|
| 75 |
+
max-width: 1100px;
|
| 76 |
+
margin-left: auto;
|
| 77 |
+
margin-right: auto;
|
| 78 |
+
}
|
| 79 |
+
|
| 80 |
+
/* --- Prediction Summary Card --- */
|
| 81 |
+
.summary-card {
|
| 82 |
+
background: var(--surface);
|
| 83 |
+
border-radius: 20px;
|
| 84 |
+
box-shadow: 0 10px 40px rgba(0, 0, 0, 0.08);
|
| 85 |
+
padding: 2rem;
|
| 86 |
+
margin-bottom: 2rem;
|
| 87 |
+
position: relative;
|
| 88 |
+
z-index: 10;
|
| 89 |
+
}
|
| 90 |
+
|
| 91 |
+
.summary-header {
|
| 92 |
+
display: flex;
|
| 93 |
+
align-items: center;
|
| 94 |
+
gap: 0.75rem;
|
| 95 |
+
margin-bottom: 1.5rem;
|
| 96 |
+
padding-bottom: 1rem;
|
| 97 |
+
border-bottom: 2px solid var(--primary-green);
|
| 98 |
+
}
|
| 99 |
+
|
| 100 |
+
.summary-header i {
|
| 101 |
+
font-size: 1.75rem;
|
| 102 |
+
color: var(--primary-green);
|
| 103 |
+
}
|
| 104 |
+
|
| 105 |
+
.summary-header h2 {
|
| 106 |
+
font-size: 1.5rem;
|
| 107 |
+
font-weight: 700;
|
| 108 |
+
color: var(--text-dark);
|
| 109 |
+
margin: 0;
|
| 110 |
+
}
|
| 111 |
+
|
| 112 |
+
.stat-grid {
|
| 113 |
+
display: grid;
|
| 114 |
+
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
|
| 115 |
+
gap: 1.5rem;
|
| 116 |
+
}
|
| 117 |
+
|
| 118 |
+
.stat-box {
|
| 119 |
+
background: linear-gradient(135deg, #f0fdf4 0%, #fff 100%);
|
| 120 |
+
border: 1px solid #e9ecef;
|
| 121 |
+
border-radius: 12px;
|
| 122 |
+
padding: 1.5rem;
|
| 123 |
+
text-align: center;
|
| 124 |
+
transition: transform 0.2s;
|
| 125 |
+
}
|
| 126 |
+
|
| 127 |
+
.stat-box:hover {
|
| 128 |
+
transform: translateY(-2px);
|
| 129 |
+
border-color: var(--accent-green);
|
| 130 |
+
}
|
| 131 |
+
|
| 132 |
+
.stat-icon {
|
| 133 |
+
width: 50px;
|
| 134 |
+
height: 50px;
|
| 135 |
+
border-radius: 12px;
|
| 136 |
+
background: var(--primary-green);
|
| 137 |
+
color: white;
|
| 138 |
+
display: flex;
|
| 139 |
+
align-items: center;
|
| 140 |
+
justify-content: center;
|
| 141 |
+
font-size: 1.25rem;
|
| 142 |
+
margin: 0 auto 1rem;
|
| 143 |
+
}
|
| 144 |
+
|
| 145 |
+
.stat-value {
|
| 146 |
+
font-size: 2rem;
|
| 147 |
+
font-weight: 700;
|
| 148 |
+
color: var(--primary-green);
|
| 149 |
+
line-height: 1;
|
| 150 |
+
margin-bottom: 0.5rem;
|
| 151 |
+
}
|
| 152 |
+
|
| 153 |
+
.stat-label {
|
| 154 |
+
font-size: 0.85rem;
|
| 155 |
+
color: var(--text-muted);
|
| 156 |
+
font-weight: 500;
|
| 157 |
+
text-transform: uppercase;
|
| 158 |
+
letter-spacing: 0.05em;
|
| 159 |
+
}
|
| 160 |
+
|
| 161 |
+
/* --- Graph Cards --- */
|
| 162 |
+
.graph-card {
|
| 163 |
+
background: var(--surface);
|
| 164 |
+
border-radius: 20px;
|
| 165 |
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
| 166 |
+
padding: 1.5rem;
|
| 167 |
+
margin-bottom: 1.5rem;
|
| 168 |
+
}
|
| 169 |
+
|
| 170 |
+
.graph-header {
|
| 171 |
+
display: flex;
|
| 172 |
+
align-items: center;
|
| 173 |
+
gap: 0.5rem;
|
| 174 |
+
margin-bottom: 1rem;
|
| 175 |
+
}
|
| 176 |
+
|
| 177 |
+
.graph-header i {
|
| 178 |
+
color: var(--accent-green);
|
| 179 |
+
font-size: 1.25rem;
|
| 180 |
+
}
|
| 181 |
+
|
| 182 |
+
.graph-header h4 {
|
| 183 |
+
font-size: 1.1rem;
|
| 184 |
+
font-weight: 600;
|
| 185 |
+
color: var(--text-dark);
|
| 186 |
+
margin: 0;
|
| 187 |
+
}
|
| 188 |
+
|
| 189 |
+
/* --- Suggestions Card --- */
|
| 190 |
+
.suggestions-card {
|
| 191 |
+
background: var(--surface);
|
| 192 |
+
border-radius: 20px;
|
| 193 |
+
box-shadow: 0 4px 20px rgba(0, 0, 0, 0.05);
|
| 194 |
+
padding: 2rem;
|
| 195 |
+
margin-bottom: 1.5rem;
|
| 196 |
+
border-left: 5px solid var(--accent-green);
|
| 197 |
+
}
|
| 198 |
+
|
| 199 |
+
.suggestions-header {
|
| 200 |
+
display: flex;
|
| 201 |
+
align-items: center;
|
| 202 |
+
gap: 0.5rem;
|
| 203 |
+
margin-bottom: 1rem;
|
| 204 |
+
}
|
| 205 |
+
|
| 206 |
+
.suggestions-header i {
|
| 207 |
+
color: var(--accent-green);
|
| 208 |
+
font-size: 1.5rem;
|
| 209 |
+
}
|
| 210 |
+
|
| 211 |
+
.suggestions-header h4 {
|
| 212 |
+
font-size: 1.25rem;
|
| 213 |
+
font-weight: 600;
|
| 214 |
+
color: var(--primary-green);
|
| 215 |
+
margin: 0;
|
| 216 |
+
}
|
| 217 |
+
|
| 218 |
+
.suggestions-content {
|
| 219 |
+
font-size: 1rem;
|
| 220 |
+
line-height: 1.7;
|
| 221 |
+
color: var(--text-dark);
|
| 222 |
+
}
|
| 223 |
+
|
| 224 |
+
/* --- Back Button --- */
|
| 225 |
+
.btn-back {
|
| 226 |
+
background-color: var(--primary-green);
|
| 227 |
+
color: white;
|
| 228 |
+
border: none;
|
| 229 |
+
padding: 0.85rem 2rem;
|
| 230 |
+
border-radius: 8px;
|
| 231 |
+
font-weight: 600;
|
| 232 |
+
font-size: 1rem;
|
| 233 |
+
display: inline-flex;
|
| 234 |
+
align-items: center;
|
| 235 |
+
gap: 0.5rem;
|
| 236 |
+
text-decoration: none;
|
| 237 |
+
transition: all 0.3s;
|
| 238 |
+
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.1);
|
| 239 |
+
}
|
| 240 |
+
|
| 241 |
+
.btn-back:hover {
|
| 242 |
+
background-color: var(--darker-accent);
|
| 243 |
+
color: white;
|
| 244 |
+
transform: translateY(-2px);
|
| 245 |
+
box-shadow: 0 6px 15px rgba(0, 0, 0, 0.15);
|
| 246 |
+
}
|
| 247 |
+
|
| 248 |
+
/* --- Footer --- */
|
| 249 |
+
.footer {
|
| 250 |
+
text-align: center;
|
| 251 |
+
padding: 2rem;
|
| 252 |
+
color: #adb5bd;
|
| 253 |
+
font-size: 0.8rem;
|
| 254 |
+
}
|
| 255 |
+
|
| 256 |
+
/* --- Responsive --- */
|
| 257 |
+
@media (max-width: 768px) {
|
| 258 |
+
.hero-title {
|
| 259 |
+
font-size: 1.5rem;
|
| 260 |
+
}
|
| 261 |
+
|
| 262 |
+
.summary-card,
|
| 263 |
+
.graph-card,
|
| 264 |
+
.suggestions-card {
|
| 265 |
+
padding: 1.5rem;
|
| 266 |
+
}
|
| 267 |
+
|
| 268 |
+
.stat-value {
|
| 269 |
+
font-size: 1.5rem;
|
| 270 |
+
}
|
| 271 |
+
|
| 272 |
+
.hero-header {
|
| 273 |
+
border-bottom-left-radius: 40px;
|
| 274 |
+
border-bottom-right-radius: 40px;
|
| 275 |
+
}
|
| 276 |
+
}
|
| 277 |
+
</style>
|
| 278 |
+
</head>
|
| 279 |
+
|
| 280 |
+
<body>
|
| 281 |
+
|
| 282 |
+
<!-- Hero Header -->
|
| 283 |
+
<div class="hero-header">
|
| 284 |
+
<i class="bi bi-bar-chart-line hero-icon"></i>
|
| 285 |
+
<h1 class="hero-title">Prediction Results</h1>
|
| 286 |
+
<p class="hero-subtitle">AI-generated yield forecast and insights</p>
|
| 287 |
+
</div>
|
| 288 |
+
|
| 289 |
+
<!-- Main Content -->
|
| 290 |
+
<div class="main-container">
|
| 291 |
+
|
| 292 |
+
<!-- Prediction Summary -->
|
| 293 |
+
<div class="summary-card">
|
| 294 |
+
<div class="summary-header">
|
| 295 |
+
<i class="bi bi-clipboard-data"></i>
|
| 296 |
+
<h2>Yield Prediction Summary</h2>
|
| 297 |
+
</div>
|
| 298 |
+
<div class="stat-grid">
|
| 299 |
+
<div class="stat-box">
|
| 300 |
+
<div class="stat-icon"><i class="bi bi-box-seam"></i></div>
|
| 301 |
+
<div class="stat-value">{{ prediction }}</div>
|
| 302 |
+
<div class="stat-label">Predicted Production (tons)</div>
|
| 303 |
+
</div>
|
| 304 |
+
<div class="stat-box">
|
| 305 |
+
<div class="stat-icon"><i class="bi bi-percent"></i></div>
|
| 306 |
+
<div class="stat-value">{{ ratio }}</div>
|
| 307 |
+
<div class="stat-label">Production-to-Area Ratio</div>
|
| 308 |
+
</div>
|
| 309 |
+
</div>
|
| 310 |
+
</div>
|
| 311 |
+
|
| 312 |
+
<!-- Gauge Chart -->
|
| 313 |
+
<div class="graph-card">
|
| 314 |
+
<div class="graph-header">
|
| 315 |
+
<i class="bi bi-speedometer2"></i>
|
| 316 |
+
<h4>Production Ratio Gauge Chart</h4>
|
| 317 |
+
</div>
|
| 318 |
+
{{ gauge_chart_html|safe }}
|
| 319 |
+
</div>
|
| 320 |
+
|
| 321 |
+
<!-- AI Suggestions -->
|
| 322 |
+
<div class="suggestions-card">
|
| 323 |
+
<div class="suggestions-header">
|
| 324 |
+
<i class="bi bi-lightbulb"></i>
|
| 325 |
+
<h4>AI-Driven Suggestions</h4>
|
| 326 |
+
</div>
|
| 327 |
+
<div class="suggestions-content">
|
| 328 |
+
{{ suggestions }}
|
| 329 |
+
</div>
|
| 330 |
+
</div>
|
| 331 |
+
|
| 332 |
+
<!-- Charts Grid -->
|
| 333 |
+
<div class="row">
|
| 334 |
+
<div class="col-lg-6">
|
| 335 |
+
<div class="graph-card">
|
| 336 |
+
<div class="graph-header">
|
| 337 |
+
<i class="bi bi-pie-chart"></i>
|
| 338 |
+
<h4>Crop Distribution</h4>
|
| 339 |
+
</div>
|
| 340 |
+
{{ pie_chart_html|safe }}
|
| 341 |
+
</div>
|
| 342 |
+
</div>
|
| 343 |
+
<div class="col-lg-6">
|
| 344 |
+
<div class="graph-card">
|
| 345 |
+
<div class="graph-header">
|
| 346 |
+
<i class="bi bi-graph-up"></i>
|
| 347 |
+
<h4>Year vs Production (2000-2023)</h4>
|
| 348 |
+
</div>
|
| 349 |
+
{{ crop_year_vs_production_html|safe }}
|
| 350 |
+
</div>
|
| 351 |
+
</div>
|
| 352 |
+
</div>
|
| 353 |
+
|
| 354 |
+
<div class="row">
|
| 355 |
+
<div class="col-lg-6">
|
| 356 |
+
<div class="graph-card">
|
| 357 |
+
<div class="graph-header">
|
| 358 |
+
<i class="bi bi-cloud-sun"></i>
|
| 359 |
+
<h4>Season vs Production</h4>
|
| 360 |
+
</div>
|
| 361 |
+
{{ season_vs_production_html|safe }}
|
| 362 |
+
</div>
|
| 363 |
+
</div>
|
| 364 |
+
<div class="col-lg-6">
|
| 365 |
+
<div class="graph-card">
|
| 366 |
+
<div class="graph-header">
|
| 367 |
+
<i class="bi bi-rulers"></i>
|
| 368 |
+
<h4>Area vs Production</h4>
|
| 369 |
+
</div>
|
| 370 |
+
{{ area_vs_production_html|safe }}
|
| 371 |
+
</div>
|
| 372 |
+
</div>
|
| 373 |
+
</div>
|
| 374 |
+
|
| 375 |
+
<div class="row">
|
| 376 |
+
<div class="col-lg-6">
|
| 377 |
+
<div class="graph-card">
|
| 378 |
+
<div class="graph-header">
|
| 379 |
+
<i class="bi bi-trophy"></i>
|
| 380 |
+
<h4>Top 10 States by Production</h4>
|
| 381 |
+
</div>
|
| 382 |
+
{{ top_states_html|safe }}
|
| 383 |
+
</div>
|
| 384 |
+
</div>
|
| 385 |
+
<div class="col-lg-6">
|
| 386 |
+
<div class="graph-card">
|
| 387 |
+
<div class="graph-header">
|
| 388 |
+
<i class="bi bi-bar-chart-steps"></i>
|
| 389 |
+
<h4>Violin Plot: Production (2014-2023)</h4>
|
| 390 |
+
</div>
|
| 391 |
+
{{ yearly_violin_plot_html|safe }}
|
| 392 |
+
</div>
|
| 393 |
+
</div>
|
| 394 |
+
</div>
|
| 395 |
+
|
| 396 |
+
<!-- Back Button -->
|
| 397 |
+
<div class="text-center mt-4">
|
| 398 |
+
<a href="/" class="btn-back">
|
| 399 |
+
<i class="bi bi-arrow-left"></i> Make New Prediction
|
| 400 |
+
</a>
|
| 401 |
+
</div>
|
| 402 |
+
</div>
|
| 403 |
+
|
| 404 |
+
<!-- Footer -->
|
| 405 |
+
<div class="footer">
|
| 406 |
+
© 2025 Crop Yield Prediction | Powered by AI
|
| 407 |
+
</div>
|
| 408 |
+
|
| 409 |
+
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0/dist/js/bootstrap.bundle.min.js"></script>
|
| 410 |
+
</body>
|
| 411 |
+
|
| 412 |
+
</html>
|