ccmusic-database实操手册:将预测结果写入CSV/MySQL,构建流派分析数据库
1. 为什么需要把预测结果存进数据库?
你已经跑通了ccmusic-database的Web界面,上传一首歌,几秒后就能看到“交响乐 87.3%”“室内乐 9.2%”这样的结果。但问题来了——如果今天分析了20首,明天又分析了50首,这些结果散落在浏览器里,没法查、没法比、更没法做趋势分析。
这就像厨师做完菜只端上桌就不管了,从不记录用了多少盐、火候多大、客人反馈如何。而真正的音乐分析工作流,需要的是可追溯、可统计、可复盘的数据资产。
本手册不讲模型原理,不调参,不重训练。我们聚焦一个工程师每天都会遇到的真实动作:把一次推理的结果,稳稳当当地落库——支持导出为CSV供Excel分析,也支持写入MySQL做长期积累和查询。所有操作都在你已有的app.py基础上增量修改,5分钟内可完成,零风险。
2. 理解ccmusic-database的输出结构
在动手写入库逻辑前,先看清它“吐出来”的是什么。打开app.py,找到核心推理函数(通常在predict()或类似命名的方法中),你会发现它最终返回的是一个形如:
[('Symphony', 0.873), ('Chamber', 0.092), ('Solo', 0.021), ('Opera', 0.008), ('Pop vocal ballad', 0.006)]这是一个长度为5的Python列表,每个元素是(流派名称, 概率值)的元组。注意两点:
- 流派名称和文档中表格完全一致,比如是
'Symphony'而不是'交响乐'(中文显示是前端做的映射) - 概率值是浮点数,范围0–1,总和不强制为1(因是Top5截断)
这个结构就是我们入库的“原始数据源”。不需要碰模型权重、不改特征提取流程,只在结果生成后加一层“搬运工”逻辑。
3. 方案一:一键导出CSV——轻量、可分享、免部署
CSV是最通用的数据交换格式。它不依赖数据库服务,双击能用Excel打开,发给同事即刻可用。适合快速验证、小批量分析或临时归档。
3.1 修改app.py:添加CSV导出功能
打开/root/music_genre/app.py,在文件末尾(demo.launch(...)之前)插入以下代码:
import csv import os from datetime import datetime def save_to_csv(filename, audio_name, predictions): """将单次预测结果保存为CSV行""" timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 构造一行数据:时间、音频名、Top5流派及概率 row = [timestamp, audio_name] for genre, prob in predictions: row.extend([genre, f"{prob:.4f}"]) # CSV文件路径(与app.py同目录) csv_path = "predictions.csv" # 第一次写入时添加表头 file_exists = os.path.isfile(csv_path) with open(csv_path, "a", newline="", encoding="utf-8") as f: writer = csv.writer(f) if not file_exists: # 表头:时间、音频名、流派1、概率1、流派2、概率2…… headers = ["timestamp", "audio_name"] for i in range(1, 6): headers.extend([f"genre_{i}", f"prob_{i}"]) writer.writerow(headers) writer.writerow(row) # 在你的 predict() 函数返回 predictions 后,立即调用它 # 例如,在 predict() 函数末尾添加: # save_to_csv("predictions.csv", audio_filename, predictions)3.2 在预测函数中触发保存
找到predict()函数(或你实际执行推理的函数),在它返回predictions前,加入一行调用:
# 假设你已有 audio_filename 变量(Gradio会传入) save_to_csv("predictions.csv", audio_filename, predictions)小提示:Gradio上传的文件对象默认有
.name属性,但可能带路径。建议用os.path.basename(audio_file.name)安全提取文件名。
3.3 效果验证
重启服务:python3 /root/music_genre/app.py
上传一首beethoven_symphony.mp3,点击分析。
立刻检查项目根目录,会出现predictions.csv,内容类似:
timestamp,audio_name,genre_1,prob_1,genre_2,prob_2,genre_3,prob_3,genre_4,prob_4,genre_5,prob_5 2024-05-20 14:22:35,beethoven_symphony.mp3,Symphony,0.8730,Chamber,0.0920,Solo,0.0210,Opera,0.0080,Pop vocal ballad,0.0060成功!每次分析都追加一行,时间戳+文件名+完整Top5,开箱即用。
4. 方案二:写入MySQL——可查询、可关联、可扩展
当分析量达到数百首以上,CSV会变得难管理:无法按“交响乐概率>0.8”筛选,不能统计“本周灵魂乐出现频次”,更无法和歌手、专辑等其他表关联。这时,MySQL就是自然选择。
4.1 准备数据库环境
确保你已安装MySQL服务(本地或远程均可)。执行以下SQL建表语句:
CREATE DATABASE IF NOT EXISTS music_analysis CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE music_analysis; CREATE TABLE IF NOT EXISTS predictions ( id BIGINT AUTO_INCREMENT PRIMARY KEY, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, audio_name VARCHAR(255) NOT NULL, genre_1 VARCHAR(100), prob_1 DECIMAL(5,4), genre_2 VARCHAR(100), prob_2 DECIMAL(5,4), genre_3 VARCHAR(100), prob_3 DECIMAL(5,4), genre_4 VARCHAR(100), prob_4 DECIMAL(5,4), genre_5 VARCHAR(100), prob_5 DECIMAL(5,4), INDEX idx_audio_name (audio_name), INDEX idx_genre1 (genre_1), INDEX idx_created (created_at) );字段说明:
DECIMAL(5,4)表示最多5位数字,其中4位小数(如0.8730),精准存储概率;索引提升常用查询速度。
4.2 安装并配置Python MySQL驱动
在项目环境中安装pymysql(轻量、纯Python,无需编译):
pip install pymysql4.3 修改app.py:添加MySQL写入逻辑
在app.py顶部导入:
import pymysql from pymysql.cursors import DictCursor在文件某处(如全局变量区)定义数据库连接配置(请按实际修改):
DB_CONFIG = { "host": "localhost", "user": "your_username", "password": "your_password", "database": "music_analysis", "charset": "utf8mb4" }然后添加写入函数:
def save_to_mysql(audio_name, predictions): """将预测结果写入MySQL predictions表""" try: conn = pymysql.connect(**DB_CONFIG) with conn.cursor() as cursor: # 构造INSERT语句(安全,防SQL注入) sql = """ INSERT INTO predictions (audio_name, genre_1, prob_1, genre_2, prob_2, genre_3, prob_3, genre_4, prob_4, genre_5, prob_5) VALUES (%s, %s, %s, %s, %s, %s, %s, %s, %s, %s, %s) """ # 提取Top5数据,不足5个则补NULL values = [audio_name] for i in range(5): if i < len(predictions): genre, prob = predictions[i] values.extend([genre, prob]) else: values.extend([None, None]) cursor.execute(sql, values) conn.commit() except Exception as e: print(f"[MySQL Error] Failed to save {audio_name}: {e}") finally: if 'conn' in locals(): conn.close() # 在 predict() 函数中调用它,位置同CSV方案 # save_to_mysql(audio_filename, predictions)4.4 验证MySQL写入
重启服务,上传音频。登录MySQL执行:
SELECT * FROM music_analysis.predictions ORDER BY id DESC LIMIT 3;你会看到类似结果:
| id | created_at | audio_name | genre_1 | prob_1 | genre_2 | prob_2 | ... |
|---|---|---|---|---|---|---|---|
| 42 | 2024-05-20 14:35:11 | beethoven_symphony.mp3 | Symphony | 0.8730 | Chamber | 0.0920 | ... |
数据已落库。现在你可以自由查询:
SELECT COUNT(*) FROM predictions WHERE genre_1 = 'Soul / R&B';SELECT AVG(prob_1) FROM predictions WHERE genre_1 = 'Dance pop';SELECT audio_name FROM predictions WHERE prob_1 > 0.95;
5. 进阶技巧:让数据库真正“活”起来
光存数据不够,要让它产生业务价值。这里提供3个即插即用的小技巧,全部基于你已有的MySQL表。
5.1 自动统计:每周流派热度排行榜
创建一个视图,自动聚合最近7天Top1流派的出现次数:
CREATE VIEW weekly_genre_rank AS SELECT genre_1 AS genre, COUNT(*) AS count, ROUND(AVG(prob_1), 4) AS avg_confidence FROM predictions WHERE created_at >= DATE_SUB(NOW(), INTERVAL 7 DAY) GROUP BY genre_1 ORDER BY count DESC;查询:SELECT * FROM weekly_genre_rank;—— 你立刻得到一份带置信度的热度榜。
5.2 批量分析:用SQL替代脚本处理历史音频
假设你有一批MP3放在/data/audio/,想批量分析并入库。传统做法是写Python循环调用Gradio API,但更简单的是:
- 先用Shell命令生成CSV清单:
ls /data/audio/*.mp3 | xargs -I{} basename {} >> batch_list.txt - 把
batch_list.txt内容复制进MySQL,用LOAD DATA INFILE直接导入为临时表 - 用
JOIN和UPDATE语句,把预测结果批量关联到这批文件上
——整个过程在数据库内完成,无需启动Python环境。
5.3 可视化对接:一行命令导出JSON供ECharts使用
很多前端图表库(如ECharts)直接读取JSON。用MySQL命令行一键导出:
mysql -u your_user -p -D music_analysis -e " SELECT genre_1, COUNT(*) as count FROM predictions WHERE created_at >= '2024-05-01' GROUP BY genre_1 ORDER BY count DESC" \ --batch --raw --skip-column-names \ | sed 's/\t/,/g' | awk -F',' '{print "{\"genre\":\""$1"\",\"count\":"$2"}"}' \ | sed ':a;N;$!ba;s/\n/,/g' | sed 's/^/[/' | sed 's/$/]/' > genre_stats.json生成的genre_stats.json可直接被网页加载,实现“分析结果→实时图表”的闭环。
6. 常见问题与避坑指南
实际落地时,总会遇到几个高频卡点。这里不是罗列报错,而是告诉你为什么错和怎么永绝后患。
6.1 “CSV中文乱码,Excel打开全是问号”
原因:Windows记事本和Excel默认用GBK编码读取文件,而Pythoncsv.writer默认UTF-8。
解法:在open()中显式指定encoding="utf-8-sig"(注意-sig后缀):
with open(csv_path, "a", newline="", encoding="utf-8-sig") as f:-sig会在文件开头写入BOM标记,Excel就能正确识别UTF-8。
6.2 “MySQL插入时报错:Incorrect string value”
原因:数据库/表字符集不是utf8mb4,无法存储emoji或某些生僻中文。
解法:建库时务必用:
CREATE DATABASE music_analysis CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;并确认my.cnf中已设置:
[client] default-character-set = utf8mb4 [mysqld] character-set-server = utf8mb4 collation-server = utf8mb4_unicode_ci6.3 “Gradio上传大文件失败,或分析超时”
原因:Gradio默认限制上传大小(2MB)和请求超时(60秒),而30秒音频的CQT频谱图可能超限。
解法:在app.py启动前,设置环境变量:
import os os.environ["GRADIO_TEMP_DIR"] = "/tmp/gradio" # 指向大空间目录 os.environ["GRADIO_MAX_FILE_SIZE"] = "100000000" # 100MB os.environ["GRADIO_SERVER_TIMEOUT"] = "300" # 300秒 # 然后再 launch demo.launch(server_port=7860)6.4 “想存更多字段,比如音频时长、采样率、艺术家”
解法:不要改现有表结构。新建一张audio_metadata表,用audio_name作为外键关联:
CREATE TABLE audio_metadata ( id BIGINT PRIMARY KEY AUTO_INCREMENT, audio_name VARCHAR(255) UNIQUE, duration_sec FLOAT, sample_rate INT, artist VARCHAR(255), album VARCHAR(255), INDEX idx_name (audio_name) );后续分析时,INSERT ... ON DUPLICATE KEY UPDATE即可自动合并元数据与预测结果。
7. 总结:从单次推理到数据资产的跨越
你现在已经掌握了两个核心能力:
- 用CSV,5分钟搭起最小可行分析单元——适合个人探索、快速验证、跨平台共享;
- 用MySQL,10分钟构建可生长的数据底座——支持查询、统计、关联、可视化,为后续加标签、建推荐、做趋势打下基础。
这不是终点,而是起点。ccmusic-database的价值,从来不在“它能分对一首歌”,而在于“它能持续、稳定、可追溯地告诉我们:听众在听什么,喜欢什么,变化是什么”。
下一步,你可以:
- 把
predictions表接入Grafana,做实时流派热力图; - 用
genre_1字段训练一个简单分类器,预测“哪些新歌最可能成为爆款”; - 把
audio_name和公开音乐平台API打通,自动补全专辑、年份、风格标签。
技术没有高下,只有是否解决真问题。你写的每一行入库代码,都在把AI的“瞬间判断”,变成组织可沉淀的“长期认知”。
获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。