十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

XiaoMusic 深度拆解:一条语音指令如何变成音箱里的歌

XiaoMusic 深度拆解:一条语音指令如何变成音箱里的歌 XiaoMusic 深度拆解一条语音指令如何变成音箱里的歌【免费下载链接】xiaomusic使用小爱音箱播放音乐音乐使用 yt-dlp 下载。项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic小爱音箱里能播什么歌最后取决于版权方曲库是别人的你说播放播出来什么也是别人定的。XiaoMusic 把这个关系翻了过来——它跑在你自己的服务器上用 yt-dlp 把歌搜索、下载进本地音乐库再让小爱音箱通过语音指令播放。本质上它是个人音乐服务器 音箱语音通道接管器。它是怎么跑起来的核心链路拆解整条链路是一个拉取—匹配—执行的结构按顺序分五步ConversationPoller每pull_ask_sec秒默认 1 秒轮询小爱对话接口拉取音箱最近的 query拉到新对话后触发new_record_event主循环暂停轮询把(did, query)交给do_check_cmdCommandHandler做命令匹配先全等匹配再按key_match_order的顺序用正则匹配把歌名抠出来当参数匹配成功后先force_stop_xiaoai掐掉音箱那句我不理解的提示音再分发到XiaoMusic的对应方法如play设备播放器先在本地库找歌找不到就走 JS 插件在线搜索 yt-dlp 下载然后播放本地文件。最值得细看的是第 2 步的主循环代码不长# conversation.py 主循环等新对话记录处理命令期间暂停轮询再转交命令处理器 await self.new_record_event.wait() self.new_record_event.clear() new_record self.last_record self.polling_event.clear() # stop polling when processing the question query new_record.get(query, ).strip() did new_record.get(did, ).strip() await do_check_cmd_callback(did, query, False)为什么是轮询而不是推送因为音箱这一侧没有回调入口只能定期问对话接口有没有新话。这里有两个细节一是收到命令的瞬间会暂停轮询polling_event.clear()避免同一条 query 被处理两遍或长命令执行期间混入上一条的旧 query二是命令执行后会根据音箱回答的 TTS 文本长度估算它还要说多久reset_timer_when_answer作为后续下一首等指令的计时依据。整套设计都建立在一个假设上你对音箱没有控制权只有一个查询接口所有状态都得自己推断。动手搭起来最短路径部署最省事的方式是 Docker 镜像。启动后几乎所有配置都能在 web 设置页完成不再需要折腾环境变量。官方给的最小配置长这样# docker-compose.yml官方推荐的最小部署两个卷分别放音乐和配置 services: xiaomusic: image: hanxi/xiaomusic container_name: xiaomusic restart: always ports: - 58090:8090 volumes: - /xiaomusic_music:/app/music - /xiaomusic_conf:/app/conf唯一的坑是两个卷目录在宿主机上不存在就先mkdir -p建好。启动成功后访问http://NAS_IP:58090先在设置页填入小米账号密码并保存——设备列表要在这之后才会出现。几个关键参数说明如下参数作用建议怎么填58090:8090宿主机端口:容器端口容器侧 8090 固定左边随意改右边保持 8090/app/music音乐库目录容器侧挂独立分区方便备份/app/conf配置文件目录容器侧与 music 分开挂载restart: always崩溃自动拉起长期运行必备源码开发模式三句话带过git clone https://gitcode.com/GitHub_Trending/xia/xiaomusic然后跑./install_dependencies.sh和pdm install用pdm run xiaomusic.py启动默认端口 8090接口文档在/docs。几个值得细看的功能设计指令匹配的两级策略与 exec# 后门它解决的问题是语音文本是自由形式的播放歌曲周杰伦晴天和下一首要走完全不同的处理系统得先判断这是哪条命令、参数在哪。匹配顺序由配置里的key_match_order定义参数用正则(.*)(关键词)(.*)抠出来。有意思的是exec#前缀配置片段如下配置示例摘自 config-example.json展示关键词到命令的映射{ key_word_dict: { 播放歌曲: play, 下一首: play_next, 测试自定义口令: exec#code1(\hello\) }, fuzzy_match_cutoff: 0.6 }这里的设计取舍是key_word_dict可以把任意关键词映射到XiaoMusic的任意公开方法内置指令和自定义指令的边界其实是同一套机制而exec#更进一步让一条语音口令直接执行 Python 插件文件里的函数比如plugins/code1.py等于不用动核心代码就能加自己的语音触发器。代价也很直白语音口令的安全性取决于你插件代码的质量。在线搜索音源是可替换的 JS 插件它解决的问题是音乐平台接口变动频繁如果把平台逻辑写死在核心里项目就得追着平台改。OnlineMusicService不直接对接任何平台而是通过JSPluginManager由js_plugin_runner.js跑 JS 插件路由支持 MusicFree 和 LX Server 两类接口核心代码只负责构建搜索关键词和挑音质# online_music.py下载前的音质优先级和搜索关键词构建 LX_QUALITY_PRIORITY [master, flac24bit, flac, 320k, 192k, 128k] def _build_keyword(song_name, artist): if song_name and artist: return f{song_name}-{artist} return song_name or artist搜索词用歌名-歌手的格式配合search_prefix: bilisearch:控制 yt-dlp 的搜索源音质按优先级列表从高到低选。这个分层的好处是核心仓库不用跟着平台接口一起抖动某个音源挂了换掉 JS 插件即可上面的播放链路完全不动。踩坑与调优真实场景下你会遇到什么社区反馈最多的是下面这几类现象大概率原因怎么解决音箱回答我不理解关键词没匹配上或命令未启用检查key_word_dict和fuzzy_match_cutoff默认 0.6启动后设备列表为空没配小米账号先在 web 设置页填账号密码并保存部分 flac 放不出来型号不支持L05B、LX06、L16A 等打开转换为MP3和型号兼容模式下载慢、在线搜索失败网络到不了音源在设置里配 proxy公网暴露无防护disable_httpauth默认 true公网必须开密码登录设复杂密码我不理解这个坑排查路径其实是固定的。先看日志里收到消息: xxx这行确认 query 被拉到了再看match_cmd是否打出未匹配到指令——如果是要么关键词不在字典里要么句式没进正则。这里有个隐藏规则不在active_cmd列表里的命令只有音箱正在播放时才会生效设计意图是避免日常对话误触发所以设备没在播时喊口令没反应多半就是没加进active_cmd。最后的手段是调key_match_order把关键词挪到更靠前——播放歌曲和播放歌单同句出现时先匹配到的赢。日志两个入口docker logs -f xiaomusic看实时输出或 web 设置页底部的下载日志文件按钮对外分享前先搜一遍确认没有账号密码残留。它还能往哪里走先把丑话说在前面这个项目已经停止活跃维护README 顶部有明确公告作者推荐社区接力项目 songloftissue 区也不再处理新反馈。所以如果要长期部署先看接力项目把本仓库当作一份成熟的参考实现来读。它的技术资产仍然有参考价值想魔改的话入口在两处JS 插件走 xiaomusic/js_plugin_manager.py由js_plugin_runner.js执行Python 级自定义命令放 plugins/ 目录code1.py是现成示例再配合配置里的exec#映射即可不需要动主流程。一句话总结XiaoMusic 本质上是个劫持音箱语音通道的个人音乐服务器把本地曲库和在线搜索结果变成音箱的播放列表。有小爱音箱、想让曲库归自己管的人它是目前最完整的参考实现想要持续更新的版本直接看社区接力项目。手里正好有台 NAS 和闲置音箱的话今晚就能把容器跑起来。【免费下载链接】xiaomusic使用小爱音箱播放音乐音乐使用 yt-dlp 下载。项目地址: https://gitcode.com/GitHub_Trending/xia/xiaomusic创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表