码道:「耳遇Musicing」戴上耳机,世界就成了只属于你的梦。
@ 耳遇 · 音乐推荐器 AI 对话(EarMeet AI Music)
寻找你的专属vov
**场景 × 性格 · 双维度智能匹配你的专属歌单
耳遇是一款纯前端(HTML5 + CSS3 + JavaScript)的 AI 音乐推荐应用。它借助 GitCode AI 的 DeepSeek-V4-Flash 大模型能力,将用户选择的**「场景」(通勤/工作/运动/深夜/旅行/睡眠/雨天/聚会)与「性格」(外向/内敛/浪漫/理性/热血/洒脱/完美/探索)两个维度组合建模,通过流式对话生成结构化 JSON 歌单数据**,再由前端进行精美的卡片化渲染,打造"会聊天、懂心情、懂得推荐"的 AI 音乐顾问。

-
✨ 核心特性
| 特性 | 说明 |
|---|---|
| 🧭 双维度画像 | 8 种场景 × 8 种性格,自由组合出 64 种个性化画像 |
| 💬 AI 流式对话 | 基于 SSE 流式输出,逐字渲染对话内容(含深度思考过程提示) |
| 📄 JSON 结构化返回 | 大模型严格按约定 Schema 返回歌单 JSON,两端协议清晰 |
| 🎵 歌单卡片渲染 | 歌单封面渐变、情绪标签、能量值、关键词云、双维匹配度进度条一应俱全 |
| 🤖 复合式对话 | 推荐完成后 AI 继续以朋友口吻引导追问"换首更轻快的 / 换成粤语歌" |
| 🛟 离线兜底 | 内置 60+ 首本地精选曲库,AI 接口异常时自动降级为本地推荐 |
| 📱 响应式布局 | 1440px 三栏工作台 → 1180px 两栏 → 移动端单栏流畅适配 |
| 🌌 沉浸视觉 | 暗夜星空 × 玻璃拟态 × 律动光斑,深度沉浸的音乐氛围 |
🚀 快速开始
项目为零构建、零依赖的纯静态站点,任意静态服务器即可运行:
# 方式一:Python 静态服务器
python3 -m http.server 8080
# 方式二:Node 静态服务器
npx serve .
# 方式三:任意 IDE 的 Live Server 插件(VS Code 等)
浏览器打开 http://localhost:8080 即可使用。
⚠️ 请务必通过 HTTP 服务器访问(而非直接双击打开
file://),避免浏览器 CORS 与 fetch 限制。
🎮 使用说明
- 选择维度:在左侧分别点选一个「场景」和一个「性格」(各选其一,可重复更换)。
- 发起推荐:点击
✨ 开始智能推荐,或使用快捷指令一键触发。 - 等待生成:耳遇会先进入"深度思考中…“状态,随后聊天区以流式显示"正在为你编织专属歌单…”。
- 查看结果:右侧自动渲染完整歌单卡片 —— 歌单名、情绪、能量、关键词、逐首歌曲的场景/性格匹配度与推荐理由。
- 自由对话:继续追问 AI,比如
为什么推荐《Eye of the Tiger》?或换一首更温柔的,AI 会边聊边按需重新推荐。
🔌 AI 接口参考(Python → JavaScript 转换)
项目调用 GitCode AI 的 OpenAI 兼容 Chat Completions 接口:
POST https://api-ai.gitcode.com/v1/chat/completions
原始 Python 参考代码
import os
import requests
API_URL = "https://api-ai.gitcode.com/v1/chat/completions"
headers = {
"Authorization": f"Bearer {os.environ['API_KEY']}",
}
def query(payload):
response = requests.post(API_URL, headers=headers, json=payload, stream=True)
for line in response.iter_lines():
if not line.startswith(b"data:"):
continue
if b"[DONE]" in line:
return
yield json.loads(line.decode("utf-8").lstrip("data:"))
for chunk in query({
"model": "deepseek-ai/DeepSeek-V4-Flash",
"messages": [{"role": "user", "content": "告诉我一个有关宇宙的有趣事实?"}],
"stream": True,
"max_tokens": 2048,
"temperature": 0.6,
"top_p": 0.95,
"frequency_penalty": 0,
"thinking_budget": 2048
}):
print(chunk["choices"])
转换要点(js/api.js)
| Python | JavaScript 对应实现 |
|---|---|
requests.post(..., stream=True) | fetch(url, { method: 'POST', body: JSON.stringify(payload) }) |
response.iter_lines() | response.body.getReader() + TextDecoder 逐行切分 |
line.startswith(b"data:") | parseSSELine():line.trim().startsWith('data:') |
b"[DONE]" in line | /\[DONE\]/i.test(data) → 结束标记 |
json.loads(line.lstrip("data:")) | JSON.parse(data.slice(5)),逐块解出 choices[0].delta |
yield 生成器 | 回调机制 onReasoning / onText / onDone / onError |
核心流读取逻辑:
const reader = response.body.getReader();
const decoder = new TextDecoder("utf-8");
let buffer = "";
while (true) {
const { done, value } = await reader.read();
if (done) break;
buffer += decoder.decode(value, { stream: true });
// 按 \n 切分,逐行解析 data: {...}
}
📦 歌单 JSON 返回格式
大模型收到系统提示词(js/config.js 中 SYSTEM_PROMPT)后,必须且仅输出一行可被 JSON.parse 直接解析的 JSON。结构如下:
{
"playlist": {
"name": "深夜仪式感·私享浪漫",
"theme": "在深夜独处的时刻,为感性浪漫的你定制的声音旅程",
"mood": "静谧温柔",
"energy": 25,
"cover_gradient": ["#7c5cff", "#3fb6ff"],
"keywords": ["深夜", "独处", "浪漫", "仪式感"],
"tracks": [
{
"title": "旅行的意义",
"artist": "陈绮贞",
"album": "华丽的冒险",
"genre": ["民谣", "治愈"],
"reason": "细腻的歌词与木吉他声,像在夜色中翻阅回忆的相册,完美契合深夜独处时感性浪漫的自我对话。",
"scene_match": 95,
"personality_match": 90
}
]
}
}
字段说明
| 字段 | 类型 | 说明 |
|---|---|---|
playlist.name | string | 歌单名称 |
playlist.theme | string | 一句主题描述 |
playlist.mood | string | 情绪氛围标签(静谧/燃爆/治愈…) |
playlist.energy | int(0-100) | 能量值,决定视觉与氛围感知 |
playlist.cover_gradient | string[2] | 封面渐变色,前端动态应用 |
playlist.keywords | string[] | 关键词云 |
tracks[].title | string | 歌名 |
tracks[].artist | string | 歌手 |
tracks[].album | string | 专辑/风格备注 |
tracks[].genre | string[] | 曲风标签 |
tracks[].reason | string | 推荐理由(含场景×性格双向解释) |
tracks[].scene_match | int(0-100) | 场景匹配度 |
tracks[].personality_match | int(0-100) | 性格匹配度 |
前端在 js/api.js 中通过 extractJSON()(支持整体解析 / ```json 代码块 / 花括号截取三级兜底)+ normalizePlaylist()(字段补全与钳制)对模型输出做容错归一化,确保无论模型如何输出都能稳定渲染。
🗂 项目结构
eryuyinyuetuijianqi_temp/
├── index.html # 页面骨架(三栏布局)
├── css/
│ └── style.css # 暗夜星空 × 玻璃拟态主题样式
├── js/
│ ├── config.js # API 配置 / 场景×性格维度 / 系统提示词
│ ├── local_songs.js # 60+ 首本地精选曲库(离线兜底)
│ ├── api.js # Python→JS 转换的 SSE 流式调用 + JSON 解析
│ ├── render.js # 消息渲染 / 歌单卡片渲染 / 匹配度进度条
│ └── app.js # 主应用逻辑:维度状态、推荐流程、流式对话
├── README.md # 本文档
└── BLOG 耳遇.md # 项目展示博客文章
⚙️ 配置说明
所有可调参数集中在 js/config.js:
| 配置项 | 默认值 | 说明 |
|---|---|---|
API_URL | https://api-ai.gitcode.com/v1/chat/completions | GitCode AI 接口地址 |
API_KEY | (项目内置示例 Key) | 建议替换为你自己的 GitCode AI Key |
MODEL | deepseek-ai/DeepSeek-V4-Flash | 模型名 |
TEMPERATURE | 0.6 | 创造力(推荐场景可调低更稳定) |
THINKING_BUDGET | 2048 | 深度思考预算 token 数 |
🔐 安全提示
- 本项目为纯前端演示,API Key 内置在
js/config.js,任何用户均可通过浏览器 DevTools 查看。 - 如需对外公开部署,强烈建议在服务端做一层代理(Node/Python/Gateway),将 Key 保存在环境变量中,前端仅请求自己的代理地址。
- 请勿将携带真实 Key 的仓库设置公开访问(示例 Key 请及时在 GitCode 控制台重置)。
🧪 已实现能力自测
- ✅ 维度选择与 UI 状态同步
- ✅ 真实 AI 流式对话(含推理思考过程提示)
- ✅ 歌单 JSON 解析与卡片渲染(含双维匹配度进度条)
- ✅ 推荐完成后的 AI 追问引导
- ✅ 接口异常 → 本地曲库兜底推荐
- ✅ 响应式布局(1440 / 1180 / 800 / 480px 四档断点)
- ✅ 控制台零错误、页面零 XSS 注入点(所有动态文本均 HTML 转义)
📄 博客
项目展示博客:《码道 · 耳遇》见仓库根目录 BLOG 耳遇.md(5000 字以上),完整记录了产品理念、技术方案与开发心路。
🧩 路线图(Roadmap)
- 多选场景支持("通勤 + 雨天"组合推荐)
- 歌单收藏 / 导出(分享链接、下载 JSON)
- 接入音乐平台真实试听(需版权接口权限)
- 服务端代理封装,隐藏 API Key
- 用户画像库:多次对话后持久化性格偏好
📜 许可
仅供学习交流使用。歌曲信息由 AI 生成,版权归原作者所有。
更多推荐


所有评论(0)