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/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}`; +}