influencer_flow_back / monitor_example.html
saidinesh07's picture
Upload 116 files
a4a766c verified
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>AI Campaign Monitor</title>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.3/dist/css/bootstrap.min.css" rel="stylesheet">
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.0.0/css/all.min.css" rel="stylesheet">
<style>
.stage-active { background: linear-gradient(45deg, #007bff, #0056b3); color: white; }
.stage-completed { background: linear-gradient(45deg, #28a745, #1e7e34); color: white; }
.live-update { animation: slideIn 0.5s ease-out; }
@keyframes slideIn {
from { opacity: 0; transform: translateY(-20px); }
to { opacity: 1; transform: translateY(0); }
}
</style>
</head>
<body class="bg-light">
<div class="container-fluid py-4">
<!-- Progress Header -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<div class="row align-items-center">
<div class="col-md-8">
<h2 id="campaignTitle">AI Campaign in Progress</h2>
<p class="text-muted" id="campaignSubtitle">Processing...</p>
</div>
<div class="col-md-4 text-end">
<div class="progress" style="height: 20px;">
<div class="progress-bar" id="progressBar" style="width: 0%">0%</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<!-- Stage Indicators -->
<div class="row mb-4">
<div class="col-12">
<div class="card shadow-sm">
<div class="card-body">
<h5>πŸ“Š Campaign Stages</h5>
<div class="row" id="stageIndicators">
<!-- Will be populated by JavaScript -->
</div>
</div>
</div>
</div>
</div>
<!-- Real-time Metrics -->
<div class="row mb-4">
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-users fa-2x text-primary mb-2"></i>
<h4 id="influencerCount">0</h4>
<small>Influencers Found</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-phone fa-2x text-success mb-2"></i>
<h4 id="callsCompleted">0</h4>
<small>Calls Completed</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-handshake fa-2x text-warning mb-2"></i>
<h4 id="successfulDeals">0</h4>
<small>Successful Deals</small>
</div>
</div>
</div>
<div class="col-md-3">
<div class="card text-center">
<div class="card-body">
<i class="fas fa-dollar-sign fa-2x text-info mb-2"></i>
<h4 id="totalCost">$0</h4>
<small>Total Cost</small>
</div>
</div>
</div>
</div>
<!-- Live Activity Feed -->
<div class="row">
<div class="col-md-8">
<div class="card">
<div class="card-header">
<h5>πŸ”΄ Live Activity Feed</h5>
</div>
<div class="card-body" style="height: 400px; overflow-y: auto;">
<div id="liveUpdates">
<div class="text-center py-4">
<div class="spinner-border text-primary"></div>
<div class="mt-2">Connecting...</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-4">
<div class="card">
<div class="card-header">
<h5>⏱️ Timing Info</h5>
</div>
<div class="card-body">
<div class="mb-3">
<small class="text-muted">Started At</small>
<div id="startedAt">-</div>
</div>
<div class="mb-3">
<small class="text-muted">Duration</small>
<div id="duration">-</div>
</div>
<div class="mb-3">
<small class="text-muted">Estimated Remaining</small>
<div id="estimatedRemaining">-</div>
</div>
<div>
<small class="text-muted">Current Activity</small>
<div id="currentInfluencer">None</div>
</div>
</div>
</div>
</div>
</div>
</div>
<script>
// Get the task ID - replace this with your actual task ID
const TASK_ID = 'your-task-id-here'; // ⚠️ Replace with actual task ID
class CampaignMonitor {
constructor(taskId) {
this.taskId = taskId;
this.updateInterval = 5000; // 5 seconds
this.isMonitoring = false;
this.pollingId = null;
this.stages = [
{ key: 'webhook_received', name: 'Starting', icon: 'fas fa-play' },
{ key: 'discovery', name: 'Discovery', icon: 'fas fa-search' },
{ key: 'negotiations', name: 'Negotiations', icon: 'fas fa-phone' },
{ key: 'contracts', name: 'Contracts', icon: 'fas fa-file-contract' },
{ key: 'completed', name: 'Complete', icon: 'fas fa-check' }
];
this.initializeUI();
}
initializeUI() {
this.renderStageIndicators();
}
renderStageIndicators() {
const container = document.getElementById('stageIndicators');
container.innerHTML = this.stages.map(stage => `
<div class="col">
<div class="text-center p-3 rounded border" id="stage-${stage.key}">
<i class="${stage.icon} fa-lg mb-2"></i>
<div class="small">${stage.name}</div>
</div>
</div>
`).join('');
}
async startMonitoring() {
console.log(`πŸš€ Starting monitoring for: ${this.taskId}`);
this.isMonitoring = true;
// Initial fetch
await this.fetchCampaignStatus();
// Start polling
this.pollingId = setInterval(async () => {
if (this.isMonitoring) {
await this.fetchCampaignStatus();
}
}, this.updateInterval);
}
async fetchCampaignStatus() {
try {
const response = await fetch(`/api/monitor/campaign/${this.taskId}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const data = await response.json();
this.updateUI(data);
if (data.is_complete) {
this.onCampaignComplete(data);
}
} catch (error) {
console.error('❌ Monitoring error:', error);
this.handleError(error);
}
}
updateUI(data) {
// Update header
document.getElementById('campaignTitle').textContent =
`${data.campaign_info.brand_name} - ${data.campaign_info.product_name}`;
document.getElementById('campaignSubtitle').textContent =
this.getStageDescription(data.current_stage, data.current_influencer);
// Update progress bar
const progressBar = document.getElementById('progressBar');
progressBar.style.width = `${data.progress_percentage}%`;
progressBar.textContent = `${Math.round(data.progress_percentage)}%`;
// Update stage indicators
this.updateStageIndicators(data.current_stage);
// Update metrics
const details = data.progress_details;
document.getElementById('influencerCount').textContent = details.discovered_influencers;
document.getElementById('callsCompleted').textContent = details.completed_negotiations;
document.getElementById('successfulDeals').textContent = details.successful_negotiations;
document.getElementById('totalCost').textContent = `$${details.total_cost.toLocaleString()}`;
// Update live feed
this.updateLiveFeed(data.live_updates);
// Update timing
const timing = data.timing;
document.getElementById('startedAt').textContent = new Date(timing.started_at).toLocaleString();
document.getElementById('duration').textContent = `${Math.round(timing.duration_so_far)} min`;
document.getElementById('estimatedRemaining').textContent = timing.estimated_remaining;
document.getElementById('currentInfluencer').textContent = data.current_influencer || 'None';
}
updateStageIndicators(currentStage) {
this.stages.forEach(stage => {
const element = document.getElementById(`stage-${stage.key}`);
element.className = 'text-center p-3 rounded border';
if (stage.key === currentStage) {
element.classList.add('stage-active');
} else if (this.isStageCompleted(stage.key, currentStage)) {
element.classList.add('stage-completed');
}
});
}
updateLiveFeed(updates) {
const container = document.getElementById('liveUpdates');
// Clear loading state
if (container.innerHTML.includes('Connecting')) {
container.innerHTML = '';
}
// Add new updates
updates.forEach(update => {
if (!this.isUpdateDisplayed(update)) {
const updateElement = this.createUpdateElement(update);
container.insertBefore(updateElement, container.firstChild);
}
});
// Limit to last 10 updates
while (container.children.length > 10) {
container.removeChild(container.lastChild);
}
}
createUpdateElement(update) {
const div = document.createElement('div');
div.className = 'border-bottom pb-2 mb-2 live-update';
div.innerHTML = `
<div class="d-flex justify-content-between">
<div>${this.formatUpdate(update)}</div>
<small class="text-muted">${new Date().toLocaleTimeString()}</small>
</div>
`;
return div;
}
formatUpdate(update) {
if (update.includes('βœ…')) return `<span class="text-success">${update}</span>`;
if (update.includes('❌')) return `<span class="text-danger">${update}</span>`;
if (update.includes('πŸ“ž')) return `<span class="text-primary">${update}</span>`;
if (update.includes('πŸ”')) return `<span class="text-info">${update}</span>`;
return update;
}
getStageDescription(stage, currentInfluencer) {
const descriptions = {
'webhook_received': 'Initializing campaign workflow...',
'discovery': 'Analyzing and discovering potential influencers...',
'negotiations': currentInfluencer ?
`Currently negotiating with ${currentInfluencer}...` :
'Conducting influencer negotiations...',
'contracts': 'Generating contracts and finalizing deals...',
'completed': 'Campaign completed successfully!'
};
return descriptions[stage] || 'Processing...';
}
isStageCompleted(stage, currentStage) {
const stageOrder = this.stages.map(s => s.key);
const currentIndex = stageOrder.indexOf(currentStage);
const stageIndex = stageOrder.indexOf(stage);
return stageIndex < currentIndex;
}
isUpdateDisplayed(update) {
const container = document.getElementById('liveUpdates');
return Array.from(container.children).some(child =>
child.textContent.includes(update.substring(0, 50))
);
}
onCampaignComplete(data) {
this.stopMonitoring();
// Show success message
const container = document.getElementById('liveUpdates');
const completionMsg = document.createElement('div');
completionMsg.className = 'alert alert-success';
completionMsg.innerHTML = `
<h5>πŸŽ‰ Campaign Complete!</h5>
<p>Successfully completed ${data.progress_details.successful_negotiations} deals
for $${data.progress_details.total_cost.toLocaleString()}</p>
`;
container.insertBefore(completionMsg, container.firstChild);
}
handleError(error) {
const container = document.getElementById('liveUpdates');
const errorMsg = document.createElement('div');
errorMsg.className = 'alert alert-warning';
errorMsg.innerHTML = `❌ Connection error: ${error.message}. Retrying...`;
container.insertBefore(errorMsg, container.firstChild);
}
stopMonitoring() {
this.isMonitoring = false;
if (this.pollingId) {
clearInterval(this.pollingId);
this.pollingId = null;
}
console.log('⏹️ Campaign monitoring stopped');
}
}
// Initialize when page loads
document.addEventListener('DOMContentLoaded', function() {
// Get task ID from URL parameters or use the constant
const urlParams = new URLSearchParams(window.location.search);
const taskId = urlParams.get('task_id') || TASK_ID;
if (taskId && taskId !== 'your-task-id-here') {
const monitor = new CampaignMonitor(taskId);
monitor.startMonitoring();
// Stop monitoring when page closes
window.addEventListener('beforeunload', () => {
monitor.stopMonitoring();
});
} else {
document.getElementById('liveUpdates').innerHTML = `
<div class="alert alert-info">
<h5>ℹ️ Setup Required</h5>
<p>Please provide a task_id parameter in the URL or update the TASK_ID constant in the JavaScript.</p>
<p><strong>Example:</strong> monitor.html?task_id=your-actual-task-id</p>
</div>
`;
}
});
</script>
</body>
</html>