soil / templates /index.html
pranit144's picture
Upload 4 files
73f907e verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Soil Analysis Dashboard</title>
<!-- Bootstrap CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet">
<!-- Leaflet CSS -->
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" />
<style>
body { background-color: #f4f8f4; }
.navbar-brand { font-weight: bold; }
#map { height: 400px; border-radius: 0.5rem; border: 1px solid #ddd; }
.card { border: 1px solid #28a745; }
.btn-success { background-color: #28a745; border-color: #28a745; }
.btn-success:hover { background-color: #218838; border-color: #1e7e34; }
.loader { display: none; }
</style>
</head>
<body>
<nav class="navbar navbar-dark bg-success">
<div class="container-fluid">
<span class="navbar-brand mb-0 h1 mx-auto">🌱 Soil Analysis Dashboard</span>
</div>
</nav>
<div class="container my-4">
<!-- Step 1: Location -->
<div class="card mb-4">
<div class="card-header fw-bold">Step 1: Select Location</div>
<div class="card-body">
<div class="row">
<div class="col-lg-8 mb-3 mb-lg-0">
<div id="map"></div>
</div>
<div class="col-lg-4">
<div class="mb-3">
<label for="lat" class="form-label">Latitude</label>
<input type="text" id="lat" class="form-control" placeholder="Click map or enter manually">
</div>
<div class="mb-3">
<label for="lon" class="form-label">Longitude</label>
<input type="text" id="lon" class="form-control" placeholder="Click map or enter manually">
</div>
<button id="current-location" class="btn btn-secondary w-100 mb-2">Use Current Location</button>
<button id="fetch-report" class="btn btn-success w-100">
<span class="spinner-border spinner-border-sm loader" role="status" aria-hidden="true"></span>
Fetch Soil Report
</button>
</div>
</div>
</div>
</div>
<!-- Alert for errors -->
<div id="alert-container" class="mt-3"></div>
<!-- Step 2: Soil Report (Initially Hidden) -->
<div id="soil-report-section" class="d-none">
<div class="card mb-4">
<div class="card-header fw-bold">Step 2: Soil Report</div>
<div class="card-body">
<div class="row">
<div class="col-md-6" id="classification-report"></div>
<div class="col-md-6" id="properties-report"></div>
</div>
</div>
</div>
</div>
<!-- Step 3: Analysis (Initially Hidden) -->
<div id="analysis-section" class="d-none">
<div class="card mb-4">
<div class="card-header fw-bold">Step 3: AI Analysis & Recommendations</div>
<div class="card-body">
<div class="row align-items-end">
<div class="col-md-8 mb-3 mb-md-0">
<label for="language" class="form-label">Response Language</label>
<select class="form-select" id="language">
<option value="English">English</option><option value="Hindi">Hindi</option><option value="Bengali">Bengali</option>
<option value="Telugu">Telugu</option><option value="Marathi">Marathi</option><option value="Tamil">Tamil</option>
<option value="Gujarati">Gujarati</option><option value="Urdu">Urdu</option><option value="Kannada">Kannada</option>
<option value="Odia">Odia</option><option value="Malayalam">Malayalam</option>
</select>
</div>
<div class="col-md-4">
<button id="analyze-soil" class="btn btn-success w-100">
<span class="spinner-border spinner-border-sm loader" role="status" aria-hidden="true"></span>
Analyze with AI
</button>
</div>
</div>
<hr>
<div id="analysis-result"></div>
</div>
</div>
</div>
</div>
<!-- Bootstrap & Leaflet JS -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.bundle.min.js"></script>
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script>
<script>
// --- Global State ---
let soilReportData = null;
let map, marker;
// --- UI Helper Functions ---
const showAlert = (message, type = 'danger') => {
const alertContainer = document.getElementById('alert-container');
alertContainer.innerHTML = `<div class="alert alert-${type} alert-dismissible fade show" role="alert">
${message}
<button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div>`;
};
const toggleLoader = (buttonId, show) => {
const button = document.getElementById(buttonId);
const loader = button.querySelector('.loader');
button.disabled = show;
loader.style.display = show ? 'inline-block' : 'none';
};
// --- Map Initialization ---
const initializeMap = () => {
map = L.map('map').setView([20.5937, 78.9629], 5);
L.tileLayer('https://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png', {
attribution: '&copy; OpenStreetMap contributors'
}).addTo(map);
map.on('click', e => {
const { lat, lng } = e.latlng;
document.getElementById('lat').value = lat.toFixed(6);
document.getElementById('lon').value = lng.toFixed(6);
if (marker) marker.setLatLng(e.latlng);
else marker = L.marker(e.latlng).addTo(map);
});
};
// --- Event Listeners ---
document.getElementById('current-location').addEventListener('click', () => {
if (navigator.geolocation) {
navigator.geolocation.getCurrentPosition(pos => {
const { latitude, longitude } = pos.coords;
document.getElementById('lat').value = latitude.toFixed(6);
document.getElementById('lon').value = longitude.toFixed(6);
const latlng = L.latLng(latitude, longitude);
map.setView(latlng, 13);
if (marker) marker.setLatLng(latlng);
else marker = L.marker(latlng).addTo(map);
}, () => showAlert('Could not get your location.'));
} else {
showAlert('Geolocation is not supported by your browser.');
}
});
document.getElementById('fetch-report').addEventListener('click', () => {
const lat = document.getElementById('lat').value;
const lon = document.getElementById('lon').value;
if (!lat || !lon) return showAlert('Please provide latitude and longitude.');
toggleLoader('fetch-report', true);
fetch('/get_soil_report', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ lat, lon })
})
.then(response => response.json().then(data => ({ ok: response.ok, data })))
.then(({ ok, data }) => {
if (!ok) throw new Error(data.error || 'Unknown error occurred.');
soilReportData = data;
renderSoilReport(data);
document.getElementById('soil-report-section').classList.remove('d-none');
document.getElementById('analysis-section').classList.remove('d-none');
})
.catch(err => showAlert(`Error fetching soil report: ${err.message}`))
.finally(() => toggleLoader('fetch-report', false));
});
document.getElementById('analyze-soil').addEventListener('click', () => {
if (!soilReportData) return showAlert('Please fetch a soil report first.');
toggleLoader('analyze-soil', true);
document.getElementById('analysis-result').innerHTML = '';
// The Authorization header is no longer sent from the frontend
fetch('/analyze_soil', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
soil_report: soilReportData,
language: document.getElementById('language').value
})
})
.then(response => response.json().then(data => ({ ok: response.ok, data })))
.then(({ ok, data }) => {
if (!ok) throw new Error(data.error || 'Failed to get analysis.');
renderAnalysis(data);
})
.catch(err => showAlert(`Error during analysis: ${err.message}`))
.finally(() => toggleLoader('analyze-soil', false));
});
// --- Rendering Functions (No change here) ---
const renderSoilReport = (data) => {
let classHtml = `<h5>Soil Classification</h5><p><strong>Type:</strong> ${data.classification.soil_type}</p>`;
if (data.classification.probabilities.length) {
classHtml += `<table class="table table-sm table-bordered"><thead><tr><th>Type</th><th>Probability</th></tr></thead><tbody>`;
data.classification.probabilities.forEach(([type, prob]) => {
classHtml += `<tr><td>${type}</td><td>${prob}%</td></tr>`;
});
classHtml += `</tbody></table>`;
}
document.getElementById('classification-report').innerHTML = classHtml;
let propHtml = `<h5>Soil Properties (5-15cm)</h5><table class="table table-sm table-striped"><thead><tr><th>Parameter</th><th>Value</th></tr></thead><tbody>`;
data.properties.forEach(({ parameter, value, unit }) => {
const displayValue = (typeof value === 'number') ? `${value.toFixed(2)} ${unit}` : 'N/A';
propHtml += `<tr><td>${parameter}</td><td>${displayValue}</td></tr>`;
});
propHtml += `</tbody></table>`;
document.getElementById('properties-report').innerHTML = propHtml;
};
const renderAnalysis = (data) => {
let analysisHtml = `
<div class="mb-4">
<h4 class="text-success">${data.soilType}</h4>
<ul class="list-unstyled">
${data.generalInsights.map(insight => `<li>- ${insight}</li>`).join('')}
</ul>
</div>
<h5 class="mt-4">Parameter Analysis</h5>
<table class="table table-bordered">
<thead class="table-light"><tr><th>Parameter</th><th>Value</th><th>Range</th><th>Comment</th></tr></thead>
<tbody>
${data.parameters.map(p => `<tr><td>${p.parameter}</td><td>${p.value}</td><td>${p.range}</td><td>${p.comment}</td></tr>`).join('')}
</tbody>
</table>
<h5 class="mt-4">Crop Recommendations</h5>
<table class="table table-striped">
<thead class="table-light"><tr><th>Crop</th><th>Reason</th></tr></thead>
<tbody>
${data.cropRecommendations.map(c => `<tr><td>${c.crop}</td><td>${c.reason}</td></tr>`).join('')}
</tbody>
</table>
<h5 class="mt-4">Management Recommendations</h5>
<p><strong>Fertilization:</strong> ${data.managementRecommendations.fertilization}</p>
<p><strong>Irrigation:</strong> ${data.managementRecommendations.irrigation}</p>
`;
document.getElementById('analysis-result').innerHTML = analysisHtml;
};
// --- Initialize App ---
document.addEventListener('DOMContentLoaded', initializeMap);
</script>
</body>
</html>