PianoReel · 项目状态(单一信源)

一页讲清:目标、现在的进度、产品最终形态。其它文档:架构看
ARCHITECTURE.md,形态发散看 14-formats-and-vision.md
YouTube 导入看 13-youtube-import.md。最后更新:2026-06-07。

1. 目标

一句话:让任何人把一首歌一键变成可直接发布的竖屏钢琴短视频,并能下载
歌曲、谱子、封面。

(对标 Rousseau / Synthesia 主流格式,并叠加歌词/原视频/氛围等模式)。


2. 现在的进度

阶段:本地端到端闭环已跑通;上线阶段 1 完成(前端已部署公网)。 后端上云 / 账号 / 付费未开始。

🌐 已上线(阶段 1):前端静态站部署到 Cloudflare Workers 静态资源,域名 pianoreel.com(Cloudflare Registrar 注册)。
开发/预览地址 dev.pianoreel.com(已绑定,每次 push 自动重部署);主域 pianoreel.com 留给正式发布;底层 pianoreel.zhukui83.workers.dev
线上 config.js 自动判定为"无后端":示例曲/MIDI/全部特效/导出可用;MP3·YouTube·歌词等需等阶段 2 后端上 Modal。部署配置见 wrangler.jsonc,步骤见 docs/17。

✅ 已完成(可用并验证)

输入

编曲

工作室(出片)

导出

工程

/lyrics /render /sheet /transcode /transcribe /health`

🔄 进行中 / 待打磨(非阻塞)

⏳ 未开始(商业化,需产品决策)

关键指标

指标目标当前
端到端闭环(上传→出片→下载)跑通✅ 本地跑通
出片模式数多样✅ 4 模式 + 片头/封面
导出格式视频+歌+谱+封面✅ MP4/MP3/PDF/MIDI/PNG
单曲出片耗时<2 分钟✅ ~15-60s(编曲)
商业化(账号/付费/部署)上线⏳ 未开始
版权策略明确⚠️ 未解

3. 产品最终形态(北极星)

粘贴链接 / 上传一首歌 → 一条可直接发布的竖屏钢琴短视频。

不是"只有一种落音符动画",而是一个可叠层、可切模式的出片台

[ 基底 ] 落音符 + 88 键 + 主题/预设            (招牌,已完成)
[叠层] 歌词卡拉OK · 片头/片尾卡 · 原视频(分屏/背景)
[调校] 竖屏 · 副歌精华 · 情感慢速 · 高级感预设
            ↓ 一键切 4 种模式
   🎹 演奏(可弹/演奏感) · 🎤 歌词(传唱/情感) · 🎬 对比(反差/关注) · 🌙 氛围(放松BGM)
            ↓ 一键导出
   MP4 视频 + 谱子 + 高音质音频 + 封面 —— 开箱即发

分发形态:双轨(见 docs/23)

完整形态还需补齐(商业化层):账号与作品库 → 订阅/配额 → 桌面打包 →
版权合规与(可选)授权曲库。技术内核已具备,缺的是"产品化 + 上线 + 合规"。


一句话总结

内核做完了(上传/链接 → 编曲 → 4 模式工作室 → 多格式导出,本地端到端跑通);
接下来是产品化与上线(账号、付费、部署、版权),这些需要你的方向决策。

01 · 商业方案 (Business Plan)

产品定名:PianoReel(「钢琴短视频,一键生成」)
命名考量:含 piano(SEO 易搜到 "piano visualizer")+ Reel(直指短视频/Reels,喊话创作者)。
一句话:上传任意音乐(MP3),自动生成「钢琴键盘随音乐演奏发光 + 音符下落」的高质量可视化视频。

1. 愿景与定位

把"音乐可视化视频"从专业门槛(需要 DAW、MIDI、After Effects、几小时手工)变成一键生成(上传 MP3 → 几分钟出片)。

对标产品的体验感:SeeMusic / Synthesia / PianoVision,但核心差异在于——
对手大多需要你先有 MIDI 文件,而我们解决的是"我只有一个 MP3 / 一段录音 / 一首歌"这个更普遍的入口。

定位句:

"Canva for music visualization" —— 不会编曲、不懂 MIDI 的人也能做出专业级的钢琴演奏视频。
业务边界(重要):我们是纯工具/服务——不提供曲库、不托管或分发音乐
音源完全由用户自带(上传自己的 MP3/录音/MIDI)。这既是产品定位,也是版权风险的关键缓解(见 §6)。

2. 市场与竞品

2.1 目标市场

市场描述规模信号
YouTube / B站 音乐区创作者钢琴翻弹、Lo-fi、放松音乐、Cover 视频钢琴教学/翻弹是 YouTube 长青品类,单频道百万订阅常见
短视频内容工厂TikTok / Reels / 抖音 上的音乐可视化内容号批量产出、靠量变现,对自动化付费意愿强
钢琴学习者 / 老师把曲子可视化辅助练习(类 Synthesia)全球钢琴学习是数千万级人群
音乐人 / 独立厂牌给单曲做 lyric-video 的替代品(视觉化 MV)每首新歌都需要视觉物料
企业/B2B API音乐 App、教育平台想集成可视化按调用付费

2.2 竞品对比

产品输入核心能力痛点(我们的机会)
SeeMusic (Visual Musician)主要 MIDI / 部分音频漂亮的可视化主题、导出视频桌面软件、上手门槛、音频转写质量有限
SynthesiaMIDI钢琴教学瀑布流偏教学、视觉相对朴素、需 MIDI
PianoVision (VR)MIDIVR 弹琴场景不同(硬件)
各类 AE 模板手工完全可定制极高人工成本
通用音频可视化 (如 Specterr)MP3频谱/波形动画不是"演奏"语义,没有"哪个键被按下"

我们的护城河方向

  1. MP3 → 演奏语义(音频转写 / Audio-to-MIDI)这一最难的环节做到足够好 + 配套"轻量人工校正"体验。
  2. Web/App 原生、零安装、模板化——把对手的"专业软件"做成"消费级 SaaS"。
  3. 风格资产库(主题、粒子、配色、相机运镜)形成内容差异化和品牌。

3. 价值主张


4. 商业模式与定价

采用 Freemium + 订阅 + 按量 组合:

档位价格(参考)内容
Free¥0720p、带水印、每月 N 首、基础主题
Creator~¥39 / 月1080p、去水印、全部主题、竖屏导出、更长时长
Pro~¥99 / 月4K、批量导出、音轨分离(左右手/人声)、自定义品牌、优先渲染队列
API / B2B按调用计费转写 + 渲染 API,给第三方集成
一次性 Credit 包按片付费不想订阅的轻度用户,按"出片数/分钟数"买点数

变现杠杆


5. 成本结构(单位经济 Unit Economics)

每生成一个视频的可变成本主要是计算

  1. 音频转写(MP3→MIDI):GPU/CPU 推理,几十秒~几分钟。
  2. 渲染出片
    • 方案 A(推荐 MVP):浏览器端实时渲染 + 客户端录制 → 服务器成本≈0(用户自己的 GPU 画)。
    • 方案 B:服务器端离线渲染 MP4(headless + ffmpeg),成本高但质量/一致性可控、适合 4K/批量。
  3. 存储 + CDN:成品视频分发。

关键策略:免费/低档用客户端渲染把成本压到接近零;高档(4K/批量/服务器一致性)才用服务器渲染并据此定价。这让 Freemium 在经济上可持续。

毛利目标:订阅档 70%+;API 档按定价覆盖推理成本 + 合理 markup。


6. 关键风险

风险说明缓解
版权 ⚠️ 最大风险用户上传受版权保护的音乐生成视频并传播① 定位"纯工具/服务,我们不提供曲库、不托管/分发音乐,用户自带音源",责任在用户(ToS);② 个人使用导向;③ 对公开发布走 Content ID 友好路径;④ 引导用户使用自己创作/已授权的音乐
转写质量复杂复调/带鼓的流行乐转 MIDI 难,易出错音① 先聚焦钢琴/简单编制;② 提供"轻量人工校正"编辑器;③ 源分离(Demucs)先抽钢琴轨
成本失控服务器渲染 4K 很贵客户端渲染优先 + 队列 + 缓存
同质化视觉效果被模仿持续做风格资产库 + 社区 + 品牌
法律提醒:版权是这个生意的核心合规问题。上线前需要正式的 ToS / 版权政策,建议咨询专业律师;本仓库文档不构成法律意见。

7. Go-To-Market

  1. 种子内容:自己用产品批量产出高质量视频,铺 YouTube/TikTok/小红书/B站,每条带水印导流。
  2. 创作者合作:找钢琴/音乐区中腰部创作者免费 Pro 换内容曝光。
  3. 模板/主题作为传播单元:每出一个爆款视觉风格 = 一波拉新。
  4. PLG:免费档无障碍出片 → 水印传播 → 自然转化付费去水印。
  5. B2B:在 PLG 跑通后,把转写+渲染能力封装成 API 卖给音乐/教育 App。

北极星指标:每周成功导出视频数(activated exports / week)。


8. 里程碑(商业视角)

详见 04-mvp-roadmap.md

02 · 产品需求 (Product Spec)

产品定名:PianoReel(「钢琴短视频,一键生成」)。面向 YouTube / Shorts / TikTok / 抖音 / B站 创作者。

0. 创作者便利清单 (Creator Conveniences)

把"专业软件"做成"创作者顺手的工具"是核心竞争力。下面是已在原型实现规划中的便利点。

已实现(原型工作室)

规划中(按创作者价值排序)

不做:曲库/内容分发。我们只提供工具/服务,音源由用户自带(见 01 商业方案)。

1. 用户画像 (Personas)

2. 核心用户旅程 (Happy Path)

上传 MP3 ──▶ 自动转写(MP3→音符) ──▶ 预览可视化 ──▶ (可选)校正音符
   ──▶ 选风格/主题/配色/画幅 ──▶ 导出视频 ──▶ 下载/分享

每一步都要可"提前看到结果"(实时预览),降低不确定感。

3. 功能清单 (Features)

3.1 输入

3.2 转写 (MP3 → 音符 JSON)

3.3 编辑 / 校正(差异化体验)

3.4 可视化 / 风格(原型已实现 12 种效果)

🎹 钢琴特效(产品主打,面向 YouTube 弹奏素材) —— js/piano-fx.js
共用下落音符+88键底座 + 可插拔「击键特效」,加新效果只需加一个 preset:

🎵 音频特效(通用背景) —— js/effects.js,实时 AnalyserNode 驱动:

其它(待做):

音频特效由实时音频分析驱动,换真实 MP3 即可复用;钢琴特效由音符 JSON 精确驱动击键时机。

3.5 导出

3.6 账户 / 商业

3.7 B2B

4. 非功能需求

5. Web vs App 分工

能力WebApp
创作/编辑/精修主力(大屏、卷帘编辑)简化版
录音输入次要主力
快速出片/分享主力(社交分享场景)
4K/批量触发服务器渲染,App 等通知
共享同一套「音符 JSON + 渲染内核」,Web/App/服务器渲染三端复用,保证一致性。这是架构的关键决策(见 03-technical-architecture.md)。

03 · 技术架构 (Technical Architecture)

本篇讲架构原理与目标态。第一版的具体部署选型、托管服务、计费机制、月成本06-mvp-v1.md §3–§4。

1. 设计原则

  1. 单一中间表示 (Single Source of Truth):一切围绕 音符 JSON(notes JSON)。

MP3 → 音符JSON → 像素。转写产出它,编辑修改它,三端渲染消费它。

  1. 同一渲染内核,多处复用:Web 预览、App、服务器导出共用同一份渲染逻辑(TypeScript),避免"预览和成品不一致"。
  2. 成本可控的渲染分层:免费/轻量用客户端渲染(成本≈0);高质量/批量/4K 用服务器渲染
  3. 可演进的转写:转写模型可替换(Basic Pitch → 更强模型/自研),接口不变。

2. 中间表示:音符 JSON

{
  "title": "Song name",
  "bpm": 120,
  "duration": 184.0,           // 秒
  "notes": [
    { "midi": 60, "start": 0.0, "dur": 0.5, "vel": 0.82, "hand": "R" }
    // midi: 21..108 ; start/dur: 秒 ; vel: 0..1 ; hand: "R"|"L"
  ]
}
原型里 prototype/web/js/songs.js 和后端
prototype/backend/transcribe.py 都用这个格式。

3. 系统全景

                         ┌──────────────────────────────────────────┐
   用户 (Web / App)      │                 前端                       │
   ─────────────▶        │  上传 UI · 实时预览(Canvas/WebGL渲染内核)   │
                         │  piano-roll 编辑器 · 客户端导出(MediaRec.)  │
                         └───────────────┬──────────────────────────┘
                                         │ HTTPS / REST
                         ┌───────────────▼──────────────────────────┐
                         │              API Gateway                  │
                         │   Auth · 计费/用量 · 限流 · 任务派发        │
                         └───────┬───────────────────────┬──────────┘
                                 │                        │
                  ┌──────────────▼───────┐     ┌──────────▼───────────┐
                  │  转写服务 (Worker)     │     │  渲染服务 (Worker)     │
                  │  源分离(可选 Demucs)   │     │  headless 渲染内核     │
                  │  Audio→MIDI(Basic     │     │  + ffmpeg → MP4 (4K)  │
                  │  Pitch等) → 音符JSON   │     │  (GPU 可选)           │
                  └──────────┬───────────┘     └──────────┬───────────┘
                             │                            │
                  ┌──────────▼────────────────────────────▼──────────┐
                  │     队列(SQS/Redis) · 对象存储(S3) · CDN · DB      │
                  └───────────────────────────────────────────────────┘

4. 组件与技术栈(建议)

选型建议理由
Web 前端TypeScript + React + Vite;渲染内核用 Canvas2D(MVP)→ WebGL/PixiJS(性能)生态成熟,渲染内核可独立成包跨端复用
渲染内核独立 npm 包 @pv/renderer,纯函数 render(notes, theme, t) → frameWeb/App/服务器共用,保证一致
移动 AppReact Native / Expo 或 Flutter;复用渲染内核(RN 可走 WebView/Skia)跨平台、复用度高
API 网关FastAPI (Python) 或 Node/NestJS转写在 Python 生态,FastAPI 顺手
转写 WorkerPython:Basic Pitch / (可选 Demucs 源分离)见技术深挖文档
渲染 WorkerNode + headless Chromium (Puppeteer/Playwright)Remotion,配 ffmpeg;或纯 ffmpeg+canvas复用同一 JS 渲染内核做离线出片
队列Redis / SQS异步长任务
存储/CDNS3 + CloudFront(或对应云)成品分发
DBPostgres用户/项目/用量
Auth/计费Clerk/Auth0 + Stripe快速上线

5. 两种渲染路径(重要权衡)

路径 A — 客户端实时渲染 + 录制(MVP 首选)

路径 B — 服务器端离线渲染(高级档)

决策:MVP 用 A 跑通闭环,把 B 留给 Pro/4K/批量。两者共用渲染内核。

6. 数据流(一次出片)

  1. 前端上传 MP3 → API 存到 S3,建任务入队。
  2. 转写 Worker:(可选源分离) → Audio→MIDI → 量化/分手 → 写入音符 JSON到 DB/S3。
  3. 前端拉取音符 JSON → 实时预览 + 用户可校正/选风格。
  4. 导出:
    • A:前端录制下载;
    • B:提交渲染任务 → 渲染 Worker 出 MP4 → S3/CDN → 通知用户下载。

7. 扩展性 / 后续

8. 本仓库原型与目标架构的对应

目标组件原型对应
渲染内核prototype/web/js/renderer.js + piano.js
中间表示prototype/web/js/songs.js(notes JSON)
播放/同步synth.js + app.js(音频时钟驱动)
转写服务prototype/backend/(FastAPI + Basic Pitch)
MIDI→JSONtools/midi_to_json.py

04 · MVP 范围与路线图

本篇是分阶段路线图(全景视角)。第一版的具体落地定稿(含怎么收费、怎么部署上线)见 06-mvp-v1.md

1. MVP 的一句话目标

用户上传一个 MP3,几分钟内得到一个可下载的「钢琴下落音符 + 键盘发光」视频。

闭环 = 上传 → 转写 → 预览 → 导出。其它全部砍掉。

2. MVP 范围 (Scope)

In(必须有)

Out(MVP 不做,留给后续)

3. 阶段与里程碑

阶段目标交付物粗估
P0 原型(本仓库)✅验证视觉与同步体验可运行 web 原型 + 文档已完成
P1 转写打通MP3→音符JSON 自动化后端转写服务 + 前端接入真实文件1–2 周
P2 闭环 MVP上传→预览→导出可下载客户端录制导出 + 主题/画幅 + 水印2–4 周
P3 商业化账户/订阅/付费墙登录 + Stripe + 用量2–3 周
P4 质量与规模4K/服务器渲染/编辑器/App渲染 Worker、piano-roll、RN App持续
时间为单人/小团队粗估,仅供排序参考。

4. 成功指标

5. 立即可做的下一步(从原型到 P1)

  1. 跑通 prototype/backend:本地 POST 一个 MP3 → 拿到音符 JSON
  2. 前端加"上传 MP3"按钮,调后端拿 JSON,喂给现有渲染内核。
  3. 用真实音频元素(<audio> 播 MP3)替换合成器,做音画同步对齐(offset 微调旋钮)。
  4. MediaRecorder 录制导出按钮,先导 webm/mp4。
  5. 用自己创作/已授权的曲子做 3 条 demo,铺第一批种子内容(产品本身不含曲库)。

6. 风险驱动的验证顺序

先验证最不确定的:转写质量到底够不够用
→ P1 先拿 10–20 首不同曲风的真实歌曲跑 Basic Pitch,人工评估"可用率",据此决定:

05 · 技术深挖:MP3 → 音符(最难的环节)

整个产品成败的核心在于:把任意音频转成"哪个键、什么时候、按多久"的演奏信息(Audio-to-MIDI / 自动音乐转写 AMT)。其余(渲染、UI)相对成熟。

1. 问题难度分级

输入难度说明
用户直接给 MIDI⭐ 容易直接解析,质量最高 → MVP 必须支持,作为兜底卖点
独奏钢琴录音⭐⭐ 中现有模型效果不错(Onsets&Frames、Basic Pitch)
单旋律乐器/人声哼唱⭐⭐ 中单音高跟踪较成熟
完整流行乐(鼓+贝斯+人声+和声)⭐⭐⭐⭐ 难复调 + 打击乐干扰,直接转易出错音 → 需源分离

策略:MVP 聚焦 ⭐~⭐⭐(钢琴/简单编制/MIDI 直传),复杂流行乐放到后续 + 源分离。

2. 可选技术方案

2.1 Audio→MIDI 转写模型

方案类型优点缺点适合
Spotify Basic Pitch开源、轻量易用、可本地跑、复调可用、支持多乐器复杂混音精度有限MVP 首选
Google Onsets & Frames开源钢琴转写经典、质量高偏钢琴、较重钢琴专精
Google MT3开源、Transformer多乐器、强重、部署成本高进阶
商业 API(各家)闭源省事成本、依赖第三方快速验证
自研/微调护城河投入大规模化后
本仓库后端用 Basic Pitch 作为默认实现。

2.2 源分离(可选前置)

完整歌曲先分离出"钢琴/某乐器/人声"再转写,能大幅减少错音:

流程:MP3 → Demucs 分离 → 取目标音轨 → Basic Pitch 转写 → 音符 JSON

2.3 后处理(很重要,直接决定观感)

转写原始输出往往"毛刺多"。后处理显著提升可用性:

3. 质量不够怎么办(UX 兜底)

转写永远不可能 100%。把"修正"做成顺滑体验是差异化:

  1. 重转写参数:灵敏度、最短音符、是否源分离 —— 给用户几个旋钮一键重算。
  2. piano-roll 编辑器:手动增删/移动音符(后续)。
  3. BPM / 偏移对齐:让下落音符与听感对齐。
  4. MIDI 直传通道:高级用户/音乐人直接给 MIDI,绕过转写。

4. 推荐管线(目标态)

MP3
 │
 ├─(可选) Demucs 源分离 ─▶ 目标音轨(钢琴/人声)
 │
 ▼
Basic Pitch 转写 ─▶ 原始音符 + onset/力度
 │
 ▼
后处理:beat tracking(librosa) → 量化 → 去碎音 → 分左右手 → 力度归一
 │
 ▼
音符 JSON  ──▶  渲染内核

5. 本仓库实现

评估建议:先拿 10–20 首代表性曲目跑一遍,人工标"可用率",再决定是否引入源分离/换模型(见 04-mvp-roadmap.md §6)。

06 · 第一版 MVP(最终落地闭环 V1)

04 是"路线图/分阶段",本篇是把第一版方向拍死:第一版到底做成什么样、怎么收费、怎么部署上线。
一句话目标:一个网站,上传音乐 → 出一个带特效的钢琴视频,能注册、能付费去水印、能跑在真实服务器上。

1. 第一版方向(已确定)

做减法,先把闭环跑通、能收到第一笔钱。

维度V1 决定理由
仅 Web(响应式,手机能用)App 留 V2,先验证需求
输入MP3/WAV/M4A 上传 + MIDI 直传 + 内置示例(仅体验)用户自带音源;不做曲库
转写Basic Pitch,主打独奏钢琴/简单编制复杂流行乐放 V2(加源分离)
可视化现有 12 种特效 + 主题 + 画幅 + 标题 + 水印原型已完成
导出客户端录制(MediaRecorder)→ webm/mp4服务器渲染成本高,V1 不做(省钱)
账户邮箱 + Google 登录注册门槛低
收费订阅(Free/Creator/Pro) + 转写额度 + 水印闸见 §3
市场全球优先(YouTube/Shorts/TikTok)支付与合规简单;国内(抖音/B站)做 V2 本地化

V1 明确不做:4K/服务器渲染、批量导出、移动 App、piano-roll 精修编辑器、源分离、B2B API、国内支付、曲库/内容分发(永不做——纯工具,用户自带音源)

关键省钱逻辑:导出走客户端(用户自己机器渲染),服务器只承担"转写"这一点计算 → V1 几乎没有渲染成本。付费点是"去水印 + 转写额度 + 画质"。

2. V1 产品具体描述

2.1 完整用户流程(已在原型实现外壳)

落地页 → 注册/登录 → 上传音乐 → 处理(真实转写) → 工作室(选特效/主题/画幅/标题)
      → 导出视频(免费带水印 / 付费去水印) → 下载 → 发到 YouTube/TikTok

2.2 功能边界(V1)

2.3 北极星 & V1 成功标准


3. 怎么收费(计费方案)

3.1 套餐设计(V1)

套餐价格内容付费点
Free¥01080p、带水印、每月 3 次转写、全部特效/主题体验 + 传播(水印)
Creator~$9/月 (或 ¥39)去水印、每月 50 次转写、竖屏/方形、更长时长主力收入
Pro~$19/月去水印、无限转写(合理用量)、优先转写队列、自定义标题样式重度用户
Credit 包按量不想订阅的人,买"转写次数/导出次数"点数长尾
V1 把"全部特效"都给免费用户(特效是传播点,不该锁)。付费墙 = 去水印 + 转写额度 + 时长

3.2 用什么支付服务

方案适用优劣
Paddle / Lemon Squeezy(推荐 V1)全球面向个人/独立开发Merchant of Record:帮你处理全球增值税/销售税、发票、退款,省去合规噩梦;✅ 接入快抽成略高(~5%+)
Stripe主要美区/自建合规✅ 费率低、生态强❌ 需自己处理各国税务
微信支付/支付宝国内市场国内必需,但需公司主体+合规 → 放 V2

V1 决定:用 Lemon Squeezy / Paddle(MoR),最快合规收全球的钱;国内支付等 V2 做本地化版本。

3.3 计费怎么落地(技术机制)

计费的"闸"放在两个最有价值的动作上:转写(有成本)和去水印导出(付费特权)。

用户登录 → 拿到 JWT
  ↓
点"开始转写" → 前端带 JWT 调后端 /transcribe
  ↓
后端先查 DB:该用户套餐 & 本月已用转写次数
   ├─ 超额/无权限 → 返回 402,前端弹"升级套餐"
   └─ 允许 → 跑 Basic Pitch,转写次数 +1,返回音符 JSON + { watermark: 是否强制 }
  ↓
导出时:watermark 标志由后端套餐决定(前端不可绕过的关键校验放后端签发的 token 里)
  ↓
支付:Lemon Squeezy/Paddle 结账 → Webhook 回调后端 → 更新 DB 里用户的套餐/额度

4. 怎么发布上线(部署方案)

4.1 V1 架构(精简版,按"少运维 + 低成本"选型)

                 ┌─────────────────────────────┐
   浏览器 ──────▶ │ 前端 (静态站)                │  Vercel / Cloudflare Pages
                 │ 工作室 + 客户端导出(MediaRec) │
                 └───────────┬─────────────────┘
                             │ HTTPS (JWT)
                 ┌───────────▼─────────────────┐
                 │ API (FastAPI 容器)           │  Render / Railway / Fly.io
                 │ 鉴权·额度·计费回调·调度转写   │
                 └─────┬───────────────┬───────┘
                       │               │ 调用
            ┌──────────▼────┐   ┌──────▼─────────────┐
            │ Supabase       │   │ 转写 (Basic Pitch)  │  Replicate / Modal
            │ Auth+Postgres  │   │ 按次计费、无闲置成本 │  (或同容器 CPU 跑)
            │ +Storage(音频) │   └────────────────────┘
            └────────────────┘
                       ▲
            ┌──────────┴────┐
            │ Lemon Squeezy │  支付 + Webhook
            └───────────────┘

4.2 具体选型与理由

组件选型理由
前端托管VercelCloudflare Pages静态站,免费档够用,全球 CDN,自动 HTTPS
后端 APIRenderRailway(容器)部署一个 Docker 就行,便宜(~$7–25/mo),自带 HTTPS
转写计算Replicate / Modal(按调用付费)无请求时零成本,避免养闲置 CPU;Basic Pitch 可打包成一个推理端点。流量大了再自建
认证Supabase Auth(邮箱+Google)与 DB 一体,省事
数据库Supabase Postgres用户/套餐/额度/项目;免费档起步
对象存储Supabase StorageCloudflare R2暂存上传音频;R2 出口免费、便宜
支付Lemon Squeezy / Paddle见 §3.2,MoR 省税务
域名/CDN/DNSCloudflare域名 + DNS + 防护
监控Sentry(前后端) + 平台自带日志错误可见
选型原则:能托管就不自运维,能按量就不养机器。 单人/小团队 V1 几乎不碰服务器运维。

4.3 V1 月成本估算(低流量起步)

估算
Vercel/Cloudflare Pages$0(Hobby/Free)
Render/Railway API$7–25
Supabase$0 → $25(Pro)
转写 (Replicate 按次)~$0.01–0.05/首 × 用量
域名~$12/年
合计约 $30–60/月 + 转写按量,跑起来后用收入覆盖

4.4 上线检查清单


5. V1 落地计划(4–6 周)

目标
W1接转写后端:上传 MP3 → 调 Basic Pitch → 音符 JSON 喂现有工作室;真实音频播放(替换合成器)
W2Supabase 登录 + 项目保存 + 转写额度计量
W3Lemon Squeezy 套餐/结账/Webhook + 水印闸
W4部署(Vercel+Render+Supabase) + 域名 + 监控 + 兜底/错误处理
W5ToS/版权/隐私、落地页打磨、SEO、少量体验示例曲目
W6内测 → 修 → 公开发布,铺种子内容
风险驱动:W1 先验证转写"可用率"够不够(拿 10–20 首真实曲子人工评估),不够就限定曲风/强化"换灵敏度/改 MIDI"兜底,再继续。

6. 与其它文档的关系

07 · 本地开发环境(如何在本地跑完整流程)

目标:在你自己电脑上,从 0 到"上传音乐 → 真实识别音符 → 工作室出片"全程跑通。


1. 依赖


2. 最快路径(用 Makefile)

# A. 免 ML 联调(秒级,先确认链路通)
make setup-mock     # 只装 fastapi/uvicorn
make dev-mock       # 同时起 后端(模拟) + 前端
# 浏览器打开 http://localhost:9000 → 上传任意音频 → 工作室 → 导出

# B. 真实转写(装 basic-pitch,首次较慢)
make setup          # 装 basic-pitch 等全部依赖
make dev            # 同时起 后端(真实) + 前端

make help 查看所有命令。

macOS:make setup 会带 coremltools,basic-pitch 自动用 CoreML,无需额外配置(已实测可用)。

3. 手动路径(不想用 make)

两个终端:

# 终端 1 — 后端
cd prototype/backend
python3 -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt           # 真实;或仅 fastapi uvicorn[standard] python-multipart 走模拟
uvicorn app:app --reload --port 9001      # 真实;模拟加前缀 PR_MOCK=1

# 终端 2 — 前端
cd prototype/web && python3 -m http.server 9000

浏览器 → http://localhost:9000

前端后端地址在 prototype/web/js/config.jsBACKEND_URL(默认 http://127.0.0.1:9001)。


4. 完整数据流(本地)

浏览器上传音频
  → POST http://localhost:9001/transcribe   (FastAPI, app.py)
  → transcribe.py 调 basic-pitch 出音符
  → 返回音符 JSON
  → 前端 loadSong() 喂给工作室渲染内核
  → 播放用户真实音频(<audio>) + 可视化
  → 导出 (MediaRecorder 录画面+声音) → 下载 .webm
后端不可达时 → 前端自动回退示例曲目(仍可玩)

5. 命令行单独转写(不开前端)

cd prototype/backend
python transcribe.py 某首歌.mp3 > song.json     # 出音符 JSON
PR_MOCK=1 python -c "import transcribe,json;print(json.dumps(transcribe.mock('x')))"  # 模拟

6. 评估转写质量(关键验证)

make gen-audio      # 生成带真值的合成测试音频到 tests/audio/
make eval           # 跑转写 + 算 F1

把你自己的真歌 .mp3 放进 tests/audio/make eval

合成测试基线(已实测):单音/左右手 F1=1.00,三音和弦 F1≈0.86。
说明 basic-pitch 对干净钢琴/简单编制很好;复杂流行乐建议先做源分离(见 05)。

7. 常见问题

08 · 服务器搭建方案(部署上线)

06 讲了选型策略与成本,本篇是可直接照做的部署步骤 + 仓库里已备好的部署文件
原则:能托管就不自运维,能按量就不养机器。

1. 部署拓扑(V1)

  用户浏览器
     │
     ├──────────────▶  前端静态站   (Vercel / Cloudflare Pages)   ← prototype/web
     │
     └── /transcribe ▶  转写 API     (Render / Railway, Docker)    ← prototype/backend
                              │
                         (V2 可拆) 转写计算 → Replicate/Modal 按量
  支付:Lemon Squeezy/Paddle Webhook → API   (账户/计费见 06 §3)

V1 把转写跑在 API 容器里即可;流量大了再把转写拆到 Replicate/Modal。


2. 仓库里已备好的部署文件

文件作用
prototype/backend/Dockerfile后端容器(Linux,装 onnxruntime 跑 basic-pitch)
prototype/backend/.dockerignore镜像瘦身
prototype/backend/.env.example环境变量模板(PR_MOCK / ALLOWED_ORIGINS)
docker-compose.yml本地一键起整套(后端+前端)
render.yamlRender 一键部署蓝图

3. 后端上线(Render,最省事)

  1. 仓库推到 GitHub。
  2. Render → New → Blueprint → 选本仓库(自动读 render.yaml)。
  3. 部署后在服务的 Environment 填:
    • ALLOWED_ORIGINS = https://你的前端域名(收紧 CORS)
  4. 健康检查 /health 通过即上线。API 地址形如 https://pianoreel-api.onrender.com
Railway / Fly.io 同理:直接用 prototype/backend/Dockerfile 部署一个容器,暴露 9001,配 /health

自己用 Docker 跑(任意云主机)

cd prototype/backend
docker build -t pianoreel-api .
docker run -p 9001:9001 -e ALLOWED_ORIGINS=https://你的域名 pianoreel-api

4. 前端上线(Vercel / Cloudflare Pages)

前端是纯静态目录 prototype/web,无需构建。

  1. Vercel → New Project → 选仓库 → Root Directory 设为 prototype/web → 部署。
  2. 部署后改 prototype/web/js/config.jsBACKEND_URL 为线上 API 地址,重新部署。

(生产建议改成读环境/构建注入,V1 直接改常量即可。)

  1. 绑定自定义域名(用 Cloudflare 管 DNS)。
也可用 cloudflare pages / netlify,同样指向 prototype/web 目录。

5. 本地用 Docker 验证整套

docker compose up --build
# 前端 http://localhost:9000   API http://localhost:9001
# 想免 ML:把 docker-compose.yml 里 backend 的 PR_MOCK=1 取消注释

6. 上线前 checklist


7. 成本与扩展

09 · AI 自动编曲(二次创作)

把"听一首歌 → 弹出来"做到音乐家水平:不只是扒出旋律,而是配上好和声、好织体,
生成一份真正能弹的钢琴谱(MIDI / 五线谱),并渲染成视频。

1. 目标:按"演奏水平"分级

水平能力技术实现状态
🎓 学生听出旋律、单手弹Demucs 人声 → melody.to_melody() 单音旋律✅ 已有
👨‍🏫 音乐老师配合理和弦、双手弹arrange.detect_chords() + render_accomp() 规则编配✅ 已有(粗糙)
🎹 音乐家高级和声 / voicing / 装饰 / 强弱AI 编曲(Claude)⬜ 本文档

难度由用户选(新手 / 进阶 / 炫技)—— 对应"老师按学生水平教"。

2. 总流水线

MP3 → Demucs(4 stems) → 转写 → 旋律 + 检测和弦
  → ① 量化到节拍网格(小节 / 四分·八分音符)
  → ② Lead Sheet(旋律 + 和弦,紧凑文本 / ABC)
  → ③ AI 编曲(Claude,混合策略)
  → ④ 渲染:可弹 MIDI / MusicXML / PDF 五线谱 + 视频

3. 表示格式:为什么用 ABC

不能直接把音符 JSON 丢给 LLM(token 大、易错)。用 ABC 记谱法(文本乐谱):

两种表示分工:

4. AI 策略

策略 A — LLM 直接生成完整编曲(ABC)

喂"旋律 + 调性 + 风格" → LLM 输出双手 ABC → 解析成 MIDI。
简单灵活,但 LLM 偶有越界 / 节奏错,需校验 + 修复

策略 B — 混合:LLM 决策 + 规则落音(推荐)

LLM 只输出高层计划(每段和弦走向 + 伴奏风格 + 强弱),不直接写音符;
arrange.py 规则引擎把计划渲染成实际音符 → 保证在音域、踩拍、能弹。
输出 token 少 → 更便宜,几乎不产出"不能弹"的谱。

5. 技术细节

① 量化(quantize)

② Lead Sheet 生成

③ AI 编曲调用(Claude)

④ 渲染与导出

6. 成本(一首 4 分钟歌,AI 仅调用一次)

约 2.5–3K token 输入 + 1–3K 输出。每首成本:

模型策略每首质量用途
Claude Haiku混合~$0.01够用走量 / 免费兜底
Claude Haiku直出 ABC~$0.02够用
Claude Sonnet混合 / ABC~$0.02–0.05好,乐感明显付费档主力
Claude Opus直出 ABC~$0.11–0.27最强炫技 / 溢价档
估算基于 Haiku≈$1/$5、Sonnet≈$3/$15、Opus≈$15/$75(每百万 token in/out),
以官方实时价为准;开 prompt 缓存后输入成本更低。

业务账(付费 $9/月,编 50 首/月):

分档: 免费=纯规则(0 成本);付费=Sonnet 混合 + 缓存;高级=Opus。

7. 编曲系统提示词(模板)

你是专业钢琴编曲师。我给你一段从歌曲中提取的旋律(含调性、速度、拍号)。
请编配一份【难度:新手/进阶/炫技】的钢琴演奏:

要求:
- 右手:给定旋律(可加得体的经过音 / 八度加厚)。
- 左手:为旋律配一个该调内好听的和弦进行,并用【分解和弦/柱式/华尔兹/抒情】
  织体演奏。
- 双手保持在舒适音区(左手 C2–C4,右手 C4–C6),符合钢琴演奏习惯。
- 保持在给定调性内;和弦要贴合旋律。

旋律格式:音名@起始拍(时值拍),调性 X,速度 Y BPM,Z/4 拍。
旋律:<<melody>>

只输出两部分:(1) 按小节的和弦进行;(2) ABC 记谱(双手,V:1 右手 / V:2 左手)。

8. 落地顺序

  1. Phase 1 量化 + Lead Sheet(地基)
  2. Phase 2 接 Claude(混合策略),在 Let It Go 上验证质量
  3. Phase 3 可弹 MIDI / 五线谱输出
  4. Phase 4 接入上传流程 + 免费/付费分级

9. 风险与备注

10 · 竞品对标:我们要达到什么水平、跟谁比

理解差距才知道往哪走。"好听"由两件独立的事决定,解法完全不同:

维度是什么我们现状解法
① 音色钢琴声本身好不好听合成器(3 振荡器),电子、廉价真钢琴采样(最易补,性价比最高)
② 音乐性音准 / 节奏 / 编曲好不好全自动转写,偏糙pYIN 旋律 + AI/规则编曲(正在做)

三类竞品

A 类 · 演奏极好听(视觉 + 听感的对标)

好听 = 人工编曲/演奏 + 好音色,而非算法。

B 类 · 下落音符播放器(视觉对标)

C 类 · 自动「音频 → 谱子」(我们真正的竞争对手)

我们的定位与差异

A 类好听 = 人工 + 好音色;C 类自动 = 转写糙但音色好。
我们做最难的全自动 MP3→可弹钢琴,所以音乐性天然更糙;
音色这块是自己拖后腿——换采样即可补上。

差异化机会:

目标水平(分阶段)

  1. 音色 → 逼近 Synthesia / Rousseau 的钢琴采样听感(短期,换 soundfont)
  2. 视觉 → 已接近 Rousseau 风格(倒影/粒子/特效,已有)
  3. 音乐性 → 旋律准(pYIN ✅ 方向对)+ 编曲好(AI/规则,进行中),目标"听得出原曲、能弹"
  4. 谱子 → 可下载 MIDI(✅)/ MusicXML / PDF,对标 Klangio

衡量标准

11 · Pop2Piano 引擎 · 服务架构与优化

实测验证:Pop2Piano(本地"音频→钢琴"专用模型)明显优于自研拼接管线
确立为核心编曲引擎。本文覆盖:怎么搭服务器、成本、优化方向。

0. 关键发现:管线大幅简化

Pop2Piano 直接吃整首歌音频 → 输出钢琴翻弹 MIDI,不需要 Demucs / 转写 / 配和弦。

旧自研管线Pop2Piano 引擎
步骤Demucs→pYIN→和弦→AI编左手→渲染Pop2Piano→渲染
单曲耗时(本地)~3-5 分钟(Demucs 最慢)~10-60 秒
AI API 费有(MiniMax/Claude)0(本地模型)
编曲质量拼接感学过真人翻弹,更自然
风格自定义织体composer1~21(21 种)

Demucs 仅在「叠加原唱」可选功能里才需要,核心编曲不依赖它。

1. 推荐服务架构(异步 ML 模式)

ML 推理慢(秒级),不能阻塞 HTTP 请求。标准做法是上传→入队→后台 GPU 推理→轮询/推送结果

用户浏览器
   │  上传 MP3 + 选风格(composer)
   ▼
[前端]  静态站  (Vercel / Cloudflare Pages)
   │  POST /jobs
   ▼
[API]   FastAPI  (Render / Railway / Fly)   ← 便宜、CPU、无状态
   │  - 鉴权 / 配额 / 计费
   │  - 存音频到对象存储,创建任务,入队,返回 job_id
   ▼
[队列]  Redis + RQ/Celery  (或 SQS)
   ▼
[GPU Worker]  Pop2Piano 推理  ← 唯一花钱的重活
   │  ① (可选)Demucs 抽人声  ② Pop2Piano → MIDI  ③ 后处理(量化/动态)
   │  写结果(MIDI/notes JSON) 到对象存储
   ▼
[结果]  前端轮询 /jobs/{id} 或 WebSocket 推送 → 进工作室渲染 → 导出视频

2. GPU 推理怎么部署(最关键的决策)

别开 24 小时常驻 GPU(烧钱)。按音量选:

方案说明成本适合
Replicate / Modal(无服务器 GPU)⭐部署一次,按秒计费、缩容到零,不用时 0 成本~$0.01–0.05/首MVP / 个人开发者首选
RunPod / Beam类似,便宜类似量上来后
自租 GPU 机器固定月费,空闲也烧$几十~上百/月稳定大流量
纯 CPU(便宜 VPS)Pop2Piano CPU 也能跑(慢),无需 GPUVPS 月费低量 / 极致省钱 MVP

推荐:Pop2Piano 打包成 Replicate(cog) 或 Modal 函数,无服务器 GPU,按调用付费。 部署一次,自动扩缩,不用管运维。

3. 成本模型(单曲)

成本
Pop2Piano 推理(无服务器 GPU)~$0.02–0.05
AI API$0(本地模型)
存储/带宽可忽略
客户端渲染$0
单曲合计~$0.02–0.05

毛利极高。免费档=水印+低配,付费档=高清+多风格。

4. 优化方向

质量

性能

成本

产品

5. 落地顺序

  1. MVP:FastAPI(Render) + Pop2Piano on Replicate/Modal + 前端(Vercel) + Supabase/Lemon Squeezy;异步任务 + 客户端渲染
  2. 提质:挑 composer、后处理、FluidSynth 高质量导出
  3. 产品化:风格=composer 映射、多版本、五线谱、原唱叠加
  4. 扩展:缓存、队列扩缩、服务端 4K 渲染

6. 结论

Pop2Piano 把"编曲"这个最难的环节用一个本地免费模型解决了,架构更简单、成本更低、质量更好
PianoReel 定位收敛为:"上传任意 MP3 → AI 一键生成好看好听的钢琴 Live 视频(多风格)"
赢在编曲(Pop2Piano) + 音色 + 可视化 + 一键导出,而非转写准确度。

12 · 路线图:MVP 之后做什么

现状:本地 MVP 跑通,效果不错 —— 上传 MP3 → Pop2Piano 编曲(8s/20s)→
工作室(真钢琴+混响+动态+特效)→ 抽原声叠加 → 导出(视频/MIDI/高音质音频)。
定位收敛:「上传任意歌 → AI 一键生成钢琴 Live 视频(多风格)」

核心原则:先把成品做完整 → 验证需求 → 再做成服务。 不要在验证前先建账户/付费/部署基建。


Phase 1 · 成品打磨(让输出能直接发布)← 现在做

目标:能产出一个完整、能发到 YouTube/B站 的 Piano Live 视频。

产出:1-2 个完整成品视频

Phase 2 · 验证需求(最便宜的 go / no-go)

目标:花最小代价确认"有人要"。你有音乐频道,这是独特优势。

Phase 3 · 做成服务(验证通过后才做)

目标:别人能上网用、能付费。架构见 doc 11

Phase 4 · 增长功能(产品成立后)


法务 / 风险

建议的立刻动作

先做 Phase 1 的「整首歌处理」 —— 这是产出第一个完整成品的前提,做完就能进 Phase 2 用你的频道验证。

13 · YouTube 链接一键导入(粘贴链接 → 自动下载 → 直接出片)

目标:用户在上传页粘贴一个 YouTube 链接,系统自动下载音频、转 MP3,直接进入
现有 Pop2Piano 出片流程。极大降低「先找歌、再下载、再上传」的门槛。

1. 用户流程(UX)

上传页
 ┌─────────────────────────────────────────────┐
 │  选择风格:钢琴现场 / Lo-fi / 动漫 / 抒情      │
 │                                               │
 │  ① 拖入 MP3            ② 粘贴 YouTube 链接 ▶   │  ← 新增②
 │  [____________]       [https://youtu.be/…] [开始]│
 └─────────────────────────────────────────────┘
        │ 粘贴链接 + 开始
        ▼
   处理页(已有动画)
   ├ 解析链接 / 读取信息(标题、时长)
   ├ 下载音频(yt-dlp)           ~5–30s
   ├ 转 MP3(ffmpeg,已装)
   └ Pop2Piano 编曲(已有)       ~15–60s
        ▼
   工作室(竖屏 / 副歌精华 / 预设 / 慢速 / 原声 / 导出)

成品和上传 MP3 完全一致:可播原声、加载人声分轨、导出竖屏副歌片段 / 谱子 / 高音质音频。


2. 技术架构

复用现有「后端写 web/samples/,前端 serve」模式(/separate 已是这么做的)。

前端(9000)  ──POST /youtube {url, style}──▶  后端(9001)
                                              │ 1. yt-dlp 取信息 → 校验时长 ≤ 上限
                                              │ 2. yt-dlp 下载 bestaudio
                                              │ 3. ffmpeg → web/samples/yt_<id>.mp3
                                              │ 4. pop2piano_engine.arrange_pop2piano()
                                              ▼
前端  ◀──{ tracks, bpm, theme, title,
          audioUrl: "samples/yt_<id>.mp3" }──┘
   → loadMultitrack(data, data.audioUrl) → show('studio')

关键点:返回 audioUrl 指向 samples/yt_<id>.mp3(前端服务器 serve),
于是「原声播放 / 🎤加载人声分轨」自动可用 —— 和上传 MP3 路径一模一样。


3. 后端实现

3.1 依赖

3.2 新端点 POST /youtube(app.py)

@app.post("/youtube")
async def youtube_endpoint(payload: dict = Body(...)):
    url   = payload["url"]
    style = payload.get("style", "piano_live")
    import youtube_service as Y          # 新文件
    info = Y.probe(url)                  # 取 title/duration/id,不下载
    if info["duration"] > MAX_YT_SEC:    # 时长上限(成本/滥用)
        raise HTTPException(400, f"视频过长({info['duration']}s),上限 {MAX_YT_SEC}s")
    mp3_path, web_url = Y.download_mp3(url, info["id"])   # 下载 + 转码 + 缓存
    import pop2piano_engine as PE
    result = PE.arrange_pop2piano(mp3_path, style=style, max_sec=None, title=info["title"])
    result["audioUrl"] = web_url         # "samples/yt_<id>.mp3"
    return JSONResponse(result)

3.3 新文件 youtube_service.py

3.4 配置

MAX_YT_SEC = 8 * 60   # 8 分钟上限(可调)

4. 前端实现

4.1 上传页(index.html)

拖拽区下方加一个「或粘贴链接」行:

<div class="yt-row">
  <input id="ytUrl" class="yt-input" placeholder="粘贴 YouTube 链接,例如 https://youtu.be/..." />
  <button id="ytGo" class="btn primary">▶ 下载并制作</button>
</div>

4.2 逻辑(app.js)

async function handleYouTube(url) {
  const finish = startProcAnim();
  try {
    const res = await fetch(CONFIG.BACKEND_URL + '/youtube', {
      method: 'POST', headers: {'Content-Type':'application/json'},
      body: JSON.stringify({ url, style: selectedStyle })
    });
    if (!res.ok) throw new Error((await res.json()).detail || ('HTTP '+res.status));
    const data = await res.json();
    finish();
    if (data.theme && Themes[data.theme]) Visualizer.setTheme(Themes[data.theme]);
    loadMultitrack(data, data.audioUrl);   // 原声 + 分轨都可用
    show('studio');
  } catch (e) { finish(); alert('下载/处理失败:' + e.message); }
}

audioUrl 成 blob 再发」(getOriginalAudio() 已会 fetch audioUrl,小改即可)


5. 风险与规避(重要)

风险说明规避
⚠️ 法律 / 版权 / ToSYouTube 服务条款禁止未经授权下载;歌曲多有版权。商用上线这是头号风险① 本地验证阶段无碍;② 上线前定位为「用户对自己有权的内容」并加用户声明/勾选;③ 或只做「链接→你本地处理」不在服务端留存
服务端 IP 被封YouTube 会封数据中心 IP;你本地 Mac(住宅 IP)现在没问题,部署到云大概率失败生产需 cookies / 住宅代理;先本地跑通,部署另算
yt-dlp 易失效YouTube 改版会让下载报错固定版本 + 定期 pip install -U yt-dlp;报错友好提示
成本 / 滥用下载+处理任意长视频耗资源时长上限(8 min)、按视频 id 缓存、生产加限流
延迟下载+编曲 30–90s,同步请求会卡住 UIMVP 用现有处理动画顶住;生产改异步任务+轮询(见 Phase 3)

6. 分期落地

阶段内容估时产出
Phase 1 · 本地 MVP装 yt-dlp;/youtube 同步端点(时长上限+按id缓存);前端链接输入框+处理动画~半天你 Mac 上:粘链接→出片 端到端跑通
Phase 2 · 健壮性错误态(无效/直播/年龄限制/超长);「加载人声」走 audioUrl;进度提示;取消~半天体验顺滑、报错清晰
Phase 3 · 异步任务任务队列 + /youtube/status 轮询,长视频不阻塞~1 天可处理较长视频、可多任务
Phase 4 · 生产cookies/代理破 IP 封锁、限流、法律声明/勾选、对象存储、清理定时任务上线前可对外服务

7. 待你决策

  1. 法律姿态:现在只做本地验证(推荐,先跑通看效果),还是直接按可上线设计(要加声明/限制)?
  2. 时长上限:默认 8 分钟够吗?(越长越慢越贵)
  3. 是否现在就实现 Phase 1?(我可立刻装 yt-dlp + 写端点 + 前端输入框,在你 Mac 上跑通)

</content>
</invoke>

14 · 最终形态与可视化方案发散

回答四个问题:最终结果是什么?只有"落音符"吗?歌词/原视频可行吗?现在流行什么?

Q4. 现在市面上的主流方案(先看全景)

方案代表卖点适合目标
① 落音符 / SynthesiaRousseau、Patrik Pietschmann、Kassia俯视键盘+彩色下落音符+粒子,演奏感强、可弹、解压钢琴翻弹(当前主流,20亿+播放
② 真人手+落音符叠加多数钢琴 up 主真实双手 + Synthesia 视觉,可信度高教学 / 炫技
③ 歌词视频 (Lyric Video)海量官方/二创动态歌词 + 背景,制作轻、传唱强情感 / 传播
④ 分屏对比 (Split-screen)原 MV vs 翻弹/反应原视频做"注意力锚点",实测 +约4% 互动反差 / 关注
⑤ 波形/频谱可视化Spotify Canvas 风通用、任意音频可用,制作极轻单曲循环 / 氛围
⑥ 3D/粒子/AI 生成视觉新一代可视化工具沉浸、drop 时粒子爆发、跟随能量电子/氛围乐
⑦ 氛围静态场景"relaxing piano" 频道雨窗/壁炉/咖啡馆 + 音频,极致氛围放松/学习 BGM
趋势:2026 行业整体在从"2D 波形贴静图"往 3D、粒子、drop 爆发、实时可交互 走;
同时歌词视频因门槛低、传唱强,仍是最大的内容池之一。

Q2. 只有"落音符"这一种吗?—— 不是

落音符是钢琴翻弹品类里最优的(展示"弹了什么"、解压、有教学感),PianoReel 已做到位。
但它只解决"演奏感"。换个目标,更优解就变了:

结论:不是替换,而是把落音符当基底,做成"可叠层的场景",按目标切模式。

Q3. 歌词 / 加入原视频,可行吗?—— 都可行,且歌词是高价值差异点

歌词(强烈建议做,门槛中等、版权风险低)

加入原视频(技术易、版权需谨慎)

商用需授权/限定自有内容。建议作为"本地/受限"能力,不默认开。

Q1. 最终结果应该是什么(北极星)

一键把任意歌 → 一条可直接发布的竖屏钢琴短视频。
不止一种视觉,而是一个可叠层的场景,按创作目标切"模式"。

场景分层(基底 + 可选叠层):

[ 基底 ] 落音符 + 88键 + 主题配色          ← 招牌,已完成
[叠层] 歌词(卡拉OK高亮)                   ← 建议下一步
[叠层] 片头标题卡 / 封面文案                 ← 轻量、提转化
[叠层] 原视频(分屏 / 背景,受限)           ← 技术易、版权慎
[调校] 竖屏 · 副歌精华 · 情感慢速 · 高级感预设 ← 已完成

四种"出片模式"(同一首歌,一键切):

模式= 哪些层目标
🎹 演奏模式落音符(现状)演奏感 / 可弹
🎤 歌词模式落音符 + 卡拉OK歌词情感 / 传唱
🎬 对比模式原 MV 分屏 + 落音符反差 / 关注
🌙 氛围模式美学背景 + 极简音符 + 音频放松 BGM

每首歌最终交付:MP4(视频)+ 谱子 + 高音质音频,开箱即发。

✅ 实现状态(已全部落地)

四种出片模式 + 片头标题卡均已实现并验证(见 studio「出片模式」切换器):

后端新增:/lyrics(faster-whisper)、/youtube_video/transcode

后续可继续打磨(非阻塞)

  1. 🎤 歌词模式(卡拉OK) —— 复用已分离的人声轨 + Whisper 逐词时间戳,

在场景上叠高亮歌词。最高性价比差异点,版权风险低。

  1. 🎬 片头标题卡 + 封面文案 —— 轻量、直接提升完播与点击。
  2. 🎬 对比/背景模式(原视频) —— 技术易(yt-dlp 视频 + ffmpeg 合成),

作为本地/受限能力先验证观感。

  1. 🌙 氛围模式 —— 一组美学背景预设,覆盖"放松 BGM"大池子。

</content>

15 · 当前服务清单 · 本地 App 打包 · 发布上线

回答三件事:现在用了哪些服务 / 打包成本地 App 要做什么 / 发布上线要做什么。

1. 当前运行时全景(用到哪些服务)

两个进程

Python 库(⚠️ 现 requirements.txt 不全,缺下列重依赖)

用途
Web 框架fastapi · uvicorn · python-multipart
编曲(主引擎)transformers + torch(Pop2Piano)
分轨demucs(torch)
歌词faster-whisper(CTranslate2)
转写(旧路径)basic-pitch(macOS CoreML / Linux onnxruntime)
音频/谱librosa · music21 · pretty_midi
YouTubeyt-dlp

系统级外部二进制(非 pip,要单独装)

数据 / 模型

前端外部 CDN(联网依赖)

外部 API:MiniMax(仅实验性 LLM 编曲路径,主流程不用)· 出站访问 YouTube


2. 打包为本地 App(自用)

难点:ML 栈很重(torch + 多模型,几个 GB),外部二进制要随包带上。

方案 A · 最省事:脚本 / Docker(推荐先做)

方案 B · 真·桌面 App:Tauri/Electron + Python sidecar

不管 A 还是 B,待办清单

  1. 补全 requirements.txt(torch/transformers/demucs/librosa/music21/pretty_midi)并钉版本
  2. 外部二进制随包带(或首启检测 + 引导安装 brew/winget)
  3. 模型缓存目录固定 + 首启下载进度提示
  4. 前端去 CDN:把 @tonejs/midisoundfont-player 和钢琴采样本地化(否则离线打不开)
  5. 后端端口动态化 + 前端 BACKEND_URL 自适应
  6. (桌面 App)macOS 代码签名/公证过 Gatekeeper

3. 发布上线(对外服务)

技术只是一部分,法务和成本才是真门槛

技术部署

产品(都没建)

安全 / 运维

⚠️ 法务(头号风险)

成本

GPU/算力 + 存储 + 带宽 + 代理 + 可能的授权费。


一句话

</content>

16 · 分发与收费方向(持续思考用)

这款产品怎么发出去、怎么收钱。本文是开放讨论的备忘,会持续更新。
两个主导约束贯穿全篇:① ML 算力成本 · ② 版权责任
相关:本地打包/部署见 15-packaging-deploy.md,状态见 00-status.md

一、三条分发主路

方向算力谁付你的法律身份触达变现
A. 本地桌面 App(Electron/Tauri)用户机器(你≈0)"工具"(像剪辑软件/OBS)要安装+要好机器买断 / 订阅+授权
B. Web SaaS(云)你付 GPU($$$)"平台"(托管+处理内容)浏览器即用,最广订阅 / 点数
C. 内容号(自己产片)你本地创作者(逐条担版权)看你做号流量/广告/接广

三个决策轴

  1. 算力成本:云=每单 GPU 烧钱;本地=0(用户出)。
  2. 法律暴露:SaaS 你托管+处理+服务端下 YouTube → 责任最大;桌面 App 你只是"工具" → 平台责任低得多;内容号逐条自担。
  3. 触达/体验:SaaS 免安装最广;桌面 App 有安装+硬件门槛;内容号不卖软件。

判断:桌面 App(local-first)同时绕开了两个最大问题(算力成本 + 平台版权责任),是最"干净"的软件产品路。代价是体积大、要好机器、更新分发麻烦。

建议序列(不要一上来就选终局):

先:内容号验证需求(零基建)
 → 再:本地桌面 App 卖给创作者(低法务/低成本)
 → 视情况:需求大 + 有钱投基建 + 做合规,再上云 SaaS

二、桌面 App 怎么收费(Electron 路线)

本质:程序跑在用户机器上,卡不了服务器 → 靠 许可证(license)门控:用户买"激活码",App 联网校验。

1. 收费模式

模式说明适配
Freemium(免费+解锁)免费版有限制,付费解 Pro最适合 —— 天然付费点:去水印
订阅月/年,定期联网校验收入稳,桌面订阅接受度略低
买断付一次永久用(大版本另收)好卖,但无复购

PianoReel 的天然分层

2. 技术怎么落地(别自己造支付/发证)

3. 几条现实

4. 加分玩法:Local-first + 少量云

桌面 App 本地干重活(免费也能用),把杀手级增值放云上:云端 4K/批量渲染、云端授权曲库。


三、落到最小可行(MVP 收费)

免费下载(带水印)获客 → Lemon Squeezy 卖 Pro license(去水印+高清+全功能)→ App 在线激活校验。
税务平台扛、license 服务器极轻、不碰 GPU 账单。

为将来预留:现在就可以在产品里把 Pro 功能位标出来(哪些免费、哪些付费),先不收费,等分发路定了再接 license。


四、版权红线(无论哪条路)


待定问题(持续思考)

</content>

17 · 上线发布指南(新手向 · 一步步怎么发)

面向完全新手:每一块发布到哪、怎么发、选哪台机器、要设置什么
不要一次全做 —— 按下面的「分阶段」来,每阶段都能看到成果。
配套:架构总览见 15-packaging-deploy.md,收费见 16-distribution-monetization.md

0. 先看全局:4 块东西,各去哪

用户浏览器
   │
   ▼
pianoreel.com
 ┌─────────────────────────────────────────────────────────┐
 │ ① 前端(静态页)      → Cloudflare Pages          [免费]   │
 │ ② API/登录/付费     → Cloudflare Workers + D1    [~$5/月] │
 │ ③ 文件存储(视频等)  → Cloudflare R2             [按量·极便宜] │
 │ ④ 重型 AI 编曲      → Modal (GPU)               [按秒·每首几日元] │
 │    收款            → Stripe                     [抽 2.9%+$0.3/笔] │
 └─────────────────────────────────────────────────────────┘
新手最重要的一句话:先只做 ①(前端上线)+ ④(AI 上 Modal),让"任何人打开 pianoreel.com 就能用"。②③(账号/付费)等有人用了再加。

阶段 1 · 把前端挂上线(最简单,先做这个)

目标pianoreel.com 打开就是你的工作室界面(纯前端,不含 AI 也能看 UI、玩示例)。

前端是什么 + 放哪家

当前前端是纯 Vanilla JS(原生 JS,无框架、无打包) —— HTML + CSS + Canvas + Web Audio,就是一堆静态文件,任何静态托管都能放。

托管免费档商用(免费档)和你的 R2/Workers备注
Cloudflare Pages流量无限允许同账号无缝你全家桶在 CF,首选
Vercel~100GB/月⚠️ 不允许,要 Pro $20/月跨平台它强在 Next.js,你用不到
Netlify~100GB/月有限制跨平台一般
GitHub Pages软上限个人项目可跨平台最简陋

建议 Cloudflare Pages:你前端是纯静态,Vercel 的 Next.js 优势用不上,反而 Vercel 免费档禁止商用(一收费就得交 $20/月),而 Cloudflare Pages 免费档就能商用、流量无限、和域名/R2/Workers 同账号。Vercel 不是不能用,只是对你这套不划算。

步骤

  1. 注册域名:Cloudflare 或 お名前.com 拿下 pianoreel.com,把 DNS 交给 Cloudflare 管。
  2. Cloudflare Pages(dash.cloudflare.com → Workers & Pages → Create → Pages):
    • Connect to Git → 选你的 pianoreel 仓库。
    • 构建设置:
      • Framework preset: None
      • Build command: 留空(纯静态,不用构建)
      • Build output directory: prototype/web
    • Save and Deploy → 几十秒后给你一个 xxx.pages.dev 网址。
  3. 绑定域名:Pages 项目 → Custom domains → 加 pianoreel.com(Cloudflare 会自动配好 DNS + HTTPS)。

✅ 完成后:打开 pianoreel.com 就是你的站,免费、自动续期 HTTPS、全球 CDN
此时"上传音频/YouTube"等需要后端的功能还不能用(后端在阶段 2 上)。


阶段 2 · 把 AI 后端发布到 Modal(重点)

目标:让前端能真正"上传歌 → AI 编曲出片",后端跑在云 GPU 上、按秒计费、没人用就停。

2.1 注册 + 装工具(5 分钟)

  1. modal.com 注册(用 GitHub 登录即可),有 每月 $30 免费额度
  2. 本机装 CLI:

```bash
pip install modal
modal token new # 浏览器弹出授权,点确认即可
```

2.2 选哪台机器(GPU)

GPU显存价格(约)给你的建议
T416GB~$0.6/小时首选 —— Pop2Piano/Demucs/Whisper 都够跑,最便宜
L424GB~$0.8/小时想快一点点可选
A10G24GB~$1.1/小时更快,没必要
A10040GB+~$3.4/小时❌ 杀鸡用牛刀,别选

就选 T4。一首歌处理几十秒,单价几日元,缩容到 0 没人用不花钱。

2.3 写一个 Modal 部署文件

prototype/backend/ 下新建 modal_app.py(把现有 FastAPI 直接搬上去):

import modal

app = modal.App("pianoreel-api")

# 镜像:系统二进制 + Python 依赖 + 你的代码
image = (
    modal.Image.debian_slim(python_version="3.11")
    .apt_install("ffmpeg", "fluidsynth", "lilypond")        # 系统工具
    .pip_install(                                            # ⚠️ 补全所有依赖
        "fastapi", "uvicorn", "python-multipart",
        "torch", "transformers", "demucs",
        "faster-whisper", "librosa", "music21", "pretty_midi",
        "yt-dlp", "basic-pitch",
    )
    .add_local_dir(".", remote_path="/app")                 # 把 backend 代码拷进去
)

# 模型缓存盘:让 Pop2Piano/Whisper/Demucs 只下载一次(重启不丢)
cache = modal.Volume.from_name("pr-models", create_if_missing=True)

@app.function(
    image=image,
    gpu="T4",                       # ← 选 T4
    timeout=600,                    # 单次最长 10 分钟
    scaledown_window=300,           # 闲置 5 分钟后关机(缩容到 0 = 省钱)
    volumes={"/root/.cache": cache},  # HF/模型缓存挂到 Volume
)
@modal.asgi_app()
def fastapi_app():
    import sys
    sys.path.insert(0, "/app")
    from app import app as fastapi   # 复用你现有的 FastAPI(app.py 里的 app)
    return fastapi

2.4 发布

cd prototype/backend
modal deploy modal_app.py

跑完会给你一个公网地址,形如:

https://你的用户名--pianoreel-api-fastapi-app.modal.run

这就是你的线上后端 URL。

2.5 让前端指向它

prototype/web/js/core/config.jsBACKEND_URL 改成上面那个 Modal 地址:

BACKEND_URL: 'https://你的用户名--pianoreel-api-fastapi-app.modal.run',

然后 make bump(升版本号)→ 重新部署 Pages(push 到 Git 自动重发)。

✅ 完成后:pianoreel.com 上传音频 → 走 Modal GPU 编曲 → 出片。

2.6 这一步必须改的两件事 ⚠️

  1. 输出别再写本地 web/samples/ —— 云上没有"前端同目录"。要把生成的 mp3/mp4/谱子上传到 R2(见阶段 3),返回 R2 的 URL。改动点stem_service.py / youtube_service.py / /sheet /render 现在写本地,要改成写 R2。
  2. YouTube 下载在云上会被封 IP —— 数据中心 IP 下 YouTube 多半 403。要么配 cookies / 住宅代理,要么 YouTube 这条路只在本地保留。

2.7 要设置的东西(Modal 后台)


阶段 3 · 文件存储 → Cloudflare R2

目标:生成的视频/音频/封面存云上,前端能下载。

  1. Cloudflare dash → R2 → Create bucket(如 pianoreel-files)。
  2. API Token(R2 → Manage API Tokens),拿到 access_key / secret_key / endpoint
  3. Modal 后端用 boto3(S3 兼容)把结果传 R2:

```python
import boto3
s3 = boto3.client("s3", endpoint_url=R2_ENDPOINT,
aws_access_key_id=KEY, aws_secret_access_key=SECRET)
s3.upload_file(local_mp4, "pianoreel-files", "out/xxx.mp4")
```

  1. 让 bucket 走公开域名(R2 → Settings → Public access,或绑 files.pianoreel.com),返回该 URL 给前端。

💡 R2 的杀手锏出站流量 0 元(S3 要收)——你存视频、用户下载,不花下载流量钱。


阶段 4 · 账号 + 付费(要收费时才做)

目标:登录、订阅、配额、收款。这是最"产品化"的一块,工作量也最大。

需求用什么怎么做
API / 登录逻辑Cloudflare Workers写边缘函数;或接 Clerk / Supabase Auth 省事
用户/订阅数据Cloudflare D1(SQLite)存 user、plan、quota
任务排队Cloudflare Queues前端请求入队 → 调 Modal → 写 R2 → 通知前端
收款Stripe建 Product/Price;Workers 接 Stripe Webhook 改用户订阅状态
免费/Pro 区分前端 + 后端校验免费=带水印/720p;Pro=去水印/高清/全功能
这一步建议最后做,而且可以先用现成 Auth(Clerk)+ Lemon Squeezy(帮你扛全球税)省一半工。

5. 成本总表(人民币 / 美元 / 日元)

项目起步成本说明
域名 .com~¥70/年($10 / ¥1,500/年)Cloudflare 成本价
Cloudflare Pages(前端)免费静态站够用
Cloudflare Workers(API)$5/月 ≈ ¥36 / ¥750要做账号/付费时才订
Cloudflare R2(存储)几乎免费(10GB 内)出站 0 元
Modal(GPU 编曲)每月 $30 免费额度每首约 $0.02–0.05 ≈ ¥0.2 / 3–8 日元
Stripe(收款)无月费2.9% + $0.30/笔

结论


6. 推荐的发布顺序(新手照这个走)

  1. 阶段 1:域名 + 前端上 Cloudflare Pages → pianoreel.com 能打开(半小时,免费)。
  2. 阶段 2:AI 后端上 Modal(选 T4)→ 上传歌能真出片(半天)。
  3. 阶段 3:输出改写 R2 → 文件可下载(接在阶段 2 里一起改)。
  4. 阶段 4:要收费了再加 账号 + Stripe(另起一摊)。

先把 1+2 跑通,你就有一个"任何人能打开、能出片"的线上 demo 了。


7. 三个必须记住的坑

  1. requirements.txt 不全 —— 上 Modal 前补齐 torch/transformers/demucs/librosa/music21/pretty_midi(上面镜像里已列)。
  2. YouTube 云端被封 IP —— 需 cookies/代理,否则云上 /youtube 会 403。
  3. ⚠️ 版权(头号风险) —— 对外服务 = 帮用户批量生成可能侵权内容。公开默认走纯钢琴模式;上线前要有 ToS / 内容政策。见 16

</content>

18 · 运作机制详解 · 每个组件在哪 · 上云 · 成本

把"各个地方"讲透:**哪个组件跑在前端还是后端、数据怎么传、本地 vs 云有什么不同、
上云后各搬到哪、各自多少钱。** 新手也能看懂。
配套:上线步骤见 17-go-live-guide.md,收费见 16

0. 一句话

重活(下载 / AI 编曲 / 转码 / 分轨 / 谱子)全在后端 Python;前端只负责界面、画落音符、放声、录像。
前端 ↔ 后端之间只用 HTTP 传两样东西:输入(URL 字符串 或 文件)输出(音符 JSON + 文件 URL)

PianoReel 有两套运行环境,逻辑一样,只有"文件怎么交付"那一处不同:


1. 每个组件在前端还是后端

组件在哪干什么文件
yt-dlp后端下载 YouTube 音频/视频services/youtube_service.py
ffmpeg后端音频转码 mp3、WebM→MP4youtube_service / render_audio.py / /transcode
Pop2Piano后端AI 把整首歌编成钢琴多轨engines/pop2piano_engine.py
Demucs后端分离原声 4 轨audio/stem_service.py
faster-whisper后端识别歌词逐词时间戳services/lyrics_service.py
FluidSynth后端音符→高音质钢琴 MP3audio/render_audio.py
music21 + LilyPond后端音符→谱子 PDF/XMLservices/sheet_service.py
————————
落音符动画 / 键盘前端Canvas 每帧绘制visual/visualizer.js
钢琴声(合成)前端WebAudio 合成器发声audio/synth.js
原声播放前端<audio> 播 mp3core/app.js
导出录制前端MediaRecorder 录画面+声core/app.js(再送后端转 MP4)
MIDI 解析前端Tone.js 直接读音符core/app.js(仅 MIDI 路径)
多语言/UI前端i18n + DOMcore/i18n.js

记忆法:凡是"要装 Python 库 / 系统工具 / 跑模型"的 → 后端;凡是"画图、出声、录屏" → 前端


2. 三条输入路径的数据流(关键)

路径 A · 上传 MP3/音频 → 经后端 AI 编曲

前端: 拿到 File → FormData(file) ──POST /arrange──▶ 后端
                                                    Pop2Piano 编曲
前端 ◀── JSON {tracks(音符), bpm, theme, title} ──┘
       loadMultitrack() → 画落音符 + 合成钢琴声

传的是文件本身;收的是音符 JSON

路径 B · YouTube 链接 → 后端下载 + 编曲(= A 前面多一步下载)

前端: 一个 URL 字符串 ──POST /youtube {url,style}──▶ 后端
                                              ① yt-dlp 读标题/时长(校验)
                                              ② yt-dlp 下音频 → ffmpeg 转 mp3
                                                 存 web/samples/yt_<id>.mp3
                                              ③ Pop2Piano 编曲
前端 ◀── JSON {tracks, bpm, title,            ┘
              audioUrl:"samples/yt_<id>.mp3"} ──
       loadMultitrack(data, audioUrl)
         ├ tracks → 画落音符
         └ <audio src="samples/yt_<id>.mp3"> 播原声

前端只传一个 URL;处理页那几步(下载/转码/编曲)全在后端一次 HTTP 里完成,前端等待时只放处理动画。

路径 C · MIDI → 完全在前端,不碰后端

前端: 读 .mid 文件 → Tone.js 解析出音符 → 直接进工作室(秒级)

不经 yt-dlp / ffmpeg / Pop2Piano —— MIDI 本身就含音符。

所以:A 和 B 殊途同归(都到 Pop2Piano);C 独立(纯前端、无 AI、秒出)。

3. 输出 / 导出怎么走

导出谁做流程
⬇ 视频 MP4前端录 + 后端转前端 MediaRecorder 录 Canvas+声(WebM) → POST /transcode → 后端 ffmpeg 转 MP4 → 下载
⬇ 谱子后端POST /sheet(传音符) → music21+LilyPond → PDF/XML
⬇ 高音质音频后端POST /render → FluidSynth → MP3
⬇ MIDI前端Tone.js 直接把音符写成 .mid
📷 封面 PNG前端Canvas toDataURL 直接存图

4. 核心机制:文件怎么从后端"交"到前端

这是最容易卡住新手、也是本地 vs 云唯一的差异点

本地:靠"共享文件夹"

云端:没有共享文件夹了 → 用 R2

本地:  后端写 web/samples/  →  返回 "samples/x.mp3"  →  前端同源取  ✅
云端:  后端传 R2          →  返回 "https://files…/x.mp3" → 前端从 R2 取  ✅

5. 上云:每个组件搬到哪

                      pianoreel.com
                           │
   ┌───────────────────────┼─────────────────────────────┐
   ▼                       ▼                              ▼
① 前端(静态)          ② API/登录/付费                ③ 文件
Cloudflare Pages      Cloudflare Workers + D1        Cloudflare R2
(免费)                + Stripe(收款)                 (存视频/音频,出站免费)
                           │ 入队 Queues
                           ▼
                  ④ 重型 AI 编曲/分轨/歌词
                     Modal (GPU, T4)
                     按秒计费,缩容到 0
组件搬到备注
前端 prototype/webCloudflare Pages纯静态,连 Git 自动部署
后端 FastAPI(全部 ML)Modal(GPU T4)现有 FastAPI 几乎直接搬;见 docs/17
生成的文件Cloudflare R2后端写 R2,前端从 R2 取
账号/订阅/配额Workers + D1要收费时才做
收款Stripe抽成,Webhook 通知 Workers
歌词模型(可选)Workers AI 自带 Whisper也可继续放 Modal

⚠️ YouTube 下载在云上会被封 IP(数据中心 IP→403)—— 见下一节的解决思路。


5.5 · ⭐ 候选目标架构:桌面轻 + 云端 ML(🟡 考虑中,未定)

纯 SaaS(全云)和纯桌面(全本地)各有短板。下面这套混合架构很可能是最优折中,
目前仍在考虑阶段、未拍板,先记录下来。

思路

桌面 App 负责"轻活 + 下载",云端只负责"重 ML"。

桌面 App(用户机器, 住宅 IP)            云端(Modal GPU)
─────────────────────────             ──────────────
· UI / 落音符渲染 / 播放
· yt-dlp 下载 YouTube  ← 住宅IP, 不被封 ✅
· ffmpeg 转 mp3(轻)
        │ 上传 mp3 ────────────────────▶ · Pop2Piano 编曲
        │ ◀── 音符 JSON + 生成文件 ────── · Demucs 分轨
· 导出 MP4(本地录+转, 轻)               · Whisper 歌词
                                        (重 ML, 要 GPU)

关键:云端不再碰 YouTube,只收一个音频文件(用户上传的、或桌面下好的,云端不在乎来源)——
这正是现有 MP3 路径的逻辑,后端几乎不用改

为什么这套好(三个问题一起解决)

问题解决
YouTube 云端被封 IP下载在用户机器(住宅 IP) → 天生没问题 ✅
用户没 GPU / 不想下几 GB 模型重 ML 在云端,用户机器只干轻活 ✅
怎么收费 / 防破解重 ML 在你服务器 → 天然防破解,正好做付费墙 ✅

轻 / 重怎么切(只有 3 个 ML 必须留云)

组件轻/重放哪
yt-dlp 下载轻(需住宅IP)桌面
ffmpeg / FluidSynth / LilyPond轻(CPU)桌面 或 云端
渲染 / 播放 / 导出桌面
Pop2Piano / Demucs / Whisper重(GPU)云端(付费墙)

→ 云端只为"编曲那几十秒 GPU"付钱,成本压到最低

YouTube 下载在三种分发路下分别怎么处理

分发路YouTube 下载说明
纯桌面 App用户本地下(住宅IP)天然没问题
纯 Web SaaS云服务器下被封,要住宅代理($/GB)或改"用户上传文件"
桌面轻 + 云端 ML(本节)用户本地下没问题 + 重 ML 仍可控可收费

还要注意(都不难)

  1. 桌面要打包 yt-dlp + ffmpeg 二进制(Electron 里带上)。
  2. 桌面↔云端加认证/license —— 只有付费用户能调你的 GPU(别被白嫖算力)。
  3. 桌面把 mp3 上传到云,一首几 MB,很快。
  4. 重 ML 仍按首付 GPU 钱(每首几日元)—— 这正是要收费的部分,合理。

取舍小结

🟡 状态:考虑中,未定。 真要做的话,现有后端基本可直接当"云端 ML 服务",桌面那层是新增的壳 + 把 yt-dlp/ffmpeg 搬到本地。

6. 成本详解(人民币 / 美元 / 日元)

项目价格折算何时花
域名 .com~$10/年¥70 / ¥1,500 一年一次性
Cloudflare Pages(前端)免费永久
Modal(GPU 编曲)每首 ~$0.02–0.05¥0.2 / 3–8 日元 一首按用量;送 $30/月免费额度
R2 存储$0.015/GB·月¥0.1 / 1.6 日元 每 GB量大才有感;10GB 内免费
R2 出站(下载)$0 免费用户下载视频不花钱
Workers(API)$5/月¥36 / ¥750 一月要做账号/付费时才订
Stripe(收款)2.9% + $0.30/笔$0.30 ≈ ¥2.2 一笔有人付钱才扣

三个省钱要点

  1. GPU 缩容到 0:没人用就不开机,别让 GPU 常驻(常驻小卡 24/7 ≈ ¥3,000+/月,纯浪费)。
  2. R2 设生命周期自动删:视频用户下载完没用了,N 天后自动删 → 存储常年在免费额度内。
  3. R2 出站免费:媒体产品在 AWS 最贵的就是下载流量,R2 砍掉这块。

不同阶段总花费

阶段月成本
自己用(一周一首)¥0 —— 本地 Mac 跑就行,不用云
小规模 demo(前端+Modal)基本免费(吃 Modal $30 额度),每首几日元
正式收费产品Workers $5/月 + R2 几块 + GPU 按量 → 月十几美元封顶 + 每首几日元

7. 现在能跑通吗?

一句话收尾:三件重活(yt-dlp / ffmpeg / Pop2Piano)全在后端,前端只画图放声;前后端用 HTTP 传 URL/文件和 JSON;本地靠共享目录交付文件,上云改成 R2。 这就是全部机制。

</content>

19 · 视觉升级评估 · 顶缘流光灯条 + 自定义背景

节点:看到两个爆款竖屏钢琴视频(TikTok),评估是否值得抄两个视觉特性。
结论:都做,因为 ~80% 复用现有代码,约 1 天工作量,是把视频从"能看"拉到"高级"的关键。

触发:两个参考样本

  1. ONE PIECE「1000回聞くやつ」(RYピアノ,赞 3,441)
    • 动漫画面当背景,假名音符 ラ/ド/ミ/ソ 从上落下,底部一排键盘,键盘顶有红线。
  2. Rush E(minapiano,赞 227.5万)
    • 暗房 + 键盘顶缘一条暖金色发光灯条,音符落下命中处爆一下辉光(bloom)。

用户提出两个想做的点:①键盘上缘发光曲线动画;②可设置背景(上传图片,YouTube 链接做模糊背景)


评估

① 键盘顶缘发光灯条 —— 优先级最高(⭐⭐⭐)

只需:常驻渐变条 + 命中点局部 bloom。

② 自定义背景:上传图片 / YouTube 模糊背景(⭐⭐)

③ 彩蛋:音符音名/唱名标签(顺手做,⭐)


决定

做不做优先级估时复用
① 顶缘流光灯条 + 命中 bloom✅ 做~0.5 天边缘辉光雏形 + shadowBlur
② 自定义背景(图片 / YT 模糊)✅ 做~0.5 天setBgVideo + drawVideoCover + /youtube_video
③ 音名/唱名标签✅ 顺手~1-2hmidi 已知

落地顺序:① → ③ → ②(先把质感拉满,再加面向日本的标签,最后做背景源)。


实现结果(已完成 ✅,2026-06-07)

三项全部落地、像素级/截图验证通过、已提交推送:

状态实现验证
① 顶缘灯条 + 命中 bloompiano-fx.js drawEdgeGlow:向上柔光溢出 + 亮线 + 命中处叠加爆光(衰减~20帧)。cfg.edge=theme/warm/off,所有 Look 自动获得像素采样:灯条行 87% 亮像素;爆光峰值纯白(765)
② 自定义背景(图片/YT模糊)visualizer.js bgSource(none/image/video)+setBgImage/setBgFx;通用 drawCover;超扫避免模糊黑边;YT 复用已下载的 compareVideo。新增「背景纸」面板(源+模糊+压暗)+ i18n像素采样 + 截图:上传图模糊压暗后透出,音符清晰可读
③ 音名/唱名标签piano-fx.js cfg.label=off/abc/solfa/kana,画在音符头部;kana=日本固定唱名(ドレミ)。组合式 FX 新增「音名标签」维度 + i18n截图:落音符上显示 ミ/ソ/シ/ラ/ド/レ,与 One Piece 参考一致

实现顺序为 ①→②→③(把用户明确要的背景先于彩蛋做)。缓存版本 v68→v73。

两个待定问题 → 最终结论(已落地 ✅)

其他待定

20 · 工作室右侧面板信息架构重组(尤其 YouTube 路径)

节点:用户反馈"右侧控制面板对 YouTube 路径太复杂、有点乱"。
结论:把"出片模式 / 叠加层 / 加载器 / 模式专属设置"四类混在一起的控件拆清,并按需展开。

问题

旧的「出片模式」一个框里塞了三种不同性质的控件,看起来全是相似按钮:

性质旧状(全挤在出片模式框)
① 选模式(画面长什么样)演奏 / 氛围 / 歌词 / 对比
② 加载素材(动词)加载人声 / 加载歌词 / 加载原视频 / 贴歌词
③ 某模式专属设置(且一直显示)语言 / 对比布局 / 原视频音量

③ 那些专属设置不管在不在该模式都常驻显示 → 信息过载。刚贴完 YouTube 链接进来的人尤其懵。

决策:四类拆清 + 渐进展开

  1. 出片模式 = 只剩 3 个基础画面:演奏 / 氛围 / 对比
  2. 歌词 = 独立叠加层(不再是模式):独立可折叠 section,一个显示歌词开关 + 自动识别/贴LRC/语言。
    • 引擎层:Visualizer.setLyricsOn(bool),渲染与 mode 解耦 → 歌词能叠在任意模式上(演奏+歌词、氛围+歌词…)。
  3. 对比专属控件按需展开#compareTools 只在选中「对比」时显示,含 加载原视频 / 对比布局 / 原视频音量。平时不占地方。
  4. 加载原视频改用 URL 输入框#cmpUrl):
    • YouTube 路径:自动预填已贴的链接,一点即载;
    • 音频/MIDI 路径:手动粘贴链接 → 对比/背景模式不再是 YouTube 路径专属,三条路径都能用。
  5. 加载人声归入「声部混音」section(它本就为多轨原声服务)。混音器渲染进 #mixerBody,静态标题保留按钮。

默认只展开「出片模式」,歌词/背景纸/混音等 section 折叠 → 初进画面很干净。

渐进展开原则

控件用到才显示:对比的子控件只在对比模式出现;歌词/背景/混音折叠收起。
把"加载素材"按钮移到它服务的对象旁边(视频→对比、歌词→歌词、人声→混音)。

验证

待办 / 另议

</content>
</invoke>

21 · 歌词从哪来(中日英)· 字幕 / 强制对齐 / Whisper

节点:歌词识别怎么做?YouTube 能不能下歌词?中日文 Whisper 难。
结论:分层兜底 —— YouTube 字幕 → 强制对齐(已知文本) → Whisper → 手贴 LRC

核心认识

分层兜底策略

优先来源时间轴适用状态
1️⃣YouTube 字幕(yt-dlp,优先人工)✅ 自带YouTube 路径、视频有字幕✅ 已做
2️⃣强制对齐(纯文本歌词 + 人声音频)✅ 算出中日英、有歌词文本无时间⏸ 暂缓(需装 aeneas/espeak,用户决定先不做)
3️⃣LRCLIB / 网易云(按曲名取 LRC)流行歌备选
4️⃣Whisper 识别人声(Demucs 人声轨)✅ 逐词任何音频、兜底✅ 已有
5️⃣手贴 LRC任何、最终兜底✅ 已有

路径差异:

① YouTube 字幕(已实现 ✅,v76)

② 强制对齐(⏸ 暂缓 —— 用户决定先不做,方案存档)

决策:Phase 1 的 YouTube 字幕 + 手贴 LRC + Whisper 兜底已覆盖大量场景;
强制对齐需装 aeneas/espeak(macOS 安装偶有摩擦),暂不做。等"有歌词文本但没时间"成强需求再启用。下方方案备查。

没歌词怎么办

⚠️ 版权

歌词受版权。本地/自用无碍;对外商用抓字幕/LRCLIB/网易云属灰色,正经做要 Musixmatch/LyricFind 授权。归 docs/15 法务。
</content>

22 · 阶段 2 · 后端 AI 上 Modal(部署手册)

目标:把后端(Pop2Piano/Demucs/Whisper/yt-dlp/ffmpeg)发布到 Modal 云 GPU,
让线上 dev.pianoreel.com 的 MP3 上传 / YouTube / 歌词真正能用。
部署文件:prototype/backend/modal_app.py

1. 一次性准备(你做)

cd ~/Documents/github/pianoreel/prototype/backend
.venv/bin/pip install modal
.venv/bin/python -m modal setup      # 弹浏览器授权,把账号和本机连起来

2. 部署(你做,我盯)

cd ~/Documents/github/pianoreel/prototype/backend
.venv/bin/modal deploy modal_app.py

3. 让前端指向它(我做)

把上面的地址填进 prototype/web/js/core/config.jsPROD_BACKEND,push → Cloudflare 自动重部署 → 线上 MP3/YouTube/歌词就活了。

4. modal_app.py 里做了什么

5. 已知待办 / 首次部署会一起调

线上要前端把它解析到 PROD_BACKEND。等拿到 Modal 地址后我加一个 mediaUrl() 解析(要联调,所以放部署时做)。

5.5 首次部署踩的坑(已解,记录备查)

  1. cannot mount volume on non-empty path /cache → 崩溃循环。

原因:把 HF_HOME/TORCH_HOME/XDG_CACHE_HOME=/cache/.. 写成镜像 ENV,build 期就往 /cache 写缓存,
导致挂卷时 /cache 非空。:这些缓存路径改在 web() 运行时(卷挂好后)再 os.environ 设置。

  1. /arrange 500:'NoneType' object is not callable(proc=None,秒崩)。

原因:Pop2Piano 处理器依赖 essentia;① 镜像漏装 essentia;② 装了但 **essentia 2.1b6 用 numpy 1.x ABI 编译,
遇 numpy 2.x → import essentia 崩 → is_essentia_available()=False → 处理器构建成 None**。
pip_install("essentia","resampy") + 主层钉 numpy<2
诊断技巧:在 web() 里临时加 /debug_deps 端点,curl 秒看依赖(免冷启诊断容器)。

  1. YouTube 被限流/youtube* 报“要求验证”)。

原因:Modal 数据中心 IP 被 YouTube 封(docs/13/18 早有预判)。MP3 上传路径不受影响。
待解:cookies / 住宅代理 / 桌面端下载的混合架构(docs/18 §5.5)——单独处理。

当前状态(阶段 2)

能力云端说明
/health · CORS放行 dev/主域
MP3 上传 → Pop2Piano 编曲T4 GPU,首次载模型~28s,之后更快
分轨 / 谱子 / 高音质 / 转码🔜同镜像应可用,待逐个验证
YouTube 下载(音频/视频/字幕)数据中心 IP 被封,待 cookies/代理/混合

6. 排错

</content>

23 · 双轨产品策略:网页版(干净)+ 桌面 App(全功能)

节点:YouTube 云端下载被数据中心 IP 封 + 下载本身违反 ToS/版权(灰色)。
决策:不在网页端做 YouTube 下载;网页保持"干净",YouTube 全部交给"桌面 App"在用户本机完成。
形成网上 + 线下两条路

决策

维度🌐 网页版 pianoreel.com💻 桌面 App(本地)
输入只接受上传音频(MP3/WAV/M4A/MIDI)YouTube 下载 + 上传音频 + 解析(全部)
后端Modal 云 GPU(已上线,MP3→钢琴 已通)本地后端(用户机器上跑,现有 make dev 那套)
网络/IP不碰 YouTube → 不会被封用户住宅 IP → YouTube 能正常下
定位干净、安全、合规友好、门槛低、即开即用全功能、强大,面向重度/创作者
版权负担我们的服务器不下载任何 YouTube下载发生在用户自己机器,责任随之转移

一句话:把 YouTube 下载的 IP 封锁 + 版权/ToS 负担,从"我们的云服务器"转移到"用户自己的电脑"。网页端保持干净低风险,桌面端保留全部能力。

为什么这样分

两版怎么共用

现状

待定(桌面 App 起步时再定)

关联文档

</content>

24 · 统一账号 + 付费(网页 & 桌面共用)

节点:双轨(docs/23)下,账号怎么处理?
决策:统一账号 —— 一个账号、一份订阅,网页版和桌面 App 通用

决策

架构

        ┌──────── 云端:唯一的账号 / 付费中心 ────────┐
        │  Auth(登录)  +  订阅状态(Stripe)            │
        │  Cloudflare Workers + D1 + Stripe          │
        └────▲──────────────────────────▲───────────┘
             │ 登录 / 查授权              │ 登录 / 查授权
        🌐 网页版                       💻 桌面 App
        (ML 在 Modal)                  (ML/YouTube 在本地)

关键点:功能由"账号套餐"决定,不由客户端决定

待定

现状 / 依赖

</content>

📒 项目文档 Playbook —— 把成长过程写下来(可复制到任何项目)

这是一套项目无关的文档组织与维护方法:一个项目从 0 慢慢长大,
每个目标、决策、功能、取舍都留一篇记录,形成可追溯的成长史
直接把本文 + tools/build-docs.js 复制到新项目即可起步。

一、核心理念

  1. 写过程,不只写结果 —— 不是"做完再补文档",而是边做边记:每做一个大功能 / 大决策,就留一篇。
  2. 文档会长大 —— 随项目持续更新,不是写完就扔。
  3. 一个权威源 —— 永远有一篇"当前状态"作为唯一真相,别处过时了以它为准。
  4. 可浏览 —— 把 markdown 编译成一个离线 HTML 文档站,自己/协作者/非技术的人都能一页翻完。

二、目录结构

项目根/
├── README.md              入口:本地启动、服务/端口、快速上手
├── ARCHITECTURE.md        架构地图:代码在哪、数据怎么流、怎么加东西
├── docs/
│   ├── 00-status.md       ⭐ 唯一权威状态(目标 / 进度 / 最终形态)—— 第一个看的
│   ├── 01-xxx.md          按主题/决策/功能编号递增
│   ├── 02-xxx.md          (每个里程碑或大决策一篇)
│   ├── …                  13-youtube · 14-vision · 16-monetization · 18-architecture …
│   └── DOC-PLAYBOOK.md     本文(方法论本身)
├── tools/build-docs.js    把 docs/*.md → 单文件 docs.html(无依赖、离线)
└── (生成)web/docs.html   可浏览的文档站

三类文档分工:


三、工具:build-docs.js

docs/*.md 编译成一个自包含、离线可开docs.html(左侧导航 + markdown 渲染,支持标题/表格/代码/引用/列表)。


四、维护纪律(养成习惯)

  1. 每个大决策 / 大功能 → 一篇编号 doc(例:13 YouTube 导入、14 形态发散、16 分发收费、17 上线、18 机制与成本)。
  2. 00-status.md 随时更新 —— 完成/在做/没做、关键指标。它是"现在到哪了"的唯一答案。
  3. 改了任何 doc → make docs 重建 docs.html,和 doc 一起提交。
  4. 一篇一提交,commit message 写清这篇讲什么(将来翻 git log 就是项目编年史)。
  5. 旧文档过时不删 —— 顶部加一句"以 00-status.md 为准"的横幅,保留历史比删掉更有价值。
  6. 决策类文档留「待定问题」小节 —— 持续填,把纠结写下来避免反复。
  7. 聊出来的重要结论及时落档 —— 讨论清楚一个取舍,就顺手写进对应 doc(别只留在聊天里)。

五、在新项目里起步(5 步)

  1. docs/,先写 docs/00-status.md(目标 / 进度 / 最终形态 三段)。
  2. 复制 tools/build-docs.js,改 FILES 列表为你的文档。
  3. 加一个 make docs(或 npm script)跑 build-docs。
  4. 之后每个里程碑/决策写一篇,更新 00-statusmake docs 重建,提交。
  5. (可选)写 ARCHITECTURE.md 当代码地图;前端项目加 make bump 管缓存版本。

六、为什么这套有用


一句话:**每做一件大事,就留一篇;永远有一篇 00-status 说清现在到哪了;
把 markdown 编成可浏览的 docs.html。** 这就是全部方法。

</content>