mirror of
https://github.com/thecyberlearn/quantum-ai-v3.git
synced 2026-08-18 13:52:57 +00:00
🚀 Major improvements to agent system: ## Wallet Management ✅ - Move wallet deduction to AFTER successful processing (not before) - Add real-time wallet balance updates in frontend - Prevent users from losing money on failed requests - Update both data_analyzer and weather_reporter processors ## Data Analyzer Agent 📊 - Fix N8N integration to handle array response format - Add binary PDF file upload (multipart/form-data) - Implement real-time AJAX results display below form - Add wallet balance updates after successful processing - Support continuous workflow with "Analyze Another File" ## Weather Reporter Agent 🌤️ - Update price from 2.5 AED to 2.0 AED - Fix results display (was using page reload, now AJAX) - Add real-time wallet balance updates - Implement dynamic results rendering below form - Add "Get Another Report" functionality ## Template System 🎨 - Update agent generator templates with correct wallet flow - Add data-wallet-balance attributes for easy targeting - Fix JavaScript querySelector errors - Implement proper error handling and logging ## Documentation 📚 - Update CLAUDE.md with wallet best practices - Add examples of current production agents - Document required JavaScript functions - Update pricing information and modern agent features - Add gitignore entries for nextjs/ and netcop-ai-hub/ ## Frontend JavaScript 💻 - Add updateWalletBalance() function for real-time updates - Implement displayResults() for dynamic content rendering - Add proper error handling with user-friendly messages - Support continuous workflow without page refresh 🎉 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
149 lines
6.1 KiB
Python
149 lines
6.1 KiB
Python
from agent_base.processors import StandardWebhookProcessor
|
|
from django.utils import timezone
|
|
from django.conf import settings
|
|
from .models import DataAnalysisAgentRequest, DataAnalysisAgentResponse
|
|
import json
|
|
import requests
|
|
import time
|
|
|
|
|
|
class DataAnalysisAgentProcessor(StandardWebhookProcessor):
|
|
"""Webhook processor for Data Analysis Agent agent"""
|
|
|
|
agent_slug = 'data-analyzer'
|
|
webhook_url = settings.N8N_WEBHOOK_DATA_ANALYZER
|
|
agent_id = 'data-analysis-001'
|
|
|
|
def make_request(self, data, timeout=60):
|
|
"""Override to send PDF file as binary data instead of JSON"""
|
|
try:
|
|
request_obj = data.get('request_obj')
|
|
if not request_obj or not request_obj.data_file:
|
|
raise ValueError("No PDF file found in request")
|
|
|
|
print(f"{self.agent_slug}: Sending PDF file to N8N webhook: {self.webhook_url}")
|
|
|
|
# Read the PDF file
|
|
pdf_file = request_obj.data_file
|
|
pdf_file.seek(0) # Reset file pointer to beginning
|
|
file_content = pdf_file.read()
|
|
|
|
print(f"{self.agent_slug}: File size: {len(file_content)} bytes")
|
|
print(f"{self.agent_slug}: File name: {pdf_file.name}")
|
|
|
|
# Prepare multipart form data
|
|
files = {
|
|
'file': (pdf_file.name, file_content, 'application/pdf')
|
|
}
|
|
|
|
start_time = time.time()
|
|
response = requests.post(self.webhook_url, files=files, timeout=timeout)
|
|
processing_time = time.time() - start_time
|
|
|
|
print(f"{self.agent_slug}: Response status: {response.status_code}")
|
|
print(f"{self.agent_slug}: Response text: {response.text[:500]}...")
|
|
|
|
response.raise_for_status()
|
|
|
|
# Check if response has content
|
|
if not response.text.strip():
|
|
raise ValueError("Empty response from webhook")
|
|
|
|
# Parse JSON response
|
|
try:
|
|
response_data = response.json()
|
|
except ValueError:
|
|
raise ValueError("Invalid JSON response from N8N workflow")
|
|
|
|
# Handle array response from N8N (extract first item)
|
|
if isinstance(response_data, list) and len(response_data) > 0:
|
|
response_data = response_data[0]
|
|
elif isinstance(response_data, list) and len(response_data) == 0:
|
|
raise ValueError("Empty array response from N8N workflow")
|
|
|
|
# Add processing metadata
|
|
response_data['processing_time'] = processing_time
|
|
|
|
return response_data
|
|
|
|
except requests.exceptions.RequestException as e:
|
|
print(f"{self.agent_slug}: Webhook request error: {e}")
|
|
raise ValueError(f"Webhook error: {e}")
|
|
except Exception as e:
|
|
print(f"{self.agent_slug}: Processing error: {e}")
|
|
raise ValueError(f"Processing error: {e}")
|
|
|
|
def prepare_request_data(self, **kwargs):
|
|
"""Prepare request data - for binary upload, we pass the request object"""
|
|
return {
|
|
'request_obj': kwargs.get('request_obj'),
|
|
'analysis_type': kwargs.get('analysis_type', 'summary')
|
|
}
|
|
|
|
def process_response(self, response_data, request_obj):
|
|
"""Process webhook response from N8N"""
|
|
try:
|
|
request_obj.status = 'processing'
|
|
request_obj.save()
|
|
|
|
# Extract N8N response data based on workflow format
|
|
analysis_text = response_data.get('analysis', '')
|
|
status = response_data.get('status', 'unknown')
|
|
processed_at = response_data.get('processed_at', '')
|
|
|
|
# Map N8N response to Django fields
|
|
analysis_results = {
|
|
'status': status,
|
|
'processed_at': processed_at,
|
|
'analysis_type': getattr(request_obj, 'analysis_type', 'summary')
|
|
}
|
|
|
|
# Use analysis text for multiple fields for compatibility
|
|
insights_summary = analysis_text[:500] + '...' if len(analysis_text) > 500 else analysis_text
|
|
report_text = analysis_text
|
|
raw_response = response_data
|
|
|
|
# Determine success based on N8N status
|
|
success = status == 'success' and bool(analysis_text)
|
|
|
|
# Create response object
|
|
response_obj = DataAnalysisAgentResponse.objects.create(
|
|
request=request_obj,
|
|
success=success,
|
|
processing_time=response_data.get('processing_time', 0),
|
|
analysis_results=analysis_results,
|
|
insights_summary=insights_summary,
|
|
report_text=report_text,
|
|
raw_response=raw_response,
|
|
)
|
|
|
|
# Only deduct wallet balance after successful processing
|
|
if success:
|
|
request_obj.user.deduct_balance(
|
|
request_obj.cost,
|
|
f"Data Analysis Agent - {request_obj.data_file.name if request_obj.data_file else 'PDF Analysis'}",
|
|
'data-analyzer'
|
|
)
|
|
print(f"{self.agent_slug}: Wallet deducted {request_obj.cost} AED for successful processing")
|
|
|
|
# Update request as completed
|
|
request_obj.status = 'completed' if success else 'failed'
|
|
request_obj.processed_at = timezone.now()
|
|
request_obj.save()
|
|
|
|
return response_obj
|
|
|
|
except Exception as e:
|
|
# Handle error
|
|
request_obj.status = 'failed'
|
|
request_obj.save()
|
|
|
|
# Create error response
|
|
error_response = DataAnalysisAgentResponse.objects.create(
|
|
request=request_obj,
|
|
success=False,
|
|
error_message=str(e),
|
|
processing_time=response_data.get('processing_time', 0) if response_data else 0
|
|
)
|
|
|
|
raise Exception(f"Failed to process Data Analysis Agent response: {e}") |