Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
# * OSMOSE_DB_USER : DB user (ex: osmose)
# * OSMOSE_DB_PWD : DB password
# * OSMOSE_DB_BASE : DB Aplose dedicated database name (ex: osmose)
# * OSMOSE_PROXY_URL : Proxy host:port if needed (ex: proxy-wiz.osmose.fr:3128)
# * Exposed port: 8000
# * Folder dedicated to "datawork" mount: /opt/datawork
# * Folder dedicated to server static files mount: /opt/staticfiles
Expand Down
123 changes: 116 additions & 7 deletions backend/api/models/data/spectrogram.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,23 @@
"""Spectrogram model"""
import csv
from datetime import datetime, timedelta
from os import path
from os.path import join
from pathlib import Path
from pathlib import Path, PureWindowsPath

from django.conf import settings
from django.db import models
from django.db.models import Q, F, QuerySet
from django.utils import timezone
from metadatax.data.models import FileFormat
from osekit.config import TIMESTAMP_FORMAT_EXPORTED_FILES_LOCALIZED

# from osekit.core_api.spectro_data import SpectroData
# from osekit.core_api.spectro_dataset import SpectroDataset
from backend.utils.osekit_replace import SpectroDataset, SpectroData
from osekit.core_api.audio_data import AudioData
from osekit.core_api.audio_file import AudioFile
from osekit.core_api.spectro_data import SpectroData
from osekit.core_api.spectro_dataset import SpectroDataset
from pandas import Timestamp
from scipy.signal import ShortTimeFFT
from scipy.signal.windows import hamming

from .__abstract_file import AbstractFile
from .__abstract_time_segment import TimeSegment
Expand Down Expand Up @@ -157,6 +162,110 @@ def __str__(self):

analysis = models.ManyToManyField(SpectrogramAnalysis, related_name="spectrograms")

def get_audio_path(self, analysis: SpectrogramAnalysis) -> str:
if analysis.dataset.legacy:
folders = PureWindowsPath(analysis.path).as_posix().split("/")
folders.pop()
return path.join(
analysis.dataset.path.split(
settings.DATASET_EXPORT_PATH.stem + "/"
).pop(),
PureWindowsPath(settings.DATASET_FILES_FOLDER),
PureWindowsPath(folders.pop()),
PureWindowsPath(f"{self.filename}.wav"),
)
else:
spectro_data: SpectroData = self.get_spectro_data_for(analysis)
audio_files = list(spectro_data.audio_data.files)
if len(audio_files) != 1:
return None

audio_file = audio_files[0]
if audio_file.begin != (
self.start if audio_file.begin.tz else timezone.make_naive(self.start)
):
return None
if audio_file.end < (
self.end if audio_file.end.tz else timezone.make_naive(self.end)
):
return None

audio_path = str(audio_file.path)
return (
audio_path.split(str(settings.DATASET_EXPORT_PATH)).pop().lstrip("\\")
)

def get_base_spectro_path(self, analysis: SpectrogramAnalysis) -> str:
if analysis.dataset.legacy:
return path.join(
PureWindowsPath(
analysis.dataset.path.split(
settings.DATASET_EXPORT_PATH.stem + "/"
).pop()
),
PureWindowsPath(analysis.path),
PureWindowsPath("image"),
PureWindowsPath(f"{self.filename}.{self.format.name}"),
)
else:
spectro_dataset: SpectroDataset = analysis.get_osekit_spectro_dataset()
spectro_dataset_path = str(spectro_dataset.folder).split(
str(settings.DATASET_EXPORT_PATH)
)[1]
return path.join(
PureWindowsPath(spectro_dataset_path),
PureWindowsPath("spectrogram"), # TODO: avoid static path parts!!!
PureWindowsPath(f"{self.filename}.{self.format.name}"),
).lstrip("\\")

def get_spectro_data_for(self, analysis: SpectrogramAnalysis) -> SpectroData:
spectro_dataset: SpectroDataset = analysis.get_osekit_spectro_dataset()
return [d for d in spectro_dataset.data if d.name == self.filename].pop()
if analysis.legacy:
audio_path = Path(
join(
settings.VOLUMES_ROOT,
settings.DATASET_EXPORT_PATH,
self.get_audio_path(analysis),
)
)
audio_file = AudioFile(
path=audio_path,
begin=Timestamp.fromisoformat(self.start.isoformat()),
)
audio_data = AudioData.from_files([audio_file])
overlap = analysis.fft.overlap or 0.95
hop = round(analysis.fft.window_size * (1 - overlap))
return SpectroData.from_audio_data(
data=audio_data,
fft=ShortTimeFFT(
win=hamming(analysis.fft.window_size),
hop=hop,
fs=analysis.fft.sampling_frequency,
scale_to="magnitude",
),
colormap="viridis", # This is the default value
)
else:
spectro_dataset: SpectroDataset = analysis.get_osekit_spectro_dataset()
return [d for d in spectro_dataset.data if d.name == self.filename].pop()

def get_audio_data_for(self, analysis: SpectrogramAnalysis) -> AudioData:
if analysis.legacy:
audio_path = Path(
join(
settings.VOLUMES_ROOT,
settings.DATASET_EXPORT_PATH,
self.get_audio_path(analysis),
)
)
audio_file = AudioFile(
path=audio_path,
begin=Timestamp.fromisoformat(self.start.isoformat()),
)
return AudioData.from_files([audio_file])
else:
spectro_dataset: SpectroDataset = analysis.get_osekit_spectro_dataset()
return (
[d for d in spectro_dataset.data if d.name == self.filename]
.pop()
.audio_data
)
4 changes: 2 additions & 2 deletions backend/api/models/data/spectrogram_analysis.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@

from backend.aplose.models import User

# from osekit.core_api.spectro_dataset import SpectroDataset
from backend.utils.osekit_replace import SpectroDataset
from osekit.core_api.spectro_dataset import SpectroDataset

from .__abstract_analysis import AbstractAnalysis
from .colormap import Colormap
from .dataset import Dataset
Expand Down
65 changes: 2 additions & 63 deletions backend/api/schema/nodes/annotation_spectrogram.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,11 @@
import graphene
import graphene_django_optimizer
from django.conf import settings
from django.utils import timezone
from django_extension.schema.errors import NotFoundError
from django_extension.schema.fields import AuthenticatedPaginationConnectionField
from django_extension.schema.types import ExtendedNode
from graphql import GraphQLResolveInfo

# from osekit.core_api.spectro_data import SpectroData
# from osekit.core_api.spectro_dataset import SpectroDataset
from backend.utils.osekit_replace import SpectroDataset, SpectroData

from backend.api.models import (
Spectrogram,
AnnotationCampaign,
Expand Down Expand Up @@ -102,77 +97,21 @@ def resolve_is_assigned(
@graphene_django_optimizer.resolver_hints()
def resolve_audio_path(self: Spectrogram, info, analysis_id: int):
analysis: SpectrogramAnalysis = self.analysis.get(id=analysis_id)

audio_path: str
if analysis.dataset.legacy:
folders = PureWindowsPath(analysis.path).as_posix().split("/")
folders.pop()
audio_path = path.join(
analysis.dataset.path.split(
settings.DATASET_EXPORT_PATH.stem + "/"
).pop(),
PureWindowsPath(settings.DATASET_FILES_FOLDER),
PureWindowsPath(folders.pop()),
PureWindowsPath(f"{self.filename}.wav"),
)
else:
spectro_data: SpectroData = self.get_spectro_data_for(analysis)
audio_files = list(spectro_data.audio_data.files)
if len(audio_files) != 1:
return None

audio_file = audio_files[0]
if audio_file.begin != (
self.start if audio_file.begin.tz else timezone.make_naive(self.start)
):
return None
if audio_file.end < (
self.end if audio_file.end.tz else timezone.make_naive(self.end)
):
return None

audio_path = str(audio_file.path)
audio_path = (
audio_path.split(str(settings.DATASET_EXPORT_PATH)).pop().lstrip("\\")
)
return path.join(
PureWindowsPath(settings.STATIC_URL),
PureWindowsPath(settings.DATASET_EXPORT_PATH),
PureWindowsPath(audio_path),
PureWindowsPath(self.get_audio_path(analysis)),
)

path = graphene.String(analysis_id=graphene.ID(required=True), required=True)

@graphene_django_optimizer.resolver_hints()
def resolve_path(self: Spectrogram, info, analysis_id: int):
analysis: SpectrogramAnalysis = self.analysis.get(id=analysis_id)

spectrogram_path: str
if analysis.dataset.legacy:
spectrogram_path = path.join(
PureWindowsPath(
analysis.dataset.path.split(
settings.DATASET_EXPORT_PATH.stem + "/"
).pop()
),
PureWindowsPath(analysis.path),
PureWindowsPath("image"),
PureWindowsPath(f"{self.filename}.{self.format.name}"),
)
else:
spectro_dataset: SpectroDataset = analysis.get_osekit_spectro_dataset()
spectro_dataset_path = str(spectro_dataset.folder).split(
str(settings.DATASET_EXPORT_PATH)
)[1]
spectrogram_path = path.join(
PureWindowsPath(spectro_dataset_path),
PureWindowsPath("spectrogram"), # TODO: avoid static path parts!!!
PureWindowsPath(f"{self.filename}.{self.format.name}"),
).lstrip("\\")
return path.join(
PureWindowsPath(settings.STATIC_URL),
PureWindowsPath(settings.DATASET_EXPORT_PATH),
PureWindowsPath(spectrogram_path),
PureWindowsPath(self.get_base_spectro_path(analysis)),
)

task = graphene.Field(
Expand Down
4 changes: 4 additions & 0 deletions backend/api/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,12 @@
AnnotationViewSet,
DownloadViewSet,
)
from backend.api.views.zoom import ZoomViewSet

# API urls are meant to be used by our React frontend
api_router = routers.DefaultRouter()
api_router.register(r"annotation", AnnotationViewSet, basename="annotation")
api_router.register("download", DownloadViewSet, basename="download")


api_router.register("data", ZoomViewSet, basename="data-zoom")
Loading