Spaces:
Running
Running
<html lang="en"> | |
<head> | |
<meta charset="UTF-8"> | |
<meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
<title>AI-Powered Daily Horoscopes</title> | |
<link href="https://cdn.replit.com/agent/bootstrap-agent-dark-theme.min.css" rel="stylesheet"> | |
<style> | |
.horoscope-card { | |
background: var(--bs-dark); | |
border: 1px solid var(--bs-secondary); | |
border-radius: 8px; | |
padding: 1.5rem; | |
margin-bottom: 1rem; | |
} | |
.sign-badge { | |
background: var(--bs-primary); | |
color: white; | |
padding: 0.25rem 0.75rem; | |
border-radius: 15px; | |
font-size: 0.875rem; | |
font-weight: 500; | |
} | |
.prediction-text { | |
line-height: 1.6; | |
margin-top: 1rem; | |
} | |
.loading { | |
display: none; | |
} | |
.source-info { | |
font-size: 0.875rem; | |
color: var(--bs-secondary); | |
margin-top: 0.5rem; | |
} | |
</style> | |
</head> | |
<body> | |
<div class="container mt-4"> | |
<div class="row"> | |
<div class="col-12"> | |
<h1 class="text-center mb-4">AI-Powered Daily Horoscopes</h1> | |
<p class="text-center text-muted mb-5">Get personalized horoscope predictions powered by AI consolidation from multiple trusted sources</p> | |
</div> | |
</div> | |
<div class="row"> | |
<div class="col-md-6"> | |
<div class="card"> | |
<div class="card-header"> | |
<h5>Single Sign Horoscope</h5> | |
</div> | |
<div class="card-body"> | |
<form id="singleSignForm"> | |
<div class="mb-3"> | |
<label for="zodiacSign" class="form-label">Zodiac Sign</label> | |
<select class="form-select" id="zodiacSign" required> | |
<option value="">Select your sign</option> | |
<option value="aries">Aries</option> | |
<option value="taurus">Taurus</option> | |
<option value="gemini">Gemini</option> | |
<option value="cancer">Cancer</option> | |
<option value="leo">Leo</option> | |
<option value="virgo">Virgo</option> | |
<option value="libra">Libra</option> | |
<option value="scorpio">Scorpio</option> | |
<option value="sagittarius">Sagittarius</option> | |
<option value="capricorn">Capricorn</option> | |
<option value="aquarius">Aquarius</option> | |
<option value="pisces">Pisces</option> | |
</select> | |
</div> | |
<div class="mb-3"> | |
<label for="source" class="form-label">Source</label> | |
<select class="form-select" id="source"> | |
<option value="astrology.com">Astrology.com</option> | |
<option value="horoscope.com">Horoscope.com</option> | |
</select> | |
</div> | |
<button type="submit" class="btn btn-primary">Get Horoscope</button> | |
<div class="loading mt-2"> | |
<div class="spinner-border spinner-border-sm" role="status"> | |
<span class="visually-hidden">Loading...</span> | |
</div> | |
<span class="ms-2">Fetching horoscope...</span> | |
</div> | |
</form> | |
</div> | |
</div> | |
</div> | |
<div class="col-md-6"> | |
<div class="card"> | |
<div class="card-header"> | |
<h5>All Signs with AI Consolidation</h5> | |
</div> | |
<div class="card-body"> | |
<p class="text-muted">Scrape horoscopes for all zodiac signs from multiple sources and get AI-consolidated predictions.</p> | |
<button type="button" class="btn btn-success" id="scrapeAllBtn">Scrape All Signs</button> | |
<div class="loading mt-2" id="allSignsLoading"> | |
<div class="spinner-border spinner-border-sm" role="status"> | |
<span class="visually-hidden">Loading...</span> | |
</div> | |
<span class="ms-2">Scraping all horoscopes...</span> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="row mt-4"> | |
<div class="col-12"> | |
<div id="results"></div> | |
</div> | |
</div> | |
<div class="row mt-5"> | |
<div class="col-12"> | |
<div class="card"> | |
<div class="card-header"> | |
<h5>API Endpoints</h5> | |
</div> | |
<div class="card-body"> | |
<h6>Available Endpoints:</h6> | |
<ul class="list-group list-group-flush"> | |
<li class="list-group-item"><strong>GET /api/health</strong> - Health check</li> | |
<li class="list-group-item"><strong>POST /api/horoscope/scrape</strong> - Scrape single horoscope</li> | |
<li class="list-group-item"><strong>POST /api/horoscope/scrape-all</strong> - Scrape all horoscopes</li> | |
<li class="list-group-item"><strong>POST /api/horoscope/consolidate</strong> - AI consolidate predictions</li> | |
<li class="list-group-item"><strong>GET /api/signs</strong> - Get zodiac signs list</li> | |
</ul> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<script> | |
// Single sign form handler | |
document.getElementById('singleSignForm').addEventListener('submit', async function(e) { | |
e.preventDefault(); | |
const sign = document.getElementById('zodiacSign').value; | |
const source = document.getElementById('source').value; | |
const loading = document.querySelector('#singleSignForm .loading'); | |
const submitBtn = document.querySelector('#singleSignForm button[type="submit"]'); | |
if (!sign) { | |
alert('Please select a zodiac sign'); | |
return; | |
} | |
// Show loading | |
loading.style.display = 'block'; | |
submitBtn.disabled = true; | |
try { | |
const response = await fetch('/api/horoscope/scrape', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({ | |
sign: sign, | |
source: source | |
}) | |
}); | |
const data = await response.json(); | |
if (data.success) { | |
displaySingleResult(data); | |
} else { | |
displayError('Error: ' + (data.error || 'Unknown error occurred')); | |
} | |
} catch (error) { | |
displayError('Network error: ' + error.message); | |
} finally { | |
// Hide loading | |
loading.style.display = 'none'; | |
submitBtn.disabled = false; | |
} | |
}); | |
// Scrape all button handler | |
document.getElementById('scrapeAllBtn').addEventListener('click', async function() { | |
const loading = document.getElementById('allSignsLoading'); | |
const btn = document.getElementById('scrapeAllBtn'); | |
// Show loading | |
loading.style.display = 'block'; | |
btn.disabled = true; | |
try { | |
const response = await fetch('/api/horoscope/scrape-all', { | |
method: 'POST', | |
headers: { | |
'Content-Type': 'application/json', | |
}, | |
body: JSON.stringify({}) | |
}); | |
const data = await response.json(); | |
if (data.success) { | |
displayAllResults(data.results); | |
} else { | |
displayError('Error: ' + (data.error || 'Unknown error occurred')); | |
} | |
} catch (error) { | |
displayError('Network error: ' + error.message); | |
} finally { | |
// Hide loading | |
loading.style.display = 'none'; | |
btn.disabled = false; | |
} | |
}); | |
function displaySingleResult(data) { | |
const resultsDiv = document.getElementById('results'); | |
resultsDiv.innerHTML = ` | |
<div class="horoscope-card"> | |
<div class="d-flex justify-content-between align-items-center mb-3"> | |
<span class="sign-badge">${data.sign.toUpperCase()}</span> | |
<small class="source-info">Source: ${data.source}</small> | |
</div> | |
<div class="prediction-text">${data.prediction}</div> | |
<div class="source-info"> | |
Date: ${data.date} | Scraped: ${new Date(data.scraped_at).toLocaleString()} | |
</div> | |
</div> | |
`; | |
} | |
function displayAllResults(results) { | |
const resultsDiv = document.getElementById('results'); | |
let html = '<h4 class="mb-4">All Horoscopes</h4>'; | |
Object.keys(results).forEach(sign => { | |
const signData = results[sign]; | |
html += ` | |
<div class="horoscope-card"> | |
<div class="mb-3"> | |
<span class="sign-badge">${sign.toUpperCase()}</span> | |
</div> | |
`; | |
Object.keys(signData).forEach(source => { | |
const data = signData[source]; | |
if (data.success) { | |
html += ` | |
<div class="mb-3"> | |
<strong>${source}:</strong> | |
<div class="prediction-text">${data.prediction}</div> | |
<div class="source-info">Date: ${data.date}</div> | |
</div> | |
`; | |
} else { | |
html += ` | |
<div class="mb-3"> | |
<strong>${source}:</strong> | |
<div class="text-danger">Error: ${data.error}</div> | |
</div> | |
`; | |
} | |
}); | |
html += '</div>'; | |
}); | |
resultsDiv.innerHTML = html; | |
} | |
function displayError(message) { | |
const resultsDiv = document.getElementById('results'); | |
resultsDiv.innerHTML = ` | |
<div class="alert alert-danger" role="alert"> | |
${message} | |
</div> | |
`; | |
} | |
// Load health check on page load | |
window.addEventListener('load', async function() { | |
try { | |
const response = await fetch('/api/health'); | |
const data = await response.json(); | |
console.log('API Health:', data); | |
} catch (error) { | |
console.error('Health check failed:', error); | |
} | |
}); | |
</script> | |
</body> | |
</html> |