mirror of
https://github.com/thecyberlearn/quantum-ai.git
synced 2026-08-18 09:32:59 +00:00
Major fixes:
- Weather Reporter: Restore correct API-based processing pattern
* Fix form submission URL to use /agents/weather-reporter/process/
* Remove incorrect polling logic (API agents return immediate results)
* Fix response field mapping to use formatted_report instead of analysis_text
* Implement immediate response display without polling
- Agent CSS System: Enhance unified styling system
* Add missing CSS classes for status display (.status-title, .status-subtitle)
* Add enhanced typography for results content formatting
* Include modern info boxes (.key-points, .insights, .summary)
* Fix animation keyframes for proper loading states
- Template Consistency: Update agents to use shared components
* Job Posting Generator: Add cache-busted CSS and shared header/panel
* Social Ads Generator: Add unified CSS link and shared components
* Create component templates for consistent agent layouts
Key architectural insight: Weather Reporter is API-based (immediate response)
while Data Analyzer is webhook-based (async polling). Fixed Weather Reporter
to use correct pattern based on git history commit 82fc051.
🤖 Generated with [Claude Code](https://claude.ai/code)
Co-Authored-By: Claude <noreply@anthropic.com>
575 lines
13 KiB
Plaintext
575 lines
13 KiB
Plaintext
Perfect! Let's proceed with **inline code generation** for manual copying. Here's how we'll break it down:
|
||
|
||
---
|
||
|
||
## ✅ Step 1: Unified Base Template — `base_agent.html`
|
||
|
||
Create this file in your templates folder:
|
||
|
||
```html
|
||
{% extends "base.html" %}
|
||
{% load static %}
|
||
|
||
{% block title %}{{ agent_title }} - NetCop AI Hub{% endblock %}
|
||
|
||
{% block extra_css %}
|
||
<link rel="stylesheet" href="{% static 'css/theme.css' %}">
|
||
{% endblock %}
|
||
|
||
{% block content %}
|
||
<div class="agent-page">
|
||
<div class="agent-container">
|
||
|
||
{% include "components/agent_header.html" %}
|
||
|
||
{% block agent_main %}{% endblock %}
|
||
|
||
{% include "components/processing_status.html" %}
|
||
{% include "components/results_block.html" %}
|
||
{% include "components/quick_agents_panel.html" %}
|
||
</div>
|
||
</div>
|
||
{% endblock %}
|
||
```
|
||
|
||
---
|
||
|
||
## 🧱 Step 2: Agent Header Component — `components/agent_header.html`
|
||
|
||
```html
|
||
<div class="agent-header">
|
||
<div>
|
||
<h1 class="agent-title">{{ agent_title }}</h1>
|
||
<p class="agent-subtitle">{{ agent_subtitle }}</p>
|
||
</div>
|
||
<div class="header-controls">
|
||
{% include "components/wallet_card.html" %}
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 💳 Step 3: Wallet Card Component — `components/wallet_card.html`
|
||
|
||
```html
|
||
<div class="wallet-card widget-small" style="margin-bottom: 0;">
|
||
<div class="wallet-header">
|
||
<h3 class="wallet-title">Your Wallet</h3>
|
||
<div class="wallet-icon">💳</div>
|
||
</div>
|
||
<div class="balance-display">
|
||
<div class="balance-amount">
|
||
<span id="walletBalance">{{ user.wallet_balance|floatformat:2 }}</span> AED
|
||
</div>
|
||
<div class="balance-label">Available Balance</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 🧭 Step 4: Quick Agents Panel — `components/quick_agents_panel.html`
|
||
|
||
```html
|
||
<div class="quick-agents-overlay" id="quickAgentsOverlay" onclick="closeQuickAgents()" aria-hidden="true"></div>
|
||
|
||
<div class="quick-agents-panel" id="quickAgentsPanel" role="dialog" aria-labelledby="quickAgentsTitle" aria-hidden="true">
|
||
<div class="quick-agents-header">
|
||
<h3 id="quickAgentsTitle">Quick Access to Other Agents</h3>
|
||
<button class="close-panel" onclick="toggleQuickAgents()" aria-label="Close quick agents panel">×</button>
|
||
</div>
|
||
|
||
<div class="quick-agents-grid">
|
||
<a href="/agents/data-analyzer/" class="quick-agent-card">
|
||
<div class="agent-icon">📊</div>
|
||
<div class="agent-info">
|
||
<h4>Data Analyzer</h4>
|
||
<p>AI-powered data analysis</p>
|
||
<span class="agent-price">5.0 AED</span>
|
||
</div>
|
||
</a>
|
||
|
||
<a href="/agents/weather-reporter/" class="quick-agent-card">
|
||
<div class="agent-icon">🌤️</div>
|
||
<div class="agent-info">
|
||
<h4>Weather Reporter</h4>
|
||
<p>Worldwide forecasts</p>
|
||
<span class="agent-price">2.0 AED</span>
|
||
</div>
|
||
</a>
|
||
|
||
<a href="/agents/job-posting-generator/" class="quick-agent-card">
|
||
<div class="agent-icon">💼</div>
|
||
<div class="agent-info">
|
||
<h4>Job Posting Generator</h4>
|
||
<p>Create job posts</p>
|
||
<span class="agent-price">3.0 AED</span>
|
||
</div>
|
||
</a>
|
||
</div>
|
||
|
||
<div class="quick-agents-footer">
|
||
<a href="{% url 'core:marketplace' %}" class="view-all-agents">View All Agents →</a>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## 📊 Step 5: Results Block — `components/results_block.html`
|
||
|
||
```html
|
||
<div class="agent-widget widget-wide results-container" id="resultsContainer" style="display: none;">
|
||
<div class="widget-header">
|
||
<h3 class="widget-title">
|
||
<span class="widget-icon">📊</span>
|
||
Analysis Results
|
||
</h3>
|
||
<span class="status-badge">Success</span>
|
||
</div>
|
||
|
||
<div class="widget-content">
|
||
<div class="results-content" id="resultsContent"></div>
|
||
<div class="results-actions">
|
||
<button onclick="copyResults()" class="btn btn-primary">📋 Copy</button>
|
||
<button onclick="downloadResults()" class="btn btn-secondary">💾 Download</button>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## ⏳ Step 6: Processing Status — `components/processing_status.html`
|
||
|
||
```html
|
||
<div id="processingStatus" class="agent-widget widget-wide processing-status">
|
||
<div class="widget-header">
|
||
<h3 class="widget-title">
|
||
<span class="widget-icon">⏳</span>
|
||
Processing
|
||
</h3>
|
||
</div>
|
||
<div class="widget-content" style="text-align: center;">
|
||
<div class="status-icon">⏳</div>
|
||
<div class="status-title">Working on your request...</div>
|
||
<div class="status-subtitle" id="statusText">Please wait...</div>
|
||
</div>
|
||
</div>
|
||
```
|
||
|
||
---
|
||
|
||
## ℹ️ Step 7: How It Works Widget — `components/how_it_works_widget.html`
|
||
|
||
```html
|
||
{% if steps == "data" %}
|
||
<ol class="info-list">
|
||
<li>Upload your data file</li>
|
||
<li>Choose analysis type</li>
|
||
<li>Get AI-powered insights</li>
|
||
<li>Copy or download results</li>
|
||
</ol>
|
||
{% elif steps == "weather" %}
|
||
<ol class="info-list">
|
||
<li>Enter any city name worldwide</li>
|
||
<li>Choose your preferred report type</li>
|
||
<li>Get real-time weather data</li>
|
||
<li>Copy or download detailed reports</li>
|
||
</ol>
|
||
{% endif %}
|
||
|
||
<button class="quick-agent-toggle btn btn-secondary btn-full" onclick="toggleQuickAgents()"
|
||
title="Quick access to other agents">
|
||
<span class="toggle-icon">🚀</span>
|
||
<span class="toggle-text">Explore Other Agents</span>
|
||
</button>
|
||
```
|
||
|
||
---
|
||
|
||
## 📁 Optional Folder Structure
|
||
|
||
```
|
||
templates/
|
||
│
|
||
├── base_agent.html
|
||
├── agents/
|
||
│ ├── data_analyzer.html
|
||
│ └── weather_reporter.html
|
||
├── components/
|
||
│ ├── agent_header.html
|
||
│ ├── wallet_card.html
|
||
│ ├── quick_agents_panel.html
|
||
│ ├── results_block.html
|
||
│ ├── processing_status.html
|
||
│ └── how_it_works_widget.html
|
||
```
|
||
|
||
---
|
||
|
||
Would you like me to now generate the unified `theme.css`? Or do you want to manually merge the CSS too?
|
||
|
||
|
||
Here is your **unified `theme.css`** for both the Data Analyzer and Weather Reporter agents. This file consolidates colors, typography, layout, buttons, forms, radio buttons, result boxes, and responsive utilities.
|
||
|
||
---
|
||
|
||
## ✅ `static/css/theme.css`
|
||
|
||
```css
|
||
/* ========== NetCop Unified Theme ========== */
|
||
|
||
/* Fonts */
|
||
@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap');
|
||
|
||
* {
|
||
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||
box-sizing: border-box;
|
||
}
|
||
|
||
/* ========== Root Variables ========== */
|
||
:root {
|
||
/* Colors */
|
||
--primary: #1a1a1a;
|
||
--primary-variant: #2d2d2d;
|
||
--background: #ffffff;
|
||
--surface: #ffffff;
|
||
--surface-variant: #f7fafc;
|
||
--outline: #e2e8f0;
|
||
--outline-variant: #cbd5e0;
|
||
|
||
--on-surface: #1a202c;
|
||
--on-surface-variant: #4a5568;
|
||
|
||
--success: #38a169;
|
||
--error: #e53e3e;
|
||
--warning: #d69e2e;
|
||
|
||
/* Spacing */
|
||
--spacing-xs: 4px;
|
||
--spacing-sm: 8px;
|
||
--spacing-md: 16px;
|
||
--spacing-lg: 24px;
|
||
--spacing-xl: 32px;
|
||
--spacing-2xl: 48px;
|
||
|
||
/* Radius */
|
||
--radius-sm: 8px;
|
||
--radius-md: 12px;
|
||
--radius-lg: 16px;
|
||
|
||
/* Shadows */
|
||
--shadow-sm: 0 1px 3px rgba(0, 0, 0, 0.1);
|
||
--shadow-md: 0 4px 6px rgba(0, 0, 0, 0.1);
|
||
--shadow-lg: 0 10px 20px rgba(0, 0, 0, 0.15);
|
||
}
|
||
|
||
/* ========== Layout ========== */
|
||
body {
|
||
background: var(--background);
|
||
color: var(--on-surface);
|
||
margin: 0;
|
||
padding: 0;
|
||
line-height: 1.6;
|
||
}
|
||
|
||
/* Utility Classes */
|
||
.text-center {
|
||
text-align: center;
|
||
}
|
||
.flex {
|
||
display: flex;
|
||
}
|
||
.flex-col {
|
||
flex-direction: column;
|
||
}
|
||
.flex-row {
|
||
flex-direction: row;
|
||
}
|
||
.gap-md {
|
||
gap: var(--spacing-md);
|
||
}
|
||
|
||
/* ========== Agent Container ========== */
|
||
.agent-page {
|
||
min-height: 100vh;
|
||
padding: var(--spacing-lg) 0;
|
||
}
|
||
|
||
.agent-container {
|
||
max-width: 1600px;
|
||
margin: 0 auto;
|
||
padding: 0 var(--spacing-lg);
|
||
}
|
||
|
||
/* ========== Header ========== */
|
||
.agent-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: var(--spacing-xl);
|
||
}
|
||
.agent-title {
|
||
font-size: 32px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.5px;
|
||
}
|
||
.agent-subtitle {
|
||
font-size: 16px;
|
||
color: var(--on-surface-variant);
|
||
}
|
||
|
||
/* ========== Wallet Card ========== */
|
||
.wallet-card {
|
||
background: linear-gradient(135deg, #000000 0%, #333333 100%);
|
||
color: white;
|
||
border-radius: var(--radius-md);
|
||
padding: var(--spacing-md);
|
||
position: relative;
|
||
box-shadow: var(--shadow-md);
|
||
}
|
||
.wallet-card::before {
|
||
content: '';
|
||
position: absolute;
|
||
top: 0;
|
||
right: 0;
|
||
width: 100px;
|
||
height: 100px;
|
||
background: rgba(255, 255, 255, 0.1);
|
||
border-radius: 50%;
|
||
transform: translate(40px, -40px);
|
||
}
|
||
.wallet-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
margin-bottom: var(--spacing-sm);
|
||
}
|
||
.wallet-title {
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
opacity: 0.9;
|
||
}
|
||
.wallet-icon {
|
||
font-size: 20px;
|
||
}
|
||
.balance-amount {
|
||
font-size: 24px;
|
||
font-weight: 700;
|
||
letter-spacing: -0.5px;
|
||
}
|
||
.balance-label {
|
||
font-size: 12px;
|
||
opacity: 0.8;
|
||
}
|
||
|
||
/* ========== Widget ========== */
|
||
.agent-widget {
|
||
background: var(--surface);
|
||
border: 1px solid var(--outline);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--spacing-xl);
|
||
box-shadow: var(--shadow-sm);
|
||
}
|
||
.widget-header {
|
||
display: flex;
|
||
justify-content: space-between;
|
||
align-items: center;
|
||
margin-bottom: var(--spacing-lg);
|
||
border-bottom: 1px solid var(--outline-variant);
|
||
padding-bottom: var(--spacing-md);
|
||
}
|
||
.widget-title {
|
||
font-size: 18px;
|
||
font-weight: 600;
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--spacing-sm);
|
||
}
|
||
.widget-icon {
|
||
font-size: 20px;
|
||
padding: 6px;
|
||
border-radius: var(--radius-sm);
|
||
background: var(--surface-variant);
|
||
}
|
||
|
||
/* ========== Buttons ========== */
|
||
.btn {
|
||
padding: 12px 24px;
|
||
font-size: 14px;
|
||
font-weight: 600;
|
||
border-radius: var(--radius-md);
|
||
display: inline-flex;
|
||
align-items: center;
|
||
justify-content: center;
|
||
text-decoration: none;
|
||
cursor: pointer;
|
||
border: 1px solid transparent;
|
||
transition: all 0.2s ease;
|
||
min-height: 44px;
|
||
}
|
||
.btn-primary {
|
||
background: var(--primary);
|
||
color: white;
|
||
}
|
||
.btn-primary:hover {
|
||
background: var(--primary-variant);
|
||
}
|
||
.btn-secondary {
|
||
background: var(--surface);
|
||
color: var(--on-surface);
|
||
border: 2px solid var(--outline);
|
||
}
|
||
.btn-secondary:hover {
|
||
background: var(--surface-variant);
|
||
}
|
||
.btn-full {
|
||
width: 100%;
|
||
}
|
||
|
||
/* ========== Form Elements ========== */
|
||
.form-group {
|
||
margin-bottom: var(--spacing-lg);
|
||
}
|
||
.form-label {
|
||
font-size: 14px;
|
||
font-weight: 500;
|
||
margin-bottom: var(--spacing-sm);
|
||
display: block;
|
||
}
|
||
.form-input,
|
||
.form-textarea {
|
||
width: 100%;
|
||
padding: 12px 16px;
|
||
border: 2px solid var(--outline-variant);
|
||
border-radius: var(--radius-md);
|
||
background: var(--surface);
|
||
font-size: 14px;
|
||
transition: all 0.2s ease;
|
||
}
|
||
.form-input:focus,
|
||
.form-textarea:focus {
|
||
outline: none;
|
||
border-color: var(--primary);
|
||
box-shadow: 0 0 0 3px rgba(0, 0, 0, 0.1);
|
||
}
|
||
.form-textarea {
|
||
resize: vertical;
|
||
min-height: 120px;
|
||
}
|
||
.form-help {
|
||
font-size: 12px;
|
||
color: var(--on-surface-variant);
|
||
}
|
||
.form-error {
|
||
font-size: 12px;
|
||
color: var(--error);
|
||
}
|
||
|
||
/* ========== Radio Buttons ========== */
|
||
.radio-grid {
|
||
display: grid;
|
||
gap: var(--spacing-md);
|
||
}
|
||
.radio-option,
|
||
.radio-card {
|
||
display: flex;
|
||
align-items: center;
|
||
gap: var(--spacing-md);
|
||
padding: var(--spacing-md);
|
||
border: 2px solid var(--outline-variant);
|
||
border-radius: var(--radius-md);
|
||
cursor: pointer;
|
||
background: var(--surface);
|
||
transition: all 0.2s ease;
|
||
}
|
||
.radio-option:hover,
|
||
.radio-card:hover {
|
||
border-color: var(--primary);
|
||
background: var(--surface-variant);
|
||
}
|
||
.radio-option.selected,
|
||
.radio-card.selected {
|
||
border-color: var(--primary);
|
||
}
|
||
|
||
/* ========== Results ========== */
|
||
.results-container {
|
||
background: var(--surface);
|
||
border: 1px solid var(--outline-variant);
|
||
border-radius: var(--radius-lg);
|
||
padding: var(--spacing-xl);
|
||
}
|
||
.results-content {
|
||
background: var(--surface-variant);
|
||
padding: var(--spacing-xl);
|
||
border-radius: var(--radius-md);
|
||
font-size: 15px;
|
||
line-height: 1.7;
|
||
}
|
||
.results-content h1,
|
||
.results-content h2,
|
||
.results-content h3 {
|
||
font-weight: 700;
|
||
color: var(--primary);
|
||
}
|
||
.results-content h1 {
|
||
font-size: 24px;
|
||
border-bottom: 3px solid var(--primary);
|
||
padding-bottom: var(--spacing-sm);
|
||
margin-bottom: var(--spacing-lg);
|
||
}
|
||
.results-content h2 {
|
||
font-size: 20px;
|
||
position: relative;
|
||
padding-left: var(--spacing-md);
|
||
}
|
||
.results-content h2::before {
|
||
content: '';
|
||
position: absolute;
|
||
left: 0;
|
||
top: 0;
|
||
bottom: 0;
|
||
width: 4px;
|
||
background: var(--primary);
|
||
}
|
||
.results-content h3 {
|
||
font-size: 18px;
|
||
background: linear-gradient(135deg, #f8f9fa 0%, #e9ecef 100%);
|
||
border-left: 4px solid var(--primary);
|
||
padding: var(--spacing-md);
|
||
}
|
||
|
||
/* ========== Responsive ========== */
|
||
@media (max-width: 768px) {
|
||
.agent-header {
|
||
flex-direction: column;
|
||
align-items: flex-start;
|
||
gap: var(--spacing-sm);
|
||
}
|
||
.agent-title {
|
||
font-size: 24px;
|
||
}
|
||
.wallet-card {
|
||
padding: var(--spacing-lg);
|
||
}
|
||
.balance-amount {
|
||
font-size: 28px;
|
||
}
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## ✅ What's Next?
|
||
|
||
* Place this file at: `static/css/theme.css`
|
||
* Link it in all agent templates using `{% static %}`
|
||
* Remove embedded `<style>` blocks from individual templates
|
||
|
||
---
|
||
|
||
Would you like me to now refactor either `data_analyzer.html` or `weather_reporter.html` to use this new theme and component system?
|
||
|