diff --git a/backend/Dockerfile b/backend/Dockerfile
index b7e40872..2f67c2be 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -28,6 +28,5 @@ RUN pip install setuptools --upgrade
COPY requirements.txt requirements.txt
RUN pip install -r requirements.txt
-
WORKDIR /app
COPY . /app
\ No newline at end of file
diff --git a/backend/core/models.py b/backend/core/models.py
index b4ed7435..b1d67be1 100644
--- a/backend/core/models.py
+++ b/backend/core/models.py
@@ -31,8 +31,8 @@ class DownloadStatus(models.IntegerChoices):
dataset = models.ForeignKey(Dataset, to_field="id", on_delete=models.CASCADE)
geom = geomodels.PolygonField(srid=4326)
- download_status = models.IntegerField(default=-1, choices=DownloadStatus.choices)
- last_fetched_date = models.DateTimeField(null=True, blank=True)
+ label_status = models.IntegerField(default=-1, choices=DownloadStatus.choices)
+ label_fetched = models.DateTimeField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
@@ -42,7 +42,6 @@ class Label(models.Model):
geom = geomodels.GeometryField(srid=4326)
osm_id = models.BigIntegerField(null=True, blank=True)
created_at = models.DateTimeField(auto_now_add=True)
- last_modified = models.DateTimeField(auto_now=True)
class Model(models.Model):
@@ -89,11 +88,11 @@ class Training(models.Model):
class Feedback(models.Model):
- ACTION_TYPE = (
- ("CREATE", "CREATE"),
- ("MODIFY", "MODIFY"),
- ("ACCEPT", "ACCEPT"),
- ("INITIAL", "INITIAL"),
+ FEEDBACK_TYPE = (
+ ("TP", "True Positive"),
+ ("TN", "True Negative"),
+ ("FP", "False Positive"),
+ ("FN", "False Negative"),
)
geom = geomodels.GeometryField(srid=4326)
training = models.ForeignKey(Training, to_field="id", on_delete=models.CASCADE)
@@ -101,7 +100,29 @@ class Feedback(models.Model):
zoom_level = models.PositiveIntegerField(
validators=[MinValueValidator(18), MaxValueValidator(23)]
)
- action = models.CharField(choices=ACTION_TYPE, max_length=10)
+ feedback_type = models.CharField(choices=FEEDBACK_TYPE, max_length=10)
+ comments = models.TextField(max_length=100,null=True,blank=True)
+ user = models.ForeignKey(OsmUser, to_field="osm_id", on_delete=models.CASCADE)
+ source_imagery = models.URLField()
+
+
+class FeedbackAOI(models.Model):
+ class DownloadStatus(models.IntegerChoices):
+ DOWNLOADED = 1
+ NOT_DOWNLOADED = -1
+ RUNNING = 0
+ training = models.ForeignKey(Training, to_field="id", on_delete=models.CASCADE)
+ geom = geomodels.PolygonField(srid=4326)
+ label_status = models.IntegerField(default=-1, choices=DownloadStatus.choices)
+ label_fetched = models.DateTimeField(null=True, blank=True)
+ created_at = models.DateTimeField(auto_now_add=True)
last_modified = models.DateTimeField(auto_now=True)
+ source_imagery = models.URLField()
user = models.ForeignKey(OsmUser, to_field="osm_id", on_delete=models.CASCADE)
- validated = models.BooleanField(default=False)
+
+
+class FeedbackLabel(models.Model):
+ osm_id = models.BigIntegerField(null=True, blank=True)
+ feedback_aoi = models.ForeignKey(FeedbackAOI, to_field="id", on_delete=models.CASCADE)
+ geom = geomodels.PolygonField(srid=4326)
+ created_at = models.DateTimeField(auto_now_add=True)
diff --git a/backend/core/serializers.py b/backend/core/serializers.py
index 35cf792e..2381ce3e 100644
--- a/backend/core/serializers.py
+++ b/backend/core/serializers.py
@@ -57,11 +57,32 @@ class Meta:
read_only_fields = (
"created_at",
"last_modified",
- "last_fetched_date",
- "download_status",
+ "label_fetched",
+ "label_status",
)
+class FeedbackAOISerializer(GeoFeatureModelSerializer):
+ class Meta:
+ model = FeedbackAOI
+ geo_field = "geom"
+ fields = "__all__"
+ partial = True
+
+ read_only_fields = (
+ "created_at",
+ "last_modified",
+ "label_fetched",
+ "label_status",
+ "user",
+ )
+
+ def create(self, validated_data):
+ user = self.context["request"].user
+ validated_data["user"] = user
+ return super().create(validated_data)
+
+
class FeedbackSerializer(GeoFeatureModelSerializer):
class Meta:
model = Feedback
@@ -90,10 +111,15 @@ class Meta:
# auto_bbox = True
fields = "__all__" # defining all the fields to be included in curd for now , we can restrict few if we want
- read_only_fields = (
- "created_at",
- "last_modified",
- )
+ read_only_fields = ("created_at", "osm_id")
+
+
+class FeedbackLabelSerializer(GeoFeatureModelSerializer):
+ class Meta:
+ model = FeedbackLabel
+ geo_field = "geom"
+ fields = "__all__"
+ read_only_fields = ("created_at", "osm_id")
class LabelFileSerializer(
@@ -136,6 +162,7 @@ class FeedbackParamSerializer(serializers.Serializer):
batch_size = serializers.IntegerField(required=False)
freeze_layers = serializers.BooleanField(required=False)
+
class PredictionParamSerializer(serializers.Serializer):
bbox = serializers.ListField(child=serializers.FloatField(), required=True)
model_id = serializers.IntegerField(required=True)
diff --git a/backend/core/urls.py b/backend/core/urls.py
index 8abbea60..8c395cdd 100644
--- a/backend/core/urls.py
+++ b/backend/core/urls.py
@@ -7,6 +7,8 @@
AOIViewSet,
APIStatus,
DatasetViewSet,
+ FeedbackAOIViewset,
+ FeedbackLabelViewset,
FeedbackView,
FeedbackViewset,
GenerateGpxView,
@@ -31,6 +33,8 @@
router.register(r"training", TrainingViewSet)
router.register(r"model", ModelViewSet)
router.register(r"feedback", FeedbackViewset)
+router.register(r"feedback-aoi", FeedbackAOIViewset)
+router.register(r"feedback-label", FeedbackLabelViewset)
urlpatterns = [
diff --git a/backend/core/views.py b/backend/core/views.py
index b6c9e5bb..ddbf8357 100644
--- a/backend/core/views.py
+++ b/backend/core/views.py
@@ -38,11 +38,22 @@
from rest_framework.views import APIView
from rest_framework_gis.filters import InBBoxFilter, TMSTileFilter
-from .models import AOI, Dataset, Feedback, Label, Model, Training
+from .models import (
+ AOI,
+ Dataset,
+ Feedback,
+ FeedbackAOI,
+ FeedbackLabel,
+ Label,
+ Model,
+ Training,
+)
from .serializers import (
AOISerializer,
DatasetSerializer,
+ FeedbackAOISerializer,
FeedbackFileSerializer,
+ FeedbackLabelSerializer,
FeedbackParamSerializer,
FeedbackSerializer,
LabelSerializer,
@@ -150,7 +161,30 @@ class FeedbackViewset(viewsets.ModelViewSet):
queryset = Feedback.objects.all()
http_method_names = ["get", "post", "patch", "delete"]
serializer_class = FeedbackSerializer # connecting serializer
- filterset_fields = ["training", "user", "action", "validated"]
+ filterset_fields = ["training", "user", "feedback_type"]
+
+
+class FeedbackAOIViewset(viewsets.ModelViewSet):
+ authentication_classes = [OsmAuthentication]
+ permission_classes = [IsOsmAuthenticated]
+ permission_allowed_methods = ["GET"]
+ queryset = FeedbackAOI.objects.all()
+ http_method_names = ["get", "post", "patch", "delete"]
+ serializer_class = FeedbackAOISerializer
+ filterset_fields = [
+ "training",
+ "user",
+ ]
+
+
+class FeedbackLabelViewset(viewsets.ModelViewSet):
+ authentication_classes = [OsmAuthentication]
+ permission_classes = [IsOsmAuthenticated]
+ permission_allowed_methods = ["GET"]
+ queryset = FeedbackLabel.objects.all()
+ http_method_names = ["get", "post", "patch", "delete"]
+ serializer_class = FeedbackLabelSerializer
+ filterset_fields = ["feedback_aoi"]
class ModelViewSet(
@@ -208,7 +242,7 @@ def post(self, request, aoi_id, *args, **kwargs):
"""
obj = get_object_or_404(AOI, id=aoi_id)
try:
- obj.download_status = 0
+ obj.label_status = 0
obj.save()
raw_data_params = {
"geometry": json.loads(obj.geom.geojson),
@@ -218,12 +252,12 @@ def post(self, request, aoi_id, *args, **kwargs):
result = request_rawdata(raw_data_params)
file_download_url = result["download_url"]
process_rawdata(file_download_url, aoi_id)
- obj.download_status = 1
- obj.last_fetched_date = datetime.utcnow()
+ obj.label_status = 1
+ obj.label_fetched = datetime.utcnow()
obj.save()
return Response("Success", status=status.HTTP_201_CREATED)
except Exception as ex:
- obj.download_status = -1
+ obj.label_status = -1
obj.save()
# raise ex
return Response("OSM Fetch Failed", status=500)
diff --git a/docker-compose.yml b/docker-compose.yml
index 263647eb..80dfc78e 100644
--- a/docker-compose.yml
+++ b/docker-compose.yml
@@ -35,7 +35,7 @@ services:
volumes:
- ./backend:/app
- ${RAMP_HOME}:/RAMP_HOME
- - ${TRAINING_WORKSPACE}:/TRAINING_WORKSPACE
+ # - ${TRAINING_WORKSPACE}:/TRAINING_WORKSPACE
depends_on:
- redis
- postgres
@@ -55,7 +55,7 @@ services:
volumes:
- ./backend:/app
- ${RAMP_HOME}:/RAMP_HOME
- - ${TRAINING_WORKSPACE}:/TRAINING_WORKSPACE
+ # - ${TRAINING_WORKSPACE}:/TRAINING_WORKSPACE
depends_on:
- backend-api
- redis
diff --git a/frontend/public/rapid-logo.png b/frontend/public/rapid-logo.png
new file mode 100644
index 00000000..1d6f3b6d
Binary files /dev/null and b/frontend/public/rapid-logo.png differ
diff --git a/frontend/src/components/Layout/AIModels/AIModelEditor/Feedback.js b/frontend/src/components/Layout/AIModels/AIModelEditor/Feedback.js
new file mode 100644
index 00000000..709bd4a9
--- /dev/null
+++ b/frontend/src/components/Layout/AIModels/AIModelEditor/Feedback.js
@@ -0,0 +1,60 @@
+import { IconButton, Tooltip } from "@mui/material";
+import React, { useContext } from "react";
+import InfoIcon from "@mui/icons-material/Info";
+import FeedbackIcon from "@mui/icons-material/Feedback";
+import { useQuery } from "react-query";
+import axios from "../../../../axios";
+import AuthContext from "../../../../Context/AuthContext";
+import FindReplaceIcon from "@mui/icons-material/FindReplace";
+const Feedback = ({ trainingId }) => {
+ const { accessToken } = useContext(AuthContext);
+ const getFeedback = async () => {
+ try {
+ const headers = {
+ "access-token": accessToken,
+ };
+ const res = await axios.get(`/feedback/?training=${trainingId}`, null, {
+ headers,
+ });
+
+ if (res.error) {
+ } else {
+ // console.log(`/feedback/?training=${trainingId}`, res.data);
+ return res.data;
+ }
+ } catch (e) {
+ console.log("isError", e);
+ } finally {
+ }
+ };
+ const { data: feedbackData, isLoading } = useQuery(
+ "getFeedback" + trainingId,
+ getFeedback,
+ {
+ refetchInterval: 10000,
+ }
+ );
+
+ return (
+ <>
+ {feedbackData &&
+ feedbackData.features &&
+ feedbackData.features.length > 0 && (
+
+
+
+
+
+ )}
+ {isLoading && (
+
+
+
+ )}
+ >
+ );
+};
+export default Feedback;
diff --git a/frontend/src/components/Layout/AIModels/AIModelEditor/Trainings.js b/frontend/src/components/Layout/AIModels/AIModelEditor/Trainings.js
index f6526afb..4c160786 100644
--- a/frontend/src/components/Layout/AIModels/AIModelEditor/Trainings.js
+++ b/frontend/src/components/Layout/AIModels/AIModelEditor/Trainings.js
@@ -20,6 +20,7 @@ import Popup from "./Popup";
import InfoIcon from "@mui/icons-material/Info";
import AuthContext from "../../../../Context/AuthContext";
+import Feedback from "./Feedback";
const DEFAULT_FILTER = {
items: [{ columnField: "created_date", id: 8537, operatorValue: "contains" }],
@@ -151,16 +152,22 @@ const TrainingsList = (props) => {
},
{
field: "popup",
- headerName: "Info",
- width: 10,
- renderCell: (params) => (
- handlePopupOpen(params.row)}
- aria-label="popup"
- >
-
-
- ),
+ headerName: "Info/Feedback",
+ width: 100,
+ renderCell: (params) => {
+ // console.log("params in info row", params);
+ return (
+
+ handlePopupOpen(params.row)}
+ aria-label="popup"
+ >
+
+
+
+
+ );
+ },
},
{
field: "accuracy",
diff --git a/frontend/src/components/Layout/Start/Prediction/EditableGeoJSON.js b/frontend/src/components/Layout/Start/Prediction/EditableGeoJSON.js
index b6eac26f..bfc1e18f 100644
--- a/frontend/src/components/Layout/Start/Prediction/EditableGeoJSON.js
+++ b/frontend/src/components/Layout/Start/Prediction/EditableGeoJSON.js
@@ -1,10 +1,14 @@
-import React, { useEffect, useState } from "react";
+import React, { useContext, useEffect, useState } from "react";
import L from "leaflet";
import { GeoJSON } from "react-leaflet";
import "@geoman-io/leaflet-geoman-free";
import "@geoman-io/leaflet-geoman-free/dist/leaflet-geoman.css";
-
+import { useMutation } from "react-query";
+// import L from "leaflet";
+import AuthContext from "../../../../Context/AuthContext";
+import axios from "../../../../axios";
+import { converToGeoPolygon } from "../../../../utils";
function deg2tile(lat_deg, lon_deg, zoom) {
const lat_rad = (Math.PI / 180) * lat_deg;
const n = Math.pow(2, zoom);
@@ -34,32 +38,32 @@ function tile2boundingbox(xtile, ytile, zoom) {
return L.latLngBounds(cornerNW, cornerSE);
}
-function addTileBoundaryLayer(
- mapref,
- addedTiles,
- tileX,
- tileY,
- zoom,
- setAddedTiles,
- tileBoundaryLayer
-) {
- const key = `${tileX}_${tileY}_${zoom}`;
+// function addTileBoundaryLayer(
+// mapref,
+// addedTiles,
+// tileX,
+// tileY,
+// zoom,
+// setAddedTiles,
+// tileBoundaryLayer
+// ) {
+// const key = `${tileX}_${tileY}_${zoom}`;
- if (!addedTiles.has(key)) {
- console.log("Key doesn't present in map");
- const bounds = tile2boundingbox(tileX, tileY, zoom);
- tileBoundaryLayer = L.rectangle(bounds, {
- color: "yellow",
- fill: false,
- pmIgnore: true,
- });
- tileBoundaryLayer.name = "Tile Box";
- mapref.addLayer(tileBoundaryLayer);
- mapref.fitBounds(tileBoundaryLayer.getBounds());
- addedTiles.add(key);
- setAddedTiles(addedTiles);
- }
-}
+// if (!addedTiles.has(key)) {
+// console.log("Key doesn't present in map");
+// const bounds = tile2boundingbox(tileX, tileY, zoom);
+// tileBoundaryLayer = L.rectangle(bounds, {
+// color: "yellow",
+// fill: false,
+// pmIgnore: true,
+// });
+// tileBoundaryLayer.name = "Tile Box";
+// mapref.addLayer(tileBoundaryLayer);
+// mapref.fitBounds(tileBoundaryLayer.getBounds());
+// addedTiles.add(key);
+// setAddedTiles(addedTiles);
+// }
+// }
function getFeatureStyle(feature) {
let color = "red";
@@ -84,6 +88,10 @@ const EditableGeoJSON = ({
setModifiedCount,
setDeletedCount,
tileBoundaryLayer,
+ modelId,
+ trainingId,
+ sourceImagery,
+ refestchFeeedback,
}) => {
const onPMCreate = (event) => {
console.log("Created");
@@ -109,86 +117,131 @@ const EditableGeoJSON = ({
corner.lng,
predictionZoomlevel
);
- addTileBoundaryLayer(
- mapref,
- addedTiles,
- tileX,
- tileY,
- predictionZoomlevel,
- setAddedTiles
- );
+ // addTileBoundaryLayer(
+ // mapref,
+ // addedTiles,
+ // tileX,
+ // tileY,
+ // predictionZoomlevel,
+ // setAddedTiles
+ // );
}
mapref.removeLayer(createdLayer);
};
+ const { accessToken } = useContext(AuthContext);
+
+ const submitFeedback = async (layer) => {
+ try {
+ // console.log("layer", layer);
+ const newAOI = {
+ id: Math.random(),
+ latlngs: layer.getLatLngs()[0],
+ };
+ const points = JSON.stringify(
+ converToGeoPolygon([newAOI])[0][0].reduce(
+ (p, c, i) => p + c[1] + " " + c[0] + ",",
+ ""
+ )
+ ).slice(1, -2);
+
+ const polygon = "SRID=4326;POLYGON((" + points + "))";
+
+ let body = {
+ geom: polygon,
+ zoom_level: predictionZoomlevel,
+ feedback_type: "TN",
+ source_imagery: sourceImagery,
+ training: trainingId,
+ comments: "comments is not support yet",
+ };
+
+ const headers = {
+ "access-token": accessToken,
+ };
+ const res = await axios.post(`/feedback/`, body, { headers });
+ console.log("res ", res);
+ refestchFeeedback();
+ } catch (error) {
+ console.log("Error in submitting feedback", error);
+ } finally {
+ }
+ };
+ const { mutate: mutateSubmitFeedback } = useMutation(submitFeedback);
+
const onEachFeature = (feature, layer) => {
- layer.on({
- "pm:update": (event) => {
- const bounds = event.layer.getBounds();
- const corners = [bounds.getSouthWest(), bounds.getNorthEast()];
+ // layer.on({
+ // "pm:update": (event) => {
+ // const bounds = event.layer.getBounds();
+ // const corners = [bounds.getSouthWest(), bounds.getNorthEast()];
- for (const corner of corners) {
- const [tileX, tileY] = deg2tile(
- corner.lat,
- corner.lng,
- predictionZoomlevel
- );
- addTileBoundaryLayer(
- mapref,
- addedTiles,
- tileX,
- tileY,
- predictionZoomlevel,
- setAddedTiles
- );
- }
+ // for (const corner of corners) {
+ // const [tileX, tileY] = deg2tile(
+ // corner.lat,
+ // corner.lng,
+ // predictionZoomlevel
+ // );
+ // // addTileBoundaryLayer(
+ // // mapref,
+ // // addedTiles,
+ // // tileX,
+ // // tileY,
+ // // predictionZoomlevel,
+ // // setAddedTiles
+ // // );
+ // }
- const editedLayer = event.target;
- const editedData = editedLayer.toGeoJSON();
- const editedFeatureIndex = data.features.findIndex(
- (feature) => feature.id === editedData.id
- );
- const newData = { ...data };
- newData.features[editedFeatureIndex] = editedData;
- setPredictions(newData);
- if (feature.properties.action !== "MODIFY") {
- feature.properties.action = "MODIFY";
- setModifiedCount((prevCount) => prevCount + 1);
- }
- },
- "pm:remove": (event) => {
- const bounds = event.layer.getBounds();
- const corners = [bounds.getSouthWest(), bounds.getNorthEast()];
+ // const editedLayer = event.target;
+ // const editedData = editedLayer.toGeoJSON();
+ // const editedFeatureIndex = data.features.findIndex(
+ // (feature) => feature.id === editedData.id
+ // );
+ // const newData = { ...data };
+ // newData.features[editedFeatureIndex] = editedData;
+ // setPredictions(newData);
+ // if (feature.properties.action !== "MODIFY") {
+ // feature.properties.action = "MODIFY";
+ // setModifiedCount((prevCount) => prevCount + 1);
+ // }
+ // },
+ // "pm:remove": (event) => {
+ // const bounds = event.layer.getBounds();
+ // const corners = [bounds.getSouthWest(), bounds.getNorthEast()];
- for (const corner of corners) {
- const [tileX, tileY] = deg2tile(
- corner.lat,
- corner.lng,
- predictionZoomlevel
- );
- addTileBoundaryLayer(
- mapref,
- addedTiles,
- tileX,
- tileY,
- predictionZoomlevel,
- setAddedTiles
- );
- }
- const deletedLayer = event.layer;
- const newFeatures = data.features.filter(
- (feature) =>
- feature.properties.id !== deletedLayer.feature.properties.id
- );
- setPredictions({ ...data, features: newFeatures });
- setDeletedCount((prevCount) => prevCount + 1);
- },
- });
+ // for (const corner of corners) {
+ // const [tileX, tileY] = deg2tile(
+ // corner.lat,
+ // corner.lng,
+ // predictionZoomlevel
+ // );
+ // // addTileBoundaryLayer(
+ // // mapref,
+ // // addedTiles,
+ // // tileX,
+ // // tileY,
+ // // predictionZoomlevel,
+ // // setAddedTiles
+ // // );
+ // }
+ // const deletedLayer = event.layer;
+ // const newFeatures = data.features.filter(
+ // (feature) =>
+ // feature.properties.id !== deletedLayer.feature.properties.id
+ // );
+ // setPredictions({ ...data, features: newFeatures });
+ // setDeletedCount((prevCount) => prevCount + 1);
+ // },
+ // });
layer.on("click", (e) => {
console.log(e);
if (feature.properties.action === "INITIAL") {
const popupContent = `
-
+
+ This feedback will be presented on the model (id: ${modelId}, training id: ${trainingId}) for improvements
+
+
Comments:
+
+
`;
const popup = L.popup()
@@ -200,23 +253,10 @@ const EditableGeoJSON = ({
.querySelector("#rightButton")
.addEventListener("click", () => {
feature.properties.action = "ACCEPT";
- const bounds = layer.getBounds();
- const corners = [bounds.getSouthWest(), bounds.getNorthEast()];
- for (const corner of corners) {
- const [tileX, tileY] = deg2tile(
- corner.lat,
- corner.lng,
- predictionZoomlevel
- );
- addTileBoundaryLayer(
- mapref,
- addedTiles,
- tileX,
- tileY,
- predictionZoomlevel,
- setAddedTiles
- );
- }
+ console.log("popup layer ", layer);
+ // handle submitting feedback
+ mutateSubmitFeedback(layer);
+ popup.close();
});
}
});
diff --git a/frontend/src/components/Layout/Start/Prediction/Prediction.js b/frontend/src/components/Layout/Start/Prediction/Prediction.js
index 36e7aa7b..cd98a351 100644
--- a/frontend/src/components/Layout/Start/Prediction/Prediction.js
+++ b/frontend/src/components/Layout/Start/Prediction/Prediction.js
@@ -16,7 +16,7 @@ import {
Link,
Select,
} from "@mui/material";
-
+import L from "leaflet";
import React, { useContext, useEffect, useRef, useState } from "react";
import {
FeatureGroup,
@@ -25,7 +25,6 @@ import {
TileLayer,
useMapEvents,
} from "react-leaflet";
-import L from "leaflet";
import { useMutation, useQuery } from "react-query";
import { useNavigate, useParams } from "react-router-dom";
import axios from "../../../../axios";
@@ -56,9 +55,9 @@ const Prediction = () => {
const [apiCallInProgress, setApiCallInProgress] = useState(false);
const [confidence, setConfidence] = useState(90);
const [totalPredictionsCount, settotalPredictionsCount] = useState(0);
- const [DeletedCount, setDeletedCount] = useState(0);
- const [CreatedCount, setCreatedCount] = useState(0);
- const [ModifiedCount, setModifiedCount] = useState(0);
+ // const [DeletedCount, setDeletedCount] = useState(0);
+ // const [CreatedCount, setCreatedCount] = useState(0);
+ // const [ModifiedCount, setModifiedCount] = useState(0);
const [map, setMap] = useState(null);
const [zoom, setZoom] = useState(15);
const [responseTime, setResponseTime] = useState(0);
@@ -232,9 +231,7 @@ const Prediction = () => {
const updatedPredictions = addIdsToPredictions(res.data);
setPredictions(updatedPredictions);
settotalPredictionsCount(updatedPredictions.features.length);
- setCreatedCount(0);
- setModifiedCount(0);
- setDeletedCount(0);
+
if (addedTiles.size > 0) {
console.log("Map has tileboundarylayer");
}
@@ -359,7 +356,37 @@ const Prediction = () => {
return { ...predictions, features };
}
const navigate = useNavigate();
+ const getFeedback = async (trainingId) => {
+ if (!modelInfo || !modelInfo.trainingId) return;
+ try {
+ const headers = {
+ "access-token": accessToken,
+ };
+ const res = await axios.get(
+ `/feedback/?training=${modelInfo.trainingId}`,
+ null,
+ {
+ headers,
+ }
+ );
+ if (res.error) {
+ } else {
+ console.log("getFeedback ", res.data);
+ return res.data;
+ }
+ } catch (e) {
+ console.log("isError", e);
+ } finally {
+ }
+ };
+ const { data: feedbackData, refetch: refetchFeedback } = useQuery(
+ "getfeedback" + (modelInfo && modelInfo.trainingId),
+ getFeedback,
+ {
+ refetchInterval: 120000,
+ }
+ );
return (
<>
@@ -386,18 +413,24 @@ const Prediction = () => {
)}
- {predictions && (
+ {predictions && dataset && (
{
+ refetchFeedback();
+ }}
/>
)}
@@ -453,48 +486,22 @@ const Prediction = () => {
Response: {responseTime} sec
- {predictions && (
-
-
- Feedback
-
+
+
+
+ Feedback
+
+
+ Initial Predictions:
+ {totalPredictionsCount}
+
+ {feedbackData && feedbackData.features && (
- Initial Predictions:
- {totalPredictionsCount}
+ Total feedbacks count:{feedbackData.features.length}
- {CreatedCount > 0 && (
-
- Total Created:
- {CreatedCount}
-
- )}
- {ModifiedCount > 0 && (
-
- Total Modified:
- {ModifiedCount}
-
- )}
- {DeletedCount > 0 && (
-
- Total Deleted:
- {DeletedCount}
-
- )}
- {CreatedCount + ModifiedCount + DeletedCount > 1 &&
- !feedbackSubmitted && (
-
- Submit my feedback
-
- )}
-
- )}
+ )}
+
+
{loading ? (
@@ -505,17 +512,19 @@ const Prediction = () => {
Loaded Model
-
- {
- e.preventDefault();
- navigate("/ai-models/" + modelInfo.id);
- }}
- color="inherit"
- >
- ID: {modelInfo.id}
-
+
+
+ {
+ e.preventDefault();
+ navigate("/ai-models/" + modelInfo.id);
+ }}
+ color="inherit"
+ >
+ ID: {modelInfo.id}
+
+
Name: {modelInfo.name}
diff --git a/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOI.js b/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOI.js
index 7ca4bc55..b5b7b911 100644
--- a/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOI.js
+++ b/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOI.js
@@ -150,7 +150,7 @@ const AOI = (props) => {
// mutateFetch(layer.aoiId);
// console.log("Open in Editor")
window.open(
- `https://mapwith.ai/rapid#background=${
+ `https://rapideditor.org/rapid#background=${
props.oamImagery
? "custom:" + props.oamImagery.url
: "Bing"
@@ -166,7 +166,7 @@ const AOI = (props) => {
diff --git a/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOIDetails.js b/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOIDetails.js
index 37add50d..3d558995 100644
--- a/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOIDetails.js
+++ b/frontend/src/components/Layout/TrainingDS/DatasetEditor/AOIDetails.js
@@ -1,47 +1,50 @@
-import { Typography } from '@material-ui/core';
-import React from 'react'
-import { useQuery } from 'react-query';
+import { Typography } from "@material-ui/core";
+import React from "react";
+import { useQuery } from "react-query";
-import axios from '../../../../axios'
+import axios from "../../../../axios";
-import {timeSince,aoiStatusText} from '../../../../utils'
-const AOIDetails = props =>
-{
+import { timeSince, aoiStatusText } from "../../../../utils";
+const AOIDetails = (props) => {
+ // console.log("rendering AOIDetails",props)
+ const fetchAOI = async () => {
+ try {
+ const res = await axios.get(`/aoi/${props.aoiId}/`);
- // console.log("rendering AOIDetails",props)
- const fetchAOI = async () => {
+ if (res.error) {
+ // setMapError(res.error.response.statusText);
+ console.log(res.error.response.statusText);
+ } else {
+ // success full fetch
+ // console.log("API details, ",props.aoiId,res.data);
+ return res.data;
+ }
+ } catch (e) {
+ console.log("isError", e);
+ } finally {
+ }
+ };
+ const { data } = useQuery("fetchAOI" + props.aoiId, fetchAOI, {
+ refetchInterval: 5000,
+ });
- try {
-
-
- const res = await axios.get(`/aoi/${props.aoiId}/`);
-
- if (res.error){
- // setMapError(res.error.response.statusText);
- console.log(res.error.response.statusText);
- }
- else
- {
-
- // success full fetch
- // console.log("API details, ",props.aoiId,res.data);
- return res.data;
- }
-
- } catch (e) {
- console.log("isError",e);
-
- } finally {
-
- }
- };
- const { data } = useQuery("fetchAOI" + props.aoiId,fetchAOI,{refetchInterval:5000});
-
- return <>
- {data &&
- {aoiStatusText(data.properties.download_status)} {data.properties.last_fetched_date && timeSince(new Date(data.properties.last_fetched_date),new Date()) }
- }
+ return (
+ <>
+ {data && (
+
+ {aoiStatusText(data.properties.label_status)}{" "}
+ {data.properties.label_fetched &&
+ timeSince(new Date(data.properties.label_fetched), new Date())}
+
+ )}
>
-}
+ );
+};
-export default AOIDetails
\ No newline at end of file
+export default AOIDetails;
diff --git a/frontend/src/components/Layout/TrainingDS/DatasetEditor/DatasetMap.js b/frontend/src/components/Layout/TrainingDS/DatasetEditor/DatasetMap.js
index db432b65..11ce4017 100644
--- a/frontend/src/components/Layout/TrainingDS/DatasetEditor/DatasetMap.js
+++ b/frontend/src/components/Layout/TrainingDS/DatasetEditor/DatasetMap.js
@@ -23,7 +23,11 @@ import { multiPolygon } from "@turf/helpers";
import axios from "../../../../axios";
-import { approximateGeom } from "../../../../utils";
+import {
+ approximateGeom,
+ converToGeoPolygon,
+ converToPolygon,
+} from "../../../../utils";
import DatasetEditorHeader from "./DatasetEditorHeader";
import AuthContext from "../../../../Context/AuthContext";
const DatasetMap = (props) => {
@@ -415,29 +419,6 @@ const DatasetMap = (props) => {
const _onEditStop = (e) => {
setIsEditing(false);
};
- const converToPolygon = (layer) => {
- const allPoly = [];
- layer.forEach((element) => {
- const x = element.latlngs.map((e) => [e.lat, e.lng]);
- allPoly.push([x]);
- });
- return allPoly;
- };
-
- const converToGeoPolygon = (layer) => {
- if (layer.length === 0) return [];
- const allPoly = converToPolygon(layer);
-
- // console.log("converToGeoPolygon",allPoly)
-
- const newAll = [];
- allPoly.forEach((element) => {
- const x = [...element[0], element[0][0]];
-
- newAll.push([x]);
- });
- return newAll;
- };
const blueOptions = { color: "#03002e", width: 10, opacity: 1 };
diff --git a/frontend/src/utils.js b/frontend/src/utils.js
index 281356a0..f9a2b5c3 100644
--- a/frontend/src/utils.js
+++ b/frontend/src/utils.js
@@ -3,7 +3,7 @@ export const timeSince = (when, then) => {
const seconds = (then.getTime() - when.getTime()) / 1000;
if (seconds > 86400 * 30)
- return " +" + ((seconds / (86400 * 30))).toFixed() + " month(s) ago";
+ return " +" + (seconds / (86400 * 30)).toFixed() + " month(s) ago";
if (seconds > 604800)
return " +" + (seconds / 604800).toFixed() + " week(s) ago";
if (seconds > 86400)
@@ -164,4 +164,28 @@ export const timeSpan = (start, end) => {
const delta = e - s;
return (Math.abs(delta) / 36e5).toFixed(2);
} else return "";
-};
\ No newline at end of file
+};
+
+export const converToPolygon = (layer) => {
+ const allPoly = [];
+ layer.forEach((element) => {
+ const x = element.latlngs.map((e) => [e.lat, e.lng]);
+ allPoly.push([x]);
+ });
+ return allPoly;
+};
+
+export const converToGeoPolygon = (layer) => {
+ if (layer.length === 0) return [];
+ const allPoly = converToPolygon(layer);
+
+ // console.log("converToGeoPolygon",allPoly)
+
+ const newAll = [];
+ allPoly.forEach((element) => {
+ const x = [...element[0], element[0][0]];
+
+ newAll.push([x]);
+ });
+ return newAll;
+};