mirror of
https://github.com/thecyberlearn/quantum-ai-v3.git
synced 2026-08-18 19:52:57 +00:00
🚀 Implement file-based agent system for instant deployment
BREAKING CHANGE: Transform from database-driven to file-based agent management Major Features: • File-based agent definitions - agents load from JSON configs instantly • Hybrid architecture - files for agent data, database for relationships • Zero-command deployment - just add JSON file and git push • Automatic database sync - maintains foreign key compatibility • Template compatibility - enriched agent data works with existing UI Technical Implementation: • AgentFileService - comprehensive file-based agent management • JSON config loading with LRU caching for performance • Category enrichment for template compatibility • Slug-based queries for AgentExecution relationships • get_or_create_agent_db_record() for foreign key maintenance Benefits: • Ultra-simple agent creation (just add JSON file) • Instant Railway deployment (no commands needed) • Version control integration (agent changes in git) • Perfect scalability (ready for 100+ agents) • Zero maintenance overhead All 8 agents verified working: - 4 Webhook agents: Social Ads, Job Posting, PDF Summarizer, 5 Whys - 4 Direct access agents: Career Navigator, Brand Strategist, Lean Six Sigma, SWOT 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
2ffd0aae50
commit
56749b77f0
347
agents/services.py
Normal file
347
agents/services.py
Normal file
@ -0,0 +1,347 @@
|
|||||||
|
import json
|
||||||
|
import os
|
||||||
|
from functools import lru_cache
|
||||||
|
from pathlib import Path
|
||||||
|
from typing import Dict, List, Optional
|
||||||
|
from django.conf import settings
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
class AgentFileService:
|
||||||
|
"""
|
||||||
|
Service for loading agent configurations from JSON files instead of database.
|
||||||
|
Provides caching and error handling for file-based agent management.
|
||||||
|
"""
|
||||||
|
|
||||||
|
BASE_DIR = Path(__file__).resolve().parent.parent
|
||||||
|
AGENTS_CONFIG_DIR = BASE_DIR / 'agents' / 'configs' / 'agents'
|
||||||
|
CATEGORIES_CONFIG_FILE = BASE_DIR / 'agents' / 'configs' / 'categories' / 'categories.json'
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def clear_cache(cls):
|
||||||
|
"""Clear all cached data - useful for testing and development"""
|
||||||
|
cls.get_all_agents.cache_clear()
|
||||||
|
cls.get_all_categories.cache_clear()
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@lru_cache(maxsize=1)
|
||||||
|
def get_all_categories(cls) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Load all agent categories from categories.json file.
|
||||||
|
Returns list of category dictionaries with caching.
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
if not cls.CATEGORIES_CONFIG_FILE.exists():
|
||||||
|
logger.warning(f"Categories file not found: {cls.CATEGORIES_CONFIG_FILE}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
with open(cls.CATEGORIES_CONFIG_FILE, 'r', encoding='utf-8') as f:
|
||||||
|
categories = json.load(f)
|
||||||
|
|
||||||
|
# Handle both array format and object format
|
||||||
|
if isinstance(categories, dict) and 'categories' in categories:
|
||||||
|
categories = categories['categories']
|
||||||
|
elif not isinstance(categories, list):
|
||||||
|
logger.error("Categories file should contain an array of categories")
|
||||||
|
return []
|
||||||
|
|
||||||
|
logger.info(f"Loaded {len(categories)} categories from file")
|
||||||
|
return categories
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading categories: {str(e)}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
@lru_cache(maxsize=1)
|
||||||
|
def get_all_agents(cls) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Load all agent configurations from JSON files in the agents config directory.
|
||||||
|
Returns list of agent dictionaries with caching.
|
||||||
|
"""
|
||||||
|
agents = []
|
||||||
|
|
||||||
|
try:
|
||||||
|
if not cls.AGENTS_CONFIG_DIR.exists():
|
||||||
|
logger.warning(f"Agents config directory not found: {cls.AGENTS_CONFIG_DIR}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
# Get all JSON files in the agents config directory
|
||||||
|
json_files = list(cls.AGENTS_CONFIG_DIR.glob('*.json'))
|
||||||
|
|
||||||
|
for json_file in json_files:
|
||||||
|
try:
|
||||||
|
with open(json_file, 'r', encoding='utf-8') as f:
|
||||||
|
agent_data = json.load(f)
|
||||||
|
|
||||||
|
# Add file-based metadata
|
||||||
|
agent_data['_source_file'] = str(json_file)
|
||||||
|
agent_data['_file_name'] = json_file.name
|
||||||
|
|
||||||
|
# Ensure required fields exist with defaults
|
||||||
|
agent_data.setdefault('is_active', True)
|
||||||
|
agent_data.setdefault('agent_type', 'form')
|
||||||
|
agent_data.setdefault('system_type', 'webhook')
|
||||||
|
agent_data.setdefault('form_schema', {'fields': []})
|
||||||
|
agent_data.setdefault('access_url_name', '')
|
||||||
|
agent_data.setdefault('display_url_name', '')
|
||||||
|
|
||||||
|
agents.append(agent_data)
|
||||||
|
|
||||||
|
except json.JSONDecodeError as e:
|
||||||
|
logger.error(f"Invalid JSON in {json_file}: {str(e)}")
|
||||||
|
continue
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error loading agent from {json_file}: {str(e)}")
|
||||||
|
continue
|
||||||
|
|
||||||
|
logger.info(f"Loaded {len(agents)} agents from {len(json_files)} files")
|
||||||
|
return agents
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logger.error(f"Error scanning agents directory: {str(e)}")
|
||||||
|
return []
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_agent_by_slug(cls, slug: str) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Get a specific agent by its slug with category info enriched.
|
||||||
|
Returns agent dictionary or None if not found.
|
||||||
|
"""
|
||||||
|
agents = cls.get_all_agents()
|
||||||
|
for agent in agents:
|
||||||
|
if agent.get('slug') == slug:
|
||||||
|
enriched_agents = cls._enrich_agents_with_category_info([agent])
|
||||||
|
return enriched_agents[0] if enriched_agents else agent
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_agents_by_category(cls, category_slug: str) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Get all agents belonging to a specific category.
|
||||||
|
Returns list of agent dictionaries with category info enriched.
|
||||||
|
"""
|
||||||
|
agents = cls.get_all_agents()
|
||||||
|
category_agents = [agent for agent in agents if agent.get('category') == category_slug]
|
||||||
|
return cls._enrich_agents_with_category_info(category_agents)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_active_agents(cls) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Get all active agents with category info enriched.
|
||||||
|
Returns list of active agent dictionaries.
|
||||||
|
"""
|
||||||
|
agents = cls.get_all_agents()
|
||||||
|
active_agents = [agent for agent in agents if agent.get('is_active', True)]
|
||||||
|
return cls._enrich_agents_with_category_info(active_agents)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def search_agents(cls, query: str) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Search agents by name or description.
|
||||||
|
Returns list of matching agent dictionaries with category info enriched.
|
||||||
|
"""
|
||||||
|
if not query:
|
||||||
|
return cls.get_active_agents()
|
||||||
|
|
||||||
|
query_lower = query.lower()
|
||||||
|
agents = cls.get_all_agents()
|
||||||
|
active_agents = [agent for agent in agents if agent.get('is_active', True)]
|
||||||
|
|
||||||
|
matching_agents = []
|
||||||
|
for agent in active_agents:
|
||||||
|
name = agent.get('name', '').lower()
|
||||||
|
description = agent.get('description', '').lower()
|
||||||
|
short_description = agent.get('short_description', '').lower()
|
||||||
|
|
||||||
|
if (query_lower in name or
|
||||||
|
query_lower in description or
|
||||||
|
query_lower in short_description):
|
||||||
|
matching_agents.append(agent)
|
||||||
|
|
||||||
|
return cls._enrich_agents_with_category_info(matching_agents)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_category_by_slug(cls, slug: str) -> Optional[Dict]:
|
||||||
|
"""
|
||||||
|
Get a specific category by its slug.
|
||||||
|
Returns category dictionary or None if not found.
|
||||||
|
"""
|
||||||
|
categories = cls.get_all_categories()
|
||||||
|
for category in categories:
|
||||||
|
if category.get('slug') == slug:
|
||||||
|
return category
|
||||||
|
return None
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def validate_agent_config(cls, agent_data: Dict) -> List[str]:
|
||||||
|
"""
|
||||||
|
Validate an agent configuration dictionary.
|
||||||
|
Returns list of validation errors (empty if valid).
|
||||||
|
"""
|
||||||
|
errors = []
|
||||||
|
required_fields = ['slug', 'name', 'short_description', 'description', 'category', 'price']
|
||||||
|
|
||||||
|
for field in required_fields:
|
||||||
|
if not agent_data.get(field):
|
||||||
|
errors.append(f"Missing required field: {field}")
|
||||||
|
|
||||||
|
# Validate price is numeric
|
||||||
|
try:
|
||||||
|
float(agent_data.get('price', 0))
|
||||||
|
except (ValueError, TypeError):
|
||||||
|
errors.append("Price must be a valid number")
|
||||||
|
|
||||||
|
# Validate category exists
|
||||||
|
category_slug = agent_data.get('category')
|
||||||
|
if category_slug and not cls.get_category_by_slug(category_slug):
|
||||||
|
errors.append(f"Category '{category_slug}' does not exist")
|
||||||
|
|
||||||
|
# Validate system_type
|
||||||
|
system_type = agent_data.get('system_type', 'webhook')
|
||||||
|
if system_type not in ['webhook', 'direct_access']:
|
||||||
|
errors.append("system_type must be 'webhook' or 'direct_access'")
|
||||||
|
|
||||||
|
return errors
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_agent_stats(cls) -> Dict:
|
||||||
|
"""
|
||||||
|
Get statistics about agents and categories.
|
||||||
|
Returns dictionary with counts and breakdown.
|
||||||
|
"""
|
||||||
|
agents = cls.get_all_agents()
|
||||||
|
categories = cls.get_all_categories()
|
||||||
|
|
||||||
|
active_agents = cls.get_active_agents()
|
||||||
|
webhook_agents = [a for a in active_agents if a.get('system_type') == 'webhook']
|
||||||
|
direct_access_agents = [a for a in active_agents if a.get('system_type') == 'direct_access']
|
||||||
|
|
||||||
|
# Category breakdown (use raw agents to avoid category object issue)
|
||||||
|
category_counts = {}
|
||||||
|
raw_active_agents = [agent for agent in agents if agent.get('is_active', True)]
|
||||||
|
for agent in raw_active_agents:
|
||||||
|
category = agent.get('category', 'unknown')
|
||||||
|
category_counts[category] = category_counts.get(category, 0) + 1
|
||||||
|
|
||||||
|
return {
|
||||||
|
'total_agents': len(agents),
|
||||||
|
'active_agents': len(active_agents),
|
||||||
|
'webhook_agents': len(webhook_agents),
|
||||||
|
'direct_access_agents': len(direct_access_agents),
|
||||||
|
'total_categories': len(categories),
|
||||||
|
'category_breakdown': category_counts
|
||||||
|
}
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def _enrich_agents_with_category_info(cls, agents: List[Dict]) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Enrich agent dictionaries with category information for template compatibility.
|
||||||
|
Adds category object with icon, name, and slug for each agent.
|
||||||
|
"""
|
||||||
|
categories = cls.get_all_categories()
|
||||||
|
category_map = {cat['slug']: cat for cat in categories}
|
||||||
|
|
||||||
|
enriched_agents = []
|
||||||
|
for agent in agents:
|
||||||
|
agent_copy = agent.copy()
|
||||||
|
category_slug = agent.get('category')
|
||||||
|
|
||||||
|
if category_slug and category_slug in category_map:
|
||||||
|
# Add category object for template compatibility
|
||||||
|
category_data = category_map[category_slug]
|
||||||
|
agent_copy['category'] = {
|
||||||
|
'slug': category_data['slug'],
|
||||||
|
'name': category_data['name'],
|
||||||
|
'icon': category_data['icon'],
|
||||||
|
'description': category_data.get('description', '')
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Fallback category
|
||||||
|
agent_copy['category'] = {
|
||||||
|
'slug': 'unknown',
|
||||||
|
'name': 'Unknown',
|
||||||
|
'icon': '❓',
|
||||||
|
'description': 'Unknown category'
|
||||||
|
}
|
||||||
|
|
||||||
|
enriched_agents.append(agent_copy)
|
||||||
|
|
||||||
|
return enriched_agents
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_or_create_agent_db_record(cls, agent_data: Dict):
|
||||||
|
"""
|
||||||
|
Get or create a database Agent record for foreign key relationships.
|
||||||
|
This maintains compatibility with AgentExecution while using file-based configs.
|
||||||
|
"""
|
||||||
|
from .models import Agent, AgentCategory
|
||||||
|
|
||||||
|
# Get or create category
|
||||||
|
category_data = cls.get_category_by_slug(agent_data.get('category', 'unknown'))
|
||||||
|
if category_data:
|
||||||
|
category, _ = AgentCategory.objects.get_or_create(
|
||||||
|
slug=category_data['slug'],
|
||||||
|
defaults={
|
||||||
|
'name': category_data['name'],
|
||||||
|
'description': category_data.get('description', ''),
|
||||||
|
'icon': category_data['icon'],
|
||||||
|
'is_active': True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
category, _ = AgentCategory.objects.get_or_create(
|
||||||
|
slug='unknown',
|
||||||
|
defaults={
|
||||||
|
'name': 'Unknown',
|
||||||
|
'description': 'Unknown category',
|
||||||
|
'icon': '❓',
|
||||||
|
'is_active': True
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Get or create agent
|
||||||
|
agent, created = Agent.objects.get_or_create(
|
||||||
|
slug=agent_data['slug'],
|
||||||
|
defaults={
|
||||||
|
'name': agent_data['name'],
|
||||||
|
'short_description': agent_data['short_description'],
|
||||||
|
'description': agent_data['description'],
|
||||||
|
'category': category,
|
||||||
|
'price': agent_data['price'],
|
||||||
|
'agent_type': agent_data.get('agent_type', 'form'),
|
||||||
|
'form_schema': agent_data.get('form_schema', {}),
|
||||||
|
'webhook_url': agent_data['webhook_url'],
|
||||||
|
'message_limit': agent_data.get('message_limit', 50),
|
||||||
|
'access_url_name': agent_data.get('access_url_name', ''),
|
||||||
|
'display_url_name': agent_data.get('display_url_name', ''),
|
||||||
|
'is_active': agent_data.get('is_active', True)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Update existing record if needed (sync file data to db)
|
||||||
|
if not created:
|
||||||
|
updated = False
|
||||||
|
for field, value in {
|
||||||
|
'name': agent_data['name'],
|
||||||
|
'short_description': agent_data['short_description'],
|
||||||
|
'description': agent_data['description'],
|
||||||
|
'price': agent_data['price'],
|
||||||
|
'agent_type': agent_data.get('agent_type', 'form'),
|
||||||
|
'form_schema': agent_data.get('form_schema', {}),
|
||||||
|
'webhook_url': agent_data['webhook_url'],
|
||||||
|
'message_limit': agent_data.get('message_limit', 50),
|
||||||
|
'access_url_name': agent_data.get('access_url_name', ''),
|
||||||
|
'display_url_name': agent_data.get('display_url_name', ''),
|
||||||
|
'is_active': agent_data.get('is_active', True),
|
||||||
|
'category': category
|
||||||
|
}.items():
|
||||||
|
if getattr(agent, field) != value:
|
||||||
|
setattr(agent, field, value)
|
||||||
|
updated = True
|
||||||
|
|
||||||
|
if updated:
|
||||||
|
agent.save()
|
||||||
|
|
||||||
|
return agent
|
||||||
309
agents/views.py
309
agents/views.py
@ -8,8 +8,9 @@ from django.utils import timezone
|
|||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from .models import Agent, AgentExecution, AgentCategory, ChatSession, ChatMessage
|
from .models import Agent, AgentExecution, ChatSession, ChatMessage
|
||||||
from .serializers import AgentSerializer, AgentExecutionSerializer
|
from .serializers import AgentExecutionSerializer
|
||||||
|
from .services import AgentFileService
|
||||||
import requests
|
import requests
|
||||||
import json
|
import json
|
||||||
import time
|
import time
|
||||||
@ -66,29 +67,30 @@ def validate_webhook_url(url):
|
|||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
def agent_list(request):
|
def agent_list(request):
|
||||||
"""List all active agents with optional category filtering"""
|
"""List all active agents with optional category filtering"""
|
||||||
agents = Agent.objects.filter(is_active=True)
|
agents = AgentFileService.get_active_agents()
|
||||||
|
|
||||||
category = request.GET.get('category')
|
category = request.GET.get('category')
|
||||||
if category:
|
if category:
|
||||||
agents = agents.filter(category__slug=category)
|
agents = AgentFileService.get_agents_by_category(category)
|
||||||
|
|
||||||
search = request.GET.get('search')
|
search = request.GET.get('search')
|
||||||
if search:
|
if search:
|
||||||
agents = agents.filter(name__icontains=search)
|
agents = AgentFileService.search_agents(search)
|
||||||
|
|
||||||
paginator = PageNumberPagination()
|
paginator = PageNumberPagination()
|
||||||
paginator.page_size = 20
|
paginator.page_size = 20
|
||||||
result_page = paginator.paginate_queryset(agents, request)
|
result_page = paginator.paginate_queryset(agents, request)
|
||||||
serializer = AgentSerializer(result_page, many=True)
|
# Return the data directly since we're working with dictionaries
|
||||||
return paginator.get_paginated_response(serializer.data)
|
return paginator.get_paginated_response(result_page)
|
||||||
|
|
||||||
@api_view(['GET'])
|
@api_view(['GET'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
def agent_detail(request, slug):
|
def agent_detail(request, slug):
|
||||||
"""Get detailed agent information"""
|
"""Get detailed agent information"""
|
||||||
agent = get_object_or_404(Agent, slug=slug, is_active=True)
|
agent = AgentFileService.get_agent_by_slug(slug)
|
||||||
serializer = AgentSerializer(agent)
|
if not agent or not agent.get('is_active', True):
|
||||||
return Response(serializer.data)
|
return Response({'error': 'Agent not found'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
return Response(agent)
|
||||||
|
|
||||||
@api_view(['POST'])
|
@api_view(['POST'])
|
||||||
@permission_classes([IsAuthenticated])
|
@permission_classes([IsAuthenticated])
|
||||||
@ -100,15 +102,31 @@ def execute_agent(request):
|
|||||||
if not agent_slug:
|
if not agent_slug:
|
||||||
return Response({'error': 'agent_slug is required'}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': 'agent_slug is required'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
agent = get_object_or_404(Agent, slug=agent_slug, is_active=True)
|
agent_data = AgentFileService.get_agent_by_slug(agent_slug)
|
||||||
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
|
return Response({'error': 'Agent not found'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
# Convert agent data to a simple object for compatibility
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug'] # Use slug as ID for file-based agents
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has sufficient balance (using existing wallet system)
|
# Check if user has sufficient balance (using existing wallet system)
|
||||||
if hasattr(request.user, 'has_sufficient_balance') and not request.user.has_sufficient_balance(agent.price):
|
if hasattr(request.user, 'has_sufficient_balance') and not request.user.has_sufficient_balance(agent.price):
|
||||||
return Response({'error': 'Insufficient wallet balance'}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': 'Insufficient wallet balance'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
# Create execution record
|
# Create execution record
|
||||||
execution = AgentExecution.objects.create(
|
execution = AgentExecution.objects.create(
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
input_data=input_data,
|
input_data=input_data,
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
@ -205,12 +223,22 @@ def career_navigator_access(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the career navigator agent
|
# Get the career navigator agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('cybersec-career-navigator')
|
||||||
agent = Agent.objects.get(slug='cybersec-career-navigator', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'Career Navigator is currently unavailable.')
|
messages.error(request, 'Career Navigator is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has sufficient balance
|
# Check if user has sufficient balance
|
||||||
if not request.user.has_sufficient_balance(agent.price):
|
if not request.user.has_sufficient_balance(agent.price):
|
||||||
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the Career Navigator.')
|
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the Career Navigator.')
|
||||||
@ -227,9 +255,12 @@ def career_navigator_access(request):
|
|||||||
messages.error(request, 'Failed to process payment. Please try again.')
|
messages.error(request, 'Failed to process payment. Please try again.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
# Create execution record for tracking
|
# Create execution record for tracking
|
||||||
execution = AgentExecution.objects.create(
|
execution = AgentExecution.objects.create(
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
@ -258,18 +289,28 @@ def career_navigator_view(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the career navigator agent
|
# Get the career navigator agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('cybersec-career-navigator')
|
||||||
agent = Agent.objects.get(slug='cybersec-career-navigator', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'Career Navigator is currently unavailable.')
|
messages.error(request, 'Career Navigator is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
recent_execution = AgentExecution.objects.filter(
|
recent_execution = AgentExecution.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent.slug, # Changed to slug-based lookup
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='completed',
|
status='completed',
|
||||||
created_at__gte=timezone.now() - timedelta(hours=2)
|
created_at__gte=timezone.now() - timedelta(hours=2)
|
||||||
@ -301,18 +342,28 @@ def ai_brand_strategist_view(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the AI Brand Strategist agent
|
# Get the AI Brand Strategist agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('ai-brand-strategist')
|
||||||
agent = Agent.objects.get(slug='ai-brand-strategist', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'AI Brand Strategist is currently unavailable.')
|
messages.error(request, 'AI Brand Strategist is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
recent_execution = AgentExecution.objects.filter(
|
recent_execution = AgentExecution.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent.slug, # Changed to slug-based lookup
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='completed',
|
status='completed',
|
||||||
created_at__gte=timezone.now() - timedelta(hours=2)
|
created_at__gte=timezone.now() - timedelta(hours=2)
|
||||||
@ -344,12 +395,22 @@ def ai_brand_strategist_access(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the AI Brand Strategist agent
|
# Get the AI Brand Strategist agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('ai-brand-strategist')
|
||||||
agent = Agent.objects.get(slug='ai-brand-strategist', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'AI Brand Strategist is currently unavailable.')
|
messages.error(request, 'AI Brand Strategist is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has sufficient balance
|
# Check if user has sufficient balance
|
||||||
if not request.user.has_sufficient_balance(agent.price):
|
if not request.user.has_sufficient_balance(agent.price):
|
||||||
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the AI Brand Strategist.')
|
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the AI Brand Strategist.')
|
||||||
@ -366,9 +427,12 @@ def ai_brand_strategist_access(request):
|
|||||||
messages.error(request, 'Failed to process payment. Please try again.')
|
messages.error(request, 'Failed to process payment. Please try again.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
# Create execution record for tracking
|
# Create execution record for tracking
|
||||||
execution = AgentExecution.objects.create(
|
execution = AgentExecution.objects.create(
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
@ -436,15 +500,18 @@ def format_agent_message(agent_slug, input_data):
|
|||||||
@login_required
|
@login_required
|
||||||
def agent_detail_view(request, slug):
|
def agent_detail_view(request, slug):
|
||||||
"""Render agent detail page with dynamic form or chat interface"""
|
"""Render agent detail page with dynamic form or chat interface"""
|
||||||
agent = get_object_or_404(Agent, slug=slug, is_active=True)
|
agent = AgentFileService.get_agent_by_slug(slug)
|
||||||
|
if not agent or not agent.get('is_active', True):
|
||||||
|
from django.http import Http404
|
||||||
|
raise Http404("Agent not found")
|
||||||
|
|
||||||
# Handle chat-based agents
|
# Handle chat-based agents
|
||||||
if agent.agent_type == 'chat':
|
if agent.get('agent_type') == 'chat':
|
||||||
return chat_agent_view(request, agent)
|
return chat_agent_view(request, agent)
|
||||||
|
|
||||||
# Handle form-based agents (existing behavior)
|
# Handle form-based agents (existing behavior)
|
||||||
# Get all other active agents for quick access panel
|
# Get all other active agents for quick access panel
|
||||||
all_agents = Agent.objects.filter(is_active=True).exclude(id=agent.id).select_related('category')
|
all_agents = [a for a in AgentFileService.get_active_agents() if a['slug'] != slug]
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'agent': agent,
|
'agent': agent,
|
||||||
@ -457,22 +524,19 @@ def agent_detail_view(request, slug):
|
|||||||
|
|
||||||
def agents_marketplace(request):
|
def agents_marketplace(request):
|
||||||
"""Agent marketplace view"""
|
"""Agent marketplace view"""
|
||||||
agents = Agent.objects.filter(is_active=True).select_related('category')
|
# Get agents from file service
|
||||||
categories = AgentCategory.objects.filter(is_active=True)
|
agents = AgentFileService.get_active_agents()
|
||||||
|
categories = AgentFileService.get_all_categories()
|
||||||
|
|
||||||
# Filter by category
|
# Filter by category
|
||||||
category_slug = request.GET.get('category')
|
category_slug = request.GET.get('category')
|
||||||
if category_slug:
|
if category_slug:
|
||||||
agents = agents.filter(category__slug=category_slug)
|
agents = AgentFileService.get_agents_by_category(category_slug)
|
||||||
|
|
||||||
# Search functionality
|
# Search functionality
|
||||||
search_query = request.GET.get('search', '').strip()
|
search_query = request.GET.get('search', '').strip()
|
||||||
if search_query:
|
if search_query:
|
||||||
agents = agents.filter(
|
agents = AgentFileService.search_agents(search_query)
|
||||||
models.Q(name__icontains=search_query) |
|
|
||||||
models.Q(short_description__icontains=search_query) |
|
|
||||||
models.Q(description__icontains=search_query)
|
|
||||||
)
|
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'agents': agents,
|
'agents': agents,
|
||||||
@ -491,10 +555,25 @@ def chat_agent_view(request, agent):
|
|||||||
chat_session = None
|
chat_session = None
|
||||||
messages = []
|
messages = []
|
||||||
|
|
||||||
|
# Convert file-based agent data to compatible object if needed
|
||||||
|
if isinstance(agent, dict):
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug'] # Use slug as ID for file-based agents
|
||||||
|
self.message_limit = data.get('message_limit', 50)
|
||||||
|
|
||||||
|
agent_compat = AgentCompat(agent)
|
||||||
|
else:
|
||||||
|
agent_compat = agent
|
||||||
|
|
||||||
if request.user.is_authenticated:
|
if request.user.is_authenticated:
|
||||||
# Get or create active chat session
|
# Get or create active chat session (using slug-based filter for file agents)
|
||||||
chat_session = ChatSession.objects.filter(
|
chat_session = ChatSession.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent_compat.slug, # Changed to slug-based lookup
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='active'
|
status='active'
|
||||||
).first()
|
).first()
|
||||||
@ -504,7 +583,7 @@ def chat_agent_view(request, agent):
|
|||||||
if session_id and not chat_session:
|
if session_id and not chat_session:
|
||||||
chat_session = ChatSession.objects.filter(
|
chat_session = ChatSession.objects.filter(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
agent=agent,
|
agent__slug=agent_compat.slug, # Changed to slug-based lookup
|
||||||
user=request.user
|
user=request.user
|
||||||
).first()
|
).first()
|
||||||
|
|
||||||
@ -513,11 +592,11 @@ def chat_agent_view(request, agent):
|
|||||||
messages = ChatMessage.objects.filter(session=chat_session).order_by('timestamp')
|
messages = ChatMessage.objects.filter(session=chat_session).order_by('timestamp')
|
||||||
|
|
||||||
# Get all other active agents for quick access panel
|
# Get all other active agents for quick access panel
|
||||||
all_agents = Agent.objects.filter(is_active=True).exclude(id=agent.id).select_related('category')
|
all_agents = [a for a in AgentFileService.get_active_agents() if a['slug'] != agent_compat.slug]
|
||||||
|
|
||||||
# Get previous sessions for this user and agent (excluding current active session)
|
# Get previous sessions for this user and agent (excluding current active session)
|
||||||
previous_sessions_query = ChatSession.objects.filter(
|
previous_sessions_query = ChatSession.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent_compat.slug, # Changed to slug-based lookup
|
||||||
user=request.user
|
user=request.user
|
||||||
).exclude(status='active').order_by('-created_at')[:5] # Last 5 non-active sessions
|
).exclude(status='active').order_by('-created_at')[:5] # Last 5 non-active sessions
|
||||||
|
|
||||||
@ -555,7 +634,7 @@ def chat_agent_view(request, agent):
|
|||||||
|
|
||||||
# Message calculations (only count user messages)
|
# Message calculations (only count user messages)
|
||||||
user_message_count = messages.filter(message_type='user').count()
|
user_message_count = messages.filter(message_type='user').count()
|
||||||
message_limit = agent.message_limit
|
message_limit = agent_compat.message_limit
|
||||||
message_percentage = min(100, (user_message_count / message_limit) * 100)
|
message_percentage = min(100, (user_message_count / message_limit) * 100)
|
||||||
|
|
||||||
session_data = {
|
session_data = {
|
||||||
@ -567,7 +646,7 @@ def chat_agent_view(request, agent):
|
|||||||
}
|
}
|
||||||
|
|
||||||
context = {
|
context = {
|
||||||
'agent': agent,
|
'agent': agent, # Keep original agent data for template compatibility
|
||||||
'chat_session': chat_session,
|
'chat_session': chat_session,
|
||||||
'messages': messages,
|
'messages': messages,
|
||||||
'all_agents': all_agents,
|
'all_agents': all_agents,
|
||||||
@ -588,15 +667,28 @@ def start_chat_session(request):
|
|||||||
if not agent_slug:
|
if not agent_slug:
|
||||||
return Response({'error': 'agent_slug is required'}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': 'agent_slug is required'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
agent = get_object_or_404(Agent, slug=agent_slug, is_active=True, agent_type='chat')
|
agent_data = AgentFileService.get_agent_by_slug(agent_slug)
|
||||||
|
if not agent_data or not agent_data.get('is_active', True) or agent_data.get('agent_type') != 'chat':
|
||||||
|
return Response({'error': 'Chat agent not found'}, status=status.HTTP_404_NOT_FOUND)
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check wallet balance
|
# Check wallet balance
|
||||||
if hasattr(request.user, 'wallet_balance') and request.user.wallet_balance < agent.price:
|
if hasattr(request.user, 'wallet_balance') and request.user.wallet_balance < agent.price:
|
||||||
return Response({'error': 'Insufficient wallet balance'}, status=status.HTTP_400_BAD_REQUEST)
|
return Response({'error': 'Insufficient wallet balance'}, status=status.HTTP_400_BAD_REQUEST)
|
||||||
|
|
||||||
# Check for existing active session
|
# Check for existing active session (using slug-based lookup)
|
||||||
existing_session = ChatSession.objects.filter(
|
existing_session = ChatSession.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent.slug,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='active'
|
status='active'
|
||||||
).first()
|
).first()
|
||||||
@ -613,9 +705,12 @@ def start_chat_session(request):
|
|||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
chat_session = ChatSession.objects.create(
|
chat_session = ChatSession.objects.create(
|
||||||
session_id=session_id,
|
session_id=session_id,
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
status='active',
|
status='active',
|
||||||
@ -1099,7 +1194,23 @@ def direct_access_handler(request, slug):
|
|||||||
Generic handler for direct access agents (external forms like JotForm).
|
Generic handler for direct access agents (external forms like JotForm).
|
||||||
Handles payment processing and grants access to external form.
|
Handles payment processing and grants access to external form.
|
||||||
"""
|
"""
|
||||||
agent = get_object_or_404(Agent, slug=slug, is_active=True)
|
agent_data = AgentFileService.get_agent_by_slug(slug)
|
||||||
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
|
from django.http import Http404
|
||||||
|
raise Http404("Agent not found")
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.access_url_name = data.get('access_url_name', '')
|
||||||
|
self.display_url_name = data.get('display_url_name', '')
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Verify this is a direct access agent
|
# Verify this is a direct access agent
|
||||||
if not agent.access_url_name or not agent.display_url_name:
|
if not agent.access_url_name or not agent.display_url_name:
|
||||||
@ -1137,7 +1248,23 @@ def direct_access_display(request, slug):
|
|||||||
Generic display handler for direct access agents.
|
Generic display handler for direct access agents.
|
||||||
Shows external form (JotForm, Google Forms, etc.) in iframe or redirects directly.
|
Shows external form (JotForm, Google Forms, etc.) in iframe or redirects directly.
|
||||||
"""
|
"""
|
||||||
agent = get_object_or_404(Agent, slug=slug, is_active=True)
|
agent_data = AgentFileService.get_agent_by_slug(slug)
|
||||||
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
|
from django.http import Http404
|
||||||
|
raise Http404("Agent not found")
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.access_url_name = data.get('access_url_name', '')
|
||||||
|
self.display_url_name = data.get('display_url_name', '')
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Verify this is a direct access agent
|
# Verify this is a direct access agent
|
||||||
if not agent.access_url_name or not agent.display_url_name:
|
if not agent.access_url_name or not agent.display_url_name:
|
||||||
@ -1161,18 +1288,28 @@ def lean_six_sigma_expert_view(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the Lean Six Sigma Expert agent
|
# Get the Lean Six Sigma Expert agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('lean-six-sigma-expert')
|
||||||
agent = Agent.objects.get(slug='lean-six-sigma-expert', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'Lean Six Sigma Expert is currently unavailable.')
|
messages.error(request, 'Lean Six Sigma Expert is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
recent_execution = AgentExecution.objects.filter(
|
recent_execution = AgentExecution.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent.slug, # Changed to slug-based lookup
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='completed',
|
status='completed',
|
||||||
created_at__gte=timezone.now() - timedelta(hours=2)
|
created_at__gte=timezone.now() - timedelta(hours=2)
|
||||||
@ -1204,12 +1341,22 @@ def lean_six_sigma_expert_access(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the Lean Six Sigma Expert agent
|
# Get the Lean Six Sigma Expert agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('lean-six-sigma-expert')
|
||||||
agent = Agent.objects.get(slug='lean-six-sigma-expert', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'Lean Six Sigma Expert is currently unavailable.')
|
messages.error(request, 'Lean Six Sigma Expert is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has sufficient balance
|
# Check if user has sufficient balance
|
||||||
if not request.user.has_sufficient_balance(agent.price):
|
if not request.user.has_sufficient_balance(agent.price):
|
||||||
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the Lean Six Sigma Expert.')
|
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the Lean Six Sigma Expert.')
|
||||||
@ -1226,9 +1373,12 @@ def lean_six_sigma_expert_access(request):
|
|||||||
messages.error(request, 'Failed to process payment. Please try again.')
|
messages.error(request, 'Failed to process payment. Please try again.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
# Create execution record for tracking
|
# Create execution record for tracking
|
||||||
execution = AgentExecution.objects.create(
|
execution = AgentExecution.objects.create(
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
@ -1257,18 +1407,28 @@ def swot_analysis_expert_view(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the SWOT Analysis Expert agent
|
# Get the SWOT Analysis Expert agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('swot-analysis-expert')
|
||||||
agent = Agent.objects.get(slug='swot-analysis-expert', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'SWOT Analysis Expert is currently unavailable.')
|
messages.error(request, 'SWOT Analysis Expert is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
# Check if user has a recent execution (within last 2 hours) or just redirect to payment
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from datetime import timedelta
|
from datetime import timedelta
|
||||||
|
|
||||||
recent_execution = AgentExecution.objects.filter(
|
recent_execution = AgentExecution.objects.filter(
|
||||||
agent=agent,
|
agent__slug=agent.slug, # Changed to slug-based lookup
|
||||||
user=request.user,
|
user=request.user,
|
||||||
status='completed',
|
status='completed',
|
||||||
created_at__gte=timezone.now() - timedelta(hours=2)
|
created_at__gte=timezone.now() - timedelta(hours=2)
|
||||||
@ -1300,12 +1460,22 @@ def swot_analysis_expert_access(request):
|
|||||||
return redirect('authentication:login')
|
return redirect('authentication:login')
|
||||||
|
|
||||||
# Get the SWOT Analysis Expert agent
|
# Get the SWOT Analysis Expert agent
|
||||||
try:
|
agent_data = AgentFileService.get_agent_by_slug('swot-analysis-expert')
|
||||||
agent = Agent.objects.get(slug='swot-analysis-expert', is_active=True)
|
if not agent_data or not agent_data.get('is_active', True):
|
||||||
except Agent.DoesNotExist:
|
|
||||||
messages.error(request, 'SWOT Analysis Expert is currently unavailable.')
|
messages.error(request, 'SWOT Analysis Expert is currently unavailable.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Convert to compatible object
|
||||||
|
class AgentCompat:
|
||||||
|
def __init__(self, data):
|
||||||
|
self.slug = data['slug']
|
||||||
|
self.name = data['name']
|
||||||
|
self.price = float(data['price'])
|
||||||
|
self.webhook_url = data['webhook_url']
|
||||||
|
self.id = data['slug']
|
||||||
|
|
||||||
|
agent = AgentCompat(agent_data)
|
||||||
|
|
||||||
# Check if user has sufficient balance
|
# Check if user has sufficient balance
|
||||||
if not request.user.has_sufficient_balance(agent.price):
|
if not request.user.has_sufficient_balance(agent.price):
|
||||||
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the SWOT Analysis Expert.')
|
messages.error(request, f'Insufficient balance! You need {agent.price} AED to access the SWOT Analysis Expert.')
|
||||||
@ -1322,9 +1492,12 @@ def swot_analysis_expert_access(request):
|
|||||||
messages.error(request, 'Failed to process payment. Please try again.')
|
messages.error(request, 'Failed to process payment. Please try again.')
|
||||||
return redirect('agents:marketplace')
|
return redirect('agents:marketplace')
|
||||||
|
|
||||||
|
# Get or create database record for foreign key compatibility
|
||||||
|
agent_db_record = AgentFileService.get_or_create_agent_db_record(agent_data)
|
||||||
|
|
||||||
# Create execution record for tracking
|
# Create execution record for tracking
|
||||||
execution = AgentExecution.objects.create(
|
execution = AgentExecution.objects.create(
|
||||||
agent=agent,
|
agent=agent_db_record,
|
||||||
user=request.user,
|
user=request.user,
|
||||||
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
input_data={'action': 'direct_access', 'source': 'try_now_button'},
|
||||||
fee_charged=agent.price,
|
fee_charged=agent.price,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user