diff --git a/myproject/myapp/models.py b/myproject/myapp/models.py
index 900085ca0dbfecf5621a2d1b8796c8bb8842cac2..326123a737d7ef7aca00446c56a78ff39684017b 100644
--- a/myproject/myapp/models.py
+++ b/myproject/myapp/models.py
@@ -1,7 +1,8 @@
+# models.py
 from django.db import models
-#from django.contrib.auth import get_user_model
-from django.contrib.auth.models import User#, Group, Permission
-#from django.contrib.contenttypes.models import ContentType
+from django.contrib.auth import get_user_model
+from django.contrib.auth.models import User, Group, Permission
+from django.contrib.contenttypes.models import ContentType
 from enum import Enum
 from django.dispatch import receiver
 from django.db.models.signals import post_save
@@ -20,6 +21,7 @@ class Profile(models.Model):
     def __str__(self):
         return f'{self.user.username} Profile'
 
+
 # Model to hold the user token count
 class UserTokenCount(models.Model):
     # User
@@ -29,28 +31,22 @@ class UserTokenCount(models.Model):
 
     def __str__(self):
         return f'{self.user.username}\'s token count: {self.token_count}'
-    
-# Automatically create a UserTokenCount and a account type Profile table entry for each user on user creation
-@receiver(post_save, sender=User)
-def create_or_update_user_profile(sender, instance, created, **kwargs):
-    if created:
-        UserTokenCount.objects.get_or_create(user=instance)
-        Profile.objects.get_or_create(user=instance)
-    # instance.profile.save()
+
 
 class Action(Enum):
-    UPLOAD_FILE = "The user has successfully uploaded a file."
-    LOGIN = "The user has logged in to their account."
-    REGISTER = "The user has registered for a new account."
-    PAYMENT_SUCCESSFUL = "The user has successfully made a payment."
-    GENERATE_FINANCIAL_STATEMENT = "The user has generated a financial statement."
-    CHANGE_MLA = "The user has changed their maximum loss amount (MLA)."
-    RUN_ALGORITHM = "The user has run an algorithm."
-    INVALID_FILE = "The uploaded file is invalid and cannot be processed."
-    INVALID_PASSWORD = "The user has entered an invalid password."
-    USER_DOES_NOT_EXIST = "The user does not exist in the system."
-    DOWNLOAD_BREAKDOWN = "The user has downloaded a breakdown of their data."
-    UNKNOWN = "An unknown error has occurred."
+    UPLOAD_FILE = "{username} has successfully uploaded a file."
+    LOGIN = "{username} has logged in to their account."
+    REGISTER = "{username} has registered for a new account."
+    PAYMENT_SUCCESSFUL = "{username} has successfully made a payment."
+    GENERATE_FINANCIAL_STATEMENT = "{username} has generated a financial statement."
+    CHANGE_MLA = "{username} has changed their maximum loss amount (MLA)."
+    RUN_ALGORITHM = "{username} has run an algorithm."
+    FEEDBACK_SUBMITTED = "{username} has submitted feedback."
+    INVALID_FILE = "{username} uploaded an invalid file that cannot be processed."
+    INVALID_PASSWORD = "{username} has entered an invalid password."
+    USER_DOES_NOT_EXIST = "The user {username} does not exist in the system."
+    DOWNLOAD_BREAKDOWN = "{username} has downloaded a breakdown of their data."
+    UNKNOWN = "An unknown error has occurred for user {username}."
 
 class Audio(models.Model):
     file = models.FileField('audio', upload_to='audio')
@@ -59,3 +55,5 @@ class Log(models.Model):
     date = models.DateTimeField(auto_now_add=True)
     user = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
     log = models.JSONField()
+    feedback = models.BooleanField(null=True)
+
diff --git a/myproject/myapp/payments.py b/myproject/myapp/payments.py
index 1fed0f117c95e23275876c5a118c4893e3bb7957..c99f04c4c4c3d6879c72cb2ffaca3993e743e753 100644
--- a/myproject/myapp/payments.py
+++ b/myproject/myapp/payments.py
@@ -6,9 +6,11 @@ from django.urls import reverse
 from django.shortcuts import redirect, render
 from django.urls import reverse
 from .models import UserTokenCount
+from rest_framework.response import Response
+from rest_framework import status
 
 # Create a payment that can be made via the PayPal API
-def create_payment(request):
+def create_payment(request, purchase_type):
     # Configure PayPal SDK
     paypalrestsdk.configure({
         "mode": settings.PAYPAL_MODE,
@@ -16,6 +18,26 @@ def create_payment(request):
         "client_secret": settings.PAYPAL_CLIENT_SECRET  
     })
 
+    # We need to check what kind of payment it is first, how many tokens are being bought?
+    if purchase_type == "single":
+        name = "Single purchase"
+        sku = "sku01"
+        quantity = 1
+        price = "9.99"
+        description = "Single purchase of 1 token"
+
+    elif purchase_type == "bulk":
+        name = "Bulk purchase"
+        sku = "sku02"
+        quantity = 10
+        price = "44.99"
+        description = "Bulk purchase of 10 tokens"
+    else:
+        return JsonResponse({"error": "Invalid purchase type"})
+
+    # Pass the quantity to the session to later change the payment execution type
+    request.session['purchase_quantity'] = quantity 
+    
     # Create payment object
     payment = paypalrestsdk.Payment({
         "intent": "sale",
@@ -29,18 +51,18 @@ def create_payment(request):
         "transactions" : [{
             "item_list" : {
                 "items" : [{
-                    "name": "Test item",
-                    "sku": "test item",
-                    "price": "9.99",
+                    "name": name,
+                    "sku": sku,
+                    "price": price,
                     "currency": "GBP",
                     "quantity": 1,
                 }]
             },
             "amount" : {
-                "total": "9.99",
+                "total": price,
                 "currency": "GBP"
             },
-            "description": "Test payment description"
+            "description": description
         }]
     })
 
@@ -66,9 +88,8 @@ def execute_payment(request):
 
     #If neither ID, error, restart
     if not payment_id or not payer_id:
-        print("no payment")
-        #TODO: Change this to a more appropriate path, maybe a generic error page that takes a string:Error to display in a template
-        return redirect('handler404')
+        print("no payment id or payer_id")
+        return Response({"error": "Error: No payment id or payer id was found."}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
     
     # configure API
     paypalrestsdk.configure({
@@ -83,28 +104,22 @@ def execute_payment(request):
     # If it we do an the payer IDs match
     if payment.execute({"payer_id": payer_id}):
         print("Payment executed successfully!")
+        print(f"Payment: {payment}")
 
         # Allocate some tokens
-        user = request.user
-        tokens_purchased = 1
-        
-        # increment user_tokens
-        # commit changes
-        # TODO: Change something here such that the token amount added depends on a detail of the transaction,
-        #       i.e. £9.99 payment for one token or £24.99 for 
-        # 
-        add_tokens(user, tokens_purchased)
+        tokens_purchased = request.session.get("purchase_quantity")
+
+        add_tokens(request.user, tokens_purchased)
 
         return redirect('success')
     else:
-        #TODO: Change this to a more appropriate error message
-        print("exiting at the end of execute_payment()")
-        return redirect('handler404')
+        print("exiting at the end of execute_payment(), incorrect payer id")
+        return Response({"error": "Error: Payment failed to execute, incorrect payer id"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
 
 
 def add_tokens(user, tokens):
     token_count_instance, created = UserTokenCount.objects.get_or_create(user=user)
-    token_count_instance.token_count += tokens
+    token_count_instance.token_count += int(tokens)
     token_count_instance.save()
 
 def payment_cancelled(request):
diff --git a/myproject/myapp/templates/payment_success.html b/myproject/myapp/templates/payment_success.html
index 8496abe27218036de5f59812760e16c1b43ba7c9..51a411039e2529af3f8d003f8490d8531ffcc352 100644
--- a/myproject/myapp/templates/payment_success.html
+++ b/myproject/myapp/templates/payment_success.html
@@ -1,10 +1,14 @@
 {% extends "_base.html" %}{% block content %}
-<div class="grid grid-cols-1 gap-16 items-center py-8 px-4 mx-auto w-70 lg:grid">
-    <div class="font-light text-gray-500 sm:text-lg dark:text-gray-400">
-        <h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900 dark:text-white">Success!</h2>
-        <p class="mb-4">Your payment was successful and you have been credited with 1 token.</p>
+<div class="flex mt-6">
+    <div class="grid grid-cols-1 gap-12 items-center py-8 px-4 mx-auto w-70 lg:grid">
+        <div class="font-light text-gray-500 sm:text-lg dark:text-gray-400 text-center">
+            <h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900 dark:text-white">Transaction completed</h2>
+            <p class=" mt-6">Your payment was successful.</p>
+        </div>
+        <button class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center text-center"><a href="{% url 'users' %}">Return</a></button>
     </div>
 </div>
 
-<button class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center text-center"><a href="{% url 'users' %}">Return</a></button>
+
+
 {% endblock content%}
diff --git a/myproject/myapp/templates/pricing.html b/myproject/myapp/templates/pricing.html
index 78b60c2de6bfdf0b8bc7348ba8439a66e76fbcc0..7f72582cc008f5f724d4beb40dab2c2ae18c1b11 100644
--- a/myproject/myapp/templates/pricing.html
+++ b/myproject/myapp/templates/pricing.html
@@ -1,7 +1,7 @@
 {% extends "_base.html" %}{% block content %}
 
 <div class="grid grid-cols-1 gap-16 items-center py-8 px-4 mx-auto w-70 lg:grid">
-    <div class="font-light text-gray-500 sm:text-lg dark:text-gray-400">
+    <div class="font-light text-gray-500 sm:text-lg dark:text-gray-400 my-10">
         <h2 class="mb-4 text-4xl tracking-tight font-extrabold text-gray-900 dark:text-white">An Intelligent System for Instrument Detection</h2>
         <p class="mb-4">*placeholder input* We present to you a intelligent system for instrument detection. Using audio processing techinques and a convolutionsal
           neural network we are able to classify instruments used in a song. other exciting words that might catch peoples attention and make them use our product.
@@ -38,62 +38,35 @@
                 <span class="text-base font-normal leading-tight text-gray-500 ms-3">Email support</span>
             </li>
         </ul>
-        <button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center w-full text-center"><a href="{% url 'create_payment' %}">Purchase via PayPal</a></button>
+        <button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center w-full text-center"><a href="{% url 'create_payment' 'single' %}">Purchase via PayPal</a></button>
     </div>
     
     <div class="w-full mx-auto max-w-sm p-4 bg-white border border-gray-200 rounded-lg shadow sm:p-8 dark:bg-gray-800 dark:border-gray-700">
         <h5 class="mb-4 text-xl font-medium text-gray-500 dark:text-gray-400">Bulk Purchase</h5>
         <div class="flex items-baseline text-gray-900 dark:text-white">
-            <span class="text-3xl font-semibold">£</span>
-            <span class="text-5xl font-extrabold tracking-tight">49</span>
-            <span class="ms-1 text-xl font-normal text-gray-500 dark:text-gray-400">/month</span>
+            <span class="text-5xl font-extrabold tracking-tight">£44.99</span>
         </div>
         <ul role="list" class="space-y-5 my-7">
             <li class="flex items-center">
                 <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-blue-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
                     <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
                 </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 dark:text-gray-400 ms-3">2 team members</span>
+                <span class="text-base font-normal leading-tight text-gray-500 dark:text-gray-400 ms-3">10 tokens</span>
             </li>
-            <li class="flex">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-blue-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
-                    <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
-                </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 dark:text-gray-400 ms-3">20GB Cloud storage</span>
-            </li>
-            <li class="flex  decoration-gray-500">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
-                    <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
-                </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 ms-3">100 File Uploads</span>
-                <span class="ms-1 text-sm font-normal text-gray-500 dark:text-gray-400">/month</span>
-            </li>
-            <li class="flex">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-blue-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
-                    <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
-                </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 dark:text-gray-400 ms-3">Integration help</span>
-            </li>
-            <li class="flex  decoration-gray-500">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
+            <li class="flex decoration-gray-500">
+                <svg class="flex-shrink-0 w-4 h-4 text-gray-400 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
                     <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
                 </svg>
                 <span class="text-base font-normal leading-tight text-gray-500 ms-3">API Access</span>
             </li>
-            <li class="flex  decoration-gray-500">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
-                    <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
-                </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 ms-3">Complete documentation</span>
-            </li>
-            <li class="flex  decoration-gray-500">
-                <svg class="flex-shrink-0 w-4 h-4 text-blue-700 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
+            <li class="flex decoration-gray-500">
+                <svg class="flex-shrink-0 w-4 h-4 text-gray-400 dark:text-gray-500" aria-hidden="true" xmlns="http://www.w3.org/2000/svg" fill="currentColor" viewBox="0 0 20 20">
                     <path d="M10 .5a9.5 9.5 0 1 0 9.5 9.5A9.51 9.51 0 0 0 10 .5Zm3.707 8.207-4 4a1 1 0 0 1-1.414 0l-2-2a1 1 0 0 1 1.414-1.414L9 10.586l3.293-3.293a1 1 0 0 1 1.414 1.414Z"/>
                 </svg>
-                <span class="text-base font-normal leading-tight text-gray-500 ms-3">24×7 phone & email support</span>
+                <span class="text-base font-normal leading-tight text-gray-500 ms-3">Email support</span>
             </li>
         </ul>
-        <button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center w-full text-center">Choose plan</button>
+        <button type="button" class="text-white bg-blue-700 hover:bg-blue-800 focus:ring-4 focus:outline-none focus:ring-blue-200 dark:bg-blue-600 dark:hover:bg-blue-700 dark:focus:ring-blue-900 font-medium rounded-lg text-sm px-5 py-2.5 inline-flex justify-center w-full text-center"><a href="{% url 'create_payment' 'bulk' %}">Purchase via PayPal</a></button>
     </div>
         
 </div>
diff --git a/myproject/myapp/urls.py b/myproject/myapp/urls.py
index f7c169ca586946c0e567e5743886c6cf0d40c6c3..b07b3678265f4c764f99a0a02be4846ec0768622 100644
--- a/myproject/myapp/urls.py
+++ b/myproject/myapp/urls.py
@@ -38,7 +38,7 @@ urlpatterns = [
     path('register/', RegisterView.as_view(), name='register'),
     path('user_logout/', auth_views.LogoutView.as_view(next_page='index'), name='user_logout'),
     # Payment
-    path('payment/create/', create_payment, name='create_payment'),
+    path('payment/create/<str:purchase_type>', create_payment, name='create_payment'),
     path('payment/execute/', execute_payment, name='execute_payment'),
     path('payment/cancel/', payment_cancelled, name='payment_cancelled'),
     path('payment_success/', payment_success, name='success')
diff --git a/myproject/myapp/views.py b/myproject/myapp/views.py
index a04cd1bbaca8bd0515bf55761b3ff87d3d048318..d7354e9b7cdb803af11d3b5672fcbadfdc6e1258 100644
--- a/myproject/myapp/views.py
+++ b/myproject/myapp/views.py
@@ -4,7 +4,7 @@ from django.contrib.auth.models import User
 from django.contrib import messages
 from django.http import HttpResponse
 from django.utils import timezone
-from django.shortcuts import render, redirect
+from django.shortcuts import render, redirect, get_object_or_404
 from django.template import RequestContext
 import logging
 from reportlab.pdfgen import canvas
@@ -12,7 +12,7 @@ import json
 from datetime import datetime
 
 from .forms import InstrumentDetectionForm
-from .models import Log, Action, User, UserTokenCount
+from .models import Log, Action, User, UserTokenCount, Profile
 from django.http import JsonResponse
 from django.db import connection
 
@@ -30,20 +30,27 @@ from django.views import generic
 from .models import Profile
 from .forms import UserRegisterForm, LoginAuthenticationForm
 from django.contrib.auth.views import LoginView
+from django.views.decorators.csrf import csrf_exempt
+
+from django.contrib.auth.mixins import UserPassesTestMixin
+from django.views.generic import TemplateView
+import re
 
 logger = logging.getLogger(__name__)
 
-def get_log_data(action, status='success', file=None, description=None):
+def get_log_data(user, action, status='success', file=None, description=None, feedback=None):
     log_data = {
-        'action': action.value,
+        'username': user.username,
+        'action': action.value.format(username=user.username),
         'status': status,
         'file': file,
         'description': description,
+        'feedback': feedback,  # Add the feedback field
     }
     return log_data
 
 def create_log(user, log_data):
-    Log.objects.create(user=user, log=log_data)
+    Log.objects.create(user=user, log=log_data, feedback=log_data.get('feedback'))
 
 def handling_music_file(request):
     if request.method == 'POST':
@@ -52,16 +59,54 @@ def handling_music_file(request):
                 'action': 'File uploaded',
                 'file': request.FILES['audio_file'].name,
             }
-            log_data = get_log_data(Action.UPLOAD_FILE, 'success', file=request.FILES['audio_file'].name)
+            log_data = get_log_data(request.user ,Action.UPLOAD_FILE, 'success', file=request.FILES['audio_file'].name)
             create_log(request.user if request.user.is_authenticated else None, log_data)
             return HttpResponse('File uploaded successfully!',log_data)
-    log_data = get_log_data(Action.invalid_file, 'error')
+    log_data = get_log_data(request.user ,Action.INVALID_FILE, 'error')
     create_log(None, log_data)
     return HttpResponse('File invalid',log_data)
 
+@csrf_exempt
+def log_fileupload(request):
+    if request.method == 'POST':
+        data = json.loads(request.body)
+        status = data.get('status')
+        file = data.get('file')
+
+        if request.user.is_authenticated:
+            log_data = get_log_data(request.user, Action.UPLOAD_FILE, status, file)
+            create_log(request.user, log_data)
+
+        return JsonResponse({'message': 'Log created successfully'}, status=201)
+
+    return JsonResponse({'error': 'Invalid request'}, status=400)
+
+def submit_feedback(request):
+    if request.method == 'POST' and request.user.is_authenticated:
+        prediction = request.POST.get('prediction')
+        liked = request.POST.get('feedback') == 'true'
+        file_name = request.POST.get('file_name')  # Get the filename from the form data
+        
+        # Create log data using the get_log_data function
+        log_data = get_log_data(
+            user=request.user,
+            action=Action.FEEDBACK_SUBMITTED,
+            status='success',
+            file=file_name,  # Use the filename obtained from the form
+            description=prediction,
+            feedback=liked
+        )
+        
+        # Create the Log entry using the create_log function
+        create_log(request.user, log_data)
+        
+        return redirect('index')
+    
+    return redirect('index')
+
 def admin_table(request):
     # Execute the query and fetch all rows
-    query = """SELECT date, user, log FROM myapp_log ORDER BY date DESC"""
+    query = """SELECT date, log, user_id, feedback FROM myapp_log ORDER BY date DESC"""
     with connection.cursor() as cursor:
         cursor.execute(query)
         rows = cursor.fetchall()
@@ -70,21 +115,24 @@ def admin_table(request):
     data = []
     for row in rows:
         # Parse the JSON string into a dictionary
-        log = json.loads(row[2])
-        # Create a dictionary with the date, user, and JSON fields
+        log = json.loads(row[1])
+        # Get the user object based on the user_id
+        user_id = row[2]
+        # Get the feedback value
+        feedback = row[3]
+        # Create a dictionary with the date, user, JSON fields, and feedback
         date = row[0].strftime('%Y-%m-%d %H:%M:%S')
-        entry = {'date': date, 'user': row[1], 'file': log['file'], 'action': log['action'], 'status': log['status']}
+        entry = {'date': date, 'user': user_id, 'file': log['file'], 'action': log['action'], 'status': log['status'],
+                 'description': log['description'], 'feedback': feedback}
         data.append(entry)
 
     # Return the data as a JSON response
     return JsonResponse({'data': data}, safe=False)
 
-
 def user_table(request):
-    # Execute the query and fetch all rows
-    query = """SELECT date, user, log FROM myapp_log ORDER BY date DESC"""
+    user_id = request.user.id
     # Only display user logs code below
-    # query = """SELECT date, user, log FROM myapp_log WHERE user = '{}' ORDER BY date DESC""".format(request.user)
+    query = """SELECT date, log, user_id, feedback FROM myapp_log WHERE user_id = {} ORDER BY date DESC""".format(user_id)
     with connection.cursor() as cursor:
         cursor.execute(query)
         rows = cursor.fetchall()
@@ -93,10 +141,15 @@ def user_table(request):
     data = []
     for row in rows:
         # Parse the JSON string into a dictionary
-        log = json.loads(row[2])
-        # Create a dictionary with the date, user, and JSON fields
+        log = json.loads(row[1])
+        # Get the user object based on the user_id
+        user_id = row[2]
+        # Get the feedback value
+        feedback = row[3]
+        # Create a dictionary with the date, user, JSON fields, and feedback
         date = row[0].strftime('%Y-%m-%d %H:%M:%S')
-        entry = {'date': date, 'user': row[1], 'file': log['file'], 'action': log['action'], 'status': log['status']}
+        entry = {'date': date, 'user': user_id, 'file': log['file'], 'action': log['action'], 'status': log['status'],
+                 'description': log['description'], 'feedback': feedback}
         data.append(entry)
 
     # Return the data as a JSON response
@@ -104,32 +157,35 @@ def user_table(request):
 
 def index(request):
     # Initialize default context
-    context = {'form': InstrumentDetectionForm(), 
-               'predictions': [],
-               'file_name': None
-               }
-    
+    context = {'form': InstrumentDetectionForm(), 'predictions': [], 'file_name': None}
+
     # Handle authenticated users
     if request.user.is_authenticated:
         token_count = UserTokenCount.objects.get(user=request.user).token_count
         context['token_count'] = token_count
+
         if request.method == 'POST':
             form = InstrumentDetectionForm(request.POST, request.FILES)
             if form.is_valid() and 'audio_file' in request.FILES:
                 uploaded_file = request.FILES['audio_file']
                 context['file_name'] = uploaded_file.name
+
                 # Make a request to the InstrumentDetectionView to get the predictions
                 view = InstrumentDetectionView().as_view()
                 response = view(request)
+
                 # Ensure there's a response and it contains predictions before updating context
                 if response and hasattr(response, 'data') and 'predictions' in response.data:
                     context['predictions'] = response.data['predictions']
+
+                    if request.user.is_authenticated:
+                        feedback = request.POST.get('feedback')  # Get the user's feedback from the form
+                        predictions_string = ', '.join(response.data['predictions'])
+                        log_data = get_log_data(request.user, Action.RUN_ALGORITHM, 'success', file=uploaded_file.name, 
+                                                description=predictions_string, feedback=feedback)
+                        create_log(request.user, log_data)
             else:
                 context['form'] = form
-        # For GET requests or if form is not valid, render the page with the default or updated context
-        return render(request, 'index1.html', context)        
-
-    # Handle unauthenticated users
     else:
         if request.method == 'POST':
             # Assuming you want to do something specific with the file if it's uploaded
@@ -137,33 +193,41 @@ def index(request):
             if uploaded_file:
                 # Process the uploaded file as needed
                 pass
-            # For now, just render the main page again, potentially after handling the uploaded file
-        # For GET requests or if POST doesn't involve a file, just show the main page
+
+    # For GET requests or if form is not valid, render the page with the default or updated context
+    if request.user.is_authenticated:
+        return render(request, 'index1.html', context)
+    else:
         return render(request, 'index2.html')
 
 
-        
+
 
 
 def users(request):
-    # Make a request to the admin_table view to get the data
-    context = {}
-    data_admin = admin_table(request)
-    data_user = user_table(request)
-    admin_dict = json.loads(data_admin.content)
-    user_dict = json.loads(data_user.content)
-    token_count = UserTokenCount.objects.get(user=request.user).token_count
-    user_profile = request.user.profile
-    user = request.user
-    # Pass the data as a context variable to the template
-    # !!! ADMIN DATA ONLY DISPLAYED AND GET IF USER IS ADMIN !!!
-    context['admin_data'] = admin_dict['data']
-    context['user_data'] = user_dict['data']
-    context['token_count'] = token_count
-    context['user_profile'] = user_profile
-    context['user'] = user
-
-    return render(request, 'user_page.html', context)
+    if request.user.is_authenticated:
+        # Make a request to the admin_table view to get the data
+        context = {}
+        data_admin = admin_table(request)
+        data_user = user_table(request)
+        admin_dict = json.loads(data_admin.content)
+        user_dict = json.loads(data_user.content)
+        token_count = UserTokenCount.objects.get(user=request.user).token_count
+        user_profile = request.user.profile
+        user = request.user
+        all_user_profiles = Profile.objects.all()  # Retrieve all Profile objects
+
+        # Pass the data as a context variable to the template
+        # !!! ADMIN DATA ONLY DISPLAYED AND GET IF USER IS ADMIN !!!
+        context['admin_data'] = admin_dict['data']
+        context['user_data'] = user_dict['data']
+        context['token_count'] = token_count
+        context['user_profile'] = user_profile
+        context['user'] = user
+        context['all_user_profiles'] = all_user_profiles  # Add all_user_profiles to the context
+
+        return render(request, 'user_page.html', context)
+    return redirect('login')
 
 def handler404(request, *args, **kwargs):
     response = render(request, '404.html', {})
@@ -178,60 +242,43 @@ def handler500(request, *args, **kwargs):
 def maintenance(request):
     return render(request, 'maintenance.html')
 
-# def user_login(request):
-#     if request.method == 'POST':
-#         form = LoginForm(request.POST)
-
-#         if form.is_valid():
-#             username = form.cleaned_data.get('username')
-#             password = form.cleaned_data.get('password')
-
-#             user = authenticate(request, username=username, password=password)  # Passing request along with username and password
-
-#             if user:
-#                 login(request, user=user)  # Passing request along with user
-#                 return redirect('users')
-#             else:
-#                 messages.error(request, 'Invalid username or password.')
-#         else:
-#             pass
-
-#     else:
-#         form = LoginForm()
-#     return render(request, 'login.html', {'form': form})
-
-
-# def register(request):
-#     if request.method == 'POST':
-#         form = CustomRegistrationForm(request.POST)
-#         if form.is_valid():
-#             form.save()
-#             return redirect('user_login')
-#     else:
-#         form = CustomRegistrationForm()
-
-#     return render(request, 'register.html', {'form': form})
-
-# def user_logout(request):
-#     logout(request)
-#     return redirect('user_login')
-
 
 # Authentication
 class RegisterView(generic.CreateView):
     form_class = UserRegisterForm
-    success_url = reverse_lazy('login')
+    success_url = reverse_lazy('index')
     template_name = 'registration/register.html'
 
     def form_valid(self, form):
         response = super().form_valid(form)
-        Profile.objects.create(user=self.object, user_type=0)  # Default user type as Basic User
+        user = self.object  # Grab the user instance
+
+        # Ensure the user is active; this line might be redundant if you're sure users are active by default
+        user.is_active = True
+        user.save()
+
+        # Check if the Profile exists, and if not, create it
+        if not Profile.objects.filter(user=user).exists():
+            Profile.objects.create(user=user, user_type=0)  # Default user type as Basic User
+
+        # Log the user in
+        login(self.request, user)
+
         return response
-    
+
 
 class CustomLoginView(LoginView):
     authentication_form = LoginAuthenticationForm
-    template_name = 'registration/login.html'  
+    template_name = 'registration/login.html'
+
+    def form_valid(self, form):
+        # Create log if user is authenticated
+        login(self.request, form.get_user())
+
+        log_data = get_log_data(form.get_user(), Action.LOGIN, 'success')
+        create_log(form.get_user(), log_data)
+
+        return super().form_valid(form)
 
 
 def terms_conditions(request):
@@ -258,25 +305,36 @@ def generate_pdf(request):
 # Running the audio file through the model
 class InstrumentDetectionView(APIView):
     def post(self, request):
+        # Get the user's token count
+        user_token_count = UserTokenCount.objects.get(user=request.user)
+
+        # Check if the user has more than one token
+        if user_token_count.token_count < 1:
+            return Response({'error': 'Insufficient tokens'}, status=status.HTTP_403_FORBIDDEN)
+
+        # Decrease the user's token count by one
+        user_token_count.token_count -= 1
+        user_token_count.save()
+
         serializer = InstrumentDetectionSerializer(data=request.data)
         if serializer.is_valid():
             audio_file = serializer.validated_data['audio_file']
-            
+
             # Save the uploaded file temporarily
             # with open('temp_audio.wav', 'wb') as f:
             #     f.write(audio_file.read())
-            
+
             # Preprocess the audio file
             preprocessed_data = preprocess_audio_for_inference(audio_file)
-            
+
             # Prepare data for TensorFlow Serving
             data = json.dumps({"signature_name": "serving_default", "instances": [window.tolist() for window in preprocessed_data]})
-            
+
             # Send request to TensorFlow Serving
             url = 'http://tensorflow_serving:8501/v1/models/instrument_model/versions/2:predict'
             headers = {"Content-Type": "application/json"}
             response = requests.post(url, data=data, headers=headers)
-            
+
             # Process the response
             if response.status_code == 200:
                 raw_predictions = response.json()['predictions']
@@ -285,32 +343,80 @@ class InstrumentDetectionView(APIView):
                 return Response({"predictions": formatted_predictions}, status=status.HTTP_200_OK)
             else:
                 return Response({"error": "Failed to get predictions"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
-        
+
         return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
-    
-    def convert_to_percentages(self, predictions):
-        # Assuming predictions is a list of lists
-        percentage_predictions = []
-        for prediction in predictions:
-            total = sum(prediction)
-            # Convert each number to a percentage of the total, rounded to 2 decimal places
-            percentages = [round((number / total) * 100, 2) for number in prediction]
-            percentage_predictions.append(percentages)
-        return percentage_predictions
-    
+
+
     def format_predictions(self, predictions):
         instruments = ['Guitar', 'Drum', 'Violin', 'Piano']
-        formatted_predictions = []
+        instrument_windows = {instrument: [] for instrument in instruments}
+
         for window_index, prediction in enumerate(predictions, start=1):
-            formatted_window = f"<strong>Window {window_index}</strong><br>"
-            formatted_scores = "<br>".join([f"{instruments[i]} - {score:.2f}" for i, score in enumerate(prediction)])
-            formatted_predictions.append(f"{formatted_window}{formatted_scores}")
+            highest_score_index = prediction.index(max(prediction))
+            highest_score_instrument = instruments[highest_score_index]
+            instrument_windows[highest_score_instrument].append(window_index)
+
+        formatted_predictions = []
+        for instrument, windows in instrument_windows.items():
+            if windows:
+                window_list = ', '.join(map(str, windows))
+                formatted_predictions.append(f"{instrument} - Windows: {window_list}")
+
         return formatted_predictions
+    
+
+
+
+class ModelPerformanceView(UserPassesTestMixin, TemplateView):
+    template_name = 'model_performance.html'
 
+    def test_func(self):
+        return self.request.user.is_authenticated and (self.request.user.is_superuser or self.request.user.profile.user_type == 2)
+
+    def get_context_data(self, **kwargs):
+        context = super().get_context_data(**kwargs)
+
+        metrics_url = 'http://tensorflow_serving:8501/monitoring/prometheus/metrics'
+        response = requests.get(metrics_url)
+
+        if response.status_code == 200:
+            metrics_data = response.text
+
+            # Extract metrics using regular expressions
+            request_count = re.search(r':tensorflow:serving:request_count{model_name="instrument_model",status="OK"} (\d+)', metrics_data)
+            request_latency_sum = re.search(r':tensorflow:serving:request_latency_sum{model_name="instrument_model",API="predict",entrypoint="REST"} ([\d\.e\+]+)', metrics_data)
+            request_latency_count = re.search(r':tensorflow:serving:request_latency_count{model_name="instrument_model",API="predict",entrypoint="REST"} (\d+)', metrics_data)
+            runtime_latency_sum = re.search(r':tensorflow:serving:runtime_latency_sum{model_name="instrument_model",API="Predict",runtime="TF1"} ([\d\.e\+]+)', metrics_data)
+            runtime_latency_count = re.search(r':tensorflow:serving:runtime_latency_count{model_name="instrument_model",API="Predict",runtime="TF1"} (\d+)', metrics_data)
+            model_load_latency = re.search(r':tensorflow:cc:saved_model:load_latency{model_path="/models/instrument_model/2"} (\d+)', metrics_data)
+
+            # Calculate average latencies in seconds
+            avg_request_latency = float(request_latency_sum.group(1)) / float(request_latency_count.group(1)) / 1e6 if request_latency_sum and request_latency_count else None
+            avg_runtime_latency = float(runtime_latency_sum.group(1)) / float(runtime_latency_count.group(1)) / 1e6 if runtime_latency_sum and runtime_latency_count else None
+            model_load_latency_seconds = float(model_load_latency.group(1)) / 1e6 if model_load_latency else None
+
+            context['metrics'] = {
+                'request_count': request_count.group(1) if request_count else None,
+                'avg_request_latency': avg_request_latency,
+                'avg_runtime_latency': avg_runtime_latency,
+                'model_load_latency': model_load_latency_seconds
+            }
+        else:
+            context['metrics'] = None
+
+        return context
+
+def change_user_type(request, user_id):
+    if request.method == 'POST':
+        user_type = request.POST.get('user_type')
+        user_profile = get_object_or_404(Profile, user__id=user_id)  # Get the user profile
+        user_profile.user_type = user_type
+        user_profile.save()
+        return redirect('users')  # Redirect to the users page
 
 def user_has_credits():
     has_credits = False
 
 
 
-    return has_credits
\ No newline at end of file
+    return has_credits