File size: 6,037 Bytes
6d89762
 
 
91c27dd
 
 
6d89762
 
 
f70d5f2
6d89762
91c27dd
6d89762
 
91c27dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d89762
91c27dd
 
 
f70d5f2
 
ba9419a
6d89762
91c27dd
 
 
 
6d89762
 
91c27dd
 
6d89762
91c27dd
6d89762
 
91c27dd
 
f70d5f2
 
 
 
 
6d89762
91c27dd
 
6d89762
f70d5f2
 
6d89762
 
91c27dd
 
6d89762
91c27dd
 
6d89762
 
 
 
 
91c27dd
6d89762
91c27dd
 
 
6d89762
91c27dd
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6d89762
91c27dd
 
6d89762
91c27dd
6d89762
 
 
 
 
91c27dd
 
 
 
 
 
 
 
 
6d89762
91c27dd
 
6d89762
91c27dd
 
 
6d89762
 
91c27dd
 
 
6d89762
91c27dd
6d89762
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91c27dd
 
 
 
 
 
 
 
 
 
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
from huggingface_hub import list_repo_files, hf_hub_download
import os
import shutil
import torch
from itertools import combinations
import platform

# Repository ID
repo_id = "hexgrad/Kokoro-82M"
repo_id2="Remsky/kokoro-82m-mirror"
# Set up the cache directory
cache_dir = "./cache"
os.makedirs(cache_dir, exist_ok=True)

# Set up the base model paths
KOKORO_DIR = "./KOKORO"
VOICES_DIR = os.path.join(KOKORO_DIR, "voices")
FP16_DIR = os.path.join(KOKORO_DIR, "fp16")
KOKORO_FILE = "kokoro-v0_19.pth"
FP16_FILE = "fp16/kokoro-v0_19-half.pth"

def download_files(repo_id, filenames, destination_dir, cache_dir):
     # Ensure directories exist
     os.makedirs(destination_dir, exist_ok=True)
     
     for filename in filenames:
        destination = os.path.join(destination_dir, os.path.basename(filename))
        if not os.path.exists(destination):
            file_path = hf_hub_download(repo_id=repo_id, filename=filename, cache_dir=cache_dir)
            shutil.copy(file_path, destination)
            print(f"Downloaded and saved: {destination}")
        else:
              print(f"File already exist in: {destination}")
        

def get_voice_models():
    """Downloads missing voice models from the Hugging Face repository."""

    # Create or empty the 'voices' directory
    if os.path.exists(VOICES_DIR):
       shutil.rmtree(VOICES_DIR)
    os.makedirs(VOICES_DIR, exist_ok=True)

    # Get list of files from the repository
    files = list_repo_files(repo_id)
    
    # Filter for voice files
    voice_files = [file.replace("voices/", "") for file in files if file.startswith("voices/")]

    # Get current voice files
    current_voice = os.listdir(VOICES_DIR)

    # Download new voices
    download_voice = [file for file in voice_files if file not in current_voice]
    if download_voice:
        #  print(f"Files to download: {download_voice}")
         pass
    eng_voices = []
    for i in download_voice:
         if i.startswith("a") or i.startswith("b"):
              eng_voices.append(i)        
    download_files(repo_id, [f"voices/{file}" for file in eng_voices], VOICES_DIR, cache_dir)

def download_base_models():
    """Downloads Kokoro base model and fp16 version if missing."""

    download_files(repo_id2, [KOKORO_FILE], KOKORO_DIR, cache_dir)
    download_files(repo_id2, [FP16_FILE], FP16_DIR, cache_dir)

def setup_batch_file():
    """Creates a 'run_app.bat' file for Windows if it doesn't exist."""

    if platform.system() == "Windows":
        bat_file_name = 'run_app.bat'
        if not os.path.exists(bat_file_name):
            bat_content_app = '''@echo off
call myenv\\Scripts\\activate
@python.exe app.py %*
@pause
'''
            with open(bat_file_name, 'w') as bat_file:
                bat_file.write(bat_content_app)
            print(f"Created '{bat_file_name}'.")
        else:
            print(f"'{bat_file_name}' already exists.")
    else:
        print("Not a Windows system, skipping batch file creation.")

def download_ffmpeg():
    """Downloads ffmpeg and ffprobe executables from Hugging Face."""
    print("For Kokoro TTS we don't need ffmpeg, But for Subtitle Dubbing we need ffmpeg")
    os_name=platform.system()
    if os_name == "Windows":
        repo_id = "fishaudio/fish-speech-1"
        filenames = ["ffmpeg.exe", "ffprobe.exe"]
        ffmpeg_dir = "./ffmpeg"
        download_files(repo_id, filenames, ffmpeg_dir, cache_dir)
    elif os_name == "Linux":
         print("Please install ffmpeg using the package manager for your system.")
         print("'sudo apt install ffmpeg' on Debian/Ubuntu")
    else:
        print(f"Manually install ffmpeg for {os_name} from https://ffmpeg.org/download.html")

def mix_all_voices(folder_path=VOICES_DIR):
     """Mix all pairs of voice models and save the new models."""
    # Get the list of available voice packs
     available_voice_pack = [
        os.path.splitext(filename)[0]
        for filename in os.listdir(folder_path)
        if filename.endswith('.pt')
    ]

     # Generate all unique pairs of voices
     voice_combinations = combinations(available_voice_pack, 2)
   
     # Function to mix two voices
     def mix_model(voice_1, voice_2):
          """Mix two voice models and save the new model."""
          new_name = f"{voice_1}_mix_{voice_2}"
          voice_id_1 = torch.load(f'{folder_path}/{voice_1}.pt', weights_only=True)
          voice_id_2 = torch.load(f'{folder_path}/{voice_2}.pt', weights_only=True)

          # Create the mixed model by averaging the weights
          mixed_voice = torch.mean(torch.stack([voice_id_1, voice_id_2]), dim=0)

          # Save the mixed model
          torch.save(mixed_voice, f'{folder_path}/{new_name}.pt')
          print(f"Created new voice model: {new_name}")

    # Create mixed voices for each pair
     for voice_1, voice_2 in voice_combinations:
          print(f"Mixing {voice_1} ❤️ {voice_2}")
          mix_model(voice_1, voice_2)

def save_voice_names(directory=VOICES_DIR, output_file="./voice_names.txt"):
    """
    Retrieves voice names from a directory, sorts them by length, and saves to a file.

    Parameters:
        directory (str): Directory containing the voice files.
        output_file (str): File to save the sorted voice names.

    Returns:
        None
    """
    # Get the list of voice names without file extensions
    voice_list = [
        os.path.splitext(filename)[0]
        for filename in os.listdir(directory)
        if filename.endswith('.pt')
    ]

    # Sort the list based on the length of each name
    voice_list = sorted(voice_list, key=len)

    # Save the sorted list to the specified file
    with open(output_file, "w") as f:
        for voice_name in voice_list:
            f.write(f"{voice_name}\n")

    print(f"Voice names saved to {output_file}")

# --- Main Execution ---
if __name__ == "__main__":
    get_voice_models()
    download_base_models()
    setup_batch_file()
    # mix_all_voices()
    save_voice_names()
    download_ffmpeg()
    print("Setup complete!")