Spaces:
Sleeping
Sleeping
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>International Trade Flow Predictor</title> | |
<link rel="stylesheet" href="/static/css/style.css"> | |
<!-- Font Awesome for icons --> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.1.1/css/all.min.css"> | |
<!-- Leaflet for maps --> | |
<link rel="stylesheet" href="https://unpkg.com/leaflet/dist/leaflet.css" /> | |
<!-- Custom trade flow map --> | |
<script src="/static/js/tradeflowmap.js"></script> | |
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap"> | |
<style> | |
/* Custom inline styles */ | |
:root { | |
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif; | |
} | |
body { | |
font-family: var(--font-sans); | |
} | |
.advanced-chart-container { | |
width: 100%; | |
height: 400px; | |
position: relative; | |
border-radius: var(--radius-md); | |
overflow: hidden; | |
border: 1px solid var(--border-color); | |
} | |
.treemap-container { | |
width: 100%; | |
border: 1px solid var(--border-color); | |
border-radius: var(--radius-md); | |
} | |
.treemap-title { | |
font-weight: 600; | |
padding: 12px 16px; | |
background: var(--background-grey); | |
border-bottom: 1px solid var(--border-color); | |
} | |
.treemap-item:hover { | |
opacity: 0.9; | |
transform: scale(1.02); | |
transition: all 0.2s ease; | |
z-index: 5; | |
} | |
/* Chart controls */ | |
.chart-controls { | |
display: flex; | |
flex-wrap: wrap; | |
gap: 8px; | |
margin-bottom: 16px; | |
} | |
.chart-type-btn { | |
display: inline-flex; | |
align-items: center; | |
padding: 6px 12px; | |
background-color: var(--background-light); | |
border: 1px solid var(--border-color); | |
border-radius: var(--radius-sm); | |
font-size: 13px; | |
cursor: pointer; | |
transition: all 0.2s ease; | |
} | |
.chart-type-btn:hover { | |
background-color: var(--primary-light); | |
color: var(--primary-color); | |
} | |
.chart-type-btn.active { | |
background-color: var(--primary-color); | |
color: white; | |
border-color: var(--primary-color); | |
} | |
/* Cached data styling */ | |
.cached-data-panel { | |
margin-top: 24px; | |
border: 1px solid var(--border-color); | |
border-radius: var(--radius-md); | |
overflow: hidden; | |
background-color: var(--background-light); | |
} | |
.cached-data-header { | |
padding: 12px 16px; | |
background-color: var(--background-grey); | |
font-weight: 600; | |
border-bottom: 1px solid var(--border-color); | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
} | |
.cached-data-list { | |
max-height: 320px; | |
overflow-y: auto; | |
padding: 0; | |
margin: 0; | |
} | |
.cached-data-item { | |
padding: 12px 16px; | |
border-bottom: 1px solid var(--border-color); | |
display: flex; | |
justify-content: space-between; | |
align-items: center; | |
transition: background-color 0.2s ease; | |
} | |
.cached-data-item:hover { | |
background-color: var(--background-grey); | |
} | |
.cached-data-item:hover { | |
background: #f9f9fa; | |
} | |
.cached-data-actions { | |
display: flex; | |
gap: 5px; | |
} | |
.cached-data-info { | |
font-size: 13px; | |
color: #666; | |
} | |
.action-btn { | |
background: none; | |
border: none; | |
color: #1976d2; | |
cursor: pointer; | |
padding: 3px 8px; | |
border-radius: 3px; | |
} | |
.action-btn:hover { | |
background: #e3e9f6; | |
} | |
.action-btn.delete { | |
color: #e53935; | |
} | |
.action-btn.delete:hover { | |
background: #ffebee; | |
} | |
/* AI Assistant styles */ | |
.chat-container { | |
display: flex; | |
flex-direction: column; | |
max-height: 350px; | |
overflow-y: auto; | |
padding: 16px; | |
background-color: var(--background-light); | |
border-radius: var(--radius-md); | |
margin-bottom: 16px; | |
border: 1px solid var(--border-color); | |
} | |
.chat-message { | |
padding: 12px 16px; | |
margin-bottom: 12px; | |
border-radius: var(--radius-md); | |
max-width: 80%; | |
word-wrap: break-word; | |
} | |
.user-message { | |
background-color: var(--primary-light); | |
color: var(--text-color); | |
margin-left: auto; | |
border-radius: 12px 12px 2px 12px; | |
} | |
.assistant-message { | |
background-color: var(--background-grey); | |
color: var(--text-color); | |
margin-right: auto; | |
border-radius: 12px 12px 12px 2px; | |
} | |
.chat-input-container { | |
padding: 16px; | |
background-color: var(--background-light); | |
border-top: 1px solid var(--border-color); | |
display: flex; | |
align-items: center; | |
gap: 12px; | |
} | |
.chat-input { | |
flex: 1; | |
padding: 10px 12px; | |
border: 1px solid var(--border-color); | |
border-radius: var(--radius-sm); | |
font-size: 14px; | |
color: var(--text-color); | |
transition: all 0.2s ease; | |
} | |
.chat-input:focus { | |
outline: none; | |
border-color: var(--primary-color); | |
box-shadow: 0 0 0 2px rgba(0, 103, 223, 0.15); | |
} | |
.chat-submit { | |
padding: 10px 16px; | |
background-color: var(--primary-color); | |
color: white; | |
border: none; | |
border-radius: var(--radius-sm); | |
cursor: pointer; | |
font-weight: 500; | |
display: inline-flex; | |
align-items: center; | |
transition: all 0.2s ease; | |
} | |
.chat-submit:hover { | |
background-color: #0055c4; | |
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1); | |
} | |
.message { | |
margin-bottom: 15px; | |
max-width: 80%; | |
} | |
.message-user { | |
align-self: flex-end; | |
margin-left: auto; | |
background: #e3f2fd; | |
border-radius: 18px 18px 0 18px; | |
padding: 10px 15px; | |
} | |
.message-assistant { | |
align-self: flex-start; | |
background: #fff; | |
border-radius: 18px 18px 18px 0; | |
padding: 10px 15px; | |
border: 1px solid #e0e0e0; | |
} | |
.message-loading { | |
display: flex; | |
align-items: center; | |
padding: 10px 15px; | |
} | |
.loading-dots span { | |
display: inline-block; | |
width: 8px; | |
height: 8px; | |
border-radius: 50%; | |
background-color: #1976d2; | |
margin-right: 3px; | |
animation: loading-bounce 1.4s infinite ease-in-out both; | |
} | |
.loading-dots span:nth-child(1) { animation-delay: -0.32s; } | |
.loading-dots span:nth-child(2) { animation-delay: -0.16s; } | |
@keyframes loading-bounce { | |
0%, 80%, 100% { transform: scale(0); } | |
40% { transform: scale(1); } | |
} | |
.quick-questions { | |
display: flex; | |
flex-wrap: wrap; | |
gap: 8px; | |
margin-top: 10px; | |
} | |
.quick-question-btn { | |
background: #f0f4f8; | |
border: 1px solid #ddd; | |
border-radius: 16px; | |
padding: 6px 12px; | |
font-size: 13px; | |
cursor: pointer; | |
transition: all 0.2s; | |
} | |
.quick-question-btn:hover { | |
background: #e3e9f6; | |
} | |
.badge { | |
display: inline-block; | |
padding: 2px 6px; | |
border-radius: 10px; | |
background-color: #E53935; | |
color: white; | |
font-size: 10px; | |
font-weight: bold; | |
margin-left: 5px; | |
vertical-align: top; | |
} | |
</style> | |
</head> | |
<body class="app-container"> | |
<!-- Header with logo and navigation --> | |
<header class="header"> | |
<div class="header-container"> | |
<a href="/" class="app-logo"> | |
<i class="fas fa-globe-americas"></i> | |
<span>Trade Flow Predictor</span> | |
</a> | |
<div class="header-actions"> | |
<a href="https://huggingface.co/spaces/jomasego/trade-flow-predictor" target="_blank" class="huggingface-link"> | |
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face"> | |
<span>View on Hugging Face</span> | |
</a> | |
</div> | |
</div> | |
</header> | |
<!-- Info banner for sources and rate-limit info --> | |
<div class="info-banner"> | |
<div class="info-sources"> | |
<span class="source-label">Sources:</span> UN COMTRADE, WTO, World Bank | |
<span class="info-divider">|</span> | |
<span class="limit-label">API Limit:</span> 1 request/sec, 100 requests/hour | |
</div> | |
<div class="powered-by"> | |
<span>Powered by</span> | |
<a href="https://huggingface.co" target="_blank" class="huggingface-badge"> | |
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face"> | |
</a> | |
</div> | |
</div> | |
<!-- Main content container --> | |
<div class="main-content"> | |
<!-- Tab Navigation --> | |
<nav class="tab-navigation"> | |
<ul id="main-tabs" class="tab-bar"> | |
<li class="tab active" data-tab="basics" tabindex="0" aria-selected="true">Basics</li> | |
<li class="tab" data-tab="exports-country" tabindex="0" aria-selected="false">Exports by Country</li> | |
<li class="tab" data-tab="imports-country" tabindex="0" aria-selected="false">Imports by Country</li> | |
<li class="tab" data-tab="exports-product" tabindex="0" aria-selected="false">Exports by Product</li> | |
<li class="tab" data-tab="imports-product" tabindex="0" aria-selected="false">Imports by Product</li> | |
<li class="tab" data-tab="rankings" tabindex="0" aria-selected="false">Rankings</li> | |
<li class="tab" data-tab="bilateral" tabindex="0" aria-selected="false">Bilateral Trade</li> | |
<li class="tab" data-tab="data-download" tabindex="0" aria-selected="false">Data Download</li> | |
<li class="tab" data-tab="prediction" tabindex="0" aria-selected="false">Prediction (ML)</li> | |
<li class="tab" data-tab="data-cache" tabindex="0" aria-selected="false">Data Cache</li> | |
<li class="tab" data-tab="assistant" tabindex="0" aria-selected="false">AI Assistant <span class="badge">New</span></li> | |
</ul> | |
</nav> | |
<!-- Tab content begins here --> | |
<!-- Tab Content Panels --> | |
<div id="tab-content-basics" class="tab-content" style="display:block;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Trade Data Analysis</h2> | |
</div> | |
<form id="tradeForm"> | |
<div style="display:flex;flex-wrap:wrap;gap:16px;"> | |
<div style="flex:1;min-width:240px;"> | |
<label for="reporterCode">Reporter Country</label> | |
<select id="reporterCode" name="reporterCode"></select> | |
</div> | |
<div style="flex:1;min-width:240px;"> | |
<label for="partnerCode">Partner Country</label> | |
<select id="partnerCode" name="partnerCode"></select> | |
</div> | |
</div> | |
<div style="display:flex;flex-wrap:wrap;gap:16px;margin-top:8px;"> | |
<div style="flex:1;min-width:240px;"> | |
<label for="year">Year</label> | |
<input type="number" id="year" name="year" value="2022" min="2000" max="2100"> | |
</div> | |
<div style="flex:1;min-width:240px;"> | |
<label for="cmdCode">Commodity Code</label> | |
<input type="text" id="cmdCode" name="cmdCode" value="TOTAL" placeholder="e.g., TOTAL or specific HS code"> | |
</div> | |
</div> | |
<div style="margin-top:16px;"> | |
<button type="submit" class="btn-primary">Generate Trade Report</button> | |
</div> | |
</form> | |
<div id="results" class="results-section"></div> | |
</div> | |
<!-- Visualization Container --> | |
<div class="chart-container" style="display:none;margin-top:24px;" id="visualizationContainer"> | |
<div class="section-heading"> | |
<h3>Trade Data Visualization</h3> | |
</div> | |
<div class="chart-controls"> | |
<button class="chart-type-btn active" data-type="bar"> | |
<i class="fas fa-chart-bar"></i> Bar Chart | |
</button> | |
<button class="chart-type-btn" data-type="pie"> | |
<i class="fas fa-chart-pie"></i> Pie Chart | |
</button> | |
<button class="chart-type-btn" data-type="line"> | |
<i class="fas fa-chart-line"></i> Line Chart | |
</button> | |
<button class="chart-type-btn" data-type="treemap"> | |
<i class="fas fa-th-large"></i> Treemap | |
</button> | |
</div> | |
<canvas id="tradeChart" height="350"></canvas> | |
</div> | |
</div> | |
<!-- Select2 for searchable dropdowns --> | |
<!-- JavaScript modules --> | |
<script src="https://unpkg.com/leaflet/dist/leaflet.js"></script> | |
<script src="/static/js/country_codes.js"></script> | |
<script src="/static/js/data_manager.js"></script> | |
<script src="/static/js/charts_module.js"></script> | |
<script src="/static/js/main.js"></script> | |
<script src="/static/js/enhanced_visualizations.js"></script> | |
<script src="/static/js/assistant.js"></script> | |
<div id="extraVisualizations" style="margin-top:2em;"></div> | |
<script> | |
// Populate country dropdowns from COUNTRY_CODES | |
document.addEventListener('DOMContentLoaded', function() { | |
function populateCountrySelect(selectId, defaultCode) { | |
const select = document.getElementById(selectId); | |
if (!select || typeof COUNTRY_CODES === 'undefined') return; | |
select.innerHTML = ''; | |
COUNTRY_CODES.forEach(c => { | |
const opt = document.createElement('option'); | |
opt.value = c.code; | |
opt.textContent = c.name + ' (' + c.code + ')'; | |
if (c.code === defaultCode) opt.selected = true; | |
select.appendChild(opt); | |
}); | |
// Make dropdown searchable with Select2 | |
window.$ && window.$(select).select2 && window.$(select).select2(); | |
} | |
populateCountrySelect('reporterCode', '842'); | |
populateCountrySelect('partnerCode', '156'); | |
}); | |
</script> | |
<!-- jQuery for select2 --> | |
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script> | |
</div> | |
<div id="tab-content-exports-country" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Exports by Country</h2> | |
<p class="section-description">Analyze international export flows by country and year</p> | |
</div> | |
<form id="exportsCountryForm"> | |
<div class="form-row"> | |
<div class="form-group col-md-4"> | |
<label for="exportsCountryYear">Year</label> | |
<input type="number" id="exportsCountryYear" name="exportsCountryYear" value="2022" min="2000" max="2100" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="exportsCountryCommodity">Commodity Code</label> | |
<input type="text" id="exportsCountryCommodity" name="exportsCountryCommodity" value="TOTAL" placeholder="e.g., TOTAL or HS code" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="exportsCountryFlow">Flow Type</label> | |
<select id="exportsCountryFlow" name="exportsCountryFlow" class="select-field"> | |
<option value="X">Export</option> | |
<option value="M">Import</option> | |
<option value="">All</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-actions"> | |
<button type="submit" class="btn-primary">Show Trade Data</button> | |
<button id="exportsCountryDownloadBtn" class="btn-secondary" style="display:none;">Download CSV</button> | |
</div> | |
</form> | |
<div id="exportsCountryResults" class="results-section"></div> | |
</div> | |
<!-- Trade Flow Visualization Card --> | |
<div class="card" id="exportsCountryChartCard" style="margin-top:24px;"> | |
<div class="section-heading"> | |
<h3>Exports Flow Visualization</h3> | |
</div> | |
<div class="visualization-tabs"> | |
<div class="chart-controls"> | |
<button class="chart-type-btn active" data-type="bar"> | |
<i class="fas fa-chart-bar"></i> Bar Chart | |
</button> | |
<button class="chart-type-btn" data-type="map"> | |
<i class="fas fa-globe"></i> Trade Flow Map | |
</button> | |
</div> | |
</div> | |
<div id="exportsCountryChart" class="chart-area"></div> | |
<!-- Trade Flow Map --> | |
<div id="exportsCountryFlowMap" class="trade-flow-map" data-height="350" data-show-labels="true" style="display:none;margin-top:16px;"></div> | |
</div> | |
</div> | |
<div id="tab-content-imports-country" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Imports by Country</h2> | |
<p class="section-description">Analyze international import flows by country and year</p> | |
</div> | |
<form id="importsCountryForm"> | |
<div class="form-row"> | |
<div class="form-group col-md-4"> | |
<label for="importsCountryYear">Year</label> | |
<input type="number" id="importsCountryYear" name="importsCountryYear" value="2022" min="2000" max="2100" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="importsCountryCommodity">Commodity Code</label> | |
<input type="text" id="importsCountryCommodity" name="importsCountryCommodity" value="TOTAL" placeholder="e.g., TOTAL or HS code" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="importsCountryFlow">Flow Type</label> | |
<select id="importsCountryFlow" name="importsCountryFlow" class="select-field"> | |
<option value="M">Import</option> | |
<option value="X">Export</option> | |
<option value="">All</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-actions"> | |
<button type="submit" class="btn-primary">Show Trade Data</button> | |
<button id="importsCountryDownloadBtn" class="btn-secondary" style="display:none;">Download CSV</button> | |
</div> | |
</form> | |
<div id="importsCountryResults" class="results-section"></div> | |
</div> | |
<!-- Trade Flow Visualization Card --> | |
<div class="card" id="importsCountryChartCard" style="margin-top:24px;"> | |
<div class="section-heading"> | |
<h3>Imports Flow Visualization</h3> | |
</div> | |
<div class="visualization-tabs"> | |
<div class="chart-controls"> | |
<button class="chart-type-btn active" data-type="bar"> | |
<i class="fas fa-chart-bar"></i> Bar Chart | |
</button> | |
<button class="chart-type-btn" data-type="map"> | |
<i class="fas fa-globe"></i> Trade Flow Map | |
</button> | |
</div> | |
</div> | |
<div id="importsCountryChart" class="chart-area"></div> | |
<!-- Trade Flow Map --> | |
<div id="importsCountryFlowMap" class="trade-flow-map" data-height="350" data-show-labels="true" style="display:none;margin-top:16px;"></div> | |
</div> | |
</div> | |
<div id="tab-content-exports-product" class="tab-content" style="display:none;"> | |
<h3>Exports by Product</h3> | |
<form id="exportsProductForm" style="margin-bottom:1em;"> | |
<label for="exportsProductCountry">Country:</label> | |
<select id="exportsProductCountry" name="exportsProductCountry"></select> | |
<label for="exportsProductYear">Year:</label> | |
<input type="number" id="exportsProductYear" name="exportsProductYear" value="2022" min="2000" max="2100" style="width:90px;"> | |
<button type="submit">Show Table</button> | |
</form> | |
<button id="exportsProductDownloadBtn" style="display:none;margin-bottom:1em;">Download CSV</button> | |
<div id="exportsProductResults"></div> | |
<div id="exportsProductChart" style="margin-top:2em;"></div> | |
</div> | |
<div id="tab-content-imports-product" class="tab-content" style="display:none;"> | |
<h3>Imports by Product</h3> | |
<form id="importsProductForm" style="margin-bottom:1em;"> | |
<label for="importsProductCountry">Country:</label> | |
<select id="importsProductCountry" name="importsProductCountry"></select> | |
<label for="importsProductYear">Year:</label> | |
<input type="number" id="importsProductYear" name="importsProductYear" value="2022" min="2000" max="2100" style="width:90px;"> | |
<button type="submit">Show Table</button> | |
</form> | |
<button id="importsProductDownloadBtn" style="display:none;margin-bottom:1em;">Download CSV</button> | |
<div id="importsProductResults"></div> | |
<div id="importsProductChart" style="margin-top:2em;"></div> | |
</div> | |
<div id="tab-content-rankings" class="tab-content" style="display:none;"> | |
<h3>Ranking of Countries</h3> | |
<form id="rankingsForm" style="margin-bottom:1em;"> | |
<label for="rankingsYear">Year:</label> | |
<input type="number" id="rankingsYear" name="rankingsYear" value="2022" min="2000" max="2100" style="width:90px;"> | |
<label for="rankingsCommodity">Commodity Code (HS or TOTAL):</label> | |
<input type="text" id="rankingsCommodity" name="rankingsCommodity" value="TOTAL" style="width:110px;"> | |
<label for="rankingsFlow">Flow:</label> | |
<select id="rankingsFlow" name="rankingsFlow"> | |
<option value="X">Exporters</option> | |
<option value="M">Importers</option> | |
</select> | |
<button type="submit">Show Rankings</button> | |
</form> | |
<button id="rankingsDownloadBtn" style="display:none;margin-bottom:1em;">Download CSV</button> | |
<div id="rankingsResults"></div> | |
<div id="rankingsChart" style="margin-top:2em;"></div> | |
</div> | |
<div id="tab-content-bilateral" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Bilateral Trade Analysis</h2> | |
<p class="section-description">Analyze trade flows between two specific countries</p> | |
</div> | |
<form id="bilateralForm"> | |
<div class="form-row"> | |
<div class="form-group col-md-6"> | |
<label for="bilateralReporter">Reporter Country</label> | |
<select id="bilateralReporter" name="bilateralReporter" class="select-field"></select> | |
</div> | |
<div class="form-group col-md-6"> | |
<label for="bilateralPartner">Partner Country</label> | |
<select id="bilateralPartner" name="bilateralPartner" class="select-field"></select> | |
</div> | |
</div> | |
<div class="form-row"> | |
<div class="form-group col-md-6"> | |
<label for="bilateralYear">Year</label> | |
<input type="number" id="bilateralYear" name="bilateralYear" value="2022" min="2000" max="2100" class="input-field"> | |
</div> | |
<div class="form-group col-md-6"> | |
<label for="bilateralCommodity">Commodity Code</label> | |
<input type="text" id="bilateralCommodity" name="bilateralCommodity" value="TOTAL" placeholder="e.g., TOTAL or HS code" class="input-field"> | |
</div> | |
</div> | |
<div class="form-actions"> | |
<button type="submit" class="btn-primary">Show Bilateral Trade</button> | |
<button id="bilateralDownloadBtn" class="btn-secondary" style="display:none;">Download CSV</button> | |
</div> | |
</form> | |
<div id="bilateralResults" class="results-section"></div> | |
</div> | |
<!-- Bilateral Trade Flow Visualization Card --> | |
<div class="card" id="bilateralChartCard" style="margin-top:24px;"> | |
<div class="section-heading"> | |
<h3>Bilateral Trade Flow Visualization</h3> | |
</div> | |
<div class="visualization-tabs"> | |
<div class="chart-controls"> | |
<button class="chart-type-btn" data-type="bar"> | |
<i class="fas fa-chart-bar"></i> Bar Chart | |
</button> | |
<button class="chart-type-btn active" data-type="map"> | |
<i class="fas fa-globe"></i> Trade Flow Map | |
</button> | |
</div> | |
</div> | |
<div id="bilateralChart" class="chart-area"></div> | |
<!-- Trade Flow Map (Active by default for bilateral) --> | |
<div id="bilateralFlowMap" class="trade-flow-map" data-height="400" data-show-labels="true" data-demo="true"></div> | |
</div> | |
</div> | |
<div id="tab-content-data-download" class="tab-content" style="display:none;"> | |
<h3>Data Download</h3> | |
<form id="dataDownloadForm" style="margin-bottom:1em;"> | |
<label for="dataDownloadReporter">Reporter Country:</label> | |
<select id="dataDownloadReporter" name="dataDownloadReporter"> | |
<option value="">All</option> | |
</select> | |
<label for="dataDownloadPartner">Partner Country:</label> | |
<select id="dataDownloadPartner" name="dataDownloadPartner"> | |
<option value="">All</option> | |
</select> | |
<label for="dataDownloadYear">Year:</label> | |
<input type="number" id="dataDownloadYear" name="dataDownloadYear" min="2000" max="2100" style="width:90px;"> | |
<label for="dataDownloadCommodity">Commodity Code (HS or TOTAL):</label> | |
<input type="text" id="dataDownloadCommodity" name="dataDownloadCommodity" style="width:110px;"> | |
<label for="dataDownloadFlow">Flow:</label> | |
<select id="dataDownloadFlow" name="dataDownloadFlow"> | |
<option value="">All</option> | |
<option value="X">Export</option> | |
<option value="M">Import</option> | |
</select> | |
<button type="submit">Download CSV</button> | |
</form> | |
<div id="dataDownloadStatus"></div> | |
</div> | |
<div id="tab-content-prediction" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Trade Flow Prediction (ML)</h2> | |
</div> | |
<form id="predictionForm"> | |
<div class="form-row"> | |
<div class="form-group col-md-6"> | |
<label for="predictionReporter">Reporter Country</label> | |
<select id="predictionReporter" name="predictionReporter" class="select-field"></select> | |
</div> | |
<div class="form-group col-md-6"> | |
<label for="predictionPartner">Partner Country</label> | |
<select id="predictionPartner" name="predictionPartner" class="select-field"></select> | |
</div> | |
</div> | |
<div class="form-row"> | |
<div class="form-group col-md-4"> | |
<label for="predictionYear">Year to Predict</label> | |
<input type="number" id="predictionYear" name="predictionYear" value="2023" min="2000" max="2100" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="predictionCommodity">Commodity Code</label> | |
<input type="text" id="predictionCommodity" name="predictionCommodity" value="TOTAL" placeholder="e.g., TOTAL or HS code" class="input-field"> | |
</div> | |
<div class="form-group col-md-4"> | |
<label for="predictionModel">Model</label> | |
<select id="predictionModel" name="predictionModel" class="select-field"> | |
<option value="linear">Linear Regression</option> | |
<option value="xgboost">XGBoost</option> | |
<option value="lstm">LSTM</option> | |
</select> | |
</div> | |
</div> | |
<div class="form-actions"> | |
<button type="submit" class="btn-primary">Generate Prediction</button> | |
<button id="predictionDownloadBtn" class="btn-secondary" style="display:none;">Download CSV</button> | |
</div> | |
</form> | |
<div id="predictionResults" class="results-container"></div> | |
</div> | |
<div class="card" id="predictionChartCard" style="display:none;margin-top:24px;"> | |
<div class="section-heading"> | |
<h3>Prediction Visualization</h3> | |
</div> | |
<div id="predictionChart" class="chart-area"></div> | |
</div> | |
</div> | |
<!-- Data Cache Management Panel --> | |
<div id="tab-content-data-cache" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>Data Cache Management</h2> | |
<p class="section-description">Manage previously cached trade data to reduce API calls and work offline</p> | |
</div> | |
<div class="cache-control-header"> | |
<h3 class="panel-title">Cached Datasets</h3> | |
<div class="action-buttons"> | |
<button id="refreshCacheBtn" class="btn-secondary btn-icon"> | |
<i class="fas fa-sync-alt"></i> Refresh | |
</button> | |
<button id="clearAllCacheBtn" class="btn-danger btn-icon"> | |
<i class="fas fa-trash"></i> Clear All | |
</button> | |
</div> | |
</div> | |
<div id="cachedDataList" class="cached-data-container"> | |
<!-- Cache items will be populated here --> | |
<div class="loading-indicator"> | |
<i class="fas fa-spinner fa-spin"></i> | |
<span>Loading cached data...</span> | |
</div> | |
</div> | |
</div> | |
<div class="card" id="cacheVisualizationCard" style="margin-top:24px;"> | |
<div class="section-heading"> | |
<h3>Visualization Options</h3> | |
</div> | |
<div class="chart-control-buttons"> | |
<button class="chart-type-btn" data-type="bar"> | |
<i class="fas fa-chart-bar"></i> Bar Chart | |
</button> | |
<button class="chart-type-btn" data-type="pie"> | |
<i class="fas fa-chart-pie"></i> Pie Chart | |
</button> | |
<button class="chart-type-btn" data-type="line"> | |
<i class="fas fa-chart-line"></i> Line Chart | |
</button> | |
<button class="chart-type-btn" data-type="treemap"> | |
<i class="fas fa-th-large"></i> Treemap | |
</button> | |
<button class="chart-type-btn" data-type="map"> | |
<i class="fas fa-globe"></i> World Map | |
</button> | |
</div> | |
<div id="cacheVisualization" class="visualization-container"> | |
<!-- Visualizations will be rendered here --> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div id="tab-content-assistant" class="tab-content" style="display:none;"> | |
<div class="card"> | |
<div class="section-heading"> | |
<h2>AI Trade Assistant</h2> | |
<div class="model-badge"> | |
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face" class="hf-logo"> | |
<span>Powered by Google Gemma-2b</span> | |
</div> | |
</div> | |
<div class="chat-container"> | |
<div id="chat-messages" class="chat-messages"> | |
<!-- Welcome message --> | |
<div class="message message-assistant"> | |
<div class="message-content"> | |
<p>👋 Hello! I'm your Trade Data Assistant powered by Google Gemma-2b.</p> | |
<p>I can help you with:</p> | |
<ul> | |
<li>Understanding trade terminology and HS codes</li> | |
<li>Exploring interesting trade patterns</li> | |
<li>Finding specific trade data</li> | |
<li>Interpreting visualization results</li> | |
<li>Providing insights about international trade</li> | |
</ul> | |
<p>How can I assist you today?</p> | |
</div> | |
</div> | |
</div> | |
<div class="chat-input-container"> | |
<input type="text" id="chat-input" class="chat-input" placeholder="Ask me about trade data, HS codes, or how to use this application..."> | |
<button id="chat-send-btn" class="btn-primary">Send</button> | |
</div> | |
</div> | |
<div class="quick-questions-container"> | |
<h3 class="section-title">Try asking</h3> | |
<div class="quick-question-chips"> | |
<button class="quick-question-chip">What are HS codes?</button> | |
<button class="quick-question-chip">Explain imports vs exports</button> | |
<button class="quick-question-chip">What does HS code 8471 represent?</button> | |
<button class="quick-question-chip">How to interpret trade data?</button> | |
<button class="quick-question-chip">Recommend trade patterns to explore</button> | |
</div> | |
</div> | |
<div class="assistant-tools"> | |
<h3 class="section-title">Specialized Tools</h3> | |
<div class="tools-grid"> | |
<div class="tool-card"> | |
<div class="tool-header"> | |
<i class="fas fa-search"></i> | |
<h4>HS Code Lookup</h4> | |
</div> | |
<div class="tool-content"> | |
<div class="input-with-button"> | |
<input type="text" id="hs-code-input" placeholder="Enter HS code (e.g. 8471)"> | |
<button id="explain-hs-btn" class="btn-success">Explain</button> | |
</div> | |
</div> | |
</div> | |
<div class="tool-card"> | |
<div class="tool-header"> | |
<i class="fas fa-lightbulb"></i> | |
<h4>Trade Insights</h4> | |
</div> | |
<div class="tool-content"> | |
<div class="form-group"> | |
<select id="recommendation-country"> | |
<option value="">Select a country (optional)</option> | |
<!-- Will be populated from COUNTRY_CODES --> | |
</select> | |
</div> | |
<div class="input-with-button"> | |
<input type="text" id="recommendation-product" placeholder="Product (optional)"> | |
<button id="get-recommendation-btn" class="btn-info">Get Insights</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Specialized Assistance Panel --> | |
<div id="tab-content-specialized" class="tab-content" style="display:none;"> | |
<div class="container"> | |
<h4>Specialized Assistance: <span style="font-size:14px;color:#666;font-weight:normal;display:inline-flex;align-items:center;"> | |
<img src="https://huggingface.co/front/assets/huggingface_logo.svg" alt="Hugging Face" style="height:16px;margin:0 4px;"> Powered by Hugging Face | |
</span></h4> | |
<div style="display:flex;gap:10px;flex-wrap:wrap;"> | |
<div style="flex:1;min-width:300px;"> | |
<h5>HS Code Lookup</h5> | |
<div class="input-group"> | |
<input type="text" id="hs-code-input" placeholder="Enter HS code (e.g. 8471)" class="chat-input" style="width:70%" /> | |
<button id="explain-hs-btn" class="chat-send-btn" style="width:25%">Explain</button> | |
</div> | |
</div> | |
<div style="flex:1;min-width:300px;"> | |
<h5>Trade Recommendation</h5> | |
<div class="input-group" style="margin-bottom:10px;"> | |
<select id="recommendation-country" class="chat-input" style="width:100%"> | |
<option value="">Select a country (optional)</option> | |
<!-- Will be populated from COUNTRY_CODES --> | |
</select> | |
</div> | |
<div class="input-group"> | |
<input type="text" id="recommendation-product" placeholder="Product (optional)" class="chat-input" style="width:70%" /> | |
<button id="get-recommendation-btn" class="chat-send-btn" style="width:25%">Get Insights</button> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Animation styles --> | |
<style> | |
@keyframes spin { | |
0% { transform: rotate(0deg); } | |
100% { transform: rotate(360deg); } | |
} | |
</style> | |
<!-- Direct tab navigation script --> | |
<script> | |
document.addEventListener('DOMContentLoaded', function() { | |
// Handle iframe loading | |
const iframe = document.getElementById('hf-assistant-iframe'); | |
const loadingIndicator = document.getElementById('assistant-loading'); | |
if (iframe && loadingIndicator) { | |
iframe.onload = function() { | |
loadingIndicator.style.display = 'none'; | |
}; | |
// Set a timeout in case the iframe fails to trigger onload | |
setTimeout(function() { | |
loadingIndicator.style.display = 'none'; | |
}, 8000); // Hide after 8 seconds regardless | |
} | |
// Direct tab navigation logic | |
const tabs = document.querySelectorAll('#main-tabs .tab'); | |
const tabContents = document.querySelectorAll('.tab-content'); | |
tabs.forEach(tab => { | |
tab.addEventListener('click', function() { | |
const tabName = tab.getAttribute('data-tab'); | |
// Check if this is the AI Assistant tab | |
if (tabName === 'assistant') { | |
// Option to redirect directly to Hugging Face Space | |
// Uncomment the next line if you want direct redirect | |
// window.open('https://huggingface.co/spaces/jomasego/ai-trade-assistant', '_blank'); | |
} | |
// Hide any visible spinners | |
document.querySelectorAll('.spinner').forEach(spinner => { | |
spinner.style.display = 'none'; | |
}); | |
// Update active tab | |
tabs.forEach(t => { | |
t.classList.remove('active'); | |
t.setAttribute('aria-selected', 'false'); | |
}); | |
tab.classList.add('active'); | |
tab.setAttribute('aria-selected', 'true'); | |
// Show corresponding tab content | |
tabContents.forEach(panel => { | |
if (panel.id === 'tab-content-' + tabName) { | |
panel.style.display = 'block'; | |
} else { | |
panel.style.display = 'none'; | |
} | |
}); | |
// Focus the active tab | |
tab.focus(); | |
}); | |
// Keyboard navigation | |
tab.addEventListener('keydown', function(e) { | |
if (e.key === 'ArrowRight') { | |
e.preventDefault(); | |
tabs[(idx + 1) % tabs.length].focus(); | |
} else if (e.key === 'ArrowLeft') { | |
e.preventDefault(); | |
tabs[(idx - 1 + tabs.length) % tabs.length].focus(); | |
} else if (e.key === 'Enter' || e.key === ' ') { | |
e.preventDefault(); | |
tab.click(); | |
} | |
}); | |
}); | |
// Initial load - make sure the active tab content is visible | |
const activeTab = document.querySelector('#main-tabs .tab.active'); | |
if (activeTab) { | |
const tabName = activeTab.getAttribute('data-tab'); | |
const activePanel = document.getElementById('tab-content-' + tabName); | |
if (activePanel) { | |
activePanel.style.display = 'block'; | |
} | |
} | |
}); | |
</script> | |
</body> | |
</html> | |