quantum-ai-v2/templates/agent_detail.html
Claude 3fc5f01309 Initial Django project setup with working homepage
- Complete Django project structure with apps/ organization
- Working homepage with exact Next.js recreation (1039 lines)
- User authentication system with wallet balance
- Agent system with processors and models
- Stripe payment integration setup
- All Django migrations and URL routing
- Comprehensive .gitignore file
- Homepage loads successfully (HTTP 200)

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-07-08 16:30:56 +05:30

486 lines
22 KiB
HTML

{% extends 'base.html' %}
{% block title %}{{ agent.name }} - NetCop AI Hub{% endblock %}
{% block content %}
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<!-- Main Content -->
<div class="lg:col-span-2">
<div class="bg-white rounded-lg shadow-lg p-6">
<div class="flex items-center mb-6">
<div class="w-16 h-16 bg-gradient-to-r {{ agent.get_gradient_class }} rounded-lg flex items-center justify-center text-white text-2xl mr-4">
{{ agent.icon }}
</div>
<div>
<h1 class="text-2xl font-bold text-gray-900">{{ agent.name }}</h1>
<p class="text-gray-600">{{ agent.description }}</p>
</div>
</div>
<!-- Agent-specific interfaces -->
{% if agent.slug == 'five-whys' %}
<!-- Advanced Chat Interface for 5 Whys -->
<div id="chatContainer" class="h-96 overflow-y-auto border border-gray-200 rounded-lg p-4 mb-4" style="background: linear-gradient(to bottom, #f9fafb, #ffffff);">
<div id="chatMessages">
<div class="mb-4 flex">
<div class="w-8 h-8 bg-gradient-to-r from-purple-500 to-blue-500 rounded-full flex items-center justify-center text-white text-sm mr-3 flex-shrink-0">
🤖
</div>
<div class="bg-gray-100 rounded-lg p-3 max-w-md">
<div class="markdown-content">
<p>👋 Welcome to the 5 Whys Root Cause Analysis!</p>
<p>I'll help you systematically analyze your problem using the proven 5 Whys methodology.</p>
<p><strong>To get started, please describe the problem you're experiencing.</strong></p>
<p>For example:</p>
<ul>
<li>"Our customer complaints increased by 40% this month"</li>
<li>"Production quality has decreased recently"</li>
<li>"Website performance is slower than usual"</li>
</ul>
<p>What problem would you like to analyze?</p>
</div>
</div>
</div>
</div>
</div>
<div class="flex gap-2">
<input type="text" id="chatInput" placeholder="Describe your problem..." class="flex-1 p-3 border border-gray-300 rounded-lg focus:ring-2 focus:ring-purple-500 focus:border-transparent">
<button id="sendButton" class="px-6 py-3 bg-gradient-to-r from-purple-600 to-blue-600 text-white rounded-lg hover:from-purple-700 hover:to-blue-700 transition-all duration-300">
Send
</button>
</div>
<!-- Report Display -->
<div id="reportSection" class="mt-6 hidden">
<h3 class="text-lg font-semibold mb-4">5 Whys Analysis Report</h3>
<div id="reportContent" class="bg-gray-50 p-4 rounded-lg"></div>
<div class="mt-4 flex gap-2">
<button onclick="copyReport()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Copy Report</button>
<button onclick="downloadReport()" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">Download PDF</button>
</div>
</div>
{% elif agent.slug == 'data-analyzer' %}
<!-- File Upload Interface -->
<div class="border-2 border-dashed border-gray-300 rounded-lg p-6 text-center" id="fileDropZone">
<div class="mb-4">
<svg class="mx-auto h-12 w-12 text-gray-400" stroke="currentColor" fill="none" viewBox="0 0 48 48">
<path d="M28 8H12a4 4 0 00-4 4v20m32-12v8m0 0v8a4 4 0 01-4 4H12a4 4 0 01-4-4v-4m32-4l-3.172-3.172a4 4 0 00-5.656 0L28 28M8 32l9.172-9.172a4 4 0 015.656 0L28 28m0 0l4 4m4-24h8m-4-4v8m-12 4h.02" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
</div>
<p class="text-lg text-gray-600 mb-2">Drop your file here or click to browse</p>
<p class="text-sm text-gray-500">Supports CSV, Excel, JSON files up to 10MB</p>
<input type="file" id="fileInput" accept=".csv,.xlsx,.xls,.json" class="hidden">
<button onclick="document.getElementById('fileInput').click()" class="mt-4 px-6 py-2 bg-blue-600 text-white rounded-lg hover:bg-blue-700">
Choose File
</button>
</div>
<div id="filePreview" class="mt-4 hidden">
<div class="bg-gray-50 p-4 rounded-lg">
<p class="font-medium">Selected File:</p>
<p id="fileName" class="text-gray-600"></p>
<p id="fileSize" class="text-sm text-gray-500"></p>
</div>
</div>
{% elif agent.slug == 'weather-reporter' %}
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Location</label>
<input type="text" name="location" id="locationInput" required class="w-full p-3 border border-gray-300 rounded-md focus:ring-2 focus:ring-purple-500" placeholder="Enter city name (e.g., Dubai, UAE)">
</div>
{% elif agent.slug == 'job-posting-generator' %}
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Job Title</label>
<input type="text" name="title" required class="w-full p-3 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Company</label>
<input type="text" name="company" required class="w-full p-3 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Job Description</label>
<textarea name="description" rows="4" required class="w-full p-3 border border-gray-300 rounded-md"></textarea>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Requirements</label>
<textarea name="requirements" rows="4" required class="w-full p-3 border border-gray-300 rounded-md"></textarea>
</div>
</div>
{% elif agent.slug == 'social-ads-generator' %}
<div class="space-y-4">
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Product/Service</label>
<input type="text" name="product" required class="w-full p-3 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Platform</label>
<select name="platform" required class="w-full p-3 border border-gray-300 rounded-md">
<option value="facebook">Facebook</option>
<option value="instagram">Instagram</option>
<option value="twitter">Twitter</option>
<option value="linkedin">LinkedIn</option>
</select>
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Target Audience</label>
<input type="text" name="target_audience" required class="w-full p-3 border border-gray-300 rounded-md">
</div>
<div>
<label class="block text-sm font-medium text-gray-700 mb-2">Tone</label>
<select name="tone" required class="w-full p-3 border border-gray-300 rounded-md">
<option value="professional">Professional</option>
<option value="casual">Casual</option>
<option value="humorous">Humorous</option>
<option value="urgent">Urgent</option>
</select>
</div>
</div>
{% elif agent.slug == 'faq-generator' %}
<div class="mb-4">
<label class="block text-sm font-medium text-gray-700 mb-2">Content Source</label>
<textarea name="content_source" rows="6" required class="w-full p-3 border border-gray-300 rounded-md" placeholder="Paste your content or URL here..."></textarea>
</div>
{% endif %}
<!-- Processing Status -->
<div id="processingStatus" class="mt-6 hidden">
<div class="flex items-center justify-center p-6">
<div class="animate-spin rounded-full h-8 w-8 border-b-2 border-purple-600 mr-3"></div>
<span class="text-gray-600">Processing your request...</span>
</div>
</div>
<!-- Results Display -->
<div id="results" class="mt-6 hidden">
<h3 class="text-lg font-semibold mb-4">Results</h3>
<div id="resultsContent" class="bg-gray-50 p-4 rounded-md">
<!-- Results will be inserted here -->
</div>
<div class="mt-4 flex gap-2">
<button onclick="copyResults()" class="px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700">Copy Results</button>
<button onclick="downloadResults()" class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700">Download</button>
</div>
</div>
</div>
</div>
<!-- Sidebar -->
<div class="lg:col-span-1">
<!-- Wallet Balance Component -->
<div class="bg-white rounded-lg shadow-lg p-6 mb-6">
<h3 class="text-lg font-semibold mb-4">Cost</h3>
<div class="mb-4">
<div class="flex justify-between items-center mb-2">
<span class="text-gray-600">Current Balance:</span>
<span class="font-semibold">{{ user.wallet_balance }} AED</span>
</div>
<div class="flex justify-between items-center mb-2">
<span class="text-gray-600">Cost:</span>
<span class="font-semibold text-red-600">-{{ agent.price_display }}</span>
</div>
<div class="border-t pt-2">
<div class="flex justify-between items-center">
<span class="font-semibold">After Processing:</span>
<span class="font-semibold {% if has_sufficient_balance %}text-green-600{% else %}text-red-600{% endif %}">
{% if has_sufficient_balance %}
{{ user.wallet_balance|floatformat:2 }} AED
{% else %}
Insufficient Balance
{% endif %}
</span>
</div>
</div>
</div>
<button id="processBtn" type="button"
class="w-full py-3 px-4 rounded-md font-semibold transition-colors
{% if has_sufficient_balance %}
bg-blue-600 text-white hover:bg-blue-700
{% else %}
bg-gray-300 text-gray-500 cursor-not-allowed
{% endif %}"
{% if not has_sufficient_balance %}disabled{% endif %}>
{% if has_sufficient_balance %}
Process Agent ({{ agent.price_display }})
{% else %}
Insufficient Balance
{% endif %}
</button>
{% if not has_sufficient_balance %}
<p class="text-center mt-4 text-sm">
<a href="{% url 'pricing' %}" class="text-blue-600 hover:text-blue-800 underline">
Top up wallet
</a> to use this agent
</p>
{% endif %}
</div>
<!-- Agent Stats -->
<div class="bg-white rounded-lg shadow-lg p-6">
<h3 class="text-lg font-semibold mb-4">Agent Statistics</h3>
<div class="space-y-3">
<div class="flex justify-between">
<span class="text-gray-600">Rating:</span>
<div class="flex items-center">
<span class="text-yellow-400"></span>
<span class="ml-1">{{ agent.rating }}</span>
</div>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Reviews:</span>
<span>{{ agent.review_count }}</span>
</div>
<div class="flex justify-between">
<span class="text-gray-600">Category:</span>
<span class="capitalize">{{ agent.get_category_display }}</span>
</div>
</div>
</div>
</div>
</div>
<script>
// Agent processing logic
document.addEventListener('DOMContentLoaded', function() {
const agentSlug = '{{ agent.slug }}';
const processBtn = document.getElementById('processBtn');
const processingStatus = document.getElementById('processingStatus');
const results = document.getElementById('results');
const resultsContent = document.getElementById('resultsContent');
// File upload for data analyzer
if (agentSlug === 'data-analyzer') {
const fileInput = document.getElementById('fileInput');
const fileDropZone = document.getElementById('fileDropZone');
const filePreview = document.getElementById('filePreview');
const fileName = document.getElementById('fileName');
const fileSize = document.getElementById('fileSize');
fileInput.addEventListener('change', function(e) {
const file = e.target.files[0];
if (file) {
fileName.textContent = file.name;
fileSize.textContent = `${(file.size / 1024 / 1024).toFixed(2)} MB`;
filePreview.classList.remove('hidden');
}
});
// Drag and drop functionality
fileDropZone.addEventListener('dragover', function(e) {
e.preventDefault();
fileDropZone.classList.add('border-blue-400', 'bg-blue-50');
});
fileDropZone.addEventListener('dragleave', function(e) {
e.preventDefault();
fileDropZone.classList.remove('border-blue-400', 'bg-blue-50');
});
fileDropZone.addEventListener('drop', function(e) {
e.preventDefault();
fileDropZone.classList.remove('border-blue-400', 'bg-blue-50');
const files = e.dataTransfer.files;
if (files.length > 0) {
fileInput.files = files;
fileInput.dispatchEvent(new Event('change'));
}
});
}
// Chat functionality for 5 Whys
if (agentSlug === 'five-whys') {
const chatInput = document.getElementById('chatInput');
const sendButton = document.getElementById('sendButton');
const chatMessages = document.getElementById('chatMessages');
const chatContainer = document.getElementById('chatContainer');
function addMessage(content, sender = 'user') {
const messageDiv = document.createElement('div');
messageDiv.className = 'mb-4 flex';
if (sender === 'user') {
messageDiv.innerHTML = `
<div class="ml-auto flex">
<div class="bg-blue-600 text-white rounded-lg p-3 max-w-md">
${content}
</div>
<div class="w-8 h-8 bg-blue-600 rounded-full flex items-center justify-center text-white text-sm ml-3 flex-shrink-0">
👤
</div>
</div>
`;
} else {
messageDiv.innerHTML = `
<div class="w-8 h-8 bg-gradient-to-r from-purple-500 to-blue-500 rounded-full flex items-center justify-center text-white text-sm mr-3 flex-shrink-0">
🤖
</div>
<div class="bg-gray-100 rounded-lg p-3 max-w-md">
<div class="markdown-content">${content}</div>
</div>
`;
}
chatMessages.appendChild(messageDiv);
chatContainer.scrollTop = chatContainer.scrollHeight;
}
function sendMessage() {
const message = chatInput.value.trim();
if (!message) return;
addMessage(message, 'user');
chatInput.value = '';
// Here you would send the message to your Django backend
// For now, we'll simulate a response
setTimeout(() => {
addMessage('Thank you for sharing that problem. Let me ask you the first "Why" question...', 'bot');
}, 1000);
}
sendButton.addEventListener('click', sendMessage);
chatInput.addEventListener('keypress', function(e) {
if (e.key === 'Enter') {
sendMessage();
}
});
}
// Main process button functionality
processBtn.addEventListener('click', async function() {
if (processBtn.disabled) return;
processBtn.disabled = true;
processBtn.textContent = 'Processing...';
processingStatus.classList.remove('hidden');
try {
const formData = new FormData();
// Collect form data based on agent type
if (agentSlug === 'data-analyzer') {
const fileInput = document.getElementById('fileInput');
if (fileInput.files[0]) {
formData.append('file', fileInput.files[0]);
} else {
throw new Error('Please select a file');
}
} else if (agentSlug === 'weather-reporter') {
const location = document.getElementById('locationInput').value;
if (!location) throw new Error('Please enter a location');
formData.append('location', location);
} else {
// For other agents, collect all form inputs
const inputs = document.querySelectorAll('input[name], textarea[name], select[name]');
inputs.forEach(input => {
if (input.value) {
formData.append(input.name, input.value);
}
});
}
const response = await fetch(`{% url 'process_agent' agent.slug %}`, {
method: 'POST',
body: formData,
headers: {
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
}
});
const data = await response.json();
if (data.success) {
// Display results
resultsContent.innerHTML = `<pre>${JSON.stringify(data.result, null, 2)}</pre>`;
results.classList.remove('hidden');
// Update balance display (you might want to refresh the page or update via AJAX)
location.reload();
} else {
alert('Error: ' + data.error);
}
} catch (error) {
alert('Error: ' + error.message);
} finally {
processBtn.disabled = false;
processBtn.textContent = 'Process Agent ({{ agent.price_display }})';
processingStatus.classList.add('hidden');
}
});
});
// Utility functions
function copyResults() {
const content = document.getElementById('resultsContent').textContent;
navigator.clipboard.writeText(content).then(() => {
alert('Results copied to clipboard!');
});
}
function downloadResults() {
const content = document.getElementById('resultsContent').textContent;
const blob = new Blob([content], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = '{{ agent.slug }}_results.txt';
a.click();
window.URL.revokeObjectURL(url);
}
function copyReport() {
const content = document.getElementById('reportContent').textContent;
navigator.clipboard.writeText(content).then(() => {
alert('Report copied to clipboard!');
});
}
function downloadReport() {
const content = document.getElementById('reportContent').textContent;
const blob = new Blob([content], { type: 'text/plain' });
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = 'five_whys_analysis_report.txt';
a.click();
window.URL.revokeObjectURL(url);
}
</script>
<style>
.markdown-content ul {
list-style-type: disc;
margin-left: 20px;
margin-top: 8px;
margin-bottom: 8px;
}
.markdown-content li {
margin: 4px 0;
}
.markdown-content p {
margin: 8px 0;
}
.markdown-content strong {
font-weight: 600;
}
@keyframes spin {
to { transform: rotate(360deg); }
}
.animate-spin {
animation: spin 1s linear infinite;
}
</style>
{% endblock %}