Skip to content

Commit

Permalink
adding file annotation to main recording view
Browse files Browse the repository at this point in the history
  • Loading branch information
BryonLewis committed Dec 9, 2024
1 parent 847663d commit b85b864
Show file tree
Hide file tree
Showing 6 changed files with 203 additions and 35 deletions.
35 changes: 26 additions & 9 deletions bats_ai/core/views/recording.py
Original file line number Diff line number Diff line change
Expand Up @@ -253,9 +253,12 @@ def get_recordings(request: HttpRequest, public: bool | None = None):
.count()
)
recording['userAnnotations'] = unique_users_with_annotations
user_has_annotations = Annotations.objects.filter(
recording_id=recording['id'], owner=request.user
).exists()
user_has_annotations = (
Annotations.objects.filter(recording_id=recording['id'], owner=request.user).exists()
or RecordingAnnotation.objects.filter(
recording_id=recording['id'], owner=request.user
).exists()
)
recording['userMadeAnnotations'] = user_has_annotations

return list(recordings)
Expand All @@ -275,16 +278,30 @@ def get_recording(request: HttpRequest, id: int):
recording['hasSpectrogram'] = Recording.objects.get(id=recording['id']).has_spectrogram
if recording['recording_location']:
recording['recording_location'] = json.loads(recording['recording_location'].json)
unique_users_with_annotations = (
annotation_owners = (
Annotations.objects.filter(recording_id=recording['id'])
.values('owner')
.values_list('owner', flat=True)
.distinct()
)
recording_annotation_owners = (
RecordingAnnotation.objects.filter(recording_id=recording['id'])
.values_list('owner', flat=True)
.distinct()
.count()
)

# Combine the sets of owners and count unique entries
unique_users_with_annotations = len(
set(annotation_owners).union(set(recording_annotation_owners))
)
recording['userAnnotations'] = unique_users_with_annotations
user_has_annotations = Annotations.objects.filter(
recording_id=recording['id'], owner=request.user
).exists()
user_has_annotations = (
Annotations.objects.filter(
recording_id=recording['id'], owner=request.user
).exists()
or RecordingAnnotation.objects.filter(
recording_id=recording['id'], owner=request.user
).exists()
)
recording['userMadeAnnotations'] = user_has_annotations
fileAnnotations = RecordingAnnotation.objects.filter(recording=id).order_by(
'confidence'
Expand Down
2 changes: 1 addition & 1 deletion bats_ai/core/views/recording_annotation.py
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ def update_recording_annotation(
annotation = RecordingAnnotation.objects.get(pk=id)

# Check permission
if annotation.recording.owner != request.user:
if annotation.recording.owner != request.user and not annotation.recording.public:
raise HttpError(403, 'Permission denied.')

# Update fields if provided
Expand Down
1 change: 1 addition & 0 deletions client/src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ export interface Recording {
userMadeAnnotations: boolean;
userAnnotations: number;
hasSpectrogram: boolean;
fileAnnotations: FileAnnotation[];
site_name?: string;
software?: string;
detector?: string;
Expand Down
57 changes: 42 additions & 15 deletions client/src/components/AnnotationList.vue
Original file line number Diff line number Diff line change
Expand Up @@ -89,24 +89,51 @@ export default defineComponent({
class="ma-auto"
@update:model-value="tabSwitch($event)"
>
<v-tab
value="recording"
size="x-small"
<v-tooltip
location="bottom"
open-delay="400"
>
Recording
</v-tab>
<v-tab
value="pulse"
size="x-small"
<template #activator="{ props }">
<v-tab
value="recording"
size="x-small"
v-bind="props"
>
Recording
</v-tab>
</template>
<span>Recording/File Level Species Annotations</span>
</v-tooltip>
<v-tooltip
location="bottom"
open-delay="400"
>
Pulse
</v-tab>
<v-tab
value="sequence"
size="x-small"
<template #activator="{ props }">
<v-tab
value="sequence"
size="x-small"
v-bind="props"
>
Sequence
</v-tab>
</template>
<span>Sequence Level annotations (Approach/Search/Terminal/Social)</span>
</v-tooltip>
<v-tooltip
location="bottom"
open-delay="400"
>
Sequence
</v-tab>
<template #activator="{ props }">
<v-tab
value="pulse"
size="x-small"
v-bind="props"
>
Pulse
</v-tab>
</template>
<span>Pulse Level Annotations (for a single pulse)</span>
</v-tooltip>
</v-tabs>
</v-row>
<v-window v-model="tab">
Expand Down
108 changes: 108 additions & 0 deletions client/src/components/RecordingAnnotationSummary.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
<script lang="ts">
import { defineComponent, onMounted, PropType, Ref } from "vue";

Check warning on line 2 in client/src/components/RecordingAnnotationSummary.vue

View workflow job for this annotation

GitHub Actions / Lint [eslint]

'onMounted' is defined but never used

Check warning on line 2 in client/src/components/RecordingAnnotationSummary.vue

View workflow job for this annotation

GitHub Actions / Lint [eslint]

'Ref' is defined but never used
import { SpectroInfo } from './geoJS/geoJSUtils';
import useState from "../use/useState";
import { watch, ref } from "vue";
import AnnotationEditor from "./AnnotationEditor.vue";
import { FileAnnotation, getFileAnnotations, putFileAnnotation, Species, SpectrogramAnnotation, SpectrogramTemporalAnnotation, UpdateFileAnnotation } from "../api/api";
import RecordingAnnotationEditor from "./RecordingAnnotationEditor.vue";
export default defineComponent({
name: "AnnotationList",
components: {
RecordingAnnotationEditor,

Check failure on line 12 in client/src/components/RecordingAnnotationSummary.vue

View workflow job for this annotation

GitHub Actions / Lint [eslint]

The "RecordingAnnotationEditor" component has been registered but not used
},
props: {
fileAnnotations: {
type: Array as PropType<FileAnnotation[]>,
required: true,
},
},
emits: [],
setup(props) {
return {
};
},
});
</script>

<template>
<v-tooltip
v-if="fileAnnotations.length"
min-width="500"
>
<template #activator="{ props: subProps }">
<span>{{ fileAnnotations.length }} Annotations <v-icon v-bind="subProps">mdi-information-outline</v-icon></span>
</template>
<v-card>
<v-list>
<v-list-item
v-for="annotation in fileAnnotations"
:key="`${annotation.id}`"
class="annotation-item "
>
<v-row>
<v-col class="annotation-owner">
<span>{{ annotation.owner }}</span>
</v-col>
<v-col class="annotation-confidence">
<span>{{ annotation.confidence }} </span>
</v-col>
<v-col class="annotation-model">
<span>{{ annotation.model }} </span>
</v-col>
</v-row>
<v-row
v-for="item in annotation.species"
:key="`${annotation.id}_${item.common_name}`"
class="ma-0 pa-0"
>
<v-col class="ma-0 pa-0">
<div class="species-name">
{{ item.species_code || item.common_name }}
</div>
<div
v-if="item.family"
class="species-hierarchy"
>
<span> {{ item.family }}</span>
<span v-if="item.genus">-></span>
<span v-if="item.genus">{{ item.genus }}</span>
</div>
</v-col>
</v-row>
</v-list-item>
</v-list>
</v-card>
</v-tooltip>
<span v-else>
None
</span>
</template>

<style lang="scss" scoped>
.annotation-owner {
font-size: 1em;
}
.annotation-confidence {
font-size: 1em;
}
.annotation-model {
font-size: 1em;
}
.annotation-item {
border: 1px solid gray;
}
.species-name {
font-weight: bold;
font-size: 1em;
}
.species-hierarchy {
font-size: 0.75em;
}
</style>
35 changes: 25 additions & 10 deletions client/src/views/Recordings.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import MapLocation from '../components/MapLocation.vue';
import useState from '../use/useState';
import BatchUploadRecording from '../components/BatchUploadRecording.vue';
import RecordingInfoDisplay from '../components/RecordingInfoDisplay.vue';
import RecordingAnnotationSummary from '../components/RecordingAnnotationSummary.vue';
export default defineComponent({
components: {
UploadRecording,
MapLocation,
BatchUploadRecording,
RecordingInfoDisplay
RecordingInfoDisplay,
RecordingAnnotationSummary,
},
setup() {
const itemsPerPage = ref(-1);
Expand All @@ -26,11 +28,14 @@ export default defineComponent({
title:'Edit',
key:'edit',
},
{
title:'Name',
key:'name',
},
{
title: 'Annotation',
key:'annotation'
},
{
title:'Owner',
key:'owner_username',
Expand All @@ -39,10 +44,6 @@ export default defineComponent({
title:'Recorded Date',
key:'recorded_date',
},
{
title:'Recorded Time',
key:'recorded_time',
},
{
title:'Public',
key:'public',
Expand Down Expand Up @@ -71,6 +72,10 @@ export default defineComponent({
title:'Name',
key:'name',
},
{
title: 'Annotation',
key:'annotation'
},
{
title:'Owner',
key:'owner_username',
Expand All @@ -79,10 +84,6 @@ export default defineComponent({
title:'Recorded Date',
key:'recorded_date',
},
{
title:'Recorded Time',
key:'recorded_time',
},
{
title:'Public',
key:'public',
Expand Down Expand Up @@ -251,6 +252,14 @@ export default defineComponent({
</v-tooltip>
</div>
</template>
<template #item.annotation="{ item }">
<RecordingAnnotationSummary :file-annotations="item.fileAnnotations" />
</template>

<template #item.recorded_date="{ item }">
{{ item.recorded_date }} {{ item.recorded_time }}
</template>

<template #item.recording_location="{ item }">
<v-menu
v-if="item.recording_location"
Expand Down Expand Up @@ -356,6 +365,12 @@ export default defineComponent({
{{ item.name }}
</router-link>
</template>
<template #item.recorded_date="{ item }">
{{ item.recorded_date }} {{ item.recorded_time }}
</template>
<template #item.annotation="{ item }">
<RecordingAnnotationSummary :file-annotations="item.fileAnnotations" />
</template>
<template #item.public="{ item }">
<v-icon
v-if="item.public"
Expand Down

0 comments on commit b85b864

Please sign in to comment.