import os import requests def synthesize_cosyvoice(text, speed=1.0, pitch=0, volume=1.0, instruction=None): """调用阿里云百炼CosyVoice API""" api_key = os.getenv('DASHSCOPE_API_KEY', '') if not api_key: raise ValueError('DASHSCOPE_API_KEY未设置') url = 'https://dashscope.aliyuncs.com/api/v1/services/audio/tts/SpeechSynthesizer' headers = { 'Authorization': f'Bearer {api_key}', 'Content-Type': 'application/json' } # 前端 pitch: -12~12 → API rate: 0.5~2.0(以1.0为中心) pitch_ratio = max(0.5, min(2.0, 1.0 + pitch / 24)) # 前端 volume: 0~10 → API volume: 0~100 volume_int = int(max(0, min(100, volume * 10))) payload = { 'model': 'cosyvoice-v3.5-flash', 'input': { 'text': text, 'voice': 'cosyvoice-v3.5-flash-bailian-e859a6e87823419f9c6b3eefb1a97dc3', 'format': 'mp3', 'sample_rate': 32000 }, 'parameters': { 'rate': max(0.5, min(2.0, speed)), 'pitch': pitch_ratio, 'volume': volume_int } } response = requests.post(url, json=payload, headers=headers, timeout=60) if response.status_code == 402 or response.status_code == 403: raise Exception('CosyVoice 账户欠费或权限不足,请联系管理员') if response.status_code == 401: raise Exception('CosyVoice API密钥无效,请联系管理员') if response.status_code == 429: raise Exception('CosyVoice 请求过于频繁,请稍后再试') if response.status_code != 200: raise Exception(f'CosyVoice 服务异常({response.status_code}),请稍后再试') result = response.json() # 阿里云返回JSON格式,音频数据在 output.audio.url 字段 if 'output' in result and 'audio' in result['output']: audio_url = result['output']['audio'].get('url') if audio_url: # 从URL下载实际音频 audio_response = requests.get(audio_url, timeout=60) if audio_response.status_code == 200: return audio_response.content raise Exception(f'下载音频失败: {audio_response.status_code}') raise Exception(f'CosyVoice返回格式异常: {result}')