krushimitravit commited on
Commit
cbaa30f
·
verified ·
1 Parent(s): 36619e7

Upload 5 files

Browse files
Files changed (5) hide show
  1. .env +3 -0
  2. Dockerfile +17 -0
  3. app.py +193 -0
  4. requirements.txt +4 -0
  5. templates/index.html +758 -0
.env ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ GEMINI_API_KEY=AIzaSyCyLzLovfjmSPJxPfzcpZ1yVeVRH4iCfQ0
2
+ GOOGLE_API_KEY=AIzaSyCyLzLovfjmSPJxPfzcpZ1yVeVRH4iCfQ0
3
+ NVIDIA_API_KEY=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
Dockerfile ADDED
@@ -0,0 +1,17 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Base image
2
+ FROM python:3.9-slim
3
+
4
+ # Set the working directory
5
+ WORKDIR /app
6
+
7
+ # Copy application files
8
+ COPY . /app
9
+
10
+ # Install dependencies
11
+ RUN pip install --no-cache-dir -r requirements.txt
12
+
13
+ # Expose the port your app runs on
14
+ EXPOSE 7860
15
+
16
+ # Command to run the application
17
+ CMD ["gunicorn", "-w", "4", "-b", "0.0.0.0:7860", "app:app"]
app.py ADDED
@@ -0,0 +1,193 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from flask import Flask, render_template, request
2
+ from markupsafe import Markup
3
+ import google.generativeai as genai
4
+ from openai import OpenAI
5
+ import os
6
+ import dotenv
7
+
8
+ dotenv.load_dotenv()
9
+
10
+ app = Flask(__name__)
11
+
12
+ # API Keys
13
+ GEMINI_API_KEY = os.getenv('GEMINI_API_KEY')
14
+ NVIDIA_API_KEY = os.getenv('NVIDIA_API_KEY')
15
+
16
+ # Initialize Gemini
17
+ if GEMINI_API_KEY:
18
+ genai.configure(api_key=GEMINI_API_KEY)
19
+
20
+ # Initialize NVIDIA
21
+ nvidia_client = None
22
+ if NVIDIA_API_KEY:
23
+ nvidia_client = OpenAI(
24
+ base_url="https://integrate.api.nvidia.com/v1",
25
+ api_key=NVIDIA_API_KEY
26
+ )
27
+
28
+ def call_llm(prompt):
29
+ """Call LLM with Gemini -> NVIDIA fallback."""
30
+ # 1. Gemini Fallback
31
+ if GEMINI_API_KEY:
32
+ for model_name in ["gemini-2.5-flash", "gemini-2.5-flash-lite"]:
33
+ try:
34
+ print(f" >> Trying Gemini {model_name}...")
35
+ model = genai.GenerativeModel(model_name)
36
+ response = model.generate_content(prompt)
37
+ if response and response.text:
38
+ print(f" >> SUCCESS with {model_name}")
39
+ return response.text
40
+ except Exception as e:
41
+ print(f" >> {model_name} failed: {e}")
42
+ continue
43
+
44
+ # 2. NVIDIA Fallback
45
+ if nvidia_client:
46
+ nvidia_models = ["meta/llama-3.1-405b-instruct", "meta/llama-3.1-70b-instruct", "google/gemma-3-27b-it"]
47
+ for model_name in nvidia_models:
48
+ try:
49
+ print(f" >> Trying NVIDIA {model_name}...")
50
+ response = nvidia_client.chat.completions.create(
51
+ model=model_name,
52
+ messages=[{"role": "user", "content": prompt}],
53
+ max_tokens=4096,
54
+ temperature=0.3
55
+ )
56
+ print(f" >> SUCCESS with {model_name}")
57
+ return response.choices[0].message.content
58
+ except Exception as e:
59
+ print(f" >> {model_name} failed: {e}")
60
+ continue
61
+
62
+ return "<p>Error: All AI models failed. Please check API keys.</p>"
63
+
64
+
65
+ @app.route('/', methods=['GET', 'POST'])
66
+ def index():
67
+ if request.method == 'POST':
68
+ # Retrieve farm details
69
+ location = request.form.get('location')
70
+ total_area = request.form.get('total_area')
71
+ language = request.form.get('language', 'English')
72
+
73
+ # Retrieve crop details structure
74
+ crop_seasons = request.form.getlist('crop_season')
75
+ crop_names = request.form.getlist('crop_name')
76
+ crop_areas = request.form.getlist('crop_area')
77
+
78
+ crops = []
79
+ for s, n, a in zip(crop_seasons, crop_names, crop_areas):
80
+ if n.strip() and a.strip():
81
+ crops.append(f"{s}: {n.strip()} ({a.strip()} acres)")
82
+
83
+ current_plan = " | ".join(crops)
84
+
85
+ prompt = f"""
86
+ You are an advanced agricultural economist. I will provide the farmer's **Current Annual Crop Cycle**.
87
+ Your task is to generate a **3-Year Optimization Plan** and explicitly explain **WHY their current plan is losing money/underperforming** compared to the potential.
88
+
89
+ **Inputs:**
90
+ - Location: {location}
91
+ - Total Area: {total_area} acres
92
+ - Current Annual Plan: {current_plan}
93
+
94
+ **OUTPUT FORMAT INSTRUCTIONS:**
95
+ Generate ONLY the HTML content inside `<div>` tags. Use the specific CSS classes below.
96
+
97
+ **Structure & CSS Classes to Use:**
98
+
99
+ 1. **Executive Summary (2 Cards):**
100
+ Use `<div class="stats-grid" style="grid-template-columns: 1fr 1fr; max-width: 700px; margin: 0 auto 1.5rem;">` containing:
101
+ - Card 1: **Projected Annual Net Profit** (Value in `stat-value`)
102
+ - Card 2: **Revenue Increase** (Value in `stat-value` with `color: #1a5d3a`)
103
+
104
+ 2. **GAP ANALYSIS (Why the Loss?):**
105
+ Header: `<h3><i class="bi bi-search"></i> Input Strategy Analysis</h3>`
106
+ Use `<div class="gap-analysis-card">` (I will add this CSS):
107
+ - `<h4><i class="bi bi-exclamation-circle"></i> Inefficiencies Detected in Current Plan:</h4>`
108
+ - `<ul>`
109
+ - `<li><b>[Factor 1]:</b> [Explanation, e.g., 'Monoculture of Wheat increases pest risk and fertilizer cost by 20%']</li>`
110
+ - `<li><b>[Factor 2]:</b> [Explanation, e.g., 'Missing Zaid season leaves 4 months of revenue potential on the table']</li>`
111
+ - `<li><b>[Factor 3]:</b> [Explanation]</li>`
112
+ - `</ul>`
113
+
114
+ 3. **Annual Financial Breakdown (Single Bar):**
115
+ Header: `<h3><i class="bi bi-pie-chart"></i> Projected Financials</h3>`
116
+ Use `<div class="breakdown-section">`:
117
+ - Title: `<div class="breakdown-title"><span>Breakdown (Avg Annual)</span> <span>Total Rev: [Value]</span></div>`
118
+ - Stacked Bar: `<div class="stacked-bar-container">`
119
+ - `<div class="bar-cost" style="width: [Cost%]%">Cost [Value]</div>`
120
+ - `<div class="bar-profit" style="width: [Profit%]%">Profit [Value]</div>`
121
+ - Legend included below.
122
+
123
+ 4. **3-Year Crop Rotation (Vertical Stalk):**
124
+ Header: `<h3><i class="bi bi-bezier2"></i> Crop Rotation Journey</h3>`
125
+ Use `<div class="growth-timeline">`:
126
+ - **For EACH Year (1, 2, 3):**
127
+ `<div class="growth-node">`
128
+ `<div class="growth-card">`
129
+ `<div class="growth-header">`
130
+ `<span>Year 1</span>`
131
+ `<span>Est. Income: [Value]</span>`
132
+ `</div>`
133
+ `<table class="annual-table">`
134
+ `<thead><tr><th>Season</th><th>Crop</th><th>Exp/Rev/Profit</th></tr></thead>`
135
+ `<tbody>`
136
+ `<tr>`
137
+ `<td><span class="season-badge">Kharif</span></td>`
138
+ `<td><b>[Crop Name]</b></td>`
139
+ `<td>Exp: [Val]<br>Prof: <b>[Val]</b></td>`
140
+ `</tr>`
141
+ `<tr>`
142
+ `<td><span class="season-badge">Rabi</span></td>`
143
+ `<td><b>[Crop Name]</b></td>`
144
+ `<td>Exp: [Val]<br>Prof: <b>[Val]</b></td>`
145
+ `</tr>`
146
+ `<tr>`
147
+ `<td><span class="season-badge">Zaid</span></td>`
148
+ `<td><b>[Crop Name]</b></td>`
149
+ `<td>Exp: [Val]<br>Prof: <b>[Val]</b></td>`
150
+ `</tr>`
151
+ `</tbody>`
152
+ `</table>`
153
+ `</div>`
154
+ `</div>`
155
+
156
+ 5. **Comparison Table:**
157
+ Header: `<h3><i class="bi bi-table"></i> Strategy Comparison</h3>`
158
+ Use `<div class="smart-table-container">` with `<table class="smart-table">`.
159
+ - Columns: Metric, Current Annual Plan, Proposed (Avg Annual), Change.
160
+ - Rows: Gross Revenue, Total Cost, Net Profit.
161
+ - **COLOR LOGIC:**
162
+ - **Total Cost:** Identify if Cost Increases or Decreases. Mark "Cost Increase" as `<span class="negative">` (Red). Mark "Cost Decrease" as `<span class="positive">` (Green).
163
+ - **Net Profit:** Increase = Positive (Green).
164
+
165
+ **Guidelines:**
166
+ - **Language:** {language}
167
+ - **REALISM:** Ensure the gap isn't exaggerated. If the current plan is decent, say so. If it's bad, explain EXACTLY why (e.g., pests, soil depletion, unused seasons).
168
+ """
169
+
170
+ try:
171
+ print(f"\n[CROP REVENUE] Generating report for {location}...")
172
+ result_html = call_llm(prompt)
173
+ result_html = result_html.strip()
174
+
175
+ # Remove markdown code blocks
176
+ if result_html.startswith("```html"):
177
+ result_html = result_html[7:]
178
+ if result_html.startswith("```"):
179
+ result_html = result_html[3:]
180
+ if result_html.endswith("```"):
181
+ result_html = result_html[:-3]
182
+
183
+ return render_template('index.html', result=Markup(result_html.strip()))
184
+
185
+ except Exception as e:
186
+ error_message = f"Error generating crop strategy: {str(e)}"
187
+ return render_template('index.html', error=error_message)
188
+
189
+ return render_template('index.html')
190
+
191
+
192
+ if __name__ == '__main__':
193
+ app.run(debug=True, port=5003)
requirements.txt ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ gunicorn
2
+ flask
3
+ google-genai
4
+ markupsafe
templates/index.html ADDED
@@ -0,0 +1,758 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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">
7
+ <title>Crop Revenue Analyzer | Smart Farm Planning</title>
8
+
9
+ <!-- Google Fonts: Outfit -->
10
+ <link rel="preconnect" href="https://fonts.googleapis.com">
11
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
12
+ <link href="https://fonts.googleapis.com/css2?family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
13
+
14
+ <!-- Bootstrap Icons -->
15
+ <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.0/font/bootstrap-icons.css">
16
+
17
+ <style>
18
+ :root {
19
+ --primary: #1a5d3a;
20
+ --primary-dark: #143d2e;
21
+ --accent: #198754;
22
+ --danger: #dc3545;
23
+ --success: #198754;
24
+ --bg-page: #f8f9fa;
25
+ --bg-surface: #ffffff;
26
+ --text-dark: #212529;
27
+ --text-muted: #6c757d;
28
+ --border: #dee2e6;
29
+ --radius-lg: 20px;
30
+ --radius-md: 12px;
31
+ --radius-sm: 8px;
32
+ --shadow-card: 0 10px 40px rgba(0, 0, 0, 0.08);
33
+ --shadow-sm: 0 2px 8px rgba(0, 0, 0, 0.06);
34
+ --font-main: 'Outfit', sans-serif;
35
+ }
36
+
37
+ * {
38
+ box-sizing: border-box;
39
+ margin: 0;
40
+ padding: 0;
41
+ }
42
+
43
+ body {
44
+ font-family: var(--font-main);
45
+ background-color: var(--bg-page);
46
+ color: var(--text-dark);
47
+ line-height: 1.6;
48
+ min-height: 100vh;
49
+ }
50
+
51
+ /* Hero Section */
52
+ .hero {
53
+ background: var(--primary);
54
+ color: white;
55
+ padding: 4rem 1rem 6rem;
56
+ text-align: center;
57
+ border-bottom-left-radius: 60px;
58
+ border-bottom-right-radius: 60px;
59
+ position: relative;
60
+ }
61
+
62
+ .hero h1 {
63
+ font-size: 2.5rem;
64
+ font-weight: 700;
65
+ margin-bottom: 0.5rem;
66
+ }
67
+
68
+ .hero p {
69
+ font-size: 1.1rem;
70
+ opacity: 0.9;
71
+ font-weight: 300;
72
+ max-width: 600px;
73
+ margin: 0 auto;
74
+ }
75
+
76
+ /* Container */
77
+ .container {
78
+ max-width: 1000px;
79
+ margin: 0 auto;
80
+ padding: 0 1rem;
81
+ }
82
+
83
+ /* Floating Card */
84
+ .card {
85
+ background: var(--bg-surface);
86
+ border-radius: var(--radius-lg);
87
+ box-shadow: var(--shadow-card);
88
+ padding: 2.5rem;
89
+ margin-top: -3rem;
90
+ position: relative;
91
+ z-index: 10;
92
+ }
93
+
94
+ /* Form Grid */
95
+ .form-grid {
96
+ display: grid;
97
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
98
+ gap: 1.5rem;
99
+ margin-bottom: 2rem;
100
+ }
101
+
102
+ .form-group {
103
+ display: flex;
104
+ flex-direction: column;
105
+ }
106
+
107
+ .form-label {
108
+ font-weight: 600;
109
+ font-size: 0.85rem;
110
+ color: var(--text-dark);
111
+ margin-bottom: 0.5rem;
112
+ text-transform: uppercase;
113
+ letter-spacing: 0.03em;
114
+ }
115
+
116
+ .form-label i {
117
+ color: var(--accent);
118
+ margin-right: 0.4rem;
119
+ }
120
+
121
+ .form-control {
122
+ background: var(--bg-page);
123
+ border: 1px solid var(--border);
124
+ border-radius: var(--radius-sm);
125
+ padding: 0.85rem 1rem;
126
+ font-size: 1rem;
127
+ font-family: var(--font-main);
128
+ color: var(--text-dark);
129
+ transition: all 0.2s ease;
130
+ }
131
+
132
+ .form-control:focus {
133
+ outline: none;
134
+ border-color: var(--accent);
135
+ background: var(--bg-surface);
136
+ box-shadow: 0 0 0 4px rgba(25, 135, 84, 0.1);
137
+ }
138
+
139
+ /* Crop Table */
140
+ .crop-table {
141
+ width: 100%;
142
+ border-collapse: collapse;
143
+ margin-bottom: 1.5rem;
144
+ background: var(--bg-surface);
145
+ border-radius: var(--radius-md);
146
+ overflow: hidden;
147
+ box-shadow: var(--shadow-sm);
148
+ }
149
+
150
+ .crop-table th {
151
+ background: var(--primary);
152
+ color: white;
153
+ padding: 1rem;
154
+ text-align: left;
155
+ font-weight: 500;
156
+ font-size: 0.85rem;
157
+ text-transform: uppercase;
158
+ }
159
+
160
+ .crop-table td {
161
+ padding: 0.75rem 1rem;
162
+ border-bottom: 1px solid var(--border);
163
+ }
164
+
165
+ .crop-table select,
166
+ .crop-table input {
167
+ width: 100%;
168
+ padding: 0.6rem 0.8rem;
169
+ border: 1px solid var(--border);
170
+ border-radius: var(--radius-sm);
171
+ font-family: var(--font-main);
172
+ }
173
+
174
+ .crop-table input:focus {
175
+ outline: none;
176
+ border-color: var(--accent);
177
+ box-shadow: 0 0 0 3px rgba(25, 135, 84, 0.1);
178
+ }
179
+
180
+ /* Buttons */
181
+ .btn {
182
+ display: inline-flex;
183
+ align-items: center;
184
+ justify-content: center;
185
+ gap: 0.5rem;
186
+ padding: 0.85rem 1.5rem;
187
+ border-radius: var(--radius-sm);
188
+ font-family: var(--font-main);
189
+ font-size: 1rem;
190
+ font-weight: 500;
191
+ cursor: pointer;
192
+ border: none;
193
+ }
194
+
195
+ .btn-primary {
196
+ background: var(--primary);
197
+ color: white;
198
+ }
199
+
200
+ .btn-secondary {
201
+ background: var(--bg-surface);
202
+ color: var(--accent);
203
+ border: 1px solid var(--accent);
204
+ }
205
+
206
+ .btn-icon {
207
+ background: transparent;
208
+ color: #dc3545;
209
+ padding: 0.5rem;
210
+ border-radius: 50%;
211
+ }
212
+
213
+ /* Results */
214
+ .results-card {
215
+ background: var(--bg-surface);
216
+ border-radius: var(--radius-lg);
217
+ box-shadow: var(--shadow-card);
218
+ padding: 2rem;
219
+ margin-top: 2rem;
220
+ animation: fadeIn 0.5s ease;
221
+ }
222
+
223
+ .results-header {
224
+ display: flex;
225
+ align-items: center;
226
+ gap: 0.75rem;
227
+ margin-bottom: 2rem;
228
+ padding-bottom: 1rem;
229
+ border-bottom: 2px solid var(--primary);
230
+ }
231
+
232
+ .results-header h2 {
233
+ margin: 0;
234
+ font-size: 1.5rem;
235
+ font-weight: 700;
236
+ color: var(--text-dark);
237
+ }
238
+
239
+ @keyframes fadeIn {
240
+ from {
241
+ opacity: 0;
242
+ transform: translateY(10px);
243
+ }
244
+
245
+ to {
246
+ opacity: 1;
247
+ transform: translateY(0);
248
+ }
249
+ }
250
+
251
+ /* --- DASHBOARD --- */
252
+
253
+ .stats-grid {
254
+ display: grid;
255
+ grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
256
+ gap: 1.5rem;
257
+ margin-bottom: 3rem;
258
+ }
259
+
260
+ .stat-card {
261
+ background: linear-gradient(145deg, #ffffff, #f0fdf4);
262
+ border: 1px solid var(--border);
263
+ border-bottom: 4px solid var(--accent);
264
+ border-radius: var(--radius-md);
265
+ padding: 1.5rem;
266
+ text-align: center;
267
+ box-shadow: var(--shadow-sm);
268
+ transition: transform 0.2s;
269
+ }
270
+
271
+ .stat-card:hover {
272
+ transform: translateY(-3px);
273
+ }
274
+
275
+ .stat-value {
276
+ font-size: 2rem;
277
+ font-weight: 700;
278
+ color: var(--primary);
279
+ line-height: 1.2;
280
+ }
281
+
282
+ .stat-label {
283
+ font-size: 0.9rem;
284
+ color: var(--text-muted);
285
+ text-transform: uppercase;
286
+ margin-top: 0.5rem;
287
+ letter-spacing: 0.05em;
288
+ }
289
+
290
+ /* --- NEW GAP ANALYSIS CARD --- */
291
+ .gap-analysis-card {
292
+ background: #fdf2f2;
293
+ /* Light Red */
294
+ border-left: 5px solid #dc3545;
295
+ border-radius: var(--radius-sm);
296
+ padding: 1.5rem;
297
+ margin-bottom: 3rem;
298
+ }
299
+
300
+ .gap-analysis-card h4 {
301
+ color: #b02a37;
302
+ margin: 0 0 1rem 0;
303
+ font-size: 1.1rem;
304
+ display: flex;
305
+ align-items: center;
306
+ gap: 0.5rem;
307
+ }
308
+
309
+ .gap-analysis-card ul {
310
+ margin: 0;
311
+ padding-left: 1.5rem;
312
+ }
313
+
314
+ .gap-analysis-card li {
315
+ margin-bottom: 0.5rem;
316
+ color: var(--text-dark);
317
+ font-size: 0.95rem;
318
+ }
319
+
320
+ .gap-analysis-card b {
321
+ color: #b02a37;
322
+ }
323
+
324
+ /* Single Breakdown Bar */
325
+ .breakdown-section {
326
+ background: #f8f9fa;
327
+ padding: 1.5rem 2rem;
328
+ border-radius: var(--radius-md);
329
+ margin-bottom: 3rem;
330
+ border: 1px solid var(--border);
331
+ }
332
+
333
+ .breakdown-title {
334
+ font-weight: 700;
335
+ margin-bottom: 1rem;
336
+ display: flex;
337
+ justify-content: space-between;
338
+ font-size: 1.05rem;
339
+ color: var(--text-dark);
340
+ }
341
+
342
+ .stacked-bar-container {
343
+ height: 28px;
344
+ width: 100%;
345
+ background: #e9ecef;
346
+ border-radius: 8px;
347
+ overflow: hidden;
348
+ display: flex;
349
+ }
350
+
351
+ .bar-cost {
352
+ background-color: #ef4444;
353
+ height: 100%;
354
+ display: flex;
355
+ align-items: center;
356
+ justify-content: center;
357
+ color: white;
358
+ font-size: 0.8rem;
359
+ font-weight: 600;
360
+ }
361
+
362
+ .bar-profit {
363
+ background-color: var(--success);
364
+ height: 100%;
365
+ display: flex;
366
+ align-items: center;
367
+ justify-content: center;
368
+ color: white;
369
+ font-size: 0.8rem;
370
+ font-weight: 600;
371
+ }
372
+
373
+ .breakdown-legend {
374
+ display: flex;
375
+ justify-content: flex-end;
376
+ gap: 1.5rem;
377
+ margin-top: 0.75rem;
378
+ font-size: 0.85rem;
379
+ color: var(--text-muted);
380
+ }
381
+
382
+ .legend-item {
383
+ display: flex;
384
+ align-items: center;
385
+ gap: 0.4rem;
386
+ }
387
+
388
+ .dot {
389
+ width: 10px;
390
+ height: 10px;
391
+ border-radius: 50%;
392
+ }
393
+
394
+ /* Vertical Growth Timeline */
395
+ .growth-timeline {
396
+ position: relative;
397
+ padding: 1rem 0;
398
+ max-width: 900px;
399
+ margin: 0 auto 3rem;
400
+ }
401
+
402
+ .growth-timeline::before {
403
+ content: '';
404
+ position: absolute;
405
+ top: 0;
406
+ bottom: 0;
407
+ left: 50%;
408
+ width: 4px;
409
+ background: #d1e7dd;
410
+ transform: translateX(-50%);
411
+ border-radius: 2px;
412
+ }
413
+
414
+ .growth-node {
415
+ position: relative;
416
+ margin-bottom: 3rem;
417
+ width: 100%;
418
+ display: flex;
419
+ justify-content: center;
420
+ }
421
+
422
+ .growth-card {
423
+ background: white;
424
+ border: 1px solid var(--border);
425
+ border-radius: var(--radius-md);
426
+ width: 46%;
427
+ padding: 0;
428
+ box-shadow: var(--shadow-sm);
429
+ position: relative;
430
+ border-top: 4px solid var(--accent);
431
+ overflow: hidden;
432
+ }
433
+
434
+ .growth-node:nth-child(odd) .growth-card {
435
+ margin-right: auto;
436
+ border-top-right-radius: 0;
437
+ }
438
+
439
+ .growth-node:nth-child(even) .growth-card {
440
+ margin-left: auto;
441
+ border-top-left-radius: 0;
442
+ }
443
+
444
+ .growth-node::after {
445
+ content: '';
446
+ position: absolute;
447
+ top: 0;
448
+ left: 50%;
449
+ width: 16px;
450
+ height: 16px;
451
+ background: var(--accent);
452
+ border: 3px solid white;
453
+ border-radius: 50%;
454
+ transform: translate(-50%, -50%);
455
+ box-shadow: 0 0 0 3px #d1e7dd;
456
+ z-index: 2;
457
+ }
458
+
459
+ .growth-header {
460
+ background: #f8f9fa;
461
+ padding: 1rem 1.5rem;
462
+ border-bottom: 1px solid var(--border);
463
+ font-weight: 700;
464
+ color: var(--primary);
465
+ display: flex;
466
+ justify-content: space-between;
467
+ align-items: center;
468
+ }
469
+
470
+ .annual-table {
471
+ width: 100%;
472
+ border-collapse: collapse;
473
+ font-size: 0.9rem;
474
+ }
475
+
476
+ .annual-table th {
477
+ background: white;
478
+ color: var(--text-muted);
479
+ font-size: 0.75rem;
480
+ text-transform: uppercase;
481
+ padding: 0.75rem 1rem;
482
+ border-bottom: 1px solid var(--border);
483
+ text-align: left;
484
+ }
485
+
486
+ .annual-table td {
487
+ padding: 0.75rem 1rem;
488
+ border-bottom: 1px solid #f0f0f0;
489
+ color: var(--text-dark);
490
+ vertical-align: middle;
491
+ }
492
+
493
+ .annual-table tr:last-child td {
494
+ border-bottom: none;
495
+ }
496
+
497
+ .season-badge {
498
+ font-family: monospace;
499
+ font-size: 0.75rem;
500
+ padding: 3px 8px;
501
+ background: #e9ecef;
502
+ border-radius: 4px;
503
+ color: var(--text-dark);
504
+ font-weight: 600;
505
+ display: inline-block;
506
+ width: 60px;
507
+ text-align: center;
508
+ }
509
+
510
+
511
+ /* Smart Table */
512
+ .smart-table-container {
513
+ overflow-x: auto;
514
+ margin-bottom: 3rem;
515
+ border: 1px solid var(--border);
516
+ border-radius: var(--radius-md);
517
+ box-shadow: var(--shadow-sm);
518
+ }
519
+
520
+ .smart-table {
521
+ width: 100%;
522
+ border-collapse: collapse;
523
+ background: white;
524
+ }
525
+
526
+ .smart-table th {
527
+ background: #f8f9fa;
528
+ color: var(--text-muted);
529
+ padding: 1rem 1.5rem;
530
+ text-align: left;
531
+ font-size: 0.8rem;
532
+ text-transform: uppercase;
533
+ border-bottom: 2px solid var(--border);
534
+ }
535
+
536
+ .smart-table td {
537
+ padding: 1rem 1.5rem;
538
+ border-bottom: 1px solid var(--border);
539
+ color: var(--text-dark);
540
+ }
541
+
542
+ .smart-table tr:last-child td {
543
+ border-bottom: none;
544
+ }
545
+
546
+ .positive {
547
+ color: var(--success);
548
+ font-weight: 700;
549
+ background: #f0fdf4;
550
+ padding: 2px 8px;
551
+ border-radius: 4px;
552
+ }
553
+
554
+ .negative {
555
+ color: var(--danger);
556
+ font-weight: 700;
557
+ background: #fef2f2;
558
+ padding: 2px 8px;
559
+ border-radius: 4px;
560
+ }
561
+
562
+ h3 {
563
+ font-size: 1.25rem;
564
+ color: var(--primary);
565
+ margin-bottom: 1.5rem;
566
+ font-weight: 700;
567
+ display: flex;
568
+ align-items: center;
569
+ gap: 0.5rem;
570
+ }
571
+
572
+ @media (max-width: 768px) {
573
+ .hero h1 {
574
+ font-size: 1.75rem;
575
+ }
576
+
577
+ .growth-node {
578
+ flex-direction: column;
579
+ padding-left: 30px;
580
+ margin-bottom: 2rem;
581
+ }
582
+
583
+ .growth-timeline::before {
584
+ left: 15px;
585
+ }
586
+
587
+ .growth-node::after {
588
+ left: 15px;
589
+ }
590
+
591
+ .growth-card {
592
+ width: 100%;
593
+ margin: 0 !important;
594
+ border-radius: var(--radius-md) !important;
595
+ }
596
+ }
597
+
598
+ .loading {
599
+ display: none;
600
+ text-align: center;
601
+ padding: 2rem;
602
+ }
603
+
604
+ .spinner {
605
+ margin: 0 auto 1rem;
606
+ width: 40px;
607
+ height: 40px;
608
+ border: 3px solid var(--border);
609
+ border-top-color: var(--primary);
610
+ border-radius: 50%;
611
+ animation: spin 0.8s linear infinite;
612
+ }
613
+
614
+ @keyframes spin {
615
+ to {
616
+ transform: rotate(360deg);
617
+ }
618
+ }
619
+ </style>
620
+ </head>
621
+
622
+ <body>
623
+ <header class="hero">
624
+ <div class="container">
625
+ <h1>Crop Revenue Analyzer</h1>
626
+ <p>AI-powered crop swapping strategies for maximum profitability</p>
627
+ </div>
628
+ </header>
629
+
630
+ <main class="container">
631
+ <div class="card">
632
+ <form id="cropForm" action="/" method="POST">
633
+ <div class="form-grid">
634
+ <div class="form-group">
635
+ <label class="form-label" for="location"><i class="bi bi-geo-alt"></i> Location</label>
636
+ <input type="text" class="form-control" id="location" name="location" placeholder="Enter your location"
637
+ required>
638
+ </div>
639
+ <div class="form-group">
640
+ <label class="form-label" for="total_area"><i class="bi bi-rulers"></i> Total Area (acres)</label>
641
+ <input type="number" class="form-control" id="total_area" name="total_area" step="0.1" min="0.1"
642
+ placeholder="e.g., 10" required>
643
+ </div>
644
+ <div class="form-group">
645
+ <label class="form-label" for="language"><i class="bi bi-translate"></i> Language</label>
646
+ <select class="form-control" id="language" name="language">
647
+ <option value="English" selected>English</option>
648
+ <option value="Hindi">Hindi</option>
649
+ <option value="Marathi">Marathi</option>
650
+ <option value="Malayalam">Malayalam</option>
651
+ <option value="Tamil">Tamil</option>
652
+ <option value="Telugu">Telugu</option>
653
+ <option value="Bengali">Bengali</option>
654
+ <option value="Odia">Odia</option>
655
+ <option value="Urdu">Urdu</option>
656
+ </select>
657
+ </div>
658
+ </div>
659
+
660
+ <h3 class="section-title" style="margin-top: 0; font-size: 1.1rem; border:none; padding-left: 0;"><i
661
+ class="bi bi-flower2"></i> CURRENT ANNUAL CROP PLAN</h3>
662
+
663
+ <table class="crop-table" id="cropTable">
664
+ <thead>
665
+ <tr>
666
+ <th style="width: 25%">Season</th>
667
+ <th style="width: 35%">Crop Name</th>
668
+ <th style="width: 25%">Area (acres)</th>
669
+ <th style="width: 15%; text-align: center;">Action</th>
670
+ </tr>
671
+ </thead>
672
+ <tbody id="cropTableBody">
673
+ <tr>
674
+ <td>
675
+ <select name="crop_season" required>
676
+ <option value="Kharif">Kharif (Monsoon)</option>
677
+ <option value="Rabi">Rabi (Winter)</option>
678
+ <option value="Zaid">Zaid (Summer)</option>
679
+ </select>
680
+ </td>
681
+ <td><input type="text" name="crop_name" placeholder="Crop Name" required></td>
682
+ <td><input type="number" name="crop_area" step="0.1" min="0.1" placeholder="Acres" required></td>
683
+ <td style="text-align: center;">
684
+ <button type="button" class="btn btn-icon" onclick="removeRow(this)" title="Remove"><i
685
+ class="bi bi-trash"></i></button>
686
+ </td>
687
+ </tr>
688
+ </tbody>
689
+ </table>
690
+
691
+ <div class="btn-group">
692
+ <button type="button" class="btn btn-secondary" onclick="addRow()"><i class="bi bi-plus-circle"></i> Add More
693
+ Crops</button>
694
+ <button type="submit" class="btn btn-primary" id="submitBtn"><i class="bi bi-lightning-charge"></i> Analyze
695
+ Strategy</button>
696
+ </div>
697
+ </form>
698
+
699
+ <div class="loading" id="loadingSpinner">
700
+ <div class="spinner"></div>
701
+ <p>Generating your comprehensive 3-year plan...</p>
702
+ </div>
703
+
704
+ {% if error %}
705
+ <div class="alert-error">
706
+ <i class="bi bi-exclamation-triangle"></i>
707
+ <span>{{ error }}</span>
708
+ </div>
709
+ {% endif %}
710
+ </div>
711
+
712
+ {% if result %}
713
+ <div class="results-card">
714
+ <div class="results-header">
715
+ <i class="bi bi-bar-chart-line"></i>
716
+ <h2>Optimized Annual Strategy</h2>
717
+ </div>
718
+ <div class="results-content">
719
+ {{ result|safe }}
720
+ </div>
721
+ </div>
722
+ {% endif %}
723
+ </main>
724
+
725
+ <footer>
726
+ <p>© 2025 Crop Revenue Analyzer • AI-Powered Farm Planning</p>
727
+ </footer>
728
+
729
+ <script>
730
+ function addRow() {
731
+ const tbody = document.getElementById('cropTableBody');
732
+ const row = document.createElement('tr');
733
+ row.innerHTML = `
734
+ <td>
735
+ <select name="crop_season" required>
736
+ <option value="Kharif">Kharif</option>
737
+ <option value="Rabi">Rabi</option>
738
+ <option value="Zaid">Zaid</option>
739
+ </select>
740
+ </td>
741
+ <td><input type="text" name="crop_name" placeholder="Crop Name" required></td>
742
+ <td><input type="number" name="crop_area" step="0.1" min="0.1" placeholder="Acres" required></td>
743
+ <td style="text-align: center;"><button type="button" class="btn btn-icon" onclick="removeRow(this)"><i class="bi bi-trash"></i></button></td>
744
+ `;
745
+ tbody.appendChild(row);
746
+ }
747
+ function removeRow(btn) {
748
+ if (document.querySelectorAll('#cropTableBody tr').length > 1) btn.closest('tr').remove();
749
+ }
750
+ document.getElementById('cropForm').addEventListener('submit', function () {
751
+ document.getElementById('submitBtn').disabled = true;
752
+ document.getElementById('submitBtn').innerHTML = '<i class="bi bi-hourglass-split"></i> Processing...';
753
+ document.getElementById('loadingSpinner').style.display = 'block';
754
+ });
755
+ </script>
756
+ </body>
757
+
758
+ </html>