From e1e7464bb70f5f5cec526a3420a1682889986f84 Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:44:55 +0530 Subject: [PATCH 01/10] implement websocket connections --- api/api/consumers.py | 22 ++ api/api/routing.py | 7 + api/backend/asgi.py | 13 +- api/backend/settings.py | 9 + client/src/App.tsx | 37 +-- client/src/contexts/WebSocketContext.tsx | 54 +++++ pyproject.toml | 278 ++++++++++++----------- requirements.txt | 15 ++ 8 files changed, 289 insertions(+), 146 deletions(-) create mode 100644 api/api/consumers.py create mode 100644 api/api/routing.py create mode 100644 client/src/contexts/WebSocketContext.tsx diff --git a/api/api/consumers.py b/api/api/consumers.py new file mode 100644 index 0000000..e4a046b --- /dev/null +++ b/api/api/consumers.py @@ -0,0 +1,22 @@ +# api/consumers.py +import json +from channels.generic.websocket import WebsocketConsumer + +class MediaConsumer(WebsocketConsumer): + def connect(self): + self.accept() + self.send(text_data=json.dumps({ + "message": "Connected to WebSocket server!" + })) + + def receive(self, text_data): + data = json.loads(text_data) + message = data.get("message", "") + + if message == "ping": + self.send(text_data=json.dumps({"response": "pong"})) + else: + self.send(text_data=json.dumps({"response": f"Received: {message}"})) + + def disconnect(self, close_code): + print("Disconnected from Websocket") \ No newline at end of file diff --git a/api/api/routing.py b/api/api/routing.py new file mode 100644 index 0000000..4819fc2 --- /dev/null +++ b/api/api/routing.py @@ -0,0 +1,7 @@ +# api/routing.py +from django.urls import path +from . import consumers + +websocket_urlpatterns= [ + path("ws/media/", consumers.MediaConsumer.as_asgi()), +] \ No newline at end of file diff --git a/api/backend/asgi.py b/api/backend/asgi.py index ed01e6a..6fa558d 100644 --- a/api/backend/asgi.py +++ b/api/backend/asgi.py @@ -8,9 +8,18 @@ https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ """ import os - from django.core.asgi import get_asgi_application +from channels.routing import ProtocolTypeRouter, URLRouter +from channels.auth import AuthMiddlewareStack +import api.routing os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings') -application = get_asgi_application() +application = ProtocolTypeRouter({ + "http": get_asgi_application(), + "websocket": AuthMiddlewareStack( + URLRouter( + api.routing.websocket_urlpatterns + ) + ) +}) diff --git a/api/backend/settings.py b/api/backend/settings.py index 0ce5725..02acbd2 100644 --- a/api/backend/settings.py +++ b/api/backend/settings.py @@ -31,6 +31,8 @@ ALLOWED_HOSTS = ['*'] # Application definition INSTALLED_APPS = [ + 'daphne', + 'channels', 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', @@ -72,7 +74,14 @@ TEMPLATES = [ ] WSGI_APPLICATION = 'backend.wsgi.application' +ASGI_APPLICATION = "backend.asgi.application" +# Redis setup for WebSocket communication +CHANNEL_LAYERS = { + "default": { + "BACKEND": "channels.layers.InMemoryChannelLayer" + } +} # Database # https://docs.djangoproject.com/en/5.1/ref/settings/#databases diff --git a/client/src/App.tsx b/client/src/App.tsx index 49f1eb3..d7a4f75 100644 --- a/client/src/App.tsx +++ b/client/src/App.tsx @@ -11,6 +11,7 @@ import { import { Home as HomeIcon } from '@mui/icons-material'; import theme from './theme/theme'; import { MediaProvider } from './contexts/MediaContext'; +import { WebSocketProvider } from './contexts/WebSocketContext'; // Import pages import LandingPage from './Pages/LandingPage'; import UploadPage from './Pages/UploadPage'; @@ -25,24 +26,26 @@ const App: React.FC = () => { - - - - FreqSplit - - - + + + + + FreqSplit + + + - - } /> - } /> - } /> - } /> - } /> - } /> - }/> - - + + } /> + } /> + } /> + } /> + } /> + } /> + }/> + + + ); diff --git a/client/src/contexts/WebSocketContext.tsx b/client/src/contexts/WebSocketContext.tsx new file mode 100644 index 0000000..7f6d1ac --- /dev/null +++ b/client/src/contexts/WebSocketContext.tsx @@ -0,0 +1,54 @@ +import React, { createContext, useContext, useEffect, useState } from "react"; + +const WEBSOCKET_URL = "ws://localhost:8000/ws/media/"; + +interface WebSocketContextType { + socket: WebSocket | null; + isConnected: boolean; +} + +const WebSocketContext = createContext({ + socket: null, + isConnected: false, +}); + +export const WebSocketProvider: React.FC<{ children: React.ReactNode }> = ({ children }) => { + const [socket, setSocket] = useState(null); + const [isConnected, setIsConnected] = useState(false); + + useEffect(() => { + const newSocket = new WebSocket(WEBSOCKET_URL); + + newSocket.onopen = () => { + console.log("Connected to WebSocket!"); + setIsConnected(true); + }; + + newSocket.onclose = () => { + console.warn("Disconnected from WebSocket"); + setIsConnected(false); + }; + + newSocket.onerror = (error) => { + console.error("WebSocket error:", error); + }; + + newSocket.onmessage = (event) => { + console.log("Message from server:", event.data); + }; + + setSocket(newSocket); + + return () => { + newSocket.close(); + }; + }, []); + + return ( + + {children} + + ); +}; + +export const useWebSocket = () => useContext(WebSocketContext); diff --git a/pyproject.toml b/pyproject.toml index 2a3cd4e..2b40929 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -6,133 +6,157 @@ build-backend = "setuptools.build_meta" name = "freqsplit" version = "0.1.0" dependencies = [ - "aiohappyeyeballs==2.4.6", - "aiohttp==3.11.13", - "aiosignal==1.3.2", - "amqp==5.3.1", - "antlr4-python3-runtime==4.9.3", - "appdirs==1.4.4", - "asgiref==3.8.1", - "asteroid==0.7.0", - "asteroid-filterbanks==0.4.0", - "attrs==25.1.0", - "audioread==3.0.1", - "billiard==4.2.1", - "cached-property==2.0.1", - "celery==5.4.0", - "certifi==2025.1.31", - "cffi==1.17.1", - "charset-normalizer==3.4.1", - "click==8.1.8", - "click-didyoumean==0.3.1", - "click-plugins==1.1.1", - "click-repl==0.3.0", - "cloudpickle==3.1.1", - "contourpy==1.3.1", - "cycler==0.12.1", - "decorator==5.2.1", - "DeepFilterLib==0.5.6", - "DeepFilterNet==0.5.6", - "demucs==4.0.1", - "Django==5.1.6", - "django-cors-headers==4.7.0", - "djangorestframework==3.15.2", - "dora_search==0.1.12", - "einops==0.8.1", - "filelock==3.17.0", - "fonttools==4.56.0", - "frozenlist==1.5.0", - "fsspec==2025.2.0", - "huggingface-hub==0.29.1", - "idna==3.10", - "iniconfig==2.0.0", - "Jinja2==3.1.5", - "joblib==1.4.2", - "julius==0.2.7", - "kiwisolver==1.4.8", - "kombu==5.4.2", - "lameenc==1.8.1", - "lazy_loader==0.4", - "librosa==0.10.2.post1", - "lightning-utilities==0.12.0", - "llvmlite==0.44.0", - "loguru==0.7.3", - "MarkupSafe==3.0.2", - "matplotlib==3.10.0", - "mir_eval==0.8.2", - "mpmath==1.3.0", - "msgpack==1.1.0", - "multidict==6.1.0", - "networkx==3.4.2", - "numba==0.61.0", - "numpy==1.26.4", - "nvidia-cublas-cu12==12.4.5.8", - "nvidia-cuda-cupti-cu12==12.4.127", - "nvidia-cuda-nvrtc-cu12==12.4.127", - "nvidia-cuda-runtime-cu12==12.4.127", - "nvidia-cudnn-cu12==9.1.0.70", - "nvidia-cufft-cu12==11.2.1.3", - "nvidia-curand-cu12==10.3.5.147", - "nvidia-cusolver-cu12==11.6.1.9", - "nvidia-cusparse-cu12==12.3.1.170", - "nvidia-cusparselt-cu12==0.6.2", - "nvidia-nccl-cu12==2.21.5", - "nvidia-nvjitlink-cu12==12.4.127", - "nvidia-nvtx-cu12==12.4.127", - "omegaconf==2.3.0", - "openunmix==1.3.0", - "packaging==23.2", - "pandas==2.2.3", - "panns-inference==0.1.1", - "pb-bss-eval==0.0.2", - "pesq==0.0.4", - "pillow==11.1.0", - "platformdirs==4.3.6", - "pluggy==1.5.0", - "pooch==1.8.2", - "prompt_toolkit==3.0.50", - "propcache==0.3.0", - "pycparser==2.22", - "pyparsing==3.2.1", - "pystoi==0.4.1", - "pytest==8.3.4", - "python-dateutil==2.9.0.post0", - "pytorch-lightning==2.5.0.post0", - "pytorch-ranger==0.1.1", - "pytz==2025.1", - "PyYAML==6.0.2", - "redis==5.2.1", - "regex==2024.11.6", - "requests==2.32.3", - "retrying==1.3.4", - "safetensors==0.5.3", - "scikit-learn==1.6.1", - "scipy==1.15.2", - "setuptools==75.8.1", - "six==1.17.0", - "soundfile==0.13.1", - "soxr==0.5.0.post1", - "sqlparse==0.5.3", - "submitit==1.5.2", - "sympy==1.13.1", - "threadpoolctl==3.5.0", - "tokenizers==0.21.0", - "torch==2.6.0", - "torch-optimizer==0.1.0", - "torch-stoi==0.2.3", - "torchaudio==2.6.0", - "torchlibrosa==0.1.0", - "torchmetrics==0.11.4", - "tqdm==4.67.1", - "transformers==4.49.0", - "treetable==0.2.5", - "triton==3.2.0", - "typing_extensions==4.12.2", - "tzdata==2025.1", - "urllib3==2.3.0", - "vine==5.1.0", - "wcwidth==0.2.13", - "yarl==1.18.3", + "aiohappyeyeballs" = "2.4.6", + "aiohttp" = "3.11.13", + "aiosignal" = "1.3.2", + "amqp" = "5.3.1", + "antlr4-python3-runtime" = "4.9.3", + "appdirs" = "1.4.4", + "asgiref" = "3.8.1", + "asteroid" = "0.7.0", + "asteroid-filterbanks" = "0.4.0", + "attrs" = "25.1.0", + "audioread" = "3.0.1", + "autobahn" = "24.4.2", + "Automat" = "24.8.1", + "billiard" = "4.2.1", + "cached-property" = "2.0.1", + "celery" = "5.4.0", + "certifi" = "2025.1.31", + "cffi" = "1.17.1", + "channels" = "4.2.0", + "charset-normalizer" = "3.4.1", + "click" = "8.1.8", + "click-didyoumean" = "0.3.1", + "click-plugins" = "1.1.1", + "click-repl" = "0.3.0", + "cloudpickle" = "3.1.1", + "colorama" = "0.4.6", + "constantly" = "23.10.4", + "contourpy" = "1.3.1", + "cors" = "1.0.1", + "cryptography" = "44.0.2", + "cycler" = "0.12.1", + "daphne" = "4.1.2", + "decorator" = "5.2.1", + "DeepFilterLib" = "0.5.6", + "DeepFilterNet" = "0.5.6", + "demucs" = "4.0.1", + "Django" = "5.1.6", + "django-cors-headers" = "4.7.0", + "djangorestframework" = "3.15.2", + "dora_search" = "0.1.12", + "einops" = "0.8.1", + "filelock" = "3.17.0", + "fonttools" = "4.56.0", + "frozenlist" = "1.5.0", + "fsspec" = "2025.2.0", + "future" = "1.0.0", + "gevent" = "24.11.1", + "greenlet" = "3.1.1", + "huggingface-hub" = "0.29.1", + "hyperlink" = "21.0.0", + "idna" = "3.10", + "incremental" = "24.7.2", + "iniconfig" = "2.0.0", + "Jinja2" = "3.1.5", + "joblib" = "1.4.2", + "julius" = "0.2.7", + "kiwisolver" = "1.4.8", + "kombu" = "5.4.2", + "lameenc" = "1.8.1", + "lazy_loader" = "0.4", + "librosa" = "0.10.2.post1", + "lightning-utilities" = "0.12.0", + "llvmlite" = "0.44.0", + "loguru" = "0.7.3", + "MarkupSafe" = "3.0.2", + "matplotlib" = "3.10.0", + "mir_eval" = "0.8.2", + "mpmath" = "1.3.0", + "msgpack" = "1.1.0", + "multidict" = "6.1.0", + "networkx" = "3.4.2", + "numba" = "0.61.0", + "numpy" = "1.26.4", + "nvidia-cublas-cu12" = "12.4.5.8", + "nvidia-cuda-cupti-cu12" = "12.4.127", + "nvidia-cuda-nvrtc-cu12" = "12.4.127", + "nvidia-cuda-runtime-cu12" = "12.4.127", + "nvidia-cudnn-cu12" = "9.1.0.70", + "nvidia-cufft-cu12" = "11.2.1.3", + "nvidia-curand-cu12" = "10.3.5.147", + "nvidia-cusolver-cu12" = "11.6.1.9", + "nvidia-cusparse-cu12" = "12.3.1.170", + "nvidia-cusparselt-cu12" = "0.6.2", + "nvidia-nccl-cu12" = "2.21.5", + "nvidia-nvjitlink-cu12" = "12.4.127", + "nvidia-nvtx-cu12" = "12.4.127", + "omegaconf" = "2.3.0", + "openunmix" = "1.3.0", + "packaging" = "23.2", + "pandas" = "2.2.3", + "panns-inference" = "0.1.1", + "pb-bss-eval" = "0.0.2", + "pesq" = "0.0.4", + "pillow" = "11.1.0", + "platformdirs" = "4.3.6", + "pluggy" = "1.5.0", + "pooch" = "1.8.2", + "prompt_toolkit" = "3.0.50", + "propcache" = "0.3.0", + "pyasn1" = "0.6.1", + "pyasn1_modules" = "0.4.1", + "pycparser" = "2.22", + "pyOpenSSL" = "25.0.0", + "pyparsing" = "3.2.1", + "PySocks" = "1.7.1", + "pystoi" = "0.4.1", + "pytest" = "8.3.4", + "python-dateutil" = "2.9.0.post0", + "pytorch-lightning" = "2.5.0.post0", + "pytorch-ranger" = "0.1.1", + "pytz" = "2025.1", + "PyYAML" = "6.0.2", + "redis" = "5.2.1", + "regex" = "2024.11.6", + "requests" = "2.32.3", + "requests-file" = "2.1.0", + "retrying" = "1.3.4", + "safetensors" = "0.5.3", + "scikit-learn" = "1.6.1", + "scipy" = "1.15.2", + "service-identity" = "24.2.0", + "setuptools" = "75.8.1", + "six" = "1.17.0", + "soundfile" = "0.13.1", + "soxr" = "0.5.0.post1", + "sqlparse" = "0.5.3", + "submitit" = "1.5.2", + "sympy" = "1.13.1", + "threadpoolctl" = "3.5.0", + "tldextract" = "5.1.3", + "tokenizers" = "0.21.0", + "torch" = "2.6.0", + "torch-optimizer" = "0.1.0", + "torch-stoi" = "0.2.3", + "torchaudio" = "2.6.0", + "torchlibrosa" = "0.1.0", + "torchmetrics" = "0.11.4", + "tqdm" = "4.67.1", + "transformers" = "4.49.0", + "treetable" = "0.2.5", + "triton" = "3.2.0", + "Twisted" = "24.11.0", + "txaio" = "23.1.1", + "typing_extensions" = "4.12.2", + "tzdata" = "2025.1", + "urllib3" = "2.3.0", + "vine" = "5.1.0", + "wcwidth" = "0.2.13", + "yarl" = "1.18.3", + "zope.event" = "5.0", + "zope.interface" = "7.2", ] [tool.setuptools] diff --git a/requirements.txt b/requirements.txt index cec5141..e33d7df 100644 --- a/requirements.txt +++ b/requirements.txt @@ -9,11 +9,14 @@ asteroid==0.7.0 asteroid-filterbanks==0.4.0 attrs==25.1.0 audioread==3.0.1 +autobahn==24.4.2 +Automat==24.8.1 billiard==4.2.1 cached-property==2.0.1 celery==5.4.0 certifi==2025.1.31 cffi==1.17.1 +channels==4.2.0 charset-normalizer==3.4.1 click==8.1.8 click-didyoumean==0.3.1 @@ -21,9 +24,12 @@ click-plugins==1.1.1 click-repl==0.3.0 cloudpickle==3.1.1 colorama==0.4.6 +constantly==23.10.4 contourpy==1.3.1 cors==1.0.1 +cryptography==44.0.2 cycler==0.12.1 +daphne==4.1.2 decorator==5.2.1 DeepFilterLib==0.5.6 DeepFilterNet==0.5.6 @@ -35,13 +41,16 @@ dora_search==0.1.12 einops==0.8.1 filelock==3.17.0 fonttools==4.56.0 +-e git+https://github.com/joelmathewthomas/freqsplit@c96b74c463f29fd5f50140701f92f92eb3109a2c#egg=freqsplit frozenlist==1.5.0 fsspec==2025.2.0 future==1.0.0 gevent==24.11.1 greenlet==3.1.1 huggingface-hub==0.29.1 +hyperlink==21.0.0 idna==3.10 +incremental==24.7.2 iniconfig==2.0.0 Jinja2==3.1.5 joblib==1.4.2 @@ -89,7 +98,10 @@ pluggy==1.5.0 pooch==1.8.2 prompt_toolkit==3.0.50 propcache==0.3.0 +pyasn1==0.6.1 +pyasn1_modules==0.4.1 pycparser==2.22 +pyOpenSSL==25.0.0 pyparsing==3.2.1 PySocks==1.7.1 pystoi==0.4.1 @@ -107,6 +119,7 @@ retrying==1.3.4 safetensors==0.5.3 scikit-learn==1.6.1 scipy==1.15.2 +service-identity==24.2.0 setuptools==75.8.1 six==1.17.0 soundfile==0.13.1 @@ -127,6 +140,8 @@ tqdm==4.67.1 transformers==4.49.0 treetable==0.2.5 triton==3.2.0 +Twisted==24.11.0 +txaio==23.1.1 typing_extensions==4.12.2 tzdata==2025.1 urllib3==2.3.0 From 5fba3b42c53729c4c78a2c839eef42b06afc2c50 Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Wed, 19 Mar 2025 23:50:29 +0530 Subject: [PATCH 02/10] change ws url --- api/api/routing.py | 2 +- client/src/contexts/WebSocketContext.tsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/api/api/routing.py b/api/api/routing.py index 4819fc2..dee36fb 100644 --- a/api/api/routing.py +++ b/api/api/routing.py @@ -3,5 +3,5 @@ from django.urls import path from . import consumers websocket_urlpatterns= [ - path("ws/media/", consumers.MediaConsumer.as_asgi()), + path("ws/freqsplit/", consumers.MediaConsumer.as_asgi()), ] \ No newline at end of file diff --git a/client/src/contexts/WebSocketContext.tsx b/client/src/contexts/WebSocketContext.tsx index 7f6d1ac..c345a18 100644 --- a/client/src/contexts/WebSocketContext.tsx +++ b/client/src/contexts/WebSocketContext.tsx @@ -1,6 +1,6 @@ import React, { createContext, useContext, useEffect, useState } from "react"; -const WEBSOCKET_URL = "ws://localhost:8000/ws/media/"; +const WEBSOCKET_URL = "ws://localhost:8000/ws/freqsplit/"; interface WebSocketContextType { socket: WebSocket | null; From 1cb3a1f197d5691ce4e907c318b6bb4c196862fa Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:03:34 +0530 Subject: [PATCH 03/10] send file_uuids to websocket --- api/api/consumers.py | 13 ++++++++++--- client/src/Pages/UploadPage.tsx | 8 ++++++++ 2 files changed, 18 insertions(+), 3 deletions(-) diff --git a/api/api/consumers.py b/api/api/consumers.py index e4a046b..6d5f6ca 100644 --- a/api/api/consumers.py +++ b/api/api/consumers.py @@ -5,6 +5,7 @@ from channels.generic.websocket import WebsocketConsumer class MediaConsumer(WebsocketConsumer): def connect(self): self.accept() + self.file_uuid = [] # List to store file uuids self.send(text_data=json.dumps({ "message": "Connected to WebSocket server!" })) @@ -12,11 +13,17 @@ class MediaConsumer(WebsocketConsumer): def receive(self, text_data): data = json.loads(text_data) message = data.get("message", "") - - if message == "ping": + + # If message contains a file UUID, store it + if "file_uuid" in data: + uuid = data["file_uuid"] + self.file_uuid.append(uuid) + self.send(text_data=json.dumps({"response": f"UUID {uuid} stored."})) + elif message == "ping": self.send(text_data=json.dumps({"response": "pong"})) else: self.send(text_data=json.dumps({"response": f"Received: {message}"})) def disconnect(self, close_code): - print("Disconnected from Websocket") \ No newline at end of file + print("Disconnected from Websocket") + print("Stored file UUIDs:", self.file_uuid) \ No newline at end of file diff --git a/client/src/Pages/UploadPage.tsx b/client/src/Pages/UploadPage.tsx index ed40adc..0dc6379 100644 --- a/client/src/Pages/UploadPage.tsx +++ b/client/src/Pages/UploadPage.tsx @@ -16,12 +16,14 @@ import { Movie as MovieIcon, } from "@mui/icons-material"; import StepperComponent from "../components/StepperComponent"; +import { useWebSocket } from "../contexts/WebSocketContext"; import { useMediaContext } from "../contexts/MediaContext"; import { formatLogMessage } from "../utils/logUtils"; function UploadPage() { const navigate = useNavigate(); const theme = useTheme(); + const { socket, isConnected } = useWebSocket(); const { setMediaFile, setResponse, response, setLogs } = useMediaContext(); const [file, setFile] = useState(null); const [isDragging, setIsDragging] = useState(false); @@ -141,6 +143,12 @@ function UploadPage() { spectrogram: res.data.spectrogram, spec_sr: res.data.spec_sr })); + if (socket && isConnected){ + socket.send(JSON.stringify({ file_uuid: res.data.file_uuid })) + } else { + console.error("Websocket not connected!"); + } + setUpload(true); setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/input: Uploaded file successfully`)]) setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/input: file_uuid: ${res.data.file_uuid}`)]) From a5705fffd0fe9975fd32339af9c4df496cdc7a3b Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:12:10 +0530 Subject: [PATCH 04/10] remove file_dir on websocket disconnect --- api/api/consumers.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/api/api/consumers.py b/api/api/consumers.py index 6d5f6ca..2b517c7 100644 --- a/api/api/consumers.py +++ b/api/api/consumers.py @@ -1,7 +1,12 @@ # api/consumers.py import json +import os +import shutil +from pathlib import Path from channels.generic.websocket import WebsocketConsumer +UPLOAD_DIR = Path("/tmp/freqsplit") + class MediaConsumer(WebsocketConsumer): def connect(self): self.accept() @@ -26,4 +31,11 @@ class MediaConsumer(WebsocketConsumer): def disconnect(self, close_code): print("Disconnected from Websocket") - print("Stored file UUIDs:", self.file_uuid) \ No newline at end of file + print("Stored file UUIDs:", self.file_uuid) + for file_uuid in self.file_uuid: + dir_path = os.path.join(UPLOAD_DIR, file_uuid); + try: + if os.path.exists(dir_path): + shutil.rmtree(dir_path) + except Exception as e: + print(f"Error: Failed to cleanup {dir_path}: {e}") \ No newline at end of file From 397e4f2c99a9da84fba8aba3e61a7adf1abfd154 Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:17:40 +0530 Subject: [PATCH 05/10] remove file_uuid.zip file on websocket disconnect --- api/api/consumers.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/api/api/consumers.py b/api/api/consumers.py index 2b517c7..b53ebca 100644 --- a/api/api/consumers.py +++ b/api/api/consumers.py @@ -34,8 +34,12 @@ class MediaConsumer(WebsocketConsumer): print("Stored file UUIDs:", self.file_uuid) for file_uuid in self.file_uuid: dir_path = os.path.join(UPLOAD_DIR, file_uuid); + zip_path = os.path.join(UPLOAD_DIR, f"{file_uuid}.zip") try: if os.path.exists(dir_path): shutil.rmtree(dir_path) + + if os.path.isfile(zip_path): + os.remove(zip_path) except Exception as e: - print(f"Error: Failed to cleanup {dir_path}: {e}") \ No newline at end of file + print(f"Error: Failed to cleanup {dir_path} or {zip_path}: {e}") \ No newline at end of file From b8a8be5ae5bd03375ee3cbe542bb54015c52ceae Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:19:52 +0530 Subject: [PATCH 06/10] remove /api/cleanup and /api/cleanupzip endpoints in favour of websocket handling cleanups --- api/api/tasks.py | 11 ----------- api/api/views.py | 37 +------------------------------------ 2 files changed, 1 insertion(+), 47 deletions(-) diff --git a/api/api/tasks.py b/api/api/tasks.py index 0c5cc54..f8955b2 100644 --- a/api/api/tasks.py +++ b/api/api/tasks.py @@ -142,16 +142,5 @@ def generate_spectrogram_task(file_path): spec_data_json = json.dumps(spec_db.tolist()) return True, spec_data_json, plot_data['sr'] - except Exception as e: - return False -@shared_task -def cleanup_task(file_path): - """Celery task to cleanup files""" - file_path = Path(file_path) - - # Cleanup - try: - shutil.rmtree(os.path.dirname(file_path)) - return True except Exception as e: return False \ No newline at end of file diff --git a/api/api/views.py b/api/api/views.py index c9ea3c0..1655b7d 100644 --- a/api/api/views.py +++ b/api/api/views.py @@ -13,7 +13,6 @@ from .tasks import resample_audio_task from .tasks import music_separation_task from .tasks import noisereduce_task from .tasks import generate_spectrogram_task -from .tasks import cleanup_task from freqsplit.input.format_checker import is_supported_format UPLOAD_DIR = "/tmp/freqsplit" @@ -220,38 +219,4 @@ def download_audio(request): zipf.write(file_path, arcname) # Stream the ZIP file - return FileResponse(open(zip_file_path, "rb"), as_attachment=True, filename=os.path.basename(zip_file_path)) - -@api_view(['POST']) -def cleanup(request): - """Handles file cleanup after pipeline processing""" - stat, result, status_code = get_audio_file_path(request, UPLOAD_DIR) - if stat == False: - return Response({"error": result}, status=status_code) - - # Call Celery task synchronously - task = cleanup_task.apply(args=(result,)) - - if task.get(): - return Response({"message": f"Successfully cleaned up files on the server"}, status=status.HTTP_200_OK) - else: - return Response({"error": "Failed to cleanup files on the server"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - -@api_view(['POST']) -def cleanup_zip(request): - """Handles cleanup of all zip files leftover by api/download""" - deleted_files = [] - - for file in os.listdir(UPLOAD_DIR): - if file.endswith(".zip"): - file_path = os.path.join(UPLOAD_DIR, file) - try: - os.remove(file_path) - deleted_files.append(file) - except Exception as e: - return Response({"message": f"Error deleting {file_path}: {e}"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR) - - if deleted_files: - return Response({"message": f"Deleted ZIP files: {deleted_files}"}, status=status.HTTP_200_OK) - else: - return Response({"message": "No ZIP files found to clean up."}, status=status.HTTP_200_OK) + return FileResponse(open(zip_file_path, "rb"), as_attachment=True, filename=os.path.basename(zip_file_path)) \ No newline at end of file From a9dd87288d357232b4a8daa198abfc6ed4d0f549 Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:24:05 +0530 Subject: [PATCH 07/10] remove leftover url patterns --- api/backend/urls.py | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/api/backend/urls.py b/api/backend/urls.py index b5af9fe..df631a5 100644 --- a/api/backend/urls.py +++ b/api/backend/urls.py @@ -38,7 +38,5 @@ urlpatterns = [ path('api/separate', separate_music, name="separate_music"), path('api/noisereduce', noisereduce, name="noisreduce"), path('api/download', download_audio, name="download_audio"), - path('api/spectrogram', generate_spectrogram, name="generate_spectrogram"), - path('api/cleanup', cleanup, name="cleanup"), - path('api/cleanup_zip', cleanup_zip, name="cleanup_zip") + path('api/spectrogram', generate_spectrogram, name="generate_spectrogram") ] From 6a91261e2d3dc0469cc302b0b0c733f76c9d44ca Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:24:58 +0530 Subject: [PATCH 08/10] remove leftover url imports from urls.py --- api/backend/urls.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/backend/urls.py b/api/backend/urls.py index df631a5..7f4e0fc 100644 --- a/api/backend/urls.py +++ b/api/backend/urls.py @@ -25,8 +25,6 @@ from api.views import separate_music from api.views import noisereduce from api.views import download_audio from api.views import generate_spectrogram -from api.views import cleanup -from api.views import cleanup_zip urlpatterns = [ path('api/ping', ping, name="ping"), From 00f16d581498e1b5ccb0ea067c0cdf3f2d38c930 Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:35:59 +0530 Subject: [PATCH 09/10] handle FileNotFound Exception in separate task remove dir_path when websocket disconnects during separation, and dir_path ends up being created again --- api/api/tasks.py | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/api/api/tasks.py b/api/api/tasks.py index f8955b2..6043223 100644 --- a/api/api/tasks.py +++ b/api/api/tasks.py @@ -78,8 +78,15 @@ def music_separation_task(file_path): # Determine the base directory (output path) output_path = file_path.parent - # Run Demucs separation - separate_audio_with_demucs(str(file_path), str(output_path)) + try: + # Run Demucs separation + separate_audio_with_demucs(str(file_path), str(output_path)) + except Exception as e: + print(f"Failed to separate music into sources: {e}") + + if os.path.exists(os.path.dirname(file_path)): + shutil.rmtree(os.path.dirname(file_path)) + return False # Define expected output dir demucs_dir = output_path / 'htdemucs' @@ -116,6 +123,7 @@ def music_separation_task(file_path): return True except Exception as e: + print(f"Failed to separate music into sources: {e}") return False @shared_task From 20230322b0055fa0ee7c14def09bb55e9f292e7e Mon Sep 17 00:00:00 2001 From: Joel Mathew Thomas <90510078+joelmathewthomas@users.noreply.github.com> Date: Thu, 20 Mar 2025 00:39:29 +0530 Subject: [PATCH 10/10] update deps --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index e33d7df..a994cfc 100644 --- a/requirements.txt +++ b/requirements.txt @@ -41,7 +41,6 @@ dora_search==0.1.12 einops==0.8.1 filelock==3.17.0 fonttools==4.56.0 --e git+https://github.com/joelmathewthomas/freqsplit@c96b74c463f29fd5f50140701f92f92eb3109a2c#egg=freqsplit frozenlist==1.5.0 fsspec==2025.2.0 future==1.0.0