mirror of
https://github.com/thecyberlearn/quantum-ai-v2.git
synced 2026-08-18 20:32:58 +00:00
Compare commits
No commits in common. "main" and "v1.0-working" have entirely different histories.
main
...
v1.0-worki
@ -4,10 +4,6 @@ DEBUG=True
|
||||
ALLOWED_HOSTS=localhost,127.0.0.1,your-domain.com
|
||||
CSRF_TRUSTED_ORIGINS=http://localhost:8000,http://127.0.0.1:8000
|
||||
|
||||
# Email Verification
|
||||
# Set to False to bypass email verification for testing (until final domain is ready)
|
||||
REQUIRE_EMAIL_VERIFICATION=True
|
||||
|
||||
# Database Configuration
|
||||
# Default: SQLite (simple, reliable, no setup required)
|
||||
# Railway: Automatically uses PostgreSQL via DATABASE_URL
|
||||
|
||||
156
CLAUDE.md
156
CLAUDE.md
@ -4,15 +4,13 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
||||
|
||||
## Project Overview
|
||||
|
||||
Quantum Tasks AI is a Django-based AI agent marketplace platform. Users can access AI agent services through a web interface, with execution handled via two distinct systems: N8N webhook integrations and direct form access integrations.
|
||||
Quantum Tasks AI is a Django-based AI agent marketplace platform. Users can purchase AI agent services through a web interface, with agent execution handled via N8N webhooks and payments processed through Stripe.
|
||||
|
||||
**Key Architecture:**
|
||||
- **Django Framework**: Main web application using Django 5.2.4
|
||||
- **Agent System**: Database-driven agents app with dual integration systems:
|
||||
- **Webhook Agents**: N8N integrations for complex processing
|
||||
- **Direct Access Agents**: Form-based integrations (JotForm, etc.)
|
||||
- **Agent System**: Database-driven agents app with marketplace and N8N webhook execution
|
||||
- **Authentication**: Custom user model with email verification
|
||||
- **Payments**: Stripe integration with wallet system (supports free agents)
|
||||
- **Payments**: Stripe integration with wallet system
|
||||
- **Database**: SQLite for development, PostgreSQL for production (Railway)
|
||||
- **Static Files**: WhiteNoise for production static file serving
|
||||
|
||||
@ -103,27 +101,17 @@ gunicorn netcop_hub.wsgi:application
|
||||
|
||||
### Agent System (agents app)
|
||||
**Key Files:**
|
||||
- `agents/models.py`: Agent, AgentCategory, AgentExecution, ChatSession models
|
||||
- `agents/views.py`: Dual integration systems and web interface views
|
||||
- `agents/templates/agents/`: Dynamic agent templates and marketplace
|
||||
- `agents/models.py`: Agent, AgentCategory, AgentExecution models
|
||||
- `agents/views.py`: REST API and web interface views
|
||||
- `agents/templates/agents/`: Dynamic agent templates with form generation
|
||||
- `agents/management/commands/`: Agent creation and management commands
|
||||
- `templates/career_navigator.html`: Direct access form template
|
||||
|
||||
**Dual Integration Systems:**
|
||||
|
||||
**System 1: Webhook Agents (N8N Integration)**
|
||||
**Agent Flow:**
|
||||
1. User browses marketplace (`/agents/`)
|
||||
2. Clicks "Try Now" → Agent detail page (`/agents/{slug}/`)
|
||||
3. Fills dynamic form → Form submission calls `/agents/api/execute/`
|
||||
4. N8N webhook processes request and returns response
|
||||
5. Results displayed with file upload support
|
||||
|
||||
**System 2: Direct Access Agents (Form Integration)**
|
||||
1. User browses marketplace (`/agents/`)
|
||||
2. Clicks special "Try Now" button → Direct access (`/agents/{slug}/access/`)
|
||||
3. Payment processed → Redirect to form page (`/agents/{slug}/`)
|
||||
4. Form displays embedded interface (JotForm, etc.)
|
||||
5. User interacts directly with external form system
|
||||
2. Selects agent and fills dynamic form (`/agents/{slug}/`)
|
||||
3. Form submission creates AgentExecution and calls N8N webhook
|
||||
4. N8N processes request and returns response via webhook
|
||||
5. Results displayed with file upload support and real-time wallet updates
|
||||
|
||||
### Database Models
|
||||
**User Management:**
|
||||
@ -148,21 +136,30 @@ gunicorn netcop_hub.wsgi:application
|
||||
- `STRIPE_SECRET_KEY`, `STRIPE_WEBHOOK_SECRET`: Stripe API keys
|
||||
- `DATABASE_URL`: PostgreSQL connection string (Railway)
|
||||
|
||||
**Current System:**
|
||||
The platform supports **8 total agents** across **6 categories**:
|
||||
- **4 Webhook Agents** (N8N integration): Social Ads Generator, Job Posting Generator, PDF Summarizer, 5 Whys Analyzer
|
||||
- **4 Direct Access Agents** (External forms): CyberSec Career Navigator, AI Brand Strategist, Lean Six Sigma Expert, SWOT Analysis Expert
|
||||
**N8N Webhook URLs:**
|
||||
Agent-specific webhook URLs are stored in the database with each agent. Current working agents (all tested and confirmed working):
|
||||
|
||||
For detailed agent information and creation instructions, see `docs/AGENT_CREATION.md`.
|
||||
1. **Social Ads Generator** (social-ads-generator) - 6.00 AED
|
||||
- Creates compelling social media advertisements
|
||||
- Form fields: description, social_platform, include_emoji, language
|
||||
- Webhook: N8N endpoint for social media ad generation
|
||||
|
||||
2. **Job Posting Generator** (job-posting-generator) - 10.00 AED
|
||||
- Creates professional job postings
|
||||
- Form fields: job_title, company_name, job_description, seniority_level, contract_type, location, language
|
||||
- Webhook: N8N endpoint for job posting generation
|
||||
|
||||
3. **PDF Summarizer** (pdf-summarizer) - 8.00 AED
|
||||
- Analyzes and summarizes PDF documents with file upload
|
||||
- Form fields: pdf_file (file upload with drag-and-drop), summary_type
|
||||
- Webhook: N8N endpoint for PDF processing with multipart file support
|
||||
|
||||
### URL Structure
|
||||
```
|
||||
/ # Homepage (core app)
|
||||
/digital-branding/ # Digital branding services page
|
||||
/auth/ # Authentication (login, register, etc.)
|
||||
/agents/ # Agent marketplace (agents app)
|
||||
/agents/{slug}/ # Individual agent pages (webhook agents)
|
||||
/agents/{slug}/access/ # Direct access agent payment processing
|
||||
/agents/{slug}/ # Individual agent pages
|
||||
/wallet/ # Wallet management
|
||||
/admin/ # Django admin
|
||||
```
|
||||
@ -180,16 +177,53 @@ For detailed agent information and creation instructions, see `docs/AGENT_CREATI
|
||||
|
||||
## Adding New Agents
|
||||
|
||||
For comprehensive agent creation instructions, see **`docs/AGENT_CREATION.md`**.
|
||||
1. **Create management command** (recommended approach):
|
||||
```python
|
||||
# agents/management/commands/create_new_agent.py
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
**Quick Summary:**
|
||||
1. Create JSON config in `agents/configs/agents/your-agent-name.json`
|
||||
2. Run `python manage.py populate_agents`
|
||||
3. Agent appears in marketplace automatically
|
||||
class Command(BaseCommand):
|
||||
def handle(self, *args, **options):
|
||||
category, _ = AgentCategory.objects.get_or_create(
|
||||
slug='category-slug',
|
||||
defaults={'name': 'Category Name', 'icon': '🤖'}
|
||||
)
|
||||
|
||||
The platform supports 2 agent types:
|
||||
- **Webhook Agents** - N8N integration with dynamic forms
|
||||
- **Direct Access Agents** - External forms (JotForm, etc.) with embedded interfaces
|
||||
Agent.objects.get_or_create(
|
||||
slug='agent-slug',
|
||||
defaults={
|
||||
'name': 'Agent Name',
|
||||
'short_description': 'Brief description',
|
||||
'description': 'Full description',
|
||||
'category': category,
|
||||
'price': 10.0,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'input_field',
|
||||
'type': 'text',
|
||||
'label': 'Input Field',
|
||||
'required': True
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'http://your-n8n-webhook-url'
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
2. **Run the command**: `python manage.py create_new_agent`
|
||||
3. **Update N8N workflow** to handle the new agent
|
||||
4. **Agent will automatically appear** in marketplace with dynamic form generation
|
||||
|
||||
**Supported Form Field Types:**
|
||||
- `text`: Text input
|
||||
- `textarea`: Multi-line text
|
||||
- `select`: Dropdown with options
|
||||
- `file`: File upload with drag-and-drop
|
||||
- `url`: URL input with validation
|
||||
- `checkbox`: Boolean checkbox
|
||||
|
||||
## Production Deployment
|
||||
|
||||
@ -236,39 +270,23 @@ The platform supports 2 agent types:
|
||||
|
||||
## System Status
|
||||
|
||||
**Current Status: ✅ STABLE COMPREHENSIVE SYSTEM**
|
||||
- **8 agents** confirmed working and tested (4 webhook + 4 direct access)
|
||||
- **6 categories** with clean, logical organization
|
||||
- **Dual integration architecture** with clear separation and documentation
|
||||
- **Streamlined agent creation** via JSON configs + `populate_agents` command
|
||||
- **Scalable architecture** ready for 100+ agents
|
||||
|
||||
**Current Agents:**
|
||||
- **Webhook Agents (4)**: Social Ads Generator, Job Posting Generator, PDF Summarizer, 5 Whys Analyzer
|
||||
- **Direct Access Agents (4)**: CyberSec Career Navigator, AI Brand Strategist, Lean Six Sigma Expert, SWOT Analysis Expert
|
||||
**Current Status: ✅ STABLE WORKING SYSTEM**
|
||||
- All 3 agents confirmed working and tested
|
||||
- Clean agents-only architecture (workflows app completely removed)
|
||||
- Emergency recovery completed from optimization failures
|
||||
- System restored to stable commit 657712f
|
||||
|
||||
**Latest Changes:**
|
||||
- **Added SWOT Analysis Expert** with proper category assignment (analysis)
|
||||
- **Streamlined agent creation process** to use only JSON + `populate_agents`
|
||||
- **Separated documentation** into focused files (`docs/AGENT_CREATION.md`)
|
||||
- **Removed 10+ redundant management commands** for cleaner codebase
|
||||
- **Fixed marketplace consistency** and updated documentation
|
||||
|
||||
**Architecture Status:**
|
||||
- **Error-free agent creation** via JSON configuration approach
|
||||
- **Railway-ready deployment** with automatic agent population
|
||||
- **Consistent UI standards** across all marketplace components
|
||||
- **Comprehensive documentation** prevents common development mistakes
|
||||
- Removed workflows app completely for simplified architecture
|
||||
- Enhanced agent marketplace with modern responsive design
|
||||
- Fixed all authentication-aware UI components
|
||||
- Implemented file upload support for PDF Summarizer
|
||||
- Real-time wallet balance updates after agent execution
|
||||
|
||||
**Future Development:**
|
||||
- **New agents** should follow patterns in `docs/AGENT_CREATION.md`
|
||||
- **Use existing categories first** to avoid unnecessary proliferation
|
||||
- **JSON + populate_agents** is the only supported creation method
|
||||
- Optimization work available in feature/optimization-backup branch
|
||||
- Safe to add new agents via database-driven approach
|
||||
- Performance optimizations should be applied incrementally with testing
|
||||
|
||||
---
|
||||
Last updated: 2025-01-08
|
||||
|
||||
## Documentation
|
||||
- **Quick Agent Requests**: See `docs/AGENT_REQUEST_TEMPLATE.md` for simple agent request template
|
||||
- **Agent Creation**: See `docs/AGENT_CREATION.md` for comprehensive agent creation guide
|
||||
- **Project Overview**: This file (CLAUDE.md) for Django development and architecture
|
||||
Last updated: Last updated: 2025-08-01 01:37:09
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
from django.contrib import admin
|
||||
from .models import AgentCategory, Agent, AgentExecution, ChatSession, ChatMessage
|
||||
from .models import AgentCategory, Agent, AgentExecution
|
||||
|
||||
@admin.register(AgentCategory)
|
||||
class AgentCategoryAdmin(admin.ModelAdmin):
|
||||
@ -10,8 +10,8 @@ class AgentCategoryAdmin(admin.ModelAdmin):
|
||||
|
||||
@admin.register(Agent)
|
||||
class AgentAdmin(admin.ModelAdmin):
|
||||
list_display = ['name', 'category', 'agent_type', 'price', 'is_active', 'created_at']
|
||||
list_filter = ['category', 'agent_type', 'is_active', 'created_at']
|
||||
list_display = ['name', 'category', 'price', 'is_active', 'created_at']
|
||||
list_filter = ['category', 'is_active', 'created_at']
|
||||
search_fields = ['name', 'description', 'short_description']
|
||||
prepopulated_fields = {'slug': ('name',)}
|
||||
readonly_fields = ['created_at', 'updated_at']
|
||||
@ -22,21 +22,3 @@ class AgentExecutionAdmin(admin.ModelAdmin):
|
||||
list_filter = ['status', 'created_at', 'agent__category']
|
||||
search_fields = ['agent__name', 'user__email']
|
||||
readonly_fields = ['created_at', 'completed_at']
|
||||
|
||||
@admin.register(ChatSession)
|
||||
class ChatSessionAdmin(admin.ModelAdmin):
|
||||
list_display = ['session_id', 'agent', 'user', 'status', 'fee_charged', 'created_at']
|
||||
list_filter = ['status', 'agent__category', 'created_at']
|
||||
search_fields = ['session_id', 'agent__name', 'user__email']
|
||||
readonly_fields = ['session_id', 'created_at', 'updated_at', 'completed_at']
|
||||
|
||||
@admin.register(ChatMessage)
|
||||
class ChatMessageAdmin(admin.ModelAdmin):
|
||||
list_display = ['session', 'message_type', 'content_preview', 'timestamp']
|
||||
list_filter = ['message_type', 'timestamp']
|
||||
search_fields = ['session__session_id', 'content']
|
||||
readonly_fields = ['timestamp']
|
||||
|
||||
def content_preview(self, obj):
|
||||
return obj.content[:50] + "..." if len(obj.content) > 50 else obj.content
|
||||
content_preview.short_description = 'Content Preview'
|
||||
|
||||
@ -1,113 +0,0 @@
|
||||
# Agent Configuration System
|
||||
|
||||
This directory contains JSON configuration files for dynamically creating agents and categories in the Quantum Tasks AI platform.
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
agents/configs/
|
||||
├── categories/
|
||||
│ └── categories.json # All agent categories
|
||||
├── agents/
|
||||
│ ├── ai-brand-strategist.json # Direct access agent
|
||||
│ ├── cybersec-career-navigator.json # Direct access agent
|
||||
│ ├── five-whys-analysis.json # Chat webhook agent
|
||||
│ ├── job-posting-generator.json # Form webhook agent
|
||||
│ ├── pdf-summarizer.json # File upload webhook agent
|
||||
│ └── social-ads-generator.json # Form webhook agent
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## How It Works
|
||||
|
||||
1. **Categories** are defined in `categories/categories.json`
|
||||
2. **Agents** are defined in individual JSON files in `agents/`
|
||||
3. Run `python manage.py populate_agents` to create all agents from configs
|
||||
4. **Adding new agents** is as simple as creating a new JSON file
|
||||
|
||||
## Adding New Agents
|
||||
|
||||
### Step 1: Create JSON Configuration File
|
||||
|
||||
Create a new file in `agents/` directory, e.g., `email-writer.json`:
|
||||
|
||||
```json
|
||||
{
|
||||
"slug": "email-writer",
|
||||
"name": "Email Writer",
|
||||
"short_description": "AI-powered professional email writing assistant",
|
||||
"description": "Generate professional emails for any purpose with AI assistance.",
|
||||
"category": "marketing",
|
||||
"price": 3.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "webhook",
|
||||
"form_schema": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "email_type",
|
||||
"type": "select",
|
||||
"label": "Email Type",
|
||||
"required": true,
|
||||
"options": [
|
||||
{"value": "business", "label": "Business Email"},
|
||||
{"value": "marketing", "label": "Marketing Email"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"webhook_url": "http://localhost:5678/webhook/email-writer",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Run Population Command
|
||||
|
||||
```bash
|
||||
python manage.py populate_agents
|
||||
```
|
||||
|
||||
### Step 3: Agent Appears Automatically
|
||||
|
||||
The agent will now appear in the marketplace with the configured settings.
|
||||
|
||||
## Agent Types
|
||||
|
||||
### Webhook Agents (N8N Integration)
|
||||
- Set `system_type`: `"webhook"`
|
||||
- Include detailed `form_schema` with fields
|
||||
- Set `webhook_url` to N8N endpoint
|
||||
- Leave `access_url_name` and `display_url_name` empty
|
||||
|
||||
### Direct Access Agents (External Forms)
|
||||
- Set `system_type`: `"direct_access"`
|
||||
- Set `form_schema`: `{"fields": []}`
|
||||
- Set `webhook_url` to external form URL (JotForm, etc.)
|
||||
- Set `access_url_name`: `"agents:direct_access_handler"`
|
||||
- Set `display_url_name`: `"agents:direct_access_display"`
|
||||
|
||||
## Field Types for Webhook Agents
|
||||
|
||||
- `text`: Single-line text input
|
||||
- `textarea`: Multi-line text input
|
||||
- `select`: Dropdown with options array
|
||||
- `file`: File upload with drag-and-drop
|
||||
- `url`: URL input with validation
|
||||
- `checkbox`: Boolean checkbox
|
||||
|
||||
## Benefits
|
||||
|
||||
✅ **Scalable**: Add 100+ agents without code changes
|
||||
✅ **Version Controlled**: All agent definitions in git
|
||||
✅ **Consistent**: Ensures local and Railway databases match
|
||||
✅ **Simple**: Just create JSON file and run command
|
||||
✅ **Validated**: Built-in validation and error handling
|
||||
|
||||
## Railway Deployment
|
||||
|
||||
On Railway, just run:
|
||||
```bash
|
||||
python manage.py populate_agents
|
||||
```
|
||||
|
||||
All agents defined in JSON files will be created automatically, ensuring Railway marketplace shows all agents consistently.
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"slug": "ai-brand-strategist",
|
||||
"name": "AI Brand Strategist",
|
||||
"short_description": "Get AI-powered brand strategy insights and recommendations for your business",
|
||||
"description": "Transform your brand with AI-driven strategic insights. Get expert guidance on brand positioning, messaging, visual identity, and competitive differentiation.",
|
||||
"category": "marketing",
|
||||
"price": 0.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "direct_access",
|
||||
"form_schema": {
|
||||
"fields": []
|
||||
},
|
||||
"webhook_url": "https://agent.jotform.com/01986502acd276b48e3d5f39337046c8d9b6",
|
||||
"access_url_name": "agents:direct_access_handler",
|
||||
"display_url_name": "agents:direct_access_display"
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"slug": "cybersec-career-navigator",
|
||||
"name": "CyberSec Career Navigator",
|
||||
"short_description": "Get personalized cybersecurity career guidance from AI expert Jessica",
|
||||
"description": "Navigate your cybersecurity career path with expert AI guidance. Get personalized advice on certifications, job roles, skills development, and career progression.",
|
||||
"category": "career-education",
|
||||
"price": 0.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "direct_access",
|
||||
"form_schema": {
|
||||
"fields": []
|
||||
},
|
||||
"webhook_url": "https://agent.jotform.com/019865a942ab7fa5b5b743a5fd2abe09e345",
|
||||
"access_url_name": "agents:direct_access_handler",
|
||||
"display_url_name": "agents:direct_access_display"
|
||||
}
|
||||
@ -1,14 +0,0 @@
|
||||
{
|
||||
"slug": "five-whys-analysis",
|
||||
"name": "5 Whys Analysis",
|
||||
"short_description": "Interactive problem-solving using the proven 5 Whys methodology",
|
||||
"description": "Systematically find root causes through guided 5 Whys methodology. Perfect for troubleshooting operational problems, understanding failures, and identifying systemic issues.",
|
||||
"category": "analysis",
|
||||
"price": 15.0,
|
||||
"agent_type": "chat",
|
||||
"system_type": "webhook",
|
||||
"form_schema": null,
|
||||
"webhook_url": "http://localhost:5678/webhook/5-whys-web",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
@ -1,55 +0,0 @@
|
||||
{
|
||||
"slug": "job-posting-generator",
|
||||
"name": "Job Posting Generator",
|
||||
"short_description": "Create professional job postings that attract top talent",
|
||||
"description": "Generate comprehensive and attractive job postings with AI-powered content creation. Perfect for HR teams and recruiters.",
|
||||
"category": "human-resources",
|
||||
"price": 10.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "webhook",
|
||||
"form_schema": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "job_title",
|
||||
"type": "text",
|
||||
"label": "Job Title",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "company_name",
|
||||
"type": "text",
|
||||
"label": "Company Name",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "job_description",
|
||||
"type": "textarea",
|
||||
"label": "Job Description",
|
||||
"required": true,
|
||||
"rows": 5
|
||||
},
|
||||
{
|
||||
"name": "seniority_level",
|
||||
"type": "select",
|
||||
"label": "Seniority Level",
|
||||
"required": true,
|
||||
"options": [
|
||||
{"value": "", "label": "Select level..."},
|
||||
{"value": "entry", "label": "Entry Level"},
|
||||
{"value": "junior", "label": "Junior"},
|
||||
{"value": "mid", "label": "Mid Level"},
|
||||
{"value": "senior", "label": "Senior"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "location",
|
||||
"type": "text",
|
||||
"label": "Location",
|
||||
"required": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"webhook_url": "http://localhost:5678/webhook/43f84411-eaaa-488c-9b1f-856e90d0aaf6",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"slug": "lean-six-sigma-expert",
|
||||
"name": "Lean Six Sigma Expert",
|
||||
"short_description": "Get expert guidance on Lean Six Sigma methodologies and process improvement strategies",
|
||||
"description": "Optimize your business processes with expert Lean Six Sigma consultation. Our AI-powered expert provides comprehensive guidance on process improvement, waste reduction, quality enhancement, and operational excellence. Get personalized recommendations for implementing Lean Six Sigma methodologies in your organization.",
|
||||
"category": "consulting",
|
||||
"price": 0.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "direct_access",
|
||||
"form_schema": {
|
||||
"fields": []
|
||||
},
|
||||
"webhook_url": "https://agent.jotform.com/01987b8843ae71129342f62a93d2c605efad",
|
||||
"access_url_name": "agents:direct_access_handler",
|
||||
"display_url_name": "agents:direct_access_display"
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
{
|
||||
"slug": "pdf-summarizer",
|
||||
"name": "PDF Summarizer",
|
||||
"short_description": "Extract and summarize content from PDF documents with AI analysis",
|
||||
"description": "Upload PDF documents and get comprehensive AI-powered summaries, key insights, and analysis. Perfect for processing reports and research papers.",
|
||||
"category": "document-processing",
|
||||
"price": 8.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "webhook",
|
||||
"form_schema": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "pdf_file",
|
||||
"type": "file",
|
||||
"label": "Upload PDF Document",
|
||||
"required": true,
|
||||
"accept": ".pdf",
|
||||
"max_size": "10MB"
|
||||
},
|
||||
{
|
||||
"name": "analysis_type",
|
||||
"type": "select",
|
||||
"label": "Analysis Type",
|
||||
"required": true,
|
||||
"default": "summary",
|
||||
"options": [
|
||||
{"value": "", "label": "Select analysis type..."},
|
||||
{"value": "summary", "label": "Document Summary"},
|
||||
{"value": "key_points", "label": "Key Points Extraction"},
|
||||
{"value": "detailed_analysis", "label": "Detailed Analysis"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"webhook_url": "http://localhost:5678/webhook/simple-pdf-processor",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
@ -1,49 +0,0 @@
|
||||
{
|
||||
"slug": "social-ads-generator",
|
||||
"name": "Social Ads Generator",
|
||||
"short_description": "Create compelling social media advertisements optimized for different platforms",
|
||||
"description": "Generate engaging social media advertisements with AI-powered content generation. Optimized for Facebook, Instagram, LinkedIn, Twitter, TikTok, and YouTube.",
|
||||
"category": "marketing",
|
||||
"price": 6.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "webhook",
|
||||
"form_schema": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "description",
|
||||
"type": "textarea",
|
||||
"label": "Describe what you'd like to generate",
|
||||
"placeholder": "Describe the product, service, or campaign",
|
||||
"required": true,
|
||||
"rows": 4
|
||||
},
|
||||
{
|
||||
"name": "social_platform",
|
||||
"type": "select",
|
||||
"label": "For Social Media Platform",
|
||||
"required": true,
|
||||
"options": [
|
||||
{"value": "", "label": "Select a platform..."},
|
||||
{"value": "facebook", "label": "Facebook"},
|
||||
{"value": "instagram", "label": "Instagram"},
|
||||
{"value": "linkedin", "label": "LinkedIn"},
|
||||
{"value": "twitter", "label": "X (Twitter)"}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "include_emoji",
|
||||
"type": "select",
|
||||
"label": "Include Emoji",
|
||||
"required": true,
|
||||
"options": [
|
||||
{"value": "", "label": "Select an option..."},
|
||||
{"value": "yes", "label": "Yes"},
|
||||
{"value": "no", "label": "No"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"webhook_url": "http://localhost:5678/webhook/2dc234d8-7217-454a-83e9-81afe5b4fe2d",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
@ -1,16 +0,0 @@
|
||||
{
|
||||
"slug": "swot-analysis-expert",
|
||||
"name": "SWOT Analysis Expert",
|
||||
"short_description": "Strategic business analysis consultation",
|
||||
"description": "Get expert SWOT analysis to evaluate your business strengths, weaknesses, opportunities, and threats with professional strategic insights.",
|
||||
"category": "analysis",
|
||||
"price": 0.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "direct_access",
|
||||
"form_schema": {
|
||||
"fields": []
|
||||
},
|
||||
"webhook_url": "https://agent.jotform.com/019880edcf997a41a2b4c50daa850a50a0b9",
|
||||
"access_url_name": "agents:direct_access_handler",
|
||||
"display_url_name": "agents:direct_access_display"
|
||||
}
|
||||
@ -1,38 +0,0 @@
|
||||
[
|
||||
{
|
||||
"slug": "analysis",
|
||||
"name": "Analysis & Problem Solving",
|
||||
"description": "AI-powered analysis tools for problem-solving and decision making",
|
||||
"icon": "🧠"
|
||||
},
|
||||
{
|
||||
"slug": "career-education",
|
||||
"name": "Career & Education",
|
||||
"description": "Professional career guidance and educational resources",
|
||||
"icon": "🎓"
|
||||
},
|
||||
{
|
||||
"slug": "document-processing",
|
||||
"name": "Document Processing",
|
||||
"description": "AI-powered document analysis and processing tools",
|
||||
"icon": "📄"
|
||||
},
|
||||
{
|
||||
"slug": "human-resources",
|
||||
"name": "Human Resources",
|
||||
"description": "HR automation and talent management solutions",
|
||||
"icon": "💼"
|
||||
},
|
||||
{
|
||||
"slug": "marketing",
|
||||
"name": "Marketing & Advertising",
|
||||
"description": "AI-powered marketing tools and advertising solutions",
|
||||
"icon": "📢"
|
||||
},
|
||||
{
|
||||
"slug": "consulting",
|
||||
"name": "Business Consulting",
|
||||
"description": "Professional business consultation and strategy services",
|
||||
"icon": "💼"
|
||||
}
|
||||
]
|
||||
@ -1,30 +0,0 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
from agents.models import ChatSession
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Mark expired chat sessions as expired'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
now = timezone.now()
|
||||
|
||||
# Find active sessions that have expired
|
||||
expired_sessions = ChatSession.objects.filter(
|
||||
status='active',
|
||||
expires_at__lt=now
|
||||
)
|
||||
|
||||
count = expired_sessions.count()
|
||||
|
||||
if count > 0:
|
||||
# Mark them as expired
|
||||
expired_sessions.update(
|
||||
status='expired',
|
||||
completed_at=now
|
||||
)
|
||||
|
||||
self.stdout.write(
|
||||
self.style.SUCCESS(f'✅ Marked {count} expired sessions as expired')
|
||||
)
|
||||
else:
|
||||
self.stdout.write('✅ No expired sessions found')
|
||||
130
agents/management/commands/create_job_posting_agent.py
Normal file
130
agents/management/commands/create_job_posting_agent.py
Normal file
@ -0,0 +1,130 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Create job posting generator agent'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get or use existing HR category
|
||||
hr_category, created = AgentCategory.objects.get_or_create(
|
||||
slug='human-resources',
|
||||
defaults={
|
||||
'name': 'Human Resources',
|
||||
'description': 'AI-powered HR and recruitment tools',
|
||||
'icon': '💼'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created category: {hr_category.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Category already exists: {hr_category.name}')
|
||||
|
||||
# Create Job Posting Generator agent
|
||||
job_posting_agent, created = Agent.objects.get_or_create(
|
||||
slug='job-posting-generator',
|
||||
defaults={
|
||||
'name': 'Job Posting Generator',
|
||||
'short_description': 'Create professional job postings that attract top talent',
|
||||
'description': 'Generate comprehensive and attractive job postings with AI-powered content creation. Perfect for HR teams and recruiters looking to create compelling job descriptions that attract qualified candidates. Supports multiple languages, locations, and contract types.',
|
||||
'category': hr_category,
|
||||
'price': 10.0,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'job_title',
|
||||
'type': 'text',
|
||||
'label': 'Job Title',
|
||||
'placeholder': 'e.g., Senior Full Stack Developer',
|
||||
'required': True,
|
||||
'help_text': 'The position title for the job posting'
|
||||
},
|
||||
{
|
||||
'name': 'company_name',
|
||||
'type': 'text',
|
||||
'label': 'Company Name',
|
||||
'placeholder': 'e.g., Quantum Technologies Inc.',
|
||||
'required': True,
|
||||
'help_text': 'Name of the hiring company'
|
||||
},
|
||||
{
|
||||
'name': 'job_description',
|
||||
'type': 'textarea',
|
||||
'label': 'Job Description',
|
||||
'placeholder': 'Describe the role, responsibilities, and what makes this opportunity exciting...',
|
||||
'required': True,
|
||||
'rows': 5,
|
||||
'help_text': 'Detailed description of the role, responsibilities, and company culture'
|
||||
},
|
||||
{
|
||||
'name': 'seniority_level',
|
||||
'type': 'select',
|
||||
'label': 'Seniority Level',
|
||||
'required': True,
|
||||
'options': [
|
||||
{'value': '', 'label': 'Select seniority level...'},
|
||||
{'value': 'entry', 'label': 'Entry Level'},
|
||||
{'value': 'junior', 'label': 'Junior'},
|
||||
{'value': 'mid', 'label': 'Mid Level'},
|
||||
{'value': 'senior', 'label': 'Senior'},
|
||||
{'value': 'lead', 'label': 'Lead'},
|
||||
{'value': 'principal', 'label': 'Principal'},
|
||||
{'value': 'executive', 'label': 'Executive'}
|
||||
],
|
||||
'help_text': 'Experience level required for this position'
|
||||
},
|
||||
{
|
||||
'name': 'contract_type',
|
||||
'type': 'select',
|
||||
'label': 'Contract Type',
|
||||
'required': True,
|
||||
'options': [
|
||||
{'value': '', 'label': 'Select contract type...'},
|
||||
{'value': 'full-time', 'label': 'Full-time'},
|
||||
{'value': 'part-time', 'label': 'Part-time'},
|
||||
{'value': 'contract', 'label': 'Contract'},
|
||||
{'value': 'freelance', 'label': 'Freelance'},
|
||||
{'value': 'internship', 'label': 'Internship'},
|
||||
{'value': 'temporary', 'label': 'Temporary'}
|
||||
],
|
||||
'help_text': 'Type of employment contract'
|
||||
},
|
||||
{
|
||||
'name': 'location',
|
||||
'type': 'text',
|
||||
'label': 'Location',
|
||||
'placeholder': 'e.g., Dubai, UAE (Remote)',
|
||||
'required': True,
|
||||
'help_text': 'Job location, include if remote work is available'
|
||||
},
|
||||
{
|
||||
'name': 'language',
|
||||
'type': 'select',
|
||||
'label': 'Language',
|
||||
'required': False,
|
||||
'default': 'English',
|
||||
'options': [
|
||||
{'value': 'English', 'label': 'English'},
|
||||
{'value': 'Arabic', 'label': 'Arabic (العربية)'},
|
||||
{'value': 'Spanish', 'label': 'Spanish (Español)'},
|
||||
{'value': 'French', 'label': 'French (Français)'},
|
||||
{'value': 'German', 'label': 'German (Deutsch)'},
|
||||
{'value': 'Chinese', 'label': 'Chinese (中文)'}
|
||||
],
|
||||
'help_text': 'Primary language for the job posting'
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'http://localhost:5678/webhook/43f84411-eaaa-488c-9b1f-856e90d0aaf6'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created agent: {job_posting_agent.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Agent already exists: {job_posting_agent.name}')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Job Posting Generator setup completed successfully'))
|
||||
self.stdout.write(f'Agent ID: {job_posting_agent.id}')
|
||||
self.stdout.write(f'Agent Slug: {job_posting_agent.slug}')
|
||||
self.stdout.write(f'Price: {job_posting_agent.price} AED')
|
||||
104
agents/management/commands/create_pdf_summarizer_agent.py
Normal file
104
agents/management/commands/create_pdf_summarizer_agent.py
Normal file
@ -0,0 +1,104 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Create PDF summarizer agent'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Get or create Document Processing category
|
||||
doc_category, created = AgentCategory.objects.get_or_create(
|
||||
slug='document-processing',
|
||||
defaults={
|
||||
'name': 'Document Processing',
|
||||
'description': 'AI-powered document analysis and processing tools',
|
||||
'icon': '📄'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created category: {doc_category.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Category already exists: {doc_category.name}')
|
||||
|
||||
# Create PDF Summarizer agent
|
||||
pdf_summarizer_agent, created = Agent.objects.get_or_create(
|
||||
slug='pdf-summarizer',
|
||||
defaults={
|
||||
'name': 'PDF Summarizer',
|
||||
'short_description': 'Extract and summarize content from PDF documents with AI analysis',
|
||||
'description': 'Upload PDF documents and get comprehensive AI-powered summaries, key insights, and analysis. Perfect for processing reports, research papers, contracts, and other documents. Supports multiple analysis types including summary, key points extraction, and sentiment analysis.',
|
||||
'category': doc_category,
|
||||
'price': 8.0,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'pdf_file',
|
||||
'type': 'file',
|
||||
'label': 'Upload PDF Document',
|
||||
'required': True,
|
||||
'accept': '.pdf',
|
||||
'max_size': '10MB',
|
||||
'help_text': 'Select a PDF file to analyze (max 10MB)'
|
||||
},
|
||||
{
|
||||
'name': 'analysis_type',
|
||||
'type': 'select',
|
||||
'label': 'Analysis Type',
|
||||
'required': True,
|
||||
'default': 'summary',
|
||||
'options': [
|
||||
{'value': '', 'label': 'Select analysis type...'},
|
||||
{'value': 'summary', 'label': 'Document Summary'},
|
||||
{'value': 'key_points', 'label': 'Key Points Extraction'},
|
||||
{'value': 'detailed_analysis', 'label': 'Detailed Analysis'},
|
||||
{'value': 'sentiment', 'label': 'Sentiment Analysis'},
|
||||
{'value': 'questions', 'label': 'Generate Questions'},
|
||||
{'value': 'action_items', 'label': 'Extract Action Items'}
|
||||
],
|
||||
'help_text': 'Choose the type of analysis to perform on the document'
|
||||
},
|
||||
{
|
||||
'name': 'language',
|
||||
'type': 'select',
|
||||
'label': 'Document Language',
|
||||
'required': False,
|
||||
'default': 'auto',
|
||||
'options': [
|
||||
{'value': 'auto', 'label': 'Auto-detect'},
|
||||
{'value': 'English', 'label': 'English'},
|
||||
{'value': 'Arabic', 'label': 'Arabic (العربية)'},
|
||||
{'value': 'Spanish', 'label': 'Spanish (Español)'},
|
||||
{'value': 'French', 'label': 'French (Français)'},
|
||||
{'value': 'German', 'label': 'German (Deutsch)'},
|
||||
{'value': 'Chinese', 'label': 'Chinese (中文)'}
|
||||
],
|
||||
'help_text': 'Specify document language for better analysis accuracy'
|
||||
},
|
||||
{
|
||||
'name': 'output_length',
|
||||
'type': 'select',
|
||||
'label': 'Summary Length',
|
||||
'required': False,
|
||||
'default': 'medium',
|
||||
'options': [
|
||||
{'value': 'short', 'label': 'Short (1-2 paragraphs)'},
|
||||
{'value': 'medium', 'label': 'Medium (3-5 paragraphs)'},
|
||||
{'value': 'long', 'label': 'Long (detailed summary)'}
|
||||
],
|
||||
'help_text': 'Choose the desired length of the analysis output'
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'http://localhost:5678/webhook/simple-pdf-processor'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created agent: {pdf_summarizer_agent.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Agent already exists: {pdf_summarizer_agent.name}')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('PDF Summarizer setup completed successfully'))
|
||||
self.stdout.write(f'Agent ID: {pdf_summarizer_agent.id}')
|
||||
self.stdout.write(f'Agent Slug: {pdf_summarizer_agent.slug}')
|
||||
self.stdout.write(f'Price: {pdf_summarizer_agent.price} AED')
|
||||
151
agents/management/commands/create_sample_agents.py
Normal file
151
agents/management/commands/create_sample_agents.py
Normal file
@ -0,0 +1,151 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Create sample agents for testing'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Create categories
|
||||
ai_category, _ = AgentCategory.objects.get_or_create(
|
||||
slug='ai-tools',
|
||||
defaults={
|
||||
'name': 'AI Tools',
|
||||
'description': 'AI-powered automation tools',
|
||||
'icon': '🤖'
|
||||
}
|
||||
)
|
||||
|
||||
data_category, _ = AgentCategory.objects.get_or_create(
|
||||
slug='data-analysis',
|
||||
defaults={
|
||||
'name': 'Data Analysis',
|
||||
'description': 'Data processing and analysis tools',
|
||||
'icon': '📊'
|
||||
}
|
||||
)
|
||||
|
||||
web_category, _ = AgentCategory.objects.get_or_create(
|
||||
slug='web-scraping',
|
||||
defaults={
|
||||
'name': 'Web Scraping',
|
||||
'description': 'Web data extraction tools',
|
||||
'icon': '🕷️'
|
||||
}
|
||||
)
|
||||
|
||||
# Create sample agents
|
||||
Agent.objects.get_or_create(
|
||||
slug='pdf-analyzer',
|
||||
defaults={
|
||||
'name': 'PDF Content Analyzer',
|
||||
'short_description': 'Extract and analyze content from PDF documents',
|
||||
'description': 'This agent processes PDF files and extracts meaningful insights including summaries, keywords, and sentiment analysis. Perfect for document processing workflows.',
|
||||
'category': ai_category,
|
||||
'price': 5.00,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'pdf_url',
|
||||
'type': 'url',
|
||||
'label': 'PDF URL',
|
||||
'placeholder': 'https://example.com/document.pdf',
|
||||
'required': True
|
||||
},
|
||||
{
|
||||
'name': 'analysis_type',
|
||||
'type': 'select',
|
||||
'label': 'Analysis Type',
|
||||
'options': [
|
||||
{'value': 'summary', 'label': 'Summary'},
|
||||
{'value': 'keywords', 'label': 'Keywords'},
|
||||
{'value': 'sentiment', 'label': 'Sentiment Analysis'}
|
||||
],
|
||||
'required': True
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'https://your-n8n-instance.com/webhook/pdf-analyzer'
|
||||
}
|
||||
)
|
||||
|
||||
Agent.objects.get_or_create(
|
||||
slug='website-scraper',
|
||||
defaults={
|
||||
'name': 'Website Data Scraper',
|
||||
'short_description': 'Extract structured data from any website',
|
||||
'description': 'Advanced web scraping agent that can extract specific data from websites using CSS selectors or XPath. Handles JavaScript-rendered content and returns clean, structured data.',
|
||||
'category': web_category,
|
||||
'price': 3.00,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'website_url',
|
||||
'type': 'url',
|
||||
'label': 'Website URL',
|
||||
'placeholder': 'https://example.com',
|
||||
'required': True
|
||||
},
|
||||
{
|
||||
'name': 'selectors',
|
||||
'type': 'textarea',
|
||||
'label': 'CSS Selectors (one per line)',
|
||||
'placeholder': 'h1.title\n.price\n.description',
|
||||
'required': True
|
||||
},
|
||||
{
|
||||
'name': 'wait_for_js',
|
||||
'type': 'checkbox',
|
||||
'label': 'Wait for JavaScript to load',
|
||||
'required': False
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'https://your-n8n-instance.com/webhook/website-scraper'
|
||||
}
|
||||
)
|
||||
|
||||
Agent.objects.get_or_create(
|
||||
slug='data-analyzer',
|
||||
defaults={
|
||||
'name': 'CSV Data Analyzer',
|
||||
'short_description': 'Analyze and visualize CSV data with insights',
|
||||
'description': 'Upload CSV files and get comprehensive data analysis including statistics, trends, and visualizations. Perfect for business intelligence and data exploration.',
|
||||
'category': data_category,
|
||||
'price': 4.50,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'csv_url',
|
||||
'type': 'url',
|
||||
'label': 'CSV File URL',
|
||||
'placeholder': 'https://example.com/data.csv',
|
||||
'required': True
|
||||
},
|
||||
{
|
||||
'name': 'analysis_columns',
|
||||
'type': 'text',
|
||||
'label': 'Columns to Analyze (comma-separated)',
|
||||
'placeholder': 'sales,revenue,date',
|
||||
'required': False
|
||||
},
|
||||
{
|
||||
'name': 'chart_type',
|
||||
'type': 'select',
|
||||
'label': 'Chart Type',
|
||||
'options': [
|
||||
{'value': 'line', 'label': 'Line Chart'},
|
||||
{'value': 'bar', 'label': 'Bar Chart'},
|
||||
{'value': 'pie', 'label': 'Pie Chart'},
|
||||
{'value': 'scatter', 'label': 'Scatter Plot'}
|
||||
],
|
||||
'required': False
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'https://your-n8n-instance.com/webhook/data-analyzer'
|
||||
}
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Sample agents created successfully'))
|
||||
self.stdout.write(f'Created categories: {AgentCategory.objects.count()}')
|
||||
self.stdout.write(f'Created agents: {Agent.objects.count()}')
|
||||
101
agents/management/commands/create_social_ads_agent.py
Normal file
101
agents/management/commands/create_social_ads_agent.py
Normal file
@ -0,0 +1,101 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Create social ads agent for testing'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
# Create Marketing category
|
||||
marketing_category, created = AgentCategory.objects.get_or_create(
|
||||
slug='marketing',
|
||||
defaults={
|
||||
'name': 'Marketing & Advertising',
|
||||
'description': 'AI-powered marketing and advertising tools',
|
||||
'icon': '📢'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created category: {marketing_category.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Category already exists: {marketing_category.name}')
|
||||
|
||||
# Create Social Ads Generator agent
|
||||
social_ads_agent, created = Agent.objects.get_or_create(
|
||||
slug='social-ads-generator',
|
||||
defaults={
|
||||
'name': 'Social Ads Generator',
|
||||
'short_description': 'Create compelling social media advertisements optimized for different platforms',
|
||||
'description': 'Generate engaging social media advertisements with AI-powered content generation. Optimized for Facebook, Instagram, LinkedIn, Twitter, TikTok, and YouTube. Includes platform-specific formatting, emoji support, and multi-language capabilities.',
|
||||
'category': marketing_category,
|
||||
'price': 6.0,
|
||||
'form_schema': {
|
||||
'fields': [
|
||||
{
|
||||
'name': 'description',
|
||||
'type': 'textarea',
|
||||
'label': 'Describe what you\'d like to generate',
|
||||
'placeholder': 'Describe the product, service, or campaign you want to create an ad for. Include key features, target audience, and any specific messaging you want to emphasize.',
|
||||
'required': True,
|
||||
'rows': 4,
|
||||
'help_text': 'Provide clear, specific information about your product or service for better ad copy'
|
||||
},
|
||||
{
|
||||
'name': 'social_platform',
|
||||
'type': 'select',
|
||||
'label': 'For Social Media Platform',
|
||||
'required': True,
|
||||
'options': [
|
||||
{'value': '', 'label': 'Select a platform...'},
|
||||
{'value': 'facebook', 'label': 'Facebook'},
|
||||
{'value': 'instagram', 'label': 'Instagram'},
|
||||
{'value': 'linkedin', 'label': 'LinkedIn'},
|
||||
{'value': 'twitter', 'label': 'X (Twitter)'},
|
||||
{'value': 'tiktok', 'label': 'TikTok'},
|
||||
{'value': 'youtube', 'label': 'YouTube'}
|
||||
],
|
||||
'help_text': 'Choose the social media platform for optimization'
|
||||
},
|
||||
{
|
||||
'name': 'include_emoji',
|
||||
'type': 'select',
|
||||
'label': 'Include Emoji',
|
||||
'required': True,
|
||||
'options': [
|
||||
{'value': '', 'label': 'Select an option...'},
|
||||
{'value': 'yes', 'label': 'Yes'},
|
||||
{'value': 'no', 'label': 'No'}
|
||||
],
|
||||
'help_text': 'Whether to include emojis in the ad copy'
|
||||
},
|
||||
{
|
||||
'name': 'language',
|
||||
'type': 'select',
|
||||
'label': 'Language',
|
||||
'required': False,
|
||||
'default': 'English',
|
||||
'options': [
|
||||
{'value': 'English', 'label': 'English'},
|
||||
{'value': 'Arabic', 'label': 'Arabic (العربية)'},
|
||||
{'value': 'Spanish', 'label': 'Spanish (Español)'},
|
||||
{'value': 'French', 'label': 'French (Français)'},
|
||||
{'value': 'German', 'label': 'German (Deutsch)'},
|
||||
{'value': 'Chinese', 'label': 'Chinese (中文)'}
|
||||
],
|
||||
'help_text': 'Select the primary language for the ad copy'
|
||||
}
|
||||
]
|
||||
},
|
||||
'webhook_url': 'http://localhost:5678/webhook/2dc234d8-7217-454a-83e9-81afe5b4fe2d'
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
self.stdout.write(self.style.SUCCESS(f'Created agent: {social_ads_agent.name}'))
|
||||
else:
|
||||
self.stdout.write(f'Agent already exists: {social_ads_agent.name}')
|
||||
|
||||
self.stdout.write(self.style.SUCCESS('Social Ads Agent setup completed successfully'))
|
||||
self.stdout.write(f'Agent ID: {social_ads_agent.id}')
|
||||
self.stdout.write(f'Agent Slug: {social_ads_agent.slug}')
|
||||
self.stdout.write(f'Price: {social_ads_agent.price} AED')
|
||||
@ -1,142 +0,0 @@
|
||||
import json
|
||||
import os
|
||||
from pathlib import Path
|
||||
from django.core.management.base import BaseCommand
|
||||
from agents.models import AgentCategory, Agent
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Dynamically populate all agents and categories from JSON configuration files'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
self.stdout.write(self.style.SUCCESS('🚀 Dynamically populating agents from configuration files...'))
|
||||
self.stdout.write('')
|
||||
|
||||
# Track creation statistics
|
||||
categories_created = 0
|
||||
agents_created = 0
|
||||
config_base_path = Path(__file__).parent.parent.parent / 'configs'
|
||||
|
||||
# Load and create categories
|
||||
categories_file = config_base_path / 'categories' / 'categories.json'
|
||||
if not categories_file.exists():
|
||||
self.stdout.write(self.style.ERROR(f'❌ Categories file not found: {categories_file}'))
|
||||
return
|
||||
|
||||
with open(categories_file, 'r', encoding='utf-8') as f:
|
||||
categories_data = json.load(f)
|
||||
|
||||
categories = {}
|
||||
for category_data in categories_data:
|
||||
category, created = AgentCategory.objects.get_or_create(
|
||||
slug=category_data['slug'],
|
||||
defaults={
|
||||
'name': category_data['name'],
|
||||
'description': category_data['description'],
|
||||
'icon': category_data['icon']
|
||||
}
|
||||
)
|
||||
categories[category_data['slug']] = category
|
||||
if created:
|
||||
categories_created += 1
|
||||
self.stdout.write(f'✅ Created category: {category.name}')
|
||||
else:
|
||||
self.stdout.write(f' Category exists: {category.name}')
|
||||
|
||||
self.stdout.write('')
|
||||
|
||||
# Load and create agents from JSON files
|
||||
agents_dir = config_base_path / 'agents'
|
||||
if not agents_dir.exists():
|
||||
self.stdout.write(self.style.ERROR(f'❌ Agents directory not found: {agents_dir}'))
|
||||
return
|
||||
|
||||
# Get all JSON files in agents directory
|
||||
agent_files = list(agents_dir.glob('*.json'))
|
||||
if not agent_files:
|
||||
self.stdout.write(self.style.WARNING('⚠️ No agent configuration files found'))
|
||||
return
|
||||
|
||||
self.stdout.write(f'📁 Found {len(agent_files)} agent configuration files')
|
||||
self.stdout.write('')
|
||||
|
||||
# Process each agent configuration file
|
||||
for agent_file in sorted(agent_files):
|
||||
try:
|
||||
with open(agent_file, 'r', encoding='utf-8') as f:
|
||||
agent_data = json.load(f)
|
||||
|
||||
# Validate required fields
|
||||
required_fields = ['slug', 'name', 'category', 'price', 'agent_type']
|
||||
missing_fields = [field for field in required_fields if field not in agent_data]
|
||||
if missing_fields:
|
||||
self.stdout.write(self.style.ERROR(f'❌ Missing fields in {agent_file.name}: {missing_fields}'))
|
||||
continue
|
||||
|
||||
# Get category
|
||||
category_slug = agent_data['category']
|
||||
if category_slug not in categories:
|
||||
self.stdout.write(self.style.ERROR(f'❌ Unknown category "{category_slug}" in {agent_file.name}'))
|
||||
continue
|
||||
|
||||
category = categories[category_slug]
|
||||
|
||||
# Create agent
|
||||
agent, created = Agent.objects.get_or_create(
|
||||
slug=agent_data['slug'],
|
||||
defaults={
|
||||
'name': agent_data['name'],
|
||||
'short_description': agent_data.get('short_description', ''),
|
||||
'description': agent_data.get('description', ''),
|
||||
'category': category,
|
||||
'price': agent_data['price'],
|
||||
'agent_type': agent_data['agent_type'],
|
||||
'form_schema': agent_data.get('form_schema'),
|
||||
'webhook_url': agent_data.get('webhook_url', ''),
|
||||
'access_url_name': agent_data.get('access_url_name', ''),
|
||||
'display_url_name': agent_data.get('display_url_name', '')
|
||||
}
|
||||
)
|
||||
|
||||
if created:
|
||||
agents_created += 1
|
||||
system_type = agent_data.get('system_type', 'webhook')
|
||||
self.stdout.write(f'✅ Created agent: {agent.name} ({system_type.title()})')
|
||||
self.stdout.write(f' 💰 Price: {agent.price} AED')
|
||||
self.stdout.write(f' 📁 Config: {agent_file.name}')
|
||||
else:
|
||||
self.stdout.write(f' Agent exists: {agent.name} (from {agent_file.name})')
|
||||
|
||||
except json.JSONDecodeError as e:
|
||||
self.stdout.write(self.style.ERROR(f'❌ Invalid JSON in {agent_file.name}: {e}'))
|
||||
continue
|
||||
except Exception as e:
|
||||
self.stdout.write(self.style.ERROR(f'❌ Error processing {agent_file.name}: {e}'))
|
||||
continue
|
||||
|
||||
self.stdout.write('')
|
||||
self.stdout.write(self.style.SUCCESS('🎉 Dynamic population completed successfully!'))
|
||||
self.stdout.write('')
|
||||
self.stdout.write(f'📊 Summary:')
|
||||
self.stdout.write(f' Categories created: {categories_created}')
|
||||
self.stdout.write(f' Agents created: {agents_created}')
|
||||
self.stdout.write(f' Configuration files processed: {len(agent_files)}')
|
||||
self.stdout.write('')
|
||||
|
||||
# Final verification
|
||||
total_categories = AgentCategory.objects.filter(is_active=True).count()
|
||||
total_agents = Agent.objects.filter(is_active=True).count()
|
||||
webhook_agents = Agent.objects.filter(is_active=True, access_url_name='').count()
|
||||
direct_agents = Agent.objects.filter(is_active=True).exclude(access_url_name='').count()
|
||||
|
||||
self.stdout.write(f'🔍 Final verification:')
|
||||
self.stdout.write(f' Total categories: {total_categories}')
|
||||
self.stdout.write(f' Total agents: {total_agents}')
|
||||
self.stdout.write(f' Webhook agents: {webhook_agents}')
|
||||
self.stdout.write(f' Direct access agents: {direct_agents}')
|
||||
self.stdout.write('')
|
||||
self.stdout.write(self.style.SUCCESS('✅ Database is now consistent and ready!'))
|
||||
self.stdout.write('')
|
||||
self.stdout.write('🚀 To add new agents:')
|
||||
self.stdout.write(' 1. Create new JSON file in agents/configs/agents/')
|
||||
self.stdout.write(' 2. Run this command again')
|
||||
self.stdout.write(' 3. Agent will automatically appear in marketplace!')
|
||||
@ -1,160 +0,0 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-01 04:01
|
||||
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("agents", "0001_initial"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="agent",
|
||||
name="agent_type",
|
||||
field=models.CharField(
|
||||
choices=[("form", "Form-based"), ("chat", "Chat-based")],
|
||||
default="form",
|
||||
help_text="Agent interaction type",
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="agent",
|
||||
name="form_schema",
|
||||
field=models.JSONField(
|
||||
blank=True, help_text="JSON schema for agent input form", null=True
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ChatSession",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"session_id",
|
||||
models.CharField(
|
||||
help_text="Unique session identifier",
|
||||
max_length=100,
|
||||
unique=True,
|
||||
),
|
||||
),
|
||||
(
|
||||
"status",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("active", "Active"),
|
||||
("completed", "Completed"),
|
||||
("abandoned", "Abandoned"),
|
||||
("failed", "Failed"),
|
||||
],
|
||||
default="active",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
(
|
||||
"context_data",
|
||||
models.JSONField(
|
||||
default=dict, help_text="Session context and progress tracking"
|
||||
),
|
||||
),
|
||||
("fee_charged", models.DecimalField(decimal_places=2, max_digits=10)),
|
||||
("created_at", models.DateTimeField(auto_now_add=True)),
|
||||
("updated_at", models.DateTimeField(auto_now=True)),
|
||||
("completed_at", models.DateTimeField(blank=True, null=True)),
|
||||
(
|
||||
"agent",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="chat_sessions",
|
||||
to="agents.agent",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["-created_at"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ChatMessage",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.UUIDField(
|
||||
default=uuid.uuid4,
|
||||
editable=False,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
),
|
||||
),
|
||||
(
|
||||
"message_type",
|
||||
models.CharField(
|
||||
choices=[
|
||||
("user", "User Message"),
|
||||
("agent", "Agent Response"),
|
||||
("system", "System Message"),
|
||||
],
|
||||
max_length=10,
|
||||
),
|
||||
),
|
||||
("content", models.TextField()),
|
||||
(
|
||||
"metadata",
|
||||
models.JSONField(
|
||||
default=dict,
|
||||
help_text="Additional message data like webhook responses",
|
||||
),
|
||||
),
|
||||
("timestamp", models.DateTimeField(auto_now_add=True)),
|
||||
(
|
||||
"session",
|
||||
models.ForeignKey(
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="messages",
|
||||
to="agents.chatsession",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"ordering": ["timestamp"],
|
||||
},
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="chatsession",
|
||||
index=models.Index(
|
||||
fields=["session_id"], name="agents_chat_session_0d9cb4_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="chatsession",
|
||||
index=models.Index(
|
||||
fields=["user", "-created_at"], name="agents_chat_user_id_f8983d_idx"
|
||||
),
|
||||
),
|
||||
migrations.AddIndex(
|
||||
model_name="chatmessage",
|
||||
index=models.Index(
|
||||
fields=["session", "timestamp"], name="agents_chat_session_e8eaed_idx"
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -1,40 +0,0 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-01 10:08
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"agents",
|
||||
"0002_agent_agent_type_alter_agent_form_schema_chatsession_and_more",
|
||||
),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="chatsession",
|
||||
name="expires_at",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Session expiration time (2 hours from last activity)",
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="chatsession",
|
||||
name="status",
|
||||
field=models.CharField(
|
||||
choices=[
|
||||
("active", "Active"),
|
||||
("completed", "Completed"),
|
||||
("expired", "Expired"),
|
||||
("abandoned", "Abandoned"),
|
||||
("failed", "Failed"),
|
||||
],
|
||||
default="active",
|
||||
max_length=20,
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -1,21 +0,0 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-03 04:57
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("agents", "0003_chatsession_expires_at_alter_chatsession_status"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="agent",
|
||||
name="message_limit",
|
||||
field=models.IntegerField(
|
||||
default=50,
|
||||
help_text="Maximum messages per chat session (for chat agents)",
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -1,23 +0,0 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-04 11:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
def fake_migration(apps, schema_editor):
|
||||
"""
|
||||
Fake migration - Railway database already has access_url_name and display_url_name columns
|
||||
but Django model didn't have them defined. Now model has fields, so we just need to
|
||||
mark this migration as applied without doing anything.
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("agents", "0004_add_message_limit"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RunPython(fake_migration, fake_migration),
|
||||
]
|
||||
@ -1,42 +0,0 @@
|
||||
# Generated by Django 5.2.4 on 2025-08-04 17:04
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("agents", "0005_auto_20250804_1105"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="agent",
|
||||
name="access_url_name",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
help_text="URL name for direct access agents",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="agent",
|
||||
name="display_url_name",
|
||||
field=models.CharField(
|
||||
blank=True,
|
||||
default="",
|
||||
help_text="URL name for agent display page",
|
||||
max_length=100,
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="chatsession",
|
||||
name="expires_at",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Session expiration time (30 minutes from last activity)",
|
||||
null=True,
|
||||
),
|
||||
),
|
||||
]
|
||||
@ -17,11 +17,6 @@ class AgentCategory(models.Model):
|
||||
return self.name
|
||||
|
||||
class Agent(models.Model):
|
||||
AGENT_TYPE_CHOICES = [
|
||||
('form', 'Form-based'),
|
||||
('chat', 'Chat-based'),
|
||||
]
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
name = models.CharField(max_length=200)
|
||||
slug = models.SlugField(unique=True)
|
||||
@ -29,12 +24,8 @@ class Agent(models.Model):
|
||||
description = models.TextField()
|
||||
category = models.ForeignKey(AgentCategory, on_delete=models.CASCADE, related_name='agents')
|
||||
price = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
agent_type = models.CharField(max_length=10, choices=AGENT_TYPE_CHOICES, default='form', help_text="Agent interaction type")
|
||||
form_schema = models.JSONField(help_text="JSON schema for agent input form", null=True, blank=True)
|
||||
form_schema = models.JSONField(help_text="JSON schema for agent input form")
|
||||
webhook_url = models.URLField(help_text="n8n webhook URL for execution")
|
||||
message_limit = models.IntegerField(default=50, help_text="Maximum messages per chat session (for chat agents)")
|
||||
access_url_name = models.CharField(max_length=100, blank=True, default='', help_text="URL name for direct access agents")
|
||||
display_url_name = models.CharField(max_length=100, blank=True, default='', help_text="URL name for agent display page")
|
||||
is_active = models.BooleanField(default=True)
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
@ -71,79 +62,3 @@ class AgentExecution(models.Model):
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.agent.name} - {self.user.email} - {self.status}"
|
||||
|
||||
class ChatSession(models.Model):
|
||||
STATUS_CHOICES = [
|
||||
('active', 'Active'),
|
||||
('completed', 'Completed'),
|
||||
('expired', 'Expired'),
|
||||
('abandoned', 'Abandoned'),
|
||||
('failed', 'Failed'),
|
||||
]
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
session_id = models.CharField(max_length=100, unique=True, help_text="Unique session identifier")
|
||||
agent = models.ForeignKey(Agent, on_delete=models.CASCADE, related_name='chat_sessions')
|
||||
user = models.ForeignKey('authentication.User', on_delete=models.CASCADE)
|
||||
status = models.CharField(max_length=20, choices=STATUS_CHOICES, default='active')
|
||||
context_data = models.JSONField(default=dict, help_text="Session context and progress tracking")
|
||||
fee_charged = models.DecimalField(max_digits=10, decimal_places=2)
|
||||
expires_at = models.DateTimeField(null=True, blank=True, help_text="Session expiration time (30 minutes from last activity)")
|
||||
created_at = models.DateTimeField(auto_now_add=True)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
completed_at = models.DateTimeField(null=True, blank=True)
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
# Set expires_at to 30 minutes from now if not set
|
||||
if not self.expires_at:
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
self.expires_at = timezone.now() + timedelta(minutes=30)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
ordering = ['-created_at']
|
||||
indexes = [
|
||||
models.Index(fields=['session_id']),
|
||||
models.Index(fields=['user', '-created_at']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.agent.name} - {self.user.email} - {self.session_id}"
|
||||
|
||||
def is_expired(self):
|
||||
from django.utils import timezone
|
||||
if not self.expires_at:
|
||||
return False # Sessions without expiration date are considered active
|
||||
return timezone.now() > self.expires_at
|
||||
|
||||
def extend_session(self):
|
||||
"""Extend session by 30 minutes from now"""
|
||||
from django.utils import timezone
|
||||
from datetime import timedelta
|
||||
self.expires_at = timezone.now() + timedelta(minutes=30)
|
||||
self.updated_at = timezone.now()
|
||||
self.save()
|
||||
|
||||
class ChatMessage(models.Model):
|
||||
MESSAGE_TYPE_CHOICES = [
|
||||
('user', 'User Message'),
|
||||
('agent', 'Agent Response'),
|
||||
('system', 'System Message'),
|
||||
]
|
||||
|
||||
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
|
||||
session = models.ForeignKey(ChatSession, on_delete=models.CASCADE, related_name='messages')
|
||||
message_type = models.CharField(max_length=10, choices=MESSAGE_TYPE_CHOICES)
|
||||
content = models.TextField()
|
||||
metadata = models.JSONField(default=dict, help_text="Additional message data like webhook responses")
|
||||
timestamp = models.DateTimeField(auto_now_add=True)
|
||||
|
||||
class Meta:
|
||||
ordering = ['timestamp']
|
||||
indexes = [
|
||||
models.Index(fields=['session', 'timestamp']),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f"{self.session.session_id} - {self.message_type} - {self.timestamp}"
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -39,42 +39,7 @@ document.body.setAttribute('data-user-balance', '{{ user.wallet_balance }}');
|
||||
</h3>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
{% if agent.access_url_name and agent.display_url_name %}
|
||||
<!-- Direct Access Agent - External Form -->
|
||||
<div class="direct-access-info">
|
||||
<div class="section-container">
|
||||
<h4 class="section-subtitle">{{ agent.category.icon }} {{ agent.name }} - External Consultation</h4>
|
||||
<p style="color: #6b7280; margin-bottom: var(--spacing-lg);">
|
||||
This consultation will redirect you to our specialized external form for personalized guidance.
|
||||
</p>
|
||||
|
||||
{% if user.is_authenticated %}
|
||||
{% if agent.price == 0 %}
|
||||
<a href="{% url 'agents:direct_access_handler' agent.slug %}" class="btn btn-primary btn-full">
|
||||
{{ agent.category.icon }} Start {{ agent.name }} Consultation (FREE)
|
||||
</a>
|
||||
{% elif user.wallet_balance >= agent.price %}
|
||||
<a href="{% url 'agents:direct_access_handler' agent.slug %}" class="btn btn-primary btn-full">
|
||||
{{ agent.category.icon }} Start {{ agent.name }} Consultation ({{ agent.price }} AED)
|
||||
</a>
|
||||
{% else %}
|
||||
<div style="background: #fef2f2; color: #dc2626; padding: var(--spacing-md); border-radius: var(--radius-md); margin-bottom: var(--spacing-md); font-size: 14px; font-weight: 500; text-align: center;">
|
||||
Insufficient balance! You need {{ agent.price }} AED.
|
||||
</div>
|
||||
<a href="{% url 'wallet:wallet' %}" class="btn btn-primary btn-full" style="text-decoration: none;">
|
||||
💰 Top Up Wallet
|
||||
</a>
|
||||
{% endif %}
|
||||
{% else %}
|
||||
<a href="{% url 'authentication:login' %}" class="btn btn-primary btn-full">
|
||||
🔐 Login to Continue
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
{% else %}
|
||||
<!-- Webhook Agent - Dynamic Form -->
|
||||
<form id="agentForm" method="POST" enctype="multipart/form-data" data-agent-id="{{ agent.id }}">
|
||||
<form id="agentForm" method="POST" enctype="multipart/form-data" data-agent-id="{{ agent.id }}">
|
||||
{% csrf_token %}
|
||||
|
||||
<!-- Dynamic Form Fields -->
|
||||
@ -202,7 +167,6 @@ document.body.setAttribute('data-user-balance', '{{ user.wallet_balance }}');
|
||||
{% endif %}
|
||||
</div>
|
||||
</form>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@ -6,9 +6,6 @@
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/agent-base.css' %}">
|
||||
<link rel="stylesheet" href="{% static 'css/marketplace.css' %}">
|
||||
<style>
|
||||
/* All Try Now buttons now use consistent styling from marketplace.css */
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
@ -52,11 +49,12 @@
|
||||
<!-- Stats -->
|
||||
<div class="marketplace-stats">
|
||||
{% if search_query %}
|
||||
Search results for "{{ search_query }}"
|
||||
{% if selected_category %} • {{ selected_category|capfirst }} category{% endif %}
|
||||
{% elif selected_category %}
|
||||
{{ selected_category|capfirst }} category
|
||||
Search results for "{{ search_query }}" •
|
||||
{% endif %}
|
||||
{% if selected_category %}
|
||||
{{ selected_category|capfirst }} category •
|
||||
{% endif %}
|
||||
{{ agents.count }} agent{{ agents.count|pluralize }} available
|
||||
</div>
|
||||
|
||||
<!-- Agents Grid -->
|
||||
@ -74,47 +72,12 @@
|
||||
<p class="agent-description">{{ agent.short_description }}</p>
|
||||
<div class="agent-footer">
|
||||
{% if user.is_authenticated %}
|
||||
{% if agent.slug == 'cybersec-career-navigator' %}
|
||||
<a href="{% url 'agents:career_navigator_access' %}" class="try-btn">
|
||||
Try Now →
|
||||
</a>
|
||||
{% elif agent.slug == 'ai-brand-strategist' %}
|
||||
<a href="{% url 'agents:ai_brand_strategist_access' %}" class="try-btn">
|
||||
Try Now →
|
||||
</a>
|
||||
{% elif agent.slug == 'lean-six-sigma-expert' %}
|
||||
<a href="{% url 'agents:lean_six_sigma_expert_access' %}" class="try-btn">
|
||||
Try Now →
|
||||
</a>
|
||||
{% elif agent.slug == 'swot-analysis-expert' %}
|
||||
<a href="{% url 'agents:swot_analysis_expert_access' %}" class="try-btn">
|
||||
Try Now →
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'agents:detail' agent.slug %}" class="try-btn">Try Now →</a>
|
||||
{% endif %}
|
||||
<span class="agent-category">{{ agent.category.name }}</span>
|
||||
<a href="{% url 'agents:detail' agent.slug %}" class="try-btn">Try Now →</a>
|
||||
{% else %}
|
||||
{% if agent.slug == 'cybersec-career-navigator' %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:career_navigator_access' %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% elif agent.slug == 'ai-brand-strategist' %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:ai_brand_strategist_access' %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% elif agent.slug == 'lean-six-sigma-expert' %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:lean_six_sigma_expert_access' %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% elif agent.slug == 'swot-analysis-expert' %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:swot_analysis_expert_access' %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:detail' agent.slug %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% endif %}
|
||||
<a href="{% url 'authentication:login' %}?next={% url 'agents:detail' agent.slug %}" class="try-btn login-required" style="width: 100%;">
|
||||
🔐 Login to Try
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -7,36 +7,13 @@ urlpatterns = [
|
||||
# Web interface
|
||||
path('', views.agents_marketplace, name='marketplace'),
|
||||
|
||||
# Direct access routes
|
||||
path('career-navigator/', views.career_navigator_view, name='career_navigator'),
|
||||
path('career-navigator/access/', views.career_navigator_access, name='career_navigator_access'),
|
||||
path('ai-brand-strategist/', views.ai_brand_strategist_view, name='ai_brand_strategist'),
|
||||
path('ai-brand-strategist/access/', views.ai_brand_strategist_access, name='ai_brand_strategist_access'),
|
||||
path('lean-six-sigma-expert/', views.lean_six_sigma_expert_view, name='lean_six_sigma_expert'),
|
||||
path('lean-six-sigma-expert/access/', views.lean_six_sigma_expert_access, name='lean_six_sigma_expert_access'),
|
||||
path('swot-analysis-expert/', views.swot_analysis_expert_view, name='swot_analysis_expert'),
|
||||
path('swot-analysis-expert/access/', views.swot_analysis_expert_access, name='swot_analysis_expert_access'),
|
||||
|
||||
# API endpoints - specific URLs first to avoid slug conflicts
|
||||
path('api/execute/', views.execute_agent, name='execute_agent'),
|
||||
path('api/executions/', views.execution_list, name='execution_list'),
|
||||
path('api/executions/<uuid:execution_id>/', views.execution_detail, name='execution_detail'),
|
||||
|
||||
# Chat API endpoints
|
||||
path('api/chat/start/', views.start_chat_session, name='start_chat_session'),
|
||||
path('api/chat/send/', views.send_chat_message, name='send_chat_message'),
|
||||
path('api/chat/history/<str:session_id>/', views.get_chat_history, name='get_chat_history'),
|
||||
path('api/chat/session/<str:session_id>/status/', views.get_session_status, name='get_session_status'),
|
||||
path('api/chat/end/', views.end_chat_session, name='end_chat_session'),
|
||||
path('api/chat/export/<str:session_id>/', views.export_chat, name='export_chat'),
|
||||
|
||||
path('api/', views.agent_list, name='agent_list'),
|
||||
path('api/<slug:slug>/', views.agent_detail, name='agent_detail_api'),
|
||||
|
||||
# Generic direct access routes (must be before agent detail)
|
||||
path('<slug:slug>/access/', views.direct_access_handler, name='direct_access_handler'),
|
||||
path('<slug:slug>/display/', views.direct_access_display, name='direct_access_display'),
|
||||
|
||||
# Agent detail page (must be last to avoid conflicts)
|
||||
path('<slug:slug>/', views.agent_detail_view, name='detail'),
|
||||
]
|
||||
1072
agents/views.py
1072
agents/views.py
File diff suppressed because it is too large
Load Diff
@ -30,7 +30,7 @@ def validate_password_strength(password):
|
||||
is_common = password.lower() in common_passwords
|
||||
|
||||
if not (has_length and has_lower and has_upper and has_digit and has_special) or is_common:
|
||||
return ["Password must have 8+ characters, uppercase, lowercase, number, and special character"]
|
||||
return ["Password must be at least 8 characters with uppercase, lowercase, number, and special character"]
|
||||
|
||||
return []
|
||||
|
||||
@ -89,17 +89,10 @@ def handle_ratelimited(request, exception):
|
||||
@ratelimit(key='ip', rate='5/m', method=UNSAFE, block=False)
|
||||
def login_view(request):
|
||||
"""User login view with rate limiting (5 attempts per minute per IP)"""
|
||||
# Handle post-login session messages
|
||||
if 'post_login_message' in request.session:
|
||||
messages.info(request, request.session.pop('post_login_message'))
|
||||
|
||||
# Check if rate limited
|
||||
if getattr(request, 'limited', False):
|
||||
# Use session to avoid repeated rate limit messages
|
||||
if not request.session.get('rate_limit_shown'):
|
||||
logger.warning(f"Login rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
|
||||
messages.error(request, 'Too many login attempts. Please wait before trying again.')
|
||||
request.session['rate_limit_shown'] = True
|
||||
logger.warning(f"Login rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
|
||||
messages.error(request, 'Too many login attempts. Please try again in a few minutes.')
|
||||
return render(request, 'authentication/login.html')
|
||||
|
||||
if request.method == 'POST':
|
||||
@ -108,16 +101,12 @@ def login_view(request):
|
||||
|
||||
user = authenticate(request, username=email, password=password)
|
||||
if user is not None:
|
||||
# Check if email is verified (only if email verification is required)
|
||||
if settings.REQUIRE_EMAIL_VERIFICATION and not user.email_verified:
|
||||
# Check if email is verified
|
||||
if not user.email_verified:
|
||||
messages.warning(request, 'Please verify your email address before logging in. Check your inbox for the verification link.')
|
||||
# Store resend URL in context for template
|
||||
context = {'show_resend_verification': True}
|
||||
return render(request, 'authentication/login.html', context)
|
||||
return render(request, 'authentication/login.html')
|
||||
|
||||
login(request, user)
|
||||
# Clear rate limit flag on successful login
|
||||
request.session.pop('rate_limit_shown', None)
|
||||
# Redirect to 'next' parameter if provided, otherwise homepage
|
||||
next_url = request.GET.get('next') or request.POST.get('next')
|
||||
if next_url:
|
||||
@ -125,8 +114,6 @@ def login_view(request):
|
||||
return redirect('core:homepage')
|
||||
else:
|
||||
messages.error(request, 'Invalid email or password')
|
||||
# Clear rate limit flag on any POST attempt (failed login)
|
||||
request.session.pop('rate_limit_shown', None)
|
||||
|
||||
return render(request, 'authentication/login.html')
|
||||
|
||||
@ -167,25 +154,15 @@ def register_view(request):
|
||||
email=email,
|
||||
password=password1
|
||||
)
|
||||
# Don't automatically login - require email verification first
|
||||
|
||||
# Handle email verification based on settings
|
||||
if settings.REQUIRE_EMAIL_VERIFICATION:
|
||||
# Don't automatically login - require email verification first
|
||||
# Send verification email
|
||||
if send_verification_email(user):
|
||||
messages.success(request, 'Account created. Check your email to verify.')
|
||||
else:
|
||||
messages.warning(request, 'Account created. Email verification failed - try again later.')
|
||||
|
||||
return redirect('authentication:login')
|
||||
# Send verification email
|
||||
if send_verification_email(user):
|
||||
messages.success(request, 'Account created successfully! Please check your email to verify your account.')
|
||||
else:
|
||||
# Skip email verification - auto-verify and login
|
||||
user.email_verified = True
|
||||
user.save()
|
||||
messages.warning(request, 'Account created but verification email could not be sent. You can request a new one after logging in.')
|
||||
|
||||
login(request, user)
|
||||
messages.success(request, f'Welcome {user.username}!')
|
||||
return redirect('core:homepage')
|
||||
return redirect('authentication:login')
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating account for {email}: {str(e)}")
|
||||
messages.error(request, 'Error creating account')
|
||||
@ -196,6 +173,7 @@ def register_view(request):
|
||||
def logout_view(request):
|
||||
"""User logout view"""
|
||||
logout(request)
|
||||
messages.success(request, 'You have been logged out successfully')
|
||||
return redirect('core:homepage')
|
||||
|
||||
|
||||
@ -347,7 +325,7 @@ def reset_password_view(request, token):
|
||||
# Mark token as used
|
||||
reset_token.mark_as_used()
|
||||
|
||||
messages.success(request, 'Password reset. You can now log in.')
|
||||
messages.success(request, 'Your password has been reset successfully. You can now log in.')
|
||||
return redirect('authentication:login')
|
||||
|
||||
return render(request, 'authentication/reset_password.html', {'token': token})
|
||||
@ -369,7 +347,7 @@ def verify_email_view(request, token):
|
||||
# Mark token as used
|
||||
verification_token.mark_as_used()
|
||||
|
||||
messages.success(request, 'Email verified. You can now log in.')
|
||||
messages.success(request, 'Email verified successfully! You can now log in.')
|
||||
return redirect('authentication:login')
|
||||
|
||||
|
||||
@ -394,7 +372,7 @@ def resend_verification_view(request):
|
||||
|
||||
# Send new verification email
|
||||
if send_verification_email(user):
|
||||
messages.success(request, 'Verification email sent.')
|
||||
messages.success(request, 'Verification email sent. Please check your inbox.')
|
||||
else:
|
||||
messages.error(request, 'Unable to send verification email at this time.')
|
||||
|
||||
|
||||
@ -5,9 +5,7 @@ app_name = 'core'
|
||||
|
||||
urlpatterns = [
|
||||
path('', views.homepage_view, name='homepage'),
|
||||
path('digital-branding/', views.digital_branding_view, name='digital_branding'),
|
||||
path('pricing/', views.pricing_view, name='pricing'),
|
||||
path('contact/', views.contact_form_view, name='contact_form'),
|
||||
path('event/', views.event_view, name='event'),
|
||||
path('health/', views.health_check_view, name='health_check'),
|
||||
]
|
||||
@ -39,30 +39,30 @@ def homepage_view(request):
|
||||
return render(request, 'core/homepage.html', {'featured_agents': [], 'user_balance': 0})
|
||||
@ratelimit(key='ip', rate='60/m', method='GET', block=False)
|
||||
def pricing_view(request):
|
||||
"""Pricing page - redirect to marketplace"""
|
||||
# Redirect all pricing page access to the AI marketplace
|
||||
return redirect('agents:marketplace')
|
||||
|
||||
|
||||
@ratelimit(key='ip', rate='60/m', method='GET', block=False)
|
||||
def digital_branding_view(request):
|
||||
"""Digital branding services page with rate limiting"""
|
||||
"""Pricing page for non-logged-in users with rate limiting"""
|
||||
# Check if rate limited
|
||||
if getattr(request, 'limited', False):
|
||||
logger.warning(f"Digital branding page rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
|
||||
logger.warning(f"Pricing page rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
|
||||
messages.warning(request, 'Too many requests. Please wait a moment before refreshing.')
|
||||
|
||||
# If user is already logged in, redirect to wallet top-up
|
||||
if request.user.is_authenticated:
|
||||
return redirect('wallet:wallet_topup')
|
||||
|
||||
try:
|
||||
# Get sample agents to show pricing context from database
|
||||
sample_agents = Agent.objects.filter(is_active=True).select_related('category')[:4]
|
||||
|
||||
context = {
|
||||
'user_balance': request.user.wallet_balance if request.user.is_authenticated else 0,
|
||||
'sample_agents': sample_agents,
|
||||
}
|
||||
|
||||
return render(request, 'core/digital_branding.html', context)
|
||||
return render(request, 'core/pricing.html', context)
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Digital branding view error: {e}")
|
||||
messages.error(request, 'Unable to load digital branding page. Please try again.')
|
||||
return render(request, 'core/digital_branding.html', {})
|
||||
logger.error(f"Pricing view error: {e}")
|
||||
messages.error(request, 'Unable to load pricing page. Please try again.')
|
||||
return render(request, 'core/pricing.html', {'sample_agents': []})
|
||||
|
||||
|
||||
def validate_contact_input(name, email, message, company=""):
|
||||
@ -214,22 +214,6 @@ def contact_form_view(request):
|
||||
}, status=500)
|
||||
|
||||
|
||||
@ratelimit(key='ip', rate='60/m', method='GET', block=False)
|
||||
def event_view(request):
|
||||
"""Event page view"""
|
||||
# Check if rate limited
|
||||
if getattr(request, 'limited', False):
|
||||
logger.warning(f"Event page rate limit exceeded for IP {request.META.get('REMOTE_ADDR')}")
|
||||
messages.warning(request, 'Too many requests. Please wait a moment before refreshing.')
|
||||
|
||||
context = {
|
||||
'form_url': 'https://form.jotform.com/252214924850455',
|
||||
'user_balance': request.user.wallet_balance if request.user.is_authenticated else 0,
|
||||
}
|
||||
|
||||
return render(request, 'core/event.html', context)
|
||||
|
||||
|
||||
@ratelimit(key='ip', rate='60/m', method='GET', block=False)
|
||||
def health_check_view(request):
|
||||
"""Simplified health check endpoint - no database dependency for startup"""
|
||||
|
||||
@ -1,302 +0,0 @@
|
||||
# Agent Creation Guide
|
||||
|
||||
This guide provides comprehensive instructions for adding new agents to the Quantum Tasks AI platform.
|
||||
|
||||
## Overview
|
||||
|
||||
Quantum Tasks AI supports **TWO DISTINCT AGENT SYSTEMS**:
|
||||
|
||||
- **Webhook Agents** - N8N integrations for complex processing with dynamic forms
|
||||
- **Direct Access Agents** - External form services (JotForm, Google Forms) with embedded interfaces
|
||||
|
||||
**⚡ RECOMMENDED APPROACH:** Use JSON configuration + `populate_agents` command for error-free, Railway-ready agent creation.
|
||||
|
||||
---
|
||||
|
||||
## Current Agent Status
|
||||
|
||||
**Total Agents: 8** (4 webhook + 4 direct access)
|
||||
**Total Categories: 6**
|
||||
|
||||
### Webhook Agents (N8N Integration)
|
||||
1. **Social Ads Generator** - 6.00 AED - Creates social media advertisements
|
||||
2. **Job Posting Generator** - 10.00 AED - Creates professional job postings
|
||||
3. **PDF Summarizer** - 8.00 AED - Analyzes and summarizes PDF documents
|
||||
4. **5 Whys Analyzer** - 15.00 AED - Interactive chat-based root cause analysis
|
||||
|
||||
### Direct Access Agents (External Forms)
|
||||
1. **CyberSec Career Navigator** - FREE - Career guidance consultation
|
||||
2. **AI Brand Strategist** - FREE - Brand strategy consultation
|
||||
3. **Lean Six Sigma Expert** - FREE - Process improvement consultation
|
||||
4. **SWOT Analysis Expert** - FREE - Strategic business analysis
|
||||
|
||||
---
|
||||
|
||||
## 🏷️ Choose Existing Category First
|
||||
|
||||
**IMPORTANT:** Always use existing categories before creating new ones to avoid category proliferation.
|
||||
|
||||
### Available Categories:
|
||||
- 🧠 **`analysis`** - Problem-solving, SWOT analysis, strategic analysis tools
|
||||
- 🎓 **`career-education`** - Career guidance, educational resources, professional development
|
||||
- 📄 **`document-processing`** - PDF analysis, file processing, document tools
|
||||
- 💼 **`human-resources`** - Job postings, HR automation, talent management
|
||||
- 📢 **`marketing`** - Social ads, branding, content marketing, advertising
|
||||
- 💼 **`consulting`** - Business consultation, strategy services, expert advice
|
||||
|
||||
**Only create new categories when absolutely necessary and logically distinct.**
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Agent Creation Workflow
|
||||
|
||||
### System 1: Webhook Agents (N8N Integration)
|
||||
- **Use for:** Dynamic forms, server-side processing, file uploads, complex workflows
|
||||
- **Examples:** Social Ads Generator, PDF Summarizer, Job Posting Generator
|
||||
- **Flow:** Marketplace → Agent detail page → Dynamic form → N8N webhook → Results
|
||||
|
||||
### System 2: Direct Access Agents (External Forms)
|
||||
- **Use for:** External form services (JotForm, Google Forms), consultation interfaces
|
||||
- **Examples:** SWOT Analysis Expert, CyberSec Career Navigator, AI Brand Strategist
|
||||
- **Flow:** Marketplace → Payment processing → Quantum Tasks header + embedded external form
|
||||
|
||||
---
|
||||
|
||||
## 📝 Implementation Steps
|
||||
|
||||
### Step 1: Create JSON Configuration
|
||||
|
||||
Create a new file in `agents/configs/agents/your-agent-name.json`:
|
||||
|
||||
#### Webhook Agent Example:
|
||||
```json
|
||||
{
|
||||
"slug": "content-optimizer",
|
||||
"name": "Content Optimizer",
|
||||
"short_description": "AI-powered content optimization and enhancement",
|
||||
"description": "Enhance your content for better engagement with AI-powered optimization suggestions, tone analysis, and improvement recommendations.",
|
||||
"category": "marketing",
|
||||
"price": 5.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "webhook",
|
||||
"form_schema": {
|
||||
"fields": [
|
||||
{
|
||||
"name": "content",
|
||||
"type": "textarea",
|
||||
"label": "Content to Optimize",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"name": "content_type",
|
||||
"type": "select",
|
||||
"label": "Content Type",
|
||||
"required": true,
|
||||
"options": [
|
||||
{"value": "blog", "label": "Blog Post"},
|
||||
{"value": "social", "label": "Social Media"},
|
||||
{"value": "email", "label": "Email Marketing"}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"webhook_url": "http://localhost:5678/webhook/content-optimizer",
|
||||
"access_url_name": "",
|
||||
"display_url_name": ""
|
||||
}
|
||||
```
|
||||
|
||||
#### Direct Access Agent Example:
|
||||
```json
|
||||
{
|
||||
"slug": "business-strategist",
|
||||
"name": "Business Strategist",
|
||||
"short_description": "Expert business strategy consultation",
|
||||
"description": "Get professional business strategy insights and recommendations from experienced consultants to grow your business effectively.",
|
||||
"category": "consulting",
|
||||
"price": 0.0,
|
||||
"agent_type": "form",
|
||||
"system_type": "direct_access",
|
||||
"form_schema": {
|
||||
"fields": []
|
||||
},
|
||||
"webhook_url": "https://agent.jotform.com/your-form-id",
|
||||
"access_url_name": "agents:direct_access_handler",
|
||||
"display_url_name": "agents:direct_access_display"
|
||||
}
|
||||
```
|
||||
|
||||
### Step 2: Run populate_agents Command
|
||||
|
||||
```bash
|
||||
# Development
|
||||
source venv/bin/activate
|
||||
python manage.py populate_agents
|
||||
|
||||
# Production (Railway)
|
||||
python manage.py populate_agents # Runs automatically on deployment
|
||||
```
|
||||
|
||||
### Step 3: Additional Setup (Direct Access Agents Only)
|
||||
|
||||
For direct access agents that need custom templates or marketplace integration:
|
||||
|
||||
#### 3a. Create Custom Template (optional):
|
||||
```html
|
||||
<!-- templates/your_agent_name.html -->
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Your Agent Name - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.main-container { max-width: none; padding: 0; height: calc(100vh - 80px); }
|
||||
.iframe-container { width: 100%; height: 100%; }
|
||||
.iframe-container iframe { width: 100%; height: 100%; border: none; display: block; }
|
||||
.footer { display: none !important; }
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe src="{{ form_url }}" frameborder="0" scrolling="auto" title="Your Agent Name"></iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
```
|
||||
|
||||
#### 3b. Add Custom Views (if needed):
|
||||
Add view functions to `agents/views.py` following the pattern of existing direct access agents.
|
||||
|
||||
#### 3c. Add URL Routes (if needed):
|
||||
Add routes to `agents/urls.py` following the pattern of existing direct access agents.
|
||||
|
||||
#### 3d. Update Marketplace Template (if needed):
|
||||
Add button logic to `agents/templates/agents/marketplace.html` for custom marketplace behavior.
|
||||
|
||||
**⚠️ Important**: Keep all "Try Now" buttons consistent with the format `Try Now →` (no icons or emojis).
|
||||
|
||||
### Step 4: Setup External Services
|
||||
|
||||
#### For Webhook Agents:
|
||||
- Create N8N workflow at the webhook URL
|
||||
- Configure webhook to accept JSON payload with `sessionId`, `message`, etc.
|
||||
|
||||
#### For Direct Access Agents:
|
||||
- Create external form (JotForm, Google Forms, etc.)
|
||||
- Ensure form URL is accessible and properly configured
|
||||
|
||||
---
|
||||
|
||||
## ✅ Benefits of This Approach
|
||||
|
||||
- ✅ **Single source of truth** - JSON configs define everything
|
||||
- ✅ **Railway-ready immediately** - No manual database setup needed
|
||||
- ✅ **Error-free** - No category creation mistakes or typos
|
||||
- ✅ **Consistent** - All agents use same reliable creation process
|
||||
- ✅ **Scalable** - Easy to add 100+ agents
|
||||
- ✅ **Version controlled** - Configs are tracked in git
|
||||
|
||||
---
|
||||
|
||||
## 🔧 Supported Form Field Types (Webhook Agents)
|
||||
|
||||
- `text` - Single-line text input
|
||||
- `textarea` - Multi-line text input
|
||||
- `select` - Dropdown with options array
|
||||
- `file` - File upload with drag-and-drop
|
||||
- `url` - URL input with validation
|
||||
- `checkbox` - Boolean checkbox
|
||||
|
||||
---
|
||||
|
||||
## ⚠️ Common Mistakes to Avoid
|
||||
|
||||
1. **Creating unnecessary categories** - Use existing ones first
|
||||
2. **Missing system_type** - Include "webhook" or "direct_access"
|
||||
3. **Wrong access_url_name** - Empty for webhook agents, populated for direct access
|
||||
4. **Forgetting populate_agents** - Run after creating JSON config
|
||||
5. **Complex custom commands** - Use JSON + populate_agents instead
|
||||
6. **Adding icons to Try Now buttons** - Keep all marketplace buttons consistent with "Try Now →" format
|
||||
|
||||
---
|
||||
|
||||
## 🔄 Agent Management Commands
|
||||
|
||||
### Essential Commands:
|
||||
```bash
|
||||
# Populate all agents from JSON configs (main command)
|
||||
python manage.py populate_agents
|
||||
|
||||
# Clean up expired chat sessions
|
||||
python manage.py cleanup_expired_sessions
|
||||
```
|
||||
|
||||
### Development Workflow:
|
||||
1. Create JSON config file
|
||||
2. Run `populate_agents`
|
||||
3. Test agent functionality
|
||||
4. Commit changes to git
|
||||
5. Deploy to Railway (auto-runs populate_agents)
|
||||
|
||||
---
|
||||
|
||||
## 📊 Agent Configuration Reference
|
||||
|
||||
### Required JSON Fields:
|
||||
- `slug` - URL-friendly identifier (kebab-case)
|
||||
- `name` - Display name
|
||||
- `short_description` - Brief description for marketplace
|
||||
- `description` - Full description with details
|
||||
- `category` - Must match existing category slug
|
||||
- `price` - Price in AED (0.0 for free agents)
|
||||
- `agent_type` - Always "form"
|
||||
- `system_type` - "webhook" or "direct_access"
|
||||
|
||||
### System-Specific Fields:
|
||||
|
||||
#### Webhook Agents:
|
||||
- `form_schema` - JSON schema defining form fields
|
||||
- `webhook_url` - N8N webhook endpoint
|
||||
- `access_url_name` - Empty string ""
|
||||
- `display_url_name` - Empty string ""
|
||||
|
||||
#### Direct Access Agents:
|
||||
- `form_schema` - Usually `{"fields": []}`
|
||||
- `webhook_url` - External form URL (JotForm, etc.)
|
||||
- `access_url_name` - "agents:direct_access_handler"
|
||||
- `display_url_name` - "agents:direct_access_display"
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Railway Deployment
|
||||
|
||||
When you commit changes to the repository:
|
||||
|
||||
1. ✅ **Railway auto-deploys** new code
|
||||
2. ✅ **populate_agents runs automatically** on deployment
|
||||
3. ✅ **New agents appear** in production marketplace
|
||||
4. ✅ **Categories are created** if needed (but use existing ones first!)
|
||||
5. ✅ **No manual database work** required
|
||||
|
||||
---
|
||||
|
||||
## 📞 Support & Documentation
|
||||
|
||||
- **Main Documentation**: See `CLAUDE.md` for project overview
|
||||
- **Agent Issues**: Check Railway logs and database for agent status
|
||||
- **Form Problems**: Verify external form URLs are accessible
|
||||
- **Category Issues**: Use existing categories from the list above
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Quick Agent Request
|
||||
|
||||
**For fast agent creation**, use the **Agent Request Template**:
|
||||
👉 **See `docs/AGENT_REQUEST_TEMPLATE.md`** for a simple template to request new agents
|
||||
|
||||
Simply fill out the template and provide it to Claude Code for instant agent creation!
|
||||
|
||||
---
|
||||
|
||||
*Last updated: 2025-01-08*
|
||||
@ -1,135 +0,0 @@
|
||||
# Agent Request Template
|
||||
|
||||
Use this template when requesting new agents to ensure all necessary information is provided for quick, error-free agent creation.
|
||||
|
||||
## How to Use This Template
|
||||
|
||||
1. **Copy the template below**
|
||||
2. **Fill in all required fields**
|
||||
3. **Provide to Claude Code** with the request "Create agent using this template"
|
||||
4. **Claude will handle** JSON config creation, populate_agents execution, and deployment
|
||||
|
||||
---
|
||||
|
||||
## Agent Request Template
|
||||
|
||||
```markdown
|
||||
## New Agent Request
|
||||
|
||||
**Agent Name**: [Enter the display name for the agent]
|
||||
**Type**: [Webhook OR Direct Access]
|
||||
**Category**: [Choose from: analysis, career-education, document-processing, human-resources, marketing, consulting]
|
||||
**Price**: [X.XX AED or 0.0 for FREE]
|
||||
**Short Description**: [Brief 1-line description for marketplace]
|
||||
**Full Description**: [Detailed description of what the agent does and its benefits]
|
||||
|
||||
### For Webhook Agents Only:
|
||||
**Form Fields**:
|
||||
- Field 1: [name: field_name, type: text/textarea/select/file/url/checkbox, label: "Display Label", required: true/false]
|
||||
- Field 2: [name: field_name, type: text/textarea/select/file/url/checkbox, label: "Display Label", required: true/false]
|
||||
- [Add more fields as needed]
|
||||
|
||||
**N8N Webhook URL**: [Your N8N webhook endpoint URL]
|
||||
|
||||
### For Direct Access Agents Only:
|
||||
**External Form URL**: [JotForm, Google Forms, or other external form URL]
|
||||
**Custom Template Needed**: [Yes/No - specify if you need custom styling/layout]
|
||||
**Custom Views Needed**: [Yes/No - specify if you need special marketplace behavior]
|
||||
|
||||
### Optional Information:
|
||||
**Special Requirements**: [Any unique features or customizations needed]
|
||||
**Integration Notes**: [Any special setup or configuration details]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Available Categories
|
||||
|
||||
**Choose from these existing categories** (avoid creating new ones):
|
||||
|
||||
- 🧠 **`analysis`** - Problem-solving, SWOT analysis, strategic analysis tools
|
||||
- 🎓 **`career-education`** - Career guidance, educational resources, professional development
|
||||
- 📄 **`document-processing`** - PDF analysis, file processing, document tools
|
||||
- 💼 **`human-resources`** - Job postings, HR automation, talent management
|
||||
- 📢 **`marketing`** - Social ads, branding, content marketing, advertising
|
||||
- 💼 **`consulting`** - Business consultation, strategy services, expert advice
|
||||
|
||||
---
|
||||
|
||||
## Form Field Types (Webhook Agents)
|
||||
|
||||
- **`text`** - Single-line text input
|
||||
- **`textarea`** - Multi-line text input
|
||||
- **`select`** - Dropdown (requires options array)
|
||||
- **`file`** - File upload with drag-and-drop
|
||||
- **`url`** - URL input with validation
|
||||
- **`checkbox`** - Boolean true/false
|
||||
|
||||
---
|
||||
|
||||
## Example Requests
|
||||
|
||||
### Example 1: Webhook Agent
|
||||
```markdown
|
||||
## New Agent Request
|
||||
|
||||
**Agent Name**: Email Campaign Optimizer
|
||||
**Type**: Webhook
|
||||
**Category**: marketing
|
||||
**Price**: 4.0 AED
|
||||
**Short Description**: AI-powered email campaign optimization and A/B testing
|
||||
**Full Description**: Optimize your email campaigns with AI analysis of subject lines, content, and send times. Get recommendations for better open rates and conversions.
|
||||
|
||||
### Form Fields:
|
||||
- Field 1: [name: email_subject, type: text, label: "Email Subject Line", required: true]
|
||||
- Field 2: [name: email_content, type: textarea, label: "Email Content", required: true]
|
||||
- Field 3: [name: target_audience, type: select, label: "Target Audience", required: true, options: [{"value": "b2b", "label": "Business"}, {"value": "b2c", "label": "Consumer"}]]
|
||||
|
||||
**N8N Webhook URL**: http://localhost:5678/webhook/email-optimizer
|
||||
```
|
||||
|
||||
### Example 2: Direct Access Agent
|
||||
```markdown
|
||||
## New Agent Request
|
||||
|
||||
**Agent Name**: Financial Planning Consultant
|
||||
**Type**: Direct Access
|
||||
**Category**: consulting
|
||||
**Price**: 0.0 AED
|
||||
**Short Description**: Professional financial planning and investment consultation
|
||||
**Full Description**: Get expert financial advice tailored to your goals. Our certified financial planners provide personalized investment strategies and retirement planning.
|
||||
|
||||
### For Direct Access Agents:
|
||||
**External Form URL**: https://agent.jotform.com/financial-planning-form-id
|
||||
**Custom Template Needed**: No
|
||||
**Custom Views Needed**: No
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What Happens Next
|
||||
|
||||
After you provide the completed template:
|
||||
|
||||
1. ✅ **Claude creates JSON config** in `agents/configs/agents/`
|
||||
2. ✅ **Runs populate_agents command** to add agent to database
|
||||
3. ✅ **Agent appears in marketplace** automatically
|
||||
4. ✅ **Creates any needed templates/views** (for Direct Access agents)
|
||||
5. ✅ **Updates marketplace integration** if needed
|
||||
6. ✅ **Commits changes** and makes them Railway-ready
|
||||
|
||||
**No additional work needed on your part!** 🚀
|
||||
|
||||
---
|
||||
|
||||
## Tips for Better Requests
|
||||
|
||||
- ✅ **Use existing categories** - Avoid creating new ones unless absolutely necessary
|
||||
- ✅ **Be specific** - Clear descriptions help users understand the agent's value
|
||||
- ✅ **Test external forms** - Ensure JotForm/external URLs are working before requesting
|
||||
- ✅ **Consider pricing** - Free agents get more usage, paid agents need clear value proposition
|
||||
- ✅ **Think about fields** - For webhook agents, plan your form fields carefully
|
||||
|
||||
---
|
||||
|
||||
*For comprehensive agent creation details, see `docs/AGENT_CREATION.md`*
|
||||
@ -1,10 +1,10 @@
|
||||
=== Documentation Auto-Update Summary ===
|
||||
Update Date: 2025-08-01 09:23:11
|
||||
Update Date: 2025-08-01 01:37:22
|
||||
|
||||
Recent Commits:
|
||||
- 11d28a1 📚 Update documentation after GitHub push
|
||||
- f6970b6 🎨 Complete Phase 1 UI optimization with button hover fixes
|
||||
- 277e7ec 📄 Auto-update documentation timestamp after security fixes
|
||||
- c8ad34f 🔒 Implement critical security fixes for production readiness
|
||||
- 657712f 🗑️ Remove workflows app completely and streamline to agents-only
|
||||
|
||||
Documentation Changes:
|
||||
- CLAUDE.md
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -61,10 +61,6 @@ if config('RAILWAY_ENVIRONMENT', default=''):
|
||||
else:
|
||||
SITE_URL = config('SITE_URL', default='http://localhost:8000')
|
||||
|
||||
# Email verification requirement
|
||||
# Set to False for testing environments until final domain is ready
|
||||
REQUIRE_EMAIL_VERIFICATION = config('REQUIRE_EMAIL_VERIFICATION', default=True, cast=bool)
|
||||
|
||||
|
||||
# Application definition
|
||||
|
||||
|
||||
@ -4,7 +4,7 @@
|
||||
"builder": "NIXPACKS"
|
||||
},
|
||||
"deploy": {
|
||||
"startCommand": "python manage.py migrate; python manage.py populate_agents; python manage.py reset_admin; python manage.py verify_email admin@quantumtaskai.com --force || true; python manage.py collectstatic --noinput && gunicorn netcop_hub.wsgi:application --bind 0.0.0.0:$PORT --workers 1 --timeout 60",
|
||||
"startCommand": "python manage.py migrate --run-syncdb; python manage.py populate_agents; python manage.py reset_admin; python manage.py verify_email admin@quantumtaskai.com --force || true; python manage.py collectstatic --noinput && gunicorn netcop_hub.wsgi:application --bind 0.0.0.0:$PORT --workers 1 --timeout 60",
|
||||
"restartPolicyType": "ON_FAILURE",
|
||||
"restartPolicyMaxRetries": 3
|
||||
},
|
||||
|
||||
@ -8,7 +8,6 @@ gunicorn==21.2.0
|
||||
psycopg2-binary==2.9.9
|
||||
dj-database-url==2.1.0
|
||||
whitenoise==6.8.2
|
||||
reportlab==4.2.5
|
||||
|
||||
# Optional performance dependencies
|
||||
redis==5.2.0
|
||||
|
||||
@ -89,7 +89,7 @@ html {
|
||||
/* Layout - Data Analyzer Exact Copy */
|
||||
.agent-container {
|
||||
margin: 0 auto;
|
||||
padding: var(--spacing-sm);
|
||||
padding: var(--spacing-lg);
|
||||
max-width: 1600px;
|
||||
}
|
||||
|
||||
@ -99,7 +99,7 @@ html {
|
||||
border-radius: var(--radius);
|
||||
padding: var(--space-lg);
|
||||
border: var(--agent-card-border);
|
||||
margin-bottom: var(--space-md);
|
||||
margin-bottom: var(--space-lg);
|
||||
backdrop-filter: var(--agent-backdrop-filter);
|
||||
box-shadow: var(--agent-card-shadow);
|
||||
}
|
||||
@ -1207,7 +1207,7 @@ html {
|
||||
/* Agent Grid and Layout System */
|
||||
.agent-grid {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
gap: var(--spacing-lg);
|
||||
align-items: flex-start;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
@ -1216,7 +1216,7 @@ html {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
margin-bottom: 20px;
|
||||
margin-bottom: var(--spacing-xl);
|
||||
}
|
||||
|
||||
/* Typography - Data Analyzer Exact Copy */
|
||||
|
||||
@ -1,652 +0,0 @@
|
||||
/* Digital Branding Services Page Styles */
|
||||
/* Following homepage.css patterns and using unified color system from base.css */
|
||||
|
||||
/* Hero Section - matches homepage hero */
|
||||
.digital-branding-hero {
|
||||
position: relative;
|
||||
background: var(--gradient-hero);
|
||||
overflow: hidden;
|
||||
min-height: 85vh;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: clamp(40px, 10vw, 80px) clamp(16px, 4vw, 24px) clamp(60px, 15vw, 100px);
|
||||
}
|
||||
|
||||
.hero-container {
|
||||
max-width: 1280px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.trust-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: rgba(59, 130, 246, 0.08);
|
||||
padding: 0.5rem 1.25rem;
|
||||
border-radius: 50px;
|
||||
margin-bottom: 2.5rem;
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary-blue);
|
||||
border: 1px solid rgba(59, 130, 246, 0.15);
|
||||
backdrop-filter: blur(10px);
|
||||
}
|
||||
|
||||
.trust-badge-emoji {
|
||||
font-size: 0.75rem;
|
||||
}
|
||||
|
||||
.hero-title {
|
||||
font-weight: 800;
|
||||
margin-bottom: 2.5rem;
|
||||
line-height: 1.1;
|
||||
letter-spacing: -0.02em;
|
||||
font-size: clamp(36px, 8vw, 110px);
|
||||
margin-bottom: clamp(24px, 6vw, 40px);
|
||||
}
|
||||
|
||||
.hero-title-gradient {
|
||||
background: var(--gradient-primary);
|
||||
background-size: 300% 300%;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
}
|
||||
|
||||
.hero-title-normal {
|
||||
color: var(--text-primary);
|
||||
}
|
||||
|
||||
.hero-description {
|
||||
color: var(--text-secondary);
|
||||
margin-bottom: 3.5rem;
|
||||
max-width: 720px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
line-height: 1.7;
|
||||
font-weight: 400;
|
||||
font-size: clamp(1.1rem, 3vw, 1.4rem);
|
||||
margin-bottom: clamp(32px, 8vw, 56px);
|
||||
padding: 0 clamp(8px, 2vw, 16px);
|
||||
}
|
||||
|
||||
.hero-buttons {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
margin-bottom: 5rem;
|
||||
gap: clamp(12px, 3vw, 20px);
|
||||
margin-bottom: clamp(40px, 10vw, 80px);
|
||||
padding: 0 clamp(8px, 2vw, 16px);
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background: var(--gradient-primary);
|
||||
color: white;
|
||||
border-radius: 1rem;
|
||||
font-weight: bold;
|
||||
border: none;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 8px 24px rgba(59, 130, 246, 0.25), 0 4px 12px rgba(0, 0, 0, 0.05);
|
||||
letter-spacing: 0.01em;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
padding: clamp(14px, 4vw, 18px) clamp(24px, 6vw, 36px);
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
min-height: 48px;
|
||||
min-width: clamp(140px, 40vw, 180px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.4);
|
||||
filter: brightness(1.1);
|
||||
}
|
||||
|
||||
.btn-primary:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.2);
|
||||
}
|
||||
|
||||
.btn-secondary {
|
||||
background: var(--background-card);
|
||||
color: var(--primary-blue);
|
||||
border-radius: 1rem;
|
||||
font-weight: 600;
|
||||
border: 2px solid var(--border-light);
|
||||
text-decoration: none;
|
||||
box-shadow: 0 8px 24px rgba(0, 0, 0, 0.04), 0 4px 12px rgba(59, 130, 246, 0.08);
|
||||
letter-spacing: 0.01em;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
padding: clamp(14px, 4vw, 18px) clamp(24px, 6vw, 36px);
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
min-height: 48px;
|
||||
min-width: clamp(140px, 40vw, 180px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 8px 20px rgba(59, 130, 246, 0.15);
|
||||
border-color: var(--primary-blue);
|
||||
background: rgba(59, 130, 246, 0.05);
|
||||
}
|
||||
|
||||
.btn-secondary:active {
|
||||
transform: translateY(0);
|
||||
box-shadow: 0 4px 12px rgba(59, 130, 246, 0.12);
|
||||
}
|
||||
|
||||
.trust-indicators {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(150px, 100%), 1fr));
|
||||
gap: clamp(16px, 4vw, 48px);
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 0 clamp(8px, 2vw, 16px);
|
||||
}
|
||||
|
||||
.trust-card {
|
||||
text-align: center;
|
||||
background: rgba(255, 255, 255, 0.5);
|
||||
border: 1px solid rgba(255, 255, 255, 0.8);
|
||||
backdrop-filter: blur(10px);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.03);
|
||||
border-radius: 1rem;
|
||||
padding: clamp(16px, 4vw, 24px) clamp(12px, 3vw, 16px);
|
||||
}
|
||||
|
||||
.trust-number {
|
||||
background: var(--text-gradient);
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
background-clip: text;
|
||||
font-weight: 800;
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: clamp(1rem, 3vw, 1.2rem);
|
||||
}
|
||||
|
||||
.trust-text {
|
||||
color: var(--text-secondary);
|
||||
font-weight: 500;
|
||||
letter-spacing: 0.01em;
|
||||
font-size: clamp(12px, 3vw, 15px);
|
||||
}
|
||||
|
||||
/* Why Choose Us Section - matches company profile */
|
||||
.why-choose-us {
|
||||
position: relative;
|
||||
background: var(--company-gradient);
|
||||
overflow: hidden;
|
||||
padding: clamp(60px, 15vw, 120px) clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.section-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
text-align: center;
|
||||
margin-bottom: clamp(40px, 10vw, 80px);
|
||||
}
|
||||
|
||||
.section-badge {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
background: rgba(30, 64, 175, 0.1);
|
||||
padding: 0.5rem 1.25rem;
|
||||
border-radius: 50px;
|
||||
margin-bottom: 1.5rem;
|
||||
border: 1px solid rgba(30, 64, 175, 0.2);
|
||||
}
|
||||
|
||||
.section-badge-icon {
|
||||
font-size: 1rem;
|
||||
}
|
||||
|
||||
.section-badge-text {
|
||||
font-size: 0.875rem;
|
||||
font-weight: 600;
|
||||
color: var(--primary-blue);
|
||||
}
|
||||
|
||||
.section-title {
|
||||
font-weight: 800;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 1rem;
|
||||
text-align: center;
|
||||
font-size: clamp(2rem, 5vw, 3.5rem);
|
||||
}
|
||||
|
||||
.section-subtitle {
|
||||
font-size: 1.25rem;
|
||||
color: var(--text-light);
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.why-choose-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
|
||||
gap: clamp(24px, 6vw, 40px);
|
||||
}
|
||||
|
||||
.choice-card {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 24px);
|
||||
box-shadow: 0 8px 32px rgba(30, 64, 175, 0.08);
|
||||
text-align: center;
|
||||
padding: clamp(24px, 6vw, 40px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.choice-icon {
|
||||
margin-bottom: 1.25rem;
|
||||
font-size: clamp(2.5rem, 6vw, 3.5rem);
|
||||
margin-bottom: clamp(16px, 4vw, 20px);
|
||||
}
|
||||
|
||||
.choice-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 1rem;
|
||||
font-size: clamp(1.2rem, 4vw, 1.5rem);
|
||||
margin-bottom: clamp(12px, 3vw, 16px);
|
||||
}
|
||||
|
||||
.choice-description {
|
||||
color: var(--text-light);
|
||||
line-height: 1.6;
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
}
|
||||
|
||||
/* Our Process Section - matches services */
|
||||
.our-process {
|
||||
background: var(--services-gradient);
|
||||
padding: clamp(60px, 15vw, 120px) clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.process-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(280px, 100%), 1fr));
|
||||
gap: clamp(20px, 5vw, 32px);
|
||||
margin-bottom: clamp(40px, 10vw, 60px);
|
||||
}
|
||||
|
||||
.process-step-card {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 20px);
|
||||
box-shadow: 0 8px 32px rgba(30, 64, 175, 0.08);
|
||||
padding: clamp(24px, 6vw, 32px);
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: clamp(16px, 4vw, 20px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
background: var(--gradient-primary);
|
||||
color: white;
|
||||
width: clamp(40px, 10vw, 50px);
|
||||
height: clamp(40px, 10vw, 50px);
|
||||
border-radius: 50%;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
font-weight: bold;
|
||||
font-size: clamp(16px, 4vw, 20px);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.step-content {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.step-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: clamp(1.1rem, 3.5vw, 1.3rem);
|
||||
}
|
||||
|
||||
.step-description {
|
||||
color: var(--text-light);
|
||||
line-height: 1.6;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
}
|
||||
|
||||
/* RACE Framework */
|
||||
.race-framework {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 24px);
|
||||
box-shadow: 0 12px 40px rgba(30, 64, 175, 0.08);
|
||||
padding: clamp(24px, 6vw, 40px);
|
||||
}
|
||||
|
||||
.race-title {
|
||||
text-align: center;
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: clamp(20px, 5vw, 32px);
|
||||
font-size: clamp(1.3rem, 4vw, 1.8rem);
|
||||
}
|
||||
|
||||
.race-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(200px, 100%), 1fr));
|
||||
gap: clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.race-card {
|
||||
text-align: center;
|
||||
background: var(--background-light);
|
||||
border-radius: clamp(12px, 3vw, 16px);
|
||||
padding: clamp(16px, 4vw, 24px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.race-phase {
|
||||
margin-bottom: 0.75rem;
|
||||
}
|
||||
|
||||
.race-icon {
|
||||
font-size: clamp(1.5rem, 4vw, 2rem);
|
||||
margin-bottom: 0.5rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.race-phase h4 {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin: 0;
|
||||
font-size: clamp(1.1rem, 3.5vw, 1.3rem);
|
||||
}
|
||||
|
||||
.race-focus {
|
||||
font-weight: 600;
|
||||
color: var(--text-primary);
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
}
|
||||
|
||||
.race-actions {
|
||||
color: var(--text-light);
|
||||
font-size: clamp(12px, 3vw, 14px);
|
||||
line-height: 1.5;
|
||||
}
|
||||
|
||||
/* Branding Services Section - matches services */
|
||||
.branding-services {
|
||||
background: var(--clients-gradient);
|
||||
padding: clamp(60px, 15vw, 120px) clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.services-title {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--primary-blue);
|
||||
font-size: clamp(1.8rem, 5vw, 2.5rem);
|
||||
}
|
||||
|
||||
.services-subtitle {
|
||||
text-align: center;
|
||||
color: var(--text-light);
|
||||
margin-bottom: 3rem;
|
||||
font-size: clamp(16px, 4vw, 20px);
|
||||
margin-bottom: clamp(24px, 6vw, 48px);
|
||||
}
|
||||
|
||||
.branding-services-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(300px, 100%), 1fr));
|
||||
gap: clamp(20px, 5vw, 32px);
|
||||
}
|
||||
|
||||
.service-card {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 20px);
|
||||
box-shadow: 0 8px 32px rgba(30, 64, 175, 0.08);
|
||||
text-align: center;
|
||||
padding: clamp(24px, 6vw, 32px);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.service-icon {
|
||||
margin-bottom: 1.25rem;
|
||||
font-size: clamp(2.5rem, 6vw, 3rem);
|
||||
margin-bottom: clamp(16px, 4vw, 20px);
|
||||
}
|
||||
|
||||
.service-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 1rem;
|
||||
font-size: clamp(1.2rem, 4vw, 1.4rem);
|
||||
margin-bottom: clamp(12px, 3vw, 16px);
|
||||
}
|
||||
|
||||
.service-description {
|
||||
color: var(--text-light);
|
||||
line-height: 1.6;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
}
|
||||
|
||||
/* CTA Section - matches contact */
|
||||
.branding-cta {
|
||||
background: var(--contact-gradient);
|
||||
padding: clamp(60px, 15vw, 120px) clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.cta-container {
|
||||
max-width: 1200px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
.cta-title {
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
color: var(--primary-blue);
|
||||
font-size: clamp(1.8rem, 5vw, 2.5rem);
|
||||
margin-bottom: clamp(24px, 6vw, 48px);
|
||||
}
|
||||
|
||||
.cta-grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(min(350px, 100%), 1fr));
|
||||
gap: clamp(30px, 8vw, 60px);
|
||||
align-items: start;
|
||||
}
|
||||
|
||||
.cta-content {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 20px);
|
||||
box-shadow: 0 8px 32px rgba(30, 64, 175, 0.08);
|
||||
padding: clamp(24px, 6vw, 40px);
|
||||
}
|
||||
|
||||
.cta-content-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 1rem;
|
||||
font-size: clamp(1.3rem, 4vw, 1.6rem);
|
||||
}
|
||||
|
||||
.cta-description {
|
||||
color: var(--text-light);
|
||||
line-height: 1.6;
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
}
|
||||
|
||||
.cta-features {
|
||||
margin-bottom: 2rem;
|
||||
}
|
||||
|
||||
.cta-feature {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
}
|
||||
|
||||
.feature-icon {
|
||||
color: var(--success-green);
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
.cta-buttons {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: clamp(12px, 3vw, 16px);
|
||||
}
|
||||
|
||||
.cta-btn {
|
||||
padding: clamp(14px, 4vw, 16px) clamp(20px, 5vw, 24px);
|
||||
border-radius: clamp(8px, 2vw, 12px);
|
||||
font-weight: 600;
|
||||
text-decoration: none;
|
||||
text-align: center;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
transition: all 0.2s ease;
|
||||
min-height: 48px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.cta-btn.primary {
|
||||
background: var(--gradient-primary);
|
||||
color: white;
|
||||
box-shadow: 0 4px 16px rgba(59, 130, 246, 0.25);
|
||||
}
|
||||
|
||||
.cta-btn.primary:hover {
|
||||
transform: translateY(-2px);
|
||||
box-shadow: 0 6px 20px rgba(59, 130, 246, 0.35);
|
||||
}
|
||||
|
||||
.cta-btn.secondary {
|
||||
background: var(--background-card);
|
||||
color: var(--primary-blue);
|
||||
border: 2px solid var(--border-light);
|
||||
box-shadow: 0 4px 16px rgba(0, 0, 0, 0.05);
|
||||
}
|
||||
|
||||
.cta-btn.secondary:hover {
|
||||
transform: translateY(-2px);
|
||||
border-color: var(--primary-blue);
|
||||
background: rgba(59, 130, 246, 0.05);
|
||||
box-shadow: 0 6px 20px rgba(59, 130, 246, 0.15);
|
||||
}
|
||||
|
||||
.cta-info {
|
||||
background: white;
|
||||
border-radius: clamp(16px, 4vw, 20px);
|
||||
box-shadow: 0 8px 32px rgba(30, 64, 175, 0.08);
|
||||
padding: clamp(24px, 6vw, 40px);
|
||||
}
|
||||
|
||||
.cta-info-title {
|
||||
font-weight: bold;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 1.5rem;
|
||||
font-size: clamp(1.2rem, 4vw, 1.5rem);
|
||||
margin-bottom: clamp(16px, 4vw, 24px);
|
||||
}
|
||||
|
||||
.contact-item {
|
||||
display: flex;
|
||||
align-items: flex-start;
|
||||
gap: clamp(12px, 3vw, 16px);
|
||||
margin-bottom: clamp(20px, 5vw, 32px);
|
||||
}
|
||||
|
||||
.contact-icon {
|
||||
background: var(--primary-gradient);
|
||||
border-radius: clamp(8px, 2vw, 12px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
flex-shrink: 0;
|
||||
width: clamp(40px, 10vw, 50px);
|
||||
height: clamp(40px, 10vw, 50px);
|
||||
font-size: clamp(16px, 4vw, 20px);
|
||||
}
|
||||
|
||||
.contact-details h4 {
|
||||
font-weight: 600;
|
||||
color: var(--primary-blue);
|
||||
margin-bottom: 0.5rem;
|
||||
font-size: clamp(16px, 4vw, 19px);
|
||||
}
|
||||
|
||||
.contact-details p {
|
||||
color: var(--text-light);
|
||||
line-height: 1.6;
|
||||
font-size: clamp(14px, 3.5vw, 16px);
|
||||
}
|
||||
|
||||
.contact-email {
|
||||
color: var(--primary-blue);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.contact-email:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.commitment-statement {
|
||||
background: var(--services-gradient);
|
||||
border-left: 4px solid var(--primary-blue);
|
||||
border-radius: clamp(12px, 3vw, 16px);
|
||||
padding: clamp(16px, 4vw, 24px);
|
||||
margin-top: clamp(20px, 5vw, 32px);
|
||||
}
|
||||
|
||||
.commitment-text {
|
||||
color: var(--primary-blue);
|
||||
font-weight: 600;
|
||||
text-align: center;
|
||||
font-size: clamp(14px, 3.5vw, 18px);
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
/* Loading state for buttons */
|
||||
.cta-btn.loading {
|
||||
opacity: 0.7;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Mobile responsive adjustments */
|
||||
@media (max-width: 767px) {
|
||||
.cta-buttons {
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.process-step-card {
|
||||
flex-direction: column;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.step-number {
|
||||
margin: 0 auto 1rem auto;
|
||||
}
|
||||
|
||||
.race-grid {
|
||||
grid-template-columns: 1fr;
|
||||
}
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 13 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 488 B |
Binary file not shown.
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 513 B |
Binary file not shown.
|
Before Width: | Height: | Size: 102 KiB |
@ -478,109 +478,6 @@ class AgentsCore extends WorkflowsCore {
|
||||
return isValid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle JotForm agent execution (CyberSec Career Navigator)
|
||||
*/
|
||||
async handleJotFormAgent() {
|
||||
// Check authentication and balance
|
||||
if (!this.constructor.checkAuthentication()) return;
|
||||
if (!this.constructor.checkBalance(this.price)) return;
|
||||
|
||||
const submitBtn = document.getElementById('generateBtn');
|
||||
if (submitBtn) {
|
||||
submitBtn.disabled = true;
|
||||
submitBtn.textContent = '⏳ Processing Payment...';
|
||||
}
|
||||
|
||||
try {
|
||||
// Create execution record and charge wallet via form API
|
||||
const response = await fetch('/agents/api/form/access/', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'Content-Type': 'application/json',
|
||||
'X-CSRFToken': document.querySelector('[name=csrfmiddlewaretoken]').value
|
||||
},
|
||||
body: JSON.stringify({
|
||||
agent_slug: this.agentSlug
|
||||
})
|
||||
});
|
||||
|
||||
if (response.ok) {
|
||||
const result = await response.json();
|
||||
|
||||
// Update wallet balance
|
||||
this.constructor.updateWalletBalance(result.new_balance);
|
||||
|
||||
// Show white-label interface
|
||||
this.showWhiteLabelInterface(result.interface_url);
|
||||
|
||||
this.constructor.showToast('✅ Payment processed! Access granted to Quantum AI Career Navigator', 'success');
|
||||
|
||||
} else {
|
||||
const error = await response.json();
|
||||
throw new Error(error.error || 'Failed to process payment');
|
||||
}
|
||||
|
||||
} catch (error) {
|
||||
console.error('Form agent error:', error);
|
||||
this.constructor.showToast(`❌ ${error.message}`, 'error');
|
||||
this.resetSubmitButton();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Show white-label interface in results container
|
||||
*/
|
||||
showWhiteLabelInterface(interfaceUrl) {
|
||||
const resultsContainer = document.getElementById('resultsContainer');
|
||||
const resultsContent = document.getElementById('resultsContent');
|
||||
|
||||
if (resultsContainer && resultsContent) {
|
||||
// Update header
|
||||
const widgetTitle = resultsContainer.querySelector('.widget-title');
|
||||
if (widgetTitle) {
|
||||
widgetTitle.innerHTML = '<span class="widget-icon">🎓</span>Quantum AI Career Navigator';
|
||||
}
|
||||
|
||||
// Create white-label interface
|
||||
resultsContent.innerHTML = `
|
||||
<div class="career-nav-container" style="text-align: center; margin-bottom: 20px;">
|
||||
<h3 style="color: #0369a1; margin-bottom: 10px;">🎓 Quantum AI Career Navigator</h3>
|
||||
<p style="color: #6b7280; margin-bottom: 20px;">Meet Jessica, your personal AI cybersecurity career advisor. Share your goals and get expert guidance tailored to your journey.</p>
|
||||
</div>
|
||||
<div class="career-interface-container" style="width: 100%; min-height: 600px; border-radius: 12px; overflow: hidden; box-shadow: 0 4px 20px rgba(0,0,0,0.1);">
|
||||
<iframe
|
||||
src="${interfaceUrl}"
|
||||
style="width: 100%; min-height: 600px; border: none; background: white;"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="Quantum AI Career Navigator - Your Personal Career Advisor">
|
||||
</iframe>
|
||||
</div>
|
||||
<div class="career-footer" style="margin-top: 20px; padding: 15px; background: #f8fafc; border-radius: 8px; text-align: center;">
|
||||
<p style="color: #6b7280; font-size: 14px; margin: 0;">
|
||||
💡 <strong>Pro Tip:</strong> Be specific about your experience level and career goals for the most personalized advice from your AI advisor!
|
||||
</p>
|
||||
</div>
|
||||
`;
|
||||
|
||||
// Hide action buttons since this is an interactive interface
|
||||
const actionButtons = resultsContainer.querySelector('.results-actions');
|
||||
if (actionButtons) {
|
||||
actionButtons.style.display = 'none';
|
||||
}
|
||||
|
||||
// Show results container
|
||||
resultsContainer.style.display = 'block';
|
||||
|
||||
// Scroll to results
|
||||
resultsContainer.scrollIntoView({ behavior: 'smooth', block: 'start' });
|
||||
|
||||
// Reset submit button
|
||||
this.resetSubmitButton();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset submit button to original state
|
||||
*/
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}AI Brand Strategist - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Override main-container for full-width iframe */
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
height: calc(100vh - 80px); /* Account for header height */
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.iframe-container iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide footer for this page */
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe
|
||||
src="{{ form_url }}"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="AI Brand Strategist">
|
||||
</iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -104,37 +104,6 @@
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.verification-actions {
|
||||
text-align: center;
|
||||
margin-bottom: var(--spacing-lg);
|
||||
padding: var(--spacing-md);
|
||||
background: var(--surface-variant);
|
||||
border-radius: var(--radius-sm);
|
||||
border: 1px solid var(--outline);
|
||||
}
|
||||
|
||||
.verification-text {
|
||||
margin: 0 0 var(--spacing-sm) 0;
|
||||
color: var(--on-surface-variant);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.btn-outline {
|
||||
background: transparent;
|
||||
border: 1px solid var(--primary);
|
||||
color: var(--primary);
|
||||
}
|
||||
|
||||
.btn-outline:hover {
|
||||
background: var(--primary);
|
||||
color: var(--on-primary);
|
||||
}
|
||||
|
||||
.btn-sm {
|
||||
padding: var(--spacing-xs) var(--spacing-md);
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
/* Responsive */
|
||||
@media (max-width: 480px) {
|
||||
.login-page {
|
||||
@ -168,13 +137,6 @@
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
{% if show_resend_verification %}
|
||||
<div class="verification-actions">
|
||||
<p class="verification-text">Need to resend verification email?</p>
|
||||
<a href="{% url 'authentication:resend_verification' %}" class="btn btn-outline btn-sm">Resend Verification</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<form method="post" class="login-form">
|
||||
{% csrf_token %}
|
||||
{% if request.GET.next %}
|
||||
@ -214,6 +176,7 @@
|
||||
|
||||
<div class="login-auth-links">
|
||||
<p><a href="{% url 'authentication:forgot_password' %}">Forgot your password?</a></p>
|
||||
<p><a href="{% url 'authentication:resend_verification' %}">Resend email verification</a></p>
|
||||
<p>Don't have an account? <a href="{% url 'authentication:register' %}">Create account</a></p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@ -6,35 +6,6 @@
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{% block title %}Quantum Tasks AI - AI Platform{% endblock %}</title>
|
||||
|
||||
<!-- SEO Meta Tags -->
|
||||
<meta name="description" content="{% block description %}Quantum Tasks AI - Advanced AI agent marketplace for automation, analysis, and productivity. Access powerful AI tools for business and personal use.{% endblock %}">
|
||||
<meta name="keywords" content="AI, artificial intelligence, automation, AI agents, machine learning, productivity, business tools">
|
||||
<meta name="author" content="Quantum Tasks AI">
|
||||
|
||||
<!-- Open Graph Meta Tags for Rich Link Previews -->
|
||||
<meta property="og:type" content="website">
|
||||
<meta property="og:site_name" content="Quantum Tasks AI">
|
||||
<meta property="og:title" content="{% block og_title %}Quantum Tasks AI - AI Platform{% endblock %}">
|
||||
<meta property="og:description" content="{% block og_description %}Advanced AI agent marketplace for automation, analysis, and productivity. Access powerful AI tools for business and personal use.{% endblock %}">
|
||||
<meta property="og:url" content="{% block og_url %}https://quantumtaskai.com{{ request.get_full_path }}{% endblock %}">
|
||||
<meta property="og:image" content="{% block og_image %}https://quantumtaskai.com{% static 'img/og-image.png' %}{% endblock %}">
|
||||
<meta property="og:image:width" content="1200">
|
||||
<meta property="og:image:height" content="630">
|
||||
<meta property="og:image:alt" content="Quantum Tasks AI - AI Agent Marketplace">
|
||||
|
||||
<!-- Twitter Card Meta Tags -->
|
||||
<meta name="twitter:card" content="summary_large_image">
|
||||
<meta name="twitter:site" content="@quantumtaskai">
|
||||
<meta name="twitter:title" content="{% block twitter_title %}Quantum Tasks AI - AI Platform{% endblock %}">
|
||||
<meta name="twitter:description" content="{% block twitter_description %}Advanced AI agent marketplace for automation, analysis, and productivity. Access powerful AI tools for business and personal use.{% endblock %}">
|
||||
<meta name="twitter:image" content="{% block twitter_image %}https://quantumtaskai.com{% static 'img/og-image.png' %}{% endblock %}">
|
||||
|
||||
<!-- Favicon -->
|
||||
<link rel="icon" type="image/x-icon" href="{% static 'img/favicon.ico' %}">
|
||||
<link rel="apple-touch-icon" sizes="180x180" href="{% static 'img/apple-touch-icon.png' %}">
|
||||
<link rel="icon" type="image/png" sizes="32x32" href="{% static 'img/favicon-32x32.png' %}">
|
||||
<link rel="icon" type="image/png" sizes="16x16" href="{% static 'img/favicon-16x16.png' %}">
|
||||
|
||||
<!-- Unified Font Loading - Single Source of Truth -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||
@ -59,8 +30,8 @@
|
||||
</a>
|
||||
<nav class="header-nav" id="header-nav">
|
||||
<a href="{% url 'core:homepage' %}" class="nav-link {% if request.resolver_match.url_name == 'homepage' %}active{% endif %}">Home</a>
|
||||
<a href="{% url 'core:digital_branding' %}" class="nav-link {% if request.resolver_match.url_name == 'digital_branding' %}active{% endif %}">AI Digital Branding</a>
|
||||
<a href="{% url 'agents:marketplace' %}" class="nav-link {% if request.resolver_match.url_name == 'marketplace' %}active{% endif %}">AI Marketplace</a>
|
||||
<a href="{% url 'core:pricing' %}" class="nav-link {% if request.resolver_match.url_name == 'pricing' %}active{% endif %}">Pricing</a>
|
||||
</nav>
|
||||
<button class="mobile-nav-toggle" onclick="toggleMobileNav()" aria-label="Toggle navigation">
|
||||
☰
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Career Navigator - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Override main-container for full-width iframe */
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
height: calc(100vh - 80px); /* Account for header height */
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.iframe-container iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide footer for this page */
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe
|
||||
src="{{ form_url }}"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="Career Navigator">
|
||||
</iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -1,119 +0,0 @@
|
||||
{% if chat_session %}
|
||||
<div class="agent-widget widget-small" style="min-width: min(280px, 100%); max-width: min(280px, 100%); margin-left: auto;">
|
||||
<div class="widget-header">
|
||||
<h3 class="widget-title">
|
||||
<span class="widget-icon">💬</span>
|
||||
Current Session
|
||||
</h3>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
<div class="current-session-info">
|
||||
<div class="session-status-row">
|
||||
<span class="status-label">Status:</span>
|
||||
<span class="session-status status-{{ chat_session.status }}">
|
||||
{% if chat_session.status == 'active' %}
|
||||
✅ {{ chat_session.get_status_display }}
|
||||
{% elif chat_session.status == 'expired' %}
|
||||
⏰ {{ chat_session.get_status_display }}
|
||||
{% elif chat_session.status == 'completed' %}
|
||||
🏁 {{ chat_session.get_status_display }}
|
||||
{% else %}
|
||||
{{ chat_session.get_status_display }}
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="session-id-row">
|
||||
<span class="id-label">Session ID:</span>
|
||||
<span class="session-id">{{ chat_session.session_id }}</span>
|
||||
</div>
|
||||
|
||||
<div class="session-time-row">
|
||||
<span class="time-label">Started:</span>
|
||||
<span class="session-time">{{ chat_session.created_at|date:"M d, H:i" }}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.current-session-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.session-status-row,
|
||||
.session-id-row,
|
||||
.session-time-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
padding: var(--spacing-xs) 0;
|
||||
border-bottom: 1px solid var(--outline-variant);
|
||||
}
|
||||
|
||||
.session-status-row:last-child,
|
||||
.session-id-row:last-child,
|
||||
.session-time-row:last-child {
|
||||
border-bottom: none;
|
||||
}
|
||||
|
||||
.status-label,
|
||||
.id-label,
|
||||
.time-label {
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
|
||||
.session-status {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.session-status.status-active {
|
||||
color: #10b981;
|
||||
}
|
||||
|
||||
.session-status.status-expired {
|
||||
color: #f59e0b;
|
||||
}
|
||||
|
||||
.session-status.status-completed {
|
||||
color: #6366f1;
|
||||
}
|
||||
|
||||
.session-id {
|
||||
font-family: var(--font-mono);
|
||||
font-size: 11px;
|
||||
color: var(--on-surface-variant);
|
||||
background: var(--surface-variant);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
word-break: break-all;
|
||||
}
|
||||
|
||||
.session-time {
|
||||
font-size: 12px;
|
||||
color: var(--on-surface);
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.session-id-row {
|
||||
flex-direction: column;
|
||||
align-items: flex-start;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.session-id {
|
||||
font-size: 10px;
|
||||
align-self: stretch;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
@ -1,206 +0,0 @@
|
||||
{% if previous_sessions %}
|
||||
<div class="agent-widget widget-small" style="min-width: min(280px, 100%); max-width: min(280px, 100%); margin-left: auto;">
|
||||
<div class="widget-header">
|
||||
<h3 class="widget-title">
|
||||
<span class="widget-icon">📋</span>
|
||||
Previous Sessions
|
||||
</h3>
|
||||
</div>
|
||||
<div class="widget-content">
|
||||
{% for session in previous_sessions %}
|
||||
<div class="session-item">
|
||||
<div class="session-header">
|
||||
<div class="session-info">
|
||||
<span class="session-status status-{{ session.status }}">
|
||||
{% if session.status == 'completed' %}✅{% elif session.status == 'expired' %}⏰{% elif session.status == 'abandoned' %}❌{% endif %}
|
||||
{{ session.get_status_display }}
|
||||
</span>
|
||||
<span class="session-date">{{ session.created_at|date:"M d" }}</span>
|
||||
</div>
|
||||
<div class="session-stats">
|
||||
<span class="message-count">{{ session.user_message_count }}/{{ session.agent.message_limit }} msgs</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if session.user_message_count > 0 and session.status != 'active' %}
|
||||
<div class="session-actions">
|
||||
<div class="download-actions">
|
||||
<a href="{% url 'agents:export_chat' session.session_id %}?format=pdf"
|
||||
class="download-link pdf-link"
|
||||
title="Download PDF">
|
||||
📄 PDF
|
||||
</a>
|
||||
<a href="{% url 'agents:export_chat' session.session_id %}?format=txt"
|
||||
class="download-link txt-link"
|
||||
title="Download TXT">
|
||||
📝 TXT
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
|
||||
{% if previous_sessions|length >= 5 %}
|
||||
<div class="view-all-sessions">
|
||||
<a href="#" class="view-all-link" onclick="alert('Full session history coming soon!')">
|
||||
View All Sessions →
|
||||
</a>
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.session-item {
|
||||
padding: var(--spacing-sm);
|
||||
border: 1px solid var(--outline-variant);
|
||||
border-radius: var(--radius-sm);
|
||||
margin-bottom: var(--spacing-sm);
|
||||
background: var(--surface);
|
||||
transition: all 0.2s ease;
|
||||
}
|
||||
|
||||
.session-item:hover {
|
||||
background: var(--surface-variant);
|
||||
border-color: var(--primary);
|
||||
}
|
||||
|
||||
.session-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.session-header {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: flex-start;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.session-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 2px;
|
||||
}
|
||||
|
||||
.session-status {
|
||||
font-size: 12px;
|
||||
font-weight: 600;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
}
|
||||
|
||||
.session-status.status-completed {
|
||||
color: var(--success);
|
||||
}
|
||||
|
||||
.session-status.status-expired {
|
||||
color: var(--warning);
|
||||
}
|
||||
|
||||
.session-status.status-abandoned {
|
||||
color: var(--error);
|
||||
}
|
||||
|
||||
.session-date {
|
||||
font-size: 11px;
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
|
||||
.session-stats {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.message-count {
|
||||
font-size: 11px;
|
||||
color: var(--on-surface-variant);
|
||||
background: var(--surface-variant);
|
||||
padding: 2px 6px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.session-actions {
|
||||
border-top: 1px solid var(--outline-variant);
|
||||
padding-top: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.download-actions {
|
||||
display: flex;
|
||||
gap: var(--spacing-sm);
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.download-link {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 4px;
|
||||
padding: 4px 8px;
|
||||
background: var(--primary);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
border-radius: 4px;
|
||||
font-size: 11px;
|
||||
font-weight: 500;
|
||||
transition: all 0.2s ease;
|
||||
flex: 1;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.download-link:hover {
|
||||
background: var(--primary-dark);
|
||||
transform: translateY(-1px);
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
.download-link.pdf-link {
|
||||
background: #dc2626;
|
||||
}
|
||||
|
||||
.download-link.pdf-link:hover {
|
||||
background: #b91c1c;
|
||||
}
|
||||
|
||||
.download-link.txt-link {
|
||||
background: var(--primary);
|
||||
}
|
||||
|
||||
.download-link.txt-link:hover {
|
||||
background: var(--primary-dark);
|
||||
}
|
||||
|
||||
.view-all-sessions {
|
||||
margin-top: var(--spacing-sm);
|
||||
text-align: center;
|
||||
border-top: 1px solid var(--outline-variant);
|
||||
padding-top: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.view-all-link {
|
||||
font-size: 12px;
|
||||
color: var(--primary);
|
||||
text-decoration: none;
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.view-all-link:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.session-header {
|
||||
flex-direction: column;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.session-stats {
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.download-actions {
|
||||
flex-direction: column;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
@ -7,23 +7,29 @@
|
||||
</div>
|
||||
|
||||
<div class="quick-agents-grid">
|
||||
{% for agent in all_agents %}
|
||||
{% if agent.slug == 'cybersec-career-navigator' %}
|
||||
<a href="{% url 'agents:career_navigator_access' %}" class="quick-agent-card">
|
||||
{% else %}
|
||||
<a href="{% url 'agents:detail' agent.slug %}" class="quick-agent-card">
|
||||
{% endif %}
|
||||
<div class="agent-icon">{{ agent.category.icon }}</div>
|
||||
<div class="agent-info">
|
||||
<h4>{{ agent.name }}</h4>
|
||||
<div class="agent-price">{{ agent.price }} AED</div>
|
||||
</div>
|
||||
</a>
|
||||
{% empty %}
|
||||
<p style="text-align: center; color: var(--on-surface-variant); padding: 20px;">
|
||||
No other agents available
|
||||
</p>
|
||||
{% endfor %}
|
||||
<a href="/agents/social-ads-generator/" class="quick-agent-card">
|
||||
<div class="agent-icon">📢</div>
|
||||
<div class="agent-info">
|
||||
<h4>Social Ads Generator</h4>
|
||||
<p>Create social media ads</p>
|
||||
</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 professional job posts</p>
|
||||
</div>
|
||||
</a>
|
||||
|
||||
<a href="/agents/pdf-summarizer/" class="quick-agent-card">
|
||||
<div class="agent-icon">📄</div>
|
||||
<div class="agent-info">
|
||||
<h4>PDF Summarizer</h4>
|
||||
<p>Analyze and summarize PDFs</p>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="quick-agents-footer">
|
||||
|
||||
@ -1,200 +0,0 @@
|
||||
{% if chat_session and messages %}
|
||||
<div class="session-indicators">
|
||||
<h4 class="session-indicators-title">Session Status</h4>
|
||||
|
||||
<!-- Time Remaining Indicator -->
|
||||
<div class="indicator-item">
|
||||
<div class="indicator-header">
|
||||
<span class="indicator-icon">⏰</span>
|
||||
<span class="indicator-label">Time Remaining</span>
|
||||
<span class="indicator-value" id="timeRemaining">
|
||||
{% if time_remaining %}
|
||||
{{ time_remaining }}
|
||||
{% else %}
|
||||
Calculating...
|
||||
{% endif %}
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill time-progress" id="timeProgress" style="width: {{ time_percentage|default:100 }}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Messages Remaining Indicator -->
|
||||
<div class="indicator-item">
|
||||
<div class="indicator-header">
|
||||
<span class="indicator-icon">💬</span>
|
||||
<span class="indicator-label">Messages</span>
|
||||
<span class="indicator-value" id="messageCount">
|
||||
{{ message_count|default:0 }}/{{ message_limit }} used
|
||||
</span>
|
||||
</div>
|
||||
<div class="progress-bar">
|
||||
<div class="progress-fill message-progress" id="messageProgress" style="width: {{ message_percentage|default:0 }}%"></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Warning Messages -->
|
||||
<div class="session-warnings" id="sessionWarnings">
|
||||
{% if time_percentage <= 20 %}
|
||||
<div class="warning-item time-warning">
|
||||
⚠️ Session expires soon!
|
||||
</div>
|
||||
{% endif %}
|
||||
{% if message_percentage >= 80 %}
|
||||
<div class="warning-item message-warning">
|
||||
⚠️ Approaching message limit!
|
||||
</div>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style>
|
||||
.session-indicators {
|
||||
background: var(--surface);
|
||||
border: 1px solid var(--outline-variant);
|
||||
border-radius: var(--radius-lg);
|
||||
padding: var(--spacing-lg);
|
||||
margin-bottom: var(--spacing-md);
|
||||
box-shadow: var(--shadow-sm);
|
||||
min-width: min(280px, 100%);
|
||||
max-width: min(280px, 100%);
|
||||
margin-left: auto;
|
||||
}
|
||||
|
||||
.session-indicators-title {
|
||||
font-size: 16px;
|
||||
font-weight: 600;
|
||||
color: var(--on-surface);
|
||||
margin: 0 0 var(--spacing-md) 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.indicator-item {
|
||||
margin-bottom: var(--spacing-md);
|
||||
}
|
||||
|
||||
.indicator-item:last-of-type {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.indicator-header {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.indicator-icon {
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.indicator-label {
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
color: var(--on-surface);
|
||||
flex: 1;
|
||||
margin-left: var(--spacing-sm);
|
||||
}
|
||||
|
||||
.indicator-value {
|
||||
font-size: 13px;
|
||||
font-weight: 600;
|
||||
color: var(--on-surface-variant);
|
||||
}
|
||||
|
||||
.progress-bar {
|
||||
width: 100%;
|
||||
height: 6px;
|
||||
background: var(--surface-variant);
|
||||
border-radius: 3px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.progress-fill {
|
||||
height: 100%;
|
||||
border-radius: 3px;
|
||||
transition: width 0.3s ease, background-color 0.3s ease;
|
||||
}
|
||||
|
||||
.time-progress {
|
||||
background: linear-gradient(90deg, #10b981, #059669);
|
||||
}
|
||||
|
||||
.time-progress[style*="width: 0"],
|
||||
.time-progress[style*="width: 1"],
|
||||
.time-progress[style*="width: 2"] {
|
||||
background: linear-gradient(90deg, #ef4444, #dc2626);
|
||||
}
|
||||
|
||||
.time-progress[style*="width: 3"],
|
||||
.time-progress[style*="width: 4"],
|
||||
.time-progress[style*="width: 5"],
|
||||
.time-progress[style*="width: 10"],
|
||||
.time-progress[style*="width: 15"],
|
||||
.time-progress[style*="width: 20"] {
|
||||
background: linear-gradient(90deg, #f59e0b, #d97706);
|
||||
}
|
||||
|
||||
.message-progress {
|
||||
background: linear-gradient(90deg, #3b82f6, #2563eb);
|
||||
}
|
||||
|
||||
.message-progress[style*="width: 8"],
|
||||
.message-progress[style*="width: 9"] {
|
||||
background: linear-gradient(90deg, #f59e0b, #d97706);
|
||||
}
|
||||
|
||||
.message-progress[style*="width: 95"],
|
||||
.message-progress[style*="width: 96"],
|
||||
.message-progress[style*="width: 97"],
|
||||
.message-progress[style*="width: 98"],
|
||||
.message-progress[style*="width: 99"],
|
||||
.message-progress[style*="width: 100"] {
|
||||
background: linear-gradient(90deg, #ef4444, #dc2626);
|
||||
}
|
||||
|
||||
.session-warnings {
|
||||
margin-top: var(--spacing-md);
|
||||
}
|
||||
|
||||
.warning-item {
|
||||
background: #fef3c7;
|
||||
color: #92400e;
|
||||
padding: var(--spacing-sm) var(--spacing-md);
|
||||
border-radius: var(--radius-sm);
|
||||
font-size: 13px;
|
||||
font-weight: 500;
|
||||
margin-bottom: var(--spacing-xs);
|
||||
border-left: 3px solid #f59e0b;
|
||||
}
|
||||
|
||||
.warning-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
.time-warning {
|
||||
background: #fee2e2;
|
||||
color: #991b1b;
|
||||
border-left-color: #ef4444;
|
||||
}
|
||||
|
||||
@media (max-width: 768px) {
|
||||
.session-indicators {
|
||||
padding: var(--spacing-md);
|
||||
}
|
||||
|
||||
.indicator-header {
|
||||
flex-wrap: wrap;
|
||||
gap: var(--spacing-xs);
|
||||
}
|
||||
|
||||
.indicator-value {
|
||||
flex-basis: 100%;
|
||||
text-align: right;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
{% endif %}
|
||||
@ -1,523 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}AI Digital Branding Services - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/digital-branding.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<style>
|
||||
/* Override main-container for full-width sections */
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- Hero Section -->
|
||||
<section id="digital-branding-hero" class="digital-branding-hero">
|
||||
<div class="hero-container">
|
||||
<!-- Trust Badge -->
|
||||
<div class="trust-badge">
|
||||
<span class="trust-badge-emoji">✨</span>
|
||||
<span>Trusted Digital Brand Partner</span>
|
||||
</div>
|
||||
|
||||
<h1 class="hero-title">
|
||||
<span class="hero-title-gradient">
|
||||
AI-Powered Digital Branding
|
||||
</span>
|
||||
<br />
|
||||
<span class="hero-title-normal">
|
||||
Intelligence
|
||||
</span>
|
||||
</h1>
|
||||
|
||||
<p class="hero-description">
|
||||
Elevate Your Brand with Intelligent Digital Strategies. Combine proven marketing expertise with AI automation to accelerate growth, optimize performance, and deliver measurable results that matter.
|
||||
</p>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="hero-buttons">
|
||||
{% if user.is_authenticated %}
|
||||
<a href="https://form.jotform.com/252121444918050" target="_blank" class="btn-primary">
|
||||
Start Discovery
|
||||
</a>
|
||||
<a href="#our-process" class="btn-secondary">
|
||||
View Process
|
||||
</a>
|
||||
{% else %}
|
||||
<a href="https://form.jotform.com/252121444918050" target="_blank" class="btn-primary">
|
||||
Get Started
|
||||
</a>
|
||||
<a href="#our-process" class="btn-secondary">
|
||||
Learn More
|
||||
</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
|
||||
<!-- Trust Indicators -->
|
||||
<div class="trust-indicators">
|
||||
<div class="trust-card">
|
||||
<div class="trust-number">
|
||||
250%
|
||||
</div>
|
||||
<div class="trust-text">
|
||||
Average ROI Increase
|
||||
</div>
|
||||
</div>
|
||||
<div class="trust-card">
|
||||
<div class="trust-number">
|
||||
3x
|
||||
</div>
|
||||
<div class="trust-text">
|
||||
Faster Content Creation
|
||||
</div>
|
||||
</div>
|
||||
<div class="trust-card">
|
||||
<div class="trust-number">
|
||||
24/7
|
||||
</div>
|
||||
<div class="trust-text">
|
||||
Performance Monitoring
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Why Choose Us Section -->
|
||||
<section id="why-choose-us" class="why-choose-us">
|
||||
<div class="section-container">
|
||||
<!-- Section Header -->
|
||||
<div class="section-header">
|
||||
<div class="section-badge">
|
||||
<span class="section-badge-icon">🎯</span>
|
||||
<span class="section-badge-text">Why Choose Us</span>
|
||||
</div>
|
||||
<h2 class="section-title">
|
||||
Intelligent Digital Excellence
|
||||
</h2>
|
||||
<p class="section-subtitle">
|
||||
Combine proven digital strategies with smart automation and data insights to accelerate your brand's growth and market impact
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="why-choose-grid">
|
||||
<div class="choice-card">
|
||||
<div class="choice-icon">🤖</div>
|
||||
<h3 class="choice-title">Data-Driven Brand Intelligence</h3>
|
||||
<p class="choice-description">
|
||||
Advanced analytics and automation for real-time audience insights, trend forecasting, and competitive intelligence. Our smart systems continuously optimize your strategy based on performance data.
|
||||
</p>
|
||||
</div>
|
||||
<div class="choice-card">
|
||||
<div class="choice-icon">🌐</div>
|
||||
<h3 class="choice-title">Comprehensive Digital Automation</h3>
|
||||
<p class="choice-description">
|
||||
End-to-end digital presence management with smart automation, content optimization, intelligent scheduling, SEO enhancement, and reputation management for maximum efficiency and impact.
|
||||
</p>
|
||||
</div>
|
||||
<div class="choice-card">
|
||||
<div class="choice-icon">⚡</div>
|
||||
<h3 class="choice-title">Smart Personalization & Optimization</h3>
|
||||
<p class="choice-description">
|
||||
Intelligent systems that learn your brand identity, automatically adapt strategies for your market, and continuously optimize campaigns based on performance data and market insights.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Our Process Section -->
|
||||
<section id="our-process" class="our-process">
|
||||
<div class="section-container">
|
||||
<div class="section-header">
|
||||
<div class="section-badge">
|
||||
<span class="section-badge-icon">📋</span>
|
||||
<span class="section-badge-text">Our Process</span>
|
||||
</div>
|
||||
<h2 class="section-title">
|
||||
AI-Enhanced SOSTAC+RACE Framework
|
||||
</h2>
|
||||
<p class="section-subtitle">
|
||||
Our proven methodology supercharged with artificial intelligence, machine learning insights, and automated optimization at every stage
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div class="process-grid">
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">1</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">AI-Powered Situation Analysis</h3>
|
||||
<p class="step-description">
|
||||
Deploy machine learning algorithms to analyze your brand's digital DNA, competitive intelligence automation, and predictive market positioning with real-time data insights.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">2</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">AI-Optimized Objectives</h3>
|
||||
<p class="step-description">
|
||||
Generate data-driven SMART goals using predictive analytics, automated KPI tracking, and AI-powered performance forecasting with continuous goal optimization.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">3</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">Intelligent Strategy Design</h3>
|
||||
<p class="step-description">
|
||||
AI-driven customer journey mapping, automated audience segmentation, dynamic value proposition testing, and intelligent channel selection with performance optimization.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">4</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">AI-Automated Tactics (RACE Framework)</h3>
|
||||
<p class="step-description">
|
||||
Deploy intelligent automation for Reach (AI-powered visibility), Act (automated engagement), Convert (smart sales funnels), and Engage (AI-driven loyalty programs).
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">5</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">Automated Action Execution</h3>
|
||||
<p class="step-description">
|
||||
AI-powered task automation, intelligent timeline management, and automated brand asset generation with smart content creation and deployment systems.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="process-step-card">
|
||||
<div class="step-number">6</div>
|
||||
<div class="step-content">
|
||||
<h3 class="step-title">Intelligent Control & Optimization</h3>
|
||||
<p class="step-description">
|
||||
Real-time AI monitoring, predictive KPI analysis, automated strategy refinement, and continuous machine learning optimization with performance forecasting.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- RACE Framework Details -->
|
||||
<div class="race-framework">
|
||||
<h3 class="race-title">RACE Framework Breakdown</h3>
|
||||
<div class="race-grid">
|
||||
<div class="race-card">
|
||||
<div class="race-phase">
|
||||
<span class="race-icon">📢</span>
|
||||
<h4>Reach</h4>
|
||||
</div>
|
||||
<div class="race-focus">AI-Powered Visibility</div>
|
||||
<div class="race-actions">Automated LLM optimization, AI-driven SEO, smart ad targeting, AI influencer matching, automated PR distribution</div>
|
||||
</div>
|
||||
<div class="race-card">
|
||||
<div class="race-phase">
|
||||
<span class="race-icon">💬</span>
|
||||
<h4>Act</h4>
|
||||
</div>
|
||||
<div class="race-focus">Intelligent Engagement</div>
|
||||
<div class="race-actions">AI content generation, dynamic landing pages, chatbot interactions, automated social responses</div>
|
||||
</div>
|
||||
<div class="race-card">
|
||||
<div class="race-phase">
|
||||
<span class="race-icon">🎯</span>
|
||||
<h4>Convert</h4>
|
||||
</div>
|
||||
<div class="race-focus">Smart Conversions</div>
|
||||
<div class="race-actions">AI-optimized CTAs, predictive retargeting, automated lead scoring, intelligent funnel optimization</div>
|
||||
</div>
|
||||
<div class="race-card">
|
||||
<div class="race-phase">
|
||||
<span class="race-icon">❤️</span>
|
||||
<h4>Engage</h4>
|
||||
</div>
|
||||
<div class="race-focus">AI-Driven Loyalty</div>
|
||||
<div class="race-actions">Automated email personalization, AI community management, predictive advocacy, smart retention campaigns</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Services Section -->
|
||||
<section id="services" class="branding-services">
|
||||
<div class="section-container">
|
||||
<h2 class="services-title">
|
||||
AI-Powered Service Portfolio
|
||||
</h2>
|
||||
<p class="services-subtitle">
|
||||
Advanced artificial intelligence solutions that automate, optimize, and accelerate your digital brand transformation
|
||||
</p>
|
||||
<div class="branding-services-grid">
|
||||
<div class="service-card">
|
||||
<div class="service-icon">🎨</div>
|
||||
<h3 class="service-title">Brand Discovery & Smart Identity Design</h3>
|
||||
<p class="service-description">
|
||||
Complete brand audit enhanced with AI insights, strategic identity creation, and adaptive design systems that evolve with market trends and audience data.
|
||||
</p>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">📱</div>
|
||||
<h3 class="service-title">Strategic Platform Management & Automation</h3>
|
||||
<p class="service-description">
|
||||
Smart platform selection and optimization, automated content distribution, intelligent scheduling, and performance optimization across social media, websites, and digital touchpoints.
|
||||
</p>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">🔍</div>
|
||||
<h3 class="service-title">Advanced Content & Marketing Automation</h3>
|
||||
<p class="service-description">
|
||||
AI-enhanced content creation, automated SEO optimization, intelligent ad targeting and social media management with real-time performance adjustments for maximum impact.
|
||||
</p>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">📢</div>
|
||||
<h3 class="service-title">Influencer Partnerships & Digital PR</h3>
|
||||
<p class="service-description">
|
||||
Strategic influencer discovery and matching, automated PR campaign management, smart media outreach, and comprehensive relationship management for maximum brand amplification.
|
||||
</p>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">🎯</div>
|
||||
<h3 class="service-title">Brand Consistency & Messaging Systems</h3>
|
||||
<p class="service-description">
|
||||
Unified brand guidelines with automated enforcement, intelligent messaging frameworks, smart visual asset management, and consistent brand voice across all platforms.
|
||||
</p>
|
||||
</div>
|
||||
<div class="service-card">
|
||||
<div class="service-icon">📊</div>
|
||||
<h3 class="service-title">Predictive AI Analytics & Automated Insights</h3>
|
||||
<p class="service-description">
|
||||
Real-time predictive analytics, automated performance optimization, AI-generated insights and recommendations, with intelligent forecasting and proactive strategy adjustments.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- CTA Section -->
|
||||
<section id="discovery-form" class="branding-cta">
|
||||
<div class="cta-container">
|
||||
<h2 class="cta-title">
|
||||
Accelerate Your Digital Brand Growth
|
||||
</h2>
|
||||
<div class="cta-grid">
|
||||
<!-- CTA Content -->
|
||||
<div class="cta-content">
|
||||
<h3 class="cta-content-title">Ready to transform your digital brand presence?</h3>
|
||||
<p class="cta-description">
|
||||
Complete our Digital Brand Strategy Assessment and receive a customized growth roadmap with smart automation recommendations within 24 hours.
|
||||
</p>
|
||||
|
||||
<!-- Features List -->
|
||||
<div class="cta-features">
|
||||
<div class="cta-feature">
|
||||
<span class="feature-icon">✓</span>
|
||||
<span>Free comprehensive brand analysis</span>
|
||||
</div>
|
||||
<div class="cta-feature">
|
||||
<span class="feature-icon">✓</span>
|
||||
<span>Personalized growth automation roadmap</span>
|
||||
</div>
|
||||
<div class="cta-feature">
|
||||
<span class="feature-icon">✓</span>
|
||||
<span>Custom strategy proposal in 24 hours</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- CTA Buttons -->
|
||||
<div class="cta-buttons">
|
||||
<!-- <a href="https://form.jotform.com/252121444918050" target="_blank" class="cta-btn primary">
|
||||
🚀 Get Discovery Questionnaire
|
||||
</a> -->
|
||||
<a href="https://form.jotform.com/252121444918050" target="_blank" class="cta-btn secondary">
|
||||
💬 Contact Us Directly
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Contact Information -->
|
||||
<div class="cta-info">
|
||||
<h3 class="cta-info-title">Get in Touch</h3>
|
||||
|
||||
<!-- Contact Item -->
|
||||
<div class="contact-item">
|
||||
<div class="contact-icon">
|
||||
✉️
|
||||
</div>
|
||||
<div class="contact-details">
|
||||
<h4>Email Address</h4>
|
||||
<p>
|
||||
<a href="mailto:abhay@quantumtaskai.com" class="contact-email">
|
||||
abhay@quantumtaskai.com
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Commitment Statement -->
|
||||
<div class="commitment-statement">
|
||||
<p class="commitment-text">
|
||||
Leading the AI Revolution in Digital Branding - Where Artificial Intelligence Meets Brand Excellence for Unprecedented Growth and Automation.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
<script>
|
||||
class DigitalBrandingManager {
|
||||
constructor() {
|
||||
this.processCards = document.querySelectorAll('.process-step-card');
|
||||
this.raceCards = document.querySelectorAll('.race-card');
|
||||
this.serviceCards = document.querySelectorAll('.service-card');
|
||||
this.ctaButtons = document.querySelectorAll('.cta-btn');
|
||||
|
||||
this.init();
|
||||
}
|
||||
|
||||
init() {
|
||||
this.setupCardInteractions();
|
||||
this.setupButtonHovers();
|
||||
this.addScrollAnimations();
|
||||
this.setupSmoothScrolling();
|
||||
}
|
||||
|
||||
setupCardInteractions() {
|
||||
// Process step cards
|
||||
this.processCards.forEach(card => {
|
||||
card.addEventListener('mouseenter', () => {
|
||||
this.highlightCard(card);
|
||||
});
|
||||
|
||||
card.addEventListener('mouseleave', () => {
|
||||
this.removeHighlight(card);
|
||||
});
|
||||
});
|
||||
|
||||
// RACE framework cards
|
||||
this.raceCards.forEach(card => {
|
||||
card.addEventListener('mouseenter', () => {
|
||||
this.highlightCard(card);
|
||||
});
|
||||
|
||||
card.addEventListener('mouseleave', () => {
|
||||
this.removeHighlight(card);
|
||||
});
|
||||
});
|
||||
|
||||
// Service cards
|
||||
this.serviceCards.forEach(card => {
|
||||
card.addEventListener('mouseenter', () => {
|
||||
this.highlightCard(card);
|
||||
});
|
||||
|
||||
card.addEventListener('mouseleave', () => {
|
||||
this.removeHighlight(card);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
highlightCard(card) {
|
||||
card.style.transform = 'translateY(-4px)';
|
||||
card.style.boxShadow = '0 20px 40px rgba(30, 64, 175, 0.15)';
|
||||
}
|
||||
|
||||
removeHighlight(card) {
|
||||
card.style.transform = 'translateY(0)';
|
||||
card.style.boxShadow = '';
|
||||
}
|
||||
|
||||
setupButtonHovers() {
|
||||
this.ctaButtons.forEach(button => {
|
||||
button.addEventListener('mouseenter', () => {
|
||||
button.style.transform = 'translateY(-2px)';
|
||||
});
|
||||
|
||||
button.addEventListener('mouseleave', () => {
|
||||
button.style.transform = '';
|
||||
});
|
||||
|
||||
button.addEventListener('click', () => {
|
||||
if (!button.classList.contains('loading')) {
|
||||
button.classList.add('loading');
|
||||
const originalText = button.textContent;
|
||||
button.textContent = '⏳ Loading...';
|
||||
|
||||
setTimeout(() => {
|
||||
if (button.classList.contains('loading')) {
|
||||
button.classList.remove('loading');
|
||||
button.textContent = originalText;
|
||||
}
|
||||
}, 2000);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
addScrollAnimations() {
|
||||
if ('IntersectionObserver' in window) {
|
||||
const observerOptions = {
|
||||
threshold: 0.1,
|
||||
rootMargin: '0px 0px -50px 0px'
|
||||
};
|
||||
|
||||
const observer = new IntersectionObserver((entries) => {
|
||||
entries.forEach(entry => {
|
||||
if (entry.isIntersecting) {
|
||||
entry.target.style.opacity = '1';
|
||||
entry.target.style.transform = 'translateY(0)';
|
||||
}
|
||||
});
|
||||
}, observerOptions);
|
||||
|
||||
// Observe cards for scroll animations
|
||||
[...this.processCards, ...this.raceCards, ...this.serviceCards].forEach((card, index) => {
|
||||
card.style.opacity = '0';
|
||||
card.style.transform = 'translateY(20px)';
|
||||
card.style.transition = `opacity 0.6s ease ${index * 0.1}s, transform 0.6s ease ${index * 0.1}s`;
|
||||
observer.observe(card);
|
||||
});
|
||||
|
||||
// Observe sections
|
||||
document.querySelectorAll('.section-header, .cta-content').forEach(section => {
|
||||
section.style.opacity = '0';
|
||||
section.style.transform = 'translateY(20px)';
|
||||
section.style.transition = 'opacity 0.6s ease, transform 0.6s ease';
|
||||
observer.observe(section);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
setupSmoothScrolling() {
|
||||
document.querySelectorAll('a[href^="#"]').forEach(anchor => {
|
||||
anchor.addEventListener('click', function (e) {
|
||||
e.preventDefault();
|
||||
const target = document.querySelector(this.getAttribute('href'));
|
||||
if (target) {
|
||||
target.scrollIntoView({
|
||||
behavior: 'smooth',
|
||||
block: 'start'
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize when DOM is loaded
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
new DigitalBrandingManager();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
@ -1,43 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Event - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Override main-container for full-width iframe */
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
height: calc(100vh - 80px); /* Account for header height */
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.iframe-container iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide footer for this page */
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe
|
||||
src="{{ form_url }}"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="Event">
|
||||
</iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -3,11 +3,6 @@
|
||||
|
||||
{% block title %}Quantum Tasks AI - AI & Task Automation Solutions{% endblock %}
|
||||
|
||||
{% block description %}Discover powerful AI agents for automation, analysis, and productivity. Access premium AI tools for social media, business analysis, document processing, and more.{% endblock %}
|
||||
|
||||
{% block og_title %}Quantum Tasks AI - AI & Task Automation Solutions{% endblock %}
|
||||
{% block og_description %}Discover powerful AI agents for automation, analysis, and productivity. Access premium AI tools for social media, business analysis, document processing, and more.{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<link rel="stylesheet" href="{% static 'css/homepage.css' %}">
|
||||
{% endblock %}
|
||||
|
||||
@ -1,43 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}Lean Six Sigma Expert - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
/* Override main-container for full-width iframe */
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
height: calc(100vh - 80px); /* Account for header height */
|
||||
}
|
||||
|
||||
.iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.iframe-container iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
|
||||
/* Hide footer for this page */
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe
|
||||
src="{{ form_url }}"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="Lean Six Sigma Expert">
|
||||
</iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -1,38 +0,0 @@
|
||||
{% extends 'base.html' %}
|
||||
{% load static %}
|
||||
|
||||
{% block title %}SWOT Analysis Expert - Quantum Tasks AI{% endblock %}
|
||||
|
||||
{% block extra_css %}
|
||||
<style>
|
||||
.main-container {
|
||||
max-width: none;
|
||||
padding: 0;
|
||||
height: calc(100vh - 80px);
|
||||
}
|
||||
.iframe-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
}
|
||||
.iframe-container iframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
border: none;
|
||||
display: block;
|
||||
}
|
||||
.footer {
|
||||
display: none !important;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
<div class="iframe-container">
|
||||
<iframe
|
||||
src="{{ form_url }}"
|
||||
frameborder="0"
|
||||
scrolling="auto"
|
||||
title="SWOT Analysis Expert">
|
||||
</iframe>
|
||||
</div>
|
||||
{% endblock %}
|
||||
@ -79,22 +79,16 @@ def wallet_topup_view(request):
|
||||
return redirect('wallet:wallet_topup')
|
||||
except Exception as e:
|
||||
logger.error(f"Checkout session creation failed for user {request.user.id}: {e}")
|
||||
messages.error(request, 'Payment failed. Try again.')
|
||||
messages.error(request, 'Unable to process payment at this time. Please try again.')
|
||||
return redirect('wallet:wallet_topup')
|
||||
|
||||
return render(request, 'wallet/wallet_topup.html')
|
||||
|
||||
|
||||
@login_required
|
||||
@ratelimit(key='user', rate='10/m', method='GET', block=False)
|
||||
def wallet_topup_success_view(request):
|
||||
"""Payment success page with automatic payment verification"""
|
||||
# Check authentication first and clear any messages if redirecting to login
|
||||
if not request.user.is_authenticated:
|
||||
# Clear any existing messages to prevent them from showing on login page
|
||||
storage = messages.get_messages(request)
|
||||
storage.used = True
|
||||
return redirect('authentication:login')
|
||||
|
||||
# Check if rate limited
|
||||
if getattr(request, 'limited', False):
|
||||
logger.warning(f"Payment success page rate limit exceeded for user {request.user.id}")
|
||||
@ -105,7 +99,7 @@ def wallet_topup_success_view(request):
|
||||
|
||||
if not session_id:
|
||||
logger.warning(f"No session ID provided for user {request.user.id}")
|
||||
messages.error(request, 'Payment session not found.')
|
||||
messages.error(request, 'No payment session found. Please contact support if you completed a payment.')
|
||||
return redirect('wallet:wallet')
|
||||
|
||||
# Verify payment directly with Stripe API
|
||||
@ -117,10 +111,10 @@ def wallet_topup_success_view(request):
|
||||
|
||||
if result['success']:
|
||||
if result['processed']:
|
||||
messages.success(request, f'{result["amount"]} AED added to wallet.')
|
||||
messages.success(request, f'Payment successful! {result["amount"]} AED has been added to your wallet.')
|
||||
logger.info(f"Payment verified and wallet updated for user {request.user.id}")
|
||||
else:
|
||||
messages.info(request, 'Payment already processed.')
|
||||
messages.info(request, 'Payment already processed. Your wallet balance is up to date.')
|
||||
logger.info(f"Payment already processed for session {session_id}")
|
||||
else:
|
||||
messages.warning(request, 'Payment verification failed. Please contact support.')
|
||||
@ -128,21 +122,15 @@ def wallet_topup_success_view(request):
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Error verifying payment for user {request.user.id}: {e}")
|
||||
messages.error(request, 'Payment verification failed.')
|
||||
messages.error(request, 'Unable to verify payment. Please contact support if you completed a payment.')
|
||||
|
||||
return redirect('wallet:wallet')
|
||||
|
||||
|
||||
@login_required
|
||||
def wallet_topup_cancel_view(request):
|
||||
"""Payment cancel page"""
|
||||
# Check authentication first and clear any messages if redirecting to login
|
||||
if not request.user.is_authenticated:
|
||||
# Clear any existing messages to prevent them from showing on login page
|
||||
storage = messages.get_messages(request)
|
||||
storage.used = True
|
||||
return redirect('authentication:login')
|
||||
|
||||
messages.info(request, 'Payment cancelled.')
|
||||
messages.info(request, 'Payment was cancelled. No charges were made.')
|
||||
return redirect('wallet:wallet_topup')
|
||||
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user