(text, save_path, mode="preset", voice_id=None, ref_audio=None, ref_text=None, check_duration=False)
| 21 | |
| 22 | @except_handler("Failed to generate audio using SiliconFlow Fish TTS", retry=2, delay=1) |
| 23 | def siliconflow_fish_tts(text, save_path, mode="preset", voice_id=None, ref_audio=None, ref_text=None, check_duration=False): |
| 24 | sf_fish_set = load_key("sf_fish_tts") |
| 25 | headers = {"Authorization": f'Bearer {sf_fish_set["api_key"]}', "Content-Type": "application/json"} |
| 26 | payload = {"model": MODEL_NAME, "response_format": "wav", "stream": False, "input": text} |
| 27 | |
| 28 | if mode == "preset": |
| 29 | payload["voice"] = f"fishaudio/fish-speech-1.4:{sf_fish_set['voice']}" |
| 30 | elif mode == "custom": |
| 31 | if not voice_id: |
| 32 | raise ValueError("custom mode requires voice_id") |
| 33 | payload["voice"] = voice_id |
| 34 | elif mode == "dynamic": |
| 35 | if not ref_audio or not ref_text: |
| 36 | raise ValueError("dynamic mode requires ref_audio and ref_text") |
| 37 | with open(ref_audio, 'rb') as f: |
| 38 | audio_base64 = base64.b64encode(f.read()).decode('utf-8') |
| 39 | payload = { |
| 40 | "model": MODEL_NAME, "response_format": "wav", "stream": False, "input": text, "voice": None, |
| 41 | "references": [{"audio": f"data:audio/wav;base64,{audio_base64}", "text": ref_text}] |
| 42 | } |
| 43 | else: raise ValueError("Invalid mode") |
| 44 | |
| 45 | response = requests.post(API_URL_SPEECH, json=payload, headers=headers) |
| 46 | if response.status_code == 200: |
| 47 | wav_file_path = Path(save_path).with_suffix('.wav') |
| 48 | wav_file_path.parent.mkdir(parents=True, exist_ok=True) |
| 49 | with open(wav_file_path, 'wb') as f: f.write(response.content) |
| 50 | |
| 51 | if check_duration: |
| 52 | duration = get_audio_duration(wav_file_path) |
| 53 | rprint(f"[blue]Audio Duration: {duration:.2f} seconds") |
| 54 | |
| 55 | rprint(f"[green]Successfully generated audio file: {wav_file_path}") |
| 56 | return True |
| 57 | |
| 58 | error_msg = response.json() |
| 59 | rprint(f"[red]Failed to generate audio | HTTP {response.status_code} (Attempt {attempt + 1}/{max_retries})") |
| 60 | rprint(f"[red]Text: {text}") |
| 61 | rprint(f"[red]Error details: {error_msg}") |
| 62 | |
| 63 | return False |
| 64 | |
| 65 | @except_handler("Failed to create custom voice") |
| 66 | def create_custom_voice(audio_path, text, custom_name=None): |
no test coverage detected