ccmusic-database部署教程:Docker Compose编排Gradio+FFmpeg预处理服务

1. 引言

你有没有想过,让AI来帮你识别一首歌是什么风格?是激昂的交响乐,还是温柔的流行抒情?今天要介绍的ccmusic-database项目,就是一个能自动识别16种音乐流派的智能系统。

这个系统基于VGG19_BN模型和CQT频谱特征,能够对上传的音频文件进行智能分析,告诉你它最可能属于哪种音乐流派。想象一下,如果你有一个音乐库需要整理,或者想为自己的作品自动打上风格标签,这个工具就能派上大用场。

但直接运行Python脚本可能会遇到环境配置、依赖冲突等问题。为了让部署过程更简单、更可靠,我决定用Docker Compose来编排整个服务。这样不仅能一键启动所有组件,还能确保在任何机器上运行效果一致。

本文将带你从零开始,用Docker Compose部署完整的ccmusic-database服务,包括Gradio Web界面和FFmpeg音频预处理服务。即使你是Docker新手,也能跟着步骤顺利完成部署。

2. 项目概览与核心原理

2.1 项目是什么

ccmusic-database是一个音乐流派分类系统,它能够识别16种不同的音乐风格。你只需要上传一个音频文件(MP3或WAV格式),系统就会自动分析并给出预测结果,显示最可能的5种流派及其概率。

支持的16种流派包括:

  • 古典音乐类:交响乐、歌剧、独奏、室内乐
  • 流行音乐类:流行抒情、成人当代、青少年流行、舞曲流行等
  • 摇滚音乐类:成人另类摇滚、励志摇滚、软摇滚
  • 其他风格:独立流行、艺术流行、灵魂乐/R&B、原声流行

2.2 技术原理简单说

虽然项目描述中提到了计算机视觉预训练模型,但理解起来很简单:

  1. 把声音变成图片:系统先把音频文件转换成一种叫做"CQT频谱图"的图片。你可以把它想象成音乐的"指纹"——不同的音乐风格会有不同的图案特征。

  2. 用AI识别图片:转换后的频谱图被送入一个经过训练的VGG19_BN模型。这个模型原本是用来识别普通图片的(比如猫、狗、汽车),但经过专门训练后,它学会了识别不同音乐风格对应的频谱图案。

  3. 给出分类结果:模型分析频谱图后,会计算它属于每种流派的概率,然后按概率从高到低排序,展示前5个最可能的结果。

2.3 为什么需要Docker Compose

原始项目虽然提供了Python脚本,但在实际部署时会遇到几个问题:

  • 环境配置复杂:需要安装特定版本的Python、PyTorch、librosa等库,版本不匹配就容易出错
  • 依赖管理麻烦:不同的系统(Windows、macOS、Linux)安装方式不同
  • 服务编排困难:项目需要Web界面(Gradio)和音频预处理(FFmpeg),手动启动多个服务很繁琐
  • 可移植性差:在一台机器上配置好了,换台机器又得重新来一遍

用Docker Compose可以解决所有这些问题:

  • 一键启动所有服务
  • 环境隔离,不会影响系统其他软件
  • 在任何支持Docker的系统上都能运行
  • 方便更新和维护

3. 环境准备与快速部署

3.1 准备工作

在开始之前,你需要确保系统已经安装了Docker和Docker Compose。如果你还没有安装,可以按照以下步骤操作:

对于Ubuntu/Debian系统:

# 安装Docker
sudo apt update
sudo apt install docker.io docker-compose

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

# 将当前用户加入docker组(避免每次都要sudo)
sudo usermod -aG docker $USER
# 然后需要重新登录生效

对于CentOS/RHEL系统:

# 安装Docker
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/centos/docker-ce.repo
sudo yum install docker-ce docker-ce-cli containerd.io docker-compose-plugin

# 启动Docker服务
sudo systemctl start docker
sudo systemctl enable docker

验证安装:

docker --version
docker-compose --version

如果两个命令都能正确显示版本号,说明安装成功。

3.2 项目文件结构

首先创建项目目录并准备必要的文件:

# 创建项目目录
mkdir ccmusic-database-docker
cd ccmusic-database-docker

# 创建目录结构
mkdir -p app/models app/examples app/processed_audio

项目最终的文件结构应该是这样的:

ccmusic-database-docker/
├── docker-compose.yml          # Docker Compose配置文件
├── Dockerfile                  # 主应用Dockerfile
├── requirements.txt           # Python依赖
├── app/
│   ├── app.py                # 主应用程序
│   ├── models/
│   │   └── save.pt          # 模型文件(需要下载)
│   ├── examples/            # 示例音频文件
│   └── processed_audio/     # 处理后的音频缓存
└── ffmpeg-service/
    └── Dockerfile           # FFmpeg服务Dockerfile

3.3 编写Docker Compose配置文件

创建docker-compose.yml文件:

version: '3.8'

services:
  # 主应用服务 - 提供Gradio Web界面
  music-genre-app:
    build: .
    container_name: music-genre-classifier
    ports:
      - "7860:7860"  # Gradio默认端口
    volumes:
      - ./app/models:/app/models
      - ./app/examples:/app/examples
      - ./app/processed_audio:/app/processed_audio
      - ./app/app.py:/app/app.py
    environment:
      - MODEL_PATH=/app/models/save.pt
      - EXAMPLES_DIR=/app/examples
      - PROCESSED_DIR=/app/processed_audio
      - FFMPEG_SERVICE_URL=http://ffmpeg-service:8000
    depends_on:
      - ffmpeg-service
    restart: unless-stopped
    networks:
      - music-network

  # FFmpeg音频预处理服务
  ffmpeg-service:
    build: ./ffmpeg-service
    container_name: ffmpeg-preprocessor
    ports:
      - "8000:8000"  # 内部API端口
    volumes:
      - ./app/processed_audio:/app/processed_audio
    restart: unless-stopped
    networks:
      - music-network

networks:
  music-network:
    driver: bridge

3.4 编写主应用Dockerfile

创建Dockerfile文件:

# 使用官方Python镜像
FROM python:3.9-slim

# 设置工作目录
WORKDIR /app

# 安装系统依赖
RUN apt-get update && apt-get install -y \
    libsndfile1 \
    ffmpeg \
    && rm -rf /var/lib/apt/lists/*

# 复制依赖文件
COPY requirements.txt .

# 安装Python依赖
RUN pip install --no-cache-dir -r requirements.txt

# 复制应用代码
COPY app/ .

# 创建必要的目录
RUN mkdir -p models examples processed_audio

# 暴露端口
EXPOSE 7860

# 启动应用
CMD ["python", "app.py"]

3.5 编写FFmpeg服务Dockerfile

创建ffmpeg-service/Dockerfile文件:

FROM python:3.9-slim

WORKDIR /app

RUN apt-get update && apt-get install -y \
    ffmpeg \
    && rm -rf /var/lib/apt/lists/*

COPY requirements-ffmpeg.txt .

RUN pip install --no-cache-dir -r requirements-ffmpeg.txt

COPY ffmpeg_api.py .

EXPOSE 8000

CMD ["python", "ffmpeg_api.py"]

3.6 创建依赖文件

创建requirements.txt(主应用):

torch==1.13.1
torchvision==0.14.1
librosa==0.9.2
gradio==3.34.0
numpy==1.24.3
scipy==1.10.1
soundfile==0.12.1
requests==2.28.2
Pillow==9.5.0

创建ffmpeg-service/requirements-ffmpeg.txt

fastapi==0.95.2
uvicorn[standard]==0.22.0
pydantic==1.10.9
requests==2.28.2

3.7 编写FFmpeg API服务

创建ffmpeg-service/ffmpeg_api.py

from fastapi import FastAPI, UploadFile, File, HTTPException
from fastapi.responses import JSONResponse
import subprocess
import os
import uuid
from pathlib import Path

app = FastAPI(title="FFmpeg Audio Preprocessor")

# 确保处理目录存在
PROCESSED_DIR = Path("/app/processed_audio")
PROCESSED_DIR.mkdir(exist_ok=True)

@app.post("/preprocess")
async def preprocess_audio(file: UploadFile = File(...)):
    """
    预处理音频文件:统一转换为WAV格式,采样率44100Hz,单声道
    """
    try:
        # 生成唯一文件名
        file_id = str(uuid.uuid4())
        input_path = PROCESSED_DIR / f"input_{file_id}.tmp"
        output_path = PROCESSED_DIR / f"processed_{file_id}.wav"
        
        # 保存上传的文件
        with open(input_path, "wb") as f:
            content = await file.read()
            f.write(content)
        
        # 使用FFmpeg进行预处理
        cmd = [
            "ffmpeg",
            "-i", str(input_path),
            "-ar", "44100",      # 采样率
            "-ac", "1",          # 单声道
            "-acodec", "pcm_s16le",  # 编码格式
            "-y",                # 覆盖输出文件
            str(output_path)
        ]
        
        # 执行FFmpeg命令
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=30  # 30秒超时
        )
        
        # 清理临时文件
        if input_path.exists():
            input_path.unlink()
        
        if result.returncode != 0:
            raise HTTPException(
                status_code=500,
                detail=f"FFmpeg处理失败: {result.stderr}"
            )
        
        # 检查输出文件是否存在
        if not output_path.exists():
            raise HTTPException(
                status_code=500,
                detail="处理后的文件未生成"
            )
        
        return JSONResponse({
            "status": "success",
            "processed_file": output_path.name,
            "message": "音频预处理完成"
        })
        
    except Exception as e:
        raise HTTPException(status_code=500, detail=str(e))

@app.get("/health")
async def health_check():
    """健康检查端点"""
    return {"status": "healthy", "service": "ffmpeg-preprocessor"}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="0.0.0.0", port=8000)

3.8 修改主应用代码

创建app/app.py(基于原始代码修改):

import torch
import torch.nn as nn
import torchvision.models as models
import librosa
import numpy as np
import gradio as gr
from PIL import Image
import requests
import os
import tempfile
from pathlib import Path

# 配置参数
MODEL_PATH = os.getenv("MODEL_PATH", "./models/save.pt")
EXAMPLES_DIR = os.getenv("EXAMPLES_DIR", "./examples")
PROCESSED_DIR = os.getenv("PROCESSED_DIR", "./processed_audio")
FFMPEG_SERVICE_URL = os.getenv("FFMPEG_SERVICE_URL", "http://localhost:8000")

# 16种音乐流派标签
GENRE_LABELS = [
    "Symphony (交响乐)",
    "Opera (歌剧)", 
    "Solo (独奏)",
    "Chamber (室内乐)",
    "Pop vocal ballad (流行抒情)",
    "Adult contemporary (成人当代)",
    "Teen pop (青少年流行)",
    "Contemporary dance pop (现代舞曲)",
    "Dance pop (舞曲流行)",
    "Classic indie pop (独立流行)",
    "Chamber cabaret & art pop (艺术流行)",
    "Soul / R&B (灵魂乐)",
    "Adult alternative rock (成人另类摇滚)",
    "Uplifting anthemic rock (励志摇滚)",
    "Soft rock (软摇滚)",
    "Acoustic pop (原声流行)"
]

class VGG19BNClassifier(nn.Module):
    """VGG19_BN分类器模型"""
    def __init__(self, num_classes=16):
        super(VGG19BNClassifier, self).__init__()
        # 加载预训练的VGG19_BN模型
        vgg19_bn = models.vgg19_bn(pretrained=False)
        
        # 移除最后的分类层
        self.features = vgg19_bn.features
        
        # 添加自定义分类器
        self.avgpool = nn.AdaptiveAvgPool2d((7, 7))
        self.classifier = nn.Sequential(
            nn.Linear(512 * 7 * 7, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, 4096),
            nn.ReLU(True),
            nn.Dropout(),
            nn.Linear(4096, num_classes)
        )
    
    def forward(self, x):
        x = self.features(x)
        x = self.avgpool(x)
        x = torch.flatten(x, 1)
        x = self.classifier(x)
        return x

def load_model(model_path):
    """加载训练好的模型"""
    model = VGG19BNClassifier(num_classes=16)
    
    # 加载模型权重
    checkpoint = torch.load(model_path, map_location=torch.device('cpu'))
    model.load_state_dict(checkpoint['model_state_dict'])
    model.eval()
    
    return model

def preprocess_audio_with_ffmpeg(audio_file):
    """使用FFmpeg服务预处理音频"""
    try:
        # 调用FFmpeg服务
        with open(audio_file, 'rb') as f:
            files = {'file': f}
            response = requests.post(
                f"{FFMPEG_SERVICE_URL}/preprocess",
                files=files,
                timeout=60
            )
        
        if response.status_code == 200:
            result = response.json()
            processed_filename = result['processed_file']
            processed_path = Path(PROCESSED_DIR) / processed_filename
            
            if processed_path.exists():
                return str(processed_path)
            else:
                print(f"处理后的文件不存在: {processed_path}")
                return audio_file  # 回退到原始文件
        else:
            print(f"FFmpeg服务调用失败: {response.status_code}")
            return audio_file  # 回退到原始文件
            
    except Exception as e:
        print(f"FFmpeg预处理失败,使用原始文件: {e}")
        return audio_file  # 回退到原始文件

def extract_cqt_spectrogram(audio_path, sr=22050, hop_length=512, n_bins=84):
    """提取CQT频谱图"""
    try:
        # 加载音频文件
        y, sr = librosa.load(audio_path, sr=sr)
        
        # 如果音频太长,截取前30秒
        if len(y) > sr * 30:
            y = y[:sr * 30]
        
        # 计算CQT
        cqt = librosa.cqt(y, sr=sr, hop_length=hop_length, n_bins=n_bins)
        cqt_mag = librosa.magphase(cqt)[0]
        
        # 转换为分贝单位
        cqt_db = librosa.amplitude_to_db(cqt_mag, ref=np.max)
        
        # 归一化到0-255范围
        cqt_normalized = (cqt_db - cqt_db.min()) / (cqt_db.max() - cqt_db.min()) * 255
        cqt_normalized = cqt_normalized.astype(np.uint8)
        
        # 调整大小为224x224
        img = Image.fromarray(cqt_normalized)
        img = img.resize((224, 224))
        
        # 转换为RGB(复制单通道到三个通道)
        img_rgb = Image.new("RGB", img.size)
        img_rgb.paste(img, (0, 0))
        
        # 转换为模型输入格式
        img_array = np.array(img_rgb).transpose(2, 0, 1)  # HWC to CHW
        img_tensor = torch.FloatTensor(img_array) / 255.0
        
        # 添加批次维度
        img_tensor = img_tensor.unsqueeze(0)
        
        return img_tensor
        
    except Exception as e:
        print(f"频谱图提取失败: {e}")
        raise

def predict_genre(audio_file):
    """预测音乐流派"""
    try:
        # 1. 使用FFmpeg预处理音频
        processed_audio = preprocess_audio_with_ffmpeg(audio_file)
        
        # 2. 提取CQT频谱图
        spectrogram = extract_cqt_spectrogram(processed_audio)
        
        # 3. 使用模型进行预测
        with torch.no_grad():
            outputs = model(spectrogram)
            probabilities = torch.nn.functional.softmax(outputs, dim=1)
            top5_prob, top5_idx = torch.topk(probabilities, 5)
        
        # 4. 准备结果
        results = []
        for i in range(5):
            idx = top5_idx[0][i].item()
            prob = top5_prob[0][i].item() * 100
            genre = GENRE_LABELS[idx]
            results.append(f"{genre}: {prob:.2f}%")
        
        # 5. 生成可视化结果
        result_text = "Top 5 流派预测:\n" + "\n".join(results)
        
        return result_text
        
    except Exception as e:
        return f"预测过程中出现错误: {str(e)}"

def create_examples():
    """创建示例文件列表"""
    examples_dir = Path(EXAMPLES_DIR)
    if examples_dir.exists():
        audio_files = list(examples_dir.glob("*.mp3")) + list(examples_dir.glob("*.wav"))
        return [[str(f)] for f in audio_files[:5]]  # 最多5个示例
    return []

# 加载模型
print("正在加载模型...")
model = load_model(MODEL_PATH)
print("模型加载完成!")

# 创建Gradio界面
with gr.Blocks(title="音乐流派分类系统") as demo:
    gr.Markdown("# 🎵 音乐流派分类系统")
    gr.Markdown("上传音频文件,系统将自动识别其音乐流派(支持16种流派分类)")
    
    with gr.Row():
        with gr.Column():
            audio_input = gr.Audio(
                label="上传音频文件",
                type="filepath",
                sources=["upload", "microphone"]
            )
            
            analyze_btn = gr.Button("分析音乐流派", variant="primary")
            
            with gr.Accordion("高级选项", open=False):
                use_ffmpeg = gr.Checkbox(
                    label="使用FFmpeg预处理音频",
                    value=True,
                    info="启用后会对音频进行标准化处理(推荐)"
                )
        
        with gr.Column():
            output_text = gr.Textbox(
                label="预测结果",
                lines=10,
                placeholder="点击'分析音乐流派'按钮查看结果..."
            )
    
    # 示例部分
    gr.Markdown("## 示例音频")
    examples = create_examples()
    if examples:
        gr.Examples(
            examples=examples,
            inputs=[audio_input],
            outputs=[output_text],
            fn=predict_genre,
            cache_examples=False,
            label="点击示例快速尝试"
        )
    
    # 说明部分
    with gr.Accordion("使用说明", open=False):
        gr.Markdown("""
        ### 使用方法
        1. **上传音频**:支持MP3、WAV等常见格式,也可以直接录音
        2. **点击分析**:系统会自动提取音频特征并进行流派分类
        3. **查看结果**:显示最可能的5种流派及其概率
        
        ### 技术说明
        - 基于VGG19_BN + CQT特征的深度学习模型
        - 自动截取音频前30秒进行分析
        - 支持16种音乐流派分类
        - 使用FFmpeg进行音频预处理(可选)
        
        ### 支持的流派
        - 古典音乐:交响乐、歌剧、独奏、室内乐
        - 流行音乐:流行抒情、成人当代、青少年流行等
        - 摇滚音乐:成人另类摇滚、励志摇滚、软摇滚
        - 其他风格:独立流行、艺术流行、灵魂乐/R&B、原声流行
        """)
    
    # 绑定事件
    analyze_btn.click(
        fn=predict_genre,
        inputs=[audio_input],
        outputs=[output_text]
    )

# 启动应用
if __name__ == "__main__":
    demo.launch(
        server_name="0.0.0.0",
        server_port=7860,
        share=False
    )

3.9 下载模型文件

由于模型文件较大(466MB),你需要手动下载并放置到正确位置:

# 进入项目目录
cd ccmusic-database-docker

# 创建models目录(如果不存在)
mkdir -p app/models

# 下载模型文件(这里需要你从原始项目获取save.pt文件)
# 将下载的save.pt文件放到 app/models/ 目录下

# 或者使用wget下载(如果原始项目提供了下载链接)
# wget -O app/models/save.pt [模型文件下载链接]

重要提示:由于模型文件较大且可能涉及版权,请确保你从合法渠道获取save.pt模型文件。如果没有现成的模型文件,你可能需要按照原始项目的说明自己训练模型。

3.10 准备示例音频

为了让演示更完整,你可以准备一些示例音频文件:

# 创建示例目录
mkdir -p app/examples

# 添加一些示例音频文件(MP3或WAV格式)
# 例如:
# cp /path/to/your/audio1.mp3 app/examples/
# cp /path/to/your/audio2.wav app/examples/

建议准备不同流派的音频文件,这样用户可以更好地测试系统的分类能力。

4. 一键部署与启动

4.1 构建并启动服务

一切准备就绪后,只需要一个命令就能启动所有服务:

# 在项目根目录执行
docker-compose up -d

这个命令会:

  1. 构建两个Docker镜像(主应用和FFmpeg服务)
  2. 创建专用网络让两个服务可以通信
  3. 在后台启动所有容器

4.2 查看服务状态

启动后,你可以检查服务运行状态:

# 查看所有容器状态
docker-compose ps

# 查看日志(实时)
docker-compose logs -f

# 查看特定服务的日志
docker-compose logs music-genre-app
docker-compose logs ffmpeg-service

正常启动后,你应该看到类似这样的输出:

NAME                       COMMAND                  SERVICE             STATUS              PORTS
music-genre-classifier     "python app.py"          music-genre-app     running             0.0.0.0:7860->7860/tcp
ffmpeg-preprocessor        "python ffmpeg_api.py"   ffmpeg-service      running             0.0.0.0:8000->8000/tcp

4.3 访问Web界面

服务启动后,打开浏览器访问:

  • 主应用界面:http://localhost:7860
  • FFmpeg服务健康检查:http://localhost:8000/health

如果一切正常,你应该能看到Gradio的Web界面,可以上传音频文件进行流派分类测试。

4.4 测试系统功能

在Web界面中,你可以:

  1. 上传音频文件:点击上传按钮选择MP3或WAV文件
  2. 使用麦克风录音:点击录音按钮直接录制音频
  3. 尝试示例音频:如果准备了示例文件,界面下方会有示例区域
  4. 查看分析结果:点击"分析音乐流派"按钮,稍等片刻就能看到结果

一个典型的分析结果可能如下:

Top 5 流派预测:
Pop vocal ballad (流行抒情): 85.32%
Adult contemporary (成人当代): 12.15%
Teen pop (青少年流行): 1.87%
Acoustic pop (原声流行): 0.43%
Soft rock (软摇滚): 0.23%

5. 使用技巧与常见问题

5.1 使用技巧

优化音频处理:

  • 对于较长的音频文件,系统会自动截取前30秒进行分析,确保音频前30秒能代表整首歌曲的风格
  • 启用FFmpeg预处理可以统一音频格式,提高识别准确率
  • 建议使用44100Hz采样率的音频文件,这是音乐CD的标准采样率

提高识别准确率:

  • 确保音频质量较好,没有太多背景噪音
  • 如果是混合风格的音乐,系统可能会给出多个相近的概率
  • 对于纯音乐(无歌词)的识别通常比带歌词的音乐更准确

批量处理技巧: 虽然Web界面不支持批量上传,但你可以通过API方式批量处理:

import requests

def batch_predict(audio_files):
    results = []
    for audio_file in audio_files:
        with open(audio_file, 'rb') as f:
            files = {'file': f}
            response = requests.post(
                'http://localhost:7860/api/predict',
                files=files
            )
            if response.status_code == 200:
                results.append(response.json())
    return results

5.2 常见问题解决

Q: 启动时提示端口被占用怎么办?

A: 修改docker-compose.yml中的端口映射:

ports:
  - "7861:7860"  # 将外部端口改为7861

然后重新启动:docker-compose up -d

Q: 模型文件太大,下载或加载慢怎么办?

A: 可以考虑以下优化:

  1. 使用更轻量级的模型(如果项目支持)
  2. 将模型文件放在SSD硬盘上
  3. 增加Docker容器的内存限制

Q: 识别结果不准确怎么办?

A: 可能的原因和解决方法:

  1. 音频质量问题:尝试使用更清晰的音频文件
  2. 风格混合:有些歌曲确实包含多种风格元素
  3. 模型局限性:当前模型只训练了16种流派,对于其他风格可能识别不准
  4. 预处理问题:尝试关闭FFmpeg预处理,使用原始文件

Q: 如何查看更详细的日志?

A: 使用以下命令查看详细日志:

# 查看所有服务的详细日志
docker-compose logs --tail=100

# 查看特定时间段的日志
docker-compose logs --since="10m"

# 实时查看日志
docker-compose logs -f

Q: 如何更新代码或配置?

A: 修改代码后,需要重新构建和启动:

# 重新构建并启动
docker-compose up -d --build

# 或者先停止再启动
docker-compose down
docker-compose up -d

5.3 性能优化建议

硬件要求:

  • CPU:至少4核,推荐8核以上
  • 内存:至少4GB,推荐8GB以上(模型加载需要约2GB内存)
  • 磁盘:至少10GB可用空间(模型文件466MB)

Docker资源限制: 你可以在docker-compose.yml中设置资源限制:

services:
  music-genre-app:
    # ... 其他配置 ...
    deploy:
      resources:
        limits:
          cpus: '2'
          memory: 4G
        reservations:
          cpus: '1'
          memory: 2G

缓存优化: 系统会缓存处理后的音频文件,避免重复处理。缓存文件保存在app/processed_audio目录,定期清理可以释放磁盘空间。

6. 总结

通过本文的教程,你已经成功使用Docker Compose部署了一个完整的音乐流派分类系统。这个方案有以下几个优点:

部署简单:只需要一个docker-compose up -d命令就能启动所有服务,无需手动安装各种依赖。

环境隔离:所有组件都在Docker容器中运行,不会影响宿主机的环境,也避免了版本冲突问题。

服务化架构:将音频预处理(FFmpeg)和主应用分离,提高了系统的可维护性和扩展性。

易于扩展:如果需要增加新的功能或服务,只需要在docker-compose.yml中添加新的服务配置即可。

跨平台运行:无论是在Linux、macOS还是Windows上,只要安装了Docker,都能以相同的方式运行。

这个项目不仅是一个技术演示,更是一个实用的工具。你可以用它来:

  • 整理个人音乐库,自动添加流派标签
  • 分析音乐作品的风格特征
  • 作为音乐推荐系统的一部分
  • 教育用途,帮助学习音乐分类

如果你对系统有任何改进建议,或者遇到了问题,欢迎根据实际情况进行调整。Docker Compose的灵活性让你可以轻松修改配置、添加新功能或优化性能。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

更多推荐