Architecture Document

JYI AI Music Score 项目框架与 API 接口说明

本项目是一个面向歌曲上传、AI 乐谱生成、歌词同步、自动分谱、线上曲库、额度计费和后台管理的单体 Node.js 应用。后端集中在 server.js,前端静态页面在 public/,AI 转谱与音频分析能力由 tools/ 下的 Python 脚本配合完成。

Node.js HTTP Server PostgreSQL / SQLite fallback Aliyun OSS AI Worker Queue MusicXML / MIDI / PDF Systemd Timers

当前系统边界

当前版本已经具备上传、生成、分谱、歌词、账户、套餐、后台、OSS、备份清理等能力。真实微信/支付宝回调、正式短信/邮件服务商、版权投诉闭环仍属于外部配置或后续扩展项。

用户端

落地页、登录注册、歌曲上传、生成主谱、阅读器、编辑器、曲库、账户中心和购买套餐入口。

服务端

Node.js 单体服务处理认证、任务队列、AI 调用、文件下载鉴权、OSS 同步、订单和后台管理。

数据与文件

用户、订单、额度、流水保存在 PostgreSQL;任务文件在本地共享存储,并按条件同步到 OSS。

整体框架图

请求从浏览器进入 Nginx/ECS,再到 Node 服务。Node 服务根据业务场景访问 PostgreSQL、OSS、本地 storage 和 Python AI 工具。

用户浏览器落地页 / App / Admin / Reader
备案访问入口IP、域名、Nginx 反向代理
Node.js server.jsAPI、静态页面、任务队列、鉴权
Session Cookiejyi_session 登录态
业务模块认证、曲库、转谱、歌词、订单、后台
AI Worker串行/限并发处理生成任务
下载鉴权无损下载额度、OSS 签名链接
PostgreSQL用户、订单、额度、流水、审计
storage/任务文件、上传文件、缓存、备份
Aliyun OSSPDF、MIDI、MusicXML、无损源音频
Python Tools音频检测、转谱、分谱、转调

分层结构图

该项目没有拆成多个微服务,当前是“单体服务 + 后台任务 + 外部存储”的结构。优点是部署简单,后续可以把 AI Worker 单独拆出。

表现层
landing.html官网落地页、价格、协议入口
index.html + app.js用户主应用
admin.html + admin.js后台管理
terms/privacy协议与隐私政策
API 层
认证 API登录、注册、验证码、资料
任务 API上传、生成、重跑、状态
曲库 APIOSS 线上曲库、审核发布
后台 API用户、额度、订单、财务、监控
业务层
AI Queue任务排队、重试、状态进度
Billing免费次数、额度扣减、下载收费
Lyrics本地歌词、内嵌歌词、联网搜索
Part Scores总谱、主唱谱、乐器分谱
数据与基础设施
PostgreSQL核心业务数据
OSS对外文件存储
本地 storage任务目录与缓存
systemd timers备份与清理

核心业务流程

下面是当前实现中最重要的四条链路:注册登录、生成乐谱、线上曲库、付费下载。

1. 登录注册流程

  • 用户提交邮箱、手机号、密码、邀请码。
  • 后端校验邮箱验证码、手机验证码和邀请码。
  • 密码使用 scrypt hash 保存,不保存明文。
  • 登录成功后写入 jyi_session Cookie。

2. 乐谱生成流程

  • 上传音频到 storage/uploads
  • 创建任务,进入 taskQueue
  • 检测音频质量,标准化为 source.wav
  • 调用 Python 工具生成 MusicXML、MIDI、PDF。
  • 任务完成后同步分数文件到 OSS。

3. 线上曲库流程

  • 任务必须完成,并且音频判定为无损。
  • 后端把 source.wav 同步到 OSS。
  • 管理员在后台审核为“公开”。
  • 用户端曲库只展示已公开的无损 OSS 曲目。

4. 下载计费流程

  • 普通 PDF/MIDI/MusicXML 下载不按无损扣费。
  • 下载无损源音频或包含无损源音频的打包文件时检查额度。
  • 第一次无损下载消耗 download_credits
  • OSS 下载使用签名 URL,避免裸暴露私有访问能力。

目录结构图

核心代码集中在以下目录。storage/ 是运行时数据目录,部署脚本已排除它,防止发版覆盖线上数据。

JYI AI Music Score/ ├─ server.js # Node.js 单体后端:API、静态资源、任务队列、OSS、DB ├─ package.json # npm scripts:dev/start ├─ requirements-ai.txt # Python AI 依赖清单 ├─ public/ │ ├─ landing.html # 落地页、价格展示 │ ├─ index.html # 用户主应用 │ ├─ app.js # 用户端交互逻辑 │ ├─ admin.html # 后台管理页面 │ ├─ admin.js # 后台交互逻辑 │ ├─ styles.css # 全站样式 │ ├─ i18n.js # 多语言替换 │ ├─ terms.html # 用户协议 │ ├─ privacy.html # 隐私政策 │ └─ project-architecture.html # 当前项目文档 ├─ tools/ │ ├─ analyze_audio.py # 音频质量、采样率、无损等分析 │ ├─ transcribe_score.py # AI 转谱入口 │ ├─ instrument_parts.py # 乐器识别与分谱 │ ├─ score_timeline.py # 乐谱时间轴 │ ├─ transpose_score.py # 转调输出 │ └─ check_ai_env.py # AI 环境检测 ├─ deploy/ │ ├─ push-release.sh # 本地推送 release 到服务器 │ ├─ release-switch.sh # 服务器切换 current release │ ├─ jyi-score.service # 主服务 systemd unit │ ├─ nginx-jyiscore.cn.conf # Nginx 反向代理配置 │ ├─ backup-postgres.sh # PostgreSQL 备份脚本 │ ├─ cleanup-storage.sh # 本地任务/缓存清理脚本 │ ├─ jyi-score-backup-postgres.* # 备份 systemd service/timer │ └─ jyi-score-cleanup-storage.* # 清理 systemd service/timer └─ storage/ ├─ uploads/ # 用户上传原始音频 ├─ songs/<taskId>/ # 单个任务工作目录 ├─ stem-cache/ # 去人声缓存 ├─ tasks.json # 文件态任务索引 ├─ auth.json # 文件态认证兼容数据 └─ backups/ # 线上 shared backups 链接目录

核心模块说明

当前后端没有拆文件,模块边界主要通过函数族体现。后续代码量继续增长时,建议按这些边界拆分。

模块主要函数/文件职责后续拆分建议
认证与会话currentUsercreateSessionsendEmailCode登录、注册、验证码、Cookie 会话。拆成 auth.service.js
任务队列enqueueTaskdrainTaskQueueprocessTaskAI 任务排队、状态、重试、进度。拆成独立 Worker 或 BullMQ。
AI 转谱tools/transcribe_score.pytools/analyze_audio.py分析音频、生成主谱、导出文件。独立 AI Worker 服务。
分谱startPartJobgeneratePartScoresinstrument_parts.py总谱拆分、乐器识别、声部 PDF/MIDI。拆为 part-score 服务。
歌词readLyricsForTaskfetchOnlineLyricssaveManualLyrics本地歌词、联网搜索、手动保存、时间轴建议。增加歌词源适配器。
OSSuploadFileToOsssyncTaskArtifactsToOssossDownloadUrl上传任务产物、生成签名下载 URL。拆成 storage adapter。
订单与额度createPlanOrdermarkOrderPaidconsumeCredit套餐、订单、额度扣减、退款登记。接入真实支付回调。
后台管理admin.js/api/admin/*用户、邀请、订单、财务、曲库审核、系统监控。增加筛选、分页、操作确认。

数据库结构

线上优先使用 PostgreSQL;开发环境可回退 SQLite。下表列出当前 schema 中的核心表。

表名用途关键字段
users用户基础数据。email、phone、role、status、password_hash
invite_codes邀请码。code、order_id、max_uses、used_count、status
purchase_requests购买邀请码申请。email、phone、note、status、order_id
plans套餐和价格。price_cents、score_credits、enhanced_credits、download_credits
invite_orders订单主表。order_no、user_id、plan_id、amount_cents、status
payments支付记录。provider、provider_trade_no、status、paid_at
ledger_entries财务流水。direction、amount_cents、memo
refunds退款登记。order_id、amount_cents、status、reason
user_quotas用户额度。score_credits、enhanced_credits、download_credits、task_quota
usage_events额度使用事件。song_key、type、free、metadata_json
user_entitlements套餐权益发放记录。order_id、plan_id、expires_at
ai_tasksAI 任务镜像。status、step、progress、metadata_json
audit_logs后台审计日志。actor_user_id、action、target_type、detail_json

API 接口清单

除公开接口外,/api/*/audio/*/view/*/download/* 默认要求登录。后台接口要求 super_admin

方法路径权限用途主要参数/返回
GET/api/health公开健康检查。返回服务、队列、任务、内存、OSS/DB 状态。
GET/api/plans公开套餐和价格。返回活动价套餐、免费生成次数。
GET/api/auth/me公开读取当前登录用户。返回 user、admin、quota、entitlement。
POST/api/auth/email-code公开发送邮箱验证码。body: email、purpose。
POST/api/auth/phone-code公开发送手机验证码。body: phone、purpose。
POST/api/auth/register公开注册并登录。body: email、phone、password、inviteCode、验证码、acceptTerms。
POST/api/auth/login公开密码或验证码登录。body: login、password 或 code。
POST/api/auth/logout登录退出登录。清理 session cookie。
PATCH/api/auth/profile登录更新昵称。body: name。
POST/api/auth/purchase-invite公开提交购买邀请码申请。body: email、phone、note。
POST/api/auth/oauth/:provider公开第三方登录预留。当前返回 501,需要配置 OAuth。
GET/api/me/purchases登录我的购买申请和订单。返回 requests、orders。
GET/api/me/entitlements登录我的额度权益。返回 quota、订阅状态、最近生成次数。
POST/api/orders登录创建套餐订单。body: planId;当前支付方式为 manual。
PUT/api/uploads?name=...登录上传音频文件。返回服务器本地 path、bytes。
GET/api/library登录线上曲库。返回已审核公开的无损 OSS 曲目。
GET/api/engines登录AI 环境检测。Basic Pitch、librosa、pretty_midi、music21、Demucs 等状态。
GET/api/tasks登录任务历史。query: limit;返回任务摘要。
POST/api/tasks登录创建 AI 转谱任务。body: path、mode;可能返回 402 需要额度。
GET/api/tasks/:id登录读取任务详情。返回任务、报告、输出文件。
GET/api/tasks/:id/preview登录读取可编辑音符预览。解析 MusicXML 返回 notes。
GET/api/tasks/:id/pages登录生成/读取乐谱 SVG 页。返回 pages。
GET/api/tasks/:id/layout登录乐谱布局时间轴。返回 measure/page layout。
GET/api/tasks/:id/lyrics登录读取歌词。同名 LRC/KRC、内嵌歌词、缓存歌词。
POST/api/tasks/:id/lyrics登录保存手动歌词。body: text。
POST/api/tasks/:id/lyrics-search登录联网搜索歌词。LRCLIB、酷狗等候选,保存缓存。
GET/api/tasks/:id/performers登录读取/推断演唱者。返回 performers。
POST/api/tasks/:id/no-vocals登录生成去人声音轨。优先复用 stem cache。
POST/api/tasks/:id/rerun登录重新生成任务。body: mode;可能扣主谱/增强额度。
POST/api/tasks/:id/transpose登录生成转调谱。body: semitones。
GET/api/tasks/:id/parts登录读取分谱目录。返回总谱、声部分谱、MIDI、排练音频。
POST/api/tasks/:id/parts登录提交分谱任务。进入 part job。
GET/api/tasks/:id/parts/job登录读取分谱任务状态。返回 progress、step、status。
POST/api/tasks/:id/sync登录保存歌词/乐谱同步校准。body: lyricsOffsetMs、lyricsScale、scoreOffsetMs、scoreScale。
GET/audio/:id/source登录播放源音频。返回 audio stream。
GET/audio/:id/no-vocals登录播放去人声音频。返回 audio stream。
GET/view/:id/:file登录在线预览谱面文件。优先 OSS redirect。
GET/download/:id/:file登录下载单个文件。无损源音频会校验下载额度。
GET/download-all/:id登录打包下载任务文件。包含无损源音频时校验下载额度。
GET/api/admin/users超管用户列表。返回用户和额度摘要。
PATCH/api/admin/users/:id超管调整用户角色/状态。body: role、status。
POST/api/admin/quotas/:userId超管手动调整额度。body: scoreCredits、enhancedCredits、downloadCredits、taskQuota、reason。
GET/api/admin/invites超管邀请码列表。返回 invite codes。
POST/api/admin/invites超管创建邀请码。body: note、maxUses、expiresAt。
PATCH/api/admin/invites/:id超管启停邀请码。body: status、note。
GET/api/admin/purchase-requests超管购买申请列表。返回 requests。
PATCH/api/admin/purchase-requests/:id超管审核购买申请。approved 会自动建单。
GET/api/admin/orders超管订单列表。返回订单和邀请码。
POST/api/admin/orders超管手动建单。body: email、phone、planId、amountCents。
POST/api/admin/orders/:id/mark-paid超管标记订单已支付。发放额度、权益或邀请码。
POST/api/admin/orders/:id/refund超管登记退款。body: amountCents、reason;写入 refunds 和 ledger。
GET/api/admin/library超管线上曲库审核池。返回无损已完成任务。
POST/api/admin/library/:id/publish超管审核曲库公开状态。body: status=approved/rejected/pending。
GET/api/admin/finance超管财务概览。summary、ledger、payments、refunds。
GET/api/admin/system超管系统监控。队列、任务、存储占用、集成状态、近期错误。

部署与运维结构

线上目录使用 release 切换模式,当前代码指向 /opt/jyi-ai-music-score/current,共享数据保存在 /opt/jyi-ai-music-score/shared

发布

本地执行 deploy/push-release.sh,脚本 rsync 到服务器 releases 目录,再由 release-switch.sh 切换 current 并重启服务。

服务

jyi-score.service 托管 Node 服务,Nginx 负责域名和端口代理。

定时任务

jyi-score-backup-postgres.timer 每天备份数据库;jyi-score-cleanup-storage.timer 每天清理缓存和异常任务。

线上已启用 systemd timer:备份约每天 03:00 执行,清理约每天 03:30 执行。备份目录为 /opt/jyi-ai-music-score/shared/backups/postgres

后续缺口与拆分建议

下面这些不是“页面没写”,而是需要外部配置、商户资料或更大工程拆分才能可靠上线。

外部服务接入

  • 微信/支付宝真实支付回调:需要商户号、证书、回调域名。
  • 正式短信:需要短信签名、模板 ID、服务商 AccessKey。
  • 正式邮件:需要 SMTP 或邮件 API 服务商。

架构拆分

  • AI Worker 从 Node 主进程拆出,使用 Redis/BullMQ 或 PostgreSQL 队列。
  • 文件存储抽象为 OSS adapter,后续可接 CDN。
  • 后台操作增加分页、筛选、二次确认和批量处理。

版权与公开曲库

  • 线上曲库当前已有管理员审核,仍建议补充版权声明、投诉入口、下架流程。
  • 用户上传内容可见范围需要进一步区分私有、公开、审核中。

乐谱质量

  • 逐小节人工校对和版本管理。
  • 歌词、乐谱、音频三者时间轴更细粒度校准。
  • 分谱结果需要更强的乐器识别和 PDF 排版能力。