fix(Git): 提交 README.md

This commit is contained in:
liubing1 2025-01-21 16:51:51 +08:00
parent 5db2d81f4d
commit 3e51867523
3 changed files with 100 additions and 35 deletions

103
README.md
View File

@ -1,28 +1,89 @@
# ollama-voice-mac # x-Ollama-Voice-Mac
A completely offline voice assistant using Mistral 7b via Ollama and Whisper speech recognition models. This builds on the [excellent work of maudoin](https://github.com/maudoin/ollama-voice) by adding Mac compatibility with various improvements. 一款完全离线运行的语音助手,集成了 Whisper、Ollama 和 pyttsx3 模型支持离线语音识别、自然语言处理及文本转语音TTS功能。
结合 **Mistral 7b**(通过 Ollama 实现)和 **Whisper** 语音识别模型构建而成。此项目基于 [maudoin 的优秀工作](https://github.com/apeatling/ollama-voice-mac),添加了对 Mac 的兼容性并进行了一系列改进。
https://github.com/apeatling/ollama-voice-mac/assets/1464705/996abeb7-7e99-451b-8d3b-feb3fecbb82e https://github.com/apeatling/ollama-voice-mac/assets/1464705/996abeb7-7e99-451b-8d3b-feb3fecbb82e
## Installing and running ---
1. Install [Ollama](https://ollama.ai) on your Mac. ## 安装与运行
2. Download the Mistral 7b model using the `ollama pull mistral` command. ### 0. 在mac上安装python的虚拟环境
3. Download an [OpenAI Whisper Model](https://github.com/openai/whisper/discussions/63#discussioncomment-3798552) (base.en works fine). python3.11 -m venv myenv_311
4. Clone this repo somewhere. source myenv_311/bin/activate
5. Place the Whisper model in a /whisper directory in the repo root folder. deactivate
6. Make sure you have [Python](https://www.python.org/downloads/macos/) and [Pip](https://pip.pypa.io/en/stable/installation/) installed.
7. For Apple silicon support of the PyAudio library you'll need to install [Homebrew](https://brew.sh) and run `brew install portaudio`.
8. Run `pip install -r requirements.txt` to install.
9. Run `python assistant.py` to start the assistant.
## Improving the voice ### 1. 安装 Ollama
在 Mac 上安装 [Ollama](https://ollama.ai)。
You can improve the quality of the voice by downloading a higher quality version. These instructions work on MacOS 14 Sonoma: ### 2. 下载 Mistral 7b 模型
运行以下命令下载模型:
```bash
ollama pull mistral
```
1. In System Settings select Accessibility > Spoken Content ### 3. 下载 Whisper 模型
2. Select System Voice and Manage Voices... 访问 [Whisper 模型库](https://github.com/openai/whisper/discussions/63#discussioncomment-3798552),选择适合的模型(`base` 即可)。
3. For English find "Zoe (Premium)" and download it.
4. Select Zoe (Premium) as your System voice.
## Other languages ### 4. 克隆本项目
You can set up support for other languages by editing `assistant.yaml`. Be sure to download a different Whisper model in your language and change the default `modelPath`. 将项目代码克隆到本地计算机:
```bash
git clone <仓库地址>
```
### 5. 配置 Whisper 模型路径
将 Whisper 模型放入项目根目录的 `/whisper` 文件夹中。
### 6. 安装 Python 和 Pip
确保已安装 [Python](https://www.python.org/downloads/macos/) 和 [Pip](https://pip.pypa.io/en/stable/installation/)。
### 7. 配置 PyAudio 库Apple Silicon 特别步骤)
对于 Apple Silicon 用户,需安装 **Homebrew** 并运行以下命令:
```bash
brew install portaudio
```
### 8. 安装依赖
运行以下命令安装所需依赖:
```bash
pip install -r requirements.txt
```
### 9. 启动助手
运行以下命令启动语音助手:
```bash
python assistant.py
```
### 10. 中间使用的要点:
语音识别:使用 Whisper 模型进行本地语音识别,完全离线运行。
自然语言处理:使用 Ollama 平台运行 Mistral 7b 模型,实现高效的本地大语言模型推理,无需联网。
文本转语音TTS基于 pyttsx3 实现的离线文本语音合成功能,支持多种语言和语音优化。但是 pyttsx3 太机械了 增加了edge-tts
---
## 提升语音质量
在 MacOS 14 Sonoma 中,可以通过以下步骤提升语音质量:
1. 打开 **系统设置** > **辅助功能** > **语音内容**
2. 选择 **系统语音** 并点击 **管理语音**
3. 在英文语音中找到 **"Zoe (Premium)"** 并下载。
4. 下载完成后,将系统语音更改为 **Zoe (Premium)**
---
## 支持其他语言
要支持其他语言,可以通过以下方式配置:
1. 编辑 `assistant.yaml` 文件。
2. 下载目标语言的 Whisper 模型并将其路径更新到 `modelPath` 配置项。
**示例(中文配置)**
- 下载适合中文的 Whisper 模型,例如 `medium.zh`
- 在 `assistant.yaml` 中将 `modelPath` 修改为下载的模型路径,例如:
```yaml
modelPath: /path/to/medium.zh.pt
```

Binary file not shown.

Before

Width:  |  Height:  |  Size: 394 KiB

After

Width:  |  Height:  |  Size: 822 B

View File

@ -45,7 +45,10 @@ class Assistant:
def __init__(self): def __init__(self):
logging.info("Initializing Assistant") logging.info("Initializing Assistant")
self.config = self.init_config() self.config = self.init_config()
# 预初始化 pygame mixer避免每次语音播放时的初始化开销
pygame.mixer.init()
programIcon = pygame.image.load('assistant.png') programIcon = pygame.image.load('assistant.png')
self.clock = pygame.time.Clock() self.clock = pygame.time.Clock()
@ -271,30 +274,32 @@ class Assistant:
logging.info(f"Using edge-tts with voice: {self.edge_voice}") logging.info(f"Using edge-tts with voice: {self.edge_voice}")
communicate = edge_tts.Communicate(text, self.edge_voice) communicate = edge_tts.Communicate(text, self.edge_voice)
# 添加调试信息 # 使用异步方式并行处理音频生成
logging.info("Starting audio generation...") audio_task = asyncio.create_task(communicate.save("temp_speech.mp3"))
await communicate.save("temp_speech.mp3")
logging.info("Audio file generated successfully") # 在音频生成的同时执行其他初始化
if not pygame.mixer.get_init():
pygame.mixer.init()
# 等待音频生成完成
await audio_task
if not os.path.exists("temp_speech.mp3") or os.path.getsize("temp_speech.mp3") == 0: if not os.path.exists("temp_speech.mp3") or os.path.getsize("temp_speech.mp3") == 0:
raise Exception("Generated audio file is empty or does not exist") raise Exception("Generated audio file is empty or does not exist")
pygame.mixer.init()
pygame.mixer.music.load("temp_speech.mp3") pygame.mixer.music.load("temp_speech.mp3")
pygame.mixer.music.play() pygame.mixer.music.play()
while pygame.mixer.music.get_busy(): while pygame.mixer.music.get_busy():
pygame.time.wait(100) await asyncio.sleep(0.1) # 使用异步等待替代 pygame.time.wait
pygame.mixer.quit()
# 不要每次都退出 mixer只清理文件
if os.path.exists("temp_speech.mp3"): if os.path.exists("temp_speech.mp3"):
os.remove("temp_speech.mp3") os.remove("temp_speech.mp3")
except Exception as e: except Exception as e:
logging.error(f"An error occurred during edge-tts speech playback: {str(e)}") logging.error(f"An error occurred during edge-tts speech playback: {str(e)}")
logging.error(f"Voice being used: {self.edge_voice}") logging.error(f"Voice being used: {self.edge_voice}")
# 如果 edge-tts 失败,回退到 pyttsx3
logging.info("Falling back to pyttsx3...") logging.info("Falling back to pyttsx3...")
self.tts_engine.say(text) self.tts_engine.say(text)
self.tts_engine.runAndWait() self.tts_engine.runAndWait()
@ -305,9 +310,7 @@ class Assistant:
def play_speech(): def play_speech():
try: try:
logging.info("Starting speech playback") # 移除不必要的延迟
time.sleep(0.5) # Short delay before speaking
if self.config.tts.engine == "edge-tts": if self.config.tts.engine == "edge-tts":
asyncio.run(self.edge_tts_speak(text)) asyncio.run(self.edge_tts_speak(text))
else: # pyttsx3 else: # pyttsx3
@ -318,7 +321,8 @@ class Assistant:
except Exception as e: except Exception as e:
logging.error(f"An error occurred during speech playback: {str(e)}") logging.error(f"An error occurred during speech playback: {str(e)}")
speech_thread = threading.Thread(target=play_speech) # 使用守护线程,这样主程序退出时不会被阻塞
speech_thread = threading.Thread(target=play_speech, daemon=True)
speech_thread.start() speech_thread.start()