quantum-ai-v3/data_analyzer/processor.py
Claude 375b2b9d65 Implement wallet deduction after success & fix display issues
🚀 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>
2025-07-10 16:34:03 +05:30

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}")