peter288 commited on
Commit
d407cff
·
verified ·
1 Parent(s): 05965df

Upload 11 files

Browse files
Dockerfile ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # Start with a Python slim base image
2
+ FROM python:3.10-slim
3
+
4
+ # Set environment variables
5
+ ENV PYTHONDONTWRITEBYTECODE 1
6
+ ENV PYTHONUNBUFFERED 1
7
+
8
+ # Set work directory
9
+ WORKDIR /app
10
+
11
+ # Install dependencies
12
+ COPY requirements.txt .
13
+ RUN pip install --no-cache-dir -r requirements.txt
14
+
15
+ # Copy the entire backend project
16
+ COPY backend/ .
17
+
18
+ # Expose the port Hugging Face expects
19
+ EXPOSE 7860
20
+
21
+ # Start the server using Uvicorn
22
+ # We point it to the Django ASGI application object
23
+ CMD ["uvicorn", "backend.asgi:application", "--host", "0.0.0.0", "--port", "7860"]
backend/api/__init__.py ADDED
File without changes
backend/api/api.py ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from ninja import NinjaAPI, File
2
+ from ninja.files import UploadedFile
3
+ from django.http import HttpResponse
4
+ from .midi_utils import process_midi # Import from the same directory
5
+
6
+ api = NinjaAPI(
7
+ title="MIDI Processor API (Django Ninja)",
8
+ version="2.0.0",
9
+ description="A robust MIDI processing API built with Django Ninja."
10
+ )
11
+
12
+ @api.get("/")
13
+ def home(request):
14
+ """
15
+ A simple welcome endpoint.
16
+ The interactive docs will be at /api/docs
17
+ """
18
+ return {"message": "Welcome to the Django Ninja MIDI API!", "docs_url": "/api/docs"}
19
+
20
+
21
+ @api.post("/process-midi")
22
+ def process_midi_file(request, file: UploadedFile = File(...)):
23
+ """
24
+ Receives a MIDI file, transposes it, and returns the processed file.
25
+ """
26
+ try:
27
+ # Check filename
28
+ if not file.name.lower().endswith(('.mid', '.midi')):
29
+ return api.create_response(request, {"error": "Invalid file type"}, status=400)
30
+
31
+ # Read file bytes
32
+ midi_bytes = file.read()
33
+
34
+ # Process the midi data
35
+ processed_buffer = process_midi(midi_bytes)
36
+
37
+ # Create an HTTP response with the processed file
38
+ response = HttpResponse(
39
+ processed_buffer.getvalue(),
40
+ content_type='audio/midi'
41
+ )
42
+ response['Content-Disposition'] = f'attachment; filename="processed_{file.name}"'
43
+ return response
44
+
45
+ except Exception as e:
46
+ return api.create_response(request, {"error": str(e)}, status=500)
backend/api/midi_utils.py ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import mido
2
+ from io import BytesIO
3
+
4
+ def process_midi(midi_bytes: bytes) -> BytesIO:
5
+ """
6
+ Processes a MIDI file by transposing all notes up by one semitone.
7
+
8
+ Args:
9
+ midi_bytes: The raw bytes of the input MIDI file.
10
+
11
+ Returns:
12
+ A BytesIO buffer containing the processed MIDI data.
13
+ """
14
+ # Create an in-memory file-like object from the input bytes
15
+ with BytesIO(midi_bytes) as input_buffer:
16
+ mid = mido.MidiFile(file=input_buffer)
17
+
18
+ # Iterate over all tracks in the MIDI file
19
+ for i, track in enumerate(mid.tracks):
20
+ # Iterate over all messages in the track
21
+ for msg in track:
22
+ # Check if the message is a note_on or note_off event
23
+ if msg.type in ['note_on', 'note_off']:
24
+ # Transpose the note by +1 semitone
25
+ # We add a check to ensure the note doesn't go above 127
26
+ if msg.note < 127:
27
+ msg.note += 1
28
+
29
+ # Save the processed MIDI data to an in-memory output buffer
30
+ output_buffer = BytesIO()
31
+ mid.save(file=output_buffer)
32
+ # Reset the buffer's position to the beginning
33
+ output_buffer.seek(0)
34
+
35
+ return output_buffer
backend/backend/__init__.py ADDED
File without changes
backend/backend/asgi.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import os
2
+ from django.core.asgi import get_asgi_application
3
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
4
+ application = get_asgi_application()
backend/backend/settings.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ from pathlib import Path
2
+
3
+ BASE_DIR = Path(__file__).resolve().parent.parent
4
+
5
+ SECRET_KEY = 'django-insecure-hf-temp-key-for-midi-project' # A temporary key is fine
6
+
7
+ DEBUG = True
8
+
9
+ # IMPORTANT: Allow all hosts, as we don't know the exact internal hostname on HF
10
+ ALLOWED_HOSTS = ['*']
11
+
12
+ # Application definition
13
+ INSTALLED_APPS = [
14
+ 'django.contrib.admin',
15
+ 'django.contrib.auth',
16
+ 'django.contrib.contenttypes',
17
+ 'django.contrib.sessions',
18
+ 'django.contrib.messages',
19
+ 'django.contrib.staticfiles',
20
+ 'api', # Register our API app
21
+ ]
22
+
23
+ MIDDLEWARE = [
24
+ 'django.middleware.security.SecurityMiddleware',
25
+ 'django.contrib.sessions.middleware.SessionMiddleware',
26
+ 'django.middleware.common.CommonMiddleware',
27
+ 'django.middleware.csrf.CsrfViewMiddleware',
28
+ 'django.contrib.auth.middleware.AuthenticationMiddleware',
29
+ 'django.contrib.messages.middleware.MessageMiddleware',
30
+ 'django.middleware.clickjacking.XFrameOptionsMiddleware',
31
+ ]
32
+
33
+ ROOT_URLCONF = 'backend.urls'
34
+ WSGI_APPLICATION = 'backend.wsgi.application'
35
+ ASGI_APPLICATION = 'backend.asgi.application'
36
+
37
+ # Internationalization
38
+ LANGUAGE_CODE = 'en-us'
39
+ TIME_ZONE = 'UTC'
40
+ USE_I18N = True
41
+ USE_TZ = True
42
+
43
+ # Static files (we don't have any, but Django requires this)
44
+ STATIC_URL = 'static/'
45
+
46
+ # Default primary key field type
47
+ DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField'
backend/backend/urls.py ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
 
1
+ from django.urls import path
2
+ from api.api import api # Import our api object
3
+
4
+ urlpatterns = [
5
+ path("api/", api.urls), # All API requests will be under /api/
6
+ ]
backend/backend/wsgi.py ADDED
@@ -0,0 +1,4 @@
 
 
 
 
 
1
+ import os
2
+ from django.core.wsgi import get_wsgi_application
3
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
4
+ application = get_wsgi_application()
backend/manage.py ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python
2
+ """Django's command-line utility for administrative tasks."""
3
+ import os
4
+ import sys
5
+
6
+ def main():
7
+ """Run administrative tasks."""
8
+ os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'backend.settings')
9
+ try:
10
+ from django.core.management import execute_from_command_line
11
+ except ImportError as exc:
12
+ raise ImportError(
13
+ "Couldn't import Django. Are you sure it's installed and "
14
+ "available on your PYTHONPATH environment variable? Did you "
15
+ "forget to activate a virtual environment?"
16
+ ) from exc
17
+ execute_from_command_line(sys.argv)
18
+
19
+ if __name__ == '__main__':
20
+ main()
requirements.txt ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ django
2
+ django-ninja
3
+ uvicorn
4
+ mido==1.2.10
5
+ python-multipart-magic