add_py_xiaozhi

This commit is contained in:
“wangquan” 2025-07-18 13:14:28 +08:00
parent 57fdf656b9
commit 3b5b8ff7c1
182 changed files with 30464 additions and 0 deletions

6
py-xiaozhi-main/.flake8 Executable file
View File

@ -0,0 +1,6 @@
[flake8]
max-line-length = 88
extend-ignore = D100,D104,D401,E203,W503,D400,I001
exclude = .git,__pycache__,.venv,build,dist
import-order-style = google
application-import-names = py_xiaozhi

View File

@ -0,0 +1,32 @@
---
name: Bug 报告Bug Report
about: 反馈项目中的缺陷或问题
title: "[Bug] 简短描述问题"
labels: bug
assignees: ''
---
## 🐛 问题描述
<!-- 清晰简洁地描述问题是什么 -->
## 🔍 复现步骤
<!-- 详细描述复现问题的步骤 -->
1. 打开 '...'
2. 点击 '...'
3. 滚动到 '...'
4. 看到错误
## 🤔 预期行为
<!-- 简要描述预期的正确行为 -->
## 😯 截图
<!-- 如果适用,添加问题的截图 -->
## 🖥️ 环境信息
- 操作系统: [例如 Windows 10]
- 项目版本: [例如 1.0.0]
- Python版本: [例如 3.9.13]
- Nodejs版本: [例如 v20.14.0]
## 📋 其他信息
<!-- 在此添加关于此问题的任何其他上下文信息 -->

View File

@ -0,0 +1,19 @@
---
name: 代码优化建议Code Improvement
about: 提出对现有代码的优化或改进建议
title: "[Improvement] 简短描述改进内容"
labels: refactor
assignees: ''
---
## 💡 改进描述
<!-- 描述需要改进的代码部分以及存在的问题 -->
## 🌟 改进建议
<!-- 提出具体的改进方案或思路 -->
## 🛠️ 相关代码
<!-- 如果可能,提供相关代码片段或链接 -->
## 📋 其他信息
<!-- 在此添加任何其他相关信息 -->

View File

@ -0,0 +1,16 @@
---
name: 文档改进建议Documentation Improvement
about: 提出对项目文档的改进或补充建议
title: "[Docs] 简短描述改进内容"
labels: documentation
assignees: ''
---
## 📚 改进描述
<!-- 描述需要改进的文档部分以及存在的问题 -->
## ✨ 改进建议
<!-- 提出具体的改进方案或内容 -->
## 📋 其他信息
<!-- 在此添加任何其他相关信息 -->

View File

@ -0,0 +1,19 @@
---
name: 功能请求Feature Request
about: 提出新的功能或改进建议
title: "[Feature] 简短描述功能"
labels: enhancement
assignees: ''
---
## 🚀 需求描述
<!-- 清晰简洁地描述你希望发生什么 -->
## 🎯 解决方案
<!-- 描述你认为可行的解决方案或实现方式 -->
## 📝 备选方案
<!-- 描述你考虑过的替代方案或功能 -->
## 📋 其他信息
<!-- 在此添加关于需求的任何其他上下文信息 -->

View File

@ -0,0 +1,119 @@
name: Setup Inno Setup, Conda, and Build
on:
push:
branches:
- main
jobs:
setup-and-build:
runs-on: windows-latest
steps:
# 检出代码
- name: 检出代码
uses: actions/checkout@v4
# 安装 Inno Setup
- name: 安装 Inno Setup通过 Chocolatey
run: choco install innosetup -y
shell: powershell
# 下载 ChineseSimplified.isl 文件
- name: 下载中文语言文件
run: |
$languageDir = "C:\Program Files (x86)\Inno Setup 6\Languages"
# 确保目录存在
if (-not (Test-Path $languageDir)) {
New-Item -ItemType Directory -Path $languageDir -Force
}
# 下载中文语言文件
Invoke-WebRequest -Uri "https://raw.githubusercontent.com/jrsoftware/issrc/main/Files/Languages/Unofficial/ChineseSimplified.isl" -OutFile "$languageDir\ChineseSimplified.isl"
Write-Host "已下载中文语言文件到 $languageDir\ChineseSimplified.isl"
# 验证文件是否存在
if (Test-Path "$languageDir\ChineseSimplified.isl") {
Write-Host "文件下载成功!"
} else {
Write-Error "文件下载失败!"
exit 1
}
shell: powershell
# 查找 ISCC.exe 路径并更新 build.json
- name: 查找 ISCC.exe 路径并更新 build.json
run: |
# 获取 ISCC 路径
$isccPath = Get-Command ISCC.exe | Select-Object -ExpandProperty Source
# 设置环境变量
$envLine = "ISCC_PATH=$($isccPath -replace '`r','' -replace '`n','')"
[System.IO.File]::AppendAllText($env:GITHUB_ENV, "$envLine`n", [System.Text.Encoding]::UTF8)
# 读取 JSON 内容
$jsonPath = "build.json"
$json = Get-Content $jsonPath -Raw | ConvertFrom-Json
# 设置新的 Inno Setup 路径
$json.inno_setup_path = $isccPath
# 写回 JSON 文件,格式化为 UTF-8 编码
$json | ConvertTo-Json -Depth 10 | Out-File -FilePath $jsonPath -Encoding UTF8
Write-Host "已更新 build.json 中的 Inno Setup 路径为: $isccPath"
shell: powershell
# 安装 Miniconda 和 Conda
- name: 安装 Miniconda 和 Conda
uses: conda-incubator/setup-miniconda@v3
with:
python-version: "3.10"
auto-update-conda: true
auto-activate-base: false
activate-environment: py-xiaozhi
# 创建 Conda 环境并安装依赖
- name: 创建 Conda 环境 py-xiaozhi
shell: bash -el {0}
run: conda create -n py-xiaozhi python=3.10 -y
# 创建一个简单的 requirements.txt 文件(如果不存在)
- name: 创建 requirements.txt
run: |
if (-not (Test-Path "requirements.txt")) {
Set-Content -Path "requirements.txt" -Value ""
}
shell: powershell
# 安装 Python 依赖pip + conda + pyinstaller
- name: 安装 Python 依赖pip + conda + pyinstaller
shell: bash -el {0}
run: |
conda activate py-xiaozhi
# 安装依赖
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
conda install pyqt=5.15.10 opencv=4.10.0 -y
pip install pyinstaller
# 拉取 UnifyPy 仓库
- name: 拉取 UnifyPy 仓库
run: git clone https://github.com/huangjunsen0406/UnifyPy.git
shell: bash
# 运行 UnifyPy 构建项目
- name: 运行 UnifyPy 构建项目
shell: bash -el {0}
run: |
conda activate py-xiaozhi
export PYTHONIOENCODING=utf-8
python UnifyPy/main.py . --config build.json
# 只上传 Inno Setup 安装程序
- name: 上传安装程序
uses: actions/upload-artifact@v4
with:
name: installer-setup
path: installer/

View File

@ -0,0 +1,46 @@
# workflow 名称,可以自定义
name: Deploy GitHub Pages
# 触发条件:在代码 push 到 master 分支后,自动执行该 workflow
on:
push:
branches:
- main
# 任务
jobs:
build-and-deploy:
# 服务器环境:最新版 Ubuntu也可以自定义版本
runs-on: ubuntu-latest
steps:
# 拉取代码
- name: Checkout
uses: actions/checkout@v2
with:
fetch-depth: 0
# 设置 Node.js 版本
- name: Setup Node.js environment
uses: actions/setup-node@v1
with:
node-version: "18.20.3"
# 安装yarn
- name: Install yarn
run: npm i yarn -g
# 如果缓存没有命中,安装依赖
- name: Install dependencies
run: cd documents && yarn install
# 生成静态文件
- name: Build
run: cd documents && yarn docs:build
# 部署到 GitHub Pages
- name: Deploy
uses: crazy-max/ghaction-github-pages@v2
env:
GITHUB_TOKEN: ${{ secrets.ACCESS_TOKEN }} # ACCESS_TOKEN 是创建的 Secret 名称,替换为你自己创建的名称
with:
target-branch: gh-pages # 部署到 gh-pages 分支master 分支存放的是项目源码,而 gh-pages 分支则用来存放生成的静态文件
build_dir: documents/docs/.vitepress/dist # vuepress 生成的静态文件存放的地方

32
py-xiaozhi-main/.gitignore vendored Executable file
View File

@ -0,0 +1,32 @@
/logs
/config
.venv
**/__pycache__/
.idea/
venv/
# 音乐缓存
cache/
/models
# 打包相关
/build
/dist
# MACOS
.DS_Store
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
xiaozhi.spec
/installer

14
py-xiaozhi-main/.vscode/settings.json vendored Executable file
View File

@ -0,0 +1,14 @@
{
"python.formatting.provider": "black",
"editor.formatOnSave": true,
"editor.codeActionsOnSave": {
"source.organizeImports": "always"
},
"python.formatting.blackArgs": ["--line-length", "88"],
"python.formatting.blackPath": "/Users/junsen/miniconda3/envs/py-test/bin/black",
"python.linting.flake8Enabled": true,
"python.linting.enabled": true,
"python.linting.flake8Args": [
"--max-line-length=88"
]
}

21
py-xiaozhi-main/LICENSE Executable file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2025 Junsen
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

189
py-xiaozhi-main/README.en.md Executable file
View File

@ -0,0 +1,189 @@
# py-xiaozhi
<p align="center">
<a href="https://github.com/huangjunsen0406/py-xiaozhi/releases/latest">
<img src="https://img.shields.io/github/v/release/huangjunsen0406/py-xiaozhi?style=flat-square&logo=github&color=blue" alt="Release"/>
</a>
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-green.svg?style=flat-square" alt="License: MIT"/>
</a>
<a href="https://github.com/huangjunsen0406/py-xiaozhi/stargazers">
<img src="https://img.shields.io/github/stars/huangjunsen0406/py-xiaozhi?style=flat-square&logo=github" alt="Stars"/>
</a>
<a href="https://github.com/huangjunsen0406/py-xiaozhi/releases/latest">
<img src="https://img.shields.io/github/downloads/huangjunsen0406/py-xiaozhi/total?style=flat-square&logo=github&color=52c41a1&maxAge=86400" alt="Download"/>
</a>
<a href="https://gitee.com/huang-jun-sen/py-xiaozhi">
<img src="https://img.shields.io/badge/Gitee-FF5722?style=flat-square&logo=gitee" alt="Gitee"/>
</a>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/guide/00_%E6%96%87%E6%A1%A3%E7%9B%AE%E5%BD%95.html">
<img alt="Usage Docs" src="https://img.shields.io/badge/Usage Docs-View-blue?labelColor=2d2d2d" />
</a>
</p>
English | [简体中文](README.md)
## Project Introduction
py-xiaozhi is a Python-based Xiaozhi voice client, designed to learn coding and experience AI voice interaction without hardware requirements. This repository is ported from [xiaozhi-esp32](https://github.com/78/xiaozhi-esp32).
## Demo
- [Bilibili Demo Video](https://www.bilibili.com/video/BV1HmPjeSED2/#reply255921347937)
![Image](./documents/docs/guide/images/系统界面.png)
## Features
- **AI Voice Interaction**: Supports voice input and recognition, enabling smart human-computer interaction with natural conversation flow.
- **Visual Multimodal**: Supports image recognition and processing, providing multimodal interaction capabilities and image content understanding.
- **IoT Device Integration**:
- Supports smart home device control including lights, volume, temperature sensors, etc.
- Integrates with Home Assistant smart home platform to control lights, switches, number controllers, and buttons
- Provides countdown timer functionality for delayed command execution
- Features built-in virtual devices and physical device drivers, easily extensible
- **Online Music Playback**: Advanced Music Player: A high-performance music player built on Pygame, supporting play/pause/stop, progress control, lyric display, and local caching, delivering a more stable and smooth listening experience.
- **Voice Wake-up**: Supports wake word activation, eliminating manual operation (disabled by default, manual activation required).
- **Auto Dialogue Mode**: Implements continuous dialogue experience, enhancing user interaction fluidity.
- **Graphical Interface**: Provides intuitive GUI with Xiaozhi expressions and text display, enhancing visual experience.
- **Command Line Mode**: Supports CLI operation, suitable for embedded devices or environments without GUI.
- **Cross-platform Support**: Compatible with Windows 10+, macOS 10.15+, and Linux systems for use anywhere.
- **Volume Control**: Supports volume adjustment to adapt to different environmental requirements with unified sound control interface.
- **Session Management**: Effectively manages multi-turn dialogues to maintain interaction continuity.
- **Encrypted Audio Transmission**: Supports WSS protocol to ensure audio data security and prevent information leakage.
- **Automatic Verification Code Handling**: Automatically copies verification codes and opens browsers during first use, simplifying user operations.
- **Automatic MAC Address Acquisition**: Avoids MAC address conflicts and improves connection stability.
- **Modular Code**: Code is split and encapsulated into classes with clear responsibilities, facilitating secondary development.
- **Stability Optimization**: Fixes multiple issues including reconnection and cross-platform compatibility.
## System Requirements
- Python version: 3.9 >= version <= 3.12
- Supported operating systems: Windows 10+, macOS 10.15+, Linux
- Microphone and speaker devices
## Read This First!
- Carefully read [项目文档](https://huangjunsen0406.github.io/py-xiaozhi/) for startup tutorials and file descriptions
- The main branch has the latest code; manually reinstall pip dependencies after each update to ensure you have new dependencies
[Zero to Xiaozhi Client (Video Tutorial)](https://www.bilibili.com/video/BV1dWQhYEEmq/?vd_source=2065ec11f7577e7107a55bbdc3d12fce)
## Configuration System
The project uses a layered configuration system, including:
1. **Basic Configuration**: Sets basic runtime parameters, located in `config/config.json`
2. **Device Activation**: Device identity information, stored in `config/efuse.json`
3. **Wake Word Settings**: Voice wake-up related configuration
4. **IoT Devices**: Configuration for various IoT devices, including temperature sensors and Home Assistant integration
For detailed configuration instructions, please refer to [Configuration Documentation](./documents/docs/guide/02_配置说明.md)
## IoT Functionality
py-xiaozhi provides rich IoT device control features:
- **Virtual Devices**: Light control, volume adjustment, countdown timers, etc.
- **Physical Device Integration**: Temperature sensors, cameras, etc.
- **Home Assistant Integration**: Connect to smart home systems via HTTP API
- **Custom Device Extension**: Complete framework for device definition and registration
For supported device types and usage examples, please refer to [IoT Functionality Guide](./documents/docs/guide/05_IoT功能说明.md)
## State Transition Diagram
```
+----------------+
| |
v |
+------+ Wake/Button +------------+ | +------------+
| IDLE | -----------> | CONNECTING | --+-> | LISTENING |
+------+ +------------+ +------------+
^ |
| | Voice Recognition Complete
| +------------+ v
+--------- | SPEAKING | <-----------------+
Playback +------------+
Complete
```
## Upcoming Features
- [ ] **New GUI (Electron)**: Provides a more modern and beautiful user interface, optimizing the interaction experience.
## FAQ
- **Can't find audio device**: Please check if your microphone and speakers are properly connected and enabled.
- **Wake word not responding**: Check if the `USE_WAKE_WORD` setting in `config.json` is set to `true` and the model path is correct.
- **Network connection failure**: Check network settings and firewall configuration to ensure WebSocket or MQTT communication is not blocked.
- **Packaging failure**: Make sure PyInstaller is installed (`pip install pyinstaller`) and all dependencies are installed. Then re-execute `python scripts/build.py`
- **IoT devices not responding**: Check if the corresponding device configuration information is correct, such as Home Assistant URL and Token.
## Related Third-party Open Source Projects
[Xiaozhi Mobile Client](https://github.com/TOM88812/xiaozhi-android-client)
[xiaozhi-esp32-server (Open source server)](https://github.com/xinnan-tech/xiaozhi-esp32-server)
[XiaoZhiAI_server32_Unity(Unity Development)](https://gitee.com/vw112266/XiaoZhiAI_server32_Unity)
[IntelliConnect(Aiot Middleware)](https://github.com/ruanrongman/IntelliConnect)
[open-xiaoai(Xiaoai Audio Access Xiaozhi)](https://github.com/idootop/open-xiaoai.git)
## Project Structure
```
├── .github # GitHub related configurations
├── assets # Resource files (emotion animations, etc.)
├── cache # Cache directory (music and temporary files)
├── config # Configuration directory
├── documents # Documentation directory
├── hooks # PyInstaller hooks directory
├── libs # Dependencies directory
├── scripts # Utility scripts directory
├── src # Source code directory
│ ├── audio_codecs # Audio encoding/decoding module
│ ├── audio_processing # Audio processing module
│ ├── constants # Constants definition
│ ├── display # Display interface module
│ ├── iot # IoT device related module
│ │ └── things # Specific device implementation directory
│ ├── network # Network communication module
│ ├── protocols # Communication protocol module
│ └── utils # Utility classes module
```
## Contribution Guidelines
We welcome issue reports and code contributions. Please ensure you follow these specifications:
1. Code style complies with PEP8 standards
2. PR submissions include appropriate tests
3. Update relevant documentation
## Community and Support
### Thanks to the Following Open Source Contributors
> In no particular order
[Xiaoxia](https://github.com/78)
[zhh827](https://github.com/zhh827)
[SmartArduino-Li Honggang](https://github.com/SmartArduino)
[HonestQiao](https://github.com/HonestQiao)
[vonweller](https://github.com/vonweller)
[Sun Weigong](https://space.bilibili.com/416954647)
[isamu2025](https://github.com/isamu2025)
[Rain120](https://github.com/Rain120)
[kejily](https://github.com/kejily)
[Radio bilibili Jun](https://space.bilibili.com/119751)
### Sponsorship Support
<div align="center">
<h3>Thanks to All Sponsors ❤️</h3>
<p>Whether it's API resources, device compatibility testing, or financial support, every contribution makes the project more complete</p>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/sponsors/" target="_blank">
<img src="https://img.shields.io/badge/View-Sponsors-brightgreen?style=for-the-badge&logo=github" alt="View Sponsors">
</a>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/sponsors/" target="_blank">
<img src="https://img.shields.io/badge/Become-Sponsor-orange?style=for-the-badge&logo=heart" alt="Become a Sponsor">
</a>
</div>
## Project Statistics
[![Star History Chart](https://api.star-history.com/svg?repos=huangjunsen0406/py-xiaozhi&type=Date)](https://www.star-history.com/#huangjunsen0406/py-xiaozhi&Date)
## License
[MIT License](LICENSE)

190
py-xiaozhi-main/README.md Executable file
View File

@ -0,0 +1,190 @@
# py-xiaozhi
<p align="center">
<a href="https://github.com/huangjunsen0406/py-xiaozhi/releases/latest">
<img src="https://img.shields.io/github/v/release/huangjunsen0406/py-xiaozhi?style=flat-square&logo=github&color=blue" alt="Release"/>
</a>
<a href="https://opensource.org/licenses/MIT">
<img src="https://img.shields.io/badge/License-MIT-green.svg?style=flat-square" alt="License: MIT"/>
</a>
<a href="https://github.com/huangjunsen0406/py-xiaozhi/stargazers">
<img src="https://img.shields.io/github/stars/huangjunsen0406/py-xiaozhi?style=flat-square&logo=github" alt="Stars"/>
</a>
<a href="https://github.com/huangjunsen0406/py-xiaozhi/releases/latest">
<img src="https://img.shields.io/github/downloads/huangjunsen0406/py-xiaozhi/total?style=flat-square&logo=github&color=52c41a1&maxAge=86400" alt="Download"/>
</a>
<a href="https://gitee.com/huang-jun-sen/py-xiaozhi">
<img src="https://img.shields.io/badge/Gitee-FF5722?style=flat-square&logo=gitee" alt="Gitee"/>
</a>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/guide/00_%E6%96%87%E6%A1%A3%E7%9B%AE%E5%BD%95.html">
<img alt="使用文档" src="https://img.shields.io/badge/使用文档-点击查看-blue?labelColor=2d2d2d" />
</a>
</p>
简体中文 | [English](README.en.md)
## 项目简介
py-xiaozhi 是一个使用 Python 实现的小智语音客户端,旨在通过代码学习和在没有硬件条件下体验 AI 小智的语音功能。
本仓库是基于[xiaozhi-esp32](https://github.com/78/xiaozhi-esp32)移植
## 演示
- [Bilibili 演示视频](https://www.bilibili.com/video/BV1HmPjeSED2/#reply255921347937)
![Image](./documents/docs/guide/images/系统界面.png)
## 功能特点
- **AI语音交互**:支持语音输入与识别,实现智能人机交互,提供自然流畅的对话体验。
- **视觉多模态**:支持图像识别和处理,提供多模态交互能力,理解图像内容。
- **IoT 设备集成**
- 支持智能家居设备控制,包括灯光、音量、温度传感器等
- 集成Home Assistant智能家居平台控制灯具、开关、数值控制器和按钮设备
- 提供倒计时器功能,支持延时执行命令
- 内置多种虚拟设备和物理设备驱动,可轻松扩展
- **联网音乐播放**基于pygame实现的高性能音乐播放器支持播放暂停停止、进度控制、歌词显示和本地缓存提供更稳定的音乐播放体验。
- **语音唤醒**:支持唤醒词激活交互,免去手动操作的烦恼(默认关闭需要手动开启)。
- **自动对话模式**:实现连续对话体验,提升用户交互流畅度。
- **图形化界面**:提供直观易用的 GUI支持小智表情与文本显示增强视觉体验。
- **命令行模式**:支持 CLI 运行,适用于嵌入式设备或无 GUI 环境。
- **跨平台支持**:兼容 Windows 10+、macOS 10.15+ 和 Linux 系统,随时随地使用。
- **音量控制**:支持音量调节,适应不同环境需求,统一声音控制接口。
- **会话管理**:有效管理多轮对话,保持交互的连续性。
- **加密音频传输**:支持 WSS 协议,保障音频数据的安全性,防止信息泄露。
- **自动验证码处理**:首次使用时,程序自动复制验证码并打开浏览器,简化用户操作。
- **自动获取 MAC 地址**:避免 MAC 地址冲突,提高连接稳定性。
- **代码模块化**:拆分代码并封装为类,职责分明,便于二次开发。
- **稳定性优化**:修复多项问题,包括断线重连、跨平台兼容等。
## 系统要求
- 3.9 >= Python版本 <= 3.12
- 支持的操作系统Windows 10+、macOS 10.15+、Linux
- 麦克风和扬声器设备
## 请先看这里!
- 仔细阅读 [项目文档](https://huangjunsen0406.github.io/py-xiaozhi/) 启动教程和文件说明都在里面了
- main是最新代码每次更新都需要手动重新安装一次pip依赖防止我新增依赖后你们本地没有
[从零开始使用小智客户端(视频教程)](https://www.bilibili.com/video/BV1dWQhYEEmq/?vd_source=2065ec11f7577e7107a55bbdc3d12fce)
## 配置系统
项目使用分层配置系统,主要包括:
1. **基础配置**:设置基本运行参数,位于`config/config.json`
2. **设备激活**:设备身份信息,存储在`config/efuse.json`
3. **唤醒词配置**:语音唤醒相关设置
4. **物联网设备**支持各种IoT设备的配置包括温度传感器和Home Assistant集成
详细配置说明请参考 [配置说明文档](./documents/docs/guide/02_配置说明.md)
## IoT功能
py-xiaozhi提供丰富的IoT设备控制功能
- **虚拟设备**:灯光控制、音量调节、倒计时器等
- **物理设备集成**:温度传感器、摄像头等
- **Home Assistant集成**通过HTTP API接入智能家居系统
- **自定义设备扩展**:提供完整的设备定义和注册框架
支持的设备类型和使用示例请参考 [IoT功能说明](./documents/docs/guide/05_IoT功能说明.md)
## 状态流转图
```
+----------------+
| |
v |
+------+ 唤醒词/按钮 +------------+ | +------------+
| IDLE | -----------> | CONNECTING | --+-> | LISTENING |
+------+ +------------+ +------------+
^ |
| | 语音识别完成
| +------------+ v
+--------- | SPEAKING | <-----------------+
完成播放 +------------+
```
## 待实现功能
- [ ] **新 GUIElectron**:提供更现代、美观的用户界面,优化交互体验。
## 常见问题
- **找不到音频设备**:请检查麦克风和扬声器是否正常连接和启用。
- **唤醒词不响应**:请检查`config.json`中的`USE_WAKE_WORD`设置是否为`true`,以及模型路径是否正确。
- **网络连接失败**请检查网络设置和防火墙配置确保WebSocket或MQTT通信未被阻止。
- **打包失败**确保已安装PyInstaller (`pip install pyinstaller`),并且所有依赖项都已安装。然后重新执行`python scripts/build.py`
- **IoT设备不响应**检查对应设备的配置信息是否正确如Home Assistant的URL和Token。
## 相关第三方开源项目
[小智手机端](https://github.com/TOM88812/xiaozhi-android-client)
[xiaozhi-esp32-server开源服务端](https://github.com/xinnan-tech/xiaozhi-esp32-server)
[XiaoZhiAI_server32_Unity(Unity开发)](https://gitee.com/vw112266/XiaoZhiAI_server32_Unity)
[IntelliConnect(Aiot中间件)](https://github.com/ruanrongman/IntelliConnect)
[open-xiaoai(小爱音响接入小智)](https://github.com/idootop/open-xiaoai.git)
## 项目结构
```
├── .github # GitHub 相关配置
├── assets # 资源文件(表情动画等)
├── cache # 缓存目录(音乐等临时文件)
├── config # 配置文件目录
├── documents # 文档目录
├── hooks # PyInstaller钩子目录
├── libs # 依赖库目录
├── scripts # 实用脚本目录
├── src # 源代码目录
│ ├── audio_codecs # 音频编解码模块
│ ├── audio_processing # 音频处理模块
│ ├── constants # 常量定义
│ ├── display # 显示界面模块
│ ├── iot # IoT设备相关模块
│ │ └── things # 具体设备实现目录
│ ├── network # 网络通信模块
│ ├── protocols # 通信协议模块
│ └── utils # 工具类模块
```
## 贡献指南
欢迎提交问题报告和代码贡献。请确保遵循以下规范:
1. 代码风格符合PEP8规范
2. 提交的PR包含适当的测试
3. 更新相关文档
## 社区与支持
### 感谢以下开源人员
> 排名不分前后
[Xiaoxia](https://github.com/78)
[zhh827](https://github.com/zhh827)
[四博智联-李洪刚](https://github.com/SmartArduino)
[HonestQiao](https://github.com/HonestQiao)
[vonweller](https://github.com/vonweller)
[孙卫公](https://space.bilibili.com/416954647)
[isamu2025](https://github.com/isamu2025)
[Rain120](https://github.com/Rain120)
[kejily](https://github.com/kejily)
[电波bilibili君](https://space.bilibili.com/119751)
### 赞助支持
<div align="center">
<h3>感谢所有赞助者的支持 ❤️</h3>
<p>无论是接口资源、设备兼容测试还是资金支持,每一份帮助都让项目更加完善</p>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/sponsors/" target="_blank">
<img src="https://img.shields.io/badge/查看-赞助者名单-brightgreen?style=for-the-badge&logo=github" alt="赞助者名单">
</a>
<a href="https://huangjunsen0406.github.io/py-xiaozhi/sponsors/" target="_blank">
<img src="https://img.shields.io/badge/成为-项目赞助者-orange?style=for-the-badge&logo=heart" alt="成为赞助者">
</a>
</div>
## 项目统计
[![Star History Chart](https://api.star-history.com/svg?repos=huangjunsen0406/py-xiaozhi&type=Date)](https://www.star-history.com/#huangjunsen0406/py-xiaozhi&Date)
## 许可证
[MIT License](LICENSE)

630
py-xiaozhi-main/alsa.conf Executable file
View File

@ -0,0 +1,630 @@
#
# ALSA library configuration file
#
# pre-load the configuration files
@hooks [
{
func load
files [
"/etc/alsa/conf.d"
"/etc/asound.conf"
"~/.asoundrc"
]
errors false
}
]
# load card-specific configuration files (on request)
cards.@hooks [
{
func load
files [
{
@func concat
strings [
{ @func datadir }
"/cards/aliases.conf"
]
}
]
}
{
func load_for_all_cards
files [
{
@func concat
strings [
{ @func datadir }
"/cards/"
{ @func private_string }
".conf"
]
}
]
errors false
}
]
#
# defaults
#
# show all name hints also for definitions without hint {} section
defaults.namehint.showall on
# show just basic name hints
defaults.namehint.basic on
# show extended name hints
defaults.namehint.extended on
#
defaults.ctl.card 0
defaults.pcm.card 5
defaults.pcm.device 0
defaults.pcm.subdevice -1
defaults.pcm.nonblock 1
defaults.pcm.compat 0
defaults.pcm.minperiodtime 5000 # in us
defaults.pcm.ipc_key 5678293
defaults.pcm.ipc_gid audio
defaults.pcm.ipc_perm 0660
defaults.pcm.dmix.max_periods 0
defaults.pcm.dmix.channels 2
defaults.pcm.dmix.rate 48000
defaults.pcm.dmix.format "unchanged"
defaults.pcm.dmix.card defaults.pcm.card
defaults.pcm.dmix.device defaults.pcm.device
defaults.pcm.dsnoop.card defaults.pcm.card
defaults.pcm.dsnoop.device defaults.pcm.device
defaults.pcm.front.card defaults.pcm.card
defaults.pcm.front.device defaults.pcm.device
defaults.pcm.rear.card defaults.pcm.card
defaults.pcm.rear.device defaults.pcm.device
defaults.pcm.center_lfe.card defaults.pcm.card
defaults.pcm.center_lfe.device defaults.pcm.device
defaults.pcm.side.card defaults.pcm.card
defaults.pcm.side.device defaults.pcm.device
defaults.pcm.surround21.card defaults.pcm.card
defaults.pcm.surround21.device defaults.pcm.device
defaults.pcm.surround40.card defaults.pcm.card
defaults.pcm.surround40.device defaults.pcm.device
defaults.pcm.surround41.card defaults.pcm.card
defaults.pcm.surround41.device defaults.pcm.device
defaults.pcm.surround50.card defaults.pcm.card
defaults.pcm.surround50.device defaults.pcm.device
defaults.pcm.surround51.card defaults.pcm.card
defaults.pcm.surround51.device defaults.pcm.device
defaults.pcm.surround71.card defaults.pcm.card
defaults.pcm.surround71.device defaults.pcm.device
defaults.pcm.iec958.card defaults.pcm.card
defaults.pcm.iec958.device defaults.pcm.device
defaults.pcm.modem.card defaults.pcm.card
defaults.pcm.modem.device defaults.pcm.device
# truncate files via file or tee PCM
defaults.pcm.file_format "raw"
defaults.pcm.file_truncate true
defaults.rawmidi.card 0
defaults.rawmidi.device 0
defaults.rawmidi.subdevice -1
defaults.hwdep.card 0
defaults.hwdep.device 0
defaults.timer.class 2
defaults.timer.sclass 0
defaults.timer.card 0
defaults.timer.device 0
defaults.timer.subdevice 0
#
# PCM interface
#
# redirect to load-on-demand extended pcm definitions
pcm.cards cards.pcm
pcm.default cards.pcm.default
pcm.sysdefault cards.pcm.default
pcm.front cards.pcm.front
pcm.rear cards.pcm.rear
pcm.center_lfe cards.pcm.center_lfe
pcm.side cards.pcm.side
pcm.surround21 cards.pcm.surround21
pcm.surround40 cards.pcm.surround40
pcm.surround41 cards.pcm.surround41
pcm.surround50 cards.pcm.surround50
pcm.surround51 cards.pcm.surround51
pcm.surround71 cards.pcm.surround71
pcm.iec958 cards.pcm.iec958
#pcm.spdif
iec958
pcm.hdmi cards.pcm.hdmi
pcm.dmix cards.pcm.dmix
pcm.dsnoop cards.pcm.dsnoop
pcm.modem cards.pcm.modem
pcm.phoneline cards.pcm.phoneline
pcm.hw {
@args [ CARD DEV SUBDEV ]
@args.CARD {
type string
default {
@func getenv
vars [
ALSA_PCM_CARD
ALSA_CARD
]
default {
@func refer
name defaults.pcm.card
}
}
}
@args.DEV {
type integer
default {
@func igetenv
vars [
ALSA_PCM_DEVICE
]
default {
@func refer
name defaults.pcm.device
}
}
}
@args.SUBDEV {
type integer
default {
@func refer
name defaults.pcm.subdevice
}
}
type hw
card $CARD
device $DEV
subdevice $SUBDEV
hint {
show {
@func refer
name defaults.namehint.extended
}
description "Direct hardware device without any conversions"
}
}
pcm.plughw {
@args [ CARD DEV SUBDEV ]
@args.CARD {
type string
default {
@func getenv
vars [
ALSA_PCM_CARD
ALSA_CARD
]
default {
@func refer
name defaults.pcm.card
}
}
}
@args.DEV {
type integer
default {
@func igetenv
vars [
ALSA_PCM_DEVICE
]
default {
@func refer
name defaults.pcm.device
}
}
}
@args.SUBDEV {
type integer
default {
@func refer
name defaults.pcm.subdevice
}
}
type plug
slave.pcm {
type hw
card $CARD
device $DEV
subdevice $SUBDEV
}
hint {
show {
@func refer
name defaults.namehint.extended
}
description "Hardware device with all software conversions"
}
}
pcm.plug {
@args [ SLAVE ]
@args.SLAVE {
type string
}
type plug
slave.pcm $SLAVE
}
pcm.shm {
@args [ SOCKET PCM ]
@args.SOCKET {
type string
}
@args.PCM {
type string
}
type shm
server $SOCKET
pcm $PCM
}
pcm.tee {
@args [ SLAVE FILE FORMAT ]
@args.SLAVE {
type string
}
@args.FILE {
type string
}
@args.FORMAT {
type string
default {
@func refer
name defaults.pcm.file_format
}
}
type file
slave.pcm $SLAVE
file $FILE
format $FORMAT
truncate {
@func refer
name defaults.pcm.file_truncate
}
}
pcm.file {
@args [ FILE FORMAT ]
@args.FILE {
type string
}
@args.FORMAT {
type string
default {
@func refer
name defaults.pcm.file_format
}
}
type file
slave.pcm null
file $FILE
format $FORMAT
truncate {
@func refer
name defaults.pcm.file_truncate
}
}
pcm.null {
type null
hint {
show {
@func refer
name defaults.namehint.basic
}
description "Discard all samples (playback) or generate zero samples (capture)"
}
}
#
# Control interface
#
ctl.sysdefault {
type hw
card {
@func getenv
vars [
ALSA_CTL_CARD
ALSA_CARD
]
default {
@func refer
name defaults.ctl.card
}
}
hint.description "Default control device"
}
ctl.default ctl.sysdefault
ctl.hw {
@args [ CARD ]
@args.CARD {
type string
default {
@func getenv
vars [
ALSA_CTL_CARD
ALSA_CARD
]
default {
@func refer
name defaults.ctl.card
}
}
}
type hw
card $CARD
hint.description "Direct control device"
}
ctl.shm {
@args [ SOCKET CTL ]
@args.SOCKET {
type string
}
@args.CTL {
type string
}
type shm
server $SOCKET
ctl $CTL
}
#
# RawMidi interface
#
rawmidi.default {
type hw
card {
@func getenv
vars [
ALSA_RAWMIDI_CARD
ALSA_CARD
]
default {
@func refer
name defaults.rawmidi.card
}
}
device {
@func igetenv
vars [
ALSA_RAWMIDI_DEVICE
]
default {
@func refer
name defaults.rawmidi.device
}
}
hint.description "Default raw MIDI device"
}
rawmidi.hw {
@args [ CARD DEV SUBDEV ]
@args.CARD {
type string
default {
@func getenv
vars [
ALSA_RAWMIDI_CARD
ALSA_CARD
]
default {
@func refer
name defaults.rawmidi.card
}
}
}
@args.DEV {
type integer
default {
@func igetenv
vars [
ALSA_RAWMIDI_DEVICE
]
default {
@func refer
name defaults.rawmidi.device
}
}
}
@args.SUBDEV {
type integer
default -1
}
type hw
card $CARD
device $DEV
subdevice $SUBDEV
hint {
description "Direct rawmidi driver device"
device $DEV
}
}
rawmidi.virtual {
@args [ MERGE ]
@args.MERGE {
type string
default 1
}
type virtual
merge $MERGE
}
#
# Sequencer interface
#
seq.default {
type hw
hint.description "Default sequencer device"
}
seq.hw {
type hw
}
#
# HwDep interface
#
hwdep.default {
type hw
card {
@func getenv
vars [
ALSA_HWDEP_CARD
ALSA_CARD
]
default {
@func refer
name defaults.hwdep.card
}
}
device {
@func igetenv
vars [
ALSA_HWDEP_DEVICE
]
default {
@func refer
name defaults.hwdep.device
}
}
hint.description "Default hardware dependent device"
}
hwdep.hw {
@args [ CARD DEV ]
@args.CARD {
type string
default {
@func getenv
vars [
ALSA_HWDEP_CARD
ALSA_CARD
]
default {
@func refer
name defaults.hwdep.card
}
}
}
@args.DEV {
type integer
default {
@func igetenv
vars [
ALSA_HWDEP_DEVICE
]
default {
@func refer
name defaults.hwdep.device
}
}
}
type hw
card $CARD
device $DEV
hint {
description "Direct hardware dependent device"
device $DEV
}
}
#
# Timer interface
#
timer_query.default {
type hw
}
timer_query.hw {
type hw
}
timer.default {
type hw
class {
@func refer
name defaults.timer.class
}
sclass {
@func refer
name defaults.timer.sclass
}
card {
@func refer
name defaults.timer.card
}
device {
@func refer
name defaults.timer.device
}
subdevice {
@func refer
name defaults.timer.subdevice
}
hint.description "Default timer device"
}
timer.hw {
@args [ CLASS SCLASS CARD DEV SUBDEV ]
@args.CLASS {
type integer
default {
@func refer
name defaults.timer.class
}
}
@args.SCLASS {
type integer
default {
@func refer
name defaults.timer.sclass
}
}
@args.CARD {
type string
default {
@func refer
name defaults.timer.card
}
}
@args.DEV {
type integer
default {
@func refer
name defaults.timer.device
}
}
@args.SUBDEV {
type integer
default {
@func refer
name defaults.timer.subdevice
}
}
type hw
class $CLASS
sclass $SCLASS
card $CARD
device $DEV
subdevice $SUBDEV
hint {
description "Direct timer device"
device $DEV
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 487 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 563 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 642 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 691 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 847 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 652 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 711 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 572 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 660 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 573 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 196 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 901 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 686 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 494 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 761 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 655 KiB

46
py-xiaozhi-main/build.json Executable file
View File

@ -0,0 +1,46 @@
{
"name": "xiaozhi",
"version": "1.0.0",
"publisher": "Junsen",
"entry": "main.py",
"icon": "assets/xiaozhi_icon.ico",
"hooks": "hooks",
"onefile": false,
"additional_pyinstaller_args": "--add-data assets;assets --add-data libs;libs --add-data src;src --add-data models;models --hidden-import=PyQt5",
"inno_setup_path": "E:\\application\\Inno Setup 6\\ISCC.exe",
"platform_specific": {
"windows": {
"format": "exe",
"additional_pyinstaller_args": "--add-data assets;assets --add-data libs;libs --add-data src;src --add-data models;models --hidden-import=PyQt5 --noconsole",
"desktop_entry": true,
"installer_options": {
"languages": ["ChineseSimplified", "English"],
"license_file": "LICENSE",
"readme_file": "README.md",
"create_desktop_icon": true,
"allow_run_after_install": true
}
},
"linux": {
"format": "deb",
"desktop_entry": true,
"categories": "Utility;Development;",
"description": "小智Ai客户端",
"requires": "libc6,libgtk-3-0,libx11-6,libopenblas-dev",
"additional_pyinstaller_args": "--add-data assets:assets --add-data libs:libs --add-data src:src --add-data models:models --hidden-import=PyQt5"
},
"macos": {
"format": "app",
"additional_pyinstaller_args": "--add-data assets:assets --add-data libs:libs --add-data src:src --add-data models:models --hidden-import=PyQt5 --windowed",
"app_bundle_name": "XiaoZhi.app",
"bundle_identifier": "com.junsen.xiaozhi",
"sign_bundle": false,
"create_dmg": true,
"installer_options": {
"license_file": "LICENSE",
"readme_file": "README.md"
}
}
},
"build_installer": true
}

2
py-xiaozhi-main/documents/.gitignore vendored Executable file
View File

@ -0,0 +1,2 @@
dist
node_modules

View File

@ -0,0 +1,74 @@
# py-xiaozhi 文档
这是 py-xiaozhi 项目的文档网站,基于 VitePress 构建。
## 功能
- 项目指南:提供项目的详细使用说明和开发文档
- 赞助商页面:展示并感谢项目的所有赞助者
- 贡献指南:说明如何为项目贡献代码
- 贡献者名单:展示所有为项目做出贡献的开发者
- 响应式设计:适配桌面和移动设备
## 本地开发
```bash
# 安装依赖
pnpm install
# 启动开发服务器
pnpm docs:dev
# 构建静态文件
pnpm docs:build
# 预览构建结果
pnpm docs:preview
```
## 目录结构
```
documents/
├── docs/ # 文档源文件
│ ├── .vitepress/ # VitePress 配置
│ ├── guide/ # 指南文档
│ ├── sponsors/ # 赞助商页面
│ ├── contributing.md # 贡献指南
│ ├── contributors.md # 贡献者名单
│ └── index.md # 首页
├── package.json # 项目配置
└── README.md # 项目说明
```
## 赞助商页面
赞助商页面通过以下方式实现:
1. `/sponsors/` 目录包含了赞助商相关的内容
2. `data.json` 文件存储赞助商数据
3. 使用 Vue 组件在客户端动态渲染赞助商列表
4. 提供成为赞助者的详细说明和支付方式
## 贡献指南
贡献指南页面提供了以下内容:
1. 开发环境准备指南
2. 代码贡献流程说明
3. 编码规范和提交规范
4. Pull Request 创建和审核流程
5. 文档贡献指南
## 贡献者名单
贡献者名单页面展示了所有为项目做出贡献的开发者,包括:
1. 核心开发团队成员
2. 代码贡献者
3. 文档贡献者
4. 测试和反馈提供者
## 部署
文档网站通过 GitHub Actions 自动部署到 GitHub Pages。

View File

@ -0,0 +1,74 @@
import { defineConfig } from 'vitepress'
import { getGuideSideBarItems } from './guide'
import tailwindcss from '@tailwindcss/vite'
// https://vitepress.dev/reference/site-config
export default defineConfig({
title: "PY-XIAOZHI",
description: "py-xiaozhi 是一个使用 Python 实现的小智语音客户端,旨在通过代码学习和在没有硬件条件下体验 AI 小智的语音功能。",
base: '/py-xiaozhi/',
themeConfig: {
// https://vitepress.dev/reference/default-theme-config
nav: [
{ text: '主页', link: '/' },
{ text: '指南', link: '/guide/00_文档目录' },
{ text: '系统架构', link: '/architecture/' },
{ text: '相关生态', link: '/ecosystem/' },
{ text: '团队', link: '/about/team' },
{ text: '贡献指南', link: '/contributing' },
{ text: '赞助', link: '/sponsors/' }
],
sidebar: {
'/guide/': [
{
text: '指南',
// 默认展开
collapsed: false,
items: getGuideSideBarItems(),
},
{
text: '旧版文档',
collapsed: true,
items: [
{ text: '使用文档', link: '/guide/old_docs/使用文档' }
]
}
],
'/ecosystem/': [
{
text: '生态系统概览',
link: '/ecosystem/'
},
{
text: '相关项目',
collapsed: false,
items: [
{ text: '小智手机端', link: '/ecosystem/projects/xiaozhi-android-client/' },
{ text: 'xiaozhi-esp32-server', link: '/ecosystem/projects/xiaozhi-esp32-server/' },
{ text: 'XiaoZhiAI_server32_Unity', link: '/ecosystem/projects/xiaozhi-unity/' },
{ text: 'IntelliConnect', link: '/ecosystem/projects/intelliconnect/' },
{ text: 'open-xiaoai', link: '/ecosystem/projects/open-xiaoai/' }
]
},
],
'/about/': [],
// 赞助页面不显示侧边栏
'/sponsors/': [],
// 贡献指南页面不显示侧边栏
'/contributing': [],
// 系统架构页面不显示侧边栏
'/architecture/': [],
// 团队页面不显示侧边栏
'/about/team': []
},
socialLinks: [
{ icon: 'github', link: 'https://github.com/huangjunsen0406/py-xiaozhi' }
]
},
vite: {
plugins: [
tailwindcss()
]
}
})

View File

@ -0,0 +1,15 @@
import { getMdFilesAsync } from "../utils";
import path from 'path';
import { DefaultTheme } from 'vitepress';
export function getGuideSideBarItems(): (DefaultTheme.SidebarItem)[] {
return getMdFilesAsync(path.resolve(__dirname, '../../guide'))
.map(item => {
return {
text: item,
link: `/guide/${item}`
}
}).filter(item => {
return !item.text.includes('使用文档')
})
}

View File

@ -0,0 +1,7 @@
import DefaultTheme from 'vitepress/theme'
import './styles/index.css'
import './styles/custom.scss'
export default {
...DefaultTheme,
}

View File

@ -0,0 +1,28 @@
.vt-badge.wip:before {
content: 'WIP';
}
.vt-badge.ts {
background-color: #3178c6;
}
.vt-badge.ts:before {
content: 'TS';
}
.vt-badge.dev-only,
.vt-badge.experimental {
color: var(--vt-c-text-light-1);
background-color: var(--vt-c-yellow);
}
.vt-badge.dev-only:before {
content: 'Dev only';
}
.vt-badge.experimental:before {
content: 'Experimental';
}
.vt-badge[data-text]:before {
content: attr(data-text);
}

View File

@ -0,0 +1,26 @@
.architecture-page-class {
@media (min-width: 1440px) {
.VPDoc:not(.has-sidebar) .content {
max-width: 1284px !important; /* <-- update your values */
}
.VPDoc:not(.has-sidebar) .container {
max-width: 1604px !important;
}
.VPDoc.has-aside .content-container {
max-width: 1188px !important;
}
.vp-doc h3 {
margin: 0;
}
.vp-doc ul {
padding-left: 0;
}
}
}

View File

@ -0,0 +1,7 @@
@import "./pages.css";
@import "./badges.css";
@import "./options-boxes.css";
@import "./inline-demo.css";
@import "./utilities.css";
@import "./style-guide.css";
@import "tailwindcss";

View File

@ -0,0 +1,90 @@
.vt-doc a[href^="https://play.vuejs.org"]:before
{
content: '▶';
width: 20px;
height: 20px;
display: inline-flex;
border-radius: 10px;
vertical-align: middle;
position: relative;
top: -2px;
color: var(--vt-c-green);
border: 2px solid var(--vt-c-green);
margin-right: 8px;
margin-left: 4px;
line-height: 16px;
padding-left: 4.2px;
font-size: 11px;
}
.demo {
padding: 22px 24px;
border-radius: 8px;
box-shadow: var(--vt-shadow-2);
margin-bottom: 1.2em;
transition: background-color 0.5s ease;
}
.dark .demo {
background-color: var(--vt-c-bg-soft);
}
.demo p {
margin: 0;
}
.demo button {
background-color: var(--vt-c-bg-mute);
transition: background-color 0.5s;
padding: 5px 12px;
border: 1px solid var(--vt-c-divider);
border-radius: 8px;
font-size: 0.9em;
font-weight: 600;
}
.demo button + button {
margin-left: 1em;
}
.demo input,
.demo textarea,
.demo select {
border: 1px solid var(--vt-c-divider);
border-radius: 4px;
padding: 0.2em 0.6em;
margin-top: 10px;
background: transparent;
transition: background-color 0.5s;
}
.dark .demo select {
background: var(--vt-c-bg-soft);
}
.dark .demo select option {
background: transparent;
}
.demo input:not([type]):focus,
.demo textarea:focus,
.demo select:focus {
outline: 1px solid blue;
}
.demo select {
/* this was set by normalize.css */
-webkit-appearance: listbox;
}
.demo label {
margin: 0 1em 0 0.4em;
}
.demo select[multiple] {
width: 100px;
}
.demo h1 {
margin: 10px 0 0;
}

View File

@ -0,0 +1,27 @@
.next-steps {
margin-top: 3rem;
}
.next-steps .vt-box {
border: 1px solid var(--vt-c-bg-soft);
}
.next-steps .vt-box:hover {
border-color: var(--vt-c-green-light);
transition: border-color 0.3s cubic-bezier(0.25, 0.8, 0.25, 1);
}
.vt-doc .next-steps-link {
font-size: 20px;
line-height: 1.4;
letter-spacing: -0.02em;
margin-bottom: 0.75em;
display: block;
color: var(--vt-c-green);
}
.vt-doc .next-steps-caption {
margin-bottom: 0;
color: var(--vt-c-text-2);
transition: color 0.5s;
}

View File

@ -0,0 +1,15 @@
/* always show anchors on /api/ and /style-guide/ pages */
.vt-doc.api h2 .header-anchor,
.vt-doc.style-guide h2 .header-anchor {
opacity: 1;
}
.vt-doc.sponsor h3 {
text-align: center;
padding-bottom: 1em;
border-bottom: 1px solid var(--vt-c-divider-light);
}
.vt-doc.sponsor h3 .header-anchor {
display: none;
}

View File

@ -0,0 +1,65 @@
.style-example {
border-radius: 8px 8px 12px 12px;
margin: 1.6em 0;
padding: 1.6em 1.6em 0.1px;
position: relative;
border: 1px solid transparent;
transition: background-color 0.25s ease, border-color 0.25s ease;
}
.vt-doc .style-example h3 {
margin: 0;
font-size: 1.1em;
}
.style-example-bad {
background: #f7e8e8;
}
.dark .style-example-bad {
background: transparent;
border-color: var(--vt-c-red);
}
.style-example-bad h3 {
color: var(--vt-c-red);
}
.style-example-good {
background: #ecfaf7;
}
.dark .style-example-good {
background: transparent;
border-color: var(--vt-c-green);
}
.style-example-good h3 {
color: var(--vt-c-green);
}
.details summary {
font-weight: bold !important;
}
.style-verb {
font-size: 0.6em;
display: inline-block;
border-radius: 6px;
font-size: 0.65em;
line-height: 1;
font-weight: 600;
padding: 0.35em 0.4em 0.3em;
position: relative;
top: -0.15em;
margin-right: 0.5em;
color: var(--vt-c-bg);
transition: color 0.5s;
background-color: var(--vt-c-brand);
}
.style-verb.avoid {
background-color: var(--vt-c-red);
}
.vt-doc summary {
width: fit-content;
cursor: pointer;
}

View File

@ -0,0 +1,14 @@
.nowrap {
white-space: nowrap;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
border: 0;
}

View File

@ -0,0 +1,65 @@
.vue-mastery-link {
background-color: var(--vt-c-bg-soft);
border-radius: 8px;
padding: 8px 16px 8px 8px;
transition: color 0.5s, background-color 0.5s;
}
.vue-mastery-link a {
display: flex;
align-items: center;
}
.vue-mastery-link .banner {
background-color: var(--vt-c-white-soft);
border-radius: 4px;
width: 96px;
height: 56px;
object-fit: cover;
}
.vue-mastery-link .description {
flex: 1;
font-weight: 500;
font-size: 14px;
line-height: 20px;
color: var(--vt-c-text-1);
margin: 0 0 0 16px;
transition: color 0.5s;
}
.vue-mastery-link .description span {
color: var(--vt-c-brand);
}
.vue-mastery-link .logo-wrapper {
position: relative;
width: 48px;
height: 48px;
border-radius: 50%;
background-color: var(--vt-c-white);
display: flex;
justify-content: center;
align-items: center;
}
.vue-mastery-link .logo-wrapper img {
width: 25px;
object-fit: contain;
}
@media (max-width: 576px) {
.vue-mastery-link .banner {
width: 56px;
}
.vue-mastery-link .description {
font-size: 12px;
line-height: 18px;
}
.vue-mastery-link .logo-wrapper {
position: relative;
width: 32px;
height: 32px;
}
}

View File

@ -0,0 +1,26 @@
import fs from 'fs-extra';
import path from 'path';
export function getMdFilesAsync(rootDir: string) {
const results: string[] = [];
function traverse(currentDir) {
const entries = fs.readdirSync(currentDir, { withFileTypes: true });
entries.map(async (entry) => {
const entryPath = path.join(currentDir, entry.name);
if (entry.isDirectory()) {
traverse(entryPath); // 递归子目录[3](@ref)
} else if (path.extname(entry.name).toLowerCase() === '.md') {
const relativePath = path.relative(rootDir, entryPath);
results.push(relativePath);
}
})
}
traverse(rootDir);
return results.map(item => {
return item.replace('.md', '');
});
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

View File

@ -0,0 +1,11 @@
---
page: true
title: Py-xiaozhi团队
layout: home
---
<script setup>
import TeamPage from './team/TeamPage.vue'
</script>
<TeamPage />

View File

@ -0,0 +1,26 @@
export interface Member {
name: string
avatarPic?: string
title: string
company?: string
companyLink?: string
projects: Link[]
location: string | string[]
languages: string[]
website?: Link
socials: Socials
sponsor?: boolean | string
reposPersonal?: string[]
}
export interface Link {
label: string
url: string
}
export interface Socials {
github: string
twitter?: string
linkedin?: string
codepen?: string
}

View File

@ -0,0 +1,75 @@
<template>
<div class="TeamHero">
<div class="container">
<h1 class="title">
<slot name="title" />
</h1>
<p class="lead">
<slot name="lead" />
</p>
<p class="action">
<slot name="action" />
</p>
</div>
</div>
</template>
<style scoped>
.TeamHero {
padding: 48px 24px;
}
@media (min-width: 768px) {
.TeamHero {
padding: 64px 32px 48px;
}
}
.container {
margin: 0 auto;
max-width: 960px;
}
.title,
.lead {
transition: color 0.25s;
}
.title {
line-height: 32px;
font-size: 32px;
font-weight: 500;
}
@media (min-width: 768px) {
.title {
line-height: 40px;
font-size: 40px;
}
}
.lead {
padding-top: 8px;
font-size: 16px;
font-weight: 500;
max-width: 512px;
color: var(--vt-c-text-2);
}
.action {
padding-top: 4px;
}
.action :deep(a) {
display: inline-block;
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--vt-c-brand);
transition: color 0.25s;
}
.action :deep(a:hover) {
color: var(--vt-c-brand-dark);
}
</style>

View File

@ -0,0 +1,128 @@
<script setup lang="ts">
import type { Member } from './Member'
import TeamMember from './TeamMember.vue'
defineProps<{
members: Member[]
}>()
</script>
<template>
<section class="TeamList">
<div class="container">
<div class="info">
<h2 class="title">
<slot name="title" />
</h2>
<p class="lead">
<slot name="lead" />
</p>
</div>
<div class="members">
<!-- to skip SSG since the members are shuffled -->
<ClientOnly>
<div v-for="member in members" :key="member.name" class="member">
<TeamMember :member="member" />
</div>
</ClientOnly>
</div>
</div>
</section>
</template>
<style scoped>
@media (min-width: 768px) {
.TeamList {
padding: 0 32px;
}
}
.container {
border-top: 1px solid var(--vt-c-divider-light);
padding-top: 24px;
}
@media (min-width: 768px) {
.container {
margin: 0 auto;
display: flex;
align-items: flex-start;
max-width: 960px;
}
}
.info {
flex-shrink: 0;
padding: 0 24px;
max-width: 512px;
}
@media (min-width: 768px) {
.info {
position: sticky;
top: calc(var(--vt-banner-height, 0px) + 32px);
left: 0;
padding: 0 24px 0 0;
width: 256px;
}
html.banner-dismissed .info {
top: 32px;
}
}
@media (min-width: 960px) {
.info {
top: calc(var(--vt-banner-height, 0px) + 88px);
padding: 0 64px 0 0;
width: 384px;
}
html.banner-dismissed .info {
top: 88px;
}
}
.title {
font-size: 20px;
font-weight: 500;
}
.lead {
padding-top: 8px;
line-height: 24px;
font-size: 14px;
font-weight: 500;
color: var(--vt-c-text-2);
}
.members {
padding-top: 24px;
}
@media (min-width: 768px) {
.members {
flex-grow: 1;
padding-top: 0;
}
}
.member + .member {
padding-top: 16px;
}
@media (min-width: 640px) {
.member {
margin: 0 auto;
max-width: 592px;
}
}
@media (min-width: 768px) {
.member {
margin: 0;
max-width: 100%;
}
}
</style>

View File

@ -0,0 +1,472 @@
<script setup lang="ts">
import { computed } from 'vue'
import {
VTIconCode,
VTIconCodePen,
VTIconGitHub,
VTIconGlobe,
VTIconHeart,
VTIconLink,
VTIconLinkedIn,
VTIconMapPin,
VTIconX,
VTLink
} from '@vue/theme'
import type { Member } from './Member'
const props = defineProps<{
member: Member
}>()
const avatarUrl = computed(() => {
return (
props.member.avatarPic ??
`https://www.github.com/${props.member.socials.github}.png`
)
})
function arrayify(value: string | string[]): string[] {
return Array.isArray(value) ? value : [value]
}
</script>
<template>
<article class="TeamMember">
<VTLink
v-if="member.sponsor"
class="sponsor"
:href="`https://github.com/sponsors/${member.socials.github}`"
no-icon
>
<VTIconHeart class="sponsor-icon" /> 赞助
</VTLink>
<div class="member-content">
<figure class="avatar">
<img
class="avatar-img"
:src="avatarUrl"
:alt="`${member.name}'s Profile Picture`"
/>
</figure>
<div class="data">
<h1 class="name">{{ member.name }}</h1>
<p class="org">
{{ member.title }}
<span v-if="member.company" class="nowrap">
@
<VTLink
v-if="member.companyLink"
class="company link"
:href="member.companyLink"
:no-icon="true"
>
{{ member.company }}
</VTLink>
<span v-else class="company">
{{ member.company }}
</span>
</span>
</p>
<div class="profiles">
<section v-if="member.projects && member.projects.length > 0" class="desc">
<div class="desc-title">
<VTIconCode class="desc-icon code" />
</div>
<ul class="desc-list">
<li
v-for="project in member.projects"
:key="project.label"
class="desc-item"
>
<VTLink
class="desc-link"
:href="project.url"
:no-icon="true"
>
{{ project.label }}
</VTLink>
</li>
</ul>
</section>
<section class="desc">
<div class="desc-title">
<VTIconMapPin class="desc-icon" />
</div>
<ul class="desc-list">
<li
v-for="location in arrayify(member.location)"
:key="location"
class="desc-item"
>
{{ location }}
</li>
</ul>
</section>
<section class="desc">
<div class="desc-title">
<VTIconGlobe class="desc-icon" />
</div>
<ul class="desc-list">
<li
v-for="language in member.languages"
:key="language"
class="desc-item"
>
{{ language }}
</li>
</ul>
</section>
<section v-if="member.website" class="desc">
<div class="desc-title">
<VTIconLink class="desc-icon" />
</div>
<p class="desc-text">
<VTLink
class="desc-link"
:href="member.website.url"
:no-icon="true"
>
{{ member.website.label }}
</VTLink>
</p>
</section>
<div class="social-container">
<ul class="social-list">
<li v-if="member.socials.github" class="social-item">
<VTLink
class="social-link"
:href="`https://github.com/${member.socials.github}`"
:no-icon="true"
>
<VTIconGitHub class="social-icon" />
</VTLink>
</li>
<li v-if="member.socials.twitter" class="social-item">
<VTLink
class="social-link"
:href="`https://twitter.com/${member.socials.twitter}`"
:no-icon="true"
>
<VTIconX class="social-icon" />
</VTLink>
</li>
<li v-if="member.socials.linkedin" class="social-item">
<VTLink
class="social-link"
:href="`https://www.linkedin.com/in/${member.socials.linkedin}`"
:no-icon="true"
>
<VTIconLinkedIn class="social-icon" />
</VTLink>
</li>
<li v-if="member.socials.codepen" class="social-item">
<VTLink
class="social-link"
:href="`https://codepen.io/${member.socials.codepen}`"
:no-icon="true"
>
<VTIconCodePen class="social-icon" />
</VTLink>
</li>
</ul>
</div>
</div>
</div>
</div>
</article>
</template>
<style scoped>
.TeamMember {
position: relative;
background-color: var(--vt-c-bg-soft);
transition: background-color 0.5s;
border-radius: 8px;
padding: 32px;
margin-bottom: 20px;
}
.member-content {
display: flex;
flex-direction: row;
align-items: flex-start;
}
@media (max-width: 511px) {
.member-content {
flex-direction: column;
align-items: center;
}
}
.vp-doc li + li {
margin-top: 0;
}
.sponsor {
position: absolute;
top: 16px;
right: 16px;
display: flex;
align-items: center;
border: 1px solid #fd1d7c;
border-radius: 4px;
padding: 4px 8px;
font-size: 12px;
font-weight: 500;
color: #fd1d7c;
transition: color 0.25s, background-color 0.25s;
}
.sponsor:hover {
color: var(--vt-c-white);
background-color: #fd1d7c;
}
.sponsor-icon {
margin-right: 6px;
width: 14px;
height: 14px;
fill: currentColor;
}
.avatar {
flex-shrink: 0;
margin: 0;
display: flex;
justify-content: flex-start;
margin-right: 24px;
}
@media (max-width: 511px) {
.avatar {
justify-content: center;
margin-right: 0;
margin-bottom: 16px;
}
}
.avatar-img {
border-radius: 50%;
width: 110px;
height: 110px;
object-fit: cover;
}
.data {
flex: 1;
padding-top: 0;
display: flex;
flex-direction: column;
justify-content: center;
}
@media (max-width: 511px) {
.data {
padding-top: 16px;
align-items: center;
text-align: center;
}
}
.name {
font-size: 22px;
font-weight: 600;
margin: 0;
}
.org {
padding-top: 4px;
line-height: 20px;
max-width: 320px;
font-size: 16px;
font-weight: 500;
color: var(--vt-c-text-2);
transition: color 0.5s;
margin: 0;
}
.company {
color: var(--vt-c-text-1);
transition: color 0.25s;
}
.company.link:hover {
color: var(--vt-c-brand);
transition: color 0.5s;
}
.profiles {
padding-top: 16px;
}
@media (max-width: 511px) {
.profiles {
width: 100%;
display: flex;
flex-direction: column;
align-items: center;
}
}
.desc {
display: flex;
align-items: center;
margin-bottom: 8px;
}
@media (max-width: 511px) {
.desc {
justify-content: center;
}
}
.desc-title {
display: flex;
justify-content: center;
align-items: center;
flex-shrink: 0;
margin-right: 12px;
height: 20px;
}
.desc-icon {
width: 18px;
height: 18px;
fill: var(--vt-c-text-2);
transition: fill 0.25s;
}
.desc-icon.code {
transform: translateY(1px);
}
.desc-list {
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0;
list-style: none;
}
@media (max-width: 511px) {
.desc-list {
justify-content: center;
}
.desc-text {
text-align: center;
}
}
.desc-item {
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--vt-c-text-1);
transition: color 0.5s;
}
.desc-item::after {
margin: 0 8px;
content: '•';
color: var(--vt-c-text-3);
transition: color 0.25s;
}
.desc-item:last-child::after {
display: none;
}
.desc-text {
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--vt-c-text-1);
transition: color 0.25s;
margin: 0;
}
.desc-link {
line-height: 20px;
font-size: 14px;
font-weight: 500;
color: var(--vt-c-brand);
transition: color 0.25s;
}
.desc-link:hover {
color: var(--vt-c-brand-dark);
}
.social-container {
margin-top: 12px;
}
.social-list {
display: flex;
flex-wrap: wrap;
padding: 0;
margin: 0;
list-style: none;
}
@media (max-width: 511px) {
.social-container {
width: 100%;
display: flex;
justify-content: center;
}
.social-list {
justify-content: center;
}
}
.social-item {
margin-right: 12px;
}
.social-link {
display: flex;
justify-content: center;
align-items: center;
width: 32px;
height: 32px;
color: var(--vt-c-text-2);
transition: color 0.25s;
}
.social-link:hover {
color: var(--vt-c-text-1);
}
.social-icon {
width: 24px;
height: 24px;
fill: currentColor;
}
.sr-only {
position: absolute;
width: 1px;
height: 1px;
padding: 0;
margin: -1px;
overflow: hidden;
clip: rect(0, 0, 0, 0);
white-space: nowrap;
border-width: 0;
}
.nowrap {
white-space: nowrap;
}
</style>

View File

@ -0,0 +1,84 @@
<script lang="ts">
import type { Member } from './Member'
const shuffleMembers = (
members: Member[],
pinTheFirstMember = false
): void => {
let offset = pinTheFirstMember ? 1 : 0
// `i` is between `1` and `length - offset`
// `j` is between `0` and `length - offset - 1`
// `offset + i - 1` is between `offset` and `length - 1`
// `offset + j` is between `offset` and `length - 1`
let i = members.length - offset
while (i > 0) {
const j = Math.floor(Math.random() * i)
;[members[offset + i - 1], members[offset + j]] = [
members[offset + j],
members[offset + i - 1]
]
i--
}
}
</script>
<script setup lang="ts">
// @ts-ignore
import { VTLink } from '@vue/theme'
// @ts-ignore
import membersCoreData from './members-core.json'
// @ts-ignore
import membersPartnerData from './members-partner.json'
import TeamHero from './TeamHero.vue'
// @ts-ignore
import TeamList from './TeamList.vue'
shuffleMembers(membersCoreData, true)
shuffleMembers(membersPartnerData)
</script>
<template>
<div class="TeamPage">
<TeamHero>
<template #title>团队成员</template>
<template #lead>
py-xiaozhi项目的开发和维护由社区人员负责
以下是核心团队成员以及社区贡献者的部分信息
</template>
</TeamHero>
<TeamList :members="membersCoreData">
<template #title>核心团队成员</template>
<template #lead>
核心团队成员积极参与项目开发和维护对py-xiaozhi项目做出了重大贡献
</template>
</TeamList>
<TeamList :members="membersPartnerData">
<template #title>社区贡献者</template>
<template #lead>
感谢以下社区成员在项目初期提供的帮助和支持
</template>
</TeamList>
</div>
</template>
<style scoped>
.TeamPage {
padding-bottom: 16px;
}
@media (min-width: 768px) {
.TeamPage {
padding-bottom: 96px;
}
}
.TeamList + .TeamList {
padding-top: 64px;
}
* {
list-style: none;
}
</style>

View File

@ -0,0 +1,90 @@
[
{
"name": "Junsen Huang",
"title": "py-xiaozhi发起者 & 核心开发者",
"company": "南方电网人工智能有限公司 前端开发工程师",
"location": "中国",
"languages": ["中文"],
"projects": [
{
"label": "py-xiaozhi",
"url": "https://github.com/huangjunsen0406/py-xiaozhi"
},
{
"label": "UnifyPy",
"url": "https://github.com/huangjunsen0406/UnifyPy"
},
{
"label": "xiaozhi-esp32-server",
"url": "https://github.com/xinnan-tech/xiaozhi-esp32-server"
}
],
"socials": {
"github": "huangjunsen0406"
},
"website": {
"label": "https://junsen.online",
"url": "https://junsen.online"
}
},
{
"name": "ASLant",
"title": "核心开发者、PyQt5界面开发、嵌入式兼容",
"company": "山东青橙数字科技有限公司 嵌入式软件工程师",
"location": "中国",
"languages": ["中文"],
"projects": [
],
"socials": {
"github": "Y-ASLant"
},
"website": {
"label": "aslant.top",
"url": "https://aslant.top/"
}
},
{
"name": "fengzai6",
"title": "前期核心开发者",
"company": "中山华定科技有限公司 前端开发工程师",
"location": "中国",
"languages": ["中文"],
"projects": [
],
"socials": {
"github": "fengzai6"
}
},
{
"name": "Cal And Nong",
"title": "文档贡献者",
"company": "腾讯 前端开发工程师",
"location": "中国",
"languages": ["中文"],
"projects": [
],
"socials": {
"github": "calandnong"
}
},
{
"name": "vonweller",
"title": "视觉功能贡献者",
"projects": [],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "vonweller"
}
},
{
"name": "gaochuang",
"company": "诺基亚通信技术 高级平台开发工程师",
"projects": [],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "gaochuang"
}
}
]

View File

@ -0,0 +1,113 @@
[
{
"name": "Xiaoxia",
"title": "社区贡献者",
"projects": [
{
"label": "小智Ai创始人",
"url": "https://github.com/78/xiaozhi-esp32"
}
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "78"
}
},
{
"name": "zhh827",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "zhh827"
}
},
{
"name": "四博智联-李洪刚",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "SmartArduino"
}
},
{
"name": "HonestQiao",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "HonestQiao"
}
},
{
"name": "孙卫公",
"title": "社区贡献者",
"avatarPic": "https://tuchuang.junsen.online/i/2025/04/27/i7ndx4.png",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
},
"website": {
"label": "Bilibili 主页",
"url": "https://space.bilibili.com/416954647"
}
},
{
"name": "isamu2025",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "isamu2025"
}
},
{
"name": "Rain120",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "Rain120"
}
},
{
"name": "kejily",
"title": "社区贡献者",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
"github": "kejily"
}
},
{
"name": "电波bilibili君",
"title": "社区贡献者",
"avatarPic": "https://tuchuang.junsen.online/i/2025/04/27/f4g54b.png",
"projects": [
],
"location": "中国",
"languages": ["中文"],
"socials": {
},
"website": {
"label": "Bilibili 主页",
"url": "https://space.bilibili.com/119751"
}
}
]

View File

@ -0,0 +1,73 @@
<script setup lang="ts">
import {
PuzzlePieceIcon,
CubeIcon,
ArrowsRightLeftIcon,
BoltIcon,
ShareIcon
} from '@heroicons/vue/24/solid';
//
const architectureFeatures = [
{
title: '模块化设计',
description: '各功能模块高度解耦,便于维护和扩展',
icon: CubeIcon
},
{
title: '协议抽象',
description: '通过抽象接口支持多种通信协议',
icon: ArrowsRightLeftIcon
},
{
title: '事件驱动',
description: '基于事件的异步处理机制',
icon: BoltIcon
},
{
title: '状态机模式',
description: '清晰的状态转换逻辑',
icon: ShareIcon
},
{
title: '插件式IoT设备',
description: '统一设备接口,支持动态加载设备',
icon: PuzzlePieceIcon
}
];
const featureColors = [
'bg-blue-500',
'bg-indigo-500',
'bg-purple-500',
'bg-pink-500',
'bg-red-500'
];
</script>
<template>
<div class="bg-white rounded-lg relative mb-10">
<div class="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
<div v-for="(feature, index) in architectureFeatures" :key="index"
class="bg-white rounded-lg p-6 hover:shadow-xl transition-shadow">
<div class="w-12 h-12 rounded-full flex items-center justify-center mb-4"
:class="featureColors[index % featureColors.length]">
<component :is="feature.icon" class="w-6 h-6 text-white" />
</div>
<h3 class="text-xl font-semibold mb-2">{{ feature.title }}</h3>
<p class="text-gray-700">{{ feature.description }}</p>
</div>
</div>
</div>
</template>
<style scoped>
/* 架构特点卡片样式优化 */
.grid-cols-1.md\:grid-cols-2.lg\:grid-cols-3 > div {
transition: all 0.3s ease;
height: 100%;
}
.grid-cols-1.md\:grid-cols-2.lg\:grid-cols-3 > div:hover {
transform: translateY(-5px);
}
</style>

View File

@ -0,0 +1,98 @@
<template>
<div class="bg-white rounded-lg relative mb-10">
<div ref="architectureChart" class="w-full h-[500px]"></div>
<p class="text-gray-600 mt-4 text-center">核心架构图展示了应用核心通信协议层音频处理系统用户界面系统IoT设备管理等模块的关系</p>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
const architectureChart = ref(null);
onMounted(() => {
if (architectureChart.value) {
const chart = echarts.init(architectureChart.value);
chart.setOption({
animation: false,
tooltip: {
trigger: 'item',
formatter: '{b}: {c}'
},
legend: {
orient: 'vertical',
right: 10,
top: 'center',
data: ['核心', '主要模块', '子模块']
},
series: [
{
name: '架构图',
type: 'graph',
layout: 'force',
data: [
{ name: '应用核心', value: 'Application', category: 0, symbolSize: 70 },
{ name: '通信协议层', value: 'Protocols', category: 1, symbolSize: 50 },
{ name: '音频处理系统', value: 'Audio Processing', category: 1, symbolSize: 50 },
{ name: '用户界面系统', value: 'UI System', category: 1, symbolSize: 50 },
{ name: 'IoT设备管理', value: 'IoT Management', category: 1, symbolSize: 50 },
{ name: 'WebSocket', value: 'WebSocket', category: 2, symbolSize: 30 },
{ name: 'MQTT', value: 'MQTT', category: 2, symbolSize: 30 },
{ name: '音频编解码', value: 'Audio Codecs', category: 2, symbolSize: 30 },
{ name: 'VAD检测', value: 'VAD', category: 2, symbolSize: 30 },
{ name: '唤醒词检测', value: 'Wakeword', category: 2, symbolSize: 30 },
{ name: 'GUI界面', value: 'GUI', category: 2, symbolSize: 30 },
{ name: 'CLI界面', value: 'CLI', category: 2, symbolSize: 30 },
{ name: '设备抽象', value: 'Device Abstract', category: 2, symbolSize: 30 },
{ name: '智能家居', value: 'Smart Home', category: 2, symbolSize: 30 }
],
links: [
{ source: '应用核心', target: '通信协议层' },
{ source: '应用核心', target: '音频处理系统' },
{ source: '应用核心', target: '用户界面系统' },
{ source: '应用核心', target: 'IoT设备管理' },
{ source: '通信协议层', target: 'WebSocket' },
{ source: '通信协议层', target: 'MQTT' },
{ source: '音频处理系统', target: '音频编解码' },
{ source: '音频处理系统', target: 'VAD检测' },
{ source: '音频处理系统', target: '唤醒词检测' },
{ source: '用户界面系统', target: 'GUI界面' },
{ source: '用户界面系统', target: 'CLI界面' },
{ source: 'IoT设备管理', target: '设备抽象' },
{ source: 'IoT设备管理', target: '智能家居' }
],
categories: [
{ name: '核心' },
{ name: '主要模块' },
{ name: '子模块' }
],
roam: true,
label: {
show: true,
position: 'right',
formatter: '{b}'
},
lineStyle: {
color: 'source',
curveness: 0.3
},
emphasis: {
focus: 'adjacency',
lineStyle: {
width: 3
}
},
force: {
repulsion: 300,
edgeLength: 120
}
}
]
});
window.addEventListener('resize', () => {
chart.resize();
});
}
});
</script>

View File

@ -0,0 +1,169 @@
<template>
<div class="bg-white rounded-lg relative mb-10">
<div class="grid grid-cols-1 lg:grid-cols-3 gap-8">
<div v-for="(flow, index) in dataFlows" :key="index"
class="data-flow-card bg-white rounded-xl shadow-xl overflow-hidden transform hover:scale-[1.02] transition-all duration-300">
<div class="p-5 text-white font-semibold bg-gradient-to-r" :class="[
index === 0 ? 'from-blue-500 to-blue-600' :
index === 1 ? 'from-green-500 to-green-600' :
'from-purple-500 to-purple-600'
]">
<div class="flex items-center">
<div class="w-10 h-10 rounded-full bg-white/20 backdrop-blur-sm flex items-center justify-center">
<component :is="flow.icon" class="w-5 h-5 text-white" />
</div>
<div class="ml-4">
<h3 class="text-xl font-bold">{{ flow.title }}</h3>
<p class="text-white/80 text-sm mt-1">{{ flow.subtitle }}</p>
</div>
</div>
</div>
<div class="p-5 flex-grow">
<div class="relative py-3 h-full" >
<div v-for="(step, stepIndex) in flow.steps" :key="stepIndex"
class="flow-step flex items-center mb-5 last:mb-0">
<div
class="flow-step-number w-10 h-10 rounded-full bg-gradient-to-br flex items-center justify-center text-white font-bold shadow-md"
:class="[
index === 0 ? 'from-blue-400 to-blue-500' :
index === 1 ? 'from-green-400 to-green-500' :
'from-purple-400 to-purple-500'
]">
{{ stepIndex + 1 }}
</div>
<div class="flow-step-content ml-3 flex-1 bg-gradient-to-br from-gray-50 to-white rounded-lg p-3 shadow-sm">
<p class="text-gray-700">{{ step }}</p>
</div>
</div>
<div class="absolute left-5 top-8 bottom-5 w-0.5" :class="[
index === 0 ? 'bg-blue-200' :
index === 1 ? 'bg-green-200' :
'bg-purple-200'
]">
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {
AcademicCapIcon,
SpeakerWaveIcon,
CommandLineIcon
} from '@heroicons/vue/24/solid';
//
const dataFlows = [
{
title: '音频输入流程',
subtitle: '从用户到服务器',
icon: AcademicCapIcon,
steps: [
'麦克风捕获音频',
'VAD 判断是否有语音',
'音频编码压缩',
'发送到服务器'
]
},
{
title: '音频输出流程',
subtitle: '从服务器到用户',
icon: SpeakerWaveIcon,
steps: [
'服务器返回音频数据',
'解码音频数据',
'音频播放'
]
},
{
title: '控制命令流程',
subtitle: '命令处理与执行',
icon: CommandLineIcon,
steps: [
'用户命令输入',
'命令解析',
'发送到服务器',
'服务器响应处理',
'更新 UI 和状态'
]
}
];
</script>
<style scoped>
.data-flow-card {
display: flex;
flex-direction: column;
height: 100%;
}
.data-flow-card > div:last-child {
flex: 1;
display: flex;
flex-direction: column;
}
.flow-chart {
flex: 1;
display: flex;
flex-direction: column;
}
.flow-step {
position: relative;
z-index: 1;
}
.flow-chart .flow-step {
margin-bottom: 1.25rem;
min-height: 3rem;
}
.flow-chart .flow-step:last-child {
margin-bottom: 0;
}
.flow-step-content {
padding: 0.75rem 1rem;
display: flex;
align-items: center;
min-height: 3rem;
}
.flow-chart .absolute {
z-index: 0;
}
@media (min-width: 1024px) {
.grid-cols-1.lg\:grid-cols-3 {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
.grid-cols-1.lg\:grid-cols-3 > div {
display: flex;
flex-direction: column;
}
.grid-cols-1.lg\:grid-cols-3 > div > div:last-child {
flex: 1;
display: flex;
flex-direction: column;
}
.flow-chart {
flex: 1;
display: flex;
flex-direction: column;
justify-content: space-between;
}
}
@media (max-width: 1023px) {
.grid-cols-1.lg\:grid-cols-3 > div {
margin-bottom: 2rem;
}
}
</style>

View File

@ -0,0 +1,132 @@
<template>
<div class="bg-white rounded-lg relative mb-10">
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-8 gap-y-6">
<div v-for="(module, index) in modules" :key="index" class="module-card">
<div class="flex items-start">
<div class="w-12 h-12 rounded-lg flex items-center justify-center"
:class="moduleColors[index % moduleColors.length]">
<component :is="module.icon" class="w-6 h-6 text-white" />
</div>
<div class="ml-4 flex-1">
<h3 class="text-lg font-semibold mb-2">{{ module.name }}</h3>
<ul class="space-y-2">
<li v-for="(feature, featureIndex) in module.features" :key="featureIndex" class="flex items-start">
<CheckCircleIcon class="w-5 h-5 text-green-500 mt-1 mr-2" />
<span>{{ feature }}</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</div>
</template>
<script setup>
import {
CogIcon,
ArrowsRightLeftIcon,
DocumentIcon,
SpeakerXMarkIcon,
ComputerDesktopIcon,
ServerIcon,
LightBulbIcon,
WrenchIcon,
CheckCircleIcon
} from '@heroicons/vue/24/solid';
//
const modules = [
{
name: 'src/application.py',
icon: CogIcon,
features: [
'应用主类,负责协调所有子系统',
'实现了单例模式,管理全局状态',
'处理事件调度和状态转换'
]
},
{
name: 'src/protocols/',
icon: ArrowsRightLeftIcon,
features: [
'通信协议的抽象接口和具体实现',
'WebSocket协议用于实时双向通信',
'MQTT协议用于物联网设备通信'
]
},
{
name: 'src/audio_codecs/',
icon: DocumentIcon,
features: [
'音频编解码器,处理音频数据压缩/解压缩',
'支持Opus编码格式'
]
},
{
name: 'src/audio_processing/',
icon: SpeakerXMarkIcon,
features: [
'语音活动检测:判断用户是否在说话',
'唤醒词检测:识别指定的唤醒词'
]
},
{
name: 'src/display/',
icon: ComputerDesktopIcon,
features: [
'用户界面抽象和实现',
'GUI界面基于PyQt5的图形界面',
'CLI界面命令行交互界面'
]
},
{
name: 'src/iot/',
icon: ServerIcon,
features: [
'IoT设备管理框架',
'设备抽象类和具体实现',
'支持智能家居设备控制'
]
},
{
name: 'src/iot/things/',
icon: LightBulbIcon,
features: [
'具体IoT设备的实现',
'音乐播放器、温度传感器',
'灯光控制、摄像头等'
]
},
{
name: 'src/utils/',
icon: WrenchIcon,
features: [
'各类工具函数和辅助类',
'日志管理、配置管理等'
]
}
];
const moduleColors = [
'bg-blue-600',
'bg-indigo-600',
'bg-purple-600',
'bg-pink-600',
'bg-red-600',
'bg-orange-600',
'bg-yellow-600',
'bg-green-600'
];
</script>
<style scoped>
.module-card {
transition: all 0.3s ease;
}
.module-card:hover {
transform: translateY(-5px);
box-shadow: 0 10px 15px -3px rgba(0, 0, 0, 0.1);
}
</style>

View File

@ -0,0 +1,85 @@
<template>
<div class="bg-white rounded-lg relative mb-10">
<div ref="stateChart" class="w-full h-[300px]"></div>
<div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
<div v-for="(state, index) in states" :key="index" class="bg-gray-50 p-4 rounded-lg border-l-4"
:class="stateBorderColors[index]">
<h4 class="font-bold mb-2">{{ state.name }}</h4>
<p class="text-gray-700">{{ state.description }}</p>
</div>
</div>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue';
import * as echarts from 'echarts';
//
const states = [
{ name: 'IDLE', description: '空闲状态,等待用户交互或唤醒词' },
{ name: 'CONNECTING', description: '正在建立连接' },
{ name: 'LISTENING', description: '正在监听用户输入' },
{ name: 'SPEAKING', description: '正在播放语音回复' }
];
const stateBorderColors = [
'border-blue-500',
'border-yellow-500',
'border-green-500',
'border-purple-500'
];
const stateChart = ref(null);
onMounted(() => {
if (stateChart.value) {
const chart = echarts.init(stateChart.value);
chart.setOption({
animation: false,
tooltip: {
trigger: 'item',
formatter: '{b}'
},
series: [
{
type: 'graph',
layout: 'circular',
symbolSize: 60,
roam: false,
label: {
show: true
},
edgeSymbol: ['circle', 'arrow'],
edgeSymbolSize: [4, 10],
edgeLabel: {
fontSize: 12
},
data: [
{ name: 'IDLE', itemStyle: { color: '#3b82f6' } },
{ name: 'CONNECTING', itemStyle: { color: '#eab308' } },
{ name: 'LISTENING', itemStyle: { color: '#22c55e' } },
{ name: 'SPEAKING', itemStyle: { color: '#a855f7' } }
],
links: [
{ source: 'IDLE', target: 'CONNECTING', label: { show: true, formatter: '唤醒' } },
{ source: 'CONNECTING', target: 'LISTENING', label: { show: true, formatter: '连接成功' } },
{ source: 'LISTENING', target: 'SPEAKING', label: { show: true, formatter: '收到响应' } },
{ source: 'SPEAKING', target: 'IDLE', label: { show: true, formatter: '播放完成' } },
{ source: 'LISTENING', target: 'IDLE', label: { show: true, formatter: '超时' } },
{ source: 'CONNECTING', target: 'IDLE', label: { show: true, formatter: '连接失败' } }
],
lineStyle: {
opacity: 0.9,
width: 2,
curveness: 0.2
}
}
]
});
window.addEventListener('resize', () => {
chart.resize();
});
}
});
</script>

View File

@ -0,0 +1,101 @@
<template>
<div class="bg-white rounded-lg relative mb-10">
<div class="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-6 gap-4">
<div v-for="(tech, index) in techStack" :key="index"
class="flex flex-col items-center p-4 rounded-lg hover:bg-gray-100 transition-colors">
<div class="w-16 h-16 rounded-full flex items-center justify-center mb-3"
:class="techColors[index % techColors.length]">
<component :is="tech.icon" class="w-8 h-8 text-white" />
</div>
<h4 class="font-semibold text-center">{{ tech.name }}</h4>
<p class="text-sm text-gray-600 text-center mt-1">{{ tech.description }}</p>
</div>
</div>
</div>
</template>
<script setup>
import {
CodeBracketIcon,
WindowIcon,
DocumentIcon,
SpeakerWaveIcon as AudioIcon,
PuzzlePieceIcon,
SignalIcon,
ArrowPathIcon,
ArrowsUpDownIcon,
MusicalNoteIcon as MusicIcon
} from '@heroicons/vue/24/solid';
//
const techStack = [
{
name: 'Python',
description: '3.9-3.12',
icon: CodeBracketIcon
},
{
name: 'PyQt5',
description: 'GUI框架',
icon: WindowIcon
},
{
name: 'OpusLib',
description: '音频编解码',
icon: DocumentIcon
},
{
name: 'PyAudio',
description: '音频处理',
icon: AudioIcon
},
{
name: 'WebSocket',
description: '通信协议',
icon: PuzzlePieceIcon
},
{
name: 'MQTT',
description: 'IoT通信',
icon: SignalIcon
},
{
name: 'AsyncIO',
description: '异步处理',
icon: ArrowPathIcon
},
{
name: 'Threading',
description: '并发处理',
icon: ArrowsUpDownIcon
},
{
name: 'Pygame',
description: '音乐播放',
icon: MusicIcon
}
];
const techColors = [
'bg-blue-500',
'bg-indigo-500',
'bg-purple-500',
'bg-pink-500',
'bg-red-500',
'bg-orange-500',
'bg-yellow-500',
'bg-green-500',
'bg-teal-500'
];
</script>
<style scoped>
/* 技术栈图标优化 */
.grid-cols-2.md\:grid-cols-3.lg\:grid-cols-6 > div {
transition: all 0.2s ease;
}
.grid-cols-2.md\:grid-cols-3.lg\:grid-cols-6 > div:hover {
transform: translateY(-3px);
}
</style>

View File

@ -0,0 +1,46 @@
---
title: Py-Xiaozhi 项目架构
description: 基于 Python 实现的小智语音客户端,采用模块化设计,支持多种通信协议和设备集成
sidebar: false,
pageClass: architecture-page-class
---
<script setup>
import CoreArchitecture from './components/CoreArchitecture.vue'
import StateManagement from './components/StateManagement.vue'
import DataFlow from './components/DataFlow.vue'
import ModuleDetails from './components/ModuleDetails.vue'
import TechnologyStack from './components/TechnologyStack.vue'
import ArchitectureFeatures from './components/ArchitectureFeatures.vue'
</script>
<div class="architecture-page">
# Py-Xiaozhi 项目架构
<p>基于 Python 实现的小智语音客户端,采用模块化设计,支持多种通信协议和设备集成</p>
## 核心架构
<CoreArchitecture/>
## 状态管理
<StateManagement/>
## 数据流
<DataFlow/>
## 模块详情
<ModuleDetails/>
## 技术栈
<TechnologyStack/>
## 架构特点
<ArchitectureFeatures/>
</div>
<style>
.architecture-page {
max-width: 100%;
padding: 0 2rem;
}
</style>

View File

@ -0,0 +1,451 @@
---
title: 贡献指南
description: 如何为 py-xiaozhi 项目贡献代码
sidebar: false
outline: deep
---
<div class="contributing-page">
# 贡献指南
<div class="header-content">
<h2>如何为 py-xiaozhi 项目贡献代码 🚀</h2>
</div>
## 前言
感谢您对 py-xiaozhi 项目感兴趣!我们非常欢迎社区成员参与贡献,无论是修复错误、改进文档还是添加新功能。本指南将帮助您了解如何向项目提交贡献。
## 开发环境准备
### 基本要求
- Python 3.9 或更高版本
- Git 版本控制系统
- 基本的 Python 开发工具(推荐使用 Visual Studio Code
### 获取源代码
1. 首先,在 GitHub 上 Fork 本项目到您自己的账号
- 访问 [py-xiaozhi 项目页面](https://github.com/huangjunsen0406/py-xiaozhi)
- 点击右上角的"Fork"按钮
- 等待 Fork 完成,您将被重定向到您的仓库副本
2. 克隆您 fork 的仓库到本地:
```bash
git clone https://github.com/YOUR_USERNAME/py-xiaozhi.git
cd py-xiaozhi
```
3. 添加上游仓库作为远程源:
```bash
git remote add upstream https://github.com/huangjunsen0406/py-xiaozhi.git
```
你可以使用 `git remote -v` 命令确认远程仓库已正确配置:
```bash
git remote -v
# 应显示:
# origin https://github.com/YOUR_USERNAME/py-xiaozhi.git (fetch)
# origin https://github.com/YOUR_USERNAME/py-xiaozhi.git (push)
# upstream https://github.com/huangjunsen0406/py-xiaozhi.git (fetch)
# upstream https://github.com/huangjunsen0406/py-xiaozhi.git (push)
```
### 安装开发依赖
- 其他依赖需要查看指南下的相关文档
```bash
# 创建并激活虚拟环境(推荐)
python -m venv venv
source venv/bin/activate # 在 Windows 上使用: venv\Scripts\activate
# 安装项目依赖
pip install -r requirements.txt
```
## 开发流程
### 与主仓库保持同步
在开始工作之前,确保您的本地仓库与主项目保持同步是非常重要的。以下是同步本地仓库的步骤:
1. 切换到您的主分支(`main`
```bash
git checkout main
```
2. 拉取上游仓库的最新更改:
```bash
git fetch upstream
```
3. 将上游主分支的更改合并到您的本地主分支:
```bash
git merge upstream/main
```
4. 将更新后的本地主分支推送到您的 GitHub 仓库:
```bash
git push origin main
```
### 创建分支
在开始任何工作之前,请确保从最新的上游主分支创建新的分支:
```bash
# 获取最新的上游代码(如上节所述)
git fetch upstream
git checkout -b feature/your-feature-name upstream/main
```
为分支命名时,可以遵循以下约定:
- `feature/xxx`:新功能开发
- `fix/xxx`:修复 bug
- `docs/xxx`:文档更新
- `test/xxx`:测试相关工作
- `refactor/xxx`:代码重构
### 编码规范
我们使用 [PEP 8](https://www.python.org/dev/peps/pep-0008/) 作为 Python 代码风格指南。在提交代码前,请确保您的代码符合以下要求:
- 使用 4 个空格进行缩进
- 行长度不超过 120 个字符
- 使用有意义的变量和函数名称
- 为公共 API 添加文档字符串
- 使用类型提示Type Hints
我们推荐使用静态代码分析工具来帮助您遵循编码规范:
```bash
# 使用 flake8 检查代码风格
flake8 .
# 使用 mypy 进行类型检查
mypy .
```
### 测试
在提交之前,请确保所有测试都能通过
## 提交变更
### 提交前的检查清单
在提交您的代码之前,请确保完成以下检查:
1. 代码是否符合 PEP 8 规范
2. 是否添加了必要的测试用例
3. 所有测试是否通过
4. 是否添加了适当的文档
5. 是否解决了您计划解决的问题
6. 是否与最新的上游代码保持同步
### 提交变更
在开发过程中,养成小批量、频繁提交的习惯。这样可以使您的更改更容易跟踪和理解:
```bash
# 查看更改的文件
git status
# 暂存更改
git add file1.py file2.py
# 提交更改
git commit -m "feat: add new feature X"
```
### 解决冲突
如果您在尝试合并上游更改时遇到冲突,请按照以下步骤解决:
1. 首先了解冲突的位置:
```bash
git status
```
2. 打开冲突文件,您会看到类似以下标记:
```
<<<<<<< HEAD
您的代码
=======
上游代码
>>>>>>> upstream/main
```
3. 修改文件以解决冲突,删除冲突标记
4. 解决完所有冲突后,暂存并提交:
```bash
git add .
git commit -m "fix: resolve merge conflicts"
```
### 提交规范
我们使用[约定式提交](https://www.conventionalcommits.org/zh-hans/)规范来格式化 Git 提交消息。提交消息应该遵循以下格式:
```
<类型>[可选 作用域]: <描述>
[可选 正文]
[可选 脚注]
```
常用的提交类型包括:
- `feat`:新功能
- `fix`:错误修复
- `docs`:文档更改
- `style`:不影响代码含义的变更(如空格、格式化等)
- `refactor`:既不修复错误也不添加功能的代码重构
- `perf`:提高性能的代码更改
- `test`:添加或修正测试
- `chore`:对构建过程或辅助工具和库的更改
例如:
```
feat(tts): 添加新的语音合成引擎支持
添加对百度语音合成API的支持包括以下功能
- 支持多种音色选择
- 支持语速和音量调节
- 支持中英文混合合成
修复 #123
```
### 推送更改
完成代码更改后,将您的分支推送到您的 GitHub 仓库:
```bash
git push origin feature/your-feature-name
```
如果您已经创建了 Pull Request并且需要更新它只需再次推送到同一分支即可
```bash
# 在进行更多更改后
git add .
git commit -m "refactor: improve code based on feedback"
git push origin feature/your-feature-name
```
### 创建 Pull Request 前同步最新代码
在创建 Pull Request 前,建议再次与上游仓库同步,以避免潜在的冲突:
```bash
# 获取上游最新代码
git fetch upstream
# 将上游最新代码变基到您的特性分支
git rebase upstream/main
# 如果出现冲突,解决冲突并继续变基
git add .
git rebase --continue
# 强制推送更新后的分支到您的仓库
git push --force-with-lease origin feature/your-feature-name
```
注意:使用 `--force-with-lease` 比直接使用 `--force` 更安全,它可以防止覆盖他人推送的更改。
### 创建 Pull Request
当您完成功能开发或问题修复后,请按照以下步骤创建 Pull Request
1. 将您的更改推送到 GitHub
```bash
git push origin feature/your-feature-name
```
2. 访问 GitHub 上您 fork 的仓库页面,点击 "Compare & pull request" 按钮
3. 填写 Pull Request 表单:
- 使用清晰的标题,遵循提交消息格式
- 在描述中提供详细信息
- 引用相关 issue使用 `#issue编号` 格式)
- 如果这是一个进行中的工作,请添加 `[WIP]` 前缀到标题
4. 提交 Pull Request等待项目维护者审核
### Pull Request 的生命周期
1. **创建**:提交您的 PR
2. **CI 检查**:自动化测试和代码风格检查
3. **代码审核**:维护者会审核您的代码并提供反馈
4. **修订**:根据反馈修改您的代码
5. **批准**:一旦您的 PR 被批准
6. **合并**:维护者会将您的 PR 合并到主分支
## 文档贡献
如果您想改进项目文档,请按照以下步骤操作:
1. 按照上述步骤 Fork 项目并克隆到本地
2. 文档位于 `documents/docs` 目录下,使用 Markdown 格式
3. 安装文档开发依赖:
```bash
cd documents
pnpm install
```
4. 启动本地文档服务器:
```bash
pnpm docs:dev
```
5. 在浏览器中访问 `http://localhost:5173/py-xiaozhi/` 预览您的更改
6. 完成更改后,提交您的贡献并创建 Pull Request
### 文档编写准则
- 使用清晰、简洁的语言
- 提供实际示例
- 对复杂概念进行详细解释
- 包含适当的截图或图表(需要时)
- 避免技术术语过多,必要时提供解释
- 保持文档结构一致
## 问题反馈
如果您发现了问题但暂时无法修复,请在 GitHub 上[创建 Issue](https://github.com/huangjunsen0406/py-xiaozhi/issues/new)。创建 Issue 时,请包含以下信息:
- 问题的详细描述
- 重现问题的步骤
- 预期行为和实际行为
- 您的操作系统和 Python 版本
- 相关的日志输出或错误信息
## 代码审核
提交 Pull Request 后,项目维护者将会审核您的代码。在代码审核过程中:
- 请耐心等待反馈
- 及时响应评论和建议
- 必要时进行修改并更新您的 Pull Request
- 保持礼貌和建设性的讨论
### 处理代码审核反馈
1. 认真阅读所有评论和建议
2. 针对每个要点作出回应或更改
3. 如果您不同意某个建议,礼貌地解释您的理由
4. 修改完成后,在 PR 中留言通知审核者
## 成为项目维护者
如果您持续为项目做出有价值的贡献,您可能会被邀请成为项目的维护者。作为维护者,您将有权限审核和合并其他人的 Pull Request。
### 维护者的职责
- 审核 Pull Request
- 管理 issue
- 参与项目规划
- 回答社区问题
- 帮助引导新贡献者
## 行为准则
请尊重所有项目参与者,遵循以下行为准则:
- 使用包容性语言
- 尊重不同的观点和经验
- 优雅地接受建设性批评
- 关注社区最佳利益
- 对其他社区成员表示同理心
## 常见问题解答
### 我应该从哪里开始贡献?
1. 查看标记为 "good first issue" 的问题
2. 修复文档中的错误或不清晰的部分
3. 添加更多测试用例
4. 解决您自己在使用过程中发现的问题
### 我提交的 PR 已经很久没有回应了,我该怎么办?
在 PR 中留言,礼貌地询问是否需要进一步的改进或澄清。请理解维护者可能很忙,需要一些时间来审核您的贡献。
### 我可以贡献哪些类型的更改?
- 错误修复
- 新功能
- 性能改进
- 文档更新
- 测试用例
- 代码重构
## 致谢
再次感谢您为项目做出贡献!您的参与对我们非常重要,共同努力让 py-xiaozhi 变得更好!
</div>
<style>
.contributing-page {
max-width: 900px;
margin: 0 auto;
padding: 2rem 1.5rem;
}
.contributing-page h1 {
text-align: center;
margin-bottom: 1rem;
}
.header-content {
text-align: center;
}
.header-content h2 {
color: var(--vp-c-brand);
margin-bottom: 1rem;
}
.contributing-page h2 {
margin-top: 3rem;
padding-top: 1rem;
border-top: 1px solid var(--vp-c-divider);
}
.contributing-page h3 {
margin-top: 2rem;
}
.contributing-page code {
background-color: var(--vp-c-bg-soft);
padding: 0.2em 0.4em;
border-radius: 3px;
}
.contributing-page pre {
margin: 1rem 0;
border-radius: 8px;
overflow: auto;
}
</style>

View File

@ -0,0 +1,130 @@
---
title: 相关生态
description: py-xiaozhi项目相关的生态系统和扩展项目
outline: deep
---
<div class="ecosystem-page">
# 相关生态
<div class="header-content">
<h2>py-xiaozhi项目生态系统 🌱</h2>
<p>探索围绕py-xiaozhi构建的相关项目和扩展</p>
</div>
## 生态概览
本页面将收集和展示py-xiaozhi项目相关的生态系统项目包括
- 官方扩展和插件
- 社区贡献的项目
- 兼容的硬件设备
- 第三方集成方案
- 示例项目和案例分析
## 即将推出
我们计划收集和整理以下内容:
- 各种设备上的安装和运行指南
- 与智能家居系统的集成方案
- 定制语音指令和技能的开发教程
- 基于py-xiaozhi构建的项目案例
- 社区贡献的扩展功能
## 参与贡献
如果您有相关的项目或扩展想要分享,欢迎通过以下方式参与贡献:
1. 在GitHub上提交Pull Request添加您的项目
2. 在Issues中建议您希望看到的集成或扩展
3. 分享您使用py-xiaozhi的经验和案例
</div>
<style>
.ecosystem-page {
max-width: 900px;
margin: 0 auto;
padding: 2rem 1.5rem;
}
.ecosystem-page h1 {
text-align: center;
margin-bottom: 1rem;
}
.header-content {
text-align: center;
margin-bottom: 3rem;
}
.header-content h2 {
color: var(--vp-c-brand);
margin-bottom: 0.5rem;
}
.ecosystem-page h2 {
margin-top: 3rem;
padding-top: 1rem;
border-top: 1px solid var(--vp-c-divider);
}
.ecosystem-page blockquote {
border-left: 4px solid var(--vp-c-brand);
padding: 1rem;
background-color: var(--vp-c-bg-soft);
margin: 2rem 0;
border-radius: 0 8px 8px 0;
}
.features {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.feature {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
box-shadow: 0 2px 10px rgba(0, 0, 0, 0.05);
transition: all 0.3s ease;
}
.feature:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 1rem;
font-size: 1.3rem;
}
.feature-links {
display: flex;
flex-direction: column;
gap: 0.5rem;
margin-top: 1rem;
}
.feature-links a {
display: block;
padding: 0.5rem;
border-radius: 4px;
background-color: rgba(var(--vp-c-brand-rgb), 0.1);
color: var(--vp-c-brand-dark);
text-decoration: none;
transition: all 0.2s ease;
}
.feature-links a:hover {
background-color: rgba(var(--vp-c-brand-rgb), 0.2);
transform: translateX(5px);
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

View File

@ -0,0 +1,237 @@
---
title: IntelliConnect
description: 基于SpringBoot的智能物联网平台集成Agent智能体技术的IoT解决方案
---
# IntelliConnect
<div class="project-header">
<div class="project-logo">
<img src="./images/logo.png" alt="IntelliConnect Logo">
</div>
<div class="project-badges">
<span class="badge platform">跨平台</span>
<span class="badge language">Java/Spring</span>
<span class="badge status">v0.1</span>
</div>
</div>
<div class="ascii-art">
<pre>
██╗ ███╗ ██╗ ████████╗ ███████╗ ██╗ ██╗ ██╗ ██████╗ ██████╗ ███╗ ██╗ ███╗ ██╗ ███████╗ ██████╗ ████████╗
██║ ████╗ ██║ ╚══██╔══╝ ██╔════╝ ██║ ██║ ██║ ██╔════╝ ██╔═══██╗ ████╗ ██║ ████╗ ██║ ██╔════╝ ██╔════╝ ╚══██╔══╝
██║ ██╔██╗ ██║ ██║ █████╗ ██║ ██║ ██║ ██║ ██║ ██║ ██╔██╗ ██║ ██╔██╗ ██║ █████╗ ██║ ██║
██║ ██║╚██╗██║ ██║ ██╔══╝ ██║ ██║ ██║ ██║ ██║ ██║ ██║╚██╗██║ ██║╚██╗██║ ██╔══╝ ██║ ██║
██║ ██║ ╚████║ ██║ ███████╗ ███████╗ ███████╗ ██║ ╚██████╗ ╚██████╔╝ ██║ ╚████║ ██║ ╚████║ ███████╗ ╚██████╗ ██║
╚═╝ ╚═╝ ╚═══╝ ╚═╝ ╚══════╝ ╚══════╝ ╚══════╝ ╚═╝ ╚═════╝ ╚═════╝ ╚═╝ ╚═══╝ ╚═╝ ╚═══╝ ╚══════╝ ╚═════╝ ╚═╝
</pre>
<p class="ascii-caption">Built by RSLLY</p>
</div>
<div class="project-badges-center">
<img src="https://img.shields.io/badge/license-apache2.0-yellow?style=flat-square" alt="License" />
<img src="https://img.shields.io/badge/release-v0.1-blue?style=flat-square" alt="Release" />
<img src="https://img.shields.io/badge/cwl-project1.8-green?style=flat-square" alt="CWL Project" />
</div>
## 概述
* 本项目基于springboot2.7开发使用spring security作为安全框架
* 配备物模型(属性,功能和事件模块)和完善的监控模块
* 支持多种大模型和先进的Agent智能体技术提供出色的AI智能可以快速搭建智能物联网应用(首个基于Agent智能体设计的物联网平台)
* 支持快速构建智能语音应用,支持语音识别和语音合成
* 支持多种iot协议使用emqx exhook作为mqtt通讯可扩展性强
* 支持OTA空中升级技术
* 支持微信小程序和微信服务号
* 支持小智AI硬件
* 使用常见的mysql和redis数据库上手简单
* 支持时序数据库influxdb
## 安装运行
<div class="notice">
<p>推荐使用docker安装docker-compose.yaml文件在docker目录下执行 docker-compose up 可初始化mysql,redis,emqx和influxdb环境安装详情请看官方文档。</p>
</div>
* 安装mysql和redis数据库高性能运行推荐安装时序数据库influxdb
* 安装EMQX集群,并配置好exhook本项目使用exhook作为mqtt消息的处理器
* 安装java17环境
* 修改配置文件application.yaml(设置ddl-auto为update模式)
* java -jar IntelliConnect-1.8-SNAPSHOT.jar
```bash
# 克隆仓库
git clone https://github.com/ruanrongman/IntelliConnect
cd intelliconnect/docker
# 启动所需环境MySQL, Redis, EMQX, InfluxDB
docker-compose up -d
```
## 项目特色
* 极简主义层次分明符合mvc分层结构
* 完善的物模型抽象使得iot开发者可以专注于业务本身
* AI能力丰富支持Agent智能体技术快速开发AI智能应用
## 小智 ESP-32 后端服务(xiaozhi-esp32-server)
<div class="esp32-section">
<p>本项目能够为开源智能硬件项目 <a href="https://github.com/78/xiaozhi-esp32" target="_blank">xiaozhi-esp32</a> 提供后端服务。根据 <a href="https://ccnphfhqs21z.feishu.cn/wiki/M0XiwldO9iJwHikpXD5cEx71nKh" target="_blank">小智通信协议</a> 使用 <code>Java</code> 实现。</p>
<p>适合希望本地部署的用户,不同于单纯语音交互,本项目重点在于提供更强大的物联网和智能体能力。</p>
</div>
## 项目文档和视频演示
* 项目文档和视频演示地址:[https://ruanrongman.github.io/IntelliConnect/](https://ruanrongman.github.io/IntelliConnect/)
* 技术博客地址:[https://wordpress.rslly.top](https://wordpress.rslly.top)
* 社区地址:[https://github.com/cwliot](https://github.com/cwliot)
* 创万联社区公众号:微信直接搜索创万联
## 相关项目和社区
* **创万联(cwl)**: 专注于物联网和人工智能技术的开源社区。
* **Promptulate**: [https://github.com/Undertone0809/promptulate](https://github.com/Undertone0809/promptulate) - A LLM application and Agent development framework.
* **Rymcu**: [https://github.com/rymcu](https://github.com/rymcu) - 为数百万人服务的开源嵌入式知识学习交流平台
## 致谢
* 感谢项目[xiaozhi-esp32](https://github.com/78/xiaozhi-esp32)提供强大的硬件语音交互。
* 感谢项目[Concentus: Opus for Everyone](https://github.com/lostromb/concentus)提供opus解码和编码。
* 感谢项目[TalkX](https://github.com/big-mouth-cn/talkx)提供了opus解码和编码的参考。
* 感谢项目[py-xiaozhi](https://github.com/huangjunsen0406/py-xiaozhi)方便项目进行小智开发调试。
## 贡献
本人正在尝试一些更加完善的抽象模式,支持更多的物联网协议和数据存储形式,如果你有更好的建议,欢迎一起讨论交流。
<style>
.project-header {
display: flex;
align-items: center;
margin-bottom: 2rem;
}
.project-logo {
width: 120px;
height: 120px;
margin-right: 1.5rem;
}
.project-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.project-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.85rem;
font-weight: 500;
}
.badge.platform {
background-color: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.badge.language {
background-color: rgba(59, 130, 246, 0.2);
color: rgb(59, 130, 246);
}
.badge.status {
background-color: rgba(234, 179, 8, 0.2);
color: rgb(234, 179, 8);
}
.ascii-art {
overflow-x: auto;
margin: 2rem 0;
text-align: center;
}
.ascii-art pre {
display: inline-block;
text-align: left;
font-size: 0.6rem;
line-height: 1;
white-space: pre;
margin: 0;
background: transparent;
color: var(--vp-c-brand);
font-family: monospace;
}
.ascii-caption {
font-size: 0.8rem;
margin-top: 0.5rem;
color: var(--vp-c-text-2);
}
.project-badges-center {
display: flex;
justify-content: center;
flex-wrap: wrap;
gap: 0.5rem;
margin-bottom: 2rem;
}
.notice {
background-color: var(--vp-c-bg-soft);
border-left: 4px solid var(--vp-c-brand);
padding: 1rem 1.5rem;
margin: 1.5rem 0;
border-radius: 0 8px 8px 0;
}
.esp32-section {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
margin: 1.5rem 0;
border: 1px solid var(--vp-c-divider);
}
.qr-container {
text-align: center;
margin: 2rem 0;
}
.qr-code {
width: 250px;
height: auto;
object-fit: contain;
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
}
@media (max-width: 768px) {
.ascii-art pre {
font-size: 0.4rem;
}
.project-header {
flex-direction: column;
align-items: flex-start;
}
.project-logo {
margin-bottom: 1rem;
}
}
@media (max-width: 480px) {
.ascii-art {
display: none;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -0,0 +1,459 @@
---
title: open-xiaoai
description: 让小爱音箱「听见你的声音」,解锁无限可能的开源项目
---
# open-xiaoai
<div class="project-header">
<div class="project-logo">
<img src="https://avatars.githubusercontent.com/u/35302658?s=48&v=4" alt="open-xiaoai Logo">
</div>
<div class="project-badges">
<span class="badge platform">跨平台</span>
<span class="badge language">Rust/Python/Node.js</span>
<span class="badge status">实验性</span>
</div>
</div>
<div class="project-banner">
<img src="./images/logo.png" alt="Open-XiaoAI 项目封面">
</div>
## 项目简介
Open-XiaoAI 是一个让小爱音箱"听见你的声音"的开源项目将小爱音箱与小智AI生态系统无缝集成。该项目直接接管小爱音箱的"耳朵"和"嘴巴"通过多模态大模型和AI Agent技术将小爱音箱的潜力完全释放解锁无限可能。
2017年当全球首款千万级销量的智能音箱诞生时我们以为触摸到了未来。但很快发现这些设备被困在「指令-响应」的牢笼里:
- 它听得见分贝,却听不懂情感
- 它能执行命令,却不会主动思考
- 它有千万用户,却只有一套思维
我们曾幻想中的"贾维斯"级人工智能,在现实场景中沦为"闹钟+音乐播放器"。
**真正的智能不应被预设的代码逻辑所束缚,而应像生命体般在交互中进化。**
在上一个 [MiGPT](https://github.com/idootop/mi-gpt) 项目的基础上Open-XiaoAI再次进化为小智生态系统提供了与小爱音箱交互的新方式。
## 核心功能
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">🎤</div>
<h3>语音输入接管</h3>
<p>直接捕获小爱音箱的麦克风输入,绕过原有语音识别限制</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔊</div>
<h3>声音输出控制</h3>
<p>完全接管小爱音箱的扬声器可以播放自定义音频和TTS内容</p>
</div>
<div class="feature-card">
<div class="feature-icon">🧠</div>
<h3>AI模型整合</h3>
<p>支持接入小智AI、ChatGPT等多种大模型实现自然对话体验</p>
</div>
<div class="feature-card">
<div class="feature-icon">🌐</div>
<h3>跨平台支持</h3>
<p>Client端使用Rust开发Server端支持Python和Node.js实现</p>
</div>
<div class="feature-card">
<div class="feature-icon">🛠️</div>
<h3>可扩展架构</h3>
<p>模块化设计,方便开发者添加自定义功能和集成其他服务</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎮</div>
<h3>开发者友好</h3>
<p>详细的文档和教程,帮助开发者快速上手并定制自己的功能</p>
</div>
</div>
## 演示视频
<div class="demo-videos">
<div class="video-item">
<a href="https://www.bilibili.com/video/BV1NBXWYSEvX" target="_blank" class="video-link">
<div class="video-thumbnail">
<img src="https://raw.githubusercontent.com/idootop/open-xiaoai/main/docs/images/xiaozhi.jpg" alt="小爱音箱接入小智AI">
</div>
<div class="video-title">
<span class="video-icon">▶️</span>
<span>小爱音箱接入小智AI演示</span>
</div>
</a>
</div>
<div class="video-item">
<a href="https://www.bilibili.com/video/BV1N1421y7qn" target="_blank" class="video-link">
<div class="video-thumbnail">
<img src="https://github.com/idootop/open-xiaoai/raw/main/docs/images/migpt.jpg" alt="小爱音箱接入MiGPT">
</div>
<div class="video-title">
<span class="video-icon">▶️</span>
<span>小爱音箱接入MiGPT演示</span>
</div>
</a>
</div>
</div>
## 快速开始
<div class="important-notice">
<div class="notice-icon">⚠️</div>
<div class="notice-content">
<strong>重要提示</strong>
<p>本教程仅适用于 <strong>小爱音箱 ProLX06</strong><strong>Xiaomi 智能音箱 ProOH2P</strong> 这两款机型,<strong>其他型号</strong>的小爱音箱请勿直接使用!</p>
</div>
</div>
Open-XiaoAI项目由Client端和Server端两部分组成您可以按照以下步骤快速开始
### 安装步骤
<div class="steps">
<div class="step">
<div class="step-number">1</div>
<div class="step-content">
<h4>小爱音箱固件更新</h4>
<p>刷机更新小爱音箱补丁固件开启并SSH连接到小爱音箱</p>
<a href="https://github.com/idootop/open-xiaoai/blob/main/docs/flash.md" target="_blank" class="step-link">查看详细教程</a>
</div>
</div>
<div class="step">
<div class="step-number">2</div>
<div class="step-content">
<h4>客户端部署</h4>
<p>在电脑上编译Client端补丁程序然后复制到小爱音箱上运行</p>
<a href="https://github.com/idootop/open-xiaoai/blob/main/packages/client-rust/README.md" target="_blank" class="step-link">查看详细教程</a>
</div>
</div>
<div class="step">
<div class="step-number">3</div>
<div class="step-content">
<h4>服务端部署</h4>
<p>在电脑上运行Server端演示程序体验小爱音箱的全新能力</p>
<ul class="step-options">
<li><a href="https://github.com/idootop/open-xiaoai/blob/main/packages/server-python/README.md" target="_blank">Python Server - 小爱音箱接入小智AI</a></li>
<li><a href="https://github.com/idootop/open-xiaoai/blob/main/packages/server-node/README.md" target="_blank">Node.js Server - 小爱音箱接入MiGPT-Next</a></li>
</ul>
</div>
</div>
</div>
## 工作原理
Open-XiaoAI通过以下方式工作
1. **固件补丁**: 修改小爱音箱的固件允许SSH访问和底层系统控制
2. **音频流劫持**: 客户端程序直接捕获麦克风输入和控制扬声器输出
3. **网络通信**: 客户端与服务端之间建立WebSocket连接进行实时通信
4. **AI处理**: 服务端接收语音输入交由AI模型处理后返回响应
5. **自定义功能**: 开发者可以在服务端实现各种自定义功能和集成
## 相关项目
如果您不想刷机或者不是小爱音箱Pro以下项目可能对您有用
- [MiGPT](https://github.com/idootop/mi-gpt) - 将ChatGPT接入小爱音箱的原始项目
- [MiGPT-Next](https://github.com/idootop/migpt-next) - MiGPT的下一代版本
- [XiaoGPT](https://github.com/yihong0618/xiaogpt) - 另一个小爱音箱ChatGPT接入方案
- [XiaoMusic](https://github.com/hanxi/xiaomusic) - 小爱音箱音乐播放增强
## 技术参考
如果您想了解更多技术细节,以下链接可能对您有帮助:
- [xiaoai-patch](https://github.com/duhow/xiaoai-patch) - 小爱音箱固件补丁
- [open-lx01](https://github.com/jialeicui/open-lx01) - 小爱音箱LX01开源项目
- [小爱FM研究](https://javabin.cn/2021/xiaoai_fm.html) - 小爱音箱FM功能研究
- [小米设备安全研究](https://github.com/yihong0618/gitblog/issues/258) - 小米IoT设备安全分析
- [小爱音箱探索](https://xuanxuanblingbling.github.io/iot/2022/09/16/mi/) - 小爱音箱技术探索
## 免责声明
<div class="disclaimer">
<h4>适用范围</h4>
<p>本项目为非盈利开源项目,仅限于技术原理研究、安全漏洞验证及非营利性个人使用。严禁用于商业服务、网络攻击、数据窃取、系统破坏等违反《网络安全法》及使用者所在地司法管辖区的法律规定的场景。</p>
<h4>非官方声明</h4>
<p>本项目由第三方开发者独立开发,与小米集团及其关联方(下称"权利方")无任何隶属/合作关系,未获其官方授权/认可或技术支持。项目中涉及的商标、固件、云服务的所有权利归属小米集团。若权利方主张权益,使用者应立即主动停止使用并删除本项目。</p>
<p>继续使用本项目,即表示您已完整阅读并同意<a href="https://github.com/idootop/open-xiaoai/blob/main/agreement.md" target="_blank">用户协议</a>,否则请立即终止使用并彻底删除本项目。</p>
</div>
## 许可证
本项目使用 [MIT](https://github.com/idootop/open-xiaoai/blob/main/LICENSE) 许可证 © 2024-PRESENT Del Wang
<style>
.project-header {
display: flex;
align-items: center;
margin-bottom: 2rem;
}
.project-logo {
width: 100px;
height: 100px;
margin-right: 1.5rem;
}
.project-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.project-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.85rem;
font-weight: 500;
}
.badge.platform {
background-color: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.badge.language {
background-color: rgba(59, 130, 246, 0.2);
color: rgb(59, 130, 246);
}
.badge.status {
background-color: rgba(139, 92, 246, 0.2);
color: rgb(139, 92, 246);
}
.project-banner {
width: 100%;
margin: 2rem 0;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.project-banner img {
width: 100%;
height: auto;
display: block;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.feature-card {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
border: 1px solid var(--vp-c-divider);
height: 100%;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2rem;
margin-bottom: 1rem;
}
.feature-card h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 0.5rem;
}
.demo-videos {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.video-item {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.video-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.video-link {
text-decoration: none;
color: inherit;
display: block;
}
.video-thumbnail {
width: 100%;
height: 180px;
overflow: hidden;
}
.video-thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.video-item:hover .video-thumbnail img {
transform: scale(1.05);
}
.video-title {
padding: 1rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.video-icon {
color: var(--vp-c-brand);
}
.important-notice {
background-color: rgba(234, 179, 8, 0.1);
border-left: 4px solid rgba(234, 179, 8, 0.8);
border-radius: 0 8px 8px 0;
padding: 1rem 1.5rem;
margin: 2rem 0;
display: flex;
gap: 1rem;
}
.notice-icon {
font-size: 1.5rem;
}
.notice-content strong {
display: block;
margin-bottom: 0.5rem;
}
.steps {
margin: 2rem 0;
}
.step {
display: flex;
margin-bottom: 1.5rem;
gap: 1rem;
}
.step-number {
display: flex;
align-items: center;
justify-content: center;
width: 32px;
height: 32px;
background-color: var(--vp-c-brand);
color: white;
border-radius: 50%;
font-weight: bold;
flex-shrink: 0;
}
.step-content {
flex: 1;
}
.step-content h4 {
margin-top: 0;
margin-bottom: 0.5rem;
color: var(--vp-c-brand);
}
.step-link {
display: inline-block;
margin-top: 0.5rem;
color: var(--vp-c-brand);
text-decoration: none;
font-weight: 500;
}
.step-link:hover {
text-decoration: underline;
}
.step-options {
list-style-type: disc;
padding-left: 1.5rem;
margin-top: 0.5rem;
}
.architecture-diagram {
text-align: center;
margin: 2rem 0;
}
.architecture-diagram img {
max-width: 100%;
border-radius: 8px;
border: 1px solid var(--vp-c-divider);
}
.disclaimer {
background-color: rgba(239, 68, 68, 0.1);
border-left: 4px solid rgba(239, 68, 68, 0.8);
border-radius: 0 8px 8px 0;
padding: 1.5rem;
margin: 2rem 0;
}
.disclaimer h4 {
margin-top: 0;
color: rgba(239, 68, 68, 0.8);
margin-bottom: 0.5rem;
}
.disclaimer p {
margin: 0.5rem 0;
}
@media (max-width: 768px) {
.project-header {
flex-direction: column;
align-items: flex-start;
}
.project-logo {
margin-bottom: 1rem;
}
.demo-videos {
grid-template-columns: 1fr;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

View File

@ -0,0 +1,500 @@
---
title: 小智手机端
description: 基于Flutter的跨平台小智客户端支持iOS、Android、Web等多平台
---
# 小智手机客户端
<div class="project-header">
<div class="project-logo">
<img src="https://avatars.githubusercontent.com/u/196275872?s=48&v=4" alt="小智手机客户端">
</div>
<div class="project-badges">
<span class="badge platform">多平台</span>
<span class="badge language">Flutter/Dart</span>
<span class="badge status">活跃开发中</span>
</div>
</div>
## 项目简介
小智手机客户端是基于Flutter框架开发的跨平台应用为小智AI生态系统提供了移动端接入能力。通过一套代码实现了在iOS、Android、Web、Windows、macOS和Linux等多个平台的部署让用户随时随地都能与小智AI进行实时语音交互和文字对话。
<div class="app-showcase">
<div class="showcase-image">
<img src="./images/界面1.jpg" alt="应用展示" onerror="this.src='./images/界面1.jpg'; this.onerror=null;">
<div class="overlay">
<a href="https://www.bilibili.com/video/BV1fgXvYqE61" target="_blank" class="watch-demo">观看演示视频</a>
</div>
</div>
<div class="showcase-description">
<p>最新版本客户端已全面升级支持iOS与Android平台并可自行打包为Web、PC版本。通过精心设计的UI和流畅的交互体验为用户提供随时随地与小智AI交流的能力。</p>
</div>
</div>
## 核心功能
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">📱</div>
<h3>跨平台支持</h3>
<p>使用Flutter开发一套代码支持iOS、Android、Web、Windows、macOS和Linux等多平台</p>
</div>
<div class="feature-card">
<div class="feature-icon">🤖</div>
<h3>多AI模型集成</h3>
<p>支持小智AI服务、Dify、OpenAI等多种AI服务可随时切换不同模型</p>
</div>
<div class="feature-card">
<div class="feature-icon">💬</div>
<h3>丰富交互方式</h3>
<p>支持实时语音对话、文字消息、图片消息,以及通话中手动打断功能</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔊</div>
<h3>语音优化技术</h3>
<p>实现安卓设备AEC+NS回音消除提升语音交互质量</p>
</div>
<div class="feature-card">
<div class="feature-icon">🎨</div>
<h3>精美界面设计</h3>
<p>轻度拟物化设计、流畅动画效果、自适应UI布局</p>
</div>
<div class="feature-card">
<div class="feature-icon">⚙️</div>
<h3>灵活配置选项</h3>
<p>支持多种AI服务配置管理可添加多个小智到聊天列表</p>
</div>
</div>
## 功能亮点
### 实时语音交互
<div class="feature-highlight">
<div class="highlight-image">
<img src="./images/界面1.jpg" alt="实时语音交互" onerror="this.src='./images/界面1.jpg'; this.onerror=null;">
</div>
<div class="highlight-content">
<h3>流畅的语音对话体验</h3>
<ul>
<li>实时语音识别和响应</li>
<li>支持持续对话模式</li>
<li>语音交互过程中支持手动打断</li>
<li>按住说话快捷模式</li>
<li>语音会话历史记录</li>
</ul>
</div>
</div>
### 多AI服务支持
<div class="feature-highlight reverse">
<div class="highlight-content">
<h3>灵活切换不同AI服务</h3>
<ul>
<li>集成小智WebSocket实时语音对话</li>
<li>支持Dify平台接入</li>
<li>支持OpenAI图文消息和流式输出</li>
<li>支持官方小智服务一键设备注册</li>
<li>可同时添加多个AI服务到对话列表</li>
</ul>
</div>
<div class="highlight-image">
<img src="./images/界面2.jpg" alt="多AI服务支持" onerror="this.src='./images/界面2.jpg'; this.onerror=null;">
</div>
</div>
## 系统要求
- **Flutter**: ^3.7.0
- **Dart**: ^3.7.0
- **iOS**: 12.0+
- **Android**: API 21+ (Android 5.0+)
- **Web**: 现代浏览器
## 安装与使用
### 安装方法
1. 克隆项目仓库:
```bash
git clone https://github.com/TOM88812/xiaozhi-android-client.git
```
2. 安装依赖:
```bash
flutter pub get
```
3. 运行应用:
```bash
flutter run
```
### 构建发布版本
```bash
# Android应用
flutter build apk --release
# iOS应用
flutter build ios --release
# Web应用
flutter build web --release
```
> **注意**: iOS编译完成后需要在设置-APP中打开网络权限
## 配置说明
应用支持灵活的服务配置管理,包括:
### 小智服务配置
- 支持配置多个小智服务地址
- WebSocket URL设置
- Token认证
- 自定义MAC地址
### Dify API配置
- 支持配置多个Dify服务
- API密钥管理
- 服务器URL配置
### OpenAI配置
- API密钥设置
- 模型选择
- 参数调整
## 开发计划
<div class="roadmap">
<div class="roadmap-item done">
<div class="status-dot"></div>
<div class="item-content">
<h4>已实现功能</h4>
<ul>
<li>支持多种AI服务提供商</li>
<li>支持OTA自动注册设备</li>
<li>增强语音识别准确性</li>
<li>实现文字和语音混合会话</li>
<li>支持OpenAI接口图文交互</li>
</ul>
</div>
</div>
<div class="roadmap-item progress">
<div class="status-dot"></div>
<div class="item-content">
<h4>正在开发</h4>
<ul>
<li>深色/浅色主题适配</li>
<li>iOS平台回音消除实现</li>
<li>本地ASR语音识别支持</li>
<li>本地唤醒词功能</li>
</ul>
</div>
</div>
<div class="roadmap-item planned">
<div class="status-dot"></div>
<div class="item-content">
<h4>计划实现</h4>
<ul>
<li>支持IoT映射手机操作</li>
<li>本地TTS实现</li>
<li>支持MCP_Client</li>
<li>OpenAI接口联网搜索功能</li>
</ul>
</div>
</div>
</div>
## 项目贡献
欢迎为小智手机客户端贡献代码或提交问题反馈:
- 目前iOS端回音消除尚未实现欢迎有经验的开发者PR
- 提交Bug、功能请求或改进建议
- 分享您使用小智手机客户端的经验和案例
## 相关链接
- [项目GitHub仓库](https://github.com/TOM88812/xiaozhi-android-client)
- [演示视频](https://www.bilibili.com/video/BV1fgXvYqE61)
- [问题反馈](https://github.com/TOM88812/xiaozhi-android-client/issues)
<style>
.project-header {
display: flex;
align-items: center;
margin-bottom: 2rem;
}
.project-logo {
width: 100px;
height: 100px;
margin-right: 1.5rem;
}
.project-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.project-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.85rem;
font-weight: 500;
}
.badge.platform {
background-color: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.badge.language {
background-color: rgba(59, 130, 246, 0.2);
color: rgb(59, 130, 246);
}
.badge.status {
background-color: rgba(16, 185, 129, 0.2);
color: rgb(16, 185, 129);
}
.app-showcase {
margin: 2rem 0;
background-color: var(--vp-c-bg-soft);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.showcase-image {
position: relative;
width: 100%;
height: 300px;
}
.showcase-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.overlay {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.3);
display: flex;
align-items: center;
justify-content: center;
opacity: 0;
transition: opacity 0.3s ease;
}
.showcase-image:hover .overlay {
opacity: 1;
}
.watch-demo {
padding: 0.75rem 1.5rem;
/*background-color: var(--vp-c-brand);*/
color: white;
border-radius: 4px;
text-decoration: none;
font-weight: 500;
transition: background-color 0.1s ease;
}
.watch-demo:hover {
background-color: var(--vp-c-brand-dark);
}
.showcase-description {
padding: 1.5rem;
font-size: 1.1rem;
line-height: 1.6;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.feature-card {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
border: 1px solid var(--vp-c-divider);
height: 100%;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2rem;
margin-bottom: 1rem;
}
.feature-card h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 0.5rem;
}
.feature-highlight {
display: flex;
margin: 3rem 0;
background-color: var(--vp-c-bg-soft);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.feature-highlight.reverse {
flex-direction: row-reverse;
}
.highlight-image {
flex: 1;
min-width: 40%;
}
.highlight-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.highlight-content {
flex: 1;
padding: 2rem;
}
.highlight-content h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 1rem;
}
.highlight-content ul {
padding-left: 1.5rem;
}
.highlight-content li {
margin-bottom: 0.5rem;
}
.roadmap {
position: relative;
margin: 3rem 0;
padding-left: 2rem;
}
.roadmap:before {
content: "";
position: absolute;
left: 7px;
top: 0;
bottom: 0;
width: 2px;
background-color: var(--vp-c-divider);
}
.roadmap-item {
position: relative;
margin-bottom: 2rem;
}
.status-dot {
position: absolute;
left: -2rem;
top: 0;
width: 16px;
height: 16px;
border-radius: 50%;
z-index: 1;
}
.roadmap-item.done .status-dot {
background-color: rgb(16, 185, 129);
}
.roadmap-item.progress .status-dot {
background-color: rgb(245, 158, 11);
}
.roadmap-item.planned .status-dot {
background-color: rgb(99, 102, 241);
}
.item-content {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
border: 1px solid var(--vp-c-divider);
}
.item-content h4 {
margin-top: 0;
margin-bottom: 1rem;
}
.roadmap-item.done h4 {
color: rgb(16, 185, 129);
}
.roadmap-item.progress h4 {
color: rgb(245, 158, 11);
}
.roadmap-item.planned h4 {
color: rgb(99, 102, 241);
}
@media (max-width: 768px) {
.feature-highlight,
.feature-highlight.reverse {
flex-direction: column;
}
.highlight-image {
height: 200px;
}
.project-header {
flex-direction: column;
align-items: flex-start;
}
.project-logo {
margin-bottom: 1rem;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

View File

@ -0,0 +1,475 @@
---
title: xiaozhi-esp32-server
description: 基于ESP32的小智开源服务端轻量级且高效的语音交互服务
---
# xiaozhi-esp32-server
<div class="project-header">
<div class="project-logo">
<img src="./images/logo.png" alt="xiaozhi-esp32-server Logo" onerror="this.src='/py-xiaozhi/images/logo.png'; this.onerror=null;">
</div>
<div class="project-badges">
<span class="badge platform">ESP32</span>
<span class="badge language">Python</span>
<span class="badge status">活跃开发中</span>
</div>
</div>
<div class="project-intro">
<p>xiaozhi-esp32-server是为开源智能硬件项目<a href="https://github.com/78/xiaozhi-esp32" target="_blank">xiaozhi-esp32</a>提供的后端服务,根据<a href="https://ccnphfhqs21z.feishu.cn/wiki/M0XiwldO9iJwHikpXD5cEx71nKh" target="_blank">小智通信协议</a>使用Python实现帮助您快速搭建小智服务器。</p>
</div>
## 适用人群
本项目需要配合ESP32硬件设备使用。如果您已经购买了ESP32相关硬件且成功对接过虾哥部署的后端服务并希望独立搭建自己的`xiaozhi-esp32`后端服务,那么本项目非常适合您。
<div class="warning-box">
<h3>⚠️ 重要提示</h3>
<ol>
<li>本项目为开源软件与对接的任何第三方API服务商包括但不限于语音识别、大模型、语音合成等平台均不存在商业合作关系不为其服务质量及资金安全提供任何形式的担保。建议使用者优先选择持有相关业务牌照的服务商并仔细阅读其服务协议及隐私政策。本软件不托管任何账户密钥、不参与资金流转、不承担充值资金损失风险。</li>
<li>本项目成立时间较短,还未通过网络安全测评,请勿在生产环境中使用。如果您在公网环境中部署学习本项目,请务必在配置文件<code>config.yaml</code>中开启防护。</li>
</ol>
</div>
## 核心特性
<div class="features-container">
<div class="feature-item">
<div class="feature-icon">🔄</div>
<h3>通信协议</h3>
<p>基于<code>xiaozhi-esp32</code>协议通过WebSocket实现数据交互</p>
</div>
<div class="feature-item">
<div class="feature-icon">💬</div>
<h3>对话交互</h3>
<p>支持唤醒对话、手动对话及实时打断,长时间无对话时自动休眠</p>
</div>
<div class="feature-item">
<div class="feature-icon">🧠</div>
<h3>意图识别</h3>
<p>支持使用LLM意图识别、function call函数调用减少硬编码意图判断</p>
</div>
<div class="feature-item">
<div class="feature-icon">🌐</div>
<h3>多语言识别</h3>
<p>支持国语、粤语、英语、日语、韩语默认使用FunASR</p>
</div>
<div class="feature-item">
<div class="feature-icon">🤖</div>
<h3>LLM模块</h3>
<p>支持灵活切换LLM模块默认使用ChatGLMLLM也可选用阿里百炼、DeepSeek、Ollama等</p>
</div>
<div class="feature-item">
<div class="feature-icon">🔊</div>
<h3>TTS模块</h3>
<p>支持EdgeTTS默认、火山引擎豆包TTS等多种TTS接口满足语音合成需求</p>
</div>
<div class="feature-item">
<div class="feature-icon">📝</div>
<h3>记忆功能</h3>
<p>支持超长记忆、本地总结记忆、无记忆三种模式,满足不同场景需求</p>
</div>
<div class="feature-item">
<div class="feature-icon">🏠</div>
<h3>IOT功能</h3>
<p>支持管理注册设备IOT功能支持基于对话上下文语境下的智能物联网控制</p>
</div>
<div class="feature-item">
<div class="feature-icon">🖥️</div>
<h3>智控台</h3>
<p>提供Web管理界面支持智能体管理、用户管理、系统配置等功能</p>
</div>
</div>
## 部署方式
本项目提供两种部署方式,请根据您的具体需求选择:
<div class="deployment-table">
<table>
<thead>
<tr>
<th>部署方式</th>
<th>特点</th>
<th>适用场景</th>
</tr>
</thead>
<tbody>
<tr>
<td><strong>最简化安装</strong></td>
<td>智能对话、IOT功能数据存储在配置文件</td>
<td>低配置环境,无需数据库</td>
</tr>
<tr>
<td><strong>全模块安装</strong></td>
<td>智能对话、IOT、OTA、智控台数据存储在数据库</td>
<td>完整功能体验</td>
</tr>
</tbody>
</table>
</div>
详细部署文档请参考:
- [Docker部署文档](https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/Deployment.md)
- [源码部署文档](https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/Deployment_all.md)
## 支持平台列表
xiaozhi-esp32-server支持丰富的第三方平台和组件
### LLM 语言模型
<div class="platform-item">
<h4>接口调用</h4>
<p><strong>支持平台:</strong>阿里百炼、火山引擎豆包、深度求索、智谱ChatGLM、Gemini、Ollama、Dify、Fastgpt、Coze</p>
<p><strong>免费平台:</strong>智谱ChatGLM、Gemini</p>
<p><em>实际上任何支持openai接口调用的LLM均可接入使用</em></p>
</div>
### TTS 语音合成
<div class="platform-item">
<h4>接口调用</h4>
<p><strong>支持平台:</strong>EdgeTTS、火山引擎豆包TTS、腾讯云、阿里云TTS、CosyVoiceSiliconflow、TTS302AI、CozeCnTTS、GizwitsTTS、ACGNTTS、OpenAITTS</p>
<p><strong>免费平台:</strong>EdgeTTS、CosyVoiceSiliconflow(部分)</p>
<h4>本地服务</h4>
<p><strong>支持平台:</strong>FishSpeech、GPT_SOVITS_V2、GPT_SOVITS_V3、MinimaxTTS</p>
<p><strong>免费平台:</strong>FishSpeech、GPT_SOVITS_V2、GPT_SOVITS_V3、MinimaxTTS</p>
</div>
### ASR 语音识别
<div class="platform-item">
<h4>接口调用</h4>
<p><strong>支持平台:</strong>DoubaoASR</p>
<h4>本地服务</h4>
<p><strong>支持平台:</strong>FunASR、SherpaASR</p>
<p><strong>免费平台:</strong>FunASR、SherpaASR</p>
</div>
### 更多组件
- **VAD语音活动检测**支持SileroVAD本地免费使用
- **记忆存储**支持mem0ai1000次/月额度、mem_local_short本地总结免费
- **意图识别**支持intent_llm通过大模型识别意图、function_call通过大模型函数调用完成意图
## 参与贡献
xiaozhi-esp32-server是一个活跃的开源项目欢迎贡献代码或提交问题反馈
- [GitHub仓库](https://github.com/xinnan-tech/xiaozhi-esp32-server)
- [问题反馈](https://github.com/xinnan-tech/xiaozhi-esp32-server/issues)
- [致开发者的公开信](https://github.com/xinnan-tech/xiaozhi-esp32-server/blob/main/docs/contributor_open_letter.md)
<style>
.project-header {
display: flex;
align-items: center;
margin-bottom: 2rem;
}
.project-logo {
width: 100px;
height: 100px;
margin-right: 1.5rem;
}
.project-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.project-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.85rem;
font-weight: 500;
}
.badge.platform {
background-color: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.badge.language {
background-color: rgba(59, 130, 246, 0.2);
color: rgb(59, 130, 246);
}
.badge.status {
background-color: rgba(16, 185, 129, 0.2);
color: rgb(16, 185, 129);
}
.project-intro {
font-size: 1.1rem;
line-height: 1.6;
margin-bottom: 2rem;
padding: 1.5rem;
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
border-left: 4px solid var(--vp-c-brand);
}
.warning-box {
margin: 2rem 0;
padding: 1.5rem;
background-color: rgba(234, 179, 8, 0.1);
border-left: 4px solid rgba(234, 179, 8, 0.8);
border-radius: 8px;
}
.warning-box h3 {
color: rgb(234, 179, 8);
margin-top: 0;
}
.features-container {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.feature-item {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
border: 1px solid var(--vp-c-divider);
}
.feature-item:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2rem;
margin-bottom: 1rem;
}
.feature-item h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 0.5rem;
}
.deployment-table {
margin: 2rem 0;
overflow-x: auto;
}
.deployment-table table {
width: 100%;
border-collapse: collapse;
}
.deployment-table th,
.deployment-table td {
padding: 1rem;
text-align: left;
border-bottom: 1px solid var(--vp-c-divider);
}
.deployment-table th {
background-color: var(--vp-c-bg-soft);
font-weight: 500;
}
.platform-item {
margin: 1.5rem 0;
padding: 1.5rem;
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
}
.platform-item h4 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 1rem;
}
.platform-item p {
margin: 0.5rem 0;
}
.demo-videos {
margin: 2rem 0;
}
.video-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
}
.video-item {
display: block;
text-decoration: none;
color: inherit;
border-radius: 8px;
overflow: hidden;
transition: transform 0.3s ease;
background-color: var(--vp-c-bg-soft);
}
.video-item:hover {
transform: translateY(-5px);
}
.video-thumbnail {
width: 100%;
aspect-ratio: 16 / 9;
overflow: hidden;
}
.video-thumbnail img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 0.3s ease;
}
.video-item:hover .video-thumbnail img {
transform: scale(1.05);
}
.video-title {
padding: 1rem;
font-weight: 500;
}
.demo-more {
text-align: center;
margin-top: 1.5rem;
}
.demo-more a {
display: inline-block;
padding: 0.5rem 1.5rem;
background-color: var(--vp-c-brand);
color: white;
border-radius: 4px;
text-decoration: none;
transition: background-color 0.3s ease;
}
.demo-more a:hover {
background-color: var(--vp-c-brand-dark);
}
.related-projects {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.project-card {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
display: flex;
flex-direction: column;
border: 1px solid var(--vp-c-divider);
transition: transform 0.3s ease, box-shadow 0.3s ease;
}
.project-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.project-card h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 1rem;
}
.project-link {
margin-top: auto;
display: inline-block;
padding: 0.5rem 1rem;
background-color: var(--vp-c-brand);
color: white;
text-decoration: none;
border-radius: 4px;
text-align: center;
transition: background-color 0.3s ease;
}
.project-link:hover {
background-color: var(--vp-c-brand-dark);
}
.contributors {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(300px, 1fr));
gap: 2rem;
margin: 2rem 0;
}
.contributor {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
text-align: center;
border: 1px solid var(--vp-c-divider);
}
.contributor img {
width: 120px;
height: 60px;
object-fit: contain;
margin-bottom: 1rem;
}
.contributor h4 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 0.5rem;
}
@media (max-width: 768px) {
.project-header {
flex-direction: column;
align-items: flex-start;
}
.project-logo {
margin-bottom: 1rem;
}
.contributors {
grid-template-columns: 1fr;
}
.related-projects {
grid-template-columns: 1fr;
}
.features-container {
grid-template-columns: 1fr;
}
}
</style>

Binary file not shown.

After

Width:  |  Height:  |  Size: 549 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 MiB

View File

@ -0,0 +1,504 @@
---
title: XiaoZhiAI_server32_Unity
description: 基于Unity的小智AI视觉交互服务实现语音与Live2D多模态人机交互体验
---
# XiaoZhiAI_server32_Unity
<div class="project-header">
<div class="project-logo">
<img src="./images/logo.png" alt="Unity Logo">
</div>
<div class="project-badges">
<span class="badge platform">跨平台</span>
<span class="badge language">C#/Unity</span>
<span class="badge status">活跃开发中</span>
</div>
</div>
## 项目简介
XiaoZhiAI_server32_Unity是一个基于Unity开发的AI应用程序专注于提供高质量的语音交互和网络服务功能。本项目利用Unity的跨平台特性支持多种设备和操作系统包括PC、Android、iOS、WebGL和微信小程序为用户提供流畅的AI语音与Live2D交互体验。
## 技术架构
XiaoZhiAI_server32_Unity基于以下技术栈构建
- **开发引擎**Unity 2020.3或更高版本
- **目标平台**PC、Android、iOS、WebGL、微信小程序
- **核心功能模块**
- **语音交互系统**:实时语音识别、自然语言处理、语音合成
- **Live2D交互**服务端返回LLM表情交互Live2D
- **Mqtt硬件交互**服务端functioncall处理IoT返回
- **依赖包**
- OPUS解码SDK
- WebSocket网络通信库
- YooAsset资源管理框架2.3.7版本
- YuikFrameWork (YOO分支)
- Hycrl热更新框架
## 核心功能
### 语音交互能力
<div class="features-grid">
<div class="feature-card">
<div class="feature-icon">🎤</div>
<h3>实时语音识别</h3>
<p>支持多种语言的实时语音转文字准确率高达95%以上</p>
</div>
<div class="feature-card">
<div class="feature-icon">🧠</div>
<h3>自然语言理解</h3>
<p>基于深度学习的语义分析,精准理解用户意图</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔊</div>
<h3>语音合成</h3>
<p>自然流畅的语音输出,支持多种音色和语速调节</p>
</div>
<div class="feature-card">
<div class="feature-icon">🤖</div>
<h3>Live2D表情交互</h3>
<p>根据LLM返回结果实现实时表情变化和情感表达</p>
</div>
<div class="feature-card">
<div class="feature-icon">📱</div>
<h3>IoT与Mqtt对接</h3>
<p>通过functioncall实现智能家居设备控制和状态反馈</p>
</div>
<div class="feature-card">
<div class="feature-icon">🔄</div>
<h3>热更新支持</h3>
<p>基于Hycrl框架的热更新能力无需重装即可升级</p>
</div>
</div>
## 环境要求
### 开发环境
- Unity版本2020.3或更高
- 操作系统Windows 10/11开发环境
### 运行环境
- **PC平台**
- 操作系统Windows 10/11、macOS 10.14+
- 处理器Intel i5或同等性能
- 内存8GB以上
- 显卡支持DirectX 11
- **移动平台**
- Android 6.0+
- iOS 11.0+
- **Web平台**
- 支持WebGL 2.0的现代浏览器
- **硬件要求**
- 麦克风支持16kHz采样率的高质量麦克风语音交互
- 网络稳定的网络连接建议5Mbps以上带宽
## 项目结构
```
XiaoZhiAI_server32_Unity/
├── Assets/ # Unity资源文件
│ ├── Scenes/ # 场景文件
│ ├── Scripts/ # 脚本文件
│ │ ├── VoiceInteraction/ # 语音交互相关脚本
│ │ ├── Networking/ # 网络通信相关脚本
│ │ └── ...
│ ├── Prefabs/ # 预制体
│ ├── Plugins/ # 第三方插件
│ │ ├── VoiceSDK/ # 语音识别SDK
│ │ └── NetworkLibs/ # 网络库
│ └── ...
├── Packages/ # 项目依赖包
├── ProjectSettings/ # Unity项目设置
└── README.md # 项目说明文档
```
## 安装指南
### 开发者安装
1. 克隆仓库到本地:
```bash
git clone https://gitee.com/vw112266/XiaoZhiAI_server32_Unity.git
```
2. 安装依赖包:
- 手动引入YooAsset资源管理框架v2.3.7https://github.com/tuyoogame/YooAsset
- 手动引入YuikFrameWork-YOO分支https://gitee.com/NikaidoShinku/YukiFrameWork
3. 使用Unity Hub打开项目并确保Unity版本兼容
### 用户安装
1. 从发布页下载对应平台的安装包
2. 按照向导完成安装
3. 启动应用并完成初始配置
## 功能特性展示
### Live2D交互
<div class="feature-highlight">
<div class="highlight-content">
<h3>表情丰富的Live2D模型</h3>
<ul>
<li>根据对话内容实时改变表情</li>
<li>支持多种情感状态表达</li>
<li>精准的口型同步</li>
<li>自然的眨眼和头部动作</li>
<li>可定制的角色形象</li>
</ul>
</div>
<div class="highlight-image">
<img src="./images/界面1.png" alt="演示界面" >
</div>
</div>
### IoT智能控制
<div class="feature-highlight reverse">
<div class="highlight-content">
<h3>家居设备智能控制</h3>
<ul>
<li>通过语音控制智能家居设备</li>
<li>基于functioncall的智能意图识别</li>
<li>支持多种MQTT协议设备</li>
<li>设备状态实时反馈</li>
<li>场景联动与自动化</li>
</ul>
</div>
<div class="highlight-image">
<img src="./images/界面2.png" alt="演示界面">
</div>
</div>
## 开发计划
<div class="roadmap">
<div class="roadmap-item done">
<div class="status-dot"></div>
<div class="item-content">
<h4>已完成功能</h4>
<ul>
<li>基础语音交互系统</li>
<li>Live2D模型集成</li>
<li>WebSocket网络通信</li>
<li>基础MQTT支持</li>
</ul>
</div>
</div>
<div class="roadmap-item progress">
<div class="status-dot"></div>
<div class="item-content">
<h4>开发中功能</h4>
<ul>
<li>更多Live2D模型支持</li>
<li>表情系统优化</li>
<li>移动平台性能优化</li>
<li>更多IoT设备支持</li>
</ul>
</div>
</div>
<div class="roadmap-item planned">
<div class="status-dot"></div>
<div class="item-content">
<h4>计划功能</h4>
<ul>
<li>微信小程序集成</li>
<li>AR互动体验</li>
<li>多角色场景支持</li>
<li>用户自定义模型系统</li>
</ul>
</div>
</div>
</div>
## 贡献指南
我们欢迎社区开发者参与XiaoZhiAI_server32_Unity项目的开发
- 提交bug报告和功能建议
- 贡献代码改进和新功能
- 创建和分享Live2D模型
- 优化性能和用户体验
- 完善文档和教程
请参考我们的贡献指南,了解如何参与项目开发。
## 相关链接
- [项目仓库](https://gitee.com/vw112266/XiaoZhiAI_server32_Unity)
<style>
.project-header {
display: flex;
align-items: center;
margin-bottom: 2rem;
}
.project-logo {
width: 100px;
height: 100px;
margin-right: 1.5rem;
}
.project-logo img {
width: 100%;
height: 100%;
object-fit: contain;
}
.project-badges {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
border-radius: 1rem;
font-size: 0.85rem;
font-weight: 500;
}
.badge.platform {
background-color: var(--vp-c-brand-soft);
color: var(--vp-c-brand-dark);
}
.badge.language {
background-color: rgba(59, 130, 246, 0.2);
color: rgb(59, 130, 246);
}
.badge.status {
background-color: rgba(16, 185, 129, 0.2);
color: rgb(16, 185, 129);
}
.project-images {
display: flex;
gap: 1rem;
margin: 2rem 0;
overflow-x: auto;
}
.image-container {
flex: 1;
min-width: 300px;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.image-container img {
width: 100%;
height: auto;
object-fit: cover;
}
.architecture-diagram {
margin: 2rem 0;
text-align: center;
}
.diagram-container {
max-width: 100%;
border-radius: 8px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.diagram-container img {
max-width: 100%;
height: auto;
}
.features-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(280px, 1fr));
gap: 1.5rem;
margin: 2rem 0;
}
.feature-card {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
transition: transform 0.3s ease, box-shadow 0.3s ease;
border: 1px solid var(--vp-c-divider);
height: 100%;
}
.feature-card:hover {
transform: translateY(-5px);
box-shadow: 0 5px 15px rgba(0, 0, 0, 0.1);
}
.feature-icon {
font-size: 2rem;
margin-bottom: 1rem;
}
.feature-card h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 0.5rem;
}
.feature-highlight {
display: flex;
margin: 3rem 0;
background-color: var(--vp-c-bg-soft);
border-radius: 12px;
overflow: hidden;
border: 1px solid var(--vp-c-divider);
}
.feature-highlight.reverse {
flex-direction: row-reverse;
}
.highlight-image {
flex: 1;
min-width: 40%;
}
.highlight-image img {
width: 100%;
height: 100%;
object-fit: cover;
}
.highlight-content {
flex: 1;
padding: 2rem;
}
.highlight-content h3 {
color: var(--vp-c-brand);
margin-top: 0;
margin-bottom: 1rem;
}
.highlight-content ul {
padding-left: 1.5rem;
}
.highlight-content li {
margin-bottom: 0.5rem;
}
.roadmap {
position: relative;
margin: 3rem 0;
padding-left: 2rem;
}
.roadmap:before {
content: "";
position: absolute;
left: 7px;
top: 0;
bottom: 0;
width: 2px;
background-color: var(--vp-c-divider);
}
.roadmap-item {
position: relative;
margin-bottom: 2rem;
}
.status-dot {
position: absolute;
left: -2rem;
top: 0;
width: 16px;
height: 16px;
border-radius: 50%;
z-index: 1;
}
.roadmap-item.done .status-dot {
background-color: rgb(16, 185, 129);
}
.roadmap-item.progress .status-dot {
background-color: rgb(245, 158, 11);
}
.roadmap-item.planned .status-dot {
background-color: rgb(99, 102, 241);
}
.item-content {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
border: 1px solid var(--vp-c-divider);
}
.item-content h4 {
margin-top: 0;
margin-bottom: 1rem;
}
.roadmap-item.done h4 {
color: rgb(16, 185, 129);
}
.roadmap-item.progress h4 {
color: rgb(245, 158, 11);
}
.roadmap-item.planned h4 {
color: rgb(99, 102, 241);
}
pre {
background-color: var(--vp-c-bg-soft);
border-radius: 8px;
padding: 1.5rem;
overflow-x: auto;
}
@media (max-width: 768px) {
.feature-highlight,
.feature-highlight.reverse {
flex-direction: column;
}
.highlight-image {
height: 200px;
}
.project-header {
flex-direction: column;
align-items: flex-start;
}
.project-logo {
margin-bottom: 1rem;
}
.project-images {
flex-direction: column;
}
}
</style>

View File

@ -0,0 +1,47 @@
# py-xiaozhi文档目录
本目录包含了 py-xiaozhi 项目 的全部功能文档,按功能模块进行划分,便于查阅和使用。
项目默认启用了以下模块音乐、灯光、音量、定时器、Home asssistant控制器、相机 IoT 控制。
其他模块可根据需求自行扩展与启用。
视觉识别功能 需配置 智普大模型的 API Key 才可使用。
当前项目已经启用v2授权协议wss链接通过ota接口返回、无论是官方小智和开源后端已经对齐认证流程
## 基础文档
- [01_系统依赖安装](01_系统依赖安装) - 各平台的系统依赖和Python环境配置
- [02_配置说明](02_配置说明.md) - 配置文件结构、配置项说明和修改指南
- [03_语音交互模式说明](03_语音交互模式说明) - 项目概述、基本使用说明和运行模式
- [04_语音唤醒](04_语音唤醒.md) - 语音唤醒功能的配置和使用说明
- [05_IoT功能说明](05_IoT功能说明.md) - 物联网功能架构、设备控制和扩展方法
- [06_音量控制功能](06_音量控制功能.md) - 系统音量控制功能的使用和配置
- [07_视觉识别功能](07_视觉识别功能.md) - 摄像头控制和视觉分析功能
- [08_设备激活流程](08_设备激活流程) - 设备激活和注册流程说明
- [09_打包教程](09_打包教程.md) - 使用UnifyPy打包小智客户端的详细教程
## 其他文档
- [异常汇总](异常汇总.md) - 常见问题和解决方案
## 旧版文档
为了便于参考,我们保留了旧版文档:
- [旧版使用文档](old_docs/使用文档.md) - 较早版本的使用说明文档
## 参与贡献
如果您想参与项目开发或提供反馈,请查看以下资源:
- [贡献指南](/contributing) - 如何为项目贡献代码包括开发流程、代码规范和PR提交流程
- [团队成员](/about/team) - 感谢为项目做出贡献的团队成员
- [赞助支持](/sponsors/) - 如何赞助项目发展
## 相关生态
- [相关生态](/ecosystem/) - py-xiaozhi项目的相关生态系统和扩展项目
## 版本信息
文档最后更新时间2025年5月

View File

@ -0,0 +1,254 @@
# 系统依赖安装
⚠️务必按照教程安装顺序进行软件、工具的安装
推荐使用conda环境进行安装PyQt5、OpenCV可以直接使用conda预编译好的版本。pip在arm64 4GB及其以下设备上PyQt5、OpenCV极其容易编译失败无法安装
## 系统依赖安装
### 多媒体处理组件
#### 1. **FFmpeg 视频处理工具**
##### 📦 Windows 安装方式
* **推荐方式:使用 Scoop 安装**
```bash
scoop install ffmpeg
```
* **手动安装**
1. 前往 [BtbN/FFmpeg-Builds](https://github.com/BtbN/FFmpeg-Builds/releases) 下载对应版本
2. 解压后将 `bin` 目录路径添加至系统环境变量 `PATH`
##### 🌐 跨平台安装(适用于 Conda 环境)
```bash
conda install -c conda-forge ffmpeg
```
---
#### 2. **Opus 音频编解码器**
* 默认情况下,项目已自动引入 `opus.dll`**通常无需额外安装**
* 如遇找不到库的问题Windows 用户可手动复制 `/libs/windows/opus.dll` 到以下任一位置:
* 应用程序运行目录
* `C:\Windows\System32`
##### Conda 环境安装方式:
```bash
conda install -c conda-forge opus
```
### Linux (Debian/Ubuntu)
```bash
# 安装系统依赖
sudo apt-get update
# 必装
sudo apt-get install python3-pyaudio portaudio19-dev ffmpeg libopus0 libopus-dev build-essential python3-venv
# 安装音量控制依赖(以下三选一)
# 1. PulseAudio 工具(推荐)
sudo apt-get install pulseaudio-utils
# 2. 或者 ALSA 工具
sudo apt-get install alsa-utils
# 3. 如果需要使用 alsamixer 方式,还需要安装 expect
sudo apt-get install alsa-utils expect
```
### macOS
```bash
# 使用 Homebrew 安装系统依赖
brew install portaudio opus python-tk ffmpeg gfortran
brew upgrade tcl-tk
```
## Python 依赖安装
---
### 方式一:使用 Miniconda推荐
### 1. 下载 Miniconda 安装包(
根据你的系统架构或操作系统选择下载命令:
| 系统 / 架构 | 下载指令 |
|:-----------|:---------|
| **Linux - x86_64**PC/服务器常用) | ```bash wget -O Miniconda3-latest-Linux-x86_64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-x86_64.sh ``` |
| **Linux - aarch64**ARM64比如树莓派、部分服务器 | ```bash wget -O Miniconda3-latest-Linux-aarch64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-aarch64.sh ``` |
| **Linux - ppc64le**IBM Power服务器 | ```bash wget -O Miniconda3-latest-Linux-ppc64le.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-Linux-ppc64le.sh ``` |
| **Windows - x86_64**普通Windows PC | [点击下载](https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-x86_64.exe) |
| **Windows - arm64**ARM Windows设备如Surface Pro X | [点击下载](https://repo.anaconda.com/miniconda/Miniconda3-latest-Windows-arm64.exe) |
| **macOS - x86_64**Intel芯片Mac | ```bash wget -O Miniconda3-latest-MacOSX-x86_64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh ``` |
| **macOS - arm64**Apple Silicon芯片如M1/M2/M3 | ```bash wget -O Miniconda3-latest-MacOSX-arm64.sh https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh ``` |
---
### 2. 给安装脚本添加执行权限仅Linux/macOS
```bash
chmod +x Miniconda3-latest-*.sh
```
### 3. 运行安装程序仅Linux/macOS
```bash
./Miniconda3-latest-*.sh
```
⚡ *注意Linux/macOS下不需要用`sudo`,用普通用户安装即可。*
---
### 4. 安装过程中 windows请按照网络搜索到的教程来
1. 出现许可协议 → 按 `Enter` 键慢慢翻,或按 `q` 直接跳过。
2. 输入 `yes` 接受协议。
3. 选择安装路径,默认是 `$HOME/miniconda3` → 直接按 `Enter` 确认。
4. 是否初始化 Miniconda → 输入 `yes`(推荐)。
---
### 5. 配置环境变量(如果未自动配置)
Linux/macOS 编辑 `.bashrc`
```bash
nano ~/.bashrc
```
在文件末尾添加:
```bash
export PATH="$HOME/miniconda3/bin:$PATH"
```
保存并退出:
- 按 `Ctrl + X`
- 按 `Y`
- 按 `Enter`
让配置立即生效:
```bash
source ~/.bashrc
```
---
### 6. 检查 conda 安装成功
```bash
conda --version
```
如果看到版本号,比如 `conda 24.1.2`,就代表安装成功!
---
### 7. 初始化conda可选但推荐
```bash
conda init
bash
```
然后打开新终端,看到 `(base)`,说明环境正常激活。
---
### 8. (推荐)关闭开机自动激活 base 环境
```bash
conda config --set auto_activate_base false
```
这样以后打开终端是干净的,需要的时候再手动 `conda activate base`
### 一键自动更换当前网络下最快pip软件源
* **为了更稳定更快速的安装所需依赖包,建议安装**
[工具地址|chsrc 全平台通用换源工具|GitHub仓库](https://github.com/RubyMetric/chsrc)
```bash
# windows安装PowerShell管理员权限打开输入下面这句
winget install RubyMetric.chsrc --source winget
# 个人服务器加速下载支持x86_64和arm64架构
wget -O- aslant.top/chsrc.sh|sudo bash
# 更换pip软件源
chsrc set pip
```
## 安装项目依赖
### 1. 创建 Conda 环境
```bash
conda create -n py-xiaozhi python=3.10 -y
```
### 2. 激活环境
```bash
conda activate py-xiaozhi
```
### 3. 安装 Python 依赖
```bash
# Windows/Linux
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# macOS
pip install -r requirements_mac.txt -i https://mirrors.aliyun.com/pypi/simple
```
* 安装其它依赖(**因为pip安装这两个可能会启动不了。需要在conda单独安装**)
```bash
# 依然在创建的px-xiaozhi虚拟环境中
# PyQt5
conda install pyqt=5.15.10 -y
# OpenCV
conda install opencv=4.10.0 -y
# windows电脑需要单独安装这个
pip install wmi
```
---
### 方式二:使用 venv (不再推荐)
- mac上会提示系统无法验证 SSL 证书的签发机构也就是说缺少或未安装系统根证书CA certificates
```bash
# 1. 创建虚拟环境
python -m venv .venv
# 2. 激活虚拟环境
# Windows
.venv\Scripts\activate
# Linux/macOS
source .venv/bin/activate
# 3. 安装依赖
# Windows/Linux
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# macOS
pip install -r requirements_mac.txt -i https://mirrors.aliyun.com/pypi/simple
# 由于requirements 去除了这几个默认的需要单独安装
pip install PyQt5==5.15.9 opencv-python==4.11.0.86 wmi==1.5.1 -i https://mirrors.aliyun.com/pypi/simple
```
## 注意事项
1. 建议使用 Python 3.9.13+ 版本,推荐 3.10 最大版本3.12(不行就降级)
2. Windows 用户无需手动安装 opus.dll项目会自动处理
3. 使用 Conda 环境时必须安装 ffmpeg 和 Opus
4. 使用 Conda 环境时请勿和esp32-server共用同一个Conda环境因为服务端websocket依赖版本高于本项目
5. 建议使用国内镜像源安装依赖,可以提高下载速度
6. macOS 用户需使用专门的 requirements_mac.txt
7. 确保系统依赖安装完成后再安装 Python 依赖

View File

@ -0,0 +1,185 @@
# 配置说明
## 项目基础配置
### 配置文件说明
项目使用两种配置方式:初始配置模板和运行时配置文件。
1. **初始配置模板**
- 位置:`/src/utils/config_manager.py`
- 作用:提供默认配置模板,首次运行时会自动生成配置文件
- 使用场景:首次运行或需要重置配置时修改此文件
2. **运行时配置文件**
- 位置:`/config/config.json`
- 作用:存储实际运行时的配置信息
- 使用场景:日常使用时修改此文件
3. **设备身份文件**
- 位置:`/config/efuse.json`
- 作用:存储设备唯一标识信息,包括序列号和激活状态
- 使用场景:设备激活流程中自动生成和更新
### 配置项访问方式
配置系统设计为层级结构,使用点分隔的路径访问特定配置项:
```python
# 示例:获取配置值
from src.utils.config_manager import ConfigManager
config = ConfigManager.get_instance()
mqtt_endpoint = config.get_config("SYSTEM_OPTIONS.NETWORK.MQTT_INFO.endpoint")
# 示例:更新配置值
config.update_config("WAKE_WORD_OPTIONS.USE_WAKE_WORD", True)
```
## 网络配置
网络配置位于`SYSTEM_OPTIONS.NETWORK`下,主要包含以下内容:
```json
"NETWORK": {
"OTA_VERSION_URL": "https://api.tenclass.net/xiaozhi/ota/", // OTA更新地址
"WEBSOCKET_URL": "ws://192.168.31.232:8000/xiaozhi/v1/", // WebSocket服务器地址
"WEBSOCKET_ACCESS_TOKEN": "test-token", // 访问令牌
"MQTT_INFO": {
"endpoint": "", // MQTT服务器地址
"client_id": "", // MQTT客户端ID
"username": "", // MQTT用户名
"password": "", // MQTT密码
"publish_topic": "", // 发布主题
"subscribe_topic": "" // 订阅主题
},
"ACTIVATION_VERSION": "v2", // 激活版本,可选值: v1, v2
"AUTHORIZATION_URL": "https://xiaozhi.me/" // 授权URL地址
}
```
## 设备激活
设备首次使用时需要进行激活,激活信息存储在`config/efuse.json`文件中:
```json
{
"serial_number": "SN-E3E1F618-902e16dbe116", // 设备序列号
"hmac_key": "b5bf012dd518080532f928b70ed958799f34f9224e80dd4128795a70a5baca24", // 密钥
"activation_status": false // 激活状态激活成功后变为true
}
```
激活流程由`ACTIVATION_VERSION`配置项控制:
- `v1`:简化激活模式
- `v2`:完整激活流程,包括验证码确认
## 唤醒词配置
语音唤醒相关配置位于`WAKE_WORD_OPTIONS`下:
```json
"WAKE_WORD_OPTIONS": {
"USE_WAKE_WORD": false, // 是否启用语音唤醒
"MODEL_PATH": "models/vosk-model-small-cn-0.22", // 唤醒模型路径
"WAKE_WORDS": [ // 唤醒词列表
"小智",
"小美"
]
}
```
## 摄像头与视觉识别
摄像头和视觉识别相关配置位于`CAMERA`下:
```json
"CAMERA": {
"camera_index": 0, // 摄像头索引
"frame_width": 640, // 画面宽度
"frame_height": 480, // 画面高度
"fps": 30, // 帧率
"Loacl_VL_url": "https://open.bigmodel.cn/api/paas/v4/", // 智普API地址
"VLapi_key": "你自己的key", // 智普视觉大模型API密钥
"models": "glm-4v-plus" // 使用的视觉模型
}
```
## IoT设备配置
### 温度传感器
温度传感器通过MQTT协议连接配置位于`TEMPERATURE_SENSOR_MQTT_INFO`下:
```json
"TEMPERATURE_SENSOR_MQTT_INFO": {
"endpoint": "你的Mqtt连接地址", // MQTT服务器地址
"port": 1883, // MQTT服务器端口
"username": "admin", // MQTT用户名
"password": "123456", // MQTT密码
"publish_topic": "sensors/temperature/command", // 发布主题
"subscribe_topic": "sensors/temperature/device_001/state" // 订阅主题
}
```
需要注意:
- `endpoint`必须是有效的MQTT服务器地址
- `port`默认为1883如使用TLS加密则通常为8883
- `publish_topic`用于发送命令到设备
- `subscribe_topic`用于接收设备状态
### Home Assistant集成
Home Assistant智能家居平台集成配置位于`HOME_ASSISTANT`下:
```json
"HOME_ASSISTANT": {
"URL": "http://你的Home Assistant地址:8123", // Home Assistant服务器地址
"TOKEN": "长期访问令牌", // 访问令牌
"DEVICES": [] // 要集成的设备列表
}
```
通过此配置可以控制添加到Home Assistant中的各类设备包括
- 灯光设备HomeAssistantLight
- 开关设备HomeAssistantSwitch
- 数值设备HomeAssistantNumber
- 按钮设备HomeAssistantButton
## 配置修改指南
1. **首次使用配置**
- 直接运行程序,系统会自动生成默认配置文件
- 如需修改默认值,可编辑 `config_manager.py` 中的 `DEFAULT_CONFIG`
2. **更换服务器配置**
- 打开 `/config/config.json`
- 修改 `SYSTEM_OPTIONS.NETWORK.WEBSOCKET_URL` 为新的服务器地址
- 示例:
```json
"SYSTEM_OPTIONS": {
"NETWORK": {
"WEBSOCKET_URL": "ws://你的服务器地址:端口号/"
}
}
```
3. **启用语音唤醒**
- 修改 `WAKE_WORD_OPTIONS.USE_WAKE_WORD``true`
- 可在 `WAKE_WORD_OPTIONS.WAKE_WORDS` 数组中添加或修改唤醒词
4. **配置摄像头与视觉识别**
- 修改 `CAMERA` 部分的相关配置
- 将 `VLapi_key` 设置为你从智普AI平台获取的API密钥
- 可以根据需要调整分辨率和帧率
5. **配置Home Assistant集成**
- 在Home Assistant中创建长期访问令牌
- 填写 `HOME_ASSISTANT.URL``HOME_ASSISTANT.TOKEN`
- 设备会自动发现并集成
## 注意事项
- 修改配置文件后需要重启程序才能生效
- WebSocket URL 必须以 `ws://``wss://` 开头
- 首次运行时会自动生成 CLIENT_ID建议不要手动修改
- DEVICE_ID 默认使用设备MAC地址可按需修改
- 配置文件使用 UTF-8 编码,请使用支持 UTF-8 的编辑器修改
- 请妥善保管API密钥和访问令牌等敏感信息
- Home Assistant集成需要保证网络可以正常访问到Home Assistant服务器

View File

@ -0,0 +1,152 @@
# 语音交互模式说明
![Image](./images/系统界面.png)
## 项目概述
py-xiaozhi是一个智能语音交互助手支持多种操作模式和功能包括语音对话、物联网设备控制、视觉识别等功能。本文档主要介绍语音交互的基本使用方法。
## 语音交互模式
语音交互支持两种模式,您可以根据实际需求选择合适的交互方式:
### 1. 长按对话模式
- **操作方法**:按住说话按钮,松手发送
- **适用场景**:短句交流,精确控制对话开始和结束时间
- **优点**:避免误触发,控制精确
- **快捷键**Alt+Shift+V按住说话
### 2. 自动对话模式
- **操作方法**:点击开始对话,系统自动检测语音并发送
- **适用场景**:长句交流,无需手动控制
- **优点**:解放双手,自然交流
- **界面提示**:显示"聆听中"表示系统正在接收您的语音
- **快捷键**Alt+Shift+A开始自动对话
### 模式切换
- 在GUI界面右下角显示当前模式
- 点击按钮可以切换模式
- 通过Alt+Shift+M快捷键切换模式
- 可以通过配置文件设置默认模式
## 对话控制
### 打断功能
当系统正在语音回复时,您可以随时打断:
- **GUI模式**使用Alt+Shift+X或界面上的打断按钮
- **CLI模式**使用F3键
## 系统托盘
GUI模式下支持系统托盘功能
- **状态指示**:托盘图标颜色反映当前系统状态
- 绿色:已启动/待命状态
- 黄色:聆听中状态
- 蓝色:说话中状态
- 红色:错误状态
- 灰色:未连接状态
- **最小化**:关闭窗口时自动最小化到系统托盘
- **退出**:右键点击托盘图标选择"退出程序"完全退出应用
### 状态流转
语音交互系统有以下几种状态:
```
+----------------+
| |
v |
+------+ 唤醒词/按钮 +------------+ | +------------+
| IDLE | -----------> | CONNECTING | --+-> | LISTENING |
+------+ +------------+ +------------+
^ |
| | 语音识别完成
| +------------+ v
+--------- | SPEAKING | <-----------------+
完成播放 +------------+
```
- **IDLE**:空闲状态,等待唤醒词或按钮触发
- **CONNECTING**:正在连接服务器
- **LISTENING**:正在聆听用户语音
- **SPEAKING**:系统正在语音回复
## 快捷键一览
| 功能 | 快捷键 | 说明 |
|------|--------|------|
| 按住说话 | Alt+Shift+V | 按住进行录音,松开发送(仅手动模式) |
| 自动对话 | Alt+Shift+A | 开始自动对话(自动检测语音并发送) |
| 打断对话 | Alt+Shift+X | 打断当前AI正在进行的回复 |
| 切换模式 | Alt+Shift+M | 在手动对话/自动对话模式间切换 |
## 语音命令
系统支持多种语音命令,以下是常用命令示例:
### 基础交互
- "你好"/"你是谁" - 基础打招呼和身份询问
- "谢谢"/"再见" - 礼貌用语
### 物联网控制
- "打开/关闭客厅的灯" - 控制灯光
- "播放 菊花台 通过iot音乐播放器播放" - 开始播放音乐
### 视觉识别
- "打开摄像头" - 开启摄像头
- "识别画面" - 分析当前画面
- "识别到了什么" - ai播放识别的内容
- "关闭摄像头" - 关闭摄像头
## 运行模式
### GUI 模式运行(默认)
```bash
python main.py
```
### CLI模式运行
```bash
python main.py --mode cli
```
### 构建打包
使用PyInstaller打包为可执行文件
```bash
# 各平台通用命令
python scripts/build.py
```
## 平台兼容性说明
- **Windows**: 完全支持所有功能
- **macOS**:
- 系统托盘显示在顶部状态栏,而非任务栏
- 快捷键使用可能需要系统权限授权
- **Linux**:
- 系统托盘支持可能因桌面环境(GNOME/KDE/Xfce等)有所不同
- 部分发行版可能需要安装额外的系统托盘支持包
## 最佳实践
1. **清晰发音**:确保在安静环境中清晰发音
2. **适当停顿**:句子间适当停顿有助于系统识别
3. **使用唤醒词**:开启唤醒词功能,可以避免误触发
4. **查看反馈**:注意界面状态提示,了解系统当前状态
5. **简洁命令**:使用简洁明了的命令获得更好的识别效果
## 获取帮助
如果遇到问题:
1. 优先查看 docs/异常汇总.md 文档
2. 通过 GitHub Issues 提交问题
3. 通过 AI 助手寻求帮助
4. 联系作者(主页有微信)(请自备 Todesk 链接并说明来意,作者工作日晚上处理)

View File

@ -0,0 +1,47 @@
# 语音唤醒功能
## 唤醒词模型
使用语音唤醒功能需要下载和配置唤醒词模型:
- [唤醒词模型下载](https://alphacephei.com/vosk/models)
- 下载完成后解压放至根目录/models
- 默认读取vosk-model-small-cn-0.22小模型
- ![Image](./images/唤醒词.png)
## 启用语音唤醒
1. 打开配置文件 `/config/config.json`
2. 修改 `WAKE_WORD_OPTIONS.USE_WAKE_WORD` 设置为 `true`
3. 可以在 `WAKE_WORD_OPTIONS.WAKE_WORDS` 数组中自定义唤醒词
4. 确保 `WAKE_WORD_OPTIONS.MODEL_PATH` 设置正确,指向您下载的模型
示例配置:
```json
{
"WAKE_WORD_OPTIONS": {
"USE_WAKE_WORD": true,
"MODEL_PATH": "models/vosk-model-small-cn-0.22",
"WAKE_WORDS": [
"小智",
"你好小智",
"嘿小智"
]
}
}
```
## 使用方法
1. 启动程序后,系统会加载唤醒词模型并自动进入唤醒词监听状态
2. 说出您设置的唤醒词(如"小智"系统会自动从IDLE状态切换到LISTENING状态
3. 此时可以继续说出您的指令
4. 如果您未说出任何指令,系统会在一段时间后自动回到唤醒词监听状态
## 注意事项
1. 唤醒词模型加载需要一定时间,请耐心等待
2. 唤醒词识别准确度取决于模型质量和环境噪音
3. 可以尝试不同大小的模型,小模型速度快但准确度较低
4. 考虑使用独特的唤醒词以避免误触发
5. 使用唤醒词功能会略微增加系统资源占用

View File

@ -0,0 +1,649 @@
# IoT功能说明
## 概述
py-xiaozhi项目中的IoT物联网模块提供了一个灵活、可扩展的设备控制框架支持通过语音命令控制多种虚拟和物理设备。本文档详细介绍IoT模块的架构、使用方法以及如何扩展自定义设备。
如需执行完立马同步状态和播报结果请参考相机模块和温湿度模块
## 核心架构
IoT模块采用分层设计由以下主要组件构成
```
├── iot # IoT设备相关模块
│ ├── things # 具体设备实现目录
│ │ ├── lamp.py # 灯设备实现
│ │ ├── speaker.py # 音量控制实现
│ │ ├── music_player.py # 音乐播放器实现
│ │ ├── countdown_timer.py # 倒计时器实现
│ │ ├── ha_control.py # Home Assistant设备控制
│ │ ├── CameraVL/ # 摄像头与视觉识别集成设备
│ │ ├── temperature_sensor.py# 温度传感器实现
│ │ └── query_bridge_rag.py # RAG检索桥接设备
│ ├── thing.py # IoT设备基类和工具类定义
│ │ ├── Thing # IoT设备抽象基类
│ │ ├── Property # 设备属性类
│ │ ├── Parameter # 设备方法参数类
│ │ └── Method # 设备方法类
│ └── thing_manager.py # IoT设备管理器
│ └── ThingManager # 单例模式实现的设备管理器
```
### 核心类说明
1. **Thing设备基类**
- 所有IoT设备的抽象基类
- 提供属性和方法的注册机制
- 提供状态和描述的JSON序列化
2. **Property属性类**
- 定义设备的可变状态(如开/关、亮度等)
- 支持布尔、数字和字符串三种基本类型
- 使用getter回调实时获取设备状态
3. **Method方法类**
- 定义设备可执行的操作(如打开、关闭等)
- 支持带参数的方法调用
- 通过callback处理具体操作实现
4. **Parameter参数类**
- 定义方法的参数规范
- 包含名称、描述、类型和是否必需等信息
5. **ThingManager设备管理器**
- 集中管理所有IoT设备实例
- 处理设备注册和命令分发
- 提供设备描述和状态查询接口
## 命令处理流程
以下是语音命令被处理并执行IoT设备控制的完整流程
```
+-------------------+
| 用户语音指令 |
+-------------------+
|
v
+-------------------+
| 语音识别 |
| (STT) |
+-------------------+
|
v
+-------------------+
| 语义理解 |
| (LLM) |
+-------------------+
|
v
+-------------------+
| 物联网命令生成 |
+-------------------+
|
v
+------------------------------+ | +------------------------------+
| WebSocket服务端处理 | | | Application._handle_iot_message()
| <--------+-------> |
+------------------------------+ +------------------------------+
|
v
+------------------------------+
| ThingManager.invoke() |
+------------------------------+
|
+-------------------------+----------+------------+
| | |
v v v
+---------------+-------+ +------------+---------+ +---------+----------+
| Lamp | | Speaker | | MusicPlayer |
| (控制灯设备) | | (控制系统音量) | | (音乐播放器) |
+---------------+-------+ +------------+---------+ +---------+----------+
| | |
v v v
+---------------+-------+ +------------+---------+ +---------+----------+
| 执行设备相关操作 | | 执行设备相关操作 | | 执行设备相关操作 |
+---------------+-------+ +------------+---------+ +---------+----------+
| | |
+-------------------------+-----------------------+
|
v
+-----------------------------+
| 更新设备状态 |
| Application._update_iot_states()
+-----------------------------+
|
v
+-----------------------------+
| 发送状态更新到服务器 |
| send_iot_states() |
+-----------------------------+
|
v
+-----------------------------+
| 语音或界面反馈结果 |
+-----------------------------+
```
## 内置设备说明
### 1. 灯设备 (Lamp)
虚拟灯设备用于演示基本的IoT控制功能。
**属性**
- `power`:灯的开关状态(布尔值)
**方法**
- `TurnOn`:打开灯
- `TurnOff`:关闭灯
**语音命令示例**
- "打开灯"
- "关闭灯"
### 2. 系统音量控制 (Speaker)
控制系统音量的设备,可调整应用程序的音量大小。
**属性**
- `volume`当前音量值0-100
**方法**
- `SetVolume`:设置音量级别
**语音命令示例**
- "把音量调到50%"
- "音量调小一点"
- "音量调大"
### 3. 音乐播放器 (MusicPlayer)
功能丰富的在线音乐播放器,支持歌曲搜索、播放控制和歌词显示。
**属性**
- `current_song`:当前播放的歌曲
- `playing`:播放状态
- `total_duration`:歌曲总时长
- `current_position`:当前播放位置
- `progress`:播放进度
**方法**
- `Play`:播放指定歌曲
- `Pause`:暂停播放
- `GetDuration`:获取播放信息
**语音命令示例**
- "播放音乐周杰伦的稻香通过iot音乐播放器播放"
- "暂停播放"
- "播放下一首"
### 4. 倒计时器 (CountdownTimer)
一个用于延迟执行命令的倒计时器设备,可以设置定时任务。
**属性**
- 无可查询属性
**方法**
- `StartCountdown`:启动一个倒计时,结束后执行指定命令
- `command`要执行的IoT命令JSON格式字符串
- `delay`延迟时间默认为5秒
- `CancelCountdown`:取消指定的倒计时
- `timer_id`要取消的计时器ID
**语音命令示例**
- "设置5秒后打开灯"
- "10秒后把音量调到70%"
- "取消倒计时3"
### 5. 温度传感器 (TemperatureSensor)
通过MQTT协议连接的温湿度传感器设备可以实时获取环境温湿度数据。
**属性**
- `temperature`:当前温度(摄氏度)
- `humidity`:当前湿度(%
- `last_update_time`:最后更新时间(时间戳)
**方法**
- 无可调用方法设备自动通过MQTT接收数据并更新状态
**特殊功能**
- 当接收到新的温湿度数据时,会自动通过语音播报结果
**语音命令示例**
- "查询当前室内温度"
- "室内湿度是多少"
- "温湿度传感器状态"
### 6. Home Assistant设备控制 (HomeAssistantDevice)
通过HTTP API连接到Home Assistant智能家居平台控制各种智能设备。
#### 6.1 HomeAssistant灯设备 (HomeAssistantLight)
**属性**
- `state`灯的状态on/off
- `brightness`灯的亮度0-100
- `last_update`:最后更新时间戳
**方法**
- `TurnOn`:打开灯
- `TurnOff`:关闭灯
- `SetBrightness`:设置灯的亮度
- `brightness`亮度值0-100%
**语音命令示例**
- "打开客厅灯"
- "把卧室灯亮度调到60%"
- "关闭所有灯"
#### 6.2 HomeAssistant开关 (HomeAssistantSwitch)
**属性**
- `state`开关状态on/off
- `last_update`:最后更新时间戳
**方法**
- `TurnOn`:打开开关
- `TurnOff`:关闭开关
**语音命令示例**
- "打开电风扇"
- "关闭空调"
#### 6.3 HomeAssistant数值控制器 (HomeAssistantNumber)
**属性**
- `state`当前状态on/off
- `value`:当前数值
- `min_value`:最小值
- `max_value`:最大值
- `last_update`:最后更新时间戳
**方法**
- `TurnOn`:打开设备
- `TurnOff`:关闭设备
- `SetValue`:设置数值
- `value`:要设置的数值
**语音命令示例**
- "把空调温度设为26度"
- "将风扇转速调到3档"
#### 6.4 HomeAssistant按钮 (HomeAssistantButton)
**属性**
- `state`当前状态on/off通常为虚拟状态
- `last_update`:最后更新时间戳
**方法**
- `TurnOn`激活按钮执行Press操作
- `TurnOff`:形式方法,大多数情况下无实际效果
- `Press`:按下按钮,触发按钮关联的动作
**语音命令示例**
- "按下门铃按钮"
- "触发紧急模式"
- "启动场景播放"
### 7. 摄像头与视觉识别 (CameraVL)
集成摄像头控制和视觉识别功能,可以捕获画面并进行智能分析。
**功能**
- 摄像头开启/关闭
- 画面智能识别
- 视觉内容分析
**语音命令示例**
- "打开摄像头"
- "识别画面"
- "关闭摄像头"
## 扩展自定义设备
要添加新的IoT设备需要遵循以下步骤
### 1. 创建设备类
`src/iot/things/`目录下创建新的Python文件定义设备类
```python
from src.iot.thing import Thing, Parameter, ValueType
class MyCustomDevice(Thing):
"""
自定义IoT设备实现示例
此类演示了如何创建一个符合项目IoT架构的自定义设备
包括属性定义、方法注册以及实际功能实现
"""
def __init__(self):
# 调用父类初始化方法,设置设备名称和描述
# 第一个参数是设备ID(全局唯一),第二个参数是对设备的描述文本
super().__init__("MyCustomDevice", "自定义设备描述")
# 设备状态变量定义
self.status = False # 定义设备的开关状态,初始为关闭(False)
self.parameter_value = 0 # 定义设备的参数值初始为0
self.last_update_time = 0 # 记录最后一次状态更新的时间戳
# 设备初始化日志
print("[IoT设备] 自定义设备初始化完成")
# =========================
# 注册设备属性(状态值)
# =========================
# 注册status属性使其可被查询
# 参数1: 属性名称 - 在JSON中显示的键名
# 参数2: 属性描述 - 对此属性的解释说明
# 参数3: getter回调函数 - 用于实时获取属性值的lambda函数
self.add_property("status", "设备开关状态(True为开启False为关闭)",
lambda: self.status)
# 注册parameter_value属性
self.add_property("parameter_value", "设备参数值(0-100)",
lambda: self.parameter_value)
# 注册last_update_time属性
self.add_property("last_update_time", "最后一次状态更新时间",
lambda: self.last_update_time)
# =========================
# 注册设备方法(可执行的操作)
# =========================
# 注册TurnOn方法用于打开设备
# 参数1: 方法名称 - 用于API调用的标识符
# 参数2: 方法描述 - 对此方法功能的说明
# 参数3: 参数列表 - 空列表表示无参数
# 参数4: 回调函数 - 执行实际功能的lambda函数调用内部的_turn_on方法
self.add_method(
"TurnOn", # 方法名称
"打开设备", # 方法描述
[], # 无参数
lambda params: self._turn_on() # 回调函数调用内部的_turn_on方法
)
# 注册TurnOff方法用于关闭设备
self.add_method(
"TurnOff",
"关闭设备",
[],
lambda params: self._turn_off()
)
# 注册SetParameter方法用于设置参数值
# 此方法需要一个参数value
self.add_method(
"SetParameter",
"设置设备参数值(范围0-100)",
# 定义方法所需参数:
[
# 创建参数对象:
# 参数1: 参数名称 - API中的参数键名
# 参数2: 参数描述 - 对此参数的说明
# 参数3: 参数类型 - 值类型(NUMBER表示数字类型)
# 参数4: 是否必需 - True表示此参数必须提供
Parameter("value", "参数值(0-100之间的数字)", ValueType.NUMBER, True)
],
# 回调函数 - 从params字典中提取参数值并传递给_set_parameter方法
lambda params: self._set_parameter(params["value"].get_value())
)
# 注册GetStatus方法用于获取设备状态信息
self.add_method(
"GetStatus",
"获取设备完整状态信息",
[], # 无参数
lambda params: self._get_status()
)
# =========================
# 内部方法实现(实际功能)
# =========================
def _turn_on(self):
"""
打开设备的内部实现方法
返回:
dict: 包含操作状态和消息的字典
"""
self.status = True # 修改设备状态为开启
self.last_update_time = int(time.time()) # 更新状态变更时间
# 这里可以添加实际的硬件控制代码如GPIO操作、串口通信等
print(f"[IoT设备] 自定义设备已打开")
# 返回操作结果,包含状态和消息
return {
"status": "success", # 操作状态: success或error
"message": "设备已打开" # 操作结果消息
}
def _turn_off(self):
"""
关闭设备的内部实现方法
返回:
dict: 包含操作状态和消息的字典
"""
self.status = False # 修改设备状态为关闭
self.last_update_time = int(time.time()) # 更新状态变更时间
# 这里可以添加实际的硬件控制代码
print(f"[IoT设备] 自定义设备已关闭")
# 返回操作结果
return {
"status": "success",
"message": "设备已关闭"
}
def _set_parameter(self, value):
"""
设置设备参数值的内部实现方法
参数:
value (float): 要设置的参数值
返回:
dict: 包含操作状态和消息的字典
异常:
ValueError: 如果参数值超出有效范围
"""
# 参数值验证
if not isinstance(value, (int, float)):
return {"status": "error", "message": "参数必须是数字"}
if not 0 <= value <= 100:
return {"status": "error", "message": "参数值必须在0-100之间"}
# 设置参数值
self.parameter_value = value
self.last_update_time = int(time.time()) # 更新状态变更时间
# 这里可以添加实际的参数设置代码
print(f"[IoT设备] 自定义设备参数已设置为: {value}")
# 返回操作结果
return {
"status": "success",
"message": f"参数已设置为 {value}",
"value": value
}
def _get_status(self):
"""
获取设备完整状态的内部实现方法
返回:
dict: 包含设备所有状态信息的字典
"""
# 返回设备的完整状态信息
return {
"status": "success",
"device_status": {
"is_on": self.status,
"parameter": self.parameter_value,
"last_update": self.last_update_time
}
}
### 2. 注册设备
在程序启动时注册设备到ThingManager
```python
# 在Application._initialize_iot_devices方法中
from src.iot.thing_manager import ThingManager
from src.iot.things.my_custom_device import MyCustomDevice
from src.utils.logging_config import get_logger
# 获取日志记录器实例
logger = get_logger(__name__)
def _initialize_iot_devices(self):
"""
初始化并注册所有IoT设备
此方法在应用程序启动时被调用
"""
# 记录日志开始初始化IoT设备
logger.info("开始初始化IoT设备...")
# 获取设备管理器单例实例
# ThingManager使用单例模式确保全局只有一个管理器实例
thing_manager = ThingManager.get_instance()
# 创建自定义设备实例
my_device = MyCustomDevice()
# 将设备实例添加到设备管理器
# 一旦添加设备将可以通过API和语音命令访问
thing_manager.add_thing(my_device)
# 记录成功添加设备的日志
logger.info(f"已添加自定义设备: {my_device.name}")
# 可以在这里继续添加其他设备...
# 记录设备初始化完成的日志
logger.info(f"IoT设备初始化完成共注册了 {len(thing_manager.things)} 个设备")
```
### 3. 设备通信(可选)
如果设备需要与实体硬件通信,可以通过各种协议实现:
- MQTT用于与标准物联网设备通信
- HTTP用于REST API调用
- 串口/GPIO用于直接硬件控制
## 使用示例
### 基本设备控制
1. 启动应用程序
2. 使用语音指令"打开灯"
3. 系统识别指令并执行lamp.py中的TurnOn方法
4. 灯设备状态更新,反馈给用户"灯已打开"
### 音乐播放控制
1. 使用指令"播放音乐周杰伦的稻香通过iot音乐播放器播放"
2. 系统解析指令并调用MusicPlayer的Play方法
3. 播放器搜索歌曲,开始播放,并显示歌词
4. 可以继续使用"暂停播放"等命令控制播放
### 倒计时控制示例
1. 使用指令"设置5秒后打开灯"
2. 系统解析指令并调用CountdownTimer的StartCountdown方法
3. 5秒后自动执行打开灯的命令
4. 返回操作结果"倒计时已设置"
### Home Assistant设备控制示例
1. 使用指令"把客厅灯调暗一点"
2. 系统解析指令并调用HomeAssistantLight的SetBrightness方法
3. 通过HTTP API向Home Assistant发送亮度调整命令
4. 返回操作结果"客厅灯亮度已调整"
## 注意事项
1. 设备属性更新后会自动通过WebSocket推送状态到服务端和UI界面
2. 设备方法的实现应该考虑异步操作,避免阻塞主线程
3. 参数类型和格式应严格遵循ValueType中定义的类型
4. 新增设备时应确保设备ID全局唯一
5. 所有设备方法应该实现适当的错误处理和反馈机制
## 高级主题Home Assistant集成
### 通过HTTP API控制Home Assistant
Home Assistant是一个流行的开源家庭自动化平台本项目通过HTTP API与Home Assistant集成支持控制各种智能设备。以下是Home Assistant集成的关键点
1. **配置文件设置**
`config/config.json`中添加Home Assistant配置
```json
{
"HOME_ASSISTANT": {
"URL": "http://your-homeassistant-url:8123",
"TOKEN": "your-long-lived-access-token",
"DEVICES": [
{
"entity_id": "light.cuco_cn_573924446_v3_s_13_indicator_light",
"friendly_name": "米家智能插座3-冰箱 指示灯"
},
{
"entity_id": "switch.cuco_cn_573924446_v3_on_p_2_1",
"friendly_name": "米家智能插座3-冰箱 开关 开关"
}
]
}
}
```
### 配置ha地址和密钥
![Image](./images/home_assistatnt配置.png)
### 设备选择
- 左上角开关处点击可以切换设备类型
- 选中设备后天机右下角添加选中设备
- 导入后需要重启小智等待程序加载完成就可以通过语音控制了
![Image](./images/设备选择.png)
### 导入后
![Image](./images/导入ha.png)
2. **支持的设备类型**
- `light`: 灯设备,支持开关和亮度控制
- `switch`: 开关设备,支持开关控制
- `number`: 数值控制器,支持设置数值
- `button`: 按钮设备,支持按下操作
3. **语音命令示例**
- "打开客厅灯"
- "把卧室灯调暗一点"
- "将空调温度设为26度"
- "关闭所有灯"
### 通信协议限制
当前IoT协议(1.0版本)存在以下限制:
1. **单向控制流**:大模型只能下发指令,无法立即获取指令执行结果
2. **状态更新延迟**设备状态变更需要等到下一轮对话时通过读取property属性值才能获知
3. **异步反馈**:如果需要操作结果反馈,必须通过设备属性的方式间接实现
### 最佳实践
1. **使用有意义的属性名称**:属性名称应清晰表达其含义,便于大模型理解和使用
2. **不产生歧义的方法描述**:为每个方法提供明确的自然语言描述,帮助大模型更准确地理解和调用

View File

@ -0,0 +1,224 @@
# 音量控制功能
## 功能概述
本应用支持调整系统音量,根据不同操作系统需要安装不同的依赖。应用程序会在启动时自动检查这些依赖是否已安装。如果缺少依赖,将会显示相应的安装指令。
## 平台支持
系统针对不同操作系统提供了不同的音量控制实现:
1. **Windows**: 使用 pycaw 和 comtypes 控制系统音量
2. **macOS**: 使用 applescript 控制系统音量
3. **Linux**: 根据系统环境使用 pactl (PulseAudio)、amixer (ALSA) 或 alsamixer 控制音量
## 依赖安装
### Windows
```bash
pip install pycaw comtypes
```
### macOS
macOS系统需要安装applescript模块
```bash
pip install applescript
```
### Linux
根据您的音频系统安装以下依赖之一:
```bash
# PulseAudio 工具(推荐)
sudo apt-get install pulseaudio-utils
# 或者 ALSA 工具
sudo apt-get install alsa-utils
# 如果需要使用 alsamixer 方式,还需要安装 expect
sudo apt-get install alsa-utils expect
```
## 使用方法
### GUI模式
- 使用界面上的音量滑块直接调节音量
- 滑块会在移动后300毫秒更新系统音量(防抖设计)
- 可通过语音命令控制音量,如"调高音量"、"把音量调到50%"等
### CLI模式
- 使用 `v <音量值>` 命令调节音量,例如 `v 50` 将音量设置为50%
- 支持的命令:
- `v <数值>` 设置为指定音量值(0-100)
### 语音控制
通过IoT功能可以使用语音命令控制音量
- "把音量调到50%"
- "音量调小一点"
- "音量调大"
- "设置音量为80"
## 架构设计
音量控制功能采用分层设计,包括:
1. **VolumeController类** - 底层实现,负责跨平台音量操作
2. **BaseDisplay.update_volume** - 中间层,应用程序与底层控制器的桥接
3. **Speaker IoT设备** - 高级抽象,提供语音命令接口
## 内部实现
### 1. VolumeController类
VolumeController类是一个跨平台的音量控制实现支持Windows、macOS和Linux系统
```python
# src/utils/volume_controller.py
class VolumeController:
"""跨平台音量控制器"""
def __init__(self):
self.system = platform.system()
# 根据不同操作系统初始化控制器
if self.system == "Windows":
self._init_windows()
elif self.system == "Darwin": # macOS
self._init_macos()
elif self.system == "Linux":
self._init_linux()
def get_volume(self):
"""获取当前音量 (0-100)"""
# 根据不同平台实现获取音量
def set_volume(self, volume):
"""设置音量 (0-100)"""
# 根据不同平台实现设置音量
```
### 2. BaseDisplay音量控制
BaseDisplay类提供音量控制接口由CLI和GUI显示类继承
```python
# src/display/base_display.py
class BaseDisplay(ABC):
def __init__(self):
self.current_volume = 70 # 默认音量值
self.volume_controller = None
# 初始化音量控制器
try:
from src.utils.volume_controller import VolumeController
if VolumeController.check_dependencies():
self.volume_controller = VolumeController()
self.current_volume = self.volume_controller.get_volume()
except Exception as e:
# 错误处理...
def get_current_volume(self):
"""获取当前音量"""
if self.volume_controller:
try:
self.current_volume = self.volume_controller.get_volume()
except Exception:
pass
return self.current_volume
def update_volume(self, volume: int):
"""更新系统音量"""
volume = max(0, min(100, volume))
self.current_volume = volume
if self.volume_controller:
try:
self.volume_controller.set_volume(volume)
except Exception:
# 错误处理...
pass
```
### 3. Speaker IoT设备
Speaker类是一个IoT设备允许通过语音命令控制音量
```python
# src/iot/things/speaker.py
from src.application import Application
from src.iot.thing import Thing, Parameter, ValueType
class Speaker(Thing):
def __init__(self):
super().__init__("Speaker", "当前 AI 机器人的扬声器")
# 获取当前显示实例的音量作为初始值
try:
app = Application.get_instance()
self.volume = app.display.current_volume
except Exception:
# 如果获取失败,使用默认值
self.volume = 100 # 默认音量
# 定义音量属性
self.add_property("volume", "当前音量值", lambda: self.volume)
# 定义设置音量方法
self.add_method(
"SetVolume",
"设置音量",
[Parameter("volume", "0到100之间的整数", ValueType.NUMBER, True)],
lambda params: self._set_volume(params["volume"].get_value())
)
def _set_volume(self, volume):
"""设置音量的具体实现"""
if 0 <= volume <= 100:
self.volume = volume
try:
app = Application.get_instance()
app.display.update_volume(volume)
return {"success": True, "message": f"音量已设置为: {volume}"}
except Exception as e:
return {"success": False, "message": f"设置音量失败: {e}"}
else:
raise ValueError("音量必须在0-100之间")
```
### 4. 在Application中注册
音量控制设备在应用程序启动时被注册:
```python
# src/application.py (部分代码)
def _initialize_iot_devices(self):
"""初始化物联网设备"""
from src.iot.thing_manager import ThingManager
from src.iot.things.speaker import Speaker
# 获取物联网设备管理器实例
thing_manager = ThingManager.get_instance()
# 添加音量控制设备
thing_manager.add_thing(Speaker())
```
## 常见问题
1. **无法调节音量**
- 检查是否安装了对应操作系统的音量控制依赖
- Windows用户确保安装了pycaw和comtypes
- macOS用户确保安装了applescript模块
- Linux用户确保安装了对应的音频控制工具(pactl或amixer)
2. **调节音量命令无响应**
- 确保IoT模块正常运行
- 检查系统音频设备是否正常工作
- 尝试重启应用
3. **音量调节不准确**
- 可能是由于不同音频接口导致的精度问题
- 尝试使用较大幅度的调节命令
4. **GUI滑块与实际音量不同步**
- 在某些情况下,系统音量可能被其他应用程序更改
- 重新启动应用程序将重新获取当前系统音量

View File

@ -0,0 +1,97 @@
# 视觉识别功能
## 功能概述
py-xiaozhi提供了摄像头控制和视觉识别功能支持通过语音命令打开/关闭摄像头,以及对摄像头捕获的画面进行智能识别分析。
## 配置说明
视觉识别功能需要在配置文件中进行相关设置:
```json
"CAMERA": {
"camera_index": 0, // 摄像头索引0通常是电脑内置摄像头
"frame_width": 640, // 画面宽度
"frame_height": 480, // 画面高度
"fps": 30, // 帧率
"Loacl_VL_url": "https://open.bigmodel.cn/api/paas/v4/", // 智普API地址
"VLapi_key": "你的key", // 智普视觉大模型API密钥
"models": "glm-4v-plus" // 使用的视觉模型
}
```
## 智普视觉大模型配置
1. 访问 [智普AI开放平台](https://open.bigmodel.cn/)
2. 注册账号并创建API密钥
3. 将获取的API密钥配置到`config.json``CAMERA.VLapi_key`字段
4. 可以选择使用的模型,默认为`glm-4v-plus`
## 使用方法
### 语音命令控制
系统支持以下语音命令控制摄像头和视觉识别功能:
- **打开摄像头**:激活系统摄像头,开始捕获视频流
- **关闭摄像头**:停止摄像头捕获
- **识别画面**:对当前摄像头画面进行智能视觉分析,识别画面中的内容
- **分析图像**:对当前画面进行详细视觉分析并提供描述
- **看到了什么**:询问当前摄像头看到的内容
### GUI 界面控制
在图形界面模式下,可以通过界面上的相关按钮控制摄像头功能。
## 内部实现
视觉识别功能通过IoT模块中的CameraVL设备类实现主要由Camera和VL两个组件组成
1. **Camera 组件**:负责摄像头的基本控制,如开启、关闭、获取视频帧等
2. **VLVision Language组件**负责对图像进行智能分析调用智普视觉大模型API
实现结构:
```
CameraVL # 摄像头与视觉识别集成设备
├── Camera.py # 摄像头控制模块
└── VL.py # 视觉语言分析模块
```
## 工作流程
1. 用户通过语音命令打开摄像头
2. 系统激活摄像头并在界面显示视频流
3. 用户请求识别当前画面
4. 系统截取当前帧,并将图像发送给智普视觉大模型
5. 获取视觉分析结果并通过语音或文字反馈给用户
## 隐私说明
视觉识别功能会使用您的摄像头并处理画面内容,请注意:
1. 摄像头捕获的画面仅用于本地分析或发送至智普API进行分析
2. 非语音命令控制时,摄像头处于关闭状态
3. 可以在配置中修改摄像头设置或完全禁用此功能
## 常见问题
1. **摄像头无法打开**
- 确认您的设备有可用摄像头
- 检查摄像头是否被其他应用占用
- 确认已授予应用使用摄像头的权限
2. **视觉识别功能无响应**
- 检查智普API密钥是否正确配置
- 确认网络连接正常
- 检查是否超出API调用次数限制
3. **识别结果不准确**
- 尝试改善摄像头光线条件
- 确保目标对象在画面中清晰可见
- 可能需要升级智普视觉模型版本
4. **摄像头画面卡顿**
- 尝试在配置中降低分辨率或帧率
- 关闭其他占用系统资源的应用
- 更新摄像头驱动

View File

@ -0,0 +1,324 @@
# 设备激活流程 v2
## 概述
当前流程是虾哥设备认证v2版本
## 激活流程
每个设备都有一个唯一的序列号(Serial Number)和HMAC密钥(HMAC Key),用于身份验证和安全通信。新设备首次使用时需要通过以下流程进行激活:
1. 客户端启动时向服务器发送设备信息包括序列号、MAC地址和客户端ID
2. 服务器检查设备是否已激活:
- 如果已激活,客户端正常工作
- 如果未激活服务器返回包含验证码和Challenge的激活请求
3. 客户端显示验证码提示用户前往xiaozhi.me网站输入验证码
4. 客户端使用HMAC密钥对Challenge进行签名并发送给服务器验证
5. 客户端通过轮询方式等待服务器确认验证结果:
- 如果验证成功,设备激活完成
- 如果验证失败或超时,设备激活失败
### 小智 ESP32 设备激活流程图
```
┌────────────────────┐
│ 设备启动 │
└──────────┬─────────┘
┌────────────────────┐
│ 初始化各组件 │
│ 连接WiFi/网络 │
└──────────┬─────────┘
┌────────────────────┐
│ 调用CheckVersion │
│ 访问OTA服务器 │──→ POST /xiaozhi/ota/
└──────────┬─────────┘
┌────────────────────┐
│ 解析服务器响应 │
└──────────┬─────────┘
┌─────┴─────┐
↓ ↓
┌─────────┐ ┌─────────┐
│是否有新版本│ │是否需要激活│
└─────┬───┘ └─────┬───┘
│ │
┌─────▼───┐ └───┬─── 否 ──┐
│升级固件 │ ↓ ↓
└─────────┘ ┌─────────────┐ ┌─────────────┐
│是否有激活码 │ │初始化协议连接│
└──────┬──────┘ │MQTT/WebSocket│
│ └─────────────┘
┌────▼───┐
│ 是 │
└────┬───┘
┌──────────────────┐
│显示激活码给用户 │
│播放语音提示 │
└────────┬─────────┘
┌──────────────────┐
│ 开始激活流程 │
└────────┬─────────┘
┌────────────────────────────────┐
│ 检查设备序列号 │
└───────────────┬────────────────┘
┌──────┴───────┐
↓ ↓
┌─────────┐ ┌─────────┐
│ 有序列号 │ │ 无序列号 │
└─────┬────┘ └────┬────┘
│ │
┌─────────▼────────┐ │
│构造激活载荷JSON: │ │
│- serial_number │ │
│- challenge │ │
│- hmac签名 │ │
└─────────┬─────────┘ │
│ │
└──────┬───────┘
┌───────────────────────┐
│发送POST请求到激活端点 │──→ POST /xiaozhi/ota/activate
└────────────┬──────────┘
┌───────────┴───────────┐
↓ ↓ ↓
┌─────────┐ ┌─────────┐ ┌─────────┐
│状态码200 │ │状态码202 │ │其他状态码│
│激活成功 │ │超时重试 │ │激活失败 │
└────┬────┘ └────┬────┘ └────┬────┘
│ │ │
│ ┌────▼─────┐ │
│ │延迟后重试 │ │
│ │最多10次 │ │
│ └────┬─────┘ │
│ │ │
└───────────┼───────────┘
┌──────────────────┐
│设置激活状态标志位 │
└────────┬─────────┘
┌──────────────────┐
│ 继续正常运行 │
│ 连接MQTT/WS协议 │
└──────────────────┘
```
### 激活数据交互详细流程
```
┌────────────┐ ┌────────────┐ ┌────────────┐
│ │ │ │ │ │
│ 设备客户端 │ │ 服务器 │ │ 用户浏览器 │
│ │ │ │ │ │
└─────┬──────┘ └─────┬──────┘ └─────┬──────┘
│ │ │
│ 请求设备状态 (MAC, ClientID, SN) │ │
│ ────────────────────────────────> │ │
│ │ │
│ 返回激活请求 (验证码, Challenge) │ │
<──────────────────────────────── │ │
│ │ │
│ 显示验证码 │ │
│ ┌─────────────┐ │ │
│ │请前往网站输入 │ │ │
│ │验证码: 123456│ │ │
│ └─────────────┘ │ │
│ │ │
│ │ 用户访问xiaozhi.me │
│ │ <─────────────────────────────────│
│ │ │
│ │ 输入验证码 123456 │
│ │ <─────────────────────────────────│
│ │ │
│ 计算HMAC签名 │ │
│ ┌─────────────┐ │ │
│ │ HMAC(密钥, │ │ │
│ │ Challenge) │ │ │
│ └─────────────┘ │ │
│ │ │
│ 发送激活请求 (SN, Challenge, 签名) │ │
│ ────────────────────────────────> │ │
│ │ ┌───────────────┐ │
│ │ │ 等待用户输入验证码 │ │
│ │ │ 超时返回202 │ │
│ │ └───────────────┘ │
│ │ │
│ 轮询等待 (HTTP Long Polling) │ │
│ ────────────────────────────────> │ │
│ HTTP 202 (Pending) │ │
<──────────────────────────────── │ │
│ │ │
│ 继续轮询... │ │
│ ────────────────────────────────> │ │
│ │ │
│ │ 验证码验证成功 │
│ │───────────────────────────────────│
│ │ │
│ 激活成功 (HTTP 200) │ │
<──────────────────────────────── │ │
│ │ │
│ ┌─────────────┐ │ │
│ │设备激活成功! │ │ │
│ └─────────────┘ │ │
│ │ │
```
## 设备与服务器通信内容详解
### 1. 设备信息请求 (POST /xiaozhi/ota/)
**请求头**:
```
Activation-Version: 2 // 表示支持序列号激活
Device-Id: AA:BB:CC:DD:EE:FF // MAC地址
Client-Id: xxxx-xxxx-xxxx-xxxx // 设备UUID
User-Agent: BOARD_NAME/1.0.0 // 开发板名称和固件版本
Content-Type: application/json
```
**请求体** (POST时):
```json
{
"version": 2,
"flash_size": 16777216,
"psram_size": 8388608,
"minimum_free_heap_size": 7265024,
"mac_address": "你的mac地址",
"uuid": "你的client_id",
"chip_model_name": "esp32s3",
"chip_info": {
"model": 9,
"cores": 2,
"revision": 0,
"features": 20
},
"application": {
"name": "xiaozhi",
"version": "1.6.0",
"compile_time": "2025-04-16T12:00:00Z",
"idf_version": "v5.3.2"
},
"partition_table": [
{
"label": "nvs",
"type": 1,
"subtype": 2,
"address": 36864,
"size": 24576
},
{
"label": "otadata",
"type": 1,
"subtype": 0,
"address": 61440,
"size": 8192
},
{
"label": "app0",
"type": 0,
"subtype": 0,
"address": 65536,
"size": 1966080
},
{
"label": "app1",
"type": 0,
"subtype": 0,
"address": 2031616,
"size": 1966080
},
{
"label": "spiffs",
"type": 1,
"subtype": 130,
"address": 3997696,
"size": 1966080
}
],
"ota": {
"label": "app0"
},
"board": {
"type": "lc-esp32-s3",
"name": "立创ESP32-S3开发板",
"features": ["wifi", "ble", "psram", "octal_flash"],
"ip": "你的ip地址",
"mac": "你的mac地址"
}
}
```
### 2. 服务器响应
**响应体**:
```json
{
"firmware": {
"version": "1.0.1",
"url": ""
},
"activation": {
"message": "请访问xiaozhi.me输入激活码",
"code": "123456",
"challenge": "randomstring123456",
"timeout_ms": 30000
},
"mqtt": {
"endpoint": "mqtt.xiaozhi.me",
"client_id": "device123",
"username": "user123",
"password": "pass123",
"publish_topic": ""
},
"websocket": {
"url": "wss://api.tenclass.net/xiaozhi/v1/",
"token": "test-token"
}
}
```
### 3. 设备激活请求 (POST /xiaozhi/ota/activate)
**请求体**:
```json
{
"Payload": {
"algorithm": "hmac-sha256",
"serial_number": "SN-5CD8467B47FB4920",
"challenge": "dac852d6-4ac4-4650-ba1a-c2a5bf00a766",
"hmac": "ada4775e3ed93cf9c0eb9ed00444138554ba416af41283a0e5603c77681a8022"
}
}
```
### 4. 激活响应
- **成功**: 状态码 200
- **等待用户输入验证码**: 状态码 202
- **失败**: 状态码 4xx (如401表示未授权400表示请求错误)
**响应体** (失败时):
```json
{
"error": "错误原因描述"
}
```
## 安全机制
设备激活流程v2版本采用以下安全机制
1. **设备唯一标识**:每个设备有一个唯一的序列号(Serial Number)
2. **HMAC签名验证**使用HMAC-SHA256算法对Challenge进行签名确保设备身份的真实性
3. **验证码验证**:通过要求用户在网页端输入验证码,防止自动化的激活攻击
4. **轮询等待机制**使用HTTP Long Polling等待服务器验证结果适应各种网络环境

View File

@ -0,0 +1,349 @@
# 项目打包教程
## 概述
UnifyPy是一个强大的自动化解决方案能将Python项目打包成跨平台的独立可执行文件和安装程序。小智客户端已配置了相应的打包配置文件本教程将指导您如何使用UnifyPy进行打包。
## 准备工作
### 1. 安装py-xiaozhi项目依赖
首先,确保您已安装项目的所有依赖:
```bash
# Windows
pip install -r requirements.txt
# macOS
pip install -r requirements_mac.txt
# Linux
pip install -r requirements.txt
```
### 2. 克隆UnifyPy仓库
```bash
git clone https://github.com/huangjunsen0406/UnifyPy.git
```
### 3. 安装平台特定工具
#### Windows平台
- 安装[Inno Setup](https://jrsoftware.org/isdl.php)(用于创建安装程序)
- 安装后在build.json中配置Inno Setup路径或设置环境变量INNO_SETUP_PATH
#### macOS平台
- 安装create-dmg用于创建DMG镜像
```bash
brew install create-dmg
```
#### Linux平台
根据需要的打包格式,安装相应的工具:
```bash
# DEB格式(Debian/Ubuntu)
sudo apt-get install dpkg-dev
# RPM格式(Fedora/CentOS)
sudo dnf install rpm-build
# AppImage格式(通用Linux)
wget -c https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage
chmod a+x appimagetool-x86_64.AppImage
sudo mv appimagetool-x86_64.AppImage /usr/local/bin/appimagetool
```
## 打包配置详解
小智客户端已经提供了预配置的`build.json`文件,以下是各配置项的详细说明:
### 基本配置
```json
{
"name": "xiaozhi", // 应用程序名称,将用于可执行文件和安装程序名称
"version": "1.0.0", // 应用程序版本号
"publisher": "Junsen", // 发布者名称
"entry": "main.py", // 程序入口文件
"icon": "assets/xiaozhi_icon.ico", // 应用图标路径
"hooks": "hooks", // PyInstaller钩子目录
"onefile": false, // 是否生成单文件模式的可执行文件
// PyInstaller通用参数适用于所有平台
"additional_pyinstaller_args": "--add-data assets;assets --add-data libs;libs --add-data src;src --add-data models;models --hidden-import=PyQt5",
// Inno Setup路径Windows平台需要
"inno_setup_path": "E:\\application\\Inno Setup 6\\ISCC.exe",
// 其他配置...
}
```
> **注意**JSON文件不支持注释上述代码中的注释仅用于说明实际配置文件中不应包含注释。
### 平台特定配置
#### Windows平台配置
```json
"windows": {
"format": "exe", // 输出格式
"additional_pyinstaller_args": "--add-data assets;assets --add-data libs;libs --add-data src;src --add-data models;models --hidden-import=PyQt5 --noconsole",
"desktop_entry": true, // 是否创建桌面快捷方式
"installer_options": {
"languages": ["ChineseSimplified", "English"], // 安装程序支持的语言
"license_file": "LICENSE", // 许可证文件
"readme_file": "README.md", // 自述文件
"create_desktop_icon": true, // 是否创建桌面图标
"allow_run_after_install": true // 安装后是否允许立即运行
}
}
```
#### Linux平台配置
```json
"linux": {
"format": "deb", // 输出格式可选值deb, rpm, appimage
"desktop_entry": true, // 是否创建桌面快捷方式
"categories": "Utility;Development;", // 应用程序类别
"description": "小智Ai客户端", // 应用描述
"requires": "libc6,libgtk-3-0,libx11-6,libopenblas-dev", // 依赖项
"additional_pyinstaller_args": "--add-data assets:assets --add-data libs:libs --add-data src:src --add-data models:models --hidden-import=PyQt5"
}
```
#### macOS平台配置
```json
"macos": {
"format": "app", // 输出格式可选值app, dmg
"additional_pyinstaller_args": "--add-data assets:assets --add-data libs:libs --add-data src:src --add-data models:models --hidden-import=PyQt5 --windowed",
"app_bundle_name": "XiaoZhi.app", // 应用包名称
"bundle_identifier": "com.junsen.xiaozhi", // 应用标识符
"sign_bundle": false, // 是否签名应用包
"create_dmg": true, // 是否创建DMG镜像
"installer_options": {
"license_file": "LICENSE", // 许可证文件
"readme_file": "README.md" // 自述文件
}
}
```
### 其他重要配置项
```json
"build_installer": true // 是否构建安装程序设为false只生成可执行文件
```
### 自定义安装程序模板
当打包Windows安装程序时UnifyPy使用`setup.iss.template`文件作为Inno Setup的脚本模板。需要注意的是模板中的AppId需要更换为自己的唯一标识符
```
[Setup]
; 应用程序信息
AppId={{05DBB87C-AE34-4F2F-AEC5-3CD2AFE9DC90}} ; 需要替换为你自己生成的GUID
```
> **重要**请勿直接使用示例中的AppId这可能导致与其他应用程序冲突。您可以使用在线GUID生成工具如[Online GUID Generator](https://www.guidgenerator.com/))来生成自己的唯一标识符。
## 执行打包
### 基本打包命令
- 建议UnifyPy放在和py-xiaozhi项目同级目录下, 直接 `python ../UnifyPy/main.py. --config build.json` 即可
```bash
# 导航到UnifyPy目录
cd 到当前py-xiaozhi项目目录下
# 执行打包命令
# UnifyPy_路径/main.py 是UnifyPy的项目路径
# . 表示当前项目目录
# --config build.json 表示使用当前目录下的build.json配置文件
python UnifyPy_路径/main.py . --config build.json
```
### 针对不同平台的打包命令
#### Windows平台
```bash
python C:\路径\到\UnifyPy\main.py . --config build.json
```
#### macOS平台
```bash
python /路径/到/UnifyPy/main.py . --config build.json
```
#### Linux平台
Linux平台下打包有两种主要格式DEB和AppImage。根据需要选择其中一种格式。
##### DEB格式打包适用于Debian/Ubuntu系统
1. **准备环境**
```bash
# 更新系统并安装必要的依赖
sudo apt update
sudo apt install -y build-essential python3-dev python3-pip python3-setuptools libopenblas-dev liblapack-dev gfortran patchelf autoconf automake libtool cmake libssl-dev libatlas-base-dev
```
2. **执行打包**
确保build.json中linux.format设置为"deb",然后执行:
```bash
python3 /路径/到/UnifyPy/main.py . --config build.json
```
##### AppImage格式打包适用于通用Linux系统
AppImage格式需要特别注意NumPy库的编译以下是完整步骤
1. **升级pip和基本构建工具**
```bash
python -m pip install --upgrade pip setuptools wheel
```
2. **安装必要的系统依赖**
```bash
sudo apt update
sudo apt install -y build-essential python3-dev python3-pip python3-setuptools libopenblas-dev liblapack-dev gfortran patchelf autoconf automake libtool cmake libssl-dev libatlas-base-dev
```
3. **安装Meson和Ninja构建系统**
```bash
pip install meson ninja
sudo apt install -y meson ninja-build
```
4. **准备NumPy编译环境**
```bash
# 卸载现有NumPy
pip uninstall numpy -y
# 设置环境变量
export BLAS=openblas
export LAPACK=openblas
export NPY_NUM_BUILD_JOBS=$(nproc) # 使用所有CPU核心加速编译
# 从源码编译安装NumPy
pip install numpy==1.26.4 --no-binary :all:
```
5. **执行打包**
确保build.json中linux.format设置为"appimage",然后执行:
```bash
python3 /路径/到/UnifyPy/main.py . --config build.json
```
## 打包输出
成功打包后,将在项目根目录下的`dist`文件夹中找到打包的应用程序:
- **Windows**:
- 可执行文件(.exe)位于`dist/xiaozhi`目录
- 安装程序位于`dist/installer`目录,命名为`xiaozhi-1.0.0-setup.exe`
- **macOS**:
- 应用程序包(.app)位于`dist/xiaozhi`目录
- 磁盘镜像(.dmg)位于`dist/installer`目录,命名为`xiaozhi-1.0.0.dmg`
- **Linux**:
- 可执行文件位于`dist/xiaozhi`目录
- 安装包位于`dist/installer`目录:
- DEB格式`xiaozhi-1.0.0.deb`
- RPM格式`xiaozhi-1.0.0.rpm`
- AppImage格式`xiaozhi-1.0.0.AppImage`
## 高级配置选项
### PyInstaller参数
`additional_pyinstaller_args`字段中您可以添加任何PyInstaller支持的参数。以下是一些常用参数
- `--noconsole`: 不显示控制台窗口(仅适用于图形界面程序)
- `--windowed`: 等同于`--noconsole`
- `--hidden-import=MODULE`: 添加隐式导入的模块
- `--add-data SRC;DEST`: 添加数据文件Windows平台使用分号分隔
- `--add-data SRC:DEST`: 添加数据文件macOS/Linux平台使用冒号分隔
- `--icon=FILE.ico`: 设置应用程序图标
### 处理特殊依赖
某些Python库可能需要特殊处理才能正确打包可以通过以下方式解决
1. **使用钩子文件**:在`hooks`目录中创建自定义钩子,处理特殊导入情况
2. **添加隐式导入**:使用`--hidden-import`参数显式包含隐式导入的模块
3. **添加数据文件**:使用`--add-data`参数包含程序运行所需的数据文件
## 常见问题及解决方案
### Windows平台常见问题
1. **找不到Inno Setup**
解决方案确保已安装Inno Setup并在build.json中正确配置路径或设置环境变量INNO_SETUP_PATH
2. **缺少隐式导入的模块**
解决方案:在`additional_pyinstaller_args`中添加`--hidden-import=模块名称`
3. **打包后无法找到资源文件**
解决方案:确保使用相对路径访问资源文件,并使用`--add-data`参数正确包含资源文件
### macOS平台常见问题
1. **创建DMG出错**
解决方案确保已安装create-dmg工具并有正确的权限
2. **签名问题**
解决方案:如果需要签名,在配置文件中启用`sign_bundle`并提供有效的开发者身份
3. **动态库加载问题**
解决方案:确保代码中正确处理库路径,特别是使用`sys._MEIPASS`路径
### Linux平台常见问题
1. **缺少依赖库**
解决方案在Linux配置中的`requires`字段中添加所需的系统依赖
2. **打包工具不可用**
解决方案:确保已安装相应格式的打包工具(dpkg-dev, rpmbuild, appimagetool)
3. **权限问题**
解决方案:确保脚本有正确的执行权限,对某些资源目录可能需要特别处理
4. **NumPy编译失败**
解决方案确保已安装所有必要的开发库特别是OpenBLAS、LAPACK和Fortran编译器
5. **找不到appimagetool**
解决方案确保已正确安装并设置appimagetool的可执行权限
## 最佳实践
1. **清理项目**:打包前移除临时文件、缓存和不必要的大型文件
2. **测试依赖**:确保所有依赖都正确安装并可以导入
3. **确认文件路径**:检查代码中的文件路径是否使用相对路径或资源路径
4. **验证配置**确保build.json中的配置与您的环境一致
5. **多平台测试**:如果条件允许,在多个平台上测试打包的应用程序
6. **保存配置**:为不同的打包场景保存不同版本的配置文件,方便复用
7. **版本管理**:每次发布前更新版本号,保持版本一致性

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

View File

@ -0,0 +1,421 @@
---
title: 旧版使用文档
description: py-xiaozhi项目的旧版使用文档提供早期版本的使用指南
outline: deep
---
# py-xiaozhi使用文档请认真阅读使用文档
![Image](https://github.com/user-attachments/assets/df8bd5d2-a8e6-4203-8084-46789fc8e9ad)
## 使用介绍
- 语音模式分为两种长按对话和自动对话,右下角按钮显示的是当前模式
- 长按对话:按住说话松手发送
- 自动对话:点击开始对话即可,当界面显示聆听中就表示到你说话了,说完会自行发送
- gui模式
- F2 键:长按说话
- F3 键:打断对话
- cli模式
- F2 键:按一次开始自动对话
- F3 键:打断对话
## 配置说明
### 项目基础配置
#### 配置文件说明
项目使用两种配置方式:初始配置模板和运行时配置文件。
1. **初始配置模板**
- 位置:`/src/utils/config_manager.py`
- 作用:提供默认配置模板,首次运行时会自动生成配置文件
- 使用场景:首次运行或需要重置配置时修改此文件
2. **运行时配置文件**
- 位置:`/config/config.json`
- 作用:存储实际运行时的配置信息
- 使用场景:日常使用时修改此文件
#### 配置项说明
- 需要什么加什么配置通过config_manager去获取就行了参考websocket或iot\things\temperature_sensor.py
- 例如获取 "MQTT_INFO"的"endpoint" , 通过这样 `config.get_config("MQTT_INFO.endpoint")`就能拿到**endpoint**
```json
{
"CLIENT_ID": "自动生成的客户端ID",
"DEVICE_ID": "设备MAC地址",
"NETWORK": {
"OTA_VERSION_URL": "OTA更新地址",
"WEBSOCKET_URL": "WebSocket服务器地址",
"WEBSOCKET_ACCESS_TOKEN": "访问令牌"
},
"MQTT_INFO": {
"endpoint": "MQTT服务器地址",
"client_id": "MQTT客户端ID",
"username": "MQTT用户名",
"password": "MQTT密码",
"publish_topic": "发布主题",
"subscribe_topic": "订阅主题"
},
"USE_WAKE_WORD": false, // 是否启用语音唤醒
"WAKE_WORDS": [ // 唤醒词列表
"小智",
"你好小明"
],
"WAKE_WORD_MODEL_PATH": "./models/vosk-model-small-cn-0.22", // 唤醒模型路径
"TEMPERATURE_SENSOR_MQTT_INFO": {
"endpoint": "你的Mqtt地址",
"port": 1883,
"username": "admin",
"password": "dtwin@123",
"publish_topic": "sensors/temperature/command",
"subscribe_topic": "sensors/temperature/device_001/state"
},
"CAMERA": { // 视觉配置
"camera_index": 0,
"frame_width": 640,
"frame_height": 480,
"fps": 30,
"Loacl_VL_url": "https://open.bigmodel.cn/api/paas/v4/", // 智普的申请地址 https://open.bigmodel.cn/
"VLapi_key": "你的key"
}
// ...可以添加任意配置
}
```
#### 配置修改指南
1. **首次使用配置**
- 直接运行程序,系统会自动生成默认配置文件
- 如需修改默认值,可编辑 `config_manager.py` 中的 `DEFAULT_CONFIG`
2. **更换服务器配置**
- 打开 `/config/config.json`
- 修改 `NETWORK.WEBSOCKET_URL` 为新的服务器地址
- 示例:
```json
"NETWORK": {
"WEBSOCKET_URL": "ws://你的服务器地址:端口号/"
}
```
3. **启用语音唤醒**
- 修改 `USE_WAKE_WORD``true`
- 可在 `WAKE_WORDS` 数组中添加或修改唤醒词
#### 注意事项
- 修改配置文件后需要重启程序才能生效
- WebSocket URL 必须以 `ws://``wss://` 开头
- 首次运行时会自动生成 CLIENT_ID建议不要手动修改
- DEVICE_ID 默认使用设备MAC地址可按需修改
- 配置文件使用 UTF-8 编码,请使用支持 UTF-8 的编辑器修改
## 启动说明
### 系统依赖安装
#### Windows
1. **安装 FFmpeg**
```bash
# 方法一:使用 Scoop 安装(推荐)
scoop install ffmpeg
# 方法二:手动安装
# 1. 访问 https://github.com/BtbN/FFmpeg-Builds/releases 下载
# 2. 解压并将 bin 目录添加到系统 PATH
```
2. **Opus 音频编解码库**
- 项目默认会自动引入 opus.dll无需手动安装
- 如遇问题,可将 `/libs/windows/opus.dll` 复制到以下位置之一:
- 应用程序目录
- `C:\Windows\System32`
#### Linux (Debian/Ubuntu)
```bash
# 安装系统依赖
sudo apt-get update
sudo apt-get install python3-pyaudio portaudio19-dev ffmpeg libopus0 libopus-dev
# 安装音量控制依赖(以下三选一)
# 1. PulseAudio 工具(推荐)
sudo apt-get install pulseaudio-utils
# 2. 或者 ALSA 工具
sudo apt-get install alsa-utils
# 3. 如果需要使用 alsamixer 方式,还需要安装 expect
sudo apt-get install alsa-utils expect
sudo apt install build-essential python3-dev
```
#### macOS
```bash
# 使用 Homebrew 安装系统依赖
brew install portaudio opus python-tk ffmpeg gfortran
brew upgrade tcl-tk
```
### Python 依赖安装
#### 方式一:使用 venv推荐
```bash
# 1. 创建虚拟环境
python -m venv .venv
# 2. 激活虚拟环境
# Windows
.venv\Scripts\activate
# Linux/macOS
source .venv/bin/activate
# 3. 安装依赖
# Windows/Linux
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# macOS
pip install -r requirements_mac.txt -i https://mirrors.aliyun.com/pypi/simple
```
#### 方式二:使用 Conda
```bash
# 1. 创建 Conda 环境
conda create -n py-xiaozhi python=3.12
# 2. 激活环境
conda activate py-xiaozhi
# 3. 安装 Conda 特定依赖
conda install conda-forge::libopus
conda install conda-forge::ffmpeg
# 4. 安装 Python 依赖
# Windows/Linux
pip install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
# macOS
pip install -r requirements_mac.txt -i https://mirrors.aliyun.com/pypi/simple
```
### 唤醒词模型
- [唤醒词模型下载](https://alphacephei.com/vosk/models)
- 下载完成后解压放至根目录/models
- 默认读取vosk-model-small-cn-0.22小模型
- ![Image](../images/唤醒词.png)
### IoT功能说明
#### IoT模块结构
```
├── iot # IoT设备相关模块
│ ├── things # 具体设备实现目录
│ │ ├── lamp.py # 智能灯控制实现
│ │ │ └── Lamp # 灯设备类,提供开关、调节亮度、改变颜色等功能
│ │ ├── music_player.py # 音乐播放器实现
│ │ │ └── MusicPlayer # 音乐播放器类,提供播放、暂停、切换歌曲等功能
│ │ └── speaker.py # 音量控制实现
│ │ └── Speaker # 扬声器类,提供音量调节、静音等功能
│ ├── thing.py # IoT设备基类定义
│ │ ├── Thing # 所有IoT设备的抽象基类
│ │ ├── Property # 设备属性类,定义设备的可变状态
│ │ ├── Action # 设备动作类,定义设备可执行的操作
│ │ └── Event # 设备事件类,定义设备可触发的事件
│ └── thing_manager.py # IoT设备管理器统一管理各类设备
│ └── ThingManager # 单例模式实现的设备管理器,负责设备注册、查找和命令分发
```
#### Iot 状态流转
```text
+----------------+
| 用户语音 |
| 指令 |
+-------+-------+
|
v
+-------+-------+
| 语音识别 |
| (STT) |
+-------+-------+
|
v
+-------+-------+
| LLM处理指令 |
| |
+-------+-------+
|
v
+-------+-------+
| 生成物联网命令 |
| |
+-------+-------+
|
v
+---------------+---------------+
| Application接收IoT消息 |
| _handle_iot_message() |
+---------------+---------------+
|
v
+---------------+---------------+
| ThingManager.invoke() |
+---------------+---------------+
|
+------------------+------------------+------------------+
| | | |
v v v v
+----------+-------+ +-------+--------+ +------+---------+ +----+-----------+
| Lamp | | Speaker | | MusicPlayer | | CameraVL |
| (控制灯设备) | | (控制音量设备) | | (播放音乐设备) | | (摄像头与视觉) |
+----------+-------+ +-------+--------+ +------+---------+ +----+-----------+
| | | |
| | | |
| | | |
| | | v
| | | +------+---------+
| | | | Camera.py |
| | | | (摄像头控制) |
| | | +------+---------+
| | | |
| | | v
| | | +------+---------+
| | | | VL.py |
| | | | (视觉识别处理) |
| | | +------+---------+
| | | |
+------------------+------------------+------------------+
|
v
+---------------+---------------+
| 执行设备操作 |
+---------------+---------------+
|
v
+---------------+---------------+
| 更新设备状态 |
| _update_iot_states() |
+---------------+---------------+
|
v
+---------------+---------------+
| 发送状态更新到服务器 |
| send_iot_states(states) |
+---------------+---------------+
|
v
+---------------+---------------+
| 服务器更新设备状态 |
+---------------+---------------+
|
v
+---------------+---------------+
| 返回执行结果给用户 |
| (语音或界面反馈) |
+-------------------------------+
```
#### IoT设备管理
- IoT模块采用灵活的多协议通信架构
- MQTT协议用于与标准物联网设备通信如智能灯、空调等
- HTTP协议用于与Web服务交互如获取在线音乐、调用多模态AI模型等
- 可扩展支持其他协议如WebSocket、TCP等
- 支持自动发现和管理IoT设备
- 可通过语音命令控制IoT设备例如
- "查看当前物联网设备"
- "打开客厅的灯"
- "关闭空调"
- "设置温度为26度"
- "打开摄像头"
- "关闭摄像头"
- "识别画面"
#### 添加新的IoT设备
1. 在`src/iot/things`目录下创建新的设备类
2. 继承`Thing`基类并实现必要方法
3. 在`thing_manager.py`中注册新设备
### 注意事项
1. 确保相应的服务器配置正确且可访问:
- MQTT服务器配置用于物联网设备
- API接口地址用于HTTP服务
2. 不同协议的设备/服务需实现对应的连接和通信逻辑
3. 建议为每个新增设备/服务添加基本的错误处理和重连机制
4. 可以通过扩展Thing基类来支持新的通信协议
5. 在添加新设备时,建议先进行通信测试,确保连接稳定
#### 在线音乐配置
- 接入在线音源了,无需自行配置默认可用
### 运行模式说明
#### GUI 模式运行(默认)
```bash
python main.py
```
#### CLI模式运行
```bash
python main.py --mode cli
```
#### 构建打包
使用PyInstaller打包为可执行文件
```bash
# Windows
python scripts/build.py
# macOS
python scripts/build.py
# Linux
python scripts/build.py
```
### 注意事项
1. 建议使用 Python 3.9.13+ 版本,推荐 3.12
2. Windows 用户无需手动安装 opus.dll项目会自动处理
3. 使用 Conda 环境时必须安装 ffmpeg 和 Opus
4. 使用 Conda 环境时请勿和esp32-server共用同一个Conda环境因为服务端websocket依赖版本高于本项目
5. 建议使用国内镜像源安装依赖,可以提高下载速度
6. macOS 用户需使用专门的 requirements_mac.txt
7. 确保系统依赖安装完成后再安装 Python 依赖
8. 如若使用xiaozhi-esp32-server作为服务端该项目只能自动对话才有反应
9. esp32-server视频部署教程 [新版小智ai服务端本地部署完整教程支持DeepSeek接入](https://www.bilibili.com/video/BV1GvQWYZEd2/?share_source=copy_web&vd_source=86370b0cff2da3ab6e3d26eb1cab13d3)
10. 音量控制功能需要安装特定依赖,程序会在启动时自动检查并提示缺少的依赖
### 音量控制功能说明
本应用支持调整系统音量,根据不同操作系统需要安装不同的依赖:
1. **Windows**: 使用 pycaw 和 comtypes 控制系统音量
2. **macOS**: 使用 applescript 控制系统音量
3. **Linux**: 根据系统环境使用 pactl (PulseAudio)、wpctl (PipeWire)、amixer (ALSA) 或 alsamixer 控制音量
应用程序会在启动时自动检查这些依赖是否已安装。如果缺少依赖,将会显示相应的安装指令。
#### 音量控制使用方法
- **GUI模式**: 使用界面上的音量滑块调节音量
- **CLI模式**: 使用 `v <音量值>` 命令调节音量,例如 `v 50` 将音量设置为50%
### 状态流转图
```
+----------------+
| |
v |
+------+ 唤醒词/按钮 +------------+ | +------------+
| IDLE | -----------> | CONNECTING | --+-> | LISTENING |
+------+ +------------+ +------------+
^ |
| | 语音识别完成
| +------------+ v
+--------- | SPEAKING | <-----------------+
完成播放 +------------+
```
## 获取帮助
如果遇到问题:
1. 优先查看 docs/异常汇总.md 文档
2. 通过 GitHub Issues 提交问题
3. 通过 AI 助手寻求帮助
4. 联系作者(主页有微信)(请自备 Todesk 链接并说明来意,作者工作日晚上处理)

View File

@ -0,0 +1,331 @@
# 错误问题汇总
## 1. `Could not find Opus library. Make sure it is installed.`
### **错误描述**
```
(.venv) C:\Users\Junsen\Desktop\learning\xiaozhi-python>python xiaozhi-python.py
Traceback (most recent call last):
File "C:\Users\Junsen\Desktop\learning\xiaozhi-python\xiaozhi-python.py", line 5, in <module>
import opuslib
File "C:\Users\Junsen\Desktop\learning\xiaozhi-python\.venv\lib\site-packages\opuslib\__init__.py", line 19, in <module>
from .exceptions import OpusError # NOQA
File "C:\Users\Junsen\Desktop\learning\xiaozhi-python\.venv\lib\site-packages\opuslib\exceptions.py", line 10, in <module>
import opuslib.api.info
File "C:\Users\Junsen\Desktop\learning\xiaozhi-python\.venv\lib\site-packages\opuslib\api\__init__.py", line 20, in <module>
raise Exception(
Exception: Could not find Opus library. Make sure it is installed.
```
### **解决方案**
1. **Windows**
- 下载并安装 Opus 库。
- 确保 `opuslib` 相关库正确安装。
2. **Linux/macOS**
- 运行以下命令安装 `libopus`:
```sh
sudo apt-get install libopus-dev # Ubuntu/Debian
brew install opus # macOS
```
3. **Python 代码安装**
```sh
pip install opuslib
```
---
## 2. `externally-managed-environment` (macOS)
### **错误描述**
```
(.venv) huangjunsen@huangjunsendeMac-mini py-xiaozhi % pip install -r requirements_mac.txt -i https://pypi.tuna.tsinghua.edu.cn/simple
error: externally-managed-environment
× This environment is externally managed
╰─> To install Python packages system-wide, try brew install
xyz, where xyz is the package you are trying to
install.
If you wish to install a Python library that isn't in Homebrew,
use a virtual environment:
python3 -m venv path/to/venv
source path/to/venv/bin/activate
python3 -m pip install xyz
If you wish to install a Python application that isn't in Homebrew,
it may be easiest to use 'pipx install xyz', which will manage a
virtual environment for you. You can install pipx with
brew install pipx
You may restore the old behavior of pip by passing
the '--break-system-packages' flag to pip, or by adding
'break-system-packages = true' to your pip.conf file. The latter
will permanently disable this error.
If you disable this error, we STRONGLY recommend that you additionally
pass the '--user' flag to pip, or set 'user = true' in your pip.conf
file. Failure to do this can result in a broken Homebrew installation.
Read more about this behavior here: <https://peps.python.org/pep-0668/>
note: If you believe this is a mistake, please contact your Python installation or OS distribution provider. You can override this, at the risk of breaking your Python installation or OS, by passing --break-system-packages.
hint: See PEP 668 for the detailed specification.
```
### **解决方案**
1. **使用虚拟环境安装**
```sh
python3 -m venv my_env
source my_env/bin/activate
pip install -r requirements.txt
```
2. **使用 **``** 进行全局安装**
```sh
brew install pipx
pipx install package_name
```
3. **强制安装(不推荐)**
```sh
pip install package_name --break-system-packages
```
---
## 3. `WebSocket连接失败: BaseEventLoop.create_connection() got an unexpected keyword argument 'extra_headers'`
### **错误描述**
```python
# 建立WebSocket连接
self.websocket = await websockets.connect(
self.WEBSOCKET_URL,
extra_headers=headers # 高版本这里改为 additional_headers=headers
)
```
### **解决方案**
- **新版本 **``: `extra_headers` 改为 `additional_headers`。
- **旧版本 **``: `additional_headers` 改为 `extra_headers`。
---
## 4. `没有找到默认的输入/输出音频设备`
### **错误描述**
```
AudioCodec - ERROR - 初始化音频设备失败: [Errno -9996] Invalid input device (no default output device)
AudioCodec - WARNING - 无法初始化音频设备: [Errno -9996] Invalid input device (no default output device)
```
### **解决方案**
1. **Windows**:
- 在 **声音设置** 中启用麦克风和扬声器。
2. **Linux/macOS**:
```sh
pactl list sources | grep "Name"
```
3. **检查可用音频设备**:
```python
import pyaudio
p = pyaudio.PyAudio()
for i in range(p.get_device_count()):
print(f"设备 {i}: {p.get_device_info_by_index(i)['name']}")
```
4. **手动指定音频设备**:
```python
stream = p.open(format=pyaudio.paInt16, channels=1, rate=16000, input=True, input_device_index=0)
```
---
## **5. `ModuleNotFoundError: No module named '_tkinter'` mac m4以下常见 **
### **错误描述**
```
(.venv) apple@appledeMac-mini py-xiaozhi % python main.py
Traceback (most recent call last):
File "/Users/apple/Desktop/py-xiaozhi/main.py", line 5, in <module>
from src.application import Application
File "/Users/apple/Desktop/py-xiaozhi/src/application.py", line 23, in <module>
from src.display import gui_display, cli_display
File "/Users/apple/Desktop/py-xiaozhi/src/display/gui_display.py", line 2, in <module>
import tkinter as tk
File "/opt/homebrew/Cellar/python@3.12/3.12.9/Frameworks/Python.framework/Versions/3.12/lib/python3.12/tkinter/__init__.py", line 38, in <module>
import _tkinter # If this fails your Python may not be configured for Tk
^^^^^^^^^^^^^^^
ModuleNotFoundError: No module named '_tkinter'
```
### **解决方案**
1. **安装 `tcl-tk`**
```sh
brew upgrade tcl-tk # 一般第一步就可以了
```
2. **检查 Homebrew 的 `tcl-tk` 路径**
```sh
brew info tcl-tk
```
3. **重新安装 Python并链接 `tcl-tk`**
```sh
brew install python-tk
```
4. **手动指定 `Tcl/Tk` 路径(如有必要)**
```sh
export PATH="/opt/homebrew/opt/tcl-tk/bin:$PATH"
export LDFLAGS="-L/opt/homebrew/opt/tcl-tk/lib"
export CPPFLAGS="-I/opt/homebrew/opt/tcl-tk/include"
```
5. **重新创建虚拟环境**
```sh
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
```
---
## 6. `导入 opuslib 失败: No module named 'pyaudioop'或'_cffi_backend'`
### **错误描述**
```
找到opus库文件: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows\opus.dll
已添加DLL搜索路径: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows
已成功加载 opus.dll: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows\opus.dll
导入 opuslib 失败: No module named 'pyaudioop'
确保 opus 动态库已正确安装或位于正确的位置
```
```
找到opus库文件: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows\opus.dll
已添加DLL搜索路径: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows
已成功加载 opus.dll: D:\xiaozhi\PC\py-xiaozhi-main\libs\windows\opus.dll
导入 opuslib 失败: No module named '_cffi_backend'
请确保 opus 动态库已正确安装或位于正确的位置
```
### **解决方案**
1. **Python版本兼容性问题**
- 这个错误通常与Python版本有关尤其是Python 3.13版本
- 建议使用Python 3.9-3.12版本
2. **重新安装cffi**
```sh
pip uninstall cffi
pip install cffi
```
3. **opus.dll放置**
- 确保已将opus.dll放在正确位置项目根目录和System32目录
```sh
# 检查是否已复制到这些位置
C:\Windows\System32\opus.dll
项目根目录\opus.dll
项目根目录\libs\windows\opus.dll
```
4. **安装pyaudioop支持库**
- 对于'pyaudioop'错误尝试降级Python版本或安装相关依赖
```sh
pip install pyaudio
```
---
## 8. `error: subprocess-exited-with-error`(安装 `numpy` 失败)
### **错误描述**
```
Collecting numpy==2.0.2 (from -r requirements.txt (line 8))
Using cached https://mirrors.aliyun.com/pypi/packages/a9/75/10dd1f8116a8b796cb2c737b674e02d02e80454bda953fa7e65d8c12b016/numpy-2.0.2.tar.gz (18.9 MB)
Installing build dependencies ... done
Getting requirements to build wheel ... done
Installing backend dependencies ... done
Preparing metadata (pyproject.toml) ... error
error: subprocess-exited-with-error
× Preparing metadata (pyproject.toml) did not run successfully.
│ exit code: 1
╰─> [21 lines of output]
...
WARNING: Failed to activate VS environment: Could not parse vswhere.exe output
ERROR: Unknown compiler(s): [['icl'], ['cl'], ['cc'], ['gcc'], ['clang'], ['clang-cl'], ['pgcc']]
The following exception(s) were encountered:
Running `icl ""` gave "[WinError 2] 系统找不到指定的文件。"
Running `cl /?` gave "[WinError 2] 系统找不到指定的文件。"
Running `cc --version` gave "[WinError 2] 系统找不到指定的文件。"
Running `gcc --version` gave "[WinError 2] 系统找不到指定的文件。"
Running `clang --version` gave "[WinError 2] 系统找不到指定的文件。"
Running `clang-cl /?` gave "[WinError 2] 系统找不到指定的文件。"
Running `pgcc --version` gave "[WinError 2] 系统找不到指定的文件。"
note: This error originates from a subprocess, and is likely not a problem with pip.
error: metadata-generation-failed
× Encountered error while generating package metadata.
╰─> See above for output.
note: This is an issue with the package mentioned above, not pip.
hint: See above for details.
```
### **解决方案**
- 建议python版本在 3.9 - 3.12
1. **确保 `numpy` 版本兼容**
`numpy==2.0.2` 可能存在构建问题,建议尝试安装较稳定的版本:
```sh
pip install numpy==1.24.3
```
如果你不需要特定版本,可以安装最新稳定版本:
```sh
pip install numpy
```
2. **安装编译工具**
Windows用户可能需要安装Visual C++ Build Tools
```sh
# 安装Microsoft C++ Build Tools
# 下载并安装: https://visualstudio.microsoft.com/visual-cpp-build-tools/
```
3. **使用预编译的轮子**
```sh
pip install --only-binary=numpy numpy
```

Some files were not shown because too many files have changed in this diff Show More