187 lines
7.1 KiB
Python
187 lines
7.1 KiB
Python
from django.shortcuts import render, get_object_or_404, redirect
|
|
from .models import Incident, Brand
|
|
from .forms import IncidentForm
|
|
from ai.local_ai_api import LocalAIApi
|
|
import json
|
|
import requests
|
|
from bs4 import BeautifulSoup
|
|
from django.contrib.auth.decorators import login_required, user_passes_test
|
|
from django.views.generic import ListView, CreateView, UpdateView, DeleteView
|
|
from django.utils.decorators import method_decorator
|
|
from django.urls import reverse_lazy, reverse
|
|
|
|
@login_required
|
|
def home(request):
|
|
# Get the brands associated with the current user
|
|
user_brands = request.user.brands.all()
|
|
# Filter incidents to only those associated with the user's brands
|
|
incidents = Incident.objects.filter(brand__in=user_brands)
|
|
|
|
# Calculate stats
|
|
total_incidents = incidents.count()
|
|
new_incidents = incidents.filter(status='new').count()
|
|
in_review_incidents = incidents.filter(status='in_review').count()
|
|
resolved_incidents = incidents.filter(status='resolved').count()
|
|
dismissed_incidents = incidents.filter(status='dismissed').count()
|
|
|
|
context = {
|
|
'incidents': incidents,
|
|
'total_incidents': total_incidents,
|
|
'new_incidents': new_incidents,
|
|
'in_review_incidents': in_review_incidents,
|
|
'resolved_incidents': resolved_incidents,
|
|
'dismissed_incidents': dismissed_incidents,
|
|
}
|
|
|
|
return render(request, "core/index.html", context)
|
|
|
|
@login_required
|
|
def article_detail(request, id):
|
|
# Fetch the specific incident from the database
|
|
incident = get_object_or_404(Incident, pk=id)
|
|
|
|
prompt = f"""Analyze the following incident and provide a summary, a sentiment analysis (Positive, Negative, or Neutral), and a list of suggested remediation steps.
|
|
Incident: {incident.content}
|
|
|
|
Return the analysis in JSON format with three keys: 'summary', 'sentiment', and 'suggested_steps' (which should be a list of strings).
|
|
"""
|
|
|
|
ai_response = LocalAIApi.create_response(
|
|
{
|
|
"input": [
|
|
{"role": "system", "content": "You are a brand protection assistant."},
|
|
{"role": "user", "content": prompt},
|
|
],
|
|
}
|
|
)
|
|
|
|
ai_analysis = {"summary": "AI analysis is currently unavailable.", "sentiment": "Unknown", "suggested_steps": []}
|
|
if ai_response.get("success"):
|
|
text = LocalAIApi.extract_text(ai_response)
|
|
try:
|
|
# Ensure the extracted text is valid JSON
|
|
ai_analysis = json.loads(text)
|
|
# Ensure all keys are present
|
|
if 'summary' not in ai_analysis: ai_analysis['summary'] = "No summary provided."
|
|
if 'sentiment' not in ai_analysis: ai_analysis['sentiment'] = "Unknown"
|
|
if 'suggested_steps' not in ai_analysis: ai_analysis['suggested_steps'] = []
|
|
except (json.JSONDecodeError, TypeError):
|
|
# If the AI response is not valid JSON, use it as the summary
|
|
ai_analysis["summary"] = text if text else "Could not retrieve AI analysis."
|
|
|
|
return render(request, "core/article_detail.html", {"incident": incident, "ai_analysis": ai_analysis})
|
|
|
|
# A check to see if the user is a staff member
|
|
def is_staff(user):
|
|
return user.is_staff
|
|
|
|
@method_decorator(login_required, name='dispatch')
|
|
class BrandListView(ListView):
|
|
model = Brand
|
|
template_name = 'core/brand_list.html'
|
|
context_object_name = 'brands'
|
|
|
|
def get_queryset(self):
|
|
return self.request.user.brands.all()
|
|
|
|
@method_decorator(login_required, name='dispatch')
|
|
class BrandCreateView(CreateView):
|
|
model = Brand
|
|
template_name = 'core/brand_form.html'
|
|
fields = ['name', 'website', 'logo_url']
|
|
success_url = reverse_lazy('brand-list')
|
|
|
|
def form_valid(self, form):
|
|
self.object = form.save()
|
|
self.object.users.add(self.request.user)
|
|
return super().form_valid(form)
|
|
|
|
|
|
@method_decorator(login_required, name='dispatch')
|
|
class BrandUpdateView(UpdateView):
|
|
model = Brand
|
|
template_name = 'core/brand_form.html'
|
|
fields = ['name', 'website', 'logo_url']
|
|
success_url = reverse_lazy('brand-list')
|
|
|
|
def get_queryset(self):
|
|
return self.request.user.brands.all()
|
|
|
|
|
|
@method_decorator(login_required, name='dispatch')
|
|
class BrandDeleteView(DeleteView):
|
|
model = Brand
|
|
template_name = 'core/brand_confirm_delete.html'
|
|
success_url = reverse_lazy('brand-list')
|
|
|
|
def get_queryset(self):
|
|
return self.request.user.brands.all()
|
|
|
|
@login_required
|
|
def dismiss_incident(request, incident_id):
|
|
incident = get_object_or_404(Incident, pk=incident_id)
|
|
# Check if the user has permission to dismiss this incident
|
|
if incident.brand in request.user.brands.all():
|
|
incident.status = 'dismissed'
|
|
incident.save()
|
|
return redirect('home')
|
|
|
|
@method_decorator(login_required, name='dispatch')
|
|
class IncidentCreateView(CreateView):
|
|
model = Incident
|
|
form_class = IncidentForm
|
|
template_name = 'core/incident_form.html'
|
|
success_url = reverse_lazy('home')
|
|
|
|
def get_form_kwargs(self):
|
|
kwargs = super(IncidentCreateView, self).get_form_kwargs()
|
|
kwargs['user'] = self.request.user
|
|
return kwargs
|
|
|
|
@login_required
|
|
def autofill_incident_from_url(request):
|
|
if request.method == 'POST':
|
|
url = request.POST.get('url')
|
|
try:
|
|
response = requests.get(url, timeout=10)
|
|
response.raise_for_status() # Raise an exception for bad status codes
|
|
soup = BeautifulSoup(response.content, 'html.parser')
|
|
page_text = soup.get_text()
|
|
|
|
prompt = f"""Analyze the following text from a webpage and extract information to create a brand protection incident report. Identify the type of incident, and a summary of the content.
|
|
|
|
Webpage content: {page_text[:4000]}
|
|
|
|
Return the analysis in JSON format with two keys: 'incident_type' (choose from {Incident.INCIDENT_TYPE_CHOICES}) and 'content'.
|
|
"""
|
|
|
|
ai_response = LocalAIApi.create_response(
|
|
{
|
|
"input": [
|
|
{"role": "system", "content": "You are a brand protection assistant that extracts information from webpages."},
|
|
{"role": "user", "content": prompt},
|
|
],
|
|
}
|
|
)
|
|
|
|
if ai_response.get("success"):
|
|
text = LocalAIApi.extract_text(ai_response)
|
|
try:
|
|
ai_data = json.loads(text)
|
|
initial_data = {
|
|
'source_url': url,
|
|
'incident_type': ai_data.get('incident_type'),
|
|
'content': ai_data.get('content'),
|
|
}
|
|
form = IncidentForm(initial=initial_data, user=request.user)
|
|
return render(request, 'core/incident_form.html', {'form': form})
|
|
except (json.JSONDecodeError, TypeError):
|
|
# Handle cases where AI response is not as expected
|
|
pass # You might want to add a message to the user
|
|
|
|
except requests.RequestException as e:
|
|
# Handle network errors
|
|
pass # You might want to add a message to the user
|
|
|
|
return render(request, 'core/autofill_incident_form.html')
|