Skip to content

Commit 42668ca

Browse files
authored
Merge branch 'main' into improve-footer-hover-scrolltop
2 parents 1c07628 + 0fdea51 commit 42668ca

98 files changed

Lines changed: 9146 additions & 23937 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
1-
name: Auto add ECWoC26 label to Issues
1+
name: Auto add NSOC'26 label to Issues
22

33
on:
44
issues:
5-
types: [opened]
5+
types:
6+
- opened
67

78
permissions:
89
issues: write
@@ -11,14 +12,15 @@ permissions:
1112
jobs:
1213
add-label:
1314
runs-on: ubuntu-latest
15+
1416
steps:
15-
- name: Add ECWoC26 label to issue
17+
- name: Add NSOC'26 label to issue
1618
uses: actions/github-script@v7
1719
with:
1820
script: |
1921
await github.rest.issues.addLabels({
2022
owner: context.repo.owner,
2123
repo: context.repo.repo,
2224
issue_number: context.payload.issue.number,
23-
labels: ["ECWoC26"],
25+
labels: ["NSOC'26"],
2426
});

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,3 +83,6 @@ datasets/
8383

8484
# Notebooks checkpoints
8585
.ipynb_checkpoints/
86+
87+
88+
*.bak

Crop Yield Prediction/crop_yield_app/templates/index.html

Lines changed: 122 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -329,97 +329,18 @@
329329
}
330330
}
331331
</style>
332-
</head>
333-
<body>
334-
<header class="sticky-header">
335-
<div class="container header-content navbar">
336-
337-
<!-- Left: Logo -->
338-
<a href="/" class="logo">
339-
<img src="/images/logo.png" alt="AgriTech Logo">
340-
<span class="logo-text">AgriTech</span>
341-
</a>
342-
343-
<!-- Center: Navigation -->
344-
<nav class="nav-links">
345-
<a href="/index.html">Home</a>
346-
<a href="/about.html">About</a>
347-
<a href="/blog.html">Blog</a>
348-
<a href="/community_forum.html">Community Forum</a>
349-
<a href="/faq.html">FAQ</a>
350-
<a href="/news.html">News</a>
351-
</nav>
352-
353-
<!-- Animated Sun/Moon Toggle -->
354-
<button class="theme-toggle" type="button" id="themeToggle" title="Switch to dark mode"
355-
aria-label="Switch to dark mode">
356-
<svg class="theme-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round"
357-
stroke-linejoin="round">
358-
<mask id="moon-mask">
359-
<rect x="0" y="0" width="100%" height="100%" fill="white" />
360-
<circle class="moon-bite" cx="14" cy="9" r="14" fill="black" />
361-
</mask>
362-
<circle class="sun-core" cx="12" cy="12" r="7" fill="currentColor" mask="url(#moon-mask)" />
363-
<g class="sun-rays" stroke="currentColor">
364-
<line x1="12" y1="1" x2="12" y2="3" />
365-
<line x1="12" y1="21" x2="12" y2="23" />
366-
<line x1="4.22" y1="4.22" x2="5.64" y2="5.64" />
367-
<line x1="18.36" y1="18.36" x2="19.78" y2="19.78" />
368-
<line x1="1" y1="12" x2="3" y2="12" />
369-
<line x1="21" y1="12" x2="23" y2="12" />
370-
<line x1="4.22" y1="19.78" x2="5.64" y2="18.36" />
371-
<line x1="18.36" y1="5.64" x2="19.78" y2="4.22" />
372-
</g>
373-
</svg>
374-
</button>
375-
376-
</div>
377-
</header>
378-
379-
380-
<main class="main-layout container">
381-
<div class="content-left">
382-
383-
<div class="header">
384-
<h1>Optimal Crop yield prediction 🎯</h1>
385-
<p>
386-
Based on your provided soil and climate data, the following crop is
387-
highly recommended for maximum yield and sustainability.
388-
</p>
389-
</div>
390-
391-
html::-webkit-scrollbar-thumb:hover {
392-
background: #94ffab;
393-
}
394-
395-
/* ================= RESPONSIVE ================= */
396-
@media (max-width: 1024px) {
397-
.main-layout {
398-
grid-template-columns: 1fr;
399-
}
400-
}
401-
402-
@media (max-width: 600px) {
403-
h1 {
404-
font-size: 1.5rem;
405-
}
406-
407-
.result-value {
408-
font-size: 1.8rem;
409-
}
410-
411-
.action-buttons-group {
412-
flex-direction: column;
413-
}
414-
415-
.nav-links {
416-
display: none;
417-
}
418-
}
419-
</style>
420332
</head>
421333

422-
<body>
334+
<body
335+
data-crop="{{ crop|default('') }}"
336+
data-n="{{ params.N|default('') }}"
337+
data-p="{{ params.P|default('') }}"
338+
data-k="{{ params.K|default('') }}"
339+
data-temperature="{{ params.temperature|default('') }}"
340+
data-rainfall="{{ params.rainfall|default('') }}"
341+
data-humidity="{{ params.humidity|default('') }}"
342+
data-ph="{{ params.ph|default('') }}"
343+
>
423344
<header class="sticky-header">
424345
<div class="container header-content navbar">
425346

@@ -482,7 +403,7 @@ <h1>Optimal Crop yield prediction 🎯</h1>
482403
<div class="result-value">
483404
<i class="fas fa-seedling"></i>
484405
<span class="recommended-crop">
485-
<h1 id="predictedCrop">Crop Result</h1>
406+
<h2 id="predictedCrop">Crop Result</h2>
486407
</span>
487408
</div>
488409
<p class="insight-note">
@@ -506,11 +427,7 @@ <h1 id="predictedCrop">Crop Result</h1>
506427
</div>
507428

508429
<div class="action-buttons-group">
509-
<form method="post" action="/download_report">
510-
511-
<input type="hidden" name="{{ key }}" value="{{ value }}" />
512-
513-
<input type="hidden" name="crop" value="{{ crop }}" />
430+
<form method="post" action="/download_report" id="downloadReportForm">
514431

515432
<button type="submit" class="btn btn-primary"
516433
onclick="this.classList.add('loading'); this.innerHTML='<i class=\'fas fa-spinner fa-spin\'></i> Generating PDF...';">
@@ -710,42 +627,124 @@ <h4>Quick Links</h4>
710627
animateCursor();
711628
</script>
712629
<script>
713-
/*
714-
Frontend-only replacement for Jinja placeholders
715-
Reads values from URL query params
716-
Example URL:
717-
result.html?crop=Wheat&temperature=25&humidity=60&rainfall=120&ph=6.5&N=90&P=40&K=50
718-
*/
719-
720-
function getParam(name) {
721-
const urlParams = new URLSearchParams(window.location.search);
722-
return urlParams.get(name);
723-
}
630+
(function () {
631+
function isTemplateToken(value) {
632+
return typeof value === "string" && value.includes("{{") && value.includes("}}");
633+
}
634+
635+
function cleanValue(value) {
636+
if (value === null || value === undefined) return "";
637+
const text = String(value).trim();
638+
return isTemplateToken(text) ? "" : text;
639+
}
640+
641+
function getParamInsensitive(name) {
642+
const params = new URLSearchParams(window.location.search);
643+
const target = String(name).toLowerCase();
644+
for (const [key, value] of params.entries()) {
645+
if (String(key).toLowerCase() === target) {
646+
return cleanValue(value);
647+
}
648+
}
649+
return "";
650+
}
651+
652+
function getBodyData(name) {
653+
const value = document.body && document.body.dataset ? document.body.dataset[name] : "";
654+
return cleanValue(value);
655+
}
724656

725-
// Set dynamic values
726-
document.getElementById("predictedCrop").textContent =
727-
(getParam("crop") || "Recommended Crop").toUpperCase();
657+
function resolveValue(options) {
658+
const keys = options.queryKeys || [];
659+
for (const key of keys) {
660+
const queryValue = getParamInsensitive(key);
661+
if (queryValue) return queryValue;
662+
}
728663

729-
document.getElementById("temperatureValue").textContent =
730-
getParam("temperature") || "--";
664+
if (options.bodyKey) {
665+
const bodyValue = getBodyData(options.bodyKey);
666+
if (bodyValue) return bodyValue;
667+
}
731668

732-
document.getElementById("humidityValue").textContent =
733-
getParam("humidity") || "--";
669+
return options.fallback || "--";
670+
}
734671

735-
document.getElementById("rainfallValue").textContent =
736-
getParam("rainfall") || "--";
672+
function toTitleCase(text) {
673+
return String(text || "")
674+
.toLowerCase()
675+
.replace(/\b\w/g, function (match) { return match.toUpperCase(); });
676+
}
737677

738-
document.getElementById("phValue").textContent =
739-
getParam("ph") || "--";
678+
const resolved = {
679+
crop: resolveValue({ queryKeys: ["crop", "Crop"], bodyKey: "crop", fallback: "Recommended Crop" }),
680+
temperature: resolveValue({ queryKeys: ["temperature", "temp"], bodyKey: "temperature" }),
681+
humidity: resolveValue({ queryKeys: ["humidity"], bodyKey: "humidity" }),
682+
rainfall: resolveValue({ queryKeys: ["rainfall"], bodyKey: "rainfall" }),
683+
ph: resolveValue({ queryKeys: ["ph", "pH"], bodyKey: "ph" }),
684+
N: resolveValue({ queryKeys: ["N", "n"], bodyKey: "n" }),
685+
P: resolveValue({ queryKeys: ["P", "p"], bodyKey: "p" }),
686+
K: resolveValue({ queryKeys: ["K", "k"], bodyKey: "k" })
687+
};
688+
689+
document.getElementById("predictedCrop").textContent = toTitleCase(resolved.crop);
690+
document.getElementById("temperatureValue").textContent = resolved.temperature;
691+
document.getElementById("humidityValue").textContent = resolved.humidity;
692+
document.getElementById("rainfallValue").textContent = resolved.rainfall;
693+
document.getElementById("phValue").textContent = resolved.ph;
694+
document.getElementById("nValue").textContent = resolved.N;
695+
document.getElementById("pValue").textContent = resolved.P;
696+
document.getElementById("kValue").textContent = resolved.K;
697+
698+
const placeholderValueMap = {
699+
Crop: toTitleCase(resolved.crop),
700+
"params.N": resolved.N,
701+
"params.P": resolved.P,
702+
"params.K": resolved.K,
703+
"params.temperature": resolved.temperature,
704+
"params.rainfall": resolved.rainfall,
705+
"params.humidity": resolved.humidity,
706+
"params.ph": resolved.ph
707+
};
708+
709+
function replaceTemplateTokens(text) {
710+
if (!text || text.indexOf("{{") === -1) return text;
711+
712+
return text
713+
.replace(/\{\{\s*Crop\s*\|\s*capitalize\s*\}\}/gi, placeholderValueMap.Crop)
714+
.replace(/\{\{\s*params\.(N|P|K|temperature|rainfall|humidity|ph)\s*\}\}/g, function (_, key) {
715+
return placeholderValueMap["params." + key] || "--";
716+
});
717+
}
740718

741-
document.getElementById("nValue").textContent =
742-
getParam("N") || "--";
719+
const walker = document.createTreeWalker(document.body, NodeFilter.SHOW_TEXT, null);
720+
let textNode = walker.nextNode();
721+
while (textNode) {
722+
textNode.nodeValue = replaceTemplateTokens(textNode.nodeValue);
723+
textNode = walker.nextNode();
724+
}
743725

744-
document.getElementById("pValue").textContent =
745-
getParam("P") || "--";
726+
document.querySelectorAll("[value], [title], [placeholder]").forEach(function (element) {
727+
["value", "title", "placeholder"].forEach(function (attr) {
728+
const existing = element.getAttribute(attr);
729+
if (existing && existing.indexOf("{{") !== -1) {
730+
element.setAttribute(attr, replaceTemplateTokens(existing));
731+
}
732+
});
733+
});
746734

747-
document.getElementById("kValue").textContent =
748-
getParam("K") || "--";
735+
const downloadForm = document.getElementById("downloadReportForm");
736+
if (downloadForm) {
737+
["crop", "temperature", "humidity", "rainfall", "ph", "N", "P", "K"].forEach(function (key) {
738+
const value = resolved[key];
739+
if (!value || value === "--") return;
740+
const input = document.createElement("input");
741+
input.type = "hidden";
742+
input.name = key;
743+
input.value = value;
744+
downloadForm.appendChild(input);
745+
});
746+
}
747+
})();
749748
</script>
750749

751750
</body>

Crop_Planning/app.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,8 +48,8 @@ def validate_payload(required_fields):
4848
def decorator(f):
4949
@wraps(f)
5050
def decorated_function(*args, **kwargs):
51-
payload = request.get_json()
52-
if not payload or 'data' not in payload:
51+
payload = request.get_json(silent=True)
52+
if not isinstance(payload, dict) or 'data' not in payload or not isinstance(payload['data'], dict):
5353
return jsonify({'error': True, 'message': 'Missing "data" key in JSON'}), 400
5454

5555
data = payload['data']
@@ -98,7 +98,8 @@ def home():
9898
@validate_payload(['season', 'soil_type', 'climate', 'water_availability'])
9999
def predict():
100100
try:
101-
user_input_data = request.get_json()['data']
101+
payload = request.get_json(silent=True) or {}
102+
user_input_data = payload['data']
102103

103104
# Get result from AI
104105
ai_data = get_ai_prediction(user_input_data)

0 commit comments

Comments
 (0)