judith.ibanez commited on
Commit ·
ccc3879
1
Parent(s): 542f57d
is working
Browse files- Dockerfile +75 -0
- README copy.md +62 -0
- app.py +84 -0
Dockerfile
ADDED
|
@@ -0,0 +1,75 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
FROM ubuntu:24.04
|
| 2 |
+
|
| 3 |
+
ENV DEBIAN_FRONTEND=noninteractive
|
| 4 |
+
|
| 5 |
+
## Install dependencies
|
| 6 |
+
RUN apt-get update && \
|
| 7 |
+
# Enable all necessary Ubuntu repositories
|
| 8 |
+
sed -i 's/^# deb /deb /g' /etc/apt/sources.list && \
|
| 9 |
+
sed -i 's/restricted/restricted universe multiverse/g' /etc/apt/sources.list && \
|
| 10 |
+
apt-get update && \
|
| 11 |
+
apt-get install -y --no-install-recommends \
|
| 12 |
+
wget \
|
| 13 |
+
unzip \
|
| 14 |
+
python3 \
|
| 15 |
+
python3-pip \
|
| 16 |
+
# Audio and GUI libraries needed by Audiveris (using correct Ubuntu 24.04 package names)
|
| 17 |
+
libasound2t64 \
|
| 18 |
+
libbsd0 \
|
| 19 |
+
libx11-6 \
|
| 20 |
+
libxau6 \
|
| 21 |
+
libxcb1 \
|
| 22 |
+
libxdmcp6 \
|
| 23 |
+
libxext6 \
|
| 24 |
+
libxi6 \
|
| 25 |
+
libxrender1 \
|
| 26 |
+
libxtst6 \
|
| 27 |
+
xdg-utils \
|
| 28 |
+
fontconfig \
|
| 29 |
+
fonts-dejavu-core \
|
| 30 |
+
fonts-freefont-ttf \
|
| 31 |
+
fonts-liberation \
|
| 32 |
+
&& apt-get clean \
|
| 33 |
+
&& rm -rf /var/lib/apt/lists/*
|
| 34 |
+
|
| 35 |
+
## Download, patch and install Audiveris for headless use
|
| 36 |
+
RUN export AUDIVERIS_URL="https://github.com/Audiveris/audiveris/releases/download/5.6.1/Audiveris-5.6.1-ubuntu24.04-x86_64.deb" && \
|
| 37 |
+
export DEB_FILE=$(basename ${AUDIVERIS_URL}) && \
|
| 38 |
+
\
|
| 39 |
+
# Download the package
|
| 40 |
+
wget ${AUDIVERIS_URL} && \
|
| 41 |
+
\
|
| 42 |
+
# Unpack the debian package to a temporary directory
|
| 43 |
+
dpkg-deb -R ${DEB_FILE} /tmp/audiveris && \
|
| 44 |
+
\
|
| 45 |
+
# Disable the post-installation script to prevent GUI-related actions.
|
| 46 |
+
# A simple script that exits successfully is used as a replacement.
|
| 47 |
+
echo -e '#!/bin/sh\nexit 0' > /tmp/audiveris/DEBIAN/postinst && \
|
| 48 |
+
chmod +x /tmp/audiveris/DEBIAN/postinst && \
|
| 49 |
+
\
|
| 50 |
+
# Repackage the modified components into a new .deb file.
|
| 51 |
+
dpkg-deb -b /tmp/audiveris /tmp/audiveris-fixed.deb && \
|
| 52 |
+
\
|
| 53 |
+
# Update lists and then install the patched package.
|
| 54 |
+
# dpkg will likely fail due to missing dependencies, which apt-get -f will then fix.
|
| 55 |
+
apt-get update && \
|
| 56 |
+
dpkg -i /tmp/audiveris-fixed.deb || apt-get -f install -y && \
|
| 57 |
+
\
|
| 58 |
+
# Clean up downloaded and temporary files
|
| 59 |
+
rm ${DEB_FILE} && \
|
| 60 |
+
rm -rf /tmp/audiveris /tmp/audiveris-fixed.deb && \
|
| 61 |
+
apt-get autoremove -y && \
|
| 62 |
+
apt-get clean && \
|
| 63 |
+
rm -rf /var/lib/apt/lists/*
|
| 64 |
+
|
| 65 |
+
## Install Gradio MCP
|
| 66 |
+
# TODO: use a python virtual environment
|
| 67 |
+
RUN pip install --break-system-packages gradio[mcp]
|
| 68 |
+
|
| 69 |
+
## Copy MCP server and execute it
|
| 70 |
+
COPY app.py /app/app.py
|
| 71 |
+
WORKDIR /app
|
| 72 |
+
|
| 73 |
+
CMD ["python3", "-u", "app.py"]
|
| 74 |
+
|
| 75 |
+
RUN find / -name Audiveris || true
|
README copy.md
ADDED
|
@@ -0,0 +1,62 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
---
|
| 2 |
+
title: Gradio APP Hackathon - score
|
| 3 |
+
emoji: 🎶
|
| 4 |
+
colorFrom: yellow
|
| 5 |
+
colorTo: red
|
| 6 |
+
sdk: gradio
|
| 7 |
+
sdk_version: 5.32.1
|
| 8 |
+
app_file: app.py
|
| 9 |
+
pinned: false
|
| 10 |
+
---
|
| 11 |
+
|
| 12 |
+
Check out the configuration reference at <https://huggingface.co/docs/hub/spaces-config-reference>
|
| 13 |
+
|
| 14 |
+
## 🚀 How to Build and Run the MCP Audiveris Server
|
| 15 |
+
|
| 16 |
+
### 🐳 Build the Docker Image
|
| 17 |
+
|
| 18 |
+
```bash
|
| 19 |
+
docker buildx build --load --platform linux/amd64 -t mcp-server-audiveris .
|
| 20 |
+
```
|
| 21 |
+
|
| 22 |
+
### ▶️ Run the Container
|
| 23 |
+
|
| 24 |
+
```bash
|
| 25 |
+
docker run --platform linux/amd64 -p 7860:7860 mcp-server-audiveris
|
| 26 |
+
```
|
| 27 |
+
|
| 28 |
+
The Gradio web interface will be available at: [http://localhost:7860](http://localhost:7860)
|
| 29 |
+
|
| 30 |
+
---
|
| 31 |
+
|
| 32 |
+
## 🎼 How to Use
|
| 33 |
+
|
| 34 |
+
1. **Upload a PDF**: Click the "Upload PDF music score" button and select your music score in PDF format.
|
| 35 |
+
2. **Convert**: The server will process the PDF and generate a MusicXML file in `.mxl` format.
|
| 36 |
+
3. **Download**: Once finished, click "Download MusicXML file" to get your `.mxl` file.
|
| 37 |
+
|
| 38 |
+
---
|
| 39 |
+
|
| 40 |
+
## 📦 What is the MXL Format?
|
| 41 |
+
|
| 42 |
+
- `.mxl` is a compressed (ZIP) version of MusicXML, used for sharing digital sheet music.
|
| 43 |
+
- You can open `.mxl` files with music notation software like MuseScore, Finale, or Sibelius.
|
| 44 |
+
- To inspect the contents, rename `.mxl` to `.zip` and extract it. You should see at least one `.xml` file inside.
|
| 45 |
+
|
| 46 |
+
**Example structure:**
|
| 47 |
+
|
| 48 |
+
```sh
|
| 49 |
+
my_score.mxl
|
| 50 |
+
├── META-INF/
|
| 51 |
+
│ └── container.xml
|
| 52 |
+
└── my_score.xml
|
| 53 |
+
```
|
| 54 |
+
|
| 55 |
+
---
|
| 56 |
+
|
| 57 |
+
## 🛠️ Troubleshooting
|
| 58 |
+
|
| 59 |
+
- If you get errors about missing fonts, make sure the Docker image includes `fontconfig` and common font packages.
|
| 60 |
+
- If no output file is generated, check that your PDF contains clear, printable music notation.
|
| 61 |
+
|
| 62 |
+
---
|
app.py
ADDED
|
@@ -0,0 +1,84 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
+
import gradio as gr
|
| 2 |
+
import subprocess
|
| 3 |
+
import os
|
| 4 |
+
|
| 5 |
+
def recognize_music(pdf_file):
|
| 6 |
+
"""Converts a PDF file to a Music score
|
| 7 |
+
|
| 8 |
+
Args:
|
| 9 |
+
pdf_file: the file with the PDF file
|
| 10 |
+
|
| 11 |
+
Returns:
|
| 12 |
+
the path were the MusicXML file is generated
|
| 13 |
+
"""
|
| 14 |
+
audiveris = "/opt/audiveris/Audiveris"
|
| 15 |
+
output_dir = "/tmp/output"
|
| 16 |
+
gradio_tmp_dir = os.path.dirname(pdf_file.name)
|
| 17 |
+
|
| 18 |
+
# Create output directory if it doesn't exist
|
| 19 |
+
os.makedirs(output_dir, exist_ok=True)
|
| 20 |
+
|
| 21 |
+
pdf_file_path = pdf_file.name
|
| 22 |
+
pdf_file_name = os.path.basename(pdf_file.name)
|
| 23 |
+
musicXml_file_name = os.path.splitext(pdf_file_name)[0]+".mxl"
|
| 24 |
+
output_file = output_dir + "/" + musicXml_file_name
|
| 25 |
+
|
| 26 |
+
cmd = [
|
| 27 |
+
audiveris, "-batch", "-export", "-output", output_dir, pdf_file_path
|
| 28 |
+
]
|
| 29 |
+
|
| 30 |
+
try:
|
| 31 |
+
result = subprocess.run(cmd, capture_output=True, text=True, timeout=300)
|
| 32 |
+
|
| 33 |
+
print(f"Audiveris command: {' '.join(cmd)}")
|
| 34 |
+
print(f"Return code: {result.returncode}")
|
| 35 |
+
print(f"STDOUT: {result.stdout}")
|
| 36 |
+
print(f"STDERR: {result.stderr}")
|
| 37 |
+
|
| 38 |
+
# List files in output and gradio temp dir for debugging
|
| 39 |
+
if os.path.exists(output_dir):
|
| 40 |
+
files_in_output = os.listdir(output_dir)
|
| 41 |
+
print(f"Files in /tmp/output: {files_in_output}")
|
| 42 |
+
if os.path.exists(gradio_tmp_dir):
|
| 43 |
+
files_in_gradio = os.listdir(gradio_tmp_dir)
|
| 44 |
+
print(f"Files in {gradio_tmp_dir}: {files_in_gradio}")
|
| 45 |
+
|
| 46 |
+
# Check if the expected file exists
|
| 47 |
+
if os.path.exists(output_file):
|
| 48 |
+
print(f"Success! Music score file saved to {output_file}")
|
| 49 |
+
return output_file
|
| 50 |
+
else:
|
| 51 |
+
# Try different possible extensions/names
|
| 52 |
+
possible_files = []
|
| 53 |
+
base_name = os.path.splitext(pdf_file_name)[0]
|
| 54 |
+
|
| 55 |
+
# Check for different extensions
|
| 56 |
+
for ext in [".mxl", ".xml", ".musicxml"]:
|
| 57 |
+
possible_file = os.path.join(output_dir, base_name + ext)
|
| 58 |
+
if os.path.exists(possible_file):
|
| 59 |
+
print(f"Found file with different extension: {possible_file}")
|
| 60 |
+
return possible_file
|
| 61 |
+
possible_files.append(possible_file)
|
| 62 |
+
|
| 63 |
+
error_msg = (
|
| 64 |
+
f"No output file found. Expected: {output_file}\n"
|
| 65 |
+
f"Tried: {possible_files}\n"
|
| 66 |
+
f"Command output (stdout):\n{result.stdout}\n"
|
| 67 |
+
f"Command errors (stderr):\n{result.stderr}\n"
|
| 68 |
+
f"Files in /tmp/output: {files_in_output if 'files_in_output' in locals() else 'N/A'}\n"
|
| 69 |
+
f"Files in {gradio_tmp_dir}: {files_in_gradio if 'files_in_gradio' in locals() else 'N/A'}\n"
|
| 70 |
+
)
|
| 71 |
+
raise FileNotFoundError(error_msg)
|
| 72 |
+
except subprocess.TimeoutExpired:
|
| 73 |
+
raise Exception("Audiveris process timed out after 300 seconds")
|
| 74 |
+
except Exception as e:
|
| 75 |
+
raise Exception(f"Error processing file: {str(e)}")
|
| 76 |
+
|
| 77 |
+
audiveris = gr.Interface(
|
| 78 |
+
fn=recognize_music,
|
| 79 |
+
inputs=gr.File(file_types=[".pdf"], label="Upload PDF music score"),
|
| 80 |
+
outputs=gr.File(label="Download MusicXML file"),
|
| 81 |
+
description="Upload a PDF music socre and create a MusicXML file from it.",
|
| 82 |
+
)
|
| 83 |
+
|
| 84 |
+
audiveris.launch(server_name="0.0.0.0", mcp_server=True, ssr_mode=False)
|