krushimitravit commited on
Commit
fa0b0d8
·
verified ·
1 Parent(s): 1695583

Upload 7 files

Browse files
.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

  • SHA256: 78cf50cb3c39b1c19b4bbeb3a792f66534d7956e6ccd4aa2c8221604b5008c09
  • Pointer size: 131 Bytes
  • Size of remote file: 283 kB
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
+ &copy; 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
+ &copy; 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>