add config
This commit is contained in:
parent
0f15b5060b
commit
a7876fb472
115
SYSTEMD_SETUP.md
Normal file
115
SYSTEMD_SETUP.md
Normal file
@ -0,0 +1,115 @@
|
||||
# Local Voice Systemd 服务配置指南
|
||||
|
||||
## 问题解决方案
|
||||
|
||||
### 核心问题
|
||||
- **直接运行**: 使用PulseAudio,自动转换16000Hz采样率 ✅
|
||||
- **systemd运行**: 直接访问USB设备,只支持48000/44100Hz ❌
|
||||
|
||||
### 解决策略
|
||||
通过配置systemd服务访问用户会话的PulseAudio,利用其采样率转换能力。
|
||||
|
||||
## 部署步骤
|
||||
|
||||
### 1. 上传文件到树莓派
|
||||
```bash
|
||||
scp local-voice.service local-voice-user.service deploy-service.sh test-audio.py zhuchaowe@192.168.101.212:~/Local-Voice/
|
||||
```
|
||||
|
||||
### 2. 运行部署脚本
|
||||
```bash
|
||||
cd ~/Local-Voice
|
||||
./deploy-service.sh
|
||||
```
|
||||
|
||||
### 3. 测试音频访问
|
||||
```bash
|
||||
python3 test-audio.py
|
||||
```
|
||||
|
||||
### 4. 启动服务 (推荐使用用户级服务)
|
||||
```bash
|
||||
# 用户级服务 (推荐)
|
||||
systemctl --user start local-voice-user.service
|
||||
systemctl --user enable local-voice-user.service
|
||||
|
||||
# 查看日志
|
||||
journalctl --user -u local-voice-user.service -f
|
||||
|
||||
# 如果用户级服务不工作,尝试系统级服务
|
||||
sudo systemctl start local-voice.service
|
||||
sudo systemctl enable local-voice.service
|
||||
|
||||
# 查看系统服务日志
|
||||
sudo journalctl -u local-voice.service -f
|
||||
```
|
||||
|
||||
## 服务配置说明
|
||||
|
||||
### 系统级服务 (local-voice.service)
|
||||
- 适用于传统systemd环境
|
||||
- 添加了PulseAudio环境变量
|
||||
- 包含音频设备权限
|
||||
|
||||
### 用户级服务 (local-voice-user.service)
|
||||
- 推荐方案,更好的音频访问
|
||||
- 自动继承用户会话环境
|
||||
- 无需额外环境变量配置
|
||||
|
||||
## 故障排除
|
||||
|
||||
### 音频设备不可用
|
||||
1. 检查pipewire-pulse服务:
|
||||
```bash
|
||||
systemctl --user status pipewire-pulse
|
||||
systemctl --user start pipewire-pulse
|
||||
```
|
||||
|
||||
2. 检查音频设备权限:
|
||||
```bash
|
||||
groups # 确认在audio组中
|
||||
```
|
||||
|
||||
3. 测试直接运行:
|
||||
```bash
|
||||
python3 multiprocess_recorder.py --enable-nfc
|
||||
```
|
||||
|
||||
### 权限问题
|
||||
如果遇到权限错误,确保用户在audio组中:
|
||||
```bash
|
||||
sudo usermod -a -G audio $USER
|
||||
# 重新登录或重启系统
|
||||
```
|
||||
|
||||
### 环境变量问题
|
||||
如果用户级服务正常但系统级服务有问题,可能需要:
|
||||
1. 检查环境变量是否正确设置
|
||||
2. 确认pipewire-pulse服务在系统启动时运行
|
||||
3. 考虑使用用户级服务作为主要方案
|
||||
|
||||
## 验证步骤
|
||||
|
||||
1. **环境测试**: `python3 test-audio.py`
|
||||
2. **服务启动**: `systemctl --user start local-voice-user.service`
|
||||
3. **日志监控**: `journalctl --user -u local-voice-user.service -f`
|
||||
4. **功能测试**: 使用NFC卡片触发录音功能
|
||||
|
||||
## 备用方案
|
||||
|
||||
如果上述方案不工作,可以考虑:
|
||||
|
||||
### 方案A: 使用screen会话
|
||||
```bash
|
||||
screen -dmS local-voice python3 ~/Local-Voice/multiprocess_recorder.py --enable-nfc
|
||||
screen -r local-voice # 查看输出
|
||||
```
|
||||
|
||||
### 方案B: 使用cron启动
|
||||
在crontab中添加:
|
||||
```
|
||||
@reboot cd ~/Local-Voice && python3 multiprocess_recorder.py --enable-nfc
|
||||
```
|
||||
|
||||
### 方案C: 修改代码支持多种采样率
|
||||
如果需要修改代码支持48000Hz采样率,请告知。
|
||||
@ -22,7 +22,9 @@
|
||||
"enable_llm": true,
|
||||
"enable_tts": true,
|
||||
"character": "libai",
|
||||
"max_tokens": 50
|
||||
"max_tokens": 50,
|
||||
"enable_chat_memory": true,
|
||||
"max_history_length": 5
|
||||
},
|
||||
"detection": {
|
||||
"zcr_min": 2400,
|
||||
|
||||
@ -91,6 +91,18 @@ class ControlSystem:
|
||||
'failed_processing': 0
|
||||
}
|
||||
|
||||
# 聊天历史记录
|
||||
self.chat_history = []
|
||||
# 从配置中读取聊天历史设置
|
||||
self.enable_chat_memory = self.config.get('processing', {}).get('enable_chat_memory', True)
|
||||
self.max_history_length = self.config.get('processing', {}).get('max_history_length', 5)
|
||||
|
||||
# 显示聊天记忆状态
|
||||
if self.enable_chat_memory:
|
||||
print(f"💬 聊天记忆功能已启用,最多保存 {self.max_history_length} 轮对话")
|
||||
else:
|
||||
print("💬 聊天记忆功能已禁用")
|
||||
|
||||
# 运行状态
|
||||
self.running = True
|
||||
|
||||
@ -997,11 +1009,28 @@ class ControlSystem:
|
||||
"Authorization": f"Bearer {self.api_config['llm']['api_key']}"
|
||||
}
|
||||
|
||||
# 构建消息列表
|
||||
messages = [
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": text}
|
||||
{
|
||||
"role": "system",
|
||||
"content": system_prompt
|
||||
}
|
||||
]
|
||||
|
||||
# 如果启用聊天记忆,添加历史对话记录
|
||||
if self.enable_chat_memory:
|
||||
for history_item in self.chat_history:
|
||||
messages.extend([
|
||||
{"role": "user", "content": history_item["user"]},
|
||||
{"role": "assistant", "content": history_item["assistant"]}
|
||||
])
|
||||
|
||||
# 添加当前用户消息
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": text
|
||||
})
|
||||
|
||||
data = {
|
||||
"model": self.api_config['llm']['model'],
|
||||
"messages": messages,
|
||||
@ -1020,7 +1049,14 @@ class ControlSystem:
|
||||
result = response.json()
|
||||
if 'choices' in result and len(result['choices']) > 0:
|
||||
content = result['choices'][0]['message']['content']
|
||||
return content.strip()
|
||||
filtered_content = self._filter_parentheses_content(content.strip())
|
||||
|
||||
# 保存对话到历史记录
|
||||
if self.enable_chat_memory:
|
||||
self._add_to_chat_history(text, filtered_content)
|
||||
print(f"💬 对话已保存到历史记录 (当前历史长度: {len(self.chat_history)})")
|
||||
|
||||
return filtered_content
|
||||
|
||||
print(f"❌ LLM API调用失败: {response.status_code}")
|
||||
return None
|
||||
@ -1059,13 +1095,23 @@ class ControlSystem:
|
||||
{
|
||||
"role": "system",
|
||||
"content": system_prompt
|
||||
},
|
||||
{
|
||||
"role": "user",
|
||||
"content": text
|
||||
}
|
||||
]
|
||||
|
||||
# 如果启用聊天记忆,添加历史对话记录
|
||||
if self.enable_chat_memory:
|
||||
for history_item in self.chat_history:
|
||||
messages.extend([
|
||||
{"role": "user", "content": history_item["user"]},
|
||||
{"role": "assistant", "content": history_item["assistant"]}
|
||||
])
|
||||
|
||||
# 添加当前用户消息
|
||||
messages.append({
|
||||
"role": "user",
|
||||
"content": text
|
||||
})
|
||||
|
||||
data = {
|
||||
"model": self.api_config['llm']['model'],
|
||||
"messages": messages,
|
||||
@ -1181,6 +1227,12 @@ class ControlSystem:
|
||||
print(f"🎵 发送剩余句子: {filtered_sentence}")
|
||||
self._send_streaming_text_to_output_process(filtered_sentence)
|
||||
|
||||
# 保存完整回复到历史记录
|
||||
if accumulated_text and self.enable_chat_memory:
|
||||
filtered_response = self._filter_parentheses_content(accumulated_text.strip())
|
||||
self._add_to_chat_history(text, filtered_response)
|
||||
print(f"💬 对话已保存到历史记录 (当前历史长度: {len(self.chat_history)})")
|
||||
|
||||
# 通知输出进程LLM生成已完成
|
||||
self._notify_llm_complete()
|
||||
|
||||
@ -1651,6 +1703,10 @@ class ControlSystem:
|
||||
|
||||
print(f"🔄 角色已切换: {old_character} -> {character_name}")
|
||||
|
||||
# 清空聊天历史
|
||||
self.clear_chat_history()
|
||||
print(f"🔄 角色切换,聊天历史已清空")
|
||||
|
||||
# 播放新角色打招呼
|
||||
print("🎭 播放新角色打招呼...")
|
||||
greeting_success = self.play_greeting()
|
||||
@ -1756,6 +1812,33 @@ class ControlSystem:
|
||||
"current_character": self.nfc_manager.get_current_character(),
|
||||
"running": self.nfc_manager.running
|
||||
}
|
||||
|
||||
def _add_to_chat_history(self, user_message, assistant_response):
|
||||
"""添加对话到历史记录"""
|
||||
import time
|
||||
|
||||
# 如果历史记录超过最大长度,移除最早的记录
|
||||
if len(self.chat_history) >= self.max_history_length:
|
||||
self.chat_history.pop(0)
|
||||
|
||||
# 添加新的对话记录
|
||||
self.chat_history.append({
|
||||
"user": user_message,
|
||||
"assistant": assistant_response,
|
||||
"timestamp": time.time()
|
||||
})
|
||||
|
||||
def clear_chat_history(self):
|
||||
"""清空聊天历史"""
|
||||
self.chat_history = []
|
||||
print("💬 聊天历史已清空")
|
||||
|
||||
def get_chat_history_summary(self):
|
||||
"""获取聊天历史摘要"""
|
||||
if not self.chat_history:
|
||||
return "暂无聊天历史"
|
||||
|
||||
return f"当前有 {len(self.chat_history)} 轮对话记录"
|
||||
|
||||
def main():
|
||||
"""主函数"""
|
||||
|
||||
78
deploy-service.sh
Executable file
78
deploy-service.sh
Executable file
@ -0,0 +1,78 @@
|
||||
#!/bin/bash
|
||||
|
||||
# Local Voice 服务部署脚本
|
||||
# 用于解决systemd环境下的音频设备访问问题
|
||||
|
||||
echo "🔧 Local Voice 服务部署脚本"
|
||||
echo "=================================="
|
||||
|
||||
# 获取用户ID
|
||||
USER_ID=$(id -u)
|
||||
USERNAME=$(whoami)
|
||||
echo "👤 当前用户: $USERNAME (UID: $USER_ID)"
|
||||
|
||||
# 备份原有服务文件
|
||||
echo "💾 备份原有服务文件..."
|
||||
if systemctl list-unit-files | grep -q "local-voice.service"; then
|
||||
sudo systemctl stop local-voice.service 2>/dev/null
|
||||
sudo systemctl disable local-voice.service 2>/dev/null
|
||||
sudo cp /etc/systemd/system/local-voice.service /etc/systemd/system/local-voice.service.backup 2>/dev/null || true
|
||||
echo "✅ 原有服务已备份"
|
||||
fi
|
||||
|
||||
# 安装systemd服务
|
||||
echo "📦 安装systemd服务..."
|
||||
sudo cp local-voice.service /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable local-voice.service
|
||||
echo "✅ 系统级服务已安装"
|
||||
|
||||
# 安装用户级服务
|
||||
echo "🏠 安装用户级服务..."
|
||||
mkdir -p ~/.config/systemd/user/
|
||||
cp local-voice-user.service ~/.config/systemd/user/
|
||||
systemctl --user daemon-reload
|
||||
systemctl --user enable local-voice-user.service
|
||||
echo "✅ 用户级服务已安装"
|
||||
|
||||
# 确保pipewire-pulse运行
|
||||
echo "🎵 检查音频服务..."
|
||||
if ! systemctl --user is-active --quiet pipewire-pulse; then
|
||||
echo "🔧 启动pipewire-pulse服务..."
|
||||
systemctl --user start pipewire-pulse
|
||||
systemctl --user enable pipewire-pulse
|
||||
echo "✅ pipewire-pulse已启动"
|
||||
else
|
||||
echo "✅ pipewire-pulse正在运行"
|
||||
fi
|
||||
|
||||
# 启用用户服务 lingering (允许用户服务在登出后继续运行)
|
||||
echo "🔄 启用用户服务lingering..."
|
||||
sudo loginctl enable-linger $USERNAME
|
||||
echo "✅ 用户服务lingering已启用"
|
||||
|
||||
# 测试建议
|
||||
echo ""
|
||||
echo "🎯 测试建议:"
|
||||
echo "1. 先测试用户级服务: systemctl --user start local-voice-user.service"
|
||||
echo "2. 查看用户服务日志: journalctl --user -u local-voice-user.service -f"
|
||||
echo "3. 如果用户级服务正常,再考虑使用系统级服务"
|
||||
echo ""
|
||||
echo "🔍 故障排除:"
|
||||
echo "- 如果用户级服务正常: 建议使用 systemctl --user start local-voice-user.service"
|
||||
echo "- 如果系统级服务正常: 使用 sudo systemctl start local-voice.service"
|
||||
echo ""
|
||||
echo "📊 当前音频设备状态:"
|
||||
python3 -c "
|
||||
import pyaudio
|
||||
p = pyaudio.PyAudio()
|
||||
print('可用音频设备:')
|
||||
for i in range(p.get_device_count()):
|
||||
info = p.get_device_info_by_index(i)
|
||||
if info['maxInputChannels'] > 0:
|
||||
print(f' 设备 {i}: {info[\"name\"]} (默认采样率: {info[\"defaultSampleRate\"]}Hz)')
|
||||
p.terminate()
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "✅ 部署完成!"
|
||||
16
local-voice-user.service
Normal file
16
local-voice-user.service
Normal file
@ -0,0 +1,16 @@
|
||||
[Unit]
|
||||
Description=Local Voice Multiprocess Recorder with NFC (User Service)
|
||||
After=network.target sound.target pipewire-pulse.service
|
||||
Wants=network.target sound.target pipewire-pulse.service
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
WorkingDirectory=/home/zhuchaowe/Local-Voice
|
||||
ExecStart=/usr/bin/python3 /home/zhuchaowe/Local-Voice/multiprocess_recorder.py --enable-nfc
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@ -1,17 +1,24 @@
|
||||
[Unit]
|
||||
Description=Local Voice Multiprocess Recorder with NFC
|
||||
After=network.target
|
||||
Wants=network.target
|
||||
After=network.target sound.target
|
||||
Wants=network.target sound.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=zhuchaowe
|
||||
WorkingDirectory=/home/zhuchaowe
|
||||
Group=audio
|
||||
WorkingDirectory=/home/zhuchaowe/Local-Voice
|
||||
Environment="PULSE_SERVER=unix:/run/user/%U/pulse/native"
|
||||
Environment="XDG_RUNTIME_DIR=/run/user/%U"
|
||||
Environment="DBUS_SESSION_BUS_ADDRESS=unix:path=/run/user/%U/bus"
|
||||
ExecStart=/usr/bin/python3 /home/zhuchaowe/Local-Voice/multiprocess_recorder.py --enable-nfc
|
||||
Restart=always
|
||||
RestartSec=10
|
||||
StandardOutput=journal
|
||||
StandardError=journal
|
||||
# 添加设备访问权限
|
||||
DeviceAllow=/dev/snd/*
|
||||
DevicePolicy=auto
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
77
test-audio.py
Executable file
77
test-audio.py
Executable file
@ -0,0 +1,77 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
音频设备测试脚本
|
||||
用于测试不同环境下的音频设备访问
|
||||
"""
|
||||
|
||||
import pyaudio
|
||||
import sys
|
||||
import os
|
||||
|
||||
def test_audio_access():
|
||||
print("🔍 音频设备访问测试")
|
||||
print("=" * 50)
|
||||
|
||||
try:
|
||||
p = pyaudio.PyAudio()
|
||||
print("✅ PyAudio 初始化成功")
|
||||
|
||||
# 显示所有音频设备
|
||||
print("\n📋 可用音频设备:")
|
||||
for i in range(p.get_device_count()):
|
||||
info = p.get_device_info_by_index(i)
|
||||
if info['maxInputChannels'] > 0:
|
||||
print(f" 设备 {i}: {info['name']}")
|
||||
print(f" 输入通道: {info['maxInputChannels']}")
|
||||
print(f" 默认采样率: {info['defaultSampleRate']}")
|
||||
|
||||
# 测试16000Hz采样率
|
||||
print(f"\n🎵 测试16000Hz采样率访问:")
|
||||
|
||||
# 测试默认设备
|
||||
try:
|
||||
stream = p.open(
|
||||
format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=16000,
|
||||
input=True,
|
||||
frames_per_buffer=1024
|
||||
)
|
||||
print("✅ 默认设备支持16000Hz")
|
||||
stream.close()
|
||||
except Exception as e:
|
||||
print(f"❌ 默认设备不支持16000Hz: {e}")
|
||||
|
||||
# 测试pulse设备
|
||||
try:
|
||||
stream = p.open(
|
||||
format=pyaudio.paInt16,
|
||||
channels=1,
|
||||
rate=16000,
|
||||
input=True,
|
||||
frames_per_buffer=1024,
|
||||
input_device_index=6 # pulse设备
|
||||
)
|
||||
print("✅ Pulse设备支持16000Hz")
|
||||
stream.close()
|
||||
except Exception as e:
|
||||
print(f"❌ Pulse设备不支持16000Hz: {e}")
|
||||
|
||||
p.terminate()
|
||||
print("\n✅ 音频测试完成")
|
||||
|
||||
except Exception as e:
|
||||
print(f"❌ 音频测试失败: {e}")
|
||||
sys.exit(1)
|
||||
|
||||
def check_environment():
|
||||
print("\n🌍 环境信息:")
|
||||
print(f"用户: {os.getenv('USER', 'Unknown')}")
|
||||
print(f"用户ID: {os.getuid()}")
|
||||
print(f"PULSE_SERVER: {os.getenv('PULSE_SERVER', 'Not set')}")
|
||||
print(f"XDG_RUNTIME_DIR: {os.getenv('XDG_RUNTIME_DIR', 'Not set')}")
|
||||
print(f"DBUS_SESSION_BUS_ADDRESS: {os.getenv('DBUS_SESSION_BUS_ADDRESS', 'Not set')}")
|
||||
|
||||
if __name__ == "__main__":
|
||||
check_environment()
|
||||
test_audio_access()
|
||||
Loading…
Reference in New Issue
Block a user