File size: 7,471 Bytes
24437ee
 
 
 
 
 
 
 
 
 
 
 
88ea7f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24437ee
 
 
 
 
 
 
 
 
 
 
 
 
 
88ea7f6
 
 
 
24437ee
 
 
 
 
 
 
 
 
 
 
 
 
88ea7f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24437ee
 
88ea7f6
24437ee
 
 
 
 
88ea7f6
24437ee
 
 
 
 
 
 
 
88ea7f6
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24437ee
 
 
 
 
 
 
 
 
 
88ea7f6
24437ee
88ea7f6
 
 
 
 
 
 
 
 
 
 
 
 
24437ee
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
"""
Genie TTS 依赖安装模块
负责处理Genie TTS包及其依赖的安装和管理
"""

import subprocess
import sys
import logging

logger = logging.getLogger(__name__)


def install_pyaudio_alternative():
    """尝试安装PyAudio的替代方案或创建mock模块"""
    try:
        # 首先尝试正常安装PyAudio
        subprocess.check_call([
            sys.executable, "-m", "pip", "install", "pyaudio"
        ], timeout=120)
        logger.info("✓ PyAudio 安装成功")
        return True
    except Exception as e:
        logger.warning(f"PyAudio 安装失败: {e}")
        
        # 如果PyAudio安装失败,创建一个mock模块
        try:
            import os
            import site
            
            # 获取site-packages路径
            site_packages = site.getsitepackages()[0]
            pyaudio_mock_path = os.path.join(site_packages, "pyaudio.py")
            
            # 创建mock pyaudio模块
            mock_pyaudio_code = '''"""
Mock PyAudio module for environments without audio support
"""

class PyAudioError(Exception):
    pass

class Stream:
    def __init__(self, *args, **kwargs):
        raise PyAudioError("音频流在此环境中不可用")
    
    def read(self, *args, **kwargs):
        raise PyAudioError("音频读取在此环境中不可用")
    
    def write(self, *args, **kwargs):
        raise PyAudioError("音频写入在此环境中不可用")
    
    def start_stream(self):
        pass
    
    def stop_stream(self):
        pass
    
    def close(self):
        pass

class PyAudio:
    paInt16 = 8
    paFloat32 = 1
    
    def __init__(self):
        logger.warning("使用Mock PyAudio - 音频功能不可用")
    
    def open(self, *args, **kwargs):
        return Stream()
    
    def get_device_count(self):
        return 0
    
    def get_device_info_by_index(self, index):
        return {"name": "Mock Device", "maxInputChannels": 0, "maxOutputChannels": 0}
    
    def terminate(self):
        pass

# 导出主要类和常量
__all__ = ['PyAudio', 'Stream', 'PyAudioError']
'''
            
            with open(pyaudio_mock_path, 'w', encoding='utf-8') as f:
                f.write(mock_pyaudio_code)
            
            logger.info("✓ 创建 PyAudio mock 模块成功")
            return True
            
        except Exception as mock_error:
            logger.error(f"创建 PyAudio mock 模块失败: {mock_error}")
            return False


def install_genie_tts():
    """尝试安装genie-tts包,处理Hugging Face Spaces的限制"""
    try:
        import genie_tts
        logger.info("genie-tts已安装")
        return True, None
    except ImportError:
        logger.info("正在尝试安装genie-tts...")
        try:
            # 首先确保关键依赖已安装
            critical_deps = [
                "onnxruntime>=1.16.0",  # 最关键:没有它TTS完全无法工作
                "numpy>=1.21.0",        # 基础依赖
                "soundfile>=0.12.0",    # 音频处理
                "huggingface-hub>=0.17.0",  # 模型下载
                "scipy>=1.9.0",         # 科学计算
                "pyyaml>=6.0",         # 配置文件解析
                "rich>=12.0.0"         # 终端输出美化
            ]
            
            logger.info("正在安装关键依赖...")
            for dep in critical_deps:
                try:
                    subprocess.check_call([
                        sys.executable, "-m", "pip", "install", dep, "--upgrade"
                    ], timeout=180)
                    logger.info(f"✓ 成功安装: {dep}")
                except Exception as e:
                    logger.error(f"✗ 关键依赖安装失败: {dep} - {e}")
                    return False, f"关键依赖 {dep} 安装失败: {str(e)}"
            
            # 处理PyAudio依赖
            logger.info("正在处理PyAudio依赖...")
            pyaudio_success = install_pyaudio_alternative()
            if not pyaudio_success:
                logger.warning("PyAudio处理失败,但将继续安装...")
            
            # 尝试安装可选的日语处理依赖
            try:
                subprocess.check_call([
                    sys.executable, "-m", "pip", "install", "pyopenjtalk"
                ], timeout=120)
                logger.info("✓ 成功安装 pyopenjtalk")
            except Exception as e:
                logger.warning(f"⚠ pyopenjtalk 安装失败: {e}")
            
            # 尝试安装可选的音频重采样依赖
            try:
                subprocess.check_call([
                    sys.executable, "-m", "pip", "install", "soxr"
                ], timeout=120)
                logger.info("✓ 成功安装 soxr")
            except Exception as e:
                logger.warning(f"⚠ soxr 安装失败: {e}")
            
            # 最后安装genie-tts主包
            logger.info("正在安装 genie-tts 主包...")
            subprocess.check_call([
                sys.executable, "-m", "pip", "install", 
                "genie-tts", "--upgrade"
            ], timeout=300)
            
            # 验证安装
            import genie_tts
            logger.info("✅ genie-tts安装成功")
            return True, "安装成功,但某些音频功能可能不可用(PyAudio限制)"
            
        except subprocess.TimeoutExpired:
            error_msg = "安装超时:Hugging Face Spaces 环境可能不支持某些依赖"
            logger.error(error_msg)
            return False, error_msg
            
        except Exception as e:
            error_msg = str(e)
            
            # 如果仍然是PyAudio相关错误,提供更详细的解决建议
            if "pyaudio" in error_msg.lower():
                error_msg = (
                    "PyAudio依赖问题:即使创建了mock模块,genie-tts仍无法正常导入。"
                    "建议解决方案:\n"
                    "1. 在本地环境运行(安装了音频驱动)\n"
                    "2. 使用替代的TTS库(如 pyttsx3 或 espeak)\n" 
                    "3. 联系Hugging Face支持团队关于音频依赖问题"
                )
                logger.error(error_msg)
                return False, error_msg
            else:
                logger.error(f"安装genie-tts失败: {error_msg}")
                return False, error_msg


def setup_genie_import():
    """设置Genie TTS的导入,返回模块和错误信息"""
    install_success, install_error = install_genie_tts()
    
    if install_success:
        try:
            import genie_tts as genie
            logger.info("Genie TTS导入成功")
            return genie, install_error  # 返回警告信息(如果有)
        except ImportError as e:
            error_msg = f"导入失败: {str(e)}"
            
            # 如果导入仍然失败,提供备用方案的建议
            if "pyaudio" in error_msg.lower():
                error_msg += (
                    "\n\n建议的备用方案:\n"
                    "1. 使用在线TTS服务(Google TTS, Azure Speech等)\n"
                    "2. 在本地环境部署Genie TTS\n"
                    "3. 使用其他兼容Hugging Face Spaces的TTS模型"
                )
            
            logger.error(error_msg)
            return None, error_msg
    else:
        return None, install_error