diff --git a/api/api/views.py b/api/api/views.py
index 6c0cf6f..c9ea3c0 100644
--- a/api/api/views.py
+++ b/api/api/views.py
@@ -21,7 +21,12 @@ UPLOAD_DIR = "/tmp/freqsplit"
# Ensure the temp directory exists
os.makedirs(UPLOAD_DIR, exist_ok=True)
-#
+# Endpoint to ping server
+@api_view(['GET'])
+def ping(request):
+ """Endpoint to ping the server"""
+ if (request):
+ return Response(status=status.HTTP_200_OK);
# Endpoint to upload audio and classify it to audio_class
@api_view(['POST'])
diff --git a/api/backend/urls.py b/api/backend/urls.py
index a675ee7..b5af9fe 100644
--- a/api/backend/urls.py
+++ b/api/backend/urls.py
@@ -16,6 +16,7 @@ Including another URLconf
"""
from django.contrib import admin
from django.urls import path
+from api.views import ping
from api.views import upload_audio
from api.views import normalize_audio
from api.views import trim_audio
@@ -28,6 +29,7 @@ from api.views import cleanup
from api.views import cleanup_zip
urlpatterns = [
+ path('api/ping', ping, name="ping"),
path('admin/', admin.site.urls),
path('api/upload', upload_audio, name='upload_audio'),
path('api/normalize', normalize_audio, name="normalize_audio"),
diff --git a/client/src/Pages/LandingPage.tsx b/client/src/Pages/LandingPage.tsx
index fdfbb2a..171483d 100644
--- a/client/src/Pages/LandingPage.tsx
+++ b/client/src/Pages/LandingPage.tsx
@@ -45,7 +45,7 @@ function LandingPage() {
Welcome to FreqSplit
- Upload, preview, and process your audio and video files with ease
+ Upload, preview, and process your audio files with ease
+
);
}
diff --git a/client/src/Pages/ProcessingPage.tsx b/client/src/Pages/ProcessingPage.tsx
index 8a44a90..e68644f 100644
--- a/client/src/Pages/ProcessingPage.tsx
+++ b/client/src/Pages/ProcessingPage.tsx
@@ -5,17 +5,24 @@ import StepperComponent from "../components/StepperComponent";
import { useMediaContext } from "../contexts/MediaContext";
import axios from "axios";
import JSZip from "jszip";
+import Logs from "../components/Logs"
+import { formatLogMessage } from "../utils/logUtils";
function ProcessingPage() {
const navigate = useNavigate();
- const { mediaFile, response, setExtractedFiles, setDownloadedFileURL, setDownloadedFileSpectrogram } = useMediaContext();
+ const { mediaFile, response, setExtractedFiles, setDownloadedFileURL, setDownloadedFileSpectrogram, setLogs } = useMediaContext();
const [progress, setProgress] = useState(0);
const [statusText, setStatusText] = useState("Analyzing media...");
const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms));
- const processStep = async (url: string, nextStep: () => void, progressValue: number, status: string, extraData = {}) => {
+ const processStep = async (url: string, log: string | null, nextStep: () => void, progressValue: number, status: string, extraData = {}) => {
try {
+
+ if (log !== null) {
+ setLogs((prevLogs) => [...prevLogs, log]);
+ }
+
const formData = new FormData();
formData.append("file_uuid", response.file_uuid);
Object.entries(extraData).forEach(([key, value]) =>
@@ -67,6 +74,10 @@ function ProcessingPage() {
responseType: "blob",
});
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/postprocessing: Exporting source file`)]);
+ setTimeout(() => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/postprocessing: Downloading file`)]);
+ }, 100);
if (res.status === 200) {
console.log("Download successful");
const blob = new Blob([res.data], { type: "audio/wav" });
@@ -78,6 +89,7 @@ function ProcessingPage() {
// Get spectrogram
setProgress(95);
setStatusText("Calculating Spectrogram");
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/spectrogram: Calculating spectrogram`)]);
const formData = new FormData();
formData.append("file_uuid", response.file_uuid);
@@ -114,6 +126,10 @@ function ProcessingPage() {
const handleDownload = async (downloadData: Blob) => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/postprocessing: Exporting source files`)]);
+ setTimeout(() => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/postprocessing: Downloading files`)]);
+ }, 100);
const zipBlob = new Blob([downloadData], { type: "application/zip" });
const zip = await JSZip.loadAsync(zipBlob);
@@ -127,6 +143,7 @@ function ProcessingPage() {
// Get spectrograms
setProgress(95);
setStatusText("Calculating Spectrograms");
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/spectrogram: Calculating spectrograms`)]);
const formData = new FormData();
formData.append("file_uuid", response.file_uuid);
@@ -161,14 +178,14 @@ function ProcessingPage() {
console.log("Starting processing...");
- processStep("/api/normalize", () => {
- processStep("/api/trim", () => {
+ processStep("/api/normalize", formatLogMessage("freqsplit/preprocessing: Applying amplitude scaling"), () => {
+ processStep("/api/trim", formatLogMessage("freqsplit/preprocessing: Pruning silent segments from audio"), () => {
if (response.audio_class === "Music") {
- processStep("/api/resample", () => {
- processStep("/api/separate", () => fetchZipDownload(), 90, "Separating music into vocals, bass, drums and other...");
+ processStep("/api/resample", formatLogMessage(`freqsplit/preprocessing: Performing rate conversion: ${response.sr}Hz -> 44100Hz`), () => {
+ processStep("/api/separate", formatLogMessage(`freqsplit/separation: Demucs: Applying Time-domain source extraction`), () => fetchZipDownload(), 90, "Separating music into vocals, bass, drums and other...");
}, 75, "Resampling audio to 44100Hz...", { sr: "44100" });
} else {
- processStep("/api/noisereduce", () => fetchDownload(), 90, "Reducing background noise from the audio...");
+ processStep("/api/noisereduce", formatLogMessage(`freqsplit/refinement: DeepFilterNet: Applying Spectral noise gating`), () => fetchDownload(), 90, "Reducing background noise from the audio...");
}
}, 50, "Trimming silent parts from the audio...");
}, 25, "Normalizing audio frequency...");
@@ -217,6 +234,7 @@ function ProcessingPage() {
height: 2,
}}
/>
+
);
}
diff --git a/client/src/Pages/ResultsPage.tsx b/client/src/Pages/ResultsPage.tsx
index 2735a50..698c1ca 100644
--- a/client/src/Pages/ResultsPage.tsx
+++ b/client/src/Pages/ResultsPage.tsx
@@ -20,10 +20,12 @@ import StepperComponent from '../components/StepperComponent';
import { useMediaContext } from '../contexts/MediaContext';
// @ts-ignore
import SpectrogramPlayer from "react-audio-spectrogram-player"
+import Logs from "../components/Logs"
+import { formatLogMessage } from "../utils/logUtils";
function ResultsPage() {
const navigate = useNavigate();
- const { mediaFile, response, extractedFiles, downloadedFileURL, downloadedFileSpectrogram } = useMediaContext();
+ const { mediaFile, response, extractedFiles, downloadedFileURL, downloadedFileSpectrogram, setLogs } = useMediaContext();
console.log("Extracted files are", extractedFiles);
// const [isPlaying, setIsPlaying] = useState(false);
const audioClass = response.audio_class
@@ -31,6 +33,7 @@ function ResultsPage() {
const handleDownloadAll = () => {
if (audioClass === 'Music') {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Saving files")]);
extractedFiles.forEach(({ name, url }) => {
const link = document.createElement('a');
link.href = url;
@@ -40,6 +43,7 @@ function ResultsPage() {
document.body.removeChild(link);
});
} else {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Saving file")]);
const link = document.createElement('a');
link.href = downloadedFileURL;
link.download = mediaFile?.name ?? 'downloaded_file';
@@ -195,6 +199,7 @@ function ResultsPage() {
+
);
}
diff --git a/client/src/Pages/UploadPage.tsx b/client/src/Pages/UploadPage.tsx
index bbbe1f4..ed40adc 100644
--- a/client/src/Pages/UploadPage.tsx
+++ b/client/src/Pages/UploadPage.tsx
@@ -1,5 +1,6 @@
import React, { useState, useEffect } from "react";
import { useNavigate } from "react-router-dom";
+import Logs from "../components/Logs"
import axios from "axios";
import {
Typography,
@@ -16,15 +17,45 @@ import {
} from "@mui/icons-material";
import StepperComponent from "../components/StepperComponent";
import { useMediaContext } from "../contexts/MediaContext";
+import { formatLogMessage } from "../utils/logUtils";
function UploadPage() {
const navigate = useNavigate();
const theme = useTheme();
- const { setMediaFile, setResponse, response } = useMediaContext();
+ const { setMediaFile, setResponse, response, setLogs } = useMediaContext();
const [file, setFile] = useState(null);
const [isDragging, setIsDragging] = useState(false);
const [fileError, setFileError] = useState("");
const [upload, setUpload] = useState(false);
+ const [inputEnabled, setInputEnabled] = useState(false);
+
+ useEffect(() => {
+ const startLogs = async () => {
+ setLogs([formatLogMessage("Initializing freqsplit")]);
+
+ setTimeout(() => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Connecting to server")]);
+
+ // Send GET request to /api/ping
+ axios.get("/api/ping")
+ .then((ping_resp) => {
+ if (ping_resp.status === 200) {
+ setTimeout(() => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Connection established successfully")]);
+ setInputEnabled(true);
+ }, 80);
+ } else {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Failed to connect to server")]);
+ }
+ })
+ .catch(() => {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("Failed to connect to server")]);
+ });
+ }, 90);
+ };
+
+ startLogs();
+ }, []);
const handleDragOver = (e: React.DragEvent) => {
e.preventDefault();
@@ -87,6 +118,7 @@ function UploadPage() {
formData.append("file", file);
try {
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage("freqsplit/input: Uploading audio file")]);
const res = await axios.post<{
file_uuid: string;
sr: number;
@@ -110,6 +142,9 @@ function UploadPage() {
spec_sr: res.data.spec_sr
}));
setUpload(true);
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/input: Uploaded file successfully`)])
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/input: file_uuid: ${res.data.file_uuid}`)])
+ setLogs((prevLogs) => [...prevLogs, formatLogMessage(`freqsplit/input: audio_class: ${res.data.audio_class}`)])
}
} catch (error) {
console.error("Upload failed:", error);
@@ -154,6 +189,7 @@ function UploadPage() {
style={{ display: "none" }}
onChange={handleFileChange}
accept="audio/*,video/*"
+ disabled={!inputEnabled}
/>
@@ -196,7 +232,7 @@ function UploadPage() {
-
+
);
}
diff --git a/client/src/components/Logs.tsx b/client/src/components/Logs.tsx
new file mode 100644
index 0000000..39f153e
--- /dev/null
+++ b/client/src/components/Logs.tsx
@@ -0,0 +1,42 @@
+import { Box, Typography } from "@mui/material";
+import { useMediaContext } from "../contexts/MediaContext";
+
+const Logs = () => {
+ const { logs } = useMediaContext();
+
+ return (
+ {
+ if (el) el.scrollTop = el.scrollHeight;
+ }}
+ >
+ {logs.length > 0 ? (
+ logs.map((log, index) => (
+
+ {`> ${log}`}
+
+ ))
+ ) : (
+
+ Waiting for logs...
+
+ )}
+
+ );
+
+};
+
+export default Logs;
\ No newline at end of file
diff --git a/client/src/contexts/MediaContext.tsx b/client/src/contexts/MediaContext.tsx
index b7afcc1..af18d00 100644
--- a/client/src/contexts/MediaContext.tsx
+++ b/client/src/contexts/MediaContext.tsx
@@ -11,6 +11,8 @@ interface MediaContextType {
setDownloadedFileURL: ( file: string) => void;
downloadedFileSpectrogram: { spectrogram: string, spec_sr: number};
setDownloadedFileSpectrogram: (spectrogram: {spectrogram: string, spec_sr: number}) => void;
+ logs: string[];
+ setLogs: React.Dispatch>;
}
@@ -31,10 +33,10 @@ export const MediaProvider: React.FC<{ children: React.ReactNode }> = ({ childre
spectrogram: "",
spec_sr: 0
});
-
+ const [logs, setLogs] = useState([""]);
return (
-
+
{children}
);
diff --git a/client/src/theme/theme.tsx b/client/src/theme/theme.tsx
index bded241..c06d961 100644
--- a/client/src/theme/theme.tsx
+++ b/client/src/theme/theme.tsx
@@ -20,6 +20,11 @@ const theme = createTheme({
h5: {
fontWeight: 500,
},
+ logText: {
+ fontFamily: 'monospace',
+ fontSize: '0.8rem',
+ whiteSpace: 'nowrap',
+ },
},
components: {
MuiButton: {
diff --git a/client/src/utils/logUtils.ts b/client/src/utils/logUtils.ts
new file mode 100644
index 0000000..cc40174
--- /dev/null
+++ b/client/src/utils/logUtils.ts
@@ -0,0 +1,28 @@
+/**
+ * Formats a log message with the current date and time, and a 'freqsplit' prefix.
+ * @param message - The log message to format.
+ * @returns The formatted log message.
+ */
+export function formatLogMessage(message: string): string {
+ const now = new Date();
+
+ // Pad single-digit numbers with leading zeros
+ const pad = (number: number, length = 2): string => number.toString().padStart(length, '0');
+
+ // Extract date components
+ const year = now.getFullYear();
+ const month = pad(now.getMonth() + 1); // Months are zero-based
+ const day = pad(now.getDate());
+
+ // Extract time components
+ const hours = pad(now.getHours());
+ const minutes = pad(now.getMinutes());
+ const seconds = pad(now.getSeconds());
+ const milliseconds = pad(now.getMilliseconds(), 3);
+
+ // Construct the formatted date-time string
+ const timestamp = `[${year}-${month}-${day} ${hours}:${minutes}:${seconds},${milliseconds}: freqsplit]`;
+
+ // Return the combined log message
+ return `${timestamp}: ${message}`;
+}