Add button for exporting results, fix history

This commit is contained in:
Piotr Szkudlarek 2024-01-04 21:33:13 +01:00
parent 270bb92c4c
commit c6ba3dd6b0
16 changed files with 229 additions and 54 deletions

View File

@ -0,0 +1,46 @@
# Generated by Django 4.2.7 on 2024-01-04 19:37
from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("DetectionApp", "0011_remove_predictedimage_class_name_and_more"),
]
operations = [
migrations.RemoveField(
model_name="predictedimage",
name="date_predicted",
),
migrations.RemoveField(
model_name="uploadimage",
name="owner",
),
migrations.CreateModel(
name="PredicitonBatch",
fields=[
(
"id",
models.BigAutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name="ID",
),
),
("date_predicted", models.DateTimeField(auto_now_add=True)),
("images", models.ManyToManyField(to="DetectionApp.predictedimage")),
(
"owner",
models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
to=settings.AUTH_USER_MODEL,
),
),
],
),
]

View File

@ -0,0 +1,18 @@
# Generated by Django 4.2.7 on 2024-01-04 19:49
from django.conf import settings
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
("DetectionApp", "0012_remove_predictedimage_date_predicted_and_more"),
]
operations = [
migrations.RenameModel(
old_name="PredicitonBatch",
new_name="PredictionBatch",
),
]

View File

@ -12,18 +12,12 @@ class UploadImage(models.Model):
validators=[FileExtensionValidator(allowed_extensions=["jpg", "png"])],
)
predicted_image_url = models.CharField(max_length=500)
owner = models.ForeignKey(User, on_delete=models.CASCADE)
class PredictedImage(models.Model):
original_image = models.OneToOneField(UploadImage, on_delete=models.CASCADE)
image = models.ImageField(upload_to=f"plankton/%Y/%m/%d/{original_image.name}")
prediction_data = models.JSONField()
date_predicted = models.DateTimeField(auto_now_add=True)
@property
def get_owner(self):
return self.original_image.owner
@property
def get_original_image(self):
@ -34,3 +28,9 @@ class PredictedImage(models.Model):
for pred in results:
pred["confidence"] = round(pred["confidence"] * 100, 2)
return results
class PredictionBatch(models.Model):
images = models.ManyToManyField(PredictedImage)
date_predicted = models.DateTimeField(auto_now_add=True)
owner = models.ForeignKey(User, on_delete=models.CASCADE)

View File

@ -10,4 +10,5 @@ urlpatterns = [
path(
"detection/<int:pk>", views.DetectionDetails.as_view(), name="detection-details"
),
path("export_pred/<int:pk>", views.download_pred_res, name="download_predicitons"),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

View File

@ -16,6 +16,6 @@ def predict_image(image):
name=f"{image.image.name}_predicted",
imgsz=[640, 640],
)
for r in results:
x = r.tojson()
return x
for result in results:
metrics = result.tojson()
return metrics

View File

@ -1,15 +1,15 @@
from typing import Any
from django.db.models.query import QuerySet
from django.shortcuts import render, redirect
from django.http import HttpResponse
from django.shortcuts import render
from django.views import View
from .forms import DetectForm
from django.views.generic import ListView, DetailView
from django.contrib.auth.decorators import login_required
from django.utils.decorators import method_decorator
from .models import UploadImage, PredictedImage
from .models import PredictionBatch, UploadImage, PredictedImage
from .utils import predict_image
from django.contrib.auth.mixins import LoginRequiredMixin
import json
class DetectView(View):
@ -26,11 +26,11 @@ class DetectView(View):
files = request.FILES.getlist("image")
predictions = []
if form.is_valid():
pred_batch = PredictionBatch.objects.create(owner=request.user)
for f in files:
image = UploadImage(
image=f,
)
image.owner = request.user
image.save()
prediciton_results = predict_image(image)
image.predicted_image_url = (
@ -43,7 +43,7 @@ class DetectView(View):
predicted_image = PredictedImage.objects.create(
original_image=image,
image=image.predicted_image_url,
prediction_data={"data": "no results"},
prediction_data={"data": "no predicitions"},
)
else:
predicted_image = PredictedImage.objects.create(
@ -52,12 +52,14 @@ class DetectView(View):
prediction_data=results_metrics,
)
predictions.append(predicted_image)
pred_batch.images.add(*predictions)
pred_batch.save()
return render(
request,
"results.html",
{
"img_saved": True,
"img_url": predictions,
"img": pred_batch,
},
)
else:
@ -65,18 +67,28 @@ class DetectView(View):
class ListHistory(LoginRequiredMixin, ListView):
model = PredictedImage
queryset = PredictedImage.objects.all()
model = PredictionBatch
queryset = PredictionBatch.objects.all()
template_name = "history.html"
paginate_by = 3
def get_queryset(self) -> QuerySet[Any]:
queryset = PredictedImage.objects.filter(
original_image__owner=self.request.user
).order_by("-date_predicted")
queryset = PredictionBatch.objects.filter(owner=self.request.user).order_by(
"-date_predicted"
)
return queryset
class DetectionDetails(LoginRequiredMixin, DetailView):
model = PredictedImage
template_name = "detection_detail.html"
model = PredictionBatch
template_name = "results.html"
context_object_name = "img"
def download_pred_res(request, pk):
pred_batch = PredictionBatch.objects.get(pk=pk)
response = HttpResponse(content_type="text/plain")
response["Content-Disposition"] = "attachment; filename=predictions.txt"
for img in pred_batch.images.all():
response.write(img.prediction_data)
return response

Binary file not shown.

View File

@ -1,3 +1,85 @@
.class{
display:flex;
body, html{
height: unset;
}
.page-container{
display: flex;
flex-direction: column;
width: 100%;
height: 100%;
align-items: center;
overflow: hidden;
}
.post{
display:flex;
margin-top:10px;
flex-direction: column;
justify-content:center;
align-items: flex-start;
border: 3px solid lightgray;
width: 80%;
padding: 15px;
border-radius: 5%;
}
.title-content{
display: flex;
flex-direction: column;
justify-content: flex-start;
align-items: center;
}
#title{
font-size: 40px;
color: black;
font-weight: bold;
}
#content{
font-size: 20px;
color:black;
}
.author{
display: flex;
justify-content: flex-end;
align-items: center;
width: 100%;
}
#author{
font-size: 15px;
}
.comments{
display: flex;
flex-direction:column;
justify-content: space-between;
align-items: center;
width: 80%;
margin-bottom: 25px;
}
#comment-label{
font-size: 30px;
align-self: flex-start;
margin-left: 10%;
color:black;
font-weight: bold;
}
.single-comment{
display: flex;
flex-direction: column;
width: 90%;
border-bottom: 3px solid lightgray;
margin-top:10px;
}
#comment-author{
display: flex;
width: 100%;
justify-content: flex-end;
}

View File

@ -1,7 +0,0 @@
.history_list{
display: flex;
flex-direction: column;
align-items: center;
width: 100%;
height: 100%;
}

View File

@ -24,7 +24,7 @@ ul{
display:flex;
width: 100%;
flex-direction: row;
align-items: flex-start;
align-items: center;
justify-content: space-evenly;
margin-bottom: 25px;
}

View File

@ -19,7 +19,7 @@ form{
border: 2px grey solid;
padding: 0px 0px 40px 0px;
margin-bottom: 5px;
overflow-y: scroll;
overflow-y: auto;
}
@ -43,10 +43,9 @@ form{
.upload_field {
margin: auto;
display: flex;
flex-direction: row;
flex-direction: column;
justify-content: right;
width:645px;
height: 465px;
}
@ -85,3 +84,14 @@ form{
text-decoration:solid;
color: black;
}
#download_json{
background-color: chartreuse;
margin: 30px auto auto auto;
height: 50px;
width: 60%;
border-radius: 25px;
border: 2px white;
box-shadow: 0 0 0 4px white;
font-size: 25px;
}

View File

@ -1,7 +0,0 @@
{%extends 'base.html'%}
{%load static%}
{%block extracss%}
<link rel="stylesheet" href="{% static 'DetectionApp/css/detection-detail.css' %}">
{%endblock extracss%}
{%block content%}
{%endblock content%}

View File

@ -6,14 +6,15 @@
{%block content%}
<div class="history_list">
<h2>History</h2>
{% for detection in page_obj %}
{% for detection in page_obj %}
<div class="history_details">
<a href="{%url 'detection-details' pk=detection.id %}">
<div class="history_details">
<img src="{{detection.image.url}}" alt="upload_image" style="width:100px; height:100px;">
<img src="{{detection.images.first.image.url}}" alt="upload_image" style="width:125px; height:125px;">
<div class="date_author">
<p class="date">{{detection.date_predicted.date}}</p>
<p class="author">{{detection.get_owner}}</p>
<p class="author">{{detection.owner}}</p>
<p class="num_images">Images uploaded: {{detection.images.all.count}}</p>
</div>
</div>
</a>

View File

@ -1,19 +1,27 @@
{%extends 'base.html'%}
{%load static%}
{%block extracss%}
<link rel="stylesheet" href="{% static 'DetectionApp/css/detection-detail.css' %}">
<link rel="stylesheet" href="{% static 'Community/css/post_details.css' %}">
{%endblock extracss%}
{%block content%}
<div class="page-container">
<div class="post">
<p class="title">{{object.title}}</p>
<p class="content">{{object.content}}</p>
<p class="author">{{object.author}}</p>
<div class="title-content">
<p id="title">{{object.title}}</p>
<p id="content">{{object.content}}</p>
</div>
<div class="author">
<p id="author">{{object.author}}</p>
</div>
</div>
<p id="comment-label">Comments:</p>
<div class="comments">
{%for comments in object.comment_set.all%}
<p>{{comments.author}}</p>
<p>{{comments.content}}</p>
<p>{{comments.post}}</p>
<div class="single-comment">
<p id="comment-content">{{comments.content}}</p>
<p id="comment-author">{{comments.author}}</p>
</div>
{%endfor%}
</div>
</div>
{%endblock content%}

View File

@ -12,7 +12,7 @@
<button onclick="location.href='{% url 'login' %}'" id='submit' method="GET" type='button'>Login</button>
{% else %}
<p id="description">Results:</p>
{%for img in img_url%}
{%for img in img.images.all %}
<p class="image_number">Image {{forloop.counter}}</p>
{%for detection in img.get_prediction_data%}
<div class="results">
@ -25,10 +25,11 @@
</div>
<div class="upload_field">
<label>
{%for img in img_url%}
{%for img in img.images.all %}
<img src="{{img.image.url}}" alt="upload_image" style="width:640px; height:460px;">
{%endfor%}
</label>
<button onclick="location.href='{%url 'download_predicitons' pk=img.id%}'" id="download_json" method="GET" type="button">Export predictions</button>
</div>
</form>
<script>

View File

@ -67,6 +67,16 @@ document.getElementById('id_image').addEventListener('change', function () {
}
});
var user = `{{user.is_authenticated}}`
var upload = document.getElementById("id_image")
if (user.toLowerCase()=="false"){
console.log('disabled');
upload.disabled=true;
}else if (user.toLowerCase()=="true"){
console.log("enabled");
upload.disabled=false;
}
</script>
</form>
{%endblock content%}