Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>Crypto Treasury Management Research Agent</title> | |
<script src="https://cdn.tailwindcss.com"></script> | |
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
<style> | |
.gradient-bg { | |
background: linear-gradient(135deg, #1e3a8a 0%, #0ea5e9 100%); | |
} | |
.card-hover:hover { | |
transform: translateY(-5px); | |
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); | |
} | |
.fade-in { | |
animation: fadeIn 0.5s ease-in-out; | |
} | |
@keyframes fadeIn { | |
from { opacity: 0; transform: translateY(10px); } | |
to { opacity: 1; transform: translateY(0); } | |
} | |
.typewriter { | |
overflow: hidden; | |
border-right: .15em solid #0ea5e9; | |
white-space: pre-wrap; | |
margin: 0 auto; | |
letter-spacing: .15em; | |
animation: | |
typing 3.5s steps(40, end), | |
blink-caret .75s step-end infinite; | |
} | |
@keyframes typing { | |
from { width: 0 } | |
to { width: 100% } | |
} | |
@keyframes blink-caret { | |
from, to { border-color: transparent } | |
50% { border-color: #0ea5e9; } | |
} | |
.topic-badge { | |
display: inline-flex; | |
align-items: center; | |
padding: 0.25rem 0.75rem; | |
border-radius: 9999px; | |
font-size: 0.875rem; | |
font-weight: 500; | |
} | |
.topic-badge i { | |
margin-right: 0.25rem; | |
} | |
.market-data-item { | |
border-left: 4px solid #0ea5e9; | |
padding-left: 1rem; | |
margin-bottom: 1rem; | |
} | |
</style> | |
</head> | |
<body class="bg-gray-50 min-h-screen"> | |
<div class="gradient-bg text-white py-12 px-4 sm:px-6 lg:px-8"> | |
<div class="max-w-7xl mx-auto"> | |
<div class="text-center"> | |
<h1 class="text-4xl font-extrabold tracking-tight sm:text-5xl md:text-6xl"> | |
<span class="block">Crypto Treasury Management</span> | |
<span class="block text-blue-200">Research Agent</span> | |
</h1> | |
<p class="mt-3 max-w-md mx-auto text-lg text-blue-100 sm:text-xl md:mt-5 md:max-w-3xl"> | |
Advanced research tool for cryptocurrency treasury management with market data integration | |
</p> | |
</div> | |
</div> | |
</div> | |
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-12"> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-8"> | |
<!-- Research Topics Section --> | |
<div class="bg-white rounded-xl shadow-md overflow-hidden p-6"> | |
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center"> | |
<i class="fas fa-search mr-3 text-blue-500"></i> | |
Research Topics | |
</h2> | |
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4"> | |
<div class="bg-blue-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('definition')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-blue-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-book text-blue-600"></i> | |
</div> | |
<h3 class="font-semibold text-blue-800">Definition & Purpose</h3> | |
</div> | |
<p class="text-sm text-gray-600">Understand what a crypto treasury is and its core purpose</p> | |
</div> | |
<div class="bg-green-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('strategies')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-green-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-chess-knight text-green-600"></i> | |
</div> | |
<h3 class="font-semibold text-green-800">Management Strategies</h3> | |
</div> | |
<p class="text-sm text-gray-600">Explore common strategies for managing crypto holdings</p> | |
</div> | |
<div class="bg-purple-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('security')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-purple-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-shield-alt text-purple-600"></i> | |
</div> | |
<h3 class="font-semibold text-purple-800">Security & Custody</h3> | |
</div> | |
<p class="text-sm text-gray-600">Learn about protecting organizational crypto assets</p> | |
</div> | |
<div class="bg-yellow-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('accounting')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-yellow-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-calculator text-yellow-600"></i> | |
</div> | |
<h3 class="font-semibold text-yellow-800">Accounting & Reporting</h3> | |
</div> | |
<p class="text-sm text-gray-600">Understand accounting treatment and reporting requirements</p> | |
</div> | |
<div class="bg-red-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('regulatory')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-red-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-balance-scale text-red-600"></i> | |
</div> | |
<h3 class="font-semibold text-red-800">Regulatory Landscape</h3> | |
</div> | |
<p class="text-sm text-gray-600">Explore the current regulatory environment</p> | |
</div> | |
<div class="bg-indigo-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('risk')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-indigo-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-exclamation-triangle text-indigo-600"></i> | |
</div> | |
<h3 class="font-semibold text-indigo-800">Risk Management</h3> | |
</div> | |
<p class="text-sm text-gray-600">Identify key risks and mitigation strategies</p> | |
</div> | |
<div class="bg-pink-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('operational')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-pink-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-cogs text-pink-600"></i> | |
</div> | |
<h3 class="font-semibold text-pink-800">Operational Aspects</h3> | |
</div> | |
<p class="text-sm text-gray-600">Practical aspects of managing a crypto treasury</p> | |
</div> | |
<div class="bg-teal-50 rounded-lg p-4 transition-all duration-300 card-hover cursor-pointer" onclick="conductResearch('trends')"> | |
<div class="flex items-center mb-2"> | |
<div class="bg-teal-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-chart-line text-teal-600"></i> | |
</div> | |
<h3 class="font-semibold text-teal-800">Market Trends & Cases</h3> | |
</div> | |
<p class="text-sm text-gray-600">Current trends and company case studies</p> | |
</div> | |
</div> | |
<!-- Additional Input Fields --> | |
<div class="mt-6"> | |
<h3 class="text-lg font-semibold text-gray-800 mb-3">Advanced Research Parameters</h3> | |
<div class="space-y-4"> | |
<div> | |
<label for="timeframe" class="block text-sm font-medium text-gray-700 mb-1">Timeframe</label> | |
<select id="timeframe" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
<option value="current">Current (last 6 months)</option> | |
<option value="1y">1 Year</option> | |
<option value="3y">3 Years</option> | |
<option value="all">All Time</option> | |
</select> | |
</div> | |
<div> | |
<label for="jurisdiction" class="block text-sm font-medium text-gray-700 mb-1">Jurisdiction</label> | |
<select id="jurisdiction" class="w-full px-4 py-2 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
<option value="global">Global</option> | |
<option value="us">United States</option> | |
<option value="eu">European Union</option> | |
<option value="uk">United Kingdom</option> | |
<option value="asia">Asia</option> | |
<option value="other">Other</option> | |
</select> | |
</div> | |
<div> | |
<label for="assets" class="block text-sm font-medium text-gray-700 mb-1">Assets to Include</label> | |
<div class="flex flex-wrap gap-2"> | |
<div class="flex items-center"> | |
<input type="checkbox" id="btc" name="assets" value="btc" checked class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
<label for="btc" class="ml-2 text-sm text-gray-700">Bitcoin</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="eth" name="assets" value="eth" checked class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
<label for="eth" class="ml-2 text-sm text-gray-700">Ethereum</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="stablecoins" name="assets" value="stablecoins" checked class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
<label for="stablecoins" class="ml-2 text-sm text-gray-700">Stablecoins</label> | |
</div> | |
<div class="flex items-center"> | |
<input type="checkbox" id="other" name="assets" value="other" class="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"> | |
<label for="other" class="ml-2 text-sm text-gray-700">Other</label> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Research Results Section --> | |
<div class="bg-white rounded-xl shadow-md overflow-hidden"> | |
<div class="p-6"> | |
<div class="flex justify-between items-center mb-6"> | |
<h2 class="text-2xl font-bold text-gray-800 flex items-center"> | |
<i class="fas fa-file-alt mr-3 text-blue-500"></i> | |
Research Results | |
</h2> | |
<div id="currentTopicBadge" class="hidden"> | |
<span class="topic-badge bg-blue-100 text-blue-800"> | |
<i class="fas fa-tag"></i> | |
<span id="currentTopicText"></span> | |
</span> | |
</div> | |
</div> | |
<div class="mb-6"> | |
<div class="relative"> | |
<input type="text" id="customQuery" placeholder="Ask a specific research question..." | |
class="w-full px-4 py-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-blue-500 focus:border-blue-500"> | |
<button onclick="conductCustomResearch()" | |
class="absolute right-2 top-1/2 transform -translate-y-1/2 bg-blue-500 hover:bg-blue-600 text-white px-4 py-1 rounded-lg transition-colors"> | |
<i class="fas fa-paper-plane"></i> | |
</button> | |
</div> | |
</div> | |
<div id="researchOutput" class="bg-gray-50 rounded-lg p-4 min-h-64"> | |
<div class="text-center py-12 text-gray-400" id="defaultOutput"> | |
<i class="fas fa-search fa-3x mb-4"></i> | |
<p class="text-lg">Select a research topic or ask a question to begin</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Market Data Section --> | |
<div class="mt-8 bg-white rounded-xl shadow-md overflow-hidden"> | |
<div class="p-6"> | |
<h2 class="text-2xl font-bold text-gray-800 mb-6 flex items-center"> | |
<i class="fas fa-chart-bar mr-3 text-blue-500"></i> | |
Market Data Integration | |
</h2> | |
<div class="grid grid-cols-1 md:grid-cols-2 gap-6"> | |
<div> | |
<h3 class="text-lg font-semibold text-gray-800 mb-4 flex items-center"> | |
<i class="fas fa-coins mr-2 text-yellow-500"></i> | |
Cryptocurrency Rates | |
</h3> | |
<div id="cryptoRates" class="space-y-3"> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading BTC/USD...</p> | |
</div> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading BCH/USD...</p> | |
</div> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading XLM/USD...</p> | |
</div> | |
</div> | |
<button onclick="fetchCryptoRates()" class="mt-4 bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center transition-colors"> | |
<i class="fas fa-sync-alt mr-2"></i> Refresh Rates | |
</button> | |
</div> | |
<div> | |
<h3 class="text-lg font-semibold text-gray-800 mb-4 flex items-center"> | |
<i class="fas fa-globe mr-2 text-green-500"></i> | |
Forex & Commodities | |
</h3> | |
<div id="forexCommodities" class="space-y-3"> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading USD/CNY...</p> | |
</div> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading Cotton Forecast...</p> | |
</div> | |
<div class="market-data-item"> | |
<p class="text-sm text-gray-500">Loading Baltic Dry Index...</p> | |
</div> | |
</div> | |
<button onclick="fetchForexCommodities()" class="mt-4 bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center transition-colors"> | |
<i class="fas fa-sync-alt mr-2"></i> Refresh Data | |
</button> | |
</div> | |
</div> | |
<div class="mt-6 bg-blue-50 rounded-lg p-4"> | |
<div class="flex items-start"> | |
<div class="flex-shrink-0"> | |
<i class="fas fa-info-circle text-blue-500 mt-1"></i> | |
</div> | |
<div class="ml-3"> | |
<h3 class="text-sm font-medium text-blue-800">Data Source Information</h3> | |
<div class="mt-2 text-sm text-blue-700"> | |
<p>Market data is powered by TradingEconomics API. This integration provides real-time cryptocurrency rates, forex data, and commodity forecasts that may impact treasury management decisions.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<!-- Agent Status --> | |
<div class="mt-8 bg-white rounded-xl shadow-md overflow-hidden"> | |
<div class="p-6"> | |
<h2 class="text-2xl font-bold text-gray-800 mb-4 flex items-center"> | |
<i class="fas fa-robot mr-3 text-blue-500"></i> | |
Agent Status | |
</h2> | |
<div class="flex flex-col sm:flex-row items-start sm:items-center justify-between"> | |
<div class="flex items-center mb-4 sm:mb-0"> | |
<div class="relative"> | |
<div class="h-3 w-3 rounded-full bg-green-500 animate-pulse absolute -left-5 top-1/2 transform -translate-y-1/2"></div> | |
</div> | |
<span class="ml-2 text-gray-700">Research Agent: <span class="font-semibold">Active</span></span> | |
</div> | |
<button onclick="initializeAgent()" class="bg-blue-500 hover:bg-blue-600 text-white px-4 py-2 rounded-lg flex items-center transition-colors"> | |
<i class="fas fa-sync-alt mr-2"></i> Reinitialize Agent | |
</button> | |
</div> | |
<div class="mt-4 bg-blue-50 rounded-lg p-4"> | |
<div class="flex items-start"> | |
<div class="flex-shrink-0"> | |
<i class="fas fa-info-circle text-blue-500 mt-1"></i> | |
</div> | |
<div class="ml-3"> | |
<h3 class="text-sm font-medium text-blue-800">About this Agent</h3> | |
<div class="mt-2 text-sm text-blue-700"> | |
<p>This agent connects to a backend API to provide comprehensive cryptocurrency treasury management research. It can analyze data based on timeframe, jurisdiction, and asset types. Now with integrated market data from TradingEconomics.</p> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Backend API URL | |
const BACKEND_API_URL = 'https://privateuserh-ctmnext.hf.space/api/process'; | |
const TRADING_ECONOMICS_API_URL = 'https://api.tradingeconomics.com'; | |
const TE_API_KEY = 'ae20da0a312d47a:ftdfzvk16ivjv7x'; | |
// Initialize the agent | |
class CryptoTreasuryResearchAgent { | |
constructor() { | |
console.log("Crypto Treasury Research Agent initialized."); | |
this.initialized = true; | |
this.currentTopic = null; | |
} | |
async callBackendAPI(payload) { | |
try { | |
const response = await fetch(BACKEND_API_URL, { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify(payload) | |
}); | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
return await response.json(); | |
} catch (error) { | |
console.error('Error calling backend API:', error); | |
return { error: true, message: 'Failed to connect to research service' }; | |
} | |
} | |
async callTradingEconomicsAPI(endpoint, params = {}) { | |
try { | |
const queryParams = new URLSearchParams({ | |
...params, | |
c: TE_API_KEY | |
}); | |
const response = await fetch(`${TRADING_ECONOMICS_API_URL}/${endpoint}?${queryParams}`, { | |
method: 'GET', | |
headers: { | |
'Accept': 'application/json' | |
} | |
}); | |
if (!response.ok) { | |
throw new Error(`HTTP error! status: ${response.status}`); | |
} | |
return await response.json(); | |
} catch (error) { | |
console.error('Error calling TradingEconomics API:', error); | |
return { error: true, message: 'Failed to fetch market data' }; | |
} | |
} | |
async conduct_comprehensive_research(topic, customQuery = null) { | |
this.currentTopic = topic; | |
const timeframe = document.getElementById('timeframe').value; | |
const jurisdiction = document.getElementById('jurisdiction').value; | |
// Get selected assets | |
const assetCheckboxes = document.querySelectorAll('input[name="assets"]:checked'); | |
const assets = Array.from(assetCheckboxes).map(cb => cb.value); | |
const payload = { | |
topic: topic, | |
query: customQuery || topic, | |
timeframe: timeframe, | |
jurisdiction: jurisdiction, | |
assets: assets | |
}; | |
console.log("Sending research request:", payload); | |
const result = await this.callBackendAPI(payload); | |
if (result.error) { | |
return result.message || 'An error occurred during research'; | |
} | |
return result.data || 'Research completed but no data returned'; | |
} | |
async getCryptoRates() { | |
const symbols = ['BTCUSD:CUR', 'BCHUSD:CUR', 'XLMUSD:CUR']; | |
const result = await this.callTradingEconomicsAPI('markets/symbol', { symbols: symbols.join(',') }); | |
if (result.error) { | |
return { error: true, message: result.message }; | |
} | |
return result; | |
} | |
async getForexCommodities() { | |
const forexResult = await this.callTradingEconomicsAPI('markets/symbol', { symbols: 'USDCNY:CUR' }); | |
const cottonResult = await this.callTradingEconomicsAPI('markets/forecast', { symbol: 'COTT:COM' }); | |
const balticResult = await this.callTradingEconomicsAPI('markets/forecast', { symbol: 'BALT:COM' }); | |
return { | |
forex: forexResult.error ? { error: true, message: forexResult.message } : forexResult[0], | |
cotton: cottonResult.error ? { error: true, message: cottonResult.message } : cottonResult[0], | |
baltic: balticResult.error ? { error: true, message: balticResult.message } : balticResult[0] | |
}; | |
} | |
} | |
// Global agent instance | |
let researchAgent = new CryptoTreasuryResearchAgent(); | |
// Initialize or reinitialize the agent | |
function initializeAgent() { | |
researchAgent = new CryptoTreasuryResearchAgent(); | |
showNotification("Agent reinitialized successfully", "success"); | |
// Refresh market data on reinitialization | |
fetchCryptoRates(); | |
fetchForexCommodities(); | |
} | |
// Fetch cryptocurrency rates | |
async function fetchCryptoRates() { | |
const cryptoRatesElement = document.getElementById('cryptoRates'); | |
cryptoRatesElement.innerHTML = ` | |
<div class="flex items-center justify-center py-4"> | |
<div class="animate-spin rounded-full h-6 w-6 border-t-2 border-b-2 border-blue-500 mr-2"></div> | |
<span class="text-gray-600">Loading cryptocurrency rates...</span> | |
</div> | |
`; | |
try { | |
const result = await researchAgent.getCryptoRates(); | |
if (result.error) { | |
cryptoRatesElement.innerHTML = ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error: ${result.message}</p> | |
</div> | |
`; | |
return; | |
} | |
let html = ''; | |
result.forEach(item => { | |
const symbol = item.symbol.replace(':CUR', ''); | |
const changeClass = item.changepct >= 0 ? 'text-green-600' : 'text-red-600'; | |
const changeIcon = item.changepct >= 0 ? 'fa-arrow-up' : 'fa-arrow-down'; | |
html += ` | |
<div class="market-data-item"> | |
<div class="flex justify-between items-center"> | |
<span class="font-medium">${symbol}</span> | |
<span class="text-gray-700">${item.price.toFixed(2)}</span> | |
</div> | |
<div class="flex justify-between text-xs mt-1"> | |
<span class="text-gray-500">${new Date(item.lastUpdate).toLocaleString()}</span> | |
<span class="${changeClass}"> | |
<i class="fas ${changeIcon} mr-1"></i> | |
${Math.abs(item.changepct)}% | |
</span> | |
</div> | |
</div> | |
`; | |
}); | |
cryptoRatesElement.innerHTML = html; | |
showNotification("Cryptocurrency rates updated", "success"); | |
} catch (error) { | |
cryptoRatesElement.innerHTML = ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error fetching cryptocurrency rates: ${error.message}</p> | |
</div> | |
`; | |
showNotification("Failed to fetch cryptocurrency rates", "error"); | |
} | |
} | |
// Fetch forex and commodities data | |
async function fetchForexCommodities() { | |
const forexCommoditiesElement = document.getElementById('forexCommodities'); | |
forexCommoditiesElement.innerHTML = ` | |
<div class="flex items-center justify-center py-4"> | |
<div class="animate-spin rounded-full h-6 w-6 border-t-2 border-b-2 border-blue-500 mr-2"></div> | |
<span class="text-gray-600">Loading forex & commodities data...</span> | |
</div> | |
`; | |
try { | |
const { forex, cotton, baltic } = await researchAgent.getForexCommodities(); | |
let html = ''; | |
// Forex data | |
if (forex.error) { | |
html += ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error loading USD/CNY: ${forex.message}</p> | |
</div> | |
`; | |
} else { | |
const changeClass = forex.changepct >= 0 ? 'text-green-600' : 'text-red-600'; | |
const changeIcon = forex.changepct >= 0 ? 'fa-arrow-up' : 'fa-arrow-down'; | |
html += ` | |
<div class="market-data-item"> | |
<div class="flex justify-between items-center"> | |
<span class="font-medium">USD/CNY</span> | |
<span class="text-gray-700">${forex.price.toFixed(4)}</span> | |
</div> | |
<div class="flex justify-between text-xs mt-1"> | |
<span class="text-gray-500">${new Date(forex.lastUpdate).toLocaleString()}</span> | |
<span class="${changeClass}"> | |
<i class="fas ${changeIcon} mr-1"></i> | |
${Math.abs(forex.changepct)}% | |
</span> | |
</div> | |
</div> | |
`; | |
} | |
// Cotton forecast | |
if (cotton.error) { | |
html += ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error loading Cotton forecast: ${cotton.message}</p> | |
</div> | |
`; | |
} else { | |
html += ` | |
<div class="market-data-item"> | |
<div class="flex justify-between items-center"> | |
<span class="font-medium">Cotton Forecast</span> | |
<span class="text-gray-700">${cotton.forecast.toFixed(2)}</span> | |
</div> | |
<div class="text-xs text-gray-500 mt-1"> | |
${new Date(cotton.lastUpdate).toLocaleDateString()} | |
</div> | |
</div> | |
`; | |
} | |
// Baltic Dry Index | |
if (baltic.error) { | |
html += ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error loading Baltic Dry Index: ${baltic.message}</p> | |
</div> | |
`; | |
} else { | |
html += ` | |
<div class="market-data-item"> | |
<div class="flex justify-between items-center"> | |
<span class="font-medium">Baltic Dry Index</span> | |
<span class="text-gray-700">${baltic.forecast.toFixed(2)}</span> | |
</div> | |
<div class="text-xs text-gray-500 mt-1"> | |
${new Date(baltic.lastUpdate).toLocaleDateString()} | |
</div> | |
</div> | |
`; | |
} | |
forexCommoditiesElement.innerHTML = html; | |
showNotification("Forex & commodities data updated", "success"); | |
} catch (error) { | |
forexCommoditiesElement.innerHTML = ` | |
<div class="market-data-item"> | |
<p class="text-sm text-red-500">Error fetching forex & commodities data: ${error.message}</p> | |
</div> | |
`; | |
showNotification("Failed to fetch forex & commodities data", "error"); | |
} | |
} | |
// Update the current topic display | |
function updateCurrentTopicDisplay(topic) { | |
const topicBadge = document.getElementById('currentTopicBadge'); | |
const topicText = document.getElementById('currentTopicText'); | |
if (topic === 'custom') { | |
const query = document.getElementById('customQuery').value.trim(); | |
topicText.textContent = `Custom: "${query}"`; | |
} else { | |
topicText.textContent = getTopicName(topic); | |
} | |
topicBadge.classList.remove('hidden'); | |
} | |
// Conduct research based on topic | |
async function conductResearch(topic) { | |
const outputElement = document.getElementById('researchOutput'); | |
const defaultOutput = document.getElementById('defaultOutput'); | |
// Hide default message | |
if (defaultOutput) defaultOutput.style.display = 'none'; | |
// Update current topic display | |
updateCurrentTopicDisplay(topic); | |
// Show loading state | |
outputElement.innerHTML = ` | |
<div class="flex flex-col items-center justify-center py-12"> | |
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mb-4"></div> | |
<p class="text-gray-600">Researching ${getTopicName(topic)}...</p> | |
</div> | |
`; | |
try { | |
const result = await researchAgent.conduct_comprehensive_research(topic); | |
outputElement.innerHTML = ` | |
<div class="fade-in"> | |
<div class="flex items-center mb-4"> | |
<div class="bg-blue-100 p-2 rounded-full mr-3"> | |
<i class="fas ${getTopicIcon(topic)} text-blue-600"></i> | |
</div> | |
<h3 class="text-lg font-semibold text-gray-800">${getTopicName(topic)}</h3> | |
</div> | |
<div class="bg-white p-4 rounded-lg border border-gray-200"> | |
<p class="text-gray-700">${result}</p> | |
</div> | |
<div class="mt-4 text-sm text-gray-500 flex items-center"> | |
<i class="fas fa-clock mr-2"></i> | |
Research completed at ${new Date().toLocaleTimeString()} | |
</div> | |
<div class="mt-3 text-xs text-gray-400"> | |
<p>Parameters: ${document.getElementById('timeframe').value} timeframe, | |
${document.getElementById('jurisdiction').value} jurisdiction</p> | |
</div> | |
</div> | |
`; | |
showNotification(`Research on ${getTopicName(topic)} completed`, "success"); | |
} catch (error) { | |
outputElement.innerHTML = ` | |
<div class="fade-in"> | |
<div class="flex items-center mb-4"> | |
<div class="bg-red-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-exclamation-triangle text-red-600"></i> | |
</div> | |
<h3 class="text-lg font-semibold text-gray-800">Research Error</h3> | |
</div> | |
<div class="bg-white p-4 rounded-lg border border-gray-200"> | |
<p class="text-gray-700">Failed to complete research: ${error.message}</p> | |
</div> | |
</div> | |
`; | |
showNotification("Research failed", "error"); | |
} | |
} | |
// Conduct custom research from input | |
async function conductCustomResearch() { | |
const query = document.getElementById('customQuery').value.trim(); | |
if (!query) { | |
showNotification("Please enter a research question", "error"); | |
return; | |
} | |
const outputElement = document.getElementById('researchOutput'); | |
const defaultOutput = document.getElementById('defaultOutput'); | |
// Hide default message | |
if (defaultOutput) defaultOutput.style.display = 'none'; | |
// Update current topic display | |
updateCurrentTopicDisplay('custom'); | |
// Show loading state | |
outputElement.innerHTML = ` | |
<div class="flex flex-col items-center justify-center py-12"> | |
<div class="animate-spin rounded-full h-12 w-12 border-t-2 border-b-2 border-blue-500 mb-4"></div> | |
<p class="text-gray-600">Processing your query: "${query}"</p> | |
</div> | |
`; | |
try { | |
const result = await researchAgent.conduct_comprehensive_research('custom', query); | |
outputElement.innerHTML = ` | |
<div class="fade-in"> | |
<div class="flex items-center mb-4"> | |
<div class="bg-blue-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-search text-blue-600"></i> | |
</div> | |
<h3 class="text-lg font-semibold text-gray-800">Results for: "${query}"</h3> | |
</div> | |
<div class="bg-white p-4 rounded-lg border border-gray-200"> | |
<p class="text-gray-700">${result}</p> | |
</div> | |
<div class="mt-4 text-sm text-gray-500 flex items-center"> | |
<i class="fas fa-clock mr-2"></i> | |
Research completed at ${new Date().toLocaleTimeString()} | |
</div> | |
<div class="mt-3 text-xs text-gray-400"> | |
<p>Parameters: ${document.getElementById('timeframe').value} timeframe, | |
${document.getElementById('jurisdiction').value} jurisdiction</p> | |
</div> | |
</div> | |
`; | |
showNotification(`Research on your query completed`, "success"); | |
} catch (error) { | |
outputElement.innerHTML = ` | |
<div class="fade-in"> | |
<div class="flex items-center mb-4"> | |
<div class="bg-red-100 p-2 rounded-full mr-3"> | |
<i class="fas fa-exclamation-triangle text-red-600"></i> | |
</div> | |
<h3 class="text-lg font-semibold text-gray-800">Research Error</h3> | |
</div> | |
<div class="bg-white p-4 rounded-lg border border-gray-200"> | |
<p class="text-gray-700">Failed to complete research: ${error.message}</p> | |
</div> | |
</div> | |
`; | |
showNotification("Research failed", "error"); | |
} | |
} | |
// Helper function to get topic name | |
function getTopicName(topic) { | |
const topicMap = { | |
'definition': 'Definition & Purpose', | |
'strategies': 'Management Strategies', | |
'security': 'Security & Custody', | |
'accounting': 'Accounting & Reporting', | |
'regulatory': 'Regulatory Landscape', | |
'risk': 'Risk Management', | |
'operational': 'Operational Considerations', | |
'trends': 'Market Trends & Case Studies', | |
'custom': 'Custom Research' | |
}; | |
return topicMap[topic] || 'Research Results'; | |
} | |
// Helper function to get topic icon | |
function getTopicIcon(topic) { | |
const iconMap = { | |
'definition': 'fa-book', | |
'strategies': 'fa-chess-knight', | |
'security': 'fa-shield-alt', | |
'accounting': 'fa-calculator', | |
'regulatory': 'fa-balance-scale', | |
'risk': 'fa-exclamation-triangle', | |
'operational': 'fa-cogs', | |
'trends': 'fa-chart-line', | |
'custom': 'fa-search' | |
}; | |
return iconMap[topic] || 'fa-file-alt'; | |
} | |
// Show notification | |
function showNotification(message, type) { | |
const notification = document.createElement('div'); | |
notification.className = `fixed bottom-4 right-4 px-6 py-3 rounded-lg shadow-lg text-white flex items-center ${ | |
type === 'success' ? 'bg-green-500' : 'bg-red-500' | |
}`; | |
notification.innerHTML = ` | |
<i class="fas ${type === 'success' ? 'fa-check-circle' : 'fa-exclamation-circle'} mr-2"></i> | |
${message} | |
`; | |
document.body.appendChild(notification); | |
setTimeout(() => { | |
notification.classList.add('opacity-0', 'transition-opacity', 'duration-500'); | |
setTimeout(() => notification.remove(), 500); | |
}, 3000); | |
} | |
// Initialize on load | |
document.addEventListener('DOMContentLoaded', () => { | |
initializeAgent(); | |
}); | |
</script> | |
<script> | |
const workerUrl = "https://ctmresearchagent.aiagents.workers.dev/"; // Replace with your Cloudflare Worker URL | |
async function handleSubmit(event) { | |
event.preventDefault(); | |
const query = document.getElementById("researchQuery").value; | |
const result = document.getElementById("resultDisplay").innerText; // Assuming result is displayed here | |
if (query && result) { | |
await fetch(`${workerUrl}/api/research`, { | |
method: "POST", | |
headers: { "Content-Type": "application/json" }, | |
body: JSON.stringify({ query, result }), | |
}); | |
} | |
} | |
async function loadResearchLogs() { | |
const response = await fetch(`${workerUrl}/api/research`); | |
const logs = await response.json(); | |
const logsContainer = document.getElementById("past-research-container"); // Add a container for logs in your HTML | |
logsContainer.innerHTML = logs | |
.map( | |
(log) => ` | |
<div> | |
<p><b>Query:</b> ${log.query}</p> | |
<p><b>Result:</b> ${log.result}</p> | |
<p><small>${new Date(log.timestamp).toLocaleString()}</small></p> | |
</div> | |
<hr> | |
` | |
) | |
.join(""); | |
} | |
document.getElementById("submitButton").addEventListener("click", handleSubmit); | |
window.addEventListener("load", loadResearchLogs); | |
</script> | |
<div id="past-research-container"></div> | |
<p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - 🧬 <a href="https://enzostvs-deepsite.hf.space?remix=privateuserh/ctm-vbeta1-03" style="color: #fff;text-decoration: underline;" target="_blank" >Remix</a></p></body> | |
</html> |